久しぶりにメモ。
今回のメモは、PHPのeval 関数を用いて、
eval関数で読み込む内容にスクリプト自体を書き、
PHPで処理させる事が書かれている。
勿論eval関数は、
引数にスクリプトを与えると処理するという代物であるので、
何の変哲も無い、当たり前の事だと感じると思う。
しかし、引数に与える内容を、外部に書かれたファイル
丸々を読み込んで自身に取り込み処理させることが出来るのです。
これは普通に皆が使っている使い方なのだろうか?
基本的に危険を感じて使わないのか、思いついてはいないのではないか?と
思った。
また、その上記な様な使い方をするなら、
include系の関数を使えば良い気がするが、
それらと違い何時でも好きな時に好きなスクリプトを
読み込み、実行した状況を作り出せる。
今回私がなぜこの関数を使おうと思ったか?
それはPHPのスクリプトソースが書かれたファイルにも
エンコードがあり、それを解釈するにもエンコードがある。
Webブラウザで表示するコードにPHPのスクリプトソースも合わせたとしても
データベースから吐き出させるスクリプトコードをどう処理するかなど、
考えなければいけないことと・・・・・①
もしファイルを作りバイナリなどのデータを保存したとしても、
それを今度読み込むときに変数に読み込む処理を書かなければいけない・・・・・・②
レンタルサーバなどの休めのサーバはデータベースを複数持てないので
クラッシュした場合に困ったり、複数ないと使い勝手やパフォーマンスに困る気がする・・・・・・③
これらの理由が大きく、よく考えてみた所、
PHPのソースごとデータとして保存することを思いついた。
つまり、arrayなどや、いろいろな型をそのまま変数にPHPスクリプトを書いて保存して、
それをeval 関数で読み込めば、保存したソース内で指定した変数に値が保存される。
つまり元のソースに存在したかの如く、変数にデータが代入される。
以下2つのソースがサンプルです。
片方は、私が勝手に付けた拡張子です。podという拡張子なのは
PHP of DATA のつもりで付けました、そんな勝手に付けた拡張子なので
後から好きに変えてもらって問題ないです。
同じディレクトリに2つのファイルを置いて下さい。
同じ文字コードで書かれていて、同じ文字コードで解釈される様に設定しておいでください。
尚、PHP of DATA(仮称)側の文字列を作成するスクリプトは
特に載せてないですが、PHPスクリプトを書く要領で記述し、エスケープするPHPスクリプトを
考えて書いて、中の変数部分に好きなデータが埋め込める様にするだけだと思います。
注意点は、元のソースには何処からこの変数は記述があるのか?
と思ってしまうと思うので、その当りを気をつければ良いと思います。
適当なソースですが、参考にどうぞ。
ファイル名:<array_string.dop> 以下中身
ファイル名:<php_of_data.php> 以下中身
<?php
$stringVal=<<<'hereDocument'
$arrayString=array('a'=>123,'b'=>555);
hereDocument;
eval($stringVal);
echo 'test';
var_dump($arrayString);
echo $arraystring;
echo $stringVal;
echo '<br/>file data php read<br/>';
$dop=file_get_contents('array_string.dop');
eval($dop);
echo $dop;
var_dump($filedata);
var_dump($filedata2);
?>
結果
array 'a' => int 123 'b' => int 555
$arrayString=array('a'=>123,'b'=>555);
file data php read
$filedata=array('a'=>777,'b'=>567); $filedata2=array('a'=>333,'b'=>789);
array 'a' => int 777 'b' => int 567
array 'a' => int 333 'b' => int 789
最後に追加の注意点ですが、evalで読み込ませる内容の元であるファイルは、データが内臓されたPHPスクリプトを作成のソース(私が言うpod拡張子)で一定の場所以外は書き込めない様なプロテクト対策が必要だと思います。つまり得体の知れない他のWebに吐き出したり、ユーザーが見ているブラウザに情報を吐き出す可能性があるスクリプトは危険です。 また、内部のデータも同様に、得体の知れないアドレスなどを保管するのは危険です。つまりWeb上の外部のアドレス先は、何時コンテンツが変更になるかわからないので、それらも理解した上で、Web上の外部のアドレスなどを保管するべきです。何にそのアドレスを使うのか、発想が変わった時には危険ですから。 また、データが内臓されたPHPスクリプトを作成のソース(私が言うpod拡張子)は Linux上などであればアクセス制限を施すべきです。ファイルが毎回新たな予測不可能なファイルネームで新規に作成される場合などは、しっかりchmod などでアクセス権限を変更するべきです。 そしてまた、大事な情報であれば、apacheのhtdocs直下などでWebページからアクセス出来る様なそんな場所で使うべきではありません。 こんな感じです。今回は短いメモでした<_ _>
追伸:
include とかでもファイルは読み込めるのと、
phpのserialize 関数もあるので、
特定のPHPソースとして残したい用途以外は
こんな使い方をしなくても良いかもです。
PHPのソースを吐き出すPHPのプログラムを作るのならば話は別ですが^ー^
したいこと | 知りたい型 | 知りたい値 |
- | 不明 | 不明 |
Falseと0を別扱いしたい | 不明 | 判る |
型が作られたら値0だと判断させたくない | 判る | 不明 |
- | 判る | 判る |
結局色を変えた2種類の事柄が知りたいが為に
isset() とempty() の関数を使うのだと思う。
ぶっちゃけ、ネットで色々調べるが、
最終的に解決できるであろう場所はココにある
公式マニュアルのPHP 型の比較表だ。
そして何よりもNULL とは何なのか?
これも公式マニュアルのNULLにも
その事柄が書いてある。
確かにその通りなのであるが、
しかし、これだけでは実感できない。
特に私の場合には配列の中身の扱いが不安である。
なので少し実験してみた。
以下ソース
---------------------------------------------------------------
<?php
header('Content-type: text/html; charset=UTF-8');
echo 'いきなりx</br>isset:'. (isset($x)?'何かある':'空') . ' empty:'. (!empty($x)?'何かある':'空') . '</br></br>';
var_dump($x);
echo '配列として見る</br>issetx[0]:'. (isset($x[0])?'何かある':'空') . ' empty:'. (!empty($x[0])?'何かある':'空') . '</br></br>';
var_dump($x);
$x[10]=0;
echo 'いきなりx[10]に0を代入</br>isset[10]:'. (isset($x[10])?'何かある':'空') . ' empty:'. (!empty($x[10])?'何かある':'空') . '</br></br>';
var_dump($x);
$x=0;
echo 'xに0を代入</br>isset:'. (isset($x)?'何かある':'空') . ' empty:'. (!empty($x)?'何かある':'空') . '</br></br>';
var_dump($x);
$x=array();
echo 'xを配列宣言</br>isset:' . (isset($x)?'何かある':'空') . ' empty:'. (!empty($x)?'何かある':'空') . '</br></br>';
var_dump($x);
$x[0]=0;
echo '配列xの[0]に0を代入</br>isset:' . (isset($x)?'何かある':'空') . ' empty:'. (!empty($x)?'何かある':'空') . '</br></br>';
var_dump($x);
$x[0]=1;
echo '配列xの[0]に1を代入</br>isset:' . (isset($x)?'何かある':'空') . ' empty:'. (!empty($x)?'何かある':'空') . '</br></br>';
var_dump($x);
$x[1]=1;
echo '配列xの[1]に1もを代入</br>isset:' . (isset($x)?'何かある':'空') . ' empty:'. (!empty($x)?'何かある':'空') . '</br></br>';
var_dump($x);
unset($x[0]);
echo '配列xの[0]だけunset</br>isset:' . (isset($x)?'何かある':'空') . ' empty:'. (!empty($x)?'何かある':'空') . '</br></br>';
var_dump($x);
unset($x);
echo 'x全てをunset</br>isset:'. (isset($x)?'何かある':'空') . ' empty:'. (!empty($x)?'何かある':'空') . '</br></br>';
var_dump($x);
echo ($x?'true':'false');
?>
---------------------------------------------------------------
以下結果:
---------------------------------------------------------------
いきなりx
isset:空 empty:空
null
配列として見る
issetx[0]:空 empty:空
null
いきなりx[10]に0を代入
isset[10]:何かある empty:空
array 10 => int 0
xに0を代入
isset:何かある empty:空
int 0
xを配列宣言
isset:何かある empty:空
array empty
配列xの[0]に0を代入
isset:何かある empty:何かある
array 0 => int 0
配列xの[0]に1を代入
isset:何かある empty:何かある
array 0 => int 1
配列xの[1]に1もを代入
isset:何かある empty:何かある
array 0 => int 1 1 => int 1
配列xの[0]だけunset
isset:何かある empty:何かある
array 1 => int 1
x全てをunset
isset:空 empty:空
null
false
---------------------------------------------------------------
結果
まず関係の無いことかもしれないが、
PHP では
型宣言されていないなんらかの変数を
配列として中身を初めて見ても、
その後から配列として型宣言された扱いとなったりはしない。
当たり前と言えば当たり前なのだが、
案外インスタンス関係はややこしく仕様が介入するので、
もしや?!なんて思ってしまうことがあるので、
これは収穫だったと思えた。
次に型の有無、これは型があり、値が使われていなければ
Emptyになると配列では証明された。
配列のEmptyは全く持って0 やFalse と変わらない、
その為型宣言後なのかだけを調べることはisset 関数でもempty 関数でも出来ない。
Emptyでは0やfalse 以外かどうかしかわらない、名前は空(empty)とと言う名称なので
型判断に思えてしまうので、毎回考えてしまうが、値が0やfalse以外かどうかしか確認できない。
つまり、結局値では0が代入されたりfalse だったりすればempty 関数ではTlue を返す。
empty関数が空であるtlue を返すのは型が宣言されていない時、0やfalse、empty の時。
※分かりにくいので ! をつけた !emptyとして使ったほうが理解しやすい場合もある、私の例題ではそうしている。
そしてisset関数が空であるFalse を返すのは
型が設定されていない時以外は結果的に全て返す。
また、0であってもfalseであっても型があればTlue を返す。
(isset関数で複数を同時に検査した場合、一つでもfalse判定であると、isset関数はfalseを返すので
それには注意が必要。)
型 | 値(x) | !empty(x) | isset(x) |
有 (例ではarray) |
0,false,empty | false | true |
0,false,empty以外 | true | true | |
無(NULL) | NULL(値として比較すると0,false,emptyに相当) | false | false |
一応参考のソースと結果を載せておく。
<?php
header('Content-type: text/html; charset=UTF-8');
echo (NULL==false?'NULL==false 同じ':'NULL==false 違う') . '</br>';
echo (NULL==0?'0==false 同じ':'0==false 違う') . '</br>';
echo (NULL===false?'NULL===false 同じ':'NULL===false 違う') . '</br>';
echo (NULL===0?'0===false 同じ':'0===false 違う') . '</br>';
?>
------ 結果 -------
NULL==false 同じ
0==false 同じ
NULL===false 違う
0===false 違う
当たり前であるが、NULLと型が一致するのはNULLしかない。
結論:
型チェックと数値チェックを混同しがちなisset関数と
!をつけた方が理解しやすい!empty関数、
これらを使い数値のチェックをするのは良いが、
型が存在するかなどは、配列に使えば話が変わる様に、
配列であるかなどのチェックが必要な場合がある。
型をチェックするのであれば、
is_array関数を用いるべきであり、
他の型をチェックするのには
is_から始まる 変数操作関数を使うべきである。
isset関数はNULL型かどうかの比較機能もつけた!empty関数だと
思えば良いのかもしれないが、実際はNULL型(値)との比較をするか、
is_null を使った方が良い場合もある。
特に細かく型を判定した方が良い場合などは
isset関数を使ってしまうよりは良いかもしれない。
そもそも紛らわしいのは、empty関数が空である場合をTrueとしていることである。
なので! をつけて !emptyとして使わなければいけないので、
これとisset関数の使い勝手を比較するのはとてもややこしく思えるのでした。
また、isset関数は、多くの引数を使い、多くの引数の中で1つでもisset関数で
falseな場合には1つでもTrueがあったとしても関数はfalseを返すので、
多数の変数全体の判断に使うのだと思います。
以上、長ぁーーーいメモでした<_ _> (かなり前回の編集が適当だった為、書き直してあります。)
ふと$_SERVER['SCRIPT_FILENAME']はPHP の説明によると
「現在実行されているスクリプトの絶対パス」と書いてあるので
読み込んでいるスクリプト内で使われているなら、
読込先のフルパスが帰ってくるのか?
疑問に思ったのでやってみた。
include()
include_once()
require()
require_once()
などで呼び出している中で$_SERVER['SCRIPT_FILENAME']を使ってみた。
以下、
--------------------------(読み込むスクリプト)--------------------------
script_name.php
------------------------------------------------------------------------------
<?php
function scriptArea(){
return $_SERVER['SCRIPT_FILENAME'];
}
?>
--------------------------(直接始めに実行するスクリプト)--------------------------
script_area_test.php
------------------------------------------------------------------------------
<?php
include_once "script_name.php";
echo "includeエリア:" . scriptArea() . "</br>";
echo "そのままエリア:" . $_SERVER['SCRIPT_FILENAME'];
?>
--------------------------実行結果--------------------------
includeエリア:C:/hogehoge/script_test_area.php
そのままエリア:C:/hogehoge/script_test_area.php
--------------------------結論--------------------------
実行しているスクリプトの名前であって、
読込先のスクリプト内を表示することは出来ない。
あくまでサーバが最初に処理し始めたスクリプトの
名前を返す様だ。
セキュリティーからすれば外部からの見通しがきかなくなる点では安全かもしれないが、
読み込みスクリプトのパスを欲している場合に、この方法で取得出来ないということみたいだ。
それもそのはず、結果からみた予想ではあるが、処理開始始めに決定される変数が
$_SERVERなんだろうと思う。たかがそれだけの事だが、されどそれだけの事だった。
一応メモ書きであぁ~るっ。