ふと$_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なんだろうと思う。たかがそれだけの事だが、されどそれだけの事だった。
一応メモ書きであぁ~るっ。
PHP だけの言語を用いて、JavaScript Cookie session データベース使用無しのリロード対策作りました。
GET でアドレス後から付け加える方法も無しで、POST情報だけで実現しています。
やり方は、自分のページのAは描画をPHPで行う最に、自分のページA内に
任意のPOSTデータを含む情報を持つページAの形をした別物A’を読む、
そのA'はPOSTデータだけが違うという物。
つまり自分自身の分身A’を読み込んでPOSTデータ処理させる。
以下で説明するスクリプトの場合、初回と同様になる様に
空のデータを0扱いする様にしてあり、処理される。
私のブログにしては妙に短いのはお酒を・・・いるからですw(朝じゃん・・・・)
さてもう眠いですが、うれしさも何も無く酔い・・・いや、軽く頭が軽い状態で、
プログラムを組んでいた訳なんですが、そのソースを惜しげもなく(無様な汚いコードですw)
ここにメモ書きとして掲載しようじゃないか>w<;(早く寝たいですw)
さて、もとい。
ブラウザの違いとか検証は、いい加減にやってみました。(何度も言いますが眠いですw)
Internet Explorer 8 と、 Mozilla Firefox 3.6.17 そして、Safari 5.0.5(7533.21.1 ) ですが、
なぜか私の場合以下のファイル名がフルパスで
http://localhost/flipflop_reload_protect.php
なのですが、Safari だけは最後に / を追加した
http://localhost/flipflop_reload_protect.php/
とアドレス入力に入力しなければ初回の画面が見られませんでした。
Safari の意味不明な仕様に驚き、良いブラウザハックの拾い物をした!と思いつつ?
時間も時間なので次に進みたいと思いますw
では本ソースです。
<?php
header('Content-type: text/html; charset=UTF-8');
echo '前のPOSTだよ!';
var_dump($_POST);
if(!$_POST['flipflopProtect'])
{
echo '0の時だけ<br/><br/>';
//POSTデータ
$originalPOST = array(
'flipflopProtect' => !(boolean)$_POST['flipflopProtect'],
'count_submit' => 1 + (integer)$_POST['count_submit']
);
$mergePOST = array_merge($_POST,$originalPOST);
$contentData = http_build_query($mergePOST, "", "&");
//header
$header = array(
"Content-Type: application/x-www-form-urlencoded",
"Content-Length: ".strlen($contentData)
);
$context = array(
"http" => array(
"method" => "POST",
"header" => implode("\r\n", $header),
"content" => $contentData
)
);
$url = "http://localhost/flipflop_reload_protect.php";
echo file_get_contents($url, false, stream_context_create($context));
die();
}
?>
/* 本文(ホームページなど) */
うんたらうんたら・・・
<?php echo "<br/>\$_POST['flipflopProtect']がずっとブラウザ内では1なんですよ! 実際の値:" . $_POST['flipflopProtect'] ?>
<form id="reloadBlock" method="POST" action="<?php echo $_SERVER['REQUEST_URI'] ?>">
<input type="hidden" name="flipflopProtect" value="0" />
<input type="hidden" name="count_submit" value="<?php echo $_POST['count_submit']?>" />
<input id="submitBottun" type="submit" value="<?php echo $_POST['flipflopProtect']==1?'プロテクト中':'何処かにバグ' ?>" />
</form>
こんな感じでした。
簡単に説明すると
POSTデータの$_POST['flipflopProtect'] は、開始直後はstringでは''で、
これは数値式のinteger で表せば0です。
その0か''の時だけ、自分自身を参照しに行き、
その処理の時に$_POST['flipflopProtect'] を1にしてプロテクトをかけ、
リロード出来ない状態にして、リロードしても処理しない部分を作り上げています、
つまり自分自身にPOSTする処理を無くしています。
そんな感じで見栄えは一緒、でもPOSTデータの内容が違うと言うとてもとても危なげで
奇想天外な事をしています。
これは本当に苦肉の策みたいな物なので、
Webページとしての描画内容はPHPのそのリロードプロテクトの後に
書いている状態なので、その辺を一まとめにするかとか、
色々他のPHPスクリプトを付け加えて実践的にすると
どんな感じになるかとかまでは書いていません
(お酒飲んでいるから早くブログを書き終えたいですw朝ですしw)。
そんな感じです<_ _>
一応ですが書くとすると自身が表示させたい下部の
/* 本文(ホームページなど) */
と書いている部分以降に
if(!$_POST['flipflopProtect']){ ~~~~~ }
この ~~~~~ にリロード時に処理させたくない内容を入れればいいんです。
別に1ページのソース内に細切れに<?php そのソース ?>でいいと思うんです。
そんな感じで今回のメモは終わりにしたいと思います。
お酒入っているので、見直しは後ほどにします。
お休みっ! ^v^ノシ
追伸:(結構ウェイト大きいです)
なんかやはり、自身を参照している部分が不可思議な表示です。
推測ではキャッシュしている部分とPHP内部で計算してしまう部分と両方を用いて
描画しているのではないかと思います。
以下の修正変更したソースのカウントが動いてしまうのがその良い例です。
A=自身 A’=自身を呼び出した物とします。
また実はAとA'の両方にPOSTメッセージは存在し、別々に処理されています。
この当りもややこしいです。
そしてA'内部からAのグローバル変数やAのPOSTデータは操作できません。
書籍などには無い、不思議なブラウザとサーバ処理(ApacheやPHPの挙動)が見え隠れします、
環境に依存する可能性もあるので気をつけてください。
とりあえず初回もカウントしない様にして、内部の時間も数値化してみました。
A'の描画が不思議であるのがわかると思います。
/* 本文(ホームページなど) */
うんたらうんたら・・・
<?php echo "<br/>\$_POST['flipflopProtect']がずっとブラウザA内では0か''なんですよ! 実際の値:[" . $_POST['flipflopProtect'] . "]" ?>
<form id="reloadBlock" method="POST" action="<?php echo $_SERVER['REQUEST_URI'] ?>">
<input type="hidden" name="flipflopProtect" value="1" />
<input type="hidden" name="count_submit" value="<?php echo $_POST['count_submit']?>" />
<input id="submitBottun" type="submit" value="<?php echo $_POST['flipflopProtect']==1?'何処かにバグ':'プロテクト中' ?>" />
</form>
<?php echo var_dump($_POST) ?>
'<br/>リロードブロックと初回だけのはずなのに!<br/><br/>' って所が、カウントした場合でも表示されています。
このIF文はどちらかしか動かないからIFなのですが・・・
IFでそうであった場合と、そうでなかった場合、両方の結論が出てしまう様に見える!
キャッシュやインスタンスなどの絡みと読み込みの絡み、AとA'の関係から、
結果的にブラウザの持つAの変数操作はされている様な挙動を
かろうじて実現出来ている様ですが、実際の絡みが不明な為、
よーく考えて使うべきです。
私はフォームメールに実装しようと思います。
A'内で処理する部分にブラウザへの描画関数は用いない方が無難だと思います。
それはキャッシュやインスタンス内の何かをAで妙な反映をさせない対策になると思います。
Aはブラウザで表示できる物全ての処理をし、
A'は間違っても表示処理を入れない方が良いと言うことです。
多分・・・・それが無難で一番良い方法になると思います^^;
以上長ーーーーーいメモでした<_ _>
さて、長い何時もの様に前置きから、
読むのが面倒な人は<本題>から読んでね!
それでももっと面倒な人は<結論>だけ見てね!
では以下長々と・・・
プログラミング言語の多くのマニュアルを書いた人は
プログラミング言語を作った人本人であろうとなかろうと
どうも全部羅派し忘れている節がある。
私もそうだが作ることの方がメインで、説明をしたりするのがサブ的な役割に
なってしまうこともある、それはモチベーションや目的、立場によって変わるのだろう。
物事を追求しなければ物事が解決できないとして、
疑問を持って追求しているのは暇人だからではない、
性格もあるとして、それをしなければ先に進まないからだ。
そして案外疑問に思ってもやってみていないことってある。
しかしその疑問を解決する事が、プログラミング言語と言う道具を使う方法が
上手くなる方法であるのも現実として間違えなく、
それこそが私は「ノウハウ」と言うのだと思う。
一見オタク要素満載であるが、職人気質な人はオタク要素があるのか、
それともオタク要素がある人は職人気質なのか、結局極めることと興味を持つことは
紙一重であり、続けなければもったいない事だと思う。
たとえ周りが色を付け、理解しなくとも気にする事も余り無いのかもしれない。境遇にもよるが。
私の部屋に貼ってあるメモ書き、戒めと言うかモチベーションの向上の為に貼ってある言葉がある。
「考えていても
やってみなければ
実感できないよ」
まぁ、考えることの割合が多く、実際にやってみる事の方が後になる私にはぴったりな文句。
今回も思ったらすぐにしてみれば終わる話だったのだが、その悪い私らしい所が
結果的にこのブログと成っている。このブログの99%は迷い悩みから生まれた物ですw(当社比率100%)
で、何について疑問に思って、今回は何を述べたいのか?
以下本題に入ります。
<本題>
PHP でMySQL を用いる時に、PDO を使った場合、データベースの操作、DMLについては
簡単に説明が見つかる、しかしDDLについては説明がない。
PDO をPHP公式のマニュアル を見る限り、どう見ても初めからMySQL のルート権限で
MySQL に接続してデータベース本体を作ったり、権限を操作する関連の説明を簡単に見つけられない。
唯一見つけたのは、ログインした後でDDLを操作する説明が、
MySQL 関数 (PDO_MYSQL)
これを読んでいると、一度データベース選択と共に接続しDMLが操作できる状況になった上で、
DDLのクエリーを発行すれば良いと書いてある気がする。
しかしこれでは、落ち度があるのだ。
もしMySQL に操作できるデータベースが1つも無かった場合には、ログイン出来ない様に感じてしまう。
つまりPDOでは空っぽのMySQL にログインしてデータベースを名前を付けて1から構築して
いくスクリプトは書けないんじゃないか?と思わせてしまう。
それはこの公式マニュアルの何処に原因があるのか?
それはこの説明
PDO::__construct と接続、および接続の管理にあるパラメータdsn の説明不足に問題がある。
<結論>
PDO のデータベース接続インスタンスの生成方法で
一見DML用途にしか接続インスタンスを生成出来ない様に見えるが、
実際はdsnパラメータはPHP公式マニュアルにかかれていない省略形の形を用いると
DDLを初めから操作できる。
例えばPHP公式マニュアルなどや他のサイトには、
dsnパラメータはこの以下2つのどちらの書き方でも使えるが、
データベースサーバへ接続するときにデータベース名が省略していいかどうか書いていない。
dsnの例
'mysql:dbname=testdb;host=127.0.0.1'や
'mysql:host=127.0.0.1;dbname=testdb'
である。
これは元々データCスに'testdb'が存在しているのが前提である。
しかし全く空な場合の使い方がかかれていない。
これを試しにdbname=testdbなしに記述し、ルートの名前とパスワードでMySQLに接続してみた。
そして'CREATE DATABASE PDO_sample_db'というクエリーを発行して確認してみた。
そうするとDDLの操作がMySQL(データベースサーバ)に接続した直後から何も意識せずにDDLが使える。
つまり
上の例で言えば、dbname=testdbなしにした
'mysql:host=127.0.0.1;'
をdsnに指定すれば、データベースを指定しない形でログインできた。
勿論ルート権限のIDとパスワードで試した。
<?php
$user='rootxxx';
$pass='passxxx';
$dsn='mysql:host=localhost;';
//DDL操作を念頭に入れない場合はいきなり以下の様に前に用意したデータベースを指定すれば良い
//$dsn='mysql:host=localhost;dbname=test';
try {
$dbh = new PDO($dsn, $user, $pass);
//データベースを作る
$dbh->query('CREATE DATABASE PDO_sample_db');
foreach($dbh->query('show databases') as $row) {
print_r($row);
echo '<br>';
}
$dbh = null;
} catch (PDOException $e) {
print "エラー!: " . $e->getMessage() . "<br/>";
die();
}
?>
さてさて、毎回Web上にある設定の変更できないレンタルのサーバの環境とローカル環境の違いを把握して・・・どうのこうの・・・
みたいなややこしいことをしてきた結果、当たり前であろう事により一段と近づく結論が浮かんだ。
それは「設定の修正が効かない側のサーバ(レンタルサーバ)の環境に極力ローカルの開発環境も整える」こと。
という結論が出た、とても当たり前と言えば当たり前だ・・・。
文字化け以外にも、文字カウントを失敗するないていうことが、
デフォルトの 内部文字エンコーディング ->mbstring.internal_encoding (php.ini内)
や
関数で指定した内部文字エンコーディング ->mb_internal_encoding 関数
によって起こる事が判明した。
まず、この結論にたどり着くまでに気がついた事柄を述べる。
<まずテストする為のソースコード>
<?php
$string = '内部文字エンコーディング環境のTESTです!'.mt_rand(0,9).mt_rand(0,9).mt_rand(0,9);
// 文字の長さの検出の色々な仕方
var_dump(strlen($string)); //内部文字エンコーディングが違う環境に依存しない(バイト数)
var_dump(mb_strlen($string)); //内部文字エンコーディングが違う環境に確実に左右される
var_dump(mb_strlen($string ,'UTF-8')); //内部文字エンコーディングが違う環境に依存しにくい
?>
これを参考に以下、1. 2. 3. を見てもらえば判ると思う。
1.文字数をカウントする計算式に狂いが生じる。
内部エンコーディング:ISO-8859-1
と
内部エンコーディング:UTF-8
では部分的に違う出力結果になる。
内部エンコーディング:UTF-8 の場合、上から答えが int 61、 int 25、 int 25 となる。
内部エンコーディング:ISO-8859-1の場合、上から答えが int 61、 int 61、 int 25 となる。
2.カウントしたい文字列が1文字が1バイト以上の文字である場合には、
文字数カウントに使えない関数がある。
つまりこの例のスクリプトの場合は、
var_dump(mb_strlen($string)); //内部文字エンコーディングが違う環境に依存しない
がバイト数でしか文字列がカウントできないです。
そしてまた、文字としてカウントできるとしても、正しい文字エンコーディングを指定していない場合、
存在しない文字を他の文字に読み違えたりして間違って文字を認識したりした結果、
文字数が変わってしまうのが、
var_dump(mb_strlen($string)); //内部文字エンコーディングが違う環境に確実に左右される
です。
また、内部エンコーディングを指定して文字数をカウントさせているので、一番文字数のカウント間違えが
少ないと思われる、
var_dump(mb_strlen($string ,'UTF-8')); //内部文字エンコーディングが違う環境に依存しにくい
ですが、
依存しにくいと書いているのは、保存形式によって保存された文字が
本当に指定したコードで文字を間違えて文字化けなどをせずに解釈できるのかどうかの
テストは今回行っていないからです。
3.サーバの環境によってデフォルトの設定があるので、
文字数カウントの関数の引数が任意であっても指定した方が環境が変わっても、
スクリプトが同様に動く可能性が高くなる。
// 文字の長さの検出の色々な仕方
var_dump(strlen($string)); //内部文字エンコーディングが違う環境に依存しない
var_dump(mb_strlen($string)); //内部文字エンコーディングが違う環境に確実に左右される
var_dump(mb_strlen($string ,'UTF-8')); //内部文字エンコーディングが違う環境に依存しにくい
?>