PHP技術者認定機構Level 3

難易度は Level 1(やさしめ)〜Level 5(難関) の5段階です。

PHP8 技術者認定 上級/準上級のサンプル問題(本番形式・解説付き)

PHP8 技術者認定 上級/準上級(PHP技術者認定機構・PHP8技術者認定上級/準上級試験(PHP 8.0 対象・主教材 PHP マニュアル))の出題形式を、実際の問題で確かめられます。ここに掲載する5問は、無料の会員登録で解ける模試 第1回(30問)の冒頭から抜粋したオリジナル問題です。当サイトは全120問を本番CBT準拠の形式で収録しており、この5問はそのごく一部にあたります。

設問1

PHP 8.0 で次のコードを実行した時の出力として、正しいものはどれですか。 ```php var_dump(0 == "abc", "1" == "01", "10" == "1e1", 100 == "1e2"); ```

  • `false`、`true`、`true`、`true`(正解)
  • `false`、`false`、`false`、`true`
  • `true`、`false`、`true`、`false`
  • `true`、`true`、`true`、`true`

解説

PHP 8.0 では、数値と非数値の文字列を比べると、数値を文字列に直して文字列同士で比べます。`0 == "abc"` は `"0" == "abc"` となり `false` です。数値文字列同士は数値として比べるので、`"1" == "01"`、`"10" == "1e1"` は `true` で、数値と数値文字列の `100 == "1e2"` も `true` です。1 つ目を `true` とするのは PHP 7 以前の挙動で、`"abc"` が 0 に変換されていました。`"1" == "01"` と `"10" == "1e1"` を `false` とするのは、文字列として比べるという誤解です。`100 == "1e2"` は指数表記も数値として解釈されるため `true` で、4 つ目を `false` とするのも誤りです。

設問2

PHP 8.0 で次のコードを実行した時、出力として正しいものはどれですか。 ```php var_dump(str_contains("abc", "")); ```

  • Warning が出たうえで bool(false) が出力される
  • ValueError が投げられ、処理が中断する
  • bool(false)
  • bool(true)(正解)

解説

`str_contains()` は PHP 8.0 で追加された関数で、探す文字列が空文字列の場合は常に true を返します。空文字列は、どの文字列にも先頭位置で含まれると扱われるためです。false になるのは、探す文字列が実際に含まれていない場合だけです。空文字列の針は ValueError の対象ではありません(ValueError になるのは `explode()` の区切り文字が空の場合などです)。警告も出ず、true が返ります。

設問3

PHP 8.0 で次のコードを実行した時の出力として、正しいものはどれですか。 ```php var_dump(null == false, 0 == "", "0" == false, "" == null); ```

  • `false`、`false`、`true`、`true`
  • `true`、`false`、`true`、`true`(正解)
  • `true`、`true`、`true`、`true`
  • `true`、`false`、`false`、`true`

解説

`null == false` は、どちらも真偽値として見ると `false` 同士なので `true` です。`0 == ""` は、空文字列が数値ではないため 0 を文字列 `"0"` に直して比べ、`false` になります。`"0" == false` は文字列を真偽値に直すと `false` になるので `true`、`"" == null` も `true` です。2 つ目を `true` とするのは PHP 7 以前の挙動です。`null == false` を `false` とするのは、`null` と真偽値のゆるい比較を取り違えた誤りです。`"0" == false` を `false` とするのは、`"0"` が真偽値では `false` になる規則を忘れた誤りです。

設問4

次のコードを PHP 8.0 で実行する Web ページがあります。`$name` に `x' onmouseover='alert(1)` が入った時、XSS が成立してしまう理由として、正しいものはどれですか。 ```php echo "<input value='" . htmlspecialchars($name) . "'>"; ```

  • 既定では `<` と `>` が変換されないため、新しいタグを挿入できるため
  • フラグを省略した時の既定では単一引用符が変換されず、属性値を `'` で閉じて別の属性を挿入できるため(正解)
  • UTF-8 の文字列は htmlspecialchars の変換の対象外のため、値がそのまま出力されるため
  • 既定では二重引用符が変換されないため、値の途中の `"` でタグを閉じられるため

解説

PHP 8.0 の htmlspecialchars の既定のフラグは `ENT_COMPAT | ENT_HTML401` で、二重引用符は変換されますが単一引用符は変換されません。値を `'` で囲んだ属性では、入力中の `'` で属性を閉じて `onmouseover` などを挿入できます。`ENT_QUOTES` を指定すれば単一引用符も `&#039;` に変換されます。二重引用符は既定でも `&quot;` に変換されます。`<` と `>` も既定で変換されます。文字種にかかわらず特殊文字は変換されます。なお、不正な UTF-8 の文字列は ENT_SUBSTITUTE を付けない限り空文字列になります。

設問5

PHP 8.0 で次のコードを実行した時の動作として、正しいものはどれですか。 ```php $r = "abc" * 1; ```

  • 警告なしで、`$r` は `0` になる
  • 警告が出て、`$r` は `0` になる
  • `TypeError` の例外となり、`$r` には何も代入されない(正解)
  • `$r` は文字列 `"abc"` のまま変わらない

解説

PHP 8.0 では、数値として解釈できない文字列を算術演算の被演算子にすると `TypeError`(`Unsupported operand types`)が投げられます。警告を出して 0 として計算を続けるのは、PHP 7.1〜7.4 の挙動です。警告も出さずに 0 になるのは PHP 7.0 以前の挙動で、8.0 では例外になります。乗算の結果が元の文字列のままになることもなく、演算は必ず数値を返すか例外になります。

続きは、会員登録なしでそのまま50問解けます。採点と解説つきで、上と同じ本物の問題です。

登録なしで50問解く