このエントリーをはてなブックマークに追加
スポンサーリンク

PHP入門

PHPの特徴

PHP言語は、ウェブサイト上で動的ページを生成することができます。動的ページといっても、PHPはJavaScriptのような端末側で処理させるのではなく、サーバー上で動作し、結果をHTMLやXML等で出力します。(※CSVやPDFも出力可能です)

JavaScriptでは端末側でプログラムを処理させるため、ページをリロードする事なく動的に表示内容を書き換えることができます。また、あるボタンを押す事で「よろしいですか?」と窓が開いて、OK/キャンセルを入力させたり、画像を切り替えたりできます。しかし、端末で処理をさせるため、複雑な処理をさせるためには端末のマシンパワーを必要とします。また、サーバー側にしかない情報を処理させることができません。

PHPではサーバーでデーターを処理して、その結果を返します。なので、画面の書き換えにはリロードを必要とします。しかし、サーバーサイドで処理をするため、サーバーにあるデーターベースから個人情報や商品の情報などを引き出して、必要なものだけを端末に返す、みたいな事ができます。

つまり、PHPは通販サイトなどの業務で使うためのサイトを作るのに適した言語と言えます。

PHPとCGI

PHPの他に、動的ページを出力させる手段として、CGIがあります。CGIでは、情報をPOST(もしくはGET引数)としてPerlなどのプログラム渡し、そこで処理した後にHTMLとして結果を出力させます。しかし、この場合、HTML全部をCGIが出力させねばならず、レイアウトの調整が困難です。また、途中でレイアウトに変更があった場合にも差し替えが困難で、最悪の場合、HTML出力部総入れ替えなんて事もありました。

PHP言語は、基本的にHTML言語に埋め込んで使います。つまり、基本的にはHTMLで、条件によって変化する部分だけをPHPにする事ができるという事です。これにより、レイアウトの変更が容易で、また、ホームページツールでレイアウトを確認しながらPHPプログラムを作るという事もできます。
例)引数(?id=)が1なら「CGな掲示板」、それ以外なら「アニメな掲示板」にする。

<title>
<?php
if ($id==1) {
  print "CGな掲示板";
} else {
  print "アニメな掲示板";
}
?>
</title>
このように、PHP言語はHTMLの途中に埋め込んで使いますので、PHP言語を使うためには、HTMLを知っておく必要があります。

PHPの埋め込み

PHPを埋め込むためには、いくつかの方法があります。

(1) <? ?>で囲む
例)
<?
printf("PHP言語\n");
?>

この方法を用いるためには、php.iniで

short_open_tag = On

に設定されている必要があります。ただ、XMLやXHTMLを記述する際に<?xmlというタグがあるとXMLをPHPの命令と解釈してパスエラーを発生させてしまいます。 もし、サーバーがshort_open_tag= Onの設定になっていて、XMLやXHTMLを記述する場合は、
<?
print "<?xml version=\"1.0\" …… >";
?>
みたいにして、PHPのprint文でXMLの宣言を出力させる必要があります。
PHP5.4以降では、short_open_tagをオフにできなくなりました。 なので、常に<?だけでPHPスクリプトの開始と解釈されます。 そのかわり、<?xmlというタグがあってもエラーにならなくなりました。
(2) <?php ?>で囲む
サーバーが、short_open_tag = Offの設定になっている場合、<?という記述はPHPの開始として認識されません。かわりに、<?xmlでエラーにもなりません。こういう設定になっている時は、PHPの開始を、<?ではなく、<?phpとして宣言します。

例)
<?php
printf("これはPHPプログラムです\n");
?>

(3) <Script Language="PHP"></Script>で囲む
この場合、JavaScriptを記述するのと同様で、スクリプトの記述を統一する事ができます。しかし、いささか面倒です。まして、PHPではinputタグのvalue=""の中に、value="<? print ""; ?>"みたいにして頻繁に組み込むので、なるべく記述を短くするのがベターですから、<Script Language="PHP">では長すぎてとても実用になりません。

書式

PHPはC系の言語で、基本形は他のC系と同じです。行の区切りにセミコロンを使って、変数を除き小文字で記述します。他のC系の言語の風習のように、if文やfor、whileのループ内など、ネストの中は、ネストの文だけタブをあけてインデントするのが一般的です。

PHPでは頭に$があると変数として扱われます。

例)$aに1を代入する。
$a=1;

関数は関数名のあとにカッコをつけて、引数を記述します。

例)kansuuという関数を$aを引数にして呼び、結果を$bに入れる
$b=kansuu($a);

また、PHPの特徴として、<?と?>でHTMLとPHPを切り替えることができるため、同じ行にHTMLとPHPを混在させる事ができます。

例)
<input type="hidden" name="sample" value="<? print $sample; ?>">

このように、inputタグのvalue値だけPHPの変数を出す、みたいな事ができ、動的ページが非常に作りやすい構造になっています。

コメント

コメントは、C++のように、//があるとその後に改行コードか、?>が来るまでコメントとなります。

例)
// これはコメントです

ただし、 ?> の後ろはコメントになりませんので、以下の場合
<?
// <input type="hidden" name="test" value="<? print $a; ?>">
?>
は、?>の後ろの">は表示されてしまいますので、HTMLとPHPが混在した行をコメントアウトしたい場合は、

<!--
<input type="hidden" name="test" value="<? print $a; ?>">
-->
のように、HTMLのコメントアウトを使ったほうが良いです。

また、C流のコメントも使えます。/* と */で囲われた区間がコメントになります。この場合は、?>があってもコメントアウト終了になりませんので、あるブロックをまとめてコメントアウトしたい場合に便利です。
<?
/*
<input type="hidden" name="test" value="<? print $a; ?>">
*/
?>

変数

PHPの変数は、頭に$をつけて表します。

$ID
$Subject
$handle

仕事でCやC++やJavaScriptとPHPをやってると、時折(頻繁に?)混乱して、Cの変数に頭に$をつけてしまったり、PHPの変数の$を忘れてしまったりするので、注意が必要です。Cの変数の頭に$があるとエラーになるから良いのですが、PHPの変数に$を忘れると、文字列(定数)として扱われ、エラーにならず思わぬバグになります。

予約語や関数と同名の変数名も使えますが、通常はあまりやりません。

変数に宣言は必要ではありません。プログラムで最初に現れた変数は、空文字列が入ってるとして扱われます。それは、つまりは変数名を間違えてもエラーにならないという事を示しています。なので、変数名間違いには注意が必要です・・という筆者も、誤動作の大半の原因が変数名の入力ミスだったりします。PHPでは変数名間違いを防ぐために、ViViなどの検索文字にヒットした文字列に色をつける機能のついたエディタが重宝します。

変数に代入
変数に値を代入するのは簡単です。通常は、$a=1みたくすれば左辺の変数に右辺が代入されます。ただし、PHPではregister_globalsがOnになっている場合、フォームからPUTされたもの、GETの引数、など自動的に代入される変数もあります。

ローカル変数
ローカル変数については、Perlと考え方が逆なので、日常的にPerlとPHPともに扱う人は注意が必要です。
PHP Perl
関数内部の変数 global宣言しない限りローカル変数 myやlocalと宣言しない限りグローバル変数
Perlでは、関数内でも特にmyとかlocalと宣言しないとグローバル変数を使うことになりましたが、PHPでは逆です。globalとして宣言するか、$GLOBALS["変数名"]という風に特殊変数を使ってグローバル変数を指定しない限りは、関数内ではローカル変数になります。ここでいうローカル変数は、Perlのレキシカル変数(my)に相当するものと思って良いです。

大文字小文字
PHPでは、基本的には他のC系の言語と同じく、変数の大文字と小文字は区別します。風習として、全て大文字の変数は定数にするのもCと同じです。ファイルハンドルはPerlなどとは違い全て小文字で書くケースが多いようで、PHPのマニュアルにあるサンプルでも、$handleという小文字の変数名が使われています。また、「クラス」で用いるオブジェクトでは、$Objectのように先頭だけ大文字にするケースがあります。

定数にしてもオブジェクトにしても、特にそうでなければならないという文法上の規則ではなく、風習としてそうなっています。


文字型、整数型、float型などの区別はありません。その都度PHPの方で自動判別します。

例)
if ($a=="") { … }
なら、$aは文字列とみなし、ヌルであるなら、という意味になります。

if ($a=="abcde") { … }
なら、$aは文字列とみなし、"abcde"であるなら、という意味になります。

if ($a==0) { … }
なら、$aは数値とみなし、ゼロであるなら、という意味になります。

明示的に型を特定したい場合は、キャストを使います。例えば、PHPでは割り算の結果は内部でfloat型となりますが、
$a=(int)$a;
のように(int)と指定すれば、$aはint型となります。

※注意
小数点同士の計算の結果をINTにキャストすると、結果が期待通りにならない場合があります。例えば、(int)(0.7+0.1)*10 とすると、8ではなく7になってしまいます。小数点同士の計算したい場合はBCMath関数か、GMP関数を使います。

真と偽
ifの条件判断で、 if ($a) { … }とした場合、$aが真なら、という意味になります。同様に、 while($a) { … }は、$aが真である限りループになります。真とは「偽ではないもの」です。偽になる条件として、

$aが空文字列である。
$aがゼロである。
$aがFALSEである。(FALSEは、PHPで定義された定数で、FALSEという値だと思ってください。)

なので、単純に「偽」を判別したい場合は、if (!$a) { … }で良いのですが、この場合だと$aがFALSEだけでなくゼロや空文字列であっても偽となってしまうため、ゼロと空文字列とFALSEを別々に判別したい時は、
if ($a=="") { … } $aが空文字列なら
if ($a==0) { … } $aがゼロなら
if ($a===false) { … } $aがFALSEなら
とします。===falseみたいに、イコールを3つ書いた場合には、FALSEである場合のみ条件に合致した事になります。

ちなみに$a==0の場合、$aが空文字列でも0とみなされるため、$aが空文字列ではなくゼロである事を判断したい場合は、 たとえば(他にも手はありますが)if (strlen($a)>0 && $a==0)みたいに文字列としてみなした時にレングスが0以上かつ…、という風にします。

配列と連想配列
PHPの配列はPerlとは違い、通常の配列と連想配列の区別が基本的にありません。通常の配列も連想配列も同じように扱うことができます。
PHP Perl
配列 連想配列 配列 連想配列
配列そのもの $配列名 $配列名 @配列名 %配列名
要素を1つ指定 $配列名[添字] $配列名["キー"] $配列名[添字] $配列名{"キー"}
要素数 count($配列名) count($配列名) $スカラ変数=@配列名 $スカラ変数=keys(%配列名)
要素を全部出す foreach ($配列名 as $値) while(list($キー,$値)=each($配列名))
foreach ($配列名 as $キー => $値)
foreach $値 (@配列名) while(($キー, $値)=each %配列名)
foreach $値 (keys(%配列名))
初期化 array(値1,値2…) array("キー"=>"値", … ) (値1, 値2) ("キー"=>"値", … )
左辺に要素を指定 list($値1, $値2…)=$配列名 list($キー1, $キー2…)=array_keys($配列名)
list($値1, $値2…)=array_values($配列名)
($値1, $値2…)=@配列名 ($キー1, $キー2…)=keys(%配列名)
($値1, $値2…)=values(%配列名)
Perlでは連想配列はそのものは頭に%をつけ、連想配列の要素は頭に$でキーを{}で囲いました。また、連想配列を取り出す時は、each関数+whileで順に取り出しましたが、PHPでは、どちらもそのものは頭に$をつけ、添字やキーは[ ]で囲います。添字を数値として評価した場合が普通の配列で、文字列として評価した場合が連想配列になります。また、配列、連想配列ともに要素をすべて取り出す場合はfoerach文を使うことができます。

関数

関数は、JavaScriptみたいにfunction につづいて、関数名(引数1, 引数2, …)という風に書きます。

例)
function kansuu($arg1, $arg2){
    :
    :
}

変数のスコープ
関数の中では、特に最初にglobalと宣言しない限り変数はローカル変数になります。global $a,$b;とすると、その関数内で$aと$bはグローバル変数になります。また、特に1回(とか2回とか少ない回数)だけグローバル変数を使いたい場合は、$GLOBALS["a"]とする事もできます。この場合、グローバル変数の$aが指定された事になります。

戻り値
PHPでは特に変数の型を意識しない言語です。なので、Cのような戻り値の型は宣言しません。戻り値は、

return $変数;

return 定数;

で返すことができます。戻り値を戻り値群にしたい場合は、配列や連想配列を返すようにします。

引数のデフォルト値
右辺の引数には、デフォルト値を設定する事ができます。たとえば、

function kansuu($arg1, $arg2, $arg3=0, $arg4=0)

みたいにすると、$arg3と$arg4が省略できます。省略した場合は、上の例でいくと0が指定された事になります。引数を省略する場合、間を抜かす事はできません。つまり、$arg4だけ指定して$arg3を指定しないというのはエラーになりますので、引数の順番の定義は、あとあとの事を考えておきましょう。

組み込み関数

PHPには、インストール時からいろいろ便利な関数が内蔵されています。Cでは普段よく使う関数群をincludeファイルで作ることから始めましたが、PHPでは特に自作の関数を使わずとも、大抵は事足りてしまいます。

どうも、PHPはC系の言語の中では後開発なおかげで、これまで他のC系の言語で培われてきたノウハウが生かされている感はあります。さらに、PEARというライブラリを入れれば、もう自作の関数で汎用的なものはほとんど作らなくて済みます。

PHPはフリーの言語なため、マニュアルもさまざまなサイトにアップされています。Googleで、PHP マニュアルで検索すれば、すぐにヒットすると思います。そこで、関数の機能や、引数&戻り値を調べることができます。

条件判断

if (条件) { … }
ここで、(条件)が真ならば、{と}の間の文が実行されます。

例)
if ($a==1) {
  :
}
この場合、$aが1なら{}内の文を実行します。

PHPには基本的に文字列と数値の比較の区別がありません。数値でも文字列でも同じ比較演算子になります。
意味 PHP Perl
数値 文字列
左辺が、小さい < < lt
左辺が、大きい > > gt
左辺が、同じか小さい <= <= le
左辺が、同じか大きい >= >= ge
同じ == == eq
違う != != ne
比較 strcmp() <=> cmp
型も等しい ===
Perlでは文字列として評価する場合と、数値として評価する場合が明確に分かれています。なので、文字列を勝手に数値として評価されてTRUEにされてしまう事はありませんが、eq と書くべきところを == と書いてしまうというミスは起こり得ます。

PHPでは文字列も数値も同じ比較演算子を使うことができます。そのかわりに、数値として評価させたくないのに、勝手に数値として評価されてしまい、全然違う文字列の比較がtrueになってしまう場合があります。

数値として評価するか文字列として評価するかは、左辺と右辺で判別しますが、一方が数字で、一方の頭の文字が数値な場合は、数値として評価します。なので、頭に数値が来る可能性がある文字列同士を比較を行う際には、強制的に文字型として判別させる必要があります。強制的に文字列として評価させたい時には、strcmp関数を使います。

PHPでは型も等しい事を示す===という演算子が使えます。strpos(……)===falseみたくすると、左辺が0や空文字列ではなくFALSEという値でなければ真にならなくなります。

HTMLを条件によって出す
PHPでは、HTMLをif文で囲う事ができます。つまり、条件成立時のみ出力される箇所を簡単に作ることができます。
<?
if ($edit_mode==1) {
?>
お名前:<input type="text" name="namae" value="<? print $namae; ?>">
メールアドレス:<input type="text" name="mailadd" value="<? print $mailadd; ?>">
<input type="submit" value="送信">
<?
}
?>
のように、<?と?>をうまく使い分けて、PHPとHTMLを切り替えるのがコツです。

ループ

ループには、 for、 while、 do while、 foreach があります。

forループ
for (初期化; 条件; カウントアップ) { … }

基本的には他のC系の言語と同じです。初期化では、例えば$cnt=0のように、ループカウンターの初期化を行います。条件には$cnt<10のように、ループを継続する条件を書きます。条件が真の場合にループを継続し、偽なら}の後に移ります。カウントアップにはループカウンターをアップさせる式を書きます。例えば$cnt++と書きます。

whileループ
while (条件){…}

これも他のC系の言語と同じです。条件が真である限りループします。while(1)とすると意図的に無限ループにできます。

do { … } while (条件);
この場合も条件が真である限りループしますが、最低でも1回は{…}内の文が実行します。

foreachループ
foreach ($配列 as $値) { … }
foreach ($配列 as $キー => $値) { … }

配列の中身を1つずつ、全てを取り出すまでループします。二番目の書式にすると、キーと値のペアを取り出すことができます。whileとeachを使うよりもすっきりします。

ループ制御命令
ループ制御命令には、breakとcontinueがあります。Perlとは異なるので、PerlとPHPを両方扱う人は混乱しないようにする必要があります。
PHP、C、C++ Perl
ループから脱出 break last
次のループの先頭へ continue next
HTMLをループさせる
TABLEタグの、行を繰り返す場合に、<tr>タグと</tr>タグの間をループさせる事ができます。
<table>
  <tr>
    <th></th>
    <th>りんご</th>
    <th>みかん</th>
    <th>ばなな</th>
  </tr>
<?
for ($cnt=1;$cnt<=12;$cnt++) {
?>
  <tr>
    <td><? print $cnt; ?>月度売上げ</td>
    <td><? print number_format($ringo[$cnt]); ?>円</td>
    <td><? print number_format($mikan[$cnt]); ?>円</td>
    <td><? print number_format($banana[$cnt]); ?>円</td>
  </tr>
<?
}
?>
        :
        :
のようにして、<tr></tr>の間をループ命令で囲うことによって、行の繰り返しを簡単に作ることができます。 いかに冷静でイカレているかをわからせるのが <?と?>をうまく使ってPHPとHTMLを切り替えるのがコツです。

register_globals

サーバーの方で、register_globalsに設定しておくと、フォームからPOSTされたり、GET引数がある場合に自動的にグローバル変数に値が入ります。

例えば、
http://ドメイン/ファイル.php?a=1

とすると、ファイル.php内では自動的に$a=1が代入されます。CGIをPerlで作る場合に、標準入力や$ENV{'QUERY_STRING'}を&記号でパースした後に、URLデコードしましたが、これらを自動的にやってくれるわけです。

しかし、URLの引数は操作をする側からも丸見えであり、URLを手動で書き換えることでグローバル変数を簡単に改ざんできてしまいます。例えば、通販サイトで、後ろに意図的に?tanka=0と入れると$tankaが0円になって、タダで注文ができてしまう、とか、そういう裏技が発生してしまいます。

なので、最近ではregister_globalsがオフになっているサーバーが多いです。オフになっている場合、$_GETや$_POSTという名前の連想配列から値を取り出します。詳しくは次の節で。

POST

入力フォームから値を送信することを「POSTする」といいます。サーバー(apache)には、POSTというログが残ります。

Perlで作られたCGIでは、標準入力から値を取得して、&でパースして、URLデコードしましたが、PHPではregister_globalsがオンなら変数に直接、オフなら$_POSTという連想配列に入ります。

テキスト入力フォーム
<INPUT type="text" name="onamae" value="<? print $onamae; ?>">
POSTされた際に、register_globalsがオンでもオフでも$_POST["onamae"]という変数に入ります。さらに、register_globalsがオンならば、$onamaeというグローバル変数にも直接入ります。

※以下の説明文は、register_globalsがオンとして説明しますので、オフになっているサーバーでは$_POST["…"]で読み替えてください。

隠し入力フォーム
<INPUT type="hidden" name="id" value="<? print $id; ?>">

画面には入力枠は出ませんが、valueで指定された値がPOSTされます。この例の場合は、$idという変数の値がPOSTされます。入力枠が出ない以外は、通常の入力フォームと同じように扱います。

ラジオボタン
<INPUT type="radio" name="sentaku" value="1" <? print ($sentaku==1)?" checked":""; ?>>

昔のカーラジオは、選局ボタンがいくつか横並びになっていて、そのうちの1つしか選局状態にできないようになってます。1つ選局すると今まで選択されたボタンはとび出て解除されます。つまり、ボタンがへっこんでる状態が常に1つだけになります。

同様に、ラジオボタンは、同じカテゴリーで選択されているボタンが1箇所だけにしかできない(複数回答できない)ボタンです。
例)ラジオボタン
このサイトはお好きですか?
好き 嫌い 普通
※これは見本なので送信できません。
この場合、選択された所に設定されたvalue値が、変数 $sentakuに入ります。デフォルト値は?演算子を用いて、value値と等しければタグ内にcheckedを出します。

チェックボックス
<input type="checkbox" name="fukusuu[]" value="1" <? print (in_array("1",$fukusuu))?" checked":""; ?> >

チェックボックスは、ラジオボタンとは違い複数回答ありの選択ボタンです。
例)チェックボックス
どのコンテンツがお好きですか?
プログラム講座 Linux情報 Windows小技集
※これは見本なので送信できません。
この場合のnameはそのフォームでユニークのものにするか、[]をつけて配列で渡します。デフォルト値は、in_array関数を使い、配列にvalue値が含まれているならcheckedを出してます。

ここで注意してほしいのは、1つもチェックされてなかった場合には、空配列ではなく、単に中身がヌルの1つの変数になるので、in_array、implode、foerachといった、引数に配列を必要とする関数にかけるとエラーになります。事前にgettype関数などで$fukusuuが配列かどうかをチェックして、配列でなければarray()関数を使って空配列として初期化するような処理が必要になります。

テキストエリア
<textarea name="message"><? print $message; ?></textarea>

テキストエリアは、複数行入力できるエリアを表示させます。

テキストエリアで入力された文字列には、改行コードが含まれる場合がありますので、テキストエリア外で表示させるためには、 nl2br($message)のように改行コードを<br />タグに変換してあげる必要があります。(テキストエリア内では不要です)

GET

GETとは、つまりURL引数です。

http://URL/ファイル.php?a=1

とすると、register_globalsがオンならば$a=1がセットされます。register_globalsがオフの場合は、$_GET["a"]から値を取得できます。PerlでCGIを作る場合のような、URLデコードは必要としません。

GETの場合、引数が丸見えになってしまうので、渡すのはせいぜいテーブルのキーぐらいにしておいて、内部でキーから詳しい情報を取得した方が良いでしょう。?password=a4b3v4x5dみたいに、パスワード見え見えにして渡したのでは大顰蹙です。

キーを渡すにしても、例えば?user_code=170みたいにユーザーの会員番号であると容易に想像できてしまうと、170番の人が「じゃあ171番にするとどうなるんだ?」と思って、?user_code=171に手動で変えたら、171番の人の個人情報が見えちゃった、なんて事にもなりかねません。この場合も暗号化した上で引数の正当性のチェックを行い、デタラメな値が来たらエラーとするのがベターです。

クッキー

クッキーとは、ブラウザ(インターネットエクスプローラとか)に一時的に記憶させておく変数のようなものと思ってください。

たとえば、アマゾンにアクセスすると「ようこそ○○さん」と表示され、最近チェックした商品と同じカテゴリーのうち、まだ購入してない商品の紹介が表示されますが、これも、クッキーを使って、アマゾンのサーバーが認識しているコードをブラウザに覚えさせているからです。

setcookie("onamae", $onamae, 86400, "/");
みたいにします。第一引数はクッキーの名前、第二引数はクッキーに記録する値、第三引数には有効期限、第四引数にはパスを入れます。値はあらかじめURLエンコードしておく必要があります。有効期限は秒なので、86400は1日になります。有効期限0は、「ブラウザを閉じるまで」という意味になります。パスは"それ以下"という意味なので、/は、/以下という意味になります。

クッキーに値をセットできるのは、ヘッダーを表示する時だけです。その前に、何らかのprint文やHTML、エラーを吐いてしまうと、その際にコンテントタイプtextのヘッダーを吐き終えてしまうので、クッキーがセットできません。気をつけないといけないのは、先頭に

<?
set cookie(………);
みたいに、1つ改行をあけてしまうと、この時既にブラウザがコンテントタイプを出力してしまうので、先頭の<?より前に改行や空白がないかどうかよく確認してください。

クッキーをセットしておくと、有効期限内に再度アクセスがあった時に、register_globalsがオンなら、クッキー名と同じグローバル変数に直接値がセットされます。オフの時は、$_COOKIE["クッキー名"]から取得します。

クッキーはユーザーの認証に役に立ちます。特定のパスワードを入力させた後、パスワードOKの人だけに、特定の暗号化された値をクッキーにセットする事で、パスワードが許可されたユーザーだけが、そのサイトを見ることが出来る、という機能をつける事ができます。

環境変数

サーバーから取得できる変数です。register_globalsがオンならば直接グローバル変数に入りますが、オフならば$_SERVER["環境変数名"]から取得します。
$HTTP_USER_AGENT 訪問者のブラウザ名
$REMOTE_HOST 訪問者のホスト名(IPアドレスの逆引き名)
$REMOTE_ADDR 訪問者のIPアドレス
$PHP_SELF 自プログラム名
$HTTP_USER_AGENTは、PC用サイトではほとんど役に立たないのですが、携帯専用サイトで訪問者が携帯電話からアクセスしているかを調べるのによく使います。ただし、あくまでも端末側の自己申告なので、HTTP_USER_AGENTを偽るツールを使えば簡単に見ることができるようになります。

本当に、どうしても携帯端末からじゃないと見せたくない、という時は、公式サイトになるか、$REMOTE_ADDRを使って携帯会社のサーバーのIPアドレスかどうかを調べるか、固体IDを取得できるかどうかで判別するしかありません。携帯会社のサーバーのIPは頻繁に変更になるのでメンテナンスが大変です。また、固体IDで判別すると、返さない設定にしている端末には見せない事になってしまいます。

$REMOTE_HOSTには、apacheでHostnameLookups on に設定されている場合のみ、逆引き名がセットされます。apacheが逆引きしない設定になっている場合はIPアドレスが入りますので、どうしてもホスト名が必要な時は、gethostbyaddr関数を使い逆引きをします。

$PHP_SELFは今実行中のプログラム名が引数付きでセットされています。自プログラムに対してPOSTするフォームとか、自プログラムをリロードするボタンを作る場合に使います。また、インクルードファイルの中でエラーが発生した時に、PHP_SELFを表示させると、どのプログラムが呼んだかを調べることができます。

PHPでJavaScriptを吐く

PHPの欠点は、POST、GET、リロードなどをせずに、フォームの入力が正しいかどうか判別できないという点です。そこで、どうしてもJavaScriptの協力が必要です。ですので、PHPプログラムを使い、適切なJavaScriptを生成してあげる必要があります。
function InputCheck2(form) {
   var check_suu;
   check_suu=eval(0);
<?
   foreach($parent_number_list as $number){
?>
   if (form.resbox_<? print $number; ?>.checked==true){
      check_suu++;
   }
<?
}
?>
   if (check_suu>1){
     alert("返信のチェックは1箇所だけにしてください。");
     return false;
   }
   return true;
}
JavaScriptとPHPという似て異なる言語が、<?と?>を区切りに混在しているため、非常に紛らわしいのですが、<?以降がPHPで、?>以降がJavaScriptになります。

上の例は、チェックボックスが2箇所以上チェックされてないか判別する部分なのですが、チェックボックスがいくつ存在しているかはPHPにしかわからず、また、リロードなしてチェック数をチェックできるのはJavaScriptだけなので、両者が協力して成立する関数になっています。PHPの方で存在し得るチェックボックス分だけ、チェックされてるかどうかを調べるスクリプトを生成し、JavaScriptがエラーメッセージを表示させます。

ただし、端末側でJavaScriptをオフにしている場合や、最初からJavaScriptが通用しないブラウザもあるので、POSTされた側で、PHPで再度入力フォームのチェックが必要になります。

サニタイジング

ここまでの例では、説明用に <? print $a; ?>のように、変数を直接プリントで出力させていました。 しかし、本当はユーザーから入力された($POSTされた)ものを、直接表示させるのは絶対にダメです

もし掲示板の利用者が、タグを使って他のサイトに無意味な文字列を送りつける送信フォームを作られてしまうと、掲示板の設置者、設置サーバーが攻撃元という事になってしまいます。また、タグを使って、全然そのサイトに関係ないページを構築され、最後に、<!--タグでコメントアウトされ、本来表示させるべきものを完全に消してしまう事だって可能です。

というように、タグを使えるようになっているだけで、ページそのものを改ざんできてしまいますので、以下のように<や>を置き換えて、タグを禁止にします。(サニタイジングといいます)
&lt; <を表示
&gt; >を表示
&amp; &を表示
&nbsp; 半角スペースを表示
PHPではhtmlspecialcharsという便利な関数があり、これを通すだけで上記の変換を行ってくれます。

例)
<input type="text" name="onamae" value="<? print htmlspecialchars($onamae); ?>">

サニタイジング抜けの対策
サニタイジングを忘れるか、意図的にサボった場合にも、デバッグでは何のエラーにもなりません。なので、ついつい忘れがちであり、サボりがちです。しかも、サニタイジングをサボったところで、めったに悪影響は出ません。悪影響が出るのは、悪意のあるユーザーが書き込みをした時や、たまたま<や>の記号を文中や顔文字で使う場合( 痛い(>_<;) とか)ぐらいです。

ところで、htmlspecialcharsは、表示の際にかなりの頻度で使う関数なのですが、そのわりには関数名が長い気がします。この関数名の長さこそが、サニタイジングをサボる要員にもなっています。

function hspc($str){
  return htmlspecialchars($str)
}
みたいにして、hspcみたいな短い関数名に置き換えた方が後々楽です。

応用編に続きます

PHPの入門編は以上です。

PHPはサーバーサイドで動かすため、実際にはデーターベースとの連動がほぼ必須になってきます。データーベースとの連動は応用編で説明します。
スポンサーリンク