それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

Google Chrome / Apple Safari は 301 リダイレクトやHSTSをずっと保存する!?

301/302 のどっちが良いか調べてて気になった。

HTTS ステータスコード 301 でリダイレクトしたら、その転送結果がキャッシュされて、リダイレクト後に戻ってこれない。

301 のリダイレクトがずっと残るので気になってた。

https://stackoverflow.com/questions/9130422/how-long-do-browsers-cache-http-301s

At least two browsers - Chrome and Firefox - will cache a 301 redirect with no expiry date
FirefoxとChromeの2つに限れば、リダイレクト情報保存に期限はない。
Chrome caches the 301 redirect infinitely, or until you open your DevTools, check Disable cache (while DevTools is open), and reload the page.

などと書いてあって、ステータスコード301はリダイレクトで乱用すると、キャッシュで面倒なことになりそう。

いちおう、キャッシュさせないように Cache-control でも制御できるみたい。 まぁ301を使うことは、サイト移転以外にあまりないと思うんけど、知って損にはならなさそう。

HSTSはどうなのか

HSTS もリダイレクトがキャッシュされて、開発中にSSLでトラブったり切替え時にアレコレすると、わりと面倒なことになる。

コッチも調べてみたら、有効期限を秒数で指定できるようでした。

Strict-Transport-Security:max-age=$int;includeSubDomains

nginx で サイトを認証を手軽にログインフォーム認証にする。(Basic認証の代わり)

nginx で サイトを認証する。

Basic認証だと不便なので、フォーム認証をする。

nginx の auth_request を使う。

auth_requestで、認証が出来る。

  • 認証済みの場合は、指定したURLをそのまま見せる
  • 未認証の場合は、認証用のページに飛ばす。
  • 認証ページが、401/403 を返せば未認証に
  • 認証ページが、200(20x)を返せば認証済みに。

要は、認証ページを指定して403 / 200 を返す。

簡単!!!!

それだけ。超簡単。

ログインフォームに転送するには nginx で 401 エラーページを指定する

もしかしたらBasic/Digest認証を設定するよりもっと簡単で使いやすいのでは。

設定はこれだけ

auth_request /auth_checker.php;
error_page 401 =301  https://$host/form.php?orig=$uri&$query_string;
auth_request  セッションチェックURL

上記のこれで、ユーザの認証状況を確認する。

error_page 401 =302  ログインフォームURL

上記のこれで、401が来たら、302 でリダイレクトに変換して、認証ページへ飛ばしてる。

認証取得ページで、認証完了後に元のURLへ再度リダイレクトをするために、LOGIN_URL?orig=$uri&$query_string で認証ページに元のリクエストページを保存している。

認証チェックの例

認証チェックは、セッションなどを見て、200 / 402 をチェックすればいい 使い方によっては、IPアドレスでチェックしたり、Oauthなどもできそうですよね。

例 auth_checker.php

<?php
if ( empty($_COOKIE) ){
     //do something for cookie
}
session_start();
if ( !empty($_SESSION['is_login']) ) {
  http_response_code(200);
  return ;
}else{
  http_response_code(401);
  return ;
}

特定のディレクトリにだけ認証をかけたい場合

location /path/to/秘密 {

    auth_request /auth_checker.php;
    error_page 401 =302  https://$host/form.php?orig=$uri&$query_string;
}

未認証のときは、単に見せない(ログイン者だけ画像が見えるなど)であれば、 error_pageのリダイレクトは無くても良い。

個人的には歓喜した。

Apacheディレクトリの一覧に保護を掛けるのが楽。 Basic認証だとiOSがパスワードを学習しないので不便なのでした。

認証を作るのが面倒くさいので、割とコレで自分ファイルにロックを掛けるだけなら、手軽でいいなとおもいます。

ファイルの共有程度に、NextCloudいれたりGoogleDrive契約するのも面倒くさい話だし。

参考資料

http://nginx.org/en/docs/http/ngx_http_auth_request_module.html

2018-05-09 更新

リダイレクトには、301 より 302 の方が良さそう。Chromeが301 リダイレクトを学習してキャッシュしてしまう。

phpで指定した日付の範囲を作り月末にも対応させる

php の日付範囲を求めるにはDatePeriodを使うと便利

DatePeriod にスタートと、終了、そして間隔を追加すると日付範囲のオブジェクトが出来る。

<?php
#(PHP 5 >= 5.3.0, PHP 7)
DatePeriod implements Traversable {

DatePeriodは Traversable なので、foreach などに入る配列オブジェクトとして扱える。

日付範囲を扱う

<?php

function date_range($start='yesterday', $days='+31 days') {

    $begin = new DateTime( $start );
    $end = new DateTime( $days );

    $interval = new DateInterval('P1D');
    $date_range = new DatePeriod($begin, $interval ,$end);
    return $date_range;
}

ループで回せるように range の変わる date_range を試しに作ってみた。

実例

<?php

$sday = date('Y-m-01', strtotime('this month '));  // 05-01 
$eday = date('Y-m-01', strtotime('next month '));   // 06-01 

foreach( date_range($sday, $eday) as $day ){
  echo $day->format('Y-m-d')."\n";
}

出力例

2018-05-01
2018-05-02
2018-05-03
(略
2018-05-29
2018-05-30
2018-05-31

ポイント

ループで回すときに、最終日の1日先を指定するのがポイント

DatePeriod は指定した終了時刻未満を配列に返すので、注意が必要。

参考資料