質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.36%

phpでSQLのLIKEの値に複数の変数を代入したい

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 365

score 14

1. やりたい・やりたかったこと  

背景
カードゲームのDBを作っています。
DBのカード検索でテーブル(ユーザがブラウザ上で入力する項目)が4つあります。
name, attribute, type, numberの4つです。
issetで値の有無を確認して変数にattribute LIKE '$pro_attributeなどの値を入れたいです。
例えば4つ全て入っているときはsqlの変数数に入るコードは以下のようになります。
$sql_part_head="SELECT code,name,attribute,type,number FROM mst_product"LIKE "WHERE name LIKE '%$pro_name%'"
"attribute LIKE '%$pro_attribute%'" 
"type LIKE '%$pro_type%'"
"number LIKE '%$pro_number%'"
(そもそもこれはSQL文として正しいのでしょうか?どのようにして検索ボックスでユーザーに入力された項目を連結してDBからデータをとれば良いのでしょうか?根本的に私の考えとアプローチが間違っていたら教えてください。)

2. 起きている問題やエラーメッセージ

以下のエラーメッセージが出力されます。

失敗:SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''WHERE name LIKE '%ドラゴン%''AND'number LIKE '%%''AND''AND''' at line 1

3. 関連するソースコード

対象のソースコードになります。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>トレカDB</title>
</head>
<body>

<?php

header("Content-type: text/html; charset=utf-8"); # このコードはコンテンツはhtmlで文字コードはutf-8であるという意味。通常はプログラムでわざわざ指定しなくても
#Webサーバが勝手につけてくれますが、プログラムから指定しているのは、より明示的に文字化けや、文字コードの違いを利用したXSS攻撃等を防ぐ

try
{

$pro_name=$_POST['name'];
$pro_attribute=$_POST['attribute'];
$pro_type=$_POST['type'];
$pro_number=$_POST['number'];

$pro_name=htmlspecialchars($pro_name,ENT_QUOTES,'UTF-8');
$pro_attribute=htmlspecialchars($pro_attribute,ENT_QUOTES,'UTF-8');
$pro_type=htmlspecialchars($pro_type,ENT_QUOTES,'UTF-8');
$pro_number=htmlspecialchars($pro_number,ENT_QUOTES,'UTF-8');

if($pro_name=='' && $pro_attribute=='' && $pro_type=='' && preg_match('/\A[0-9]+\z/',$pro_number)==0 )
{
    print("検索項目が全て空白です。値を入力してください。");
    print '<form>';
    print '<input type="button" onclick="history.back()" value="戻る">';
    print '</form>';
    exit();
}
else
{
    print 'カード一覧<br /><br />';
}

$sql_part_head="SELECT code,name,attribute,type,number FROM mst_product";

$first_query = true;

if(isset($_POST['name'])==true) 
{
    $sql_part_A = "WHERE name LIKE '%$pro_name%'";
    $first_query=false;
}
if(isset($_POST['attribute'])==true) {
    if($first_query=false){
    $sql_part_B = "WHERE attribute LIKE '%$pro_attribute%'";    
    }
    else{
        $sql_part_B="attribute LIKE '%$pro_attribute%'";
    }
}
if(isset($_POST['type'])==true) {
    if($first_query=false){
    $sql_part_B = "WHERE type LIKE '%$pro_type%'";    
    }
    else{
        $sql_part_B="type LIKE '%$pro_type%'";
    }
}

if(isset($_POST['number'])==true) {
    if($first_query=false){
    $sql_part_B = "WHERE number LIKE '%$pro_number%'";    
    }
    else{
        $sql_part_B="number LIKE '%$pro_number%'";
    }
}

$dsn='mysql:dbname=yugioh;host=localhost;charset=utf8';
$user='root';
$password='';
$dbh=new PDO($dsn,$user,$password);
$dbh->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);

$sql="SELECT code,name,attribute,type,number FROM mst_product '$sql_part_A'AND'$sql_part_B'AND'$sql_part_C'AND'$sql_part_D'";
$stmt=$dbh->prepare($sql);
$stmt->execute();

$dbh=null;

print '<form method="post" action="pro_branch.php">';
while(true)
{
    $rec=$stmt->fetch(PDO::FETCH_ASSOC);
    if($rec==false)
    {
        break;
    }
    print '<input type="radio" name="procode" value="'.$rec['code']. '">';
    print $rec['name'].'  種族:';
    print $rec['attribute'].'    属性';
    print $rec['type'].'   枚数:';
    print $rec['number'].'枚';
    print '<br />';
}

/* if(isset($_POST['name'])==true || isset($_POST['attribute'])==true || isset($_POST['type'])==true || isset($_POST['number'])==true) #もし検索ボックスのどれかに値が入っていたら
{ */

/* if(isset($_POST['name'])==true && $pro_attribute=='' && $pro_type=='' && $pro_number=='') */
/* if(isset($_POST['name'])==true )
{

$dsn='mysql:dbname=yugioh;host=localhost;charset=utf8';
$user='root';
$password='';
$dbh=new PDO($dsn,$user,$password);
$dbh->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);

$sql="SELECT code,name,attribute,type,number FROM mst_product WHERE name LIKE '%$pro_name%'";
$stmt=$dbh->prepare($sql);
$stmt->execute();

$dbh=null;


print '<form method="post" action="pro_branch.php">';
while(true)
{
    $rec=$stmt->fetch(PDO::FETCH_ASSOC);
    if($rec==false)
    {
        break;
    }
    print '<input type="radio" name="procode" value="'.$rec['code']. '">';
    print $rec['name'].'  種族:';
    print $rec['attribute'].'    属性';
    print $rec['type'].'   枚数:';
    print $rec['number'].'枚';
    print '<br />';
}

} */

/* } */

/* if(isset($_POST['name'])==true && isset($_POST['attribute'])==true && $pro_type=='' && $pro_number=='')
{
    $dsn='mysql:dbname=yugioh;host=localhost;charset=utf8';
$user='root';
$password='';
$dbh=new PDO($dsn,$user,$password);
$dbh->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);

$sql="SELECT code,name,attribute,type,number FROM mst_product WHERE name LIKE '%$pro_name%','%pro_attribute'";
$stmt=$dbh->prepare($sql);
$stmt->execute();

$dbh=null;


print '<form method="post" action="pro_branch.php">';
while(true)
{
    $rec=$stmt->fetch(PDO::FETCH_ASSOC);
    if($rec==false)
    {
        break;
    }
    print '<input type="radio" name="procode" value="'.$rec['code']. '">';
    print $rec['name'].'  種族:';
    print $rec['attribute'].'    属性';
    print $rec['type'].'   枚数:';
    print $rec['number'].'枚';
    print '<br />';
}

} */


}
catch(PDOException $e)
{
    echo "失敗:" . $e->getMessage() . "\n";
    exit();
}

?>

</body>
</html>
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • yambejp

    2021/04/30 09:22

    もし質問者さんが初心者ならエラーがおきない最小単位を実装して徐々に
    機能を付与していくことをおすすめします。

    キャンセル

回答 1

checkベストアンサー

+1

そもそもこれはSQL文として正しいのでしょうか?

Syntax エラーは構文エラーで正しくない。正しくないからエラーが出ています。

ひとまずいきなりPHPから実行するのではなく、DBに対して直接実行して想定のデータを得られるSQLを組んで想定の結果を得られてからPHPでそのSQLになるように組み立ててください。

直接実行して想定の結果が得られなければ、PHPから実行しても想定の結果は得られません。

SQLインジェクションの脆弱性があったり、画面に出力しない項目に対してHTMLエスケープ対応していたり、実装として非常にまずいところは沢山ありますが、1つずつやっていくと良いです。


直接的なヒントとしては
=は代入
=====は比較

ifには「式」を入れますが代入も「式」であるためエラーになりません。
代入結果がfalseになることってないので、必ず通ります。

また、代入はつまるところ上書きなので、別の値が入っててもなくなります。
文字列演算子あたりも確認してください。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2021/05/01 07:34

    asianLadさん
    データベースに関するまとめ記事なら下記が非常に優秀です。
    https://qiita.com/mpyw/items/b00b72c5c95aac573b71
    アンチパターン→こうするべき
    というのが章立てて記載されています。

    キャンセル

  • 2021/05/01 07:59

    あーちょっと誤解を与えたかも^^;

    > 一度読んでみると良いです。

    「副読本を」一度読んでみると良いです。だね。
    なぜか、ID と PASS が公開されているので非購入者も読むことが出来そうです。
    目次を見ても、問題個所のほとんどはケアされてます。

    ただ、やっぱり古いんだよなぁ。。。

    キャンセル

  • 2021/05/01 18:44

    中身もそうですが、情報の鮮度は尚のこと重要ですね。
    日進月歩の世界において古いとそれだけ信用度も下がります。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.36%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る