ショッピングサイトなどで商品を探すときに使われている「検索フォーム」はご存じですよね。
そんな「検索フォーム」が使えるWebシステムを自分でも実装してみたいと思ったことはありますでしょうか。
今回の記事は、そういった方を対象に「検索フォーム」の実装方法や実装時の注意点などを解説していきます。
目次
PHPでの検索フォーム実装方法 基礎知識
PHPで「検索フォーム」を実装するには、いくつかの知識が必要となってきます。
まずは基本的な処理の流れを記載していきますので、どんな知識が必要になるのかみていきましょう。
html
Webシステム開発を行うにあたり、必ず知っておく必要があるのが「html」です。
htmlとは「HyperText Markup Language」の略称で、Webページを作成するために使われている言語です。
htmlを使うことで、ブラウザ画面に文字や画像などを表示させたり、クリックすると別のページへ移動するリンクを埋め込んだりすることができるようになります。
「検索フォーム」を実装する場合は、文字を入力する「テキストフォーム」や検索を実行する「検索」ボタンなどをhtmlで構築することになりますので、ユーザーとの最初の接点となる部分と言えるでしょう。
PHP・MySQLでの処理の流れ
「テキストフォーム」で入力した内容は「検索」ボタンでサーバーに送信され、指定したプログラムで処理されることになります。
プログラムは色々な言語で書かれることになりますが、Webシステムを構築するのに最も適していると言われているのが「PHP」です。
PHPとは正式名称を「PHP:Hypertext preprocessor」といい、htmlと組み合わせて記述することができるプログラム言語のため、多くのWebシステム開発に使われています。
「検索フォーム」を実装する場合は、htmlから受け取ったデータを「SQL文」に組み込み、「MySQL」と呼ばれるデータベースシステムに送信する処理を構築することになります。
また、データベースから返された結果をhtmlにわたす役目もありますので、ユーザーとデータベースとの橋渡し的な存在と言えるでしょう。
MySQLによるデータベース構築
MySQLとはオープンソースで提供されているデータベースシステムのことで、無料のレンタルサーバーでも利用できることが多く、大規模なWebシステムでの運用にも耐えられる頑丈な作りとなっているため、ほとんどのWebシステムで利用されているといっても過言ではありません。
「検索フォーム」を実装する場合は、プログラムからSQL文を受け取り、データベースにあるデータを検索したあと、プログラムにデータベースの抽出結果を返却する処理を行います。
ユーザーの要求を実際に実行していく部分となりますので、Webシステムで一番重要な部分を担っていると言えるでしょう。
当然、データベースを理解していなければWebシステムを構築することはできませんので、データベースの基礎知識について、もう少し詳しくみていきましょう。
リレーショナルデータベース
MySQLに限らず、多くのデータベースは「リレーショナル型」と呼ばれる手法でデータを扱っています。
リレーショナルデータベースを簡単に説明すると、以下のような特徴があるデータベースです。
- 行×列の表形式でデータを管理
- 複数の表をキーとなる情報で結合して表現
例えばショッピングサイトで販売する商品を「商品ID」「商品名」「価格」「カテゴリ」といった項目で管理している場合、リレーショナルデータベースでは、「商品」という表と「カテゴリ」という表といった具合に、複数の表に分けてデータを管理し、「カテゴリID」というキーで結合して表現することになります。
このように、複数の表を使ってデータを管理することで、データの整合性を確保することができるようになります。
例えば、上表の場合、テレビとブルーレイレコーダーは「ビジュアル家電」という同じカテゴリで管理されなければなりませんが、ブルーレイレコーダーのカテゴリを「ビデオ家電」と誤登録してしまうと、同じカテゴリで管理できなくなってしまいます。
商品表にはカテゴリIDだけ登録し、カテゴリ表と照合しながら管理でき、データベース上に存在しないデータの誤登録を防ぐという点が、リレーショナルデータベースの大きな特徴と言ってよいでしょう。
ER図・状態遷移図
プログラム言語やデータベースを理解したところで早速Webシステム開発に着手してみましょう、と言いたいところですが、実際にWebシステムを構築していくには、それだけでは不十分である可能性があります。
特に大規模なデータベースシステムを構築したい場合、データベースをER図というもので視覚的に表したり、システム上の画面遷移や状態遷移を明示したりするスキルが必要となってきます。
スキル習得は一朝一夕にはいきませんので、ここでは、上述の例で構築したデータベースの場合をER図にしてみることにします。
この図を参考に、各々で構築したいデータベースを想定しながらER図を作る練習をしてみていただければと思います。
なお「検索フォーム」を構築する場合の状態遷移図は以下のようなものになります。
こちらも各々で構築したいWebシステムを想定しながら状態遷移図を作る練習をしていただければと思います。
ER図はともかく、画面遷移図や状態遷移図は人によって様々な書き方があるように思われます。
重要なのは画面や状態の遷移が分かりやすく書けているかどうかがポイントとなりますので、「どのように書けばよいか分からない」と言った方は、堅苦しく考えず「どのように遷移するかが伝わればよい」といった程度の気楽な気持ちで書くとよいかもしれません。
PHPでの検索フォーム実装方法 実装内容
Webシステム構築のための基礎知識を把握したところで、早速、「検索フォーム」を実装する方法について考えていきましょう。
html・form要素
まずはhtml部分です。
「検索フォーム」を実装するには、何はともあれ「検索する文字」を入力する「テキストボックス」と、「入力した内容で検索を実行する」ための「検索ボタン」が必要です。
テキストボックスと検索ボタンについては以下のように記述して実装します。
1 2 3 4 |
<form action="" method="POST"> <input type="text" name=“textbox”> <input type="submit" name="search" value="検索"> </form> |
この場合「textbox」という名前がつけられたテキストボックスと「search」という名前の「検索」ボタンが実装されます。
PHP・$_POST
html部分で実装したフォームに入力されたデータは「検索」ボタンをクリックすることでPHPに送信されます。
PHP側では以下のように記述することでフォームに入力されたデータを取得することができます。
1 |
$textbox = $_POST[“textbox”]; |
この場合、テキストボックスに入力されたデータを$textboxという変数に格納します。
また、検索ボタンが押されたことを判定する処理は以下の通りです。
1 2 3 |
if (isset($_POST["search"])) { //検索ボタン押下時の処理を記述 } |
MySQL・WHERE句
PHPの変数に格納されたデータをSQLに組み込み、データベースを操作する方法はPDOを使います。
1 2 3 4 5 6 7 8 9 |
//PDOを使ってMySQLに接続 $pdo = new PDO(◯◯◯◯,◯◯◯◯,◯◯◯◯, array(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION)); //SQLを作成 $sql = "SELECT * FROM [テーブル名] WHERE [カラム名] = ?"; //executeで実行 $stmt = $pdo->prepare($sql); $stmt->execute(array($textbox)); |
MySQLでの実行結果を出力させる方法は以下のとおりです。
1 2 3 |
foreach($stmt as $row){ echo $row[カラム名]; } |
PHPでの検索フォーム実装方法 プログラミング
それでは、これまで説明した内容をもとに、早速プログラミングしていきましょう。
今回はMySQL上に「t_product」テーブル(商品表)と「t_category」テーブル(カテゴリ)がすでに作成されている前提での説明となります。
Search.phpの作成
テキストエディタで「Search.php」を作成し、以下のコードを記述してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
<?php //データベース情報の指定 $db['dbname'] = "◯◯◯◯"; // データベース名 $db['user'] = "◯◯◯◯"; // ユーザー名 $db['pass'] = "◯◯◯◯"; // ユーザー名のパスワード $db['host'] = "◯◯◯◯"; // DBサーバのURL //エラーメッセージの初期化 $errorMessage = ""; //フラグの初期化 $o = false; //検索ボタンが押された時の処理 if (isset($_POST["search"])) { //入力チェック if (empty($_POST["textbox"])) { $errorMessage = '未入力です。'; } if (!empty($_POST["textbox"])) { $o = true; //入力した文字を変数に格納 $textbox = $_POST["textbox"]; $textboxs = explode(" ",mb_convert_kana($textbox,'s')); $operator_in = $_POST["operator_in"]; $operator_like = $_POST["operator_like"]; $selectbox = $_POST["selectbox"]; //dsnを作成 $dsn = sprintf('mysql:host=%s; dbname=%s; charset=utf8', $db['host'], $db['dbname']); try { //PDOを使ってMySQLに接続 $pdo = new PDO($dsn, $db['user'], $db['pass'], array(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION)); //SQLを作成 if($operator_like == 'like'){ if($operator_in == 'in'){ foreach($textboxs as $textbox){ $textboxCondition[] = "(".$selectbox." LIKE ?)"; $values[] = '%'.preg_replace('/(?=[!_%])/', '', $textbox) . '%'; } $textboxCondition = implode(' OR ', $textboxCondition); }else{ $textboxCondition[] = "(".$selectbox." LIKE ?)"; $values[] = '%'.preg_replace('/(?=[!_%])/', '', $textbox) . '%'; $textboxCondition = implode(' OR ', $textboxCondition); } $sql = "SELECT * FROM t_product left outer join t_category on t_product.t_product_category_id = t_category.t_category_id WHERE $textboxCondition"; }else{ if($operator_in =='in'){ $place_holders = implode(',', array_fill(0, count($textboxs), '?')); $sql = "SELECT * FROM t_product left outer join t_category on t_product.t_product_category_id = t_category.t_category_id WHERE $selectbox IN ($place_holders)"; }else{ $sql = "SELECT * FROM t_product left outer join t_category on t_product.t_product_category_id = t_category.t_category_id WHERE $selectbox = ?"; } } $stmt = $pdo->prepare($sql); if($operator_like == 'like'){ $stmt->execute($values); }else{ if($operator_in =='in'){ $stmt->execute($textboxs); }else{ $stmt->execute(array($textbox)); } } } catch (PDOException $e) { $errorMessage = 'データベースエラー'; } } } ?> <!doctype html> <html> <head> <meta charset="UTF-8"> <title>検索</title> </head> <body> <h1>出力画面</h1> <form id="searchForm" name="searchForm" action="" method="POST"> <p>検索フォーム</p> <div><font color="#ff0000"><?php echo htmlspecialchars($errorMessage, ENT_QUOTES); ?></font></div> <div><input type="checkbox" name="operator_like" value="like" <?php if($_POST["operator_like"]=="like"){echo "checked";} ?> >あいまい検索</div> <div><input type="checkbox" name="operator_in" value="in" <?php if($_POST["operator_in"]=="in"){echo "checked";} ?> >複数検索(スペース区切り)</div> <div><select name="selectbox"> <option value="t_product_name" <?php if($_POST["selectbox"]=="t_product_name"){echo "selected";} ?>>商品名</option> <option value="t_category_name"<?php if($_POST["selectbox"]=="t_category_name"){echo "selected";} ?>>カテゴリ名</option> </select> <input type="text" id="textbox" name="textbox" placeholder="検索したい文字を入力" value="<?php if (!empty($_POST["textbox"])) {echo htmlspecialchars($_POST["textbox"], ENT_QUOTES);} ?>"> <input type="submit" id="search" name="search" value="検索"> </div> </form> <div> <?php if($stmt){ $ct = 0; echo '<p>検索結果<br>'; echo '- - - - - - - - - - - - - - - - - - - - - - - - </p>'; foreach($stmt as $row){ if($ct == 0){ } echo '<div>商品ID:'.$row['t_product_id'].'</div>'; echo '<div>商品名:'.$row['t_product_name'].'</div>'; echo '<div>価格:'.$row['t_product_price'].'</div>'; echo '<div>カテゴリ:'.$row['t_category_name'].'</div>'; echo '<p>- - - - - - - - - - - - - - - - - - - - - - - - </p>'; $ct++; } if($ct ==0){ echo '<div>該当するデータはありません</div>'; } }else{ } ?> </div> </body> </html> |
このファイルをWebサーバーにアップし、ブラウザでSearch.phpにアクセスすると、以下の画面が表示されます。
テキストボックスに文字を入力して商品やカテゴリが検索できれば成功です。
IN演算子の追加方法
「Search.php」では入力フォームにスペース区切り文字を入力することで、複数の文字を検索条件に指定することができる仕様としています。
その処理は以下のように記述することで実装しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
//テキストボックスの入力内容を取得 $textbox = $_POST["textbox"]; //テキストボックスの空白を半角スペースに置換し半角スペース区切りで配列に格納 $textboxs = explode(" ",mb_convert_kana($textbox,'s')); //配列の要素数分のプレースホルダを生成 $place_holders = implode(',', array_fill(0, count($textboxs), '?')); //SQL作成 $sql = "SELECT * FROM [テーブル名] WHERE [カラム名] IN ($place_holders)"; //実行 $stmt = $pdo->prepare($sql); $stmt->execute($textboxs); |
like演算子の追加方法
同様にlike演算子であいまい検索する場合は以下のように記述します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
//テキストボックスの入力内容を取得 $textbox = $_POST["textbox"]; //テキストボックスの空白を半角スペースに置換し半角スペース区切りで配列に格納 $textboxs = explode(" ",mb_convert_kana($textbox,'s')); //SQL文に追加する字句の生成 foreach($textboxs as $textbox){ $textboxCondition[] = "([カラム名] LIKE ?)"; $values[] = '%'.preg_replace('/(?=[!_%])/', '', $textbox) . '%'; } //各Like条件を「OR」でつなぐ $textboxCondition = implode(' OR ', $textboxCondition); //SQLの作成 $sql = "SELECT * FROM [テーブル名] WHERE $textboxCondition"; //実行 $stmt = $pdo->prepare($sql); $stmt->execute($values); |
SQLインジェクション対策
以上が、PHPでWebシステムを構築するための方法となりますが、最後に「SQLインジェクション」というものについて説明しておきたいと思います。
「SQLインジェクション」とはWebシステムの入力フォームに「SQL文を含む文字列」を入力して情報を盗み取ったり、データを改ざんしたりする攻撃のことを指します。
「検索フォーム」のようにユーザーから文字列を入力させた内容をデータベースに送信する必要があるものについては必ず考慮しておかなければなりません。
SQL文の中には想定している文字列しか入れないようにし、PDOを使ってSQLを実行させる、などのSQLインジェクション対策はしっかりと把握しておきましょう。
まとめ
いかがでしたか。
PHPによる検索フォームの実装方法がお分かりいただけましたでしょうか。
SQL文の理解はWebシステム開発に必須のスキルですので、SELECTを使う「検索フォーム」だけでなく、UPDATEやINSERTなどについても別の機会に紹介してみたいと考えています。
今回は「検索フォーム」実装方法の説明のみとなっておりますので、今後、PHPで検索フォームを作成してみたいと思った時に、こちらの記事を思い出していただければ幸いです。