よくわかるPHPの教科書でPHPを学習中です
メモアプリを作る過程で、input.phpで入力されたmemoの値をPOSTで呼び出し、それをデータベースにINSERTするという部分がわかりません。(コードでいうと上から3行目です)INSERTなどの文法はわかるのですが、クオーテーションが謎です。
なぜダブルクオーテーションで囲まれているところにシングルクオーテーションがさらにあるのかということがわかりません。
ダブルクオーテーションはなぜ必要なのでしょうか?
解説お願いいたします。
php
1 2 $db = new PDO("mysql:host=localhost;dbname=mydb","****","****"); 3 $memo=$_POST["memo"]; 4 $db->exec('INSERT INTO memos SET memo="'.$_POST['memo'].'",created_at=now()'); 5}catch(PDOException $e){ 6 echo "DB接続エラー" ;}
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答5件
0
根本的に、こんなコードは書いてはいけません。載せている教科書がよくない(脆弱性の教材にするなら別だけど)というレベルの話です。
データベースに与える値は、
- 可能な限り、プリペアドステートメントを活用する(PDOだと
prepare
があります) - 列名や文法要素になる場合は、ホワイトリストでチェックを行う
- どうしようもないときは、手動でエスケープする
教科書だからこそ、こんな「エスケープすらせずに、$_POST
をそのまま混ぜ込む」ような、SQLインジェクション待ったなしのコードは排除してもらいたいものです。
投稿2020/02/15 13:39
総合スコア145184
0
根本的な話、PHPの教科書はPHPマニュアルのみです。
書籍での学習が悪いとは言いませんが、あくまで「参考書」です。
書いている内容が正しいか、機能の確認は必ずPHPマニュアルで行ってください。
セキュリティについても結構なページ数を割いて整備されています。
現在質問者さんが直面されているクォーテーションの問題も文字列の項に詳細書かれています。
またネットの記事を参考にする場合は、Qiitaなどから評価の高い記事を選んだ方が良いでしょう。
データベース関係でよく参照されるのは下記。
PHPでデータベースに接続するときのまとめ
あと、これはSQLの話ですが、INSERT文の基本は下記です。
INSERT INTO テーブル名 VALUES(値1, 値2, ...);
INSERTでSETというと記憶の限りではMySQLしか出てこなかったと思いますし、検索してもおそらくMySQLしかでてきません。
もし今後業務で使うことを目指しているなら多くのDBがサポートしているスタンダードな形式を覚えた方が良いです。
場所やプロジェクトによるかもしれませんが、少なくとも私はMySQLを業務で使ってる場面にほとんど出会ってません。
(PostgreSQLが一番多く、次にOracleでした。)
投稿2020/02/15 22:32
総合スコア80850
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/02/16 04:23
2020/02/16 05:22 編集
2020/02/16 06:19 編集
2020/02/17 13:30
2020/02/17 13:37 編集
2020/02/17 14:23
2020/02/18 06:21
2020/02/18 13:43
2020/02/18 13:48
2020/02/18 14:16
2020/02/19 00:52
2020/02/19 02:26
2020/02/19 02:29
2020/02/19 02:34 編集
0
もし、$_POST['memo']
にPOYO
という内容が含まれて送信したとされます。
もし、ダブルクォーテーションがない場合以下のような流れになります。
'INSERT INTO memos SET memo='.$_POST['memo'].',created_at=now()'
'INSERT INTO memos SET memo='.'POYO'.',created_at=now()'
'INSERT INTO memos SET memo=POYO,created_at=now()'
しかし、これは文法的に正しくありません。
ダブルクォーテーションで文字列は括らなければいけません。
このような回答でよろしいでしょうか?
投稿2020/02/15 12:40
編集2020/02/15 13:00総合スコア10429
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2020/02/15 12:43
2020/02/15 12:46
退会済みユーザー
2020/02/15 12:59 編集
2020/02/15 13:00
退会済みユーザー
2020/02/15 13:02
2020/02/15 13:04
退会済みユーザー
2020/02/15 13:07
2020/02/15 14:44
2020/02/15 21:08
2020/02/16 07:08 編集
0
実際に何をやっているか動かしてみると良いです。
php
1<?php 2$_POST['memo'] = 'hogehoge'; 3$str = 'INSERT INTO memos SET memo="'.$_POST['memo'].'",created_at=now()'; 4echo $str;
解説はマニュアルに任せますw
文字列 - php.net
まぁ、すでに別の回答にあるように、DB 利用時の文字連結は、基本的に NG なので、根本から見直す必要があります。
余談
DB の接続に関しては、テンプレートを作成しているので参照してみてください。
PHP で MySQL 接続時に必要な知識(最小限版)
投稿2020/02/16 07:08
退会済みユーザー
総合スコア0
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
ベストアンサー
なぜダブルクオーテーションで囲まれているところにシングルクオーテーションがさらにあるのかということがわかりません。
ダブルクオーテーションはなぜ必要なのでしょうか?
以下の例でダブルクオーテーションはSQL文における文字列を表現したもので、シングルクオーテーションはPHPにおける文字列を表現しています。2重になっているということです。
PHP
1$db->exec('INSERT INTO memos SET memo="'.$_POST['memo'].'",created_at=now()');
ですが、ちょっと変なところがあって、
一般に、SQLでは文字列をシングルクォーテーションで括ります。
例のようにダブルクォーテーションで括るのは標準的ではありません。
memoの値が「XXX」だとすると、SQLは以下になります。
SQL
1INSERT INTO memos SET memo = 'XXX', created_at = now()
ちなみにSQLには多くの方言やバリエーションがあり、以下が標準的です。
SQL
1INSERT INTO memos (memo, created_at) VALUES('XXX', now())
※この後の例ではSQLのシングルクォーテーションとダブルクォーテーションを正さずに書いています。
また「$memo=$_POST["memo"];」で「$memo」に値を移しているのであれば、
PHP
1$db->exec('INSERT INTO memos SET memo="'.$_POST['memo'].'",created_at=now()');
でなく、以下になるはずです。
PHP
1$db->exec('INSERT INTO memos SET memo="'.$memo.'",created_at=now()');
PHPも文字列をクォーテーションで括ります。
ただ、シングルクォーテーションとダブルクォーテーションで効果が違います。
また、シングルクォーテーションの中にダブルクォーテーションがある場合や、その逆などの状況では、どちらを使うか工夫する必要があります。
※参考
https://www.php.net/manual/ja/language.types.string.php#language.types.string.syntax.double
これらを踏まえると、以下のようになります。
※この後の例ではSQLのシングルクォーテーションとダブルクォーテーションを正して書いています。
PHP
1$db->exec("INSERT INTO memos SET memo='" . $_POST['memo'] . "',created_at=now()");
「$_POST['memo']」のままだとできないのですが、
「$memo」に移したのであれば、「.」で文字列を結合せずに、以下のようにも書けます({}は、この場合は無くても良いです)。
PHP
1$db->exec("INSERT INTO memos SET memo='{$memo}',created_at=now()");
こんな風にするともっと分かりやすいかも。
PHP
1$sql = "INSERT INTO memos SET memo='%s',created_at=%s"; 2$db->exec(sprintf($sql, $memo, 'now()')); 3 4※sprintf()の書き漏れを訂正[2/16 14:40] 5前:$db->exec($sql, $memo, 'now()'); 6後:$db->exec(sprintf($sql, $memo, 'now()'));
※参考
https://www.php.net/manual/ja/function.sprintf.php
また他の方も指摘するように、プリペアドステートメントという方法でSQLの変数以外を作っておいて変数を設定してSQLを完成させる方法がセキュリティ的に望ましいので、最終的にはそういう方法でSQLを実行するのが良いですが、まぁ、後でやればいいことです(今はもっと基本的なことを学ぶべきです)。
※参考
https://www.php.net/manual/ja/pdo.prepared-statements.php
https://www.php.net/manual/ja/pdo.prepare.php
投稿2020/02/16 04:02
編集2020/02/17 14:27総合スコア31
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/02/16 05:23
2020/02/16 07:06
2020/02/17 13:21
2020/02/17 13:28
2020/02/17 13:31
2020/02/17 13:35
2020/02/17 13:48
2020/02/17 14:44
2020/02/17 14:48
2020/02/17 14:49
2020/02/17 15:45
2020/02/18 06:14
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/02/15 13:40