続いて、sample3の「完了画面(purchase.php)」でポイントとなる個所を解説します。
  
    1   <?php 
        (省略) 
5   $order_no = addslashes($_SESSION["order_no"]); 
6   $now = date("Y/m/d H:i:s", time()); 
7   $name = addslashes($_POST["name"]); 
8   $name = htmlspecialchars($name); 
9   $address = addslashes($_POST["address"]); 
10  $address = htmlspecialchars($address); 
11  $apache = addslashes($_SESSION["apache"]); 
12  $qmail = addslashes($_SESSION["qmail"]); 
13  $mysql = addslashes($_SESSION["mysql"]); 
14  $bind = addslashes($_SESSION["bind"]); 
15 
16  $mysqli = new mysqli("localhost", "php", "password", "sample_db"); 
17 
18  if(mysqli_connect_errno()){ 
19    die("MySQLサーバ接続に失敗しました<br> 理由:" . mysqli_connect_error()); 
20  } 
21 | 
  
 メニュー画面(menu.php)では、次のような手順でMySQLを操作しました。完了画面(purchase.php)でも同じ手順でMySQLを操作します。
- $mysqli= new mysqli() (MySQL サーバへの接続を表すオブジェクト$mysqliを取得)
 ↓ 
- mysqli_connect_errno()の確認
 ↓ 
- クエリー実行
 ↓ 
- $mysqli->close()
 
 
  
5〜14行目
 フォームで入力された値をデータベースに登録するため、事前に危険な文字列を取り除きます。連載第3回目のsample1やsample2では、シェルに対して特別な意味を持つ文字列をエスケープするためにescapeshellcmd()を使用しました。SQLクエリーで特別な意味を持つ「'(シングルクオート)」「"(ダブルクオート)」「\(バックスラッシュ)」「NUL(NULL バイト)」のような文字列をエスケープするにはaddslashes()を使用します。addslashes()を使用しないとSQL Injection(SQLインジェクション)の危険性があります(注)。
  
    22  $result = $mysqli->query 
      ("SELECT order_no FROM order_main WHERE order_no = '$order_no'"); 
23 
24  if($result->num_rows != 0){ 
25    die("すでに注文済みです"); 
26  } 
27 
28  $mysqli->query("SET NAMES utf8"); | 
  
22〜26行目
 ここでは、二重発注の確認を実施しています。「SELECT COUNT()」クエリーで該当件数を引き出します。同じ注文番号で注文を受けると、該当件数が0ではない(初めての注文ではない)ため処理を終了させます(24〜26行目)。続いて、氏名や住所といったマルチバイト文字を挿入するため、28行目で「SET NAMES」クエリーを実行して、MySQLサーバにUTF-8の使用を明示して、不要な文字コードの自動変換を防止します。
  
    29  $mysqli->autocommit(FALSE); 
30 
31  $query =<<<EOS 
32  INSERT INTO order_main 
33  values 
34  ('$order_no','$now','$name','$address') 
35  EOS; 
36 
37  if( !$mysqli->query($query) ){ 
38    die("登録に失敗しました(3001) " . $mysqli->error); 
39  } 
40 
41  if($apache > 0){ 
42    if( !$mysqli->query("INSERT INTO order_item 
 values ('$order_no','$now','apache','$apache')") ){ 
43      die("登録に失敗しました(3002) " . $mysqli->error); 
44    } 
45  } 
46  if($qmail > 0){ 
47    if( !$mysqli->query("INSERT INTO order_item 
 values ('$order_no','$now','qmail','$qmail')") ){ 
48      die("登録に失敗しました(3003) " . $mysqli->error); 
49    } 
50  } 
51  if($mysql > 0){ 
52    if( !$mysqli->query("INSERT INTO order_item 
 values ('$order_no','$now','mysql','$mysql')") ){ 
53      die("登録に失敗しました(3004) " . $mysqli->error); 
54    } 
55  } 
56  if($bind > 0){ 
57    if( !$mysqli->query("INSERT INTO order_item 
 values ('$order_no','$now','bind','$bind')") ){ 
58      die("登録に失敗しました(3005) " . $mysqli->error); 
59    } 
60  } 
61  $mysqli->commit(); | 
  
29行目
 トランザクションを開始します。
31〜35行目
 INSERTクエリーが長くなってしまうため、ここではヒアドキュメントを使用します。
29〜61行目
 トランザクション中では、以下の処理が行われます。
- トランザクション開始
 ↓ 
- order_mainテーブルに「注文番号/現在日時/氏名/住所」を登録
 ↓ 
- Apacheの注文があれば、order_itemテーブルに「注文番号/現在日時/アイテム名apache/注文件数」を登録
 ↓ 
- qmailの注文があれば、order_itemテーブルに「注文番号/現在日時/アイテム名qmail/注文件数」を登録
 ↓ 
- MySQLの注文があれば、order_itemテーブルに「注文番号/現在日時/アイテム名mysql/注文件数」を登録
 ↓ 
- BIND9の注文があれば、order_itemテーブルに「注文番号/現在日時/アイテム名bind/注文件数」を登録
 ↓ 
- コミット
 
 
  
 各データの登録では、エラーチェックを行っています。もし、エラーがあればdie("")が実行されて、コミットまでたどり着きません。つまり、登録データはロールバックされて、order_mainにもorder_itemにもデータは登録されず登録前の状態に戻ります。
  
    62  $result->close(); 
      63  $mysqli->close(); 
      (省略) 
      68  ?> | 
  
62〜68行目
 MySQLサーバとの処理が終了したところで、各オブジェクトを解放します。
 第3回目から今回まで、段階的に3つのサンプルを紹介しました。PHPやMySQLを使用すれば、開発規模が大きくなった場合にも比較的単純な手順でオンラインストアを構築できます。
 次回は、さらに機能を加え、より本格的なオンラインショッピングサイトに近づけていきましょう! (次回に続く)