oracleのストアドプロシージャ・ファンクションの実行
SQL*Plusで無名プロシージャを実行するときの要領でそのまま実行する。
●PHPから「p_test」を実行
<?php
/* 無名プロシージャの定義 */
$sql = "declare begin p_test; end;";
$conn = Ora_Logon("scott@orcl", "tiger");
$cursor = Ora_Open($conn);
Ora_Parse($cursor, $sql);
$ncols = Ora_Exec($cursor);
Ora_Close($cursor);
Ora_Logoff($conn);
?>
●ストアド内のOracle変数をPHP変数とbindすることで、PHP側で参照できるようになります。
プロシージャ定義
DECLARE
ret INTEGER := 0;
BEGIN
/* 最終的に、PHPでこのretの値を取り出す */
:ret := test(1, 2);
END;
ファンクション定義
CREATE OR REPLACE FUNCTION test(
a IN INTEGER,
b IN INTEGER
) RETURN INTEGER
IS
BEGIN
RETURN (a + b);
END;
OCI8関数の場合、OCIBindByName 関数を使用します。なお、BIND する Oracle 変数は、大文字で記述する必要があるので、注意しましょう。また、LOB・ROWID・BFILEなどのデータ型を BIND する場合、OCINewDescriptor 関数を使用して PHP 変数を定義しておく必要があります
●PHPからストアド内の変数を参照
<?php
$conn = OCILogon( "scott", "tiger", "orcl");
$sql = "begin ";
$sql .= ":ret := test(1,2); ";
$sql .= "end;";
$sql = OCIParse($conn, $sql);
/**
* BINDするOracle変数は、大文字で記述する
*/
OCIBindByName($sql, ":RET" , &$ret, 2);
OCIExecute($sql, OCI_DEFAULT );
echo "ret=$ret";
OCIFreeStatement($sql);
OCILogoff($conn);
?>
●PHPから「p_test」を実行
<?php
/* 無名プロシージャの定義 */
$sql = "declare begin p_test; end;";
$conn = Ora_Logon("scott@orcl", "tiger");
$cursor = Ora_Open($conn);
Ora_Parse($cursor, $sql);
$ncols = Ora_Exec($cursor);
Ora_Close($cursor);
Ora_Logoff($conn);
?>
●ストアド内のOracle変数をPHP変数とbindすることで、PHP側で参照できるようになります。
プロシージャ定義
DECLARE
ret INTEGER := 0;
BEGIN
/* 最終的に、PHPでこのretの値を取り出す */
:ret := test(1, 2);
END;
ファンクション定義
CREATE OR REPLACE FUNCTION test(
a IN INTEGER,
b IN INTEGER
) RETURN INTEGER
IS
BEGIN
RETURN (a + b);
END;
OCI8関数の場合、OCIBindByName 関数を使用します。なお、BIND する Oracle 変数は、大文字で記述する必要があるので、注意しましょう。また、LOB・ROWID・BFILEなどのデータ型を BIND する場合、OCINewDescriptor 関数を使用して PHP 変数を定義しておく必要があります
●PHPからストアド内の変数を参照
<?php
$conn = OCILogon( "scott", "tiger", "orcl");
$sql = "begin ";
$sql .= ":ret := test(1,2); ";
$sql .= "end;";
$sql = OCIParse($conn, $sql);
/**
* BINDするOracle変数は、大文字で記述する
*/
OCIBindByName($sql, ":RET" , &$ret, 2);
OCIExecute($sql, OCI_DEFAULT );
echo "ret=$ret";
OCIFreeStatement($sql);
OCILogoff($conn);
?>
改行コードを得る関数
■改行コードを得る
function CR()
{
return "
"; // この改行を詰めるべからず!
}
■文字列中の改行コードを <br /> に置き換え
function CRtoBR( $str )
{
return str_replace( "
", '<br />', $str ); // この改行を詰めるべからず!
}
■文字列中の <br /> を改行コードに置き換え
function BRtoCR( $str )
{
return str_replace( '<br />', "
", $str ); // この改行を詰めるべからず!
}
■文字列中のHTML特殊文字を元に戻す(htmlspecialchars() の逆)
function unhtmlspecialchars( $str )
{
$entry = array_flip( get_html_translation_table( HTML_SPECIALCHARS ) );
return strtr( $str, $entry );
}
function CR()
{
return "
"; // この改行を詰めるべからず!
}
■文字列中の改行コードを <br /> に置き換え
function CRtoBR( $str )
{
return str_replace( "
", '<br />', $str ); // この改行を詰めるべからず!
}
■文字列中の <br /> を改行コードに置き換え
function BRtoCR( $str )
{
return str_replace( '<br />', "
", $str ); // この改行を詰めるべからず!
}
■文字列中のHTML特殊文字を元に戻す(htmlspecialchars() の逆)
function unhtmlspecialchars( $str )
{
$entry = array_flip( get_html_translation_table( HTML_SPECIALCHARS ) );
return strtr( $str, $entry );
}
COOKIE
■ 値を送信する
COOKIE を送信(クライアントのコンピュータに保存)するには、setcookie関数を使います。
setcookie("変数名","値","有効期限")
となります。変数名以外の引数は全てオプションで、さらにオプション引数がありますが、よく使われるのは有効期限までの引数です。
setcookie("count1", $count2, time() + 3600*24*7)
■ 値を得る
クライアントのコンピュータに COOKIE として保存された値は、
$_COOKIE['変数名']
という書式で得ることが出来ます。
$_COOKIE['count1']
COOKIE を送信(クライアントのコンピュータに保存)するには、setcookie関数を使います。
setcookie("変数名","値","有効期限")
となります。変数名以外の引数は全てオプションで、さらにオプション引数がありますが、よく使われるのは有効期限までの引数です。
setcookie("count1", $count2, time() + 3600*24*7)
■ 値を得る
クライアントのコンピュータに COOKIE として保存された値は、
$_COOKIE['変数名']
という書式で得ることが出来ます。
$_COOKIE['count1']
ディレクトリツリーの作り方
PHPの基礎体力さんのとこで知った情報
■ディレクトリを配列に格納した時のイメージ図
<blockquote>
Array
(
[edithead.php] => ./sumple/edithead.php
[conf.txt] => ./sumple/conf.txt
[file.html] => ./sumple/file.html
[strings.html] => ./sumple/strings.html
[data] => Array
(
[template] => Array
(
[file.data] => ./sumple/data/template/file.data
[file.data.bak] => ./sumple/data/template/file.data.bak
[readme.txt] => ./sumple/data/template/readme.txt
)
[log.txt] => ./sumple/data/log.txt
)
)
</blockquote>
■ディレクトリ内のファイル名を獲得するサンプル
<blockquote>
if( $handle = opendir( $dir ) ) // ディレクトリハンドルを獲得
{
while( false !== $file = readdir( $handle ) ) // ファイル名獲得
{
echo $file; // 何らかの処理(ここで配列に格納すれば出来そう)
}
closedir( $handle ); // ディレクトリハンドルを閉じる
}
</blockquote>
■ ディレクトリの場合は、再び同じ処理の繰り返し (再帰関数)
上記の例で、echo $file; の部分を、$dirtree[] = $file; とすれば、ファイル名の一覧を配列に格納できます。これがディレクトリだった場合はどうでしょう。再びディレクトリハンドルを獲得して、readdir() で読み出し、ディレクトリハンドルを閉じるという、まったく同じ処理の繰り返しを行なうことになります。ディレクトリ階層が何段になっているか事前に知ることは出来ませんので、こんな時は「再帰関数」を使用します。
再帰関数とは、関数内で自分自身を呼び出す関数のことです。ディレクトリ内を走査し、ファイルならばファイル名を配列に格納し、ディレクトリだった場合には自分自身を呼び出し、その戻り値を配列に格納するようにします。
<blockquote>
//*****************************************************
// function getdirtree( $dir )
// 指定したディレクトリ以下のファイル一覧を獲得します。
//-----------------------------------------------------
// 引 数:ディレクトリを示す文字列
// 戻り値:ファイル一覧を格納した配列
// 注 意:$dir は、スクリプトから見た相対パスを指定します。
//*****************************************************
function getdirtree( $dir )
{
if( !is_dir( $dir ) ) // ディレクトリでなければ false を返す
return false;
$tree = array(); // 戻り値用の配列
if( $handle = opendir( $dir ) )
{
while ( false !== $file = readdir( $handle ) )
{
// 自分自身と上位階層のディレクトリを除外
if( $file != "." && $file != ".." )
{
if( is_dir( $dir."/".$file ) )
// ディレクトリならば再帰呼出
$tree[ $file ] = getdirtree( $dir."/".$file );
else
// ファイルならばパスを格納
$tree[ $file ] = $dir."/".$file;
}
}
closedir( $handle );
uasort( $tree, "strcmp" ); // uasort() でないと添え字が失われます
}
return $tree;
}
</blockquote>
■ ツリーを表示させる
上記の、getdirtree() で得た配列を、print_r() で表示させただけでは、まだはじめのデータモデル図と同じでかっこ良いツリーではありません。もっとツリーらしく表示させるためには、ツリーらしく表示する処理も必要です。
配列の値を順番に走査し、値が配列ならば再び配列内をそうさする・・・?!これって「再帰」と思った方は正解!この処理も関数化し、再帰呼出を使ってオートマティックに済ませましょう。
あと、ツリーのインデントやアンカータグなどの処理を盛り込んで出来た関数が下のコードです。
<blockquote>
//*****************************************************
// function showdirtree( $tree )
// 配列の中身をツリー状に表示します。
//-----------------------------------------------------
// 引 数:$tree = 表示させる配列
// 戻り値:true=成功、false=失敗
//*****************************************************
function showdirtree( $tree )
{
if( !is_array( $tree ) ) // 配列でなければ false を返す
return false;
static $count = 0; // インデントの階層の深さ
$indent = ( $count ) ? str_repeat( " ", $count ) : "";
$count++;
foreach( $tree as $key => $value )
{
if( is_array( $value ) )
{
// 配列の場合ディレクトリ名を表示し再帰呼出
print( $indent."+ " . $key . "<br>\n" );
showdirtree( $value );
}
elseif( preg_match( "/.*(\.html|\.txt|\.php)$/i", $value ) )
{
// HTMLとTEXTとPHPのみアンカーをつけてファイル名を表示
print( $indent."- " . $key . "<br />\n" );
}
}
$count--;
return true;
}
</blockquote>
・テストコード( tree.php )
<blockquote>
<?php
// 上記関数部省略
// function getdirtree()
// function showdirtree()
$dir = "./sample";
$tree = getdirtree( $dir );
?>
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=Shift_JIS">
<title>ディレクトリ表示:tree.php</title>
</head>
<body>
<p>ディレクトリ:<?php print( $dir ); ?></p>
<?php showdirtree( $tree ); ?>
<hr>
<p>こちらは print_r による表示</p>
<pre><?php print_r( $tree ) ?></pre>
</body>
</html>
</blockquote>
■ディレクトリを配列に格納した時のイメージ図
<blockquote>
Array
(
[edithead.php] => ./sumple/edithead.php
[conf.txt] => ./sumple/conf.txt
[file.html] => ./sumple/file.html
[strings.html] => ./sumple/strings.html
[data] => Array
(
[template] => Array
(
[file.data] => ./sumple/data/template/file.data
[file.data.bak] => ./sumple/data/template/file.data.bak
[readme.txt] => ./sumple/data/template/readme.txt
)
[log.txt] => ./sumple/data/log.txt
)
)
</blockquote>
■ディレクトリ内のファイル名を獲得するサンプル
<blockquote>
if( $handle = opendir( $dir ) ) // ディレクトリハンドルを獲得
{
while( false !== $file = readdir( $handle ) ) // ファイル名獲得
{
echo $file; // 何らかの処理(ここで配列に格納すれば出来そう)
}
closedir( $handle ); // ディレクトリハンドルを閉じる
}
</blockquote>
■ ディレクトリの場合は、再び同じ処理の繰り返し (再帰関数)
上記の例で、echo $file; の部分を、$dirtree[] = $file; とすれば、ファイル名の一覧を配列に格納できます。これがディレクトリだった場合はどうでしょう。再びディレクトリハンドルを獲得して、readdir() で読み出し、ディレクトリハンドルを閉じるという、まったく同じ処理の繰り返しを行なうことになります。ディレクトリ階層が何段になっているか事前に知ることは出来ませんので、こんな時は「再帰関数」を使用します。
再帰関数とは、関数内で自分自身を呼び出す関数のことです。ディレクトリ内を走査し、ファイルならばファイル名を配列に格納し、ディレクトリだった場合には自分自身を呼び出し、その戻り値を配列に格納するようにします。
<blockquote>
//*****************************************************
// function getdirtree( $dir )
// 指定したディレクトリ以下のファイル一覧を獲得します。
//-----------------------------------------------------
// 引 数:ディレクトリを示す文字列
// 戻り値:ファイル一覧を格納した配列
// 注 意:$dir は、スクリプトから見た相対パスを指定します。
//*****************************************************
function getdirtree( $dir )
{
if( !is_dir( $dir ) ) // ディレクトリでなければ false を返す
return false;
$tree = array(); // 戻り値用の配列
if( $handle = opendir( $dir ) )
{
while ( false !== $file = readdir( $handle ) )
{
// 自分自身と上位階層のディレクトリを除外
if( $file != "." && $file != ".." )
{
if( is_dir( $dir."/".$file ) )
// ディレクトリならば再帰呼出
$tree[ $file ] = getdirtree( $dir."/".$file );
else
// ファイルならばパスを格納
$tree[ $file ] = $dir."/".$file;
}
}
closedir( $handle );
uasort( $tree, "strcmp" ); // uasort() でないと添え字が失われます
}
return $tree;
}
</blockquote>
■ ツリーを表示させる
上記の、getdirtree() で得た配列を、print_r() で表示させただけでは、まだはじめのデータモデル図と同じでかっこ良いツリーではありません。もっとツリーらしく表示させるためには、ツリーらしく表示する処理も必要です。
配列の値を順番に走査し、値が配列ならば再び配列内をそうさする・・・?!これって「再帰」と思った方は正解!この処理も関数化し、再帰呼出を使ってオートマティックに済ませましょう。
あと、ツリーのインデントやアンカータグなどの処理を盛り込んで出来た関数が下のコードです。
<blockquote>
//*****************************************************
// function showdirtree( $tree )
// 配列の中身をツリー状に表示します。
//-----------------------------------------------------
// 引 数:$tree = 表示させる配列
// 戻り値:true=成功、false=失敗
//*****************************************************
function showdirtree( $tree )
{
if( !is_array( $tree ) ) // 配列でなければ false を返す
return false;
static $count = 0; // インデントの階層の深さ
$indent = ( $count ) ? str_repeat( " ", $count ) : "";
$count++;
foreach( $tree as $key => $value )
{
if( is_array( $value ) )
{
// 配列の場合ディレクトリ名を表示し再帰呼出
print( $indent."+ " . $key . "<br>\n" );
showdirtree( $value );
}
elseif( preg_match( "/.*(\.html|\.txt|\.php)$/i", $value ) )
{
// HTMLとTEXTとPHPのみアンカーをつけてファイル名を表示
print( $indent."- " . $key . "<br />\n" );
}
}
$count--;
return true;
}
</blockquote>
・テストコード( tree.php )
<blockquote>
<?php
// 上記関数部省略
// function getdirtree()
// function showdirtree()
$dir = "./sample";
$tree = getdirtree( $dir );
?>
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=Shift_JIS">
<title>ディレクトリ表示:tree.php</title>
</head>
<body>
<p>ディレクトリ:<?php print( $dir ); ?></p>
<?php showdirtree( $tree ); ?>
<hr>
<p>こちらは print_r による表示</p>
<pre><?php print_r( $tree ) ?></pre>
</body>
</html>
</blockquote>
汚染された GET・POST・COOKIE
PHPの基礎体力さんのとこで知った情報
GET・POST・COOKIE は、クライアントから送られてくるデータなのでちゃんとチェックしましょうとのこと。
<blockquote>【対策】改ざんされて困るデータは、クライアントに渡さないことです。上記買い物カゴの場合ならば、フォームからは、商品コード・数量・カラーなどの情報だけを受け取り、クッキーやセッション変数に保存しておき、発注処理の際、データベースなどにある価格を参照するといった処理にする必要があります。
【対策】クライアントから来る値を直接SQL文に使わない。適当な値かどうか、必ず最低限の確認を行なうことで、このような攻撃を防ぐことが出来ます。上記の例ならば $_POST['bnumber'] を SQL文に使用する前に、preg_match("/^[0-9]+$/", $_POST['bnumber']) で、数字がどうか確認するべきです。
</blockquote>
GET・POST・COOKIE は、クライアントから送られてくるデータなのでちゃんとチェックしましょうとのこと。
<blockquote>【対策】改ざんされて困るデータは、クライアントに渡さないことです。上記買い物カゴの場合ならば、フォームからは、商品コード・数量・カラーなどの情報だけを受け取り、クッキーやセッション変数に保存しておき、発注処理の際、データベースなどにある価格を参照するといった処理にする必要があります。
【対策】クライアントから来る値を直接SQL文に使わない。適当な値かどうか、必ず最低限の確認を行なうことで、このような攻撃を防ぐことが出来ます。上記の例ならば $_POST['bnumber'] を SQL文に使用する前に、preg_match("/^[0-9]+$/", $_POST['bnumber']) で、数字がどうか確認するべきです。
</blockquote>
session_register()と[戻る] ボタン
すいません。どこで見かけた文書か失念したのですが、勉強になったので。
また思い出したら参照元をご紹介させていただきます。
<blockquote>
session_register() と、確認画面の "ブラウザの [戻る] ボタンで戻って修正してください" という常套手段は 相性が悪い。一度戻った画面で修正しても、session_start() や session_register() を呼び出した瞬間に、 前のデータのほうで上書きされてしまうからだ。
php.ini の variables_order と GPC_ORDER の両方を C が G の前に来るように書き換えて apachectl restart してみたが、やはり上書きされてしまう。
そのあと、一度マシンを落として再起動。つまり Apache に ついても 終了, 再起動をしてみたら session 関数を呼び出した 瞬間に前の値でグローバル変数を上書きする、 という現象を回避することができたように思う。(???)
日本語の自動変換がうまくいっていないようなのと、 本当に回避できたのか、再現するのではないか、という心配から 一度 session_register したグローバル変数に $HTTP_GET_VARS 配列から、文字コードを変換 しながら代入する、という PHP らしからぬ 真似をすることに決めた。
</blockquote>
また思い出したら参照元をご紹介させていただきます。
<blockquote>
session_register() と、確認画面の "ブラウザの [戻る] ボタンで戻って修正してください" という常套手段は 相性が悪い。一度戻った画面で修正しても、session_start() や session_register() を呼び出した瞬間に、 前のデータのほうで上書きされてしまうからだ。
php.ini の variables_order と GPC_ORDER の両方を C が G の前に来るように書き換えて apachectl restart してみたが、やはり上書きされてしまう。
そのあと、一度マシンを落として再起動。つまり Apache に ついても 終了, 再起動をしてみたら session 関数を呼び出した 瞬間に前の値でグローバル変数を上書きする、 という現象を回避することができたように思う。(???)
日本語の自動変換がうまくいっていないようなのと、 本当に回避できたのか、再現するのではないか、という心配から 一度 session_register したグローバル変数に $HTTP_GET_VARS 配列から、文字コードを変換 しながら代入する、という PHP らしからぬ 真似をすることに決めた。
</blockquote>
グローバル変数のメモ
ユーザー入力を格納するためのグローバル変数
$_POST POSTされたFORM変数
$_GET GETされたFORM変数
$_COOKIE Cookie
$_SERVER SERVER変数
$_ENV 環境変数
$_REQUEST GET、POST、Cookie
$_SESSION SESSION変数
<blockquote>Win32用バイナリにmbstringが追加されました。これにより日本語が使いやすくなるかもしれません。ただし、ソースコードをSJISで書いた場合の問題が解消されるわけではありません。文字コード変換や半角全角変換などがjcode.phpを使わずにできるようになります。
</blockquote>
$_POST POSTされたFORM変数
$_GET GETされたFORM変数
$_COOKIE Cookie
$_SERVER SERVER変数
$_ENV 環境変数
$_REQUEST GET、POST、Cookie
$_SESSION SESSION変数
<blockquote>Win32用バイナリにmbstringが追加されました。これにより日本語が使いやすくなるかもしれません。ただし、ソースコードをSJISで書いた場合の問題が解消されるわけではありません。文字コード変換や半角全角変換などがjcode.phpを使わずにできるようになります。
</blockquote>
初滑り
今日は今期初ボードに、ウイングヒルズというところへ行ってきました。
Tシャツ本舗さん店主氏主宰のボードツアーです♪
いやー楽しかったぁ。やっぱりボード最高!Tシャツ本舗最高!!
店主どうもありがとうございました、また行きましょう。
腕が筋肉痛でキーボードが打てないのでこの辺で。
■Tシャツ本舗さん
Tシャツ本舗さん店主氏主宰のボードツアーです♪
いやー楽しかったぁ。やっぱりボード最高!Tシャツ本舗最高!!
店主どうもありがとうございました、また行きましょう。
腕が筋肉痛でキーボードが打てないのでこの辺で。
■Tシャツ本舗さん
友情はいいなぁ
あの夜消えた火、つけた火。
全米が泣いたつД`)・゚・。・゚゚・*:.。
どう頑張ってもかなわぬ恋ってありますよね。でもそういうの自分で立ち直るものなんでしょうけど、そのとき友達か居てくれたら本当にありがたいっす。
isi
全米が泣いたつД`)・゚・。・゚゚・*:.。
どう頑張ってもかなわぬ恋ってありますよね。でもそういうの自分で立ち直るものなんでしょうけど、そのとき友達か居てくれたら本当にありがたいっす。
isi