PHPとMySQLを使って検索システムの作り方を勉強しています。
以下のようなhtmlとデータベースがあります。
id pref
1 東京
2 大阪
3 札幌
4 京都
5 那覇
6 福岡
現在配列データをどのように加工して、SQL文を発行すればいいか悩んでいます。
配列データを受け取り、それを表示させることや、単数選択の場合データベースから一致するデータを表示するというのはできるのですが、”複数選択された時に一致するデータを検索してすべて表示する” 方法が思いつきません。
単純にnameをすべて別の名前にすればいいと思ったのですが、データ量が多い場合非効率だと考え、別の効率的なやり方を模索しています。
配列でデータを受け取ったらそれをcount関数でカウントし、添字をうまく使って検索するワード(選択された値)を変数に格納、SQL文へ持っていくというやり方は可能でしょうか?
効率のよい方法やわかりやすいシンプルな方法があれば教えて下さい!
<現在取り組んでいるやり方>
<複数選択した場合の検証結果>
string '那覇,福岡' (length=13)
object(mysqli_result)[2]
public 'current_field' => int 0
public 'field_count' => int 2
public 'lengths' => null
public 'num_rows' => int 0
public 'type' => int 0
string 'SELECT * FROM checkbox_search WHERE pref IN ('那覇,福岡')' (length=61)
<単数選択した場合の検証結果>
string '福岡' (length=6)
object(mysqli_result)[2]
public 'current_field' => int 0
public 'field_count' => int 2
public 'lengths' => null
public 'num_rows' => int 2
public 'type' => int 0
string 'SELECT * FROM checkbox_search WHERE pref IN ('福岡')' (length=54)
implode関数を使ったやり方がわかりやすいと思い、色々調べたのですが、どうにもSQL文がうまく機能しません。
単数選択した場合の方のSQL文,
SELECT * FROM checkbox_search WHERE pref IN ('福岡')
は正しいと思うのですが、検索結果を表示させるところまでいけません。
複数選択の方はお手上げです・・・
以下のようなhtmlとデータベースがあります。
<form action="index.php" method="POST">
<input type="checkbox" name="pref[]" value="東京">東京
<input type="checkbox" name="pref[]" value="大阪">大阪
<input type="checkbox" name="pref[]" value="札幌">札幌
<input type="checkbox" name="pref[]" value="京都">京都
<input type="checkbox" name="pref[]" value="那覇">那覇
<input type="checkbox" name="pref[]" value="福岡">福岡
<input type="checkbox" name="pref[]" value="新宿">新宿
<input type="checkbox" name="pref[]" value="北京">北京
<input type="submit" value="検索">
</form>
id pref
1 東京
2 大阪
3 札幌
4 京都
5 那覇
6 福岡
現在配列データをどのように加工して、SQL文を発行すればいいか悩んでいます。
$check = $_POST['pref'];
foreach($check as value){
echo $value;
配列データを受け取り、それを表示させることや、単数選択の場合データベースから一致するデータを表示するというのはできるのですが、”複数選択された時に一致するデータを検索してすべて表示する” 方法が思いつきません。
単純にnameをすべて別の名前にすればいいと思ったのですが、データ量が多い場合非効率だと考え、別の効率的なやり方を模索しています。
配列でデータを受け取ったらそれをcount関数でカウントし、添字をうまく使って検索するワード(選択された値)を変数に格納、SQL文へ持っていくというやり方は可能でしょうか?
効率のよい方法やわかりやすいシンプルな方法があれば教えて下さい!
<現在取り組んでいるやり方>
$check = $_POST['pref'];
$imp = implode(",",$check);
$sql = "SELECT * FROM checkbox_search WHERE pref IN ('$imp')";
$query = mysqli_query($connect,$sql);
var_dump($imp);
var_dump($query);
var_dump($sql);
<複数選択した場合の検証結果>
string '那覇,福岡' (length=13)
object(mysqli_result)[2]
public 'current_field' => int 0
public 'field_count' => int 2
public 'lengths' => null
public 'num_rows' => int 0
public 'type' => int 0
string 'SELECT * FROM checkbox_search WHERE pref IN ('那覇,福岡')' (length=61)
<単数選択した場合の検証結果>
string '福岡' (length=6)
object(mysqli_result)[2]
public 'current_field' => int 0
public 'field_count' => int 2
public 'lengths' => null
public 'num_rows' => int 2
public 'type' => int 0
string 'SELECT * FROM checkbox_search WHERE pref IN ('福岡')' (length=54)
implode関数を使ったやり方がわかりやすいと思い、色々調べたのですが、どうにもSQL文がうまく機能しません。
単数選択した場合の方のSQL文,
SELECT * FROM checkbox_search WHERE pref IN ('福岡')
は正しいと思うのですが、検索結果を表示させるところまでいけません。
複数選択の方はお手上げです・・・
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
0
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.23%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2015/09/23 04:58
おそらくそのSQL文を使うと思います。
DBアクセスにはmysqliを使用しており、参考サイトとはほんのすこしずれています。
PHPにて配列の内容をどのように検索条件に持っていくかという部分でして、上記SQL文ですと、INの()内にはどのようにして配列データのそれぞれを挿入すれば良いのでしょうか?
2015/09/23 05:28
以下検証しておりません。fetch部分はお任せします!
$checkNum = count($check);
if( $checkNum ){
$sql ="SELECT * FROM table WHERE ";
$sql.=" AND pref IN(".substr(str_repeat(',?', $checkNum),1).")";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param('s', $check);
$stmt->execute();
}
2015/09/23 16:15
ご指摘頂いた方法が今ひとつ理解できなかったので、implodeを使ったやり方に挑戦してみました。
$check = $_POST['pref'];
$imp = implode(",",$check);
$sql = "SELECT * FROM checkbox_search WHERE pref IN ('$imp')";
$query = mysqli_query($connect,$sql);
しかし、うまく行きませんでした。色々なサイトを見てimplode部分の書き方を工夫したりしたのですが、どうも配列データをSQLにうまく組み込めていないようで検索結果を表示することができません。
2015/09/23 21:06
NG: SELECT * FROM checkbox_search WHERE pref IN ('"東京","大阪"');
→ ('$imp')
OK: SELECT * FROM checkbox_search WHERE pref IN ("東京","大阪");
→ ($imp)
あと、bind_paramを用いてプレースホルダによる安全なSQLにしておかなければ
POSTされた値を鵜呑みにしてしまうと、SQLインジェクションにより、プログラムを
自由に改変実行されてしまいます。
例えば引数が東京・大阪の2つだとして
$checkNum = count($check);
$sql = 'SELECT * FROM checkbox_search WHERE pref IN ( ?, ? );';
$stmt = $mysqli->prepare($sql);
$stmtParams = array( str_repeat( 's', $checkNum ) );
$stmt->bind_param('ss', '東京', '大阪');
$stmt->execute();
IN( ?, ? ) ← 左はbind_paramの一つ目=東京が代入される予定です、右は大阪
'ss' ← 左は 東京が文字列である事をしめしています。右は大阪も文字列である事を示しています。$stmtParamsに置き換えれば、可変に対応できそうです。
ここで、$sqlの IN( ? の ?の数と、bind_paramの 'ss'と その引数(?と対になる)が可変になるので、変数で事前に組み立てておこうという流れです。
(すみません、手元に動作確認環境が無いため、コードは試していません。。。)
2015/09/23 22:47
SQL文ですが、implode("','",$check)とすることでうまく組み込むことができました。
(var_dumpなどで確認しました。)
しかし、SQL文を組めてもObject of class mysqli_result could not be converted to string〜 というエラーが出てしまい、立ち止まっていたのですが、以下のようにwhileの部分のコードを変えることで検索結果を表示することができました。
while ($row = $query->fetch_assoc()) {
echo $row['pref'];
}
SQLインジェクションなど対策は後々組み込んでいきたいと思います。
ご指摘いただいた方法にも取り組んでみたいと思います。
勉強なりました。ありがとうございます。