第 55章PHPを使う

このセクションにはPHPスクリプトを書くにあたってよく問題となる事柄が 集められています。

1. あらゆるフォームから送信されたデータを扱うことができる汎用的な PHPスクリプトを書きたいのですが、POSTメソッドでどのようなデータ が送信されたかを知るにはどうするのですか?
2. シングルクオート(')をバックスラッシュでエスケープされた シングルクオート(\')に変換しなければならないのですが、 正規表現を用いてこれを行うにはどの様にするのですか? 同様に " を \" に、\ を \\ に変換したいのです。
3. " は \" に、また ' は \' に全て変換されているのですが、 これら無用なバックスラッシュを除去するにはどうしたらよいですか? どうやって、そしてなぜ、こんなことになっているのでしょう?
4. 次のようなコードを実行すると、思った通りの順番で出力が表示されま せん。
function myfunc($argument)
{
    echo $argument + 10;
}
$variable = 10;
echo "myfunc($variable) = " . myfunc($variable);
なぜですか?
5. 改行されないのですが?
<pre>
<?php echo "これは1行目"; ?>
<?php
echo "この行は改行に続いて出力されるはず"; ?>
</pre>
6. 'Warning: Cannot send session cookie - headers already sent...'や 'Cannot add header information - headers already set...'といった メッセージが出力されるのですが。 sent...'.
7. リクエストヘッダに直接アクセスしたいのですが、どうすればよいですか?
8. IISで認証を行おうとすると'No Input file specified'というエラーが 発生します。
9. Windows: 他のコンピュータと共有しているファイルに、IIS でアクセスできません。
10. 私が書いたPHPスクリプトはIEとLynxでは動作するのですが、Netscapeを 使うと出力の一部が失われてしまいます。"ソースの表示"をするとIEには あるがNetscapeにはない内容があります。
11. どうすればXMLとPHPは共存することが出来るのですか?XMLの <?xml>タグがPHPでエラーになります。
12. FrontPageやその他のHTMLエディタを使うと、書いたPHPのコードが勝手 にあちこちに移動されてしまいます。どうしたらいいですか?
13. あらかじめ設定されている変数を全て網羅したリストはどこにあるので すか?なぜPHPのドキュメントにはその一覧がないのですか?
14. フリーではない商用ライブラリである ClibPDFPDFLibを使わずに PDFファイルを生成するにはどうしたらよいでしょうか? フリーのもので、外部のPDFライブラリを必要としない ものがいいのです。
15. ユーザ定義関数の中で、標準的な($DOCUMENT_ROOTや$HTTP_REFERER等の) CGI変数にアクセスしたいのですが、PHPはそれらの変数を見つけること ができていないようです。何がおかしいのですか?
16. いくつかの PHP ディレクティブでは、バイト値を integer ではなく省略形で設定できます。この省略形で使えるオプションを教えてください。 また、これは php.ini 以外でも使えるのですか ?

1. あらゆるフォームから送信されたデータを扱うことができる汎用的な PHPスクリプトを書きたいのですが、POSTメソッドでどのようなデータ が送信されたかを知るにはどうするのですか?

PHPは$_POSTのような 定義済みの変数 を沢山提供しています。$_POSTを連想配列として ループすることでPOSTされた全ての値にアクセスできます。例えば、 foreachで 単純にループしてempty()で値をチェックし、 結果を出力します。
<?php
$empty
= $post = array();
foreach (
$_POST as $varname => $varvalue) {
    if (empty(
$varvalue)) {
        
$empty[$varname] = $varvalue;
    } else {
        
$post[$varname] = $varvalue;
    }
}

print
"<pre>";
if (empty(
$empty)) {
    print
"None of the POSTed values are empty, posted:\n";
    
var_dump($post);
} else {
    print
"We have " . count($empty) . " empty values\n";
    print
"Posted:\n"; var_dump($post);
    print
"Empty:\n";  var_dump($empty);
    exit;
}
?>

スーパーグローバル: 使用可能なバージョンに関する注意: PHP 4.1.0 以降、 $_GET, $_POST, $_SERVER 等のスーパーグローバル配列が使用可能となっています。 詳細な情報については、マニュアルの superglobals のセクションを参照してください。

2. シングルクオート(')をバックスラッシュでエスケープされた シングルクオート(\')に変換しなければならないのですが、 正規表現を用いてこれを行うにはどの様にするのですか? 同様に " を \" に、\ を \\ に変換したいのです。

addslashes()がこれを行ってくれます。 mysql_escape_string()も見てください。 stripslashes()によって バックスラッシュを除去することもできます。

ディレクティブに関する注意: magic_quotes_gpc: PHP ディレクティブmagic_quotes_gpc のデフォルトは on です。この場合、すべての GET, POST, COOKIE データに ついて addslashes() が実行されます。 これらを取り除くため stripslashes() を使用することが できます。

3. " は \" に、また ' は \' に全て変換されているのですが、 これら無用なバックスラッシュを除去するにはどうしたらよいですか? どうやって、そしてなぜ、こんなことになっているのでしょう?

stripslashes()関数によってstringから バックスラッシュを取り除くことができます。 このような奇妙なバックスラッシュは、ほとんどの場合、PHPの magic_quotes_gpc ディレクティブがオンになっていることによって付加されています。

ディレクティブに関する注意: magic_quotes_gpc: PHP ディレクティブmagic_quotes_gpc のデフォルトは on です。この場合、すべての GET, POST, COOKIE データに ついて addslashes() が実行されます。 これらを取り除くため stripslashes() を使用することが できます。

4. 次のようなコードを実行すると、思った通りの順番で出力が表示されま せん。
function myfunc($argument)
{
    echo $argument + 10;
}
$variable = 10;
echo "myfunc($variable) = " . myfunc($variable);
なぜですか?

式の中で関数の実行結果を使用する(例えば上の例の様に他の文字列と 連結する)ためには、echo()するのではなく、その 値をreturnしなければいけません。

5. 改行されないのですが?
<pre>
<?php echo "これは1行目"; ?>
<?php
echo "この行は改行に続いて出力されるはず"; ?>
</pre>

PHPでは、"?>"か"?>\n"(\nは改行を表します)をPHPのコードブロッ クの終端と見なします。このため、コードブロック終端の改行記号は省 略され、表示される文は1行になります。つまり、改行をさせるために は、PHPのコードブロックの終端の後にもう1つ改行を挿入する必要があ るということです。

なぜPHPはこのようなことをするのでしょうか?なぜならHTMLを出力する 場合にはこの方が都合のよいことが多いからです。もしとても長い1行を 出力しなければならない場合に、改行が解釈されてしまうとしたらどう でしょう。ソースコードの1行もとても読めないくらい長いものになって しまいます。

6. 'Warning: Cannot send session cookie - headers already sent...'や 'Cannot add header information - headers already set...'といった メッセージが出力されるのですが。 sent...'.

header(), set_cookie()セッション関数は出力ストリームに ヘッダを付加する関数で、ヘッダを送信できるのは本文の出力を 開始する前のみです。headers_sent()を使って 既にヘッダが送信済みでないかチェックすることができます。 出力制御関数もご覧ください。

7. リクエストヘッダに直接アクセスしたいのですが、どうすればよいですか?

もしPHPがApacheモジュールとして動作しているなら、 getallheaders()を使えば全てのヘッダを取得する ことができます。下のちょっとしたコードで全てのリクエストヘッダを 表示することができます。
$headers = getallheaders();
foreach ($headers as $name => $content) {
    echo "headers[$name] = $content<br />\n";
}

apache_lookup_uri(), apache_response_headers(), fsockopen()も参照してください。

8. IISで認証を行おうとすると'No Input file specified'というエラーが 発生します。

これはIISのセキュリティモデルの欠点で、IISで動作するCGIに共通する 問題です。これを回避策するには、認証のかかったディレクトリに(PHP が解釈しない)HTMLファイルを作成します。そしてMETAタグを使ってPHP を使用したページにリダイレクトするか、リンクを張ります。こうすれ ばPHPは認証済みかどうかを正しく認識することが出来ます。ISAPIモジュー ルの場合はこの問題は起きません。また、これは他のNTウェブサーバに は影響ありません。詳しくはhttp://support.microsoft.com/kb/q160422/HTTP 認証を 参照してください。

9. Windows: 他のコンピュータと共有しているファイルに、IIS でアクセスできません。

Go to Internet Information Services を変更する必要があります。PHP ファイルを選択して プロパティを開き、セキュリティ タブに移動し、 Edit -< Anonymous access and authentication control

この問題を解決するには Anonymous Access のチェックをはずして Integrated Window Authentication をチェックしたままにしておきか、 あるいは Anonymous Access をチェックしてアクセスできないユーザを別途指定します。

10. 私が書いたPHPスクリプトはIEとLynxでは動作するのですが、Netscapeを 使うと出力の一部が失われてしまいます。"ソースの表示"をするとIEには あるがNetscapeにはない内容があります。

NetscapeはHTMLタグの扱いがIEに比べて厳密になっています(テーブル等)。 スクリプトが出力したHTMLを validator.w3.orgなどのHTMLバリデータに掛けてみると良いでしょう。 例えば</table>が無いとこのような現象が発生します。

また、IEとLynxは共にHTMLストリーム中のNULL文字(\0)を 無視しますがNetscapeは無視しません。この問題をチェックする一番の方法 はコマンドライン版の PHP(つまりCGIバージョン)をコンパイルして、コマンドラインからその スクリプトを実行することです。*nix上では、その出力を od -c にパイプして\0があるかどうかを チェックしてください。もしWindowsを使っている場合は、バイナリファ イルを扱えるエディタかそれに類するソフトウェアが必要です。IEや Lynxと異なりNetscapeはNULL文字を見つけるとその行の文字を一切出力 しません。

11. どうすればXMLとPHPは共存することが出来るのですか?XMLの <?xml>タグがPHPでエラーになります。

<?xml を直接PHPコードに埋め込むには、 PHPディレクティブのshort_tags を0に設定しなければなりません。 このディレクティブはini_set()でセットすることは できません。short_open_tags のオン/オフに関わらず、次のようにもできます: <?php echo '<?xml'; ?> このディレクティブはデフォルトでオンです。

12. FrontPageやその他のHTMLエディタを使うと、書いたPHPのコードが勝手 にあちこちに移動されてしまいます。どうしたらいいですか?

最も簡単なのはASPタグを使う方法です。こうすればASPの様に<%と %>をコード区切りとして使用することが出来ます。有名なHTMLエディ タは(今のところ)ASPタグを賢く扱ってくれます。ASPスタイルのタグを 有効にするにはphp.iniファイルでasp_tagsを設定するか、適切なApacheディレ クティブを使用します。

13. あらかじめ設定されている変数を全て網羅したリストはどこにあるので すか?なぜPHPのドキュメントにはその一覧がないのですか?

マニュアルの 定義済みの変数 のページを読んでください。スクリプト上で有効な定義済み変数のリストの 一部があります。有効な変数の完全なリスト(とその詳しい情報)は phpinfo()をコールすることで見ることができます。 マニュアルの PHPの外部から来る変数 のセクションも読んでください。HTMLフォームやCookie、URL等から 来る外部変数に関するシナリオが説明されています。

register_globals: 重要な注意: PHP 4.2.0 以降、PHP ディレクティブ register_globals のデフォルト値は off となっています。 また、このディレクティブは PHP 6.0.0 で完全に削除される予定です。 PHP コミュニティは、ユーザがこのディレクティブの設定に依存せず、 superglobals のような他の手段を使用することを推奨します。

14. フリーではない商用ライブラリである ClibPDFPDFLibを使わずに PDFファイルを生成するにはどうしたらよいでしょうか? フリーのもので、外部のPDFライブラリを必要としない ものがいいのです。

PHPで書かれている代替手段がいくつかあります。 http://www.ros.co.nz/pdf/, http://www.fpdf.org/, http://www.gnuvox.com/pdf4php/, http://www.potentialtech.com/ppl.php等です。 Pandaモジュールもあります。

15. ユーザ定義関数の中で、標準的な($DOCUMENT_ROOTや$HTTP_REFERER等の) CGI変数にアクセスしたいのですが、PHPはそれらの変数を見つけること ができていないようです。何がおかしいのですか?

PHPディレクティブの register_globals がサーバと環境変数に与える影響を認識することは重要なことです。 register_globals = off (PHP4.2.0以降デフォルトでoff)の場合、 $DOCUMENT_ROOTは存在しません。代わりに $_SERVER['DOCUMENT_ROOT']を使用してください。 register_globals = on の場合は $DOCUMENT_ROOT$GLOBALS['DOCUMENT_ROOT']も存在します。

スーパーグローバル: 使用可能なバージョンに関する注意: PHP 4.1.0 以降、 $_GET, $_POST, $_SERVER 等のスーパーグローバル配列が使用可能となっています。 詳細な情報については、マニュアルの superglobals のセクションを参照してください。

16. いくつかの PHP ディレクティブでは、バイト値を integer ではなく省略形で設定できます。この省略形で使えるオプションを教えてください。 また、これは php.ini 以外でも使えるのですか ?

有効なオプションは K(キロバイト)、M(メガバイト)および G(ギガバイト: PHP 5.1.0 以降で有効)です。大文字小文字は区別しません。これ以外の文字は バイト値と判断されます。 1M は、1 メガバイトあるいは 1048576 バイトと等しくなります。1K は、1 キロバイトあるいは 1024 バイトです。この表記法を php.ini 以外では使用 しないでください。かわりに integer のバイト値を設定します。 これらの値を数値に変換する例は ini_get() のドキュメントを 参照ください。