【PHP】header関数とErrorDocument 404

WEBサイトの制作において、エラーページの表示は重要です。

基本的には、404エラー等は、.htaccess に記述する、ErrorDocument により制御できます。

たとえば、次のように .htaccessに記述します。

ErrorDocument 404 /error/404.html

基本中の基本ですね。ちなみに、遷移先のパスは相対パスにしないと404ステータスにならない場合があります。つまり、絶対パス(URL)ではなく、相対パスにするということです。

他方で、PHPのスクリプトによっても、404ステータスを発行することが可能です。

PHPの場合には、header関数により、次のように記述します。

header("HTTP/1.0 404 Not Found");

http://jp1.php.net/manual/ja/function.header.php

上記の記述により、ブラウザに404ステータスを送出できます。

しかし、ここで大きな問題に直面します。

どういう問題かというと、PHPのheader関数により、404ステータスを送出した場合には、自動的には、/error/404.html には遷移しないのです。

これは、少々、面倒なことになります。

というのも、header(“HTTP/1.0 404 Not Found”); の後に、header(“Location: http://~”); とロケーションを付け足してやるとエラーページに遷移はするものの、ヘッダーステータスが302に変更され、404ではなくなってしまうからです。

この対応策ですが、/error/404.htmlをfile_get_contents ()関数などで、読み込んで、出力するのも一つの方法となります。

header("HTTP/1.0 404 Not Found");

$error_page = file_get_contents('../error/404.html')

echo $error_page;

exit;

こうすることで、一応、ErrorDocumentの場合とPHPの場合で同一の404ファイルを出力することができます。
また、file_get_contentsの代わりに、require_once等でエラーファイルを読み込む方法も考えられます。

なお、取得するファイルのパスは、サイトの構造により修正が必要です。

もっとも、404ファイルを動的に作成している場合には、上手くいかない場合もあるので注意が必要です。

この件で、他に良い方法があれば、コメントください。

以上です。

カテゴリー: PHP | コメントする

【書評】CakePHP2 実践入門 (WEB+DB PRESS plus)

■ 書評対象:CakePHP2 実践入門 (WEB+DB PRESS plus)

■ 良い点

・ わかりやすく丁寧な説明
・ サンプルアプリ(タスク管理システム)を作りながら学べる
・ インストール等環境構築に詳しい
・ セキュリティ対策の解説有り
・ チートシート(プロパティ・メソッド集)が巻末に有り

■ 悪い点

・ 本文とコード等(図表)のページ位置関係が悪い
・ 白黒の本のため重要箇所がわかりづらい
・ レイアウト(ヘッダー・フッター)の扱いは無し

■ 総評

全体的に良書です。大きく分けて、前半の基礎部分と、後半の応用部分に分かれます。

前半部分は、安藤氏が一貫して解説しており、とても分かりやすくなっています。

コントローラー・モデル・ビューのそれぞれについて、サンプルコードを交え構文を解説し、各章のまとめで、タスク管理アプリを段階的に構築していきます。

当該サンプルアプリは、簡易的なものですが、DBのテーブルのアソーシエイション(JOIN)などまで含めての解説です。実用にも応用可能なレベルです。

後半部分は、CakePHPの応用となっており、各章ごとに執筆者が異なっています。

もっとも、各章ごとに、きちんとトピックが決まっており、前半同様、内容の濃い解説となっています。

セキュリティの対策についても、CakePHPの観点から、XSSなど代表的なリスク対策について検討がなされています。

また、公開準備にあわせたデプロイ等にも触れられていて、なかなかの参考になりました。

さらに、PHPUnitをつかったテストの自動化などにも触れられています。ここら辺は、自分のレベルではついていけなかったですが、マスターできれば、より効率的な開発ができそうです。

巻末には、CakePHPの重要なプロパティ・メソッド集としてチートシートが収録されていて、開発時の参考に随所で活躍しそうです。

全体的にレベルは高いですが、前半部分は初心者にも易しい解説になっているのでCakePHPの入門としてオススメです。 前半部分だけでも読むとCakePHPについてだいぶ自信が持てるようになると思います。

カテゴリー: BOOK, CakePHP | コメントする

【http】404ページへアクセスがある原因【error】

WEBサイトにおいて、存在しないページにアクセスがあると、404ステータスコードを返すのが一般的な仕様となっています。

そして、404ステータスの場合に、WEBサイト側で用意した、404ページへリダイレクトさせることもできます。

 ErrorDocument 404 http://example.com/error/404.html

このような設定を、.htaccess に記述すると、リンク切れなどでページが存在しない場合、404.html に遷移します。

つまり、通常、リンク切れなどがなければ、404.htmlへのアクセスは無いはずなのですが、頻繁にアクセスが有るケースがあります。

それは、検索エンジンのロボット(クローラー)が、robots.txt にアクセスする場合です。

robots.txt とは、検索エンジンのロボットに対して、クロールの可否を知らせるものです。

ロボットがrobots.txtにアクセスしてきた時、このrobots.txt  を設置していないと、サーバーは、存在しないページにアクセスしてきたものとして、ロボットに対し404ページへ移動するよう処理します。

つまり、リンク切れがない場合でも、robots.txt  を設置しておらず、かつ、404ページへの遷移の設定をしていると、robots.txt のため、404ページへのアクセスがログに記録されてしまうわけです。

この対策としては、robots.txt を設置すればよいのですが、サイトへのアクセスを左右するものだけに、慎重に行うべきだと考えます。

なお、robots.txt は、サイトに必須のものではないので、「設置しない」というのも一つの選択肢です。

カテゴリー: WEB | コメントする

【JavaScript】メールフォームのスパム対策【PHP】

WEBサイトを運営していてメールフォームを設置すると、遅かれ早かれスパム投稿に悩まされるようになります。

メールフォームのスパム対策には、画像認証を付けるなど、いくつかの方法があるのですが、より簡単に実装できるのが、JavaScriptによるフォーム値の上書き方法です。

どういう方法かというと、フォームにhiddenタグを埋め込みトークンを値にセットします。このトークン値をPOSTされる際に、JavaScriptにより書き換えてしまうというものです。

以下、具体例です。

(略)
<input id="token" type="hidden" name="token" value="some_token">

<input onclick="change_token();" type="submit" value="送信">

</form>

上記コードには、hiddenタグに、トークンとして、some_tokenがセットされています。

この状態で送信すると、原則的には、スパムは、token=some_token を送信してきます。

この原則を、JavaScriptの関数により変更します。つまり、送信ボタンが押されたときに、トークンの値を書き換えて、その書き換え後の値でなければ、スクリプト側でスパムとして送信を弾くようにします。

JavaScriptは次のようになります。(外部ファイルにする場合)

function change_token(){
    var token = 10 * 10;
    document.getElementById('token').value = token;
}

ここでは、例として、トークンの値を10 * 10 の100 としています。送信されたスクリプト側(PHPなど)で、入力チェックをするのですが、このtokenの値が100でなければスパムによる送信と判断するわけです。

スパムは、JavaScriptを実行しないことを利用したものですが、何も対策をしないよりは効果があると思います。

以上です。

カテゴリー: JavaScript, PHP | コメントする

PHPを使いサーバー監視をする方法

WEBサイトを運営する場合、気になるのがサーバーの死活状況です。

サーバーがダウンしてユーザーに迷惑をかけてしまっては一大事です。
ただ、そうかといって、ずっとサーバーの負荷状況を目視で確認するのも非現実的な話です。

そこで、PHPスクリプトを組み、サーバーを監視します。

■ 監視方法の概要は次のようになります。

・ 甲サーバーを監視するため、外部乙サーバーからPHPスクリプトにより死活状況監視
・ 乙サーバーのPHPスクリプトは、CRONの仕組みにより定期的に実行
・ 甲サーバーにおいてエラーが生じていたらメールにて通知

それでは、実際のPHPスクリプトです。

<?php

/**** サーバー設定 ****/

mb_language('ja');
mb_internal_encoding('UTF-8');

/**** サーバー情報初期化 ****/

$server_ip   = '20*.*72.*4.5*';
$server_name = 'example.com';
$page_url    = 'http://example.com/sample_page.html';
$mail_to     = 'your-mail';
$mail_from   = 'your-mail';

/**** チェック開始 ****/

$result = '';

//■ 1.pingチェック
$ping_command = 'ping -c 3 -w 5 '. $server_ip;

if (strstr(`$ping_command`, '100% packet loss')) {

    $result .= '1.pingが停止しています。'."\n";
}

//■ 2.socketチェック
$socket = @fsockopen($server_name, '80', $errno, $errstr, 5);

if ($socket === FALSE) {

    $result .= '2.socketを接続できません。'.$errno.$errstr."\n";
}

//■ 3.webアクセスチェック
if (!$res = @file_get_contents($page_url)) {

    $result .= '3.pageを取得できません。'."\n";
}

/**** メール送信 ****/

//停止していればをメール送信
if ($result != '') {

    $subject = 'エラー!停止しています。('. $server_name .')';
    mb_send_mail($mail_to, $subject, $result, 'From: '. $mail_from);

} else {

    $subject = '正常に稼動してます。('. $server_name .')';
    mb_send_mail($mail_to, $subject, '正常稼動中', 'From: '. $mail_from);
}

それでは、少し補足です。

■ 1では、pingを送信し正常かを確認しています。もし、送信したパケットが100%失われていれば、エラーとします。

通常だとpingは次のようなメッセージを生成します。

PING 20*.*72.*6.*0 (20*.*72.*6.*0) 56(84) bytes of data. 
64 bytes from 20*.*72.*6.*0: icmp_seq=1 ttl=64 time=2.71 ms 
64 bytes from 20*.*72.*6.*0: icmp_seq=2 ttl=64 time=0.146 ms 
64 bytes from 20*.*72.*6.*0: icmp_seq=3 ttl=64 time=0.143 ms
 --- 20*.*72.*6.*0 ping statistics --- 
3 packets transmitted, 3 received, 0% packet loss, 
time 2002ms rtt min/avg/max/mdev = 0.143/1.000/2.713/1.211 ms

つまり、‘ping -c 3 -w 5 ‘ のコマンドを実行すると、-cオプションの回数だけ、-wオプションの秒数を限度にパケットを送信するのですが、そのパケットのロスの割合を出力します。このロスの割合が、100%ならば、エラーと判断するわけです。

なお、pingのコマンドは、バッククオート`コマンド`で実行しています。(@マークのキーで出る記号です。)

■ 2では、サーバーにソケット接続して、正常に接続できるかを判断しています。

@fsockopen($server_name, ’80’, $errno, $errstr, 5);の部分ですが、これは、指定したサーバーの80ポート(httpポート)にソケット接続するための関数を実行しています。

引数に、$errno, $errstr などといきなり変数が出てきていますが、この変数に結果が参照で入るのでこのように指定しておきます。なお、5とあるのは、5秒を限度に接続を試みるというものです。

ちなみに、先頭の@マークは、スクリプトエラーが生じた場合に、エラーメッセージを表示させないための記号です。

■ 3では、@file_get_contents($page_url)を実行しています。@マークは上と同様です。

file_get_contentsで正常にファイルを取得できると、その結果を返しますが、失敗するとFALSEを返します。ここで、データベースを使用しているページを指定すると、データベースがきちんと動いているかも推定できます。

最後は、エラー結果に基づき、場合分けしてメールを送信しています。エラーの処理だけ欲しい場合には、else以降は不要となります。

以上です。

(参考)
http://blog.asial.co.jp/486
http://www.seeds-std.co.jp/seedsblog/315.html
http://www.okushin.co.jp/kodanuki_note/2012/09/php-2.html

感謝です。

カテゴリー: PHP | コメントする