1年以上放置した末の更新というか、生存証明的なエントリーというか、まあ死にそうになりながらも生きてる俺・輝いてる☆ 的な話というか、結論としては、生きててすみません。(積極的に生存の許しを請うていくスタイル)
1年以上更新していないと、書き出しのスタイルすら迷走し混迷を深めていくものだなあと他人事のように語りつつ、暁の軌跡 引退記念としてこのエントリーを奉じる次第……って前置きはこのあたりにしておいて。
だいたいタイトルだけで説明になってますが、Google App Engine では .htaccess が使えないため、mod_rewrite を使っての SNI SSL 非対応ブラウザの振り分けができない。よってスクリプト書いて代替したよーという話。
1年ぶりの更新なので、このくらいのネタがリハビリとしてはいいんじゃないかなということで、以下続きにて。
スポンサードリンク
これまで、SNI SSL非対応環境を振り分ける .htaccess については、SNI SSL(HTTPS)を使いたいけど Android 2.X とか古いブラウザもあるから SNI 対応ブラウザだけ SSL 接続させる正規表現 様のページを参考に振り分けしていたのだけど、その自前サイトはたいした規模でもないので、Google App Engine で動作させればサーバー維持費が無料になるんじゃね? と思い立って作業開始したものの、Google App Engine は Apache 環境じゃないので .htaccess での振り分けが使えない。
じゃあせっかくだしPHP経由で振り分けすればいけるかな、と思って試したら上手くいったので、そのスクリプトとか app.yaml の設定などをメモ的に残す感じで。
ただ、振り分けにPHPを使う=サイトへのアクセス毎にインスタンスが起動するという事でもあるので、静的HTMLベースのサイトでも、調整によってはインスタンスが無料範囲に収まらない可能性もあるため、その点だけはご注意を。
PHPのコードは下記の通り。一部環境の判定に不要なものもあるけれど、App Engine 以外の環境でも使えるように保険として。App Engineだけでしか使わないなら、ログを見て不要な判定部分は削ってもいいかもしれない。
処理としては、初めから https つきでアクセスされたら、SNI非対応の場合はその時点でエラーやら警告が出るので、SNI非対応かどうかは判定せずに https にジャンプさせている。http でアクセスされた場合のみ、User Agent を確認して振り分ける。処理の速さを優先して strpos で判定しているので冗長だけど、この程度の規模なら正規表現で判定させてもたいして速度や負荷は変わらなかったかも。
ファイル名 : snicheck.php <?php # ヘッダー情報を取得 $http_host = $_SERVER['HTTP_HOST']; $http_cf_visitor = $_SERVER['HTTP_CF_VISITOR']; $cf_visitor = $_SERVER['CF_VISITOR']; $x_forwarded_proto = $_SERVER['HTTP:X-Forwarded-Proto']; $https = $_SERVER['HTTPS']; $user_agent = $_SERVER['HTTP_USER_AGENT']; # ジャンプ先 URL $nosnijump = 'http://www.example.com/index.html'; $snijump = 'https://www.example.com/index.html'; # httpsで接続してきているかの確認 # https で接続された場合、htmlにリダイレクトする if($x_forwarded_proto === 'https' || $https === 'on' || strpos($http_cf_visitor, 'https') !== false || strpos($cf_visitor, 'https') !== false) { header("Location: ".$snijump); # https 接続ではない場合の処理 } else { # SNI非対応かチェック if(strpos($user_agent, 'MSIE 4') !== false || strpos($user_agent, 'MSIE 5') !== false || strpos($user_agent, 'MSIE 6') !== false || strpos($user_agent, 'MSIE 7') !== false || strpos($user_agent, 'MSIE 8') !== false || strpos($user_agent, 'Windows NT 5') !== false || strpos($user_agent, 'UP.Browser') !== false || strpos($user_agent, 'DoCoMo/') !== false || strpos($user_agent, 'SoftBank/') !== false || strpos($user_agent, 'Android 1') !== false || strpos($user_agent, 'Android 2') !== false) { # SNI非対応ブラウザは http にジャンプ header("Location: ".$nosnijump); # SNI 対応ブラウザの処理 } else { # SNI対応ブラウザは https にジャンプ header("Location: ".$snijump); } } ?>
この例では、インデックスファイルとして上記 snicheck.php を読み込ませるように設定している。スクリプト内で index.html にリダイレクトさせているので、その設定も handlers に追加している。
そのため、直接 index.html を指定してアクセスされると無意味になってしまうけど、自分の場合は特にそれでも支障ないのでこのやり方にした。
handlers: - url: / script: snicheck.php - url: /index.html static_files: index.html upload: index.html
最近はSNI非対応環境も(Windows XP のサポート終了に伴って) 少なくなってきているだろうし、Android 2.x 環境も同様だとは思うけど、一部フィーチャーフォンに対応しないといけない場合などにはまだ使う事もあるかなと。
Google App Engine 前提で書いたスクリプトだけど、改造すれば Apache 以外の環境で条件判定するのに使えるかもしれないので、もしお役に立てれば幸い。
別のサイトで、IE 4~8 環境を判定して別ページに飛ばす必要があったので、そのスクリプトもおまけとして公開。もうサポートも終了しているので切り捨ててもいいんだろうけど、ロングテールで細かくアクセスを稼ぐタイプのサイトなので、その辺りもフォローする必要があり・・・。
<?php # ヘッダー情報を取得 $http_host = $_SERVER['HTTP_HOST']; $http_cf_visitor = $_SERVER['HTTP_CF_VISITOR']; $cf_visitor = $_SERVER['CF_VISITOR']; $x_forwarded_proto = $_SERVER['HTTP:X-Forwarded-Proto']; $https = $_SERVER['HTTPS']; $user_agent = $_SERVER['HTTP_USER_AGENT']; # ジャンプ先 URL $iejump = 'http://www.example.com/ie4-8.html'; $nosnijump = 'http://www.example.com/index.html'; $snijump = 'https://www.example.com/index.html'; # httpsで接続してきているかの確認 # https で接続された場合、htmlにリダイレクトする if($x_forwarded_proto === 'https' || $https === 'on' || strpos($http_cf_visitor, 'https') !== false || strpos($cf_visitor, 'https') !== false) { header("Location: ".$snijump); # https 接続ではない場合の処理 } else { # IE 4~8かどうかチェック if(strpos($user_agent, 'MSIE 4') !== false || strpos($user_agent, 'MSIE 5') !== false || strpos($user_agent, 'MSIE 6') !== false || strpos($user_agent, 'MSIE 7') !== false || strpos($user_agent, 'MSIE 8') !== false) { # IE 4~8なら、SNI非対応かつIE専用ページにジャンプ header("Location: ".$iejump); # SNI 非対応かどうかチェック } elseif(strpos($user_agent, 'Windows NT 5') !== false || strpos($user_agent, 'UP.Browser') !== false || strpos($user_agent, 'DoCoMo/') !== false || strpos($user_agent, 'SoftBank/') !== false || strpos($user_agent, 'Android 1') !== false || strpos($user_agent, 'Android 2') !== false) { # SNI非対応ブラウザは http にジャンプ header("Location: ".$nosnijump); # SNI 対応ブラウザの処理 } else { # SNI対応ブラウザは https にジャンプ header("Location: ".$snijump); } } ?>
Google App Engine でこのスクリプトを導入した際に、インスタンス節約のために調整した app.yaml ファイルもおまけで公開。アクセス数にもよるだろうけど、この調整でインスタンスの無料範囲を超えることなく運用できるようになった。
service: default runtime: php55 api_version: 1 threadsafe: true automatic_scaling: min_idle_instances: 0 max_idle_instances: 1 min_pending_latency: 3000ms max_pending_latency: 4000ms handlers: - url: / script: snicheck.php - url: /index.html static_files: index.html upload: index.html
スポンサードリンク
当サイトのコメント欄は承認制となっております。また、日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)
コメントを残す