PHP7初級試験 模擬問題 – 出題範囲: ユーザの記憶:クッキーとセッション からの出題となります。
受験を考えているあなたも、試験を合格したあなたも、ぜひチャレンジしてみてください!
問題
次の選択肢のなかで、正しいものはどれでしょう? (1つ選択)
- クッキーの有効期限を無期限に設定するには、setcookie() 関数の expires (3番目) 引数に 0 を指定する
- クッキーの有効なドメインを指定するには、setcookie() 関数の domain (5番目) 引数に指定する。ただし、サブドメインに対しても有効となる
- HTTPS 通信のときのみクッキーを送信するには、setcookie() 関数の httponly (7番目) 引数を true にする
- セッションが利用するクッキーのデフォルトは PHPSESID の値である
- session_start() 関数はレスポンスボディより後に出力しないといけない
解答と解説は下にスクロールしてください
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
解答
正解は 2. です。
解説
1. クッキーの有効期限を無期限に設定するには、setcookie() 関数の expires (3番目) 引数に 0 を指定する
expires
引数に 0 を指定すると、クッキーはセッションの最後 (つまりブラウザを閉じるとき) が有効期限となります。
引数に設定する数字は、「1970年1月1日 00:00:00 GMT」からの経過秒である Unix エポックというものが基準となります。
PHP では、現在の Unix エポックタイムを time()
関数で取得できるので、有効期限を設定する際には、この値に有効期限を秒で加算します。
- 有効期限 1分:
time() + 60
- 有効期限 1時間:
time() + 60 * 60
- 有効期限 1日:
time() + 24 * 60 * 60
- 有効期限 30日(1ヶ月):
time() + 30 * 24 * 60 * 60
- 有効期限 365日(1年):
time() + 365 * 24 * 60 * 60
【試験合格後もステップアップ!】
クッキーの有効期限を無期限に設定する方法はありません。 無期限に指定したいときには、代替策として長い有効期限を設定する方法となります。
また、クッキーの有効期限は「2038年1月19日 03:14:07 UTC」を超える値を設定すると、環境によっては誤動作を起こす可能性がありますので注意が必要です。
これは Unix エポックの仕様上「2038年1月19日 03:14:07 UTC」を過ぎると、コンピュータが誤動作する可能性があり、これはクッキーの有効期限に関わらずあらゆる場所に影響があるとされている問題です。
ウィキペディア – 2038年問題
https://ja.wikipedia.org/wiki/2038年問題
なお、Google で使用されているポリシーではクッキーの保持期間の最長は2年間と書かれています。
クッキーの有効期限は長くても2年位を目安にするのが良さそうです。
Google ポリシーと規約
https://policies.google.com/technologies/cookies?hl=ja
2. クッキーの有効なドメインを指定するには、setcookie() 関数の domain (5番目) 引数に指定する。ただし、サブドメインに対しても有効となる
選択肢のとおりです。
domain
引数はクッキーが有効なドメインやサブドメインを指定します。 さらに、有効なドメインやサブドメインの更にサブドメインに対しても有効となります。
例として domain
に www.example.com を指定した場合は下記の通りとなります。
- www.example.com 指定したドメイン
- sub.www.example.com などの指定したドメインのサブドメイン
【試験合格後もステップアップ!】domain
属性をきちんと指定すると、指定しないより安全なように見えますが、この認識は正しくありません。
上記で説明したとおり、サブドメインも有効になってしまうからです。 domain
属性を指定しないで発行するクッキーは、クッキーを発行したホストのみに送信されるものとなります。
これは、一番制限がかかっている状態です。 特にサブドメインとクッキーを共有する必要ない場合は指定しないほうが良いです。
また、別ドメインに対しては samesite
属性も影響があります。
3. HTTPS 通信のときのみクッキーを送信するには、setcookie() 関数の httponly (7番目) 引数を true にする
httponly
引数は JavaScript によりクッキーの操作をできなくするための設定です。基本的に true
にしておくことが推奨です。 また「HTTPS ではなく HTTP 通信のみ」という意味ではありません。
SSL/TLS を利用した HTTPS 通信のときのみクッキーを送信するには、6番目の引数である secure
引数に true
を指定します。こちらも Web サイトが HTTPS 対応であれば true
にしておくことを推奨します。
暗号化されていない HTTP 通信は、暗号化されていないため経路の途中で盗み見される可能性があります。
これは通常の Web を閲覧する、例えば Wikipedia をゲストで閲覧しても Wikipedia の内容が盗み見られてもは特に問題はありません。
ただ、クッキーは(この後の解説で触れるセッション ID など)盗み見られると問題となる重要なデータが入っていることがあります。
また、JavaScript などで外部に流出させれられても問題です。
基本的にクッキーはどのデータが重要か判定するよりも、一律で httponly
と secure
は両方とも true
にしておいたほうが良いでしょう。
【試験合格後もステップアップ!】setcookie()
関数でセキュリティ上重要な引数は後から追加された関係上、引数の順番が後ろの方にあるためすべて書く必要があります。
PHP 7.3 で options
配列をサポートする追加の設定方法が追加されました。 samesite
に対してはこの options
配列でないと対応できないので注意してください。
$options = [
‘expires’ => time() + 60 * 60 * 24 * 30,
‘path’ => ‘/’,
‘domain’ => ”,
‘secure’ => true,
‘httponly’ => true,
‘samesite’ => ‘Lax’,
];
setcookie(’SampleCookie’, ’クッキーのサンプル’, $options);
PHP 7.3 以降ではこちらの options
を利用すると、コードの再利用性も高くオススメです。
4. セッションが利用するクッキーのデフォルトは PHPSESID の値である
PHPSESID
ではなく PHPSESSID
です。
HTTP では原則、ページを読み込むたびに接続手続きが完了します。 これをステートレスといいます。 ただ、ユーザーのログイン状態などを他のページでも使いまわしたい場合があります。 このときにセッションを利用することで可能となります。 これを、ステートレスに対しステートフルといいます。
サーバーでセッション ID は、 session_id()
で取得できます。 クッキー(クライアント側情報)でセッション ID は、 $_COOKIE['PHPSESSID']
で取得できます。
【試験合格後もステップアップ!】
サーバーとクライアントでやり取りするセッション ID は PHPSESSID
という名前ですが、 session_name()
関数か php.ini で設定変更できます。
セッション ID を PHPSESSID
から SESSIONID
に変更する例です。
・関数: session_name('SESSIONID');
・php.ini: session.name=SESSIONID
当然、セッション ID を変更した場合はクッキー名が変わるので、現在のセッション ID を取得する必要があります。
これは、セッション ID を設定するのと同じ関数に引数を設定しないことで取得できます。session_name();
つまり、クッキー(クライアント側情報)でセッション ID は、 $_COOKIE[session_name()]
で取得するほうが正確です。
5. session_start() 関数はレスポンスボディより後に出力しないといけない
session_start()
関数はレスポンスヘッダーに出力される関数です。レスポンスボディより前に出力しないといけません。
レスポンスヘッダーに出力する代表的な関数として、下記のようなものがあります。
header()
session_start()
setcookie()
HTTP 通信では、ヘッダー部とボディ部に大きく分かれます。 レスポンスとはサーバーから返された結果のことです。 まず、レスポンスヘッダーが返されて、続けてレスポンスボディが返されます。 レスポンスボディは基本的にブラウザで表示される部分です。
レスポンスボディを取得中にレスポンスヘッダーを追加で取得することはできません。 ですので、ヘッダー部分を先に出力する必要があります。
通常の PHP 関数で出力されるものは基本的にレスポンスボディに表示されます。 レスポンスヘッダーに出力される PHP 関数のほうが少ないため、これらの関数を使用するときには注意してください。
つまり下記のようなコードを実行すると、
<?php
echo 'セッションのデモ'; // リクエストボディに返されるデータ
session_start(); // リクエストヘッダーに返されるデータ
下記のような Warning が表示もしくはログに出力されます。
Warning: session_start(): Session cannot be started after headers have already been sent in /home/kusanagi/php_column/DocumentRoot/test.php on line 3
【試験合格後もステップアップ!】
レスポンスヘッダー絡みでよく問題になる原因に、「UTF-8 BOM エンコーディング」と「不要な PHP 終了タグ ?>
」があります。
PHP では <?php ~ ?>
以外の部分はそのままレスポンスボディとして出力されます。
これは元々 PHP タグが HTML 内部に埋め込むことを想定した仕様だったためです。
つまり、下記のようなただの PHP コードファイルを作ったつもりで、
<?php
// PHP コード
?>
このような目視で確認しづらい PHP ファイルができている恐れがあります。
(①画面で見えないBOM)<?php
// PHP コード
?>
(②終了タグ後の余計な改行や空白)
この PHP ファイルを外部から読み込むと、①や②の部分でレスポンスボディがすで出力されてしまっているので、新たにレスポンスヘッダーの出力に失敗します。
①は PHP ファイルを「UTF-8 BOM あり」で保存していることが原因ですので、「UTF-8 BOM なし」で保存しなおしてください。
②は終了タグ ?>
を省略することで余計な改行や空白は無視されますので、終了タグを削除してください。
上記の訂正を入れると、下記のような PHP コードになります。
<?php
// PHP コード
このように、「UTF-8 BOM なしで保存」と「終了タグ ?>
の省略」にはバグを未然ぬ防ぐ大きな意味があります。
この 2 つは経験者でもよくハマるポイントなので、予め起こさないようにコーディングルールで対応しておくことが非常に重要です。
原理原則を抑えた上で、上記のコーディングルールを徹底してください。
試験の情報
今回の内容は、セキュリティや脆弱性に直結する項目も含まれておりますのできちんと押さえておいてください。
PHP 7 初級レベルではウェブ・セキュリティの基本を押さえただけにとどまりますので、実務ではもう少し深く知っておく必要があります。
ウェブ・セキュリティの名著として知られる徳丸浩氏による「体系的に学ぶ 安全なWebアプリケーションの作り方 第2版」では、より丁寧で詳細にウェブ・セキュリティについて学ぶことができますのでおすすめです。
上記の本は「ウェブ・セキュリティ基礎試験(通称:徳丸基礎試験)」の主教材でもあります。
徳丸基礎試験は Python や Ruby on Rails などの PHP 以外の言語で Web アプリケーションを作成されている方にも非常に有益な試験となっております。
知識としても実務としても PHP 関わらず幅広く使えるため、ウェブに関わるエンジニアに私が一番オススメしている試験が「徳丸基礎試験」だったりします。
PHP 7 初級を合格した方は、徳丸基礎試験もぜひチャレンジしてみてください!
模擬問題作成及び解説
PHP ユーザーが集まる PHP カンファレンス 2022 が今年も 9月24日(土) 〜 25日(日) の日程で開催されました。
この記事を書いている私(三雲)も、当日スタッフとLT発表で現地オフライン参加しました。
会場でたくさんの方にお会いできました。また、Twitter でたくさんの方と交流できました。
ありがとうございました!