PHP レコードを複合語検索する方法。

前回までのPHPプログラムは、単一キーワードによる検索にしか対応していませんでしたが、今回は以下の点を改良してみましょう。

・複数のキーワードで検索できるようにする
・AND OR 条件を切り替えて検索できるようにする

キーワードはスペースで区切ることにします。スペースは全角でも半角でもかまいません。AND OR の選択にはラジオボタンを使います。

実は複合語検索できるようにするには、いろんな条件を想定しなければならないため複雑ですが、今回は最も基本的な機能に絞って説明します。基本をつかめばあとは少しずつ改良できます。


【1】sample107 フォルダをコピーして sample108 フォルダを作成します。

php-241.gif


【2】今回は以下のようなファイルの構成になります。

php-242.gif

・select.php、search.phpは変更があります。
・他のファイルは前回の sample107 と同じものなので、ソースコードは省略します。

*「\」はWindowsではエンマークのことです。

保存先 C:\phpdev\www\test\sample108
ファイル名 select.php

<?php
  //ファイルを読み込み
  require_once("SampleDB050.php");

  // クエリを送信する
  $sql = "SELECT * FROM T01Prefecture ORDER BY PREF_CD";
  $result = executeQuery($sql);

  //結果セットの行数を取得する
  $rows = mysql_num_rows($result);

  //表示するデータを作成
  if($rows){
    while($row = mysql_fetch_array($result)) {
      $tempHtml .= "<tr>";
      $tempHtml .= "<td>".$row["PREF_CD"]."</td><td>".$row["PREF_NAME"]."</td>";
      $tempHtml .= "<td><a href=\"update.php?cd=".$row["PREF_CD"]."\" target=\"_self\">更新</a></td>";
      $tempHtml .= "<td><a href=\"delete.php?cd=".$row["PREF_CD"]."\" target=\"_self\">削除</a></td>";
      $tempHtml .= "</tr>\n";
    }
    $msg = $rows."件のデータがあります。";
  }else{
    $msg = "データがありません。";
  }

  //結果保持用メモリを開放する
  mysql_free_result($result);

?>

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=SHIFT-JIS">
    <title>全件表示</title>
    <script type="text/javascript" src="select.js"></script>
  </head>
  <body>
    <h3>全件表示</h3>

    <form name="form2" action="search.php" method="post">
      <input type="text" name="keyword" size="25">
      <input type="submit" name="search" value="検索"><br />
      <input type="radio" checked name="searchSelect" value="AND">AND 
      <input type="radio" name="searchSelect" value="OR">OR
    </form>

    <?= $msg ?>
    <table width = "300" border = "1">
      <tr bgcolor="##ccffcc"><td>PREF_CD</td><td>PREF_NAME</td><td colspan="2">EDIT</td></tr>
      <?= $tempHtml ?>
      <form name="form1" action="insert.php" method="post">
        <tr>
          <td><input type="text" name="cd" id="cd"></td>
          <td><input type="text" name="name"></td>
          <td colspan="2">
            <input type="submit" name="insert" value="追加"><input type="reset" value="リセット">
          </td>
        </tr>
      </form>
    </table>
  </body>
</html>


保存先 C:\phpdev\www\test\sample108
ファイル名 search.php

<?php
  //ファイルを読み込み
  require_once("SampleDB050.php");

  //データを取得する
  $searchSelect = $_POST['searchSelect'];
  $keyword = $_POST['keyword'];
  $keyword = str_replace(" ", " ", $keyword);
  $keyword = trim($keyword);
  

  //検索キーワード未入力時
  if(empty($keyword)){
    print "<html>";
    print "<head><title>未入力</title></head>";
    print "<body>";
    print "検索キーワードが入力されていません。";
    print "<p><a href=\"select.php\" target=\"_self\">全件表示へ</a><p>";
    print "</body>";
    print "</html>";
    exit;
  }

  //抽出条件を組み立てる
  $array = explode(" ", $keyword);
  $cnt = count($array);
  $where = "WHERE ";

  for($i=0; $i < $cnt; $i++){
    $where.= "PREF_NAME LIKE '%".$array[$i]."%'";
    if($i < $cnt-1){
      $where .=" ".$searchSelect." ";
    }
  }

  // クエリを送信する
  $sql = "SELECT * FROM T01Prefecture ".$where;
  $sql .= " ORDER BY PREF_CD";
  $result = executeQuery($sql);
  print $sql;
  //結果セットの行数を取得する
  $rows = mysql_num_rows($result);

  //表示するデータを作成
  if($rows){
    while($row = mysql_fetch_array($result)) {
      $tempHtml .= "<tr>";
      $tempHtml .= "<td>".$row["PREF_CD"]."</td><td>".$row["PREF_NAME"]."</td>";
      $tempHtml .= "<td><a href=\"update.php?cd=".$row["PREF_CD"]."\" target=\"_self\">更新</a></td>";
      $tempHtml .= "<td><a href=\"delete.php?cd=".$row["PREF_CD"]."\" target=\"_self\">削除</a></td>";
      $tempHtml .= "</tr>\n";
    }
    $msg = $rows."件のデータがあります。";
  }else{
    $msg = "データがありません。";
  }

  //結果保持用メモリを開放する
  mysql_free_result($result);

?>

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=SHIFT-JIS">
    <title>検索結果</title>
    <script type="text/javascript" src="select.js"></script>
  </head>
  <body>
    <h3>検索結果</h3>

    <form name="form2" action="search.php" method="post">
      <input type="text" name="keyword" size="25" value="<?= $keyword ?>">
      <input type="submit" name="search" value="検索"><br />
      <input type="radio" checked name="searchSelect" value="AND">AND 
      <input type="radio" <?= ($searchSelect == "OR")? "checked" : "" ?> name="searchSelect" value="OR">OR
    </form>

    <?= $msg ?>
    <table width = "300" border = "1">
      <tr bgcolor="##ccffcc"><td>PREF_CD</td><td>PREF_NAME</td><td colspan="2">EDIT</td></tr>
      <?= $tempHtml ?>
      <form name="form1" action="insert.php" method="post">
        <tr>
          <td><input type="text" name="cd" id="cd"></td>
          <td><input type="text" name="name"></td>
          <td colspan="2">
            <input type="submit" name="insert" value="追加"><input type="reset" value="リセット">
          </td>
        </tr>
      </form>
    </table>
    <p><a href="select.php" target="_self">全件表示へ</a><p>
  </body>
</html>



【3】C:\phpdev にある 2K-NT-XP-phpdev_start.bat をダブルクリックして、phpdev を起動します。

php-02.gif

準備ができたら作成したPHPプログラムを実行してみましょう。


【4】ブラウザのアドレスに http://localhost/test/sample108/select.php と入力し、実行します。


【5】全件表示(select.php)の画面が表示されました。検索用のテキストボックスの下に、ANDとORのラジオボタンが表示されています。

php-243.gif


【6】テキストボックスに「山」と入力し、「AND」を選択して「検索」ボタンをクリックします。

php-244.gif


【7】検索結果(search.php)の画面が表示されました。「山」を含む都道府県の一覧が表示されています。

php-245.gif

・確認のためプログラムで組み立てたSQL文を表示しています。
・検索キーワードが1つなので、普通のあいまい検索になっています。
・テキストボックスには select.php で入力したキーワードが表示されています。


【8】次はキーワードをスペースで区切り「山 岡」と入力し、「AND」を選択して「検索」ボタンをクリックします。

php-246.gif

*スペースは半角でも全角でもかまいません。ただしスペースを2つ以上続けないでください。


【9】検索結果(search.php)の画面が表示されました。「山」かつ「 岡」を含む都道府県の一覧が表示されています。

php-247.gif

SQL文を見ると抽出条件が AND でつながっています。AND は両方のキーワードが含まれていなければならないので、岡山県しかありません。


【10】次はキーワードをスペースで区切り「山 岡」と入力し、「OR」を選択して「検索」ボタンをクリックします。

php-248.gif


【11】検索結果(search.php)の画面が表示されました。「山」または「岡」を含む都道府県の一覧が表示されています。

php-249.gif

SQL文を見ると抽出条件が OR でつながっています。ORはどちらか一つのキーワードが含まれていればよいので、表示件数は多くなります。


【12】次はキーワードをスペースで区切り「児 島 鹿」と入力し、「OR」を選択して「検索」ボタンをクリックします。

php-251.gif


【13】検索結果(search.php)の画面が表示されました。「児」または「島」または「鹿」を含む都道府県の一覧が表示されています。

php-250.gif

SQL文の OR が2つになり、3語以上のキーワードにも対応していることが確認できました。

都道府県名は多くても4文字なので、AND検索で多くのキーワードを使うことは無いと思いますが、OR検索では役立ちます。


【解説】

■select.php

(1)検索用のテキストボックスのサイズを少し大きくし、ANDとORのラジオボタンを追加しました。デフォルトでは AND が選択(checked)されるようにしています。

<form name="form2" action="search.php" method="post">
  <input type="text" name="keyword" size="25">
  <input type="submit" name="search" value="検索"><br />
  <input type="radio" checked name="searchSelect" value="AND">AND 
  <input type="radio" name="searchSelect" value="OR">OR
</form>


■search.php

(1)ラジオボタンのデータを取得する部分です。AND か OR の文字列が代入されます。

$searchSelect = $_POST['searchSelect'];


(2)キーワードのデータを取得する部分です。

$keyword = $_POST['keyword'];
$keyword = str_replace(" ", " ", $keyword);
$keyword = trim($keyword);

キーワードに全角のスペースが含まれている場合は、str_replace()関数で半角スペースに置換して、trim()関数で文字列の前後の空白を除いています。

これはキーワードの前後にスペースが入っていた場合の対策です。またキーワードを半角スペースで区切る準備も兼ねています。

例えば文字列が「 A BC DEF 」の場合、trim()関数で除けるのは「Aの前」と「Fの後」の空白だけです。文字列内の空白は除けません。


(3)キーワードが未入力の場合はメッセージを表示して、「exit;」で現在のスクリプトを終了しています。exitより下に書かれているものは表示されません。htmlやbodyのタグも表示されないので、最低限のHTMLタグは print で出力しています。

if(empty($keyword)){
  print "<html>";
  print "<head><title>未入力</title></head>";
  print "<body>";
  print "検索キーワードが入力されていません。";
  print "<p><a href=\"select.php\" target=\"_self\">全件表示へ</a><p>";
  print "</body>";
  print "</html>";
  exit;
}


(4)複数の検索キーワードにも対応できるように、抽出条件を組み立てる部分を変更しました。

検索キーワードを「半角スペース」で区切り、配列に格納する
$array = explode(" ", $keyword);

キーワード数(配列の要素数)を数える
$cnt = count($array);

変数に抽出条件の文字列を代入する
$where = "WHERE ";

for文でキーワード数の回数だけ繰り返しています。if文で最後のキーワードになるまでは AND か OR でつなぎます。

for($i=0; $i < $cnt; $i++){
  $where.= "PREF_NAME LIKE '%".$array[$i]."%'";
  if($i < $cnt-1){
    $where .=" ".$searchSelect." ";
  }
}


(5)前の画面でテキストボックスに入力した値を、デフォルトで表示しています。

<input type="text" name="keyword" size="25" value="<?= $keyword ?>">


(6)前の画面でORラジオボタンが選択されていた場合は、選択(checked)します。

<input type="radio" <?= ($searchSelect == "OR")? "checked" : "" ?> name="searchSelect" value="OR">OR

デフォルトでは AND が選択(checked)されるようになっているので、ORの場合だけ切り替えればよいわけです。


【ワンポイント】

検索ボックスに入力されたキーワードを、半角スペースで区切って取り出しているので、文字列内に半角スペースが2つ以上続くと空白がキーワードとなります。そうするとSQL文で「PREF_NAME LIKE '%%'」となるため、全てのレコードが抽出されてしまいます。

これを防ぐには正規表現を使い、1つ目のスペースだけ残し、2つ以上のスペースを除くようにプログラムすると解決できます。


スポンサードリンク

スポンサードリンク






PHP初心者入門講座TOPへ