もくじ


じつは、最初にPHPを学ぶのに使ったのはこの本。

PHP入門 確認画面付きのお問い合わせフォームをつくりながらPHPを学ぶ(第2版) (DESIGNMAP BOOKS) Kindle版

その後に「誰もが~」をやって、今このお問い合わせの2周めをやっています。

誰もが~のときにメモらなかったことを主に書いていきます。

※自分用のノートなので、書籍を見ながら読む前提です(コードを追加する位置などここには詳細に書いていません)。可能であれば書籍とともにこのページをご利用ください。2023.9.11現在Unlimitedでも読める本です。

前ページで入力画面と確認画面を作ったので、次は完了画面でデータベースにデータを入れるのですが、セキュリティなど色々やるので、いっぱいメモします。

クロスサイトリクエストフォージェリ対策

クロスサイトリクエストフォージェリについて。

クロスサイトリクエストフォージェリという有名な攻撃方法があります。これは、ユーザーがあるサイトでログインをした状態で、他のサイトを閲覧しただけで、そのサイトにコードが仕掛けられていると、ユーザーが意図しない操作を、ユーザーの権限を利用して実行されてしまいます。

例えば、SNSサイトで勝手にパスワードが更新されてしまう、勝手に投稿されてしまう、自分が投稿した記事が削除されてしまうという不具合がおきます。

PHP入門 確認画面付きのお問い合わせフォームをつくりながらPHPを学ぶ(第2版)より

前ページで作ったお問い合わせフォームはこのリスクがあるので対策を実装する、とのこと。

ワンタイムチケットを発行する(なんかかっこいいぞw)

ワンタイムチケットは一回限りのランダムな文字列。form2.phpの確認画面でワンタイムチケットを発行し、それを持ってform3.phpに行けばきちんとしたアクセスとして認識される。
直接form3.phpにアクセスしたり、form3.phpに連続アクセス(リロード)したりするとチケットがないので不正なアクセスと認識されて処理は行われない。

form2.phpにコードを追加する。(form2.phpについては前ページ

$_SESSION['token'] = base64_encode(openssl_random_pseudo_bytes(48));
$token = htmlspecialchars($_SESSION['token'],ENT_QUOTES);

<form action="form3.php" method="post">
    <input type="hidden" name="token" value="<?php echo $token ?>">

PHP入門 確認画面付きのお問い合わせフォームをつくりながらPHPを学ぶ(第2版)より

PHPコードはHTML開始より上に書きます。

openssl_random_pseudo_bytesは関数で、疑似乱数を生成する。実際の乱数とは違って計算的に生成されるので疑似乱数と呼ぶ。
base64_encodeも関数で、MINE base64方式でデータをエンコードする。(MINE base64方式は、バイナリデータをASCII文字列にエンコードする方法の1つ)

上の2行は、ランダムな文字列を作って$_SESSIONのtokenに代入し、その値にHTMLタグが含まれていた場合はhtmlspecialcharsとENT_QUOTESによって無効にし、$tokenに代入しなおしている。

下の2行のうち1行目はすでに書いてあるので、追加するのは<input type="hidden"~の行。
上の2行で$tokenに代入した文字列をinputタグの値にセットする。(type="hidden"により画面には表示されないが、ソースを見ると文字列がセットされているのがわかる)

ChatGPT
バイナリデータとASCII文字列について、基本的な概念を以下に説明します。

バイナリデータ:
  • 定義: バイナリデータは、0と1の2つの数値のみを使用するデータのことを指します。
  • 特性: 画像、音声、実行ファイルなどのデータは基本的にバイナリ形式で保存されています。
  • 表示: テキストエディタでバイナリファイルを開くと、通常は読めない文字やガヤクチャーが表示されることが多いです。
ASCII文字列:
  • 定義: ASCII(American Standard Code for Information Interchange)は、数字、英字、特定の記号などの文字を、0から127までの7ビットの数値で表現する文字コードの標準です。
  • 特性: ASCII文字列は、人間が読むことができるテキストとして表現される文字のセットです。例: "Hello, World!"
  • バイナリとの関係: 実際には、コンピュータ内部ではASCII文字もバイナリデータとして保存されます。しかし、これらのバイナリの組み合わせは特定のASCII文字に対応しています。例えば、ASCIIでは、文字「A」は数値65(バイナリで01000001)に対応します。
なぜBase64エンコーディングが必要か:

コンピュータが理解するためのバイナリデータ(0と1)と人間が読むことができるテキストの間には大きな違いがあります。特に、多くのコンピュータシステムやネットワークプロトコルはテキストデータのみを扱うように設計されているため、バイナリデータをそのまま転送することはできません。

ここでBase64エンコーディングの役割が登場します。Base64エンコーディングは、バイナリデータをASCII文字セットの一部である64の異なる文字を使用して表現する方法です。これにより、多くのシステムやプロトコルで安全に転送できるようになります。

たとえば、電子メールはもともとテキストのみを送信するためのものでしたが、Base64エンコーディングを使用することで、画像や音声などのバイナリデータをメールの本文に埋め込むことができるようになりました。

ワンタイムチケットのチェック&破棄

form3.phpにコードを追加する。

session_start();

if(isset($_POST['token'], $_SESSION['token']) && ($_POST['token'] === $_SESSION['token'])){
  unset($_SESSION['token']);
  echo "きちんとしたアクセスです";
}else{
  exit("不正なアクセスです");
}

PHP入門 確認画面付きのお問い合わせフォームをつくりながらPHPを学ぶ(第2版)より

(isset($_POST['token'], $_SESSION['token'])は、$_POSTにtokenキーとその値、$_SESSIONにtokenキーとその値がセットされているかをチェックしている。

($_POST['token'] === $_SESSION['token'])は、$_POSTメソッドで送られてきたワンタイムチケットの値と、$_SESSIONに保存されているワンタイムチケットの値が同じかどうかチェックしている。

ここでちょっと疑問が。

$_SESSION['token']はhtmlspecialcharsで一部の文字が別の文字に置き換わる。そうなった場合、$_POST['token']とは違うものになってしまう。
でも、base64_encodeで変換されたものには置き換わる文字が含まれないはず。だから結局この2つは同じものになる。htmlspecialcharsは使わなくてもいいよね。

それでもあえてhtmlspecialcharsを使ってコードを書いているのはどうして?

ChatGPT
htmlspecialcharsを使用するのは、一般的にユーザーからの入力をそのままブラウザに出力する場合にXSS(クロスサイトスクリプティング)攻撃を防ぐための一般的なプラクティスです。

しかし、base64_encodeの結果として得られる文字列は、先ほども説明した通り、特殊な文字を含まないので、実際にはhtmlspecialcharsの使用は不要です。特に、この具体的なコード例のコンテキストで$_SESSION['token']の値をHTMLエスケープする必要はないでしょう。

その上で、なぜそれが行われているのか理由として考えられるのは:

  1. コーディングの慣習: ユーザーからの入力やセッション変数をHTMLに出力する際には常にhtmlspecialcharsを使用するという慣習やルールがある場合。これは、開発者が特定のシチュエーションでのみエスケープをスキップするのを避けるためのものであり、セキュリティのベストプラクティスとして取り入れられていることもあります。

  2. 再利用性: 将来的にトークン生成のロジックが変更され、base64_encode以外の方法が使用される可能性が考えられる。その場合、出力時に安全にエスケープする習慣があると、未来の変更で安全なコードを維持しやすくなります。

  3. 明示的なセキュリティ: コードを見た人が、開発者がセキュリティを意識していることを認識しやすくするため。

しかしながら、冗長に思える場合もあり、必要ないと感じれば省略しても問題ないです。大切なのは、どのようなデータを扱っているのか、そしてそのデータがどのように使用されるのかを正確に理解することです。

さらに、

初心者向けの書籍やチュートリアルでは、明示的にセキュリティ対策を行うことで、読者がセキュリティを常に意識することの重要性を学べるように設計されていることが多いです。このようなアプローチは、初心者が将来的に独自のコードを書く際の基盤として役立ちます。

とのこと。

で続き。これら2つの値が同じだった場合、unsetでこのワンタイムチケットは破棄され、"きちんとしたアクセスです"と表示される。
同じでない場合は"不正なアクセスです"と表示され、その後のコードは処理されない。

データベースを作る

phpMyAdminの管理画面からデータベースを作るのですが、照合順序に「utf8_unicode_ci」を選択するという指示。これの前にやった誰もがあきらめずにすむPHP超入門では「utf8_general_ci」を選択した。unicodeとgeneral。これの違いっていったい何だろう?

ChatGPT
utf8_unicode_ciutf8_general_ci は、MySQL(phpMyAdminを通してアクセスすることが多い)で使用される文字セット utf8 の2つの異なる照合順序(collation)です。照合順序は文字列の比較やソートをどのように行うかを定義します。

これら二つの照合順序の違いを理解するためには、以下の点に注意してください:  

  1. Performance: utf8_general_ciutf8_unicode_ci よりも若干高速です。これは、utf8_general_ci が文字の比較をより単純化された方法で行うためです。

  2. Accuracy: utf8_unicode_ci は Unicode 標準を使用して文字の比較を行います。これは、多くの言語の特定の文字や記号の比較が utf8_general_ci よりも正確に行われることを意味します。

例として、一部のヨーロッパの言語では特定の文字が2つの別々の文字として扱われることがありますが、utf8_general_ci ではこれらの文字を同じとして扱うことがあります。utf8_unicode_ci は、これらの違いを正確に扱います。

  1. Unicode Version: utf8_unicode_ci の動作は Unicode の特定のバージョンに基づいています。したがって、新しい Unicode バージョンがリリースされるたびに、新しい照合順序が追加されることがあります(例:utf8_unicode_520_ci)。

結論として、もしパフォーマンスが最優先で、文字の比較の精度がそれほど重要でない場合は utf8_general_ci を使用することができます。しかし、文字の比較の精度が非常に重要な場合や、多言語のテキストを取り扱う場合は、utf8_unicode_ci を使用することをおすすめします。

とのこと。

データベース名をcontact_formとして作成。テーブル名をinquiries、カラムを

名前 データ型 長さ/値 デフォルト値 属性 インデックス A_I
id INT UNSIGNED PRIMARY
name VARCHAR 30
email VARCHAR 100
subject TEXT
body TEXT
state TINYINT ユーザー定義,0

データ型のINTは整数型、UNSIGNEDで符号なしの整数になる(マイナスが使えなくなる)。A_IはAUTO_INCREMENT(自動的に順番がつく)。
VARCHARは可変長文字列型、TEXTは文字列型。TINYINTは整数型で8ビット分の整数を格納できる。
PRIMARYは主キー。データがダブらないフィールドにつけられる。

はて、整数型で8ビット分てどのくらいですか??

ChatGPT
TINYINT は、MySQLで使用される整数型の1つです。8ビットという情報から、その値の範囲を計算することができます。

1ビットは2つの状態(0 または 1)を持つことができます。したがって、8ビットでは (2^8 = 256) の異なる値を表現することができます。

  • 符号なし(UNSIGNED)の場合:

    • 0 から 255 の範囲の整数を格納することができます。
  • 符号ありの場合(デフォルト):

    • (2^7 = 128) は符号ビットとして使われるため、
    • -128 から 127 の範囲の整数を格納することができます。

簡単に言うと、TINYINT は符号なしの場合 0〜255、符号ありの場合 -128〜127 の整数を格納することができます。

データベースに接続するコード:「たい焼きの型」と「たい焼き」

form3.phpにコードを追加。

$dsn = 'mysql:dbname=contact_form;host=localhost;charset=utf8';
$user = 'root';
$password = '';

$dbh = new PDO($dsn, $user, $password);
var_dump($dbh);

$dbh = null;

PHP入門 確認画面付きのお問い合わせフォームをつくりながらPHPを学ぶ(第2版)より

データベースの設定(名前など)、ユーザー、パスワードをそれぞれ変数に入れて、それらを使って$dbhインスタンス(オブジェクト)を作ってる??で合ってる?

そして最後の行でデータベースと切断してる。

一冊目と書き方が違うので、違いを理解せねば。

クラスは、たい焼きの型、インスタンスはたい焼きに例えられます。

PHP入門 確認画面付きのお問い合わせフォームをつくりながらPHPを学ぶ(第2版)

PDOクラス、new演算子でクラスからインスタンスを作っている、クラスはたい焼きの型、インスタンスはたい焼きに例えられる。なんかむずかしなー。コンストラクタって何だっけなー。

このへんのわかりやすい説明をChatGPTに求めてみました。

ChatGPT
了解しました。たい焼きの例えをもう少し詳しく解説してみますね。

クラスとインスタンスの関係を理解するため、たい焼きの型(鋳型)と実際に焼かれるたい焼きの関係を考えてみましょう。

  1. クラス(たい焼きの型):

    • クラスは「設計図」や「鋳型」と考えることができます。たい焼きの型のように、具体的なものではなく、形や構造を定義するものです。
    • たとえば、たい焼きの型が「魚の形をしていて、あんこを中に詰められる」ことを定義しているように、クラスは特定の属性やメソッド(機能)を持つことを定義しています。
  2. インスタンス(実際のたい焼き):

    • インスタンスはクラス(設計図)を基にして作られた「具体的なもの」です。
    • たい焼きの鋳型(クラス)を使って、実際にたい焼きを焼くと、そのたい焼きがインスタンスになります。鋳型はそのままでは食べられませんが、たい焼きは食べられますよね。同様に、クラスそのものではなく、クラスから作成されたインスタンスを通じて具体的な動作をさせたり、情報を保持したりします。
  3. new演算子:

    • new演算子は、たい焼きの型(クラス)から実際のたい焼き(インスタンス)を作る過程を担当する「たい焼きを焼く機械」のようなものです。
    • PHPや多くのオブジェクト指向言語で、クラスからインスタンスを作成するときに使用します。

この例えを用いると、クラスは「型」としての存在で、その設計に基づいて具体的なものを作成するための「鋳型」のような役割を果たしています。そして、インスタンスはその「鋳型」から具体的に作られたもの、つまり「実際のたい焼き」のような存在と言えます。

ChatGPT
もちろん、コンストラクタについて説明します!

コンストラクタは、クラスからインスタンスが作成される際に、自動的に実行される特殊なメソッドです。オブジェクト指向プログラミングにおけるコンストラクタの役割は、新しく作成されるインスタンスの初期化を行うことです。例えば、インスタンスのプロパティに初期値を設定したり、必要なリソースを準備したりすることができます。

-中略-

コンストラクタを使う利点:

  1. インスタンスの初期化処理を一元化できる。
  2. インスタンス作成時に必要な設定や値の確認を行うことができる。
  3. インスタンス作成時に必須の処理や値の設定を強制することができる。

たい焼きの例えで言うと、コンストラクタはたい焼きを焼く際に、必ず魚の形をしてあんこを詰める、という工程を確実に行う役割を果たします。

さっきのコードでいうと、具体的にはどれがどれ?

ChatGPT
このコードにおいて、PDO は PHP に組み込まれているデータベースへの接続を管理するためのクラスです。このクラスを使って、データベースに接続するためのインスタンス(オブジェクト)を作成しています。

以下に、たい焼きの例えと照らし合わせながら詳しく解説します:

  1. たい焼きの型(クラス):

    • このコードの場合、PDO がたい焼きの型に相当します。PDO クラスは、どのようにデータベースに接続するかの「設計図」や「型」の役割を果たしています。
  2. 具体的なたい焼き(インスタンス):

    • $dbh = new PDO($dsn, $user, $password); の部分で、新しい PDO インスタンス(たい焼き)を作成しています。ここで $dbh は、具体的なたい焼き(インスタンス)に相当します。
  3. コンストラクタ:

    • たい焼きの例えにおける「魚の形をしてあんこを詰める工程」に該当するのが、このコンストラクタです。PDO クラスのコンストラクタは、データベース接続のための情報(DSN、ユーザー名、パスワード)を受け取り、それをもとにデータベースに接続するという初期化の役割を果たします。このコードにおいて、コンストラクタの引数として $dsn, $user, $password が渡されています。
  4. 引数:

    • コンストラクタで必要な情報や材料を渡すためのものです。この例で言えば、$dsn, $user, $password がそれに当たります。たい焼きの例えでは、これは「あんこの種類や魚の形のサイズ」のようなものに該当するでしょう。

要するに、new PDO($dsn, $user, $password); この行で「たい焼きの型(PDOクラス)」を使って「具体的なたい焼き($dbhインスタンス)」を作成しています。そして、その過程でコンストラクタが動作して、データベースへの接続が行われます。

なんかやっと、イメージできてきた、、

SQLのINSERT文

コードの解説に、初学を超えたレベルだから、今のところはおおまかな流れや段取りをつかめと書いてあります。

$name = $_SESSION['name'];
$email = $_SESSION['email'];
$subject = $_SESSION['subject'];
$body = $_SESSION['body'];

$dbh->query('SET NAMES utf8');
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$sql = 'INSERT INTO inquiries (name, email, subject, body) VALUES (?,?,?,?)';
$stmt = $dbh->prepare($sql);
$stmt->bindValue(1, $name, PDO::PARAM_STR);
$stmt->bindValue(2, $email, PDO::PARAM_STR);
$stmt->bindValue(3, $subject, PDO::PARAM_STR);
$stmt->bindValue(4, $body, PDO::PARAM_STR);
$stmt->execute();

PHP入門 確認画面付きのお問い合わせフォームをつくりながらPHPを学ぶ(第2版)より

いつものように$_SESSIONからnameやemailなどを取り出す。
たい焼きが出来上がったあとに、後半のコードを書いていく。

  • 後半一行目、PODオブジェクトのqueryメソッド(SQL文を発行する)を呼び出している。このコードは文字化けを防ぐ。
  • 後半2行目、セキュリティ対策。静的プレースホルダを指定している。
  • 後半4行目、PDOオブジェクトのqrepareメソッド(SQL文を準備する)を呼び出している。正しく準備されるとメモリにPDOStatementオブジェクトが生成され、$stmtはそれを参照する。
  • 後半3行目がSQL文。テーブルにデータを挿入している。データはプレースホルダ(?)にしておく(セキュリティ対策)。
  • 後半5行目、PDOStatementオブジェクトのbindValueメソッドを呼び出し、変数の値と?を結びつける。
  • 後半9行目、PDOStatementオブジェクトのexecuteメソッドを呼び出し、SQL文を実行している。

少し詳しい説明が欲しかったので、ChatGPTにきいてみました。

ChatGPT

このコードは、セッションから収集された情報(おそらくフォームからの入力情報)をデータベースに保存する処理を行っています。以下に、各部分の詳細な説明をします。

  1. $name = $_SESSION['name'];
    $email = $_SESSION['email'];
    $subject = $_SESSION['subject'];
    $body = $_SESSION['body'];

    上記は、セッション変数からデータを取り出して、それぞれの変数に格納しています。

  2. $dbh->query('SET NAMES utf8');

    こちらは、データベースとの通信で使用する文字セットをutf8に設定しています。これにより、データの文字エンコーディングの問題を回避します。

  3. $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

    この行は、PDO(PHP Data Objects)の設定を変更しています。具体的には、エミュレーションされたプリペアドステートメントの使用を無効にしています。これにより、データベースがネイティブのプリペアドステートメントをサポートしていれば、それを使用するようになります。これは、SQLインジェクション攻撃を防ぐためのセキュリティ対策として推奨されています。

  4. $sql = 'INSERT INTO inquiries (name, email, subject, body) VALUES (?,?,?,?)';
    $stmt = $dbh->prepare($sql);

    ここで、データベースにデータを追加するためのSQL文を準備しています。prepareメソッドを使用して、このSQL文を"プリペアドステートメント"として準備します。これは、SQLインジェクション攻撃を防ぐための重要な手段です。

  5. $stmt->bindValue(1, $name, PDO::PARAM_STR);
    $stmt->bindValue(2, $email, PDO::PARAM_STR);
    $stmt->bindValue(3, $subject, PDO::PARAM_STR);
    $stmt->bindValue(4, $body, PDO::PARAM_STR);

    bindValueメソッドを使用して、先程のSQL文のプレースホルダ(?)に具体的な値をバインド(結びつけ)しています。これにより、実際のデータがSQL文に挿入される準備ができます。

  6. $stmt->execute();

    最後に、executeメソッドを使用して、プリペアドステートメントを実行します。これにより、データがデータベースに挿入されます。

要するに、このコードの流れとしては:

  1. セッションからデータを取得。
  2. データベースの設定を行う。
  3. データをデータベースに追加するSQL文を準備。
  4. SQL文に実際のデータをバインド。
  5. SQL文を実行してデータベースにデータを保存。

という手順で動作しています。

プリペアドステートメント、エミュレーションされたプリペアドステートメント、ネイティブのプリペアドステートメント、について教えて下さい。

ChatGPT
もちろん、これらの用語について詳しく説明します。

1. プリペアドステートメント (Prepared Statement)

プリペアドステートメントは、SQLインジェクション攻撃からデータベースを保護するための技術の1つです。具体的には、SQLクエリとして実行される前にSQLとデータを分離します。クエリがデータベースに送信される際、実際のデータ値の代わりにプレースホルダー(通常 ?:name のような形)が使用され、後で実際のデータがこれらのプレースホルダーにバインドされます。

2. エミュレーションされたプリペアドステートメント (Emulated Prepared Statement)

エミュレート(模倣)されたプリペアドステートメントは、実際にはデータベースサーバーでの本物のプリペアドステートメントを使用せずに、クライアントサイド(この場合はPHPのPDO拡張機能)でプリペアドステートメントの動作を模倣するものです。これは、データベースがネイティブのプリペアドステートメントをサポートしていない場合や、PDOがこの機能をエミュレートする設定になっている場合に行われます。

3. ネイティブのプリペアドステートメント (Native Prepared Statement)

ネイティブのプリペアドステートメントは、データベースサーバー自体がサポートしている本物のプリペアドステートメントを指します。この場合、SQLクエリとデータは別々にデータベースサーバーに送信され、サーバー側で結合されて実行されます。これにより、悪意のあるデータがクエリの一部として実行されるリスクを大幅に低減できます。

総括:

  • プリペアドステートメントはSQLインジェクション攻撃からの防御手段の1つです。
  • エミュレーションされたプリペアドステートメントはクライアントサイドでの模倣で、ネイティブのものと完全な同等性はありません。
  • ネイティブのプリペアドステートメントはデータベースサーバー自体が提供するセキュリティ機能で、最も信頼性が高いとされています。

PDOでは、PDO::ATTR_EMULATE_PREPARES属性を使って、エミュレーションされたプリペアドステートメントを使用するかどうかを制御できます。セキュリティを最大化するために、可能な限りネイティブのプリペアドステートメントを使用することが推奨されています。


inquiries (name, email, subject, body)のname, email, subject, bodyはデータベース側のテーブルのカラム名、そこに仮に(?,?,?,?)をいれている。bindValue(1, $name, PDO::PARAM_STR)などで実際の値も入れている、1,2,3,4は何の数字?
これらは同じ変数に格納されて、データベースに値が挿入されるときにそれらの処理がされるという理解で、あっているのでしょうか?

ChatGPT

はい、あなたの理解は基本的に正確です。詳しく説明します。

  1. inquiries (name, email, subject, body) は、inquiries というテーブルにデータを挿入する際、どのカラムにデータを入れるかを示しています。name, email, subject, body はデータベーステーブルinquiriesのカラム名を示しています。

  2. (?,?,?,?) はプリペアドステートメントのプレースホルダーで、実際の値が後からバインドされる場所を示します。これにより、SQLインジェクション攻撃からの防御が図られています。

  3. bindValue(1, $name, PDO::PARAM_STR) では、先ほどのプレースホルダーの中で1番目の?$nameというPHP変数の値を文字列としてバインドしています。同様に、2番目、3番目、4番目の?もそれぞれの値でバインドされます。

  4. 1, 2, 3, 4 の数字は、どのプレースホルダーに対して値をバインドするかを示す順番を示しています。具体的には、$stmt->bindValue(1, $name, PDO::PARAM_STR)は、最初の?$nameという変数で置き換えることを示しています。

要するに、このコードはデータベースのinquiriesテーブルの特定のカラムに、特定の変数の値を安全に挿入するための方法を示しています。そして、$stmt->execute()が呼び出されると、実際にデータがテーブルに挿入されます。

だいたいは理解できていたみたいだけど、ややこしいです、、

それから、
実際のコードは$stmt->execute();で動くのですが、コードの説明箇所では$stmt->execute($data);となっていました。誤字かな?と思いましたがいちおうChatGPTにきいてみました。

ChatGPT

$stmt->execute();$stmt->execute($data); は、PDOのプリペアドステートメントを実行する際の2つの異なる方法を示しています。どちらも有効な方法で、使用する方法はコーディングスタイルやシチュエーションによります。

  1. $stmt->execute();

    この方法は、前に bindValue()bindParam() メソッドを使用して、SQLクエリ内のプレースホルダ(? または :paramName)に対応する値をバインドしてから execute() を呼び出す際に使用されます。例:

    $stmt->bindValue(1, $name, PDO::PARAM_STR);
    $stmt->bindValue(2, $email, PDO::PARAM_STR);
    $stmt->execute();
  2. $stmt->execute($data);

    この方法は、execute() メソッドの引数として配列を直接渡すことで、プレースホルダに対応する値をバインドします。例:

    $data = [$name, $email];
    $stmt->execute($data);

    この方法を使用する場合、bindValue()bindParam() メソッドを呼び出す必要はありません。

解説箇所が $stmt->execute($data); としている場合、その方法を示している可能性があります。しかし、コードが bindValue() を使用して値をバインドしている場合、$stmt->execute(); だけでも問題なく動作します。

結論として、どちらの方法を選択するかは好みや状況によるので、必要に応じて適切な方法を選択してください。

誤字ではありましたが、どちらも有効なんですね。

セッションの破棄

セッションと、Cookieファイルを削除する必要がある。


$_SESSION = array();
if(ini_get("session.use_cookies")){
  $params = session_get_cookie_params();
  setcookie(session_name(), '', time() -42000,
  $params["path"], $params["domain"], $params["secure"], $params["httponly"]);
}

session_destroy();

PHP入門 確認画面付きのお問い合わせフォームをつくりながらPHPを学ぶ(第2版)より

セッション破棄のコードはワンパターン、とのこと。

わかりやすい説明はChatGPTにお願いしました。

ChatGPT
このコードはセッションを完全に破棄するための一連の処理を示しています。一つ一つの部分について簡単に解説します。

  1. $_SESSION = array();

    • これは $_SESSION 配列を空にする操作です。これにより、セッション変数に保存されたすべてのデータが消去されます。
  2. if(ini_get("session.use_cookies")){ ... }

    • ini_get("session.use_cookies") は PHP の設定で、セッションがクッキーを使用しているかどうかを確認します。
    • クッキーを使用している場合、その内部のコードが実行されます。
  3. $params = session_get_cookie_params();

    • これは、現在のセッションクッキーの設定を取得する関数です。$params には、クッキーの設定情報(path, domain, secure, httponly など)が連想配列として格納されます。
  4. setcookie(session_name(), '', time() -42000, ...);

    • この行は、セッションクッキーを無効にするために使用されます。セッションIDを格納しているクッキーの有効期限を過去の時間に設定することで、クッキーを削除しています。
  5. session_destroy();

    • これは、セッションそのものを破棄する関数です。セッションに関連するすべてのデータとリソースが解放されます。

要するに、このコードは以下の手順で動作します:

  1. セッション変数をすべて削除
  2. セッションクッキーが使用されていれば、そのクッキーを削除
  3. セッションそのものを破棄

これにより、セッション関連のデータやクッキーがクライアントやサーバーから安全に削除されます。

書籍はこのあとに全ソースコードの掲載があります。

初学者向けの本ですが、いろはのいから説明していくのではなく、実際にお問合せフォームを作りながらそれに必要なものを学んでいく構成です。
説明もわかりやすいし(自動販売機やたい焼きのたとえとか)、実際にお問い合わせフォームが出来上がるので、最後まで飽きずに学べました。

PHP入門 確認画面付きのお問い合わせフォームをつくりながらPHPを学ぶ(第2版) (DESIGNMAP BOOKS) Kindle版