Webサイトに登録された多くの商品やユーザー情報の中から、目的のデータを素早く見つけ出す「検索機能」は、ユーザーにとって非常に価値の高い機能です。
今回は、PHPとデータベース(MySQL)を連携させ、入力されたキーワードに一致する会員データを一覧表示する、シンプルな検索アプリケーションの作り方を一から解説します。
この解説を通じて、安全なデータベース操作に不可欠なPDOと、あいまい検索を実現するSQLの**LIKE
句**という、2つの重要なテクニックをマスターしましょう。
1. 検索フォームのHTMLを作成する
まずは、ユーザーが検索キーワードを入力するためのHTMLフォームを準備します。今回は、1つのPHPファイル(search.php
など)にフォームと検索結果の両方を表示するため、<form>
タグのaction
属性は空にします。action=""
とすると、フォームのデータは自分自身のページに送信されます。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>会員検索アプリ</title>
</head>
<body>
<h1>会員検索</h1>
<p>検索したい会員の名前(一部でも可)を入力してください。</p>
<form action="" method="POST">
<label for="name">お名前:</label>
<input type="text" id="name" name="search_name">
<input type="submit" value="検索する">
</form>
</body>
</html>
2. SQLのLIKE
句による「あいまい検索」
完全一致のデータを探す場合、SQLではWHERE name = '山田太郎'
のように=
を使います。しかし、検索機能では「山田」と入力されただけで「山田太郎」さんや「山田花子」さんを見つけ出したいですよね。
このような「部分一致(あいまい検索)」を実現するのがLIKE
句と、**ワイルドカード文字%
**です。
%
は「0文字以上の任意の文字列」を意味します。
パターン | 意味 |
'田中%' | 「田中」で始まる文字列(例: 田中三郎, 田中商店) |
'%一郎' | 「一郎」で終わる文字列(例: 鈴木一郎, 田中一郎) |
'%京都%' | 「京都」を含む文字列(例: 京都府, 東京都京都市) |
一般的な検索フォームでは、キーワードがどこに含まれていてもヒットさせたいので、'%キーワード%'
の形をよく使います。
3. PHPで安全な検索処理を実装する
それでは、PHPのロジックを組み立てていきます。全体の流れは以下の通りです。
- ページがPOST送信されたかどうかを
$_SERVER['REQUEST_METHOD']
で判定する。 - 送信されていたら、検索キーワードを
$_POST
から受け取る。 - データベースにPDOで接続する。
LIKE
句とプリペアドステートメントを使って、安全なSQL文を準備する。- キーワードをSQL文に**バインド(紐付け)**して、実行する。
- 取得した結果を配列に格納する。
なぜプリペアドステートメントが必須なのか?
もしユーザーが入力した値を直接SQL文に連結してしまうと、「SQLインジェクション」という非常に危険な攻撃を受ける可能性があります。プリペアドステートメントを使えば、PDOが値を安全な形に処理してくれるため、この攻撃を根本的に防ぐことができます。
LIKE
句で値をバインドする際のポイント bindValue()
の第2引数で、検索キーワードの前後に%
を連結するのがコツです。 $stmt->bindValue(':name', '%' . $search_name . '%', PDO::PARAM_STR);
4. 完成版コード
これまでの要素をすべて統合した、1つのファイルで動作する完成版のコードです。 事前にmembers
テーブル(ID, 名前, 年齢, メールアドレスなどを持つ)が用意されていることを前提としています。
【search.php
】
<?php
// ===== 変数の初期化 =====
$search_name = '';
$results = [];
$message = '';
// ===== データベース接続情報 =====
$dsn = 'mysql:dbname=php_learning_db;host=localhost;charset=utf8mb4';
$user = 'root';
$password = ''; // XAMPPのデフォルトは空パスワード
// ===== POSTリクエストがあった場合の検索処理 =====
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$search_name = $_POST['search_name'] ?? '';
if (!empty($search_name)) {
try {
$dbh = new PDO($dsn, $user, $password);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// SQL文の準備 (LIKE句とプレースホルダを使用)
$sql = 'SELECT id, name, age FROM members WHERE name LIKE :name';
$stmt = $dbh->prepare($sql);
// 値をバインド
$stmt->bindValue(':name', '%' . $search_name . '%', PDO::PARAM_STR);
// 実行
$stmt->execute();
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (count($results) === 0) {
$message = '該当する会員が見つかりませんでした。';
}
} catch (PDOException $e) {
$message = "データベースエラー: " . $e->getMessage();
}
} else {
$message = '検索キーワードを入力してください。';
}
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>会員検索アプリ</title>
<style>
body { font-family: sans-serif; }
.container { width: 80%; margin: 20px auto; }
table { border-collapse: collapse; width: 100%; margin-top: 20px; }
th, td { border: 1px solid #ccc; padding: 10px; }
thead { background-color: #f2f2f2; }
.message { color: #d9534f; }
</style>
</head>
<body>
<div class="container">
<h1>会員検索</h1>
<p>検索したい会員の名前(一部でも可)を入力してください。</p>
<form action="" method="POST">
<label for="name">お名前:</label>
<input type="text" id="name" name="search_name" value="<?php echo htmlspecialchars($search_name, ENT_QUOTES, 'UTF-8'); ?>">
<input type="submit" value="検索する">
</form>
<?php if ($_SERVER['REQUEST_METHOD'] === 'POST'): ?>
<hr>
<h2>検索結果</h2>
<?php if (!empty($message)): ?>
<p class="message"><?php echo $message; ?></p>
<?php elseif (!empty($results)): ?>
<table>
<thead>
<tr>
<th>ID</th>
<th>名前</th>
<th>年齢</th>
</tr>
</thead>
<tbody>
<?php foreach ($results as $row): ?>
<tr>
<td><?php echo htmlspecialchars($row['id'], ENT_QUOTES, 'UTF-8'); ?></td>
<td><?php echo htmlspecialchars($row['name'], ENT_QUOTES, 'UTF-8'); ?></td>
<td><?php echo htmlspecialchars($row['age'], ENT_QUOTES, 'UTF-8'); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
<?php endif; ?>
</div>
</body>
</html>
まとめ
今回は、PHPとMySQLを使った基本的な検索機能の実装方法を学びました。
【重要ポイントの振り返り】
- あいまい検索には、SQLの**
LIKE
句とワイルドカード%
**を使う。 - ユーザーからの入力値を扱う際は、SQLインジェクション対策として必ずPDOのプリペアドステートメントを使用する。
bindValue()
で値を紐付ける際に、'%' . $keyword . '%'
のように%
を連結する。- 1つのファイルにフォームと処理を同居させると、シンプルなアプリを効率的に作れる。
このパターンは、会員検索、商品検索、記事検索など、あらゆるWebアプリケーションの基本となります。ぜひこのコードをベースにして、さまざまな検索機能を実装してみてください。