人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

PHP Mysql について
初歩的な質問で申し訳ないのですが、
クエリーを発酵する際に、
$sql = "SELECT * FROM users WHERE userid = '". $_POST['userid']. "'";
のように書けば動くということがわかりました。

しかし、『'". $_POST['userid']. "'』の部分の
『"』やら、そのあとの半角スペースや、『.』が必要な理由というか、
なんの作用をもたらしているのかがわかりません。
『'$_POST['userid']'』だったらうまく動作しなかったので、手当たり次第
検索して、見つけたソースをそのまま使用したら上手く動いただけです。

これについて、解説したページ等ありますでしょうか?

●質問者: gwrite
●カテゴリ:コンピュータ ウェブ制作
○ 状態 :終了
└ 回答数 : 3/3件

▽最新の回答へ

1 ● きゃづみぃ

『"』
文字列の指定に必要です。


『.』
文字列の連結をします。

半角スペースは 特には 関係ないと思います。

SQLを指定していますが、その文字列を変数を交えて 記述しているということです。


ただ、このような書き方だと セキュリティ上問題が発生する恐れがあります。
それについては ↓を参照してください。

http://ja.wikipedia.org/wiki/SQL%E3%82%A4%E3%83%B3%E3%82%B8%E3%82%A7%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3


きゃづみぃさんのコメント
なお "と'の違いですが "は PHP上での文字列の指定 'は SQL上での文字列の指定となります。

gwriteさんのコメント
連結演算子ですか。そういえばあったような気がします。 ありがとうございました。

2 ● gyoh_k

.(ドット) は、PHPで文字列を足す演算子です。

$param = "abc" . "def";
この場合、$paramは"abcdef" になります。


仮に、$_POST['userid'] が変数でなく、ユーザーID "abcd"を検索する場合、
SQLは以下のようになります。

$sql = "SELECT * FROM users WHERE userid = 'abcd'";

$sql = "SELECT * FROM users WHERE userid = '" . "abcd" . "'";

$sql = "SELECT * FROM users WHERE userid = '". $_POST['userid']. "'";

なお、実務のプログラミングでこの書き方をすると、
あっという間に読みづらいプログラムになってしまうため、
プレースホルダという機能を使ったほうがよいです。


tdoiさんのコメント
プレースホルダを使った方が色々な点でいいのは間違いないですが、場合によっては、 $sql = "SELECT * FROM users WHERE userid = '{$_POST['userid']}'"; と書くのがシンプルで好きだったりします。 ひょっとしたら質問者さんを混乱させてしまうだけかもしれませんが。

JULYさんのコメント
もし、$_POST{'uesr'} の中身が「1' or '1' = '1」となっていたら、どのような事が起きるか分かりますか? 作られる SQL 文は下記のようになります。 SELECT * FROM users WHERE userid = '1' or '1' = '1'' これが SQL インジェクションです。SQL 文をつなげて作るのが分かりやすい事は分かりますが、少なくとも、仕事してそんなコードを書いたらアウトです。

tdoiさんのコメント
*場合によっては*という注釈を付けたのですが、説明不足でしたね。 ユーザからの入力が直接来るような、$_POSTを突っ込むのは持っての他なのは言うまでもないですので、おっしゃってることは、もっともです。

gwriteさんのコメント
プレースホルダ使うようにします。 が、レンタルサーバでPEARが動かないという壁にもぶち当たっています。 また、『'" . "abcd" . "'』の時点で、よくわからなくなりました。 両端のシングルクォートはわかるのですが、ダブルクォーテーションが何をどう囲っているのか理解できません。

gyoh_kさんのコメント
一般的にプログラミング言語では、文字列をダブルクォーテーション(またはシングルクォーテーション)で囲みます。 たとえば、以下の構文はエラーになります。 $param = あいうえお; また、以下のように、ダブルクォーテーションとシングルクォーテーションを併用させることもできません。 $param = "あいうえお'; 以下の書き方だとOKです。 $param = "あいうえお"; 文字列でなく、数値の場合はクォーテーションで囲む必要はありません。 $param = 123; なお、「123」のような数値としても文字列としても扱えるデータの場合、 ダブルクォートで囲うこともできます。 $param = "123"; どちらにするかは、プログラム内で数値として扱いたいか、 文字列として扱いたいかによって決めるとよいと思います。 レンタルサーバでPEARが動かない件については、 初学者の方だと結構大変かも、ですね。 サーバの種類によっても設定内容が違ったりするので、 有効な解決策をお答えすることはできませんが、 数日かけるつもりでトライしていただければと思います。

3 ● うぃんど
ベストアンサー

ダブルクォートで囲まれた中にあるシングルクォートは文字として取り扱われるため、
userid という文字列ではなく 'userid' という文字列だと誤認してしまうというのが原因です。

そのため質問文にあるように、複数のパーツに分けて求めたものを結合するという手間をかけています。
その他にも方法はありますが、現在では質問文にあるような書き方が主流です。

(a)質問文のように分離する方法
$sql = "SELECT * FROM users WHERE userid = '" . $_POST['userid'] . "'";
変数は変数だけで独立して扱うので、
エディタ上での検索や置換などの編集作業が容易になります。
文字列の結合演算子である . を(人間が)見逃してエラーになるなんてことにもなるので、
. の前後に半角スペースをいれるなどの工夫もしています。

(b)中括弧を使って変数名であることを明示する方法
$sql = "SELECT * FROM users WHERE userid = '${_POST['userid']}'";
1つの変数をあらわす方法が複数(${_POST['userid']}と$_POST['userid'])になり、
再度コードを読み直したり、書き直したりする際にミスをしやすくなるため、
最近ではこの方法を使っている人をあまり見なくなってきました。

(c)シングルクォートを使わない方法(非推奨)
$sql = "SELECT * FROM users WHERE userid = '$_POST[userid]'";
下記ページの「配列ですべきこととしてはならないこと」に詳しいので下記参照
http://php.net/manual/ja/language.types.array.php


gwriteさんのコメント
中括弧のが一番わかりやすいです。

うぃんどさんのコメント
繰り返しておきますが、最近使っている人をあまり見なくなってきたのは、 回答欄に書いたようにコードを見直したりする際に大きな障害になるためです。 分割した(a)の書き方であれば、 php向けのエディタでは色が変わったりしてミスに気づきやすいのですが、 中括弧を使った(b)ではエディタなどの持っている機能では対応が難しく、 初心者であれば特にミスに気づきにくかったりします。 繰り返し説明してもまだ、一番というなら止めはしませんが・・・ 話は変わってプレースフォルダについては、 PEARでエミュレートしなくとも、最近の環境には標準で備わっていたりします。 お使いのサーバー会社に問い合わせるなどしてphpで mysqli ドライバを使えるかどうか確認してみてくださいな。 http://www.php.net/manual/ja/book.mysqli.php

gwriteさんのコメント
$mysqli = new mysqli("host", "user", "pass", "db"); $sql = "SELECT * FROM users WHERE userid = '". $_POST['userid']. "'"; $result = mysqli_query($mysqli , $sql) or die("クエリの送信に失敗しました。<br />SQL:".$sql); $rows = mysqli_num_rows($result); と書いて動くところまでは確認できたのですが、いろいろ間違っていそうです。 お手数ですが、上記ソースをプレースホルダを使って、正しくといいますか、一般的な形に書き直していただくことは可能でしょうか? 別途、お礼のポイント送信させていただきます。(こころばかりですが)

うぃんどさんのコメント
mysqliでprepareを使った例 単体テスト用のhtmlフォーム付きにしておいたので、 "host", "user", "pass", "db"の設定と入力チェック部分を、 そちらの環境に合わせるだけで動くはずです (テストですから入力チェックの部分をコメントアウトしてもかまいません) (今回の回答用に新規作成し、動作テストしたものを貼り付けてます) >|php| <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf8" /> <meta http-equiv="content-style-type" content="text/css"> <title>test</title> </head> <body> <form action="<?=$_SERVER['PHP_SELF'] ?>" method="post"> <input type="text" name="userid" size="30"><br /> <input type="submit" value="送信" /> </form> <?php // 入力値の存在チェック if (!isset($_POST['userid'])) die('useridが送られてきていません。'); // 入力値の適正チェック(アルファベットで始まる2-6桁の文字列のみ受付とする) if (!preg_match('!^[a-zA-Z][a-zA-Z0-9]{1,5}$!', $_POST['userid'])) die('useridが不適切です。'); // 入力値の受け入れ $userid = $_POST['userid']; // // mysqlドライバ利用に近い形(手続き型)での記述例 // // SQL準備 // *も使えるけれど、下記のようにカラムを指定しておけば、 // データベース側の構造が変わってもプログラム改変は不要となり、 // プログラミング中の記述ミスなども発見しやすくなるため、 // プログラム中にSQLを書く場合にはカラム指定必須と覚えておきましょう $sql = "SELECT userid, username FROM users WHERE userid = ?"; // コネクト $mysqli = mysqli_connect('host', 'user', 'pass', 'db'); // SQL送信 $stmt = mysqli_prepare($mysqli, $sql) or die('プリペア送信に失敗しました。SQL:' . $sql); // パラメータの送信 mysqli_stmt_bind_param($stmt, 's', $userid) or die('パラメータ送信に失敗しました'); // SQL実行 mysqli_stmt_execute($stmt) or die('クエリ実行に失敗しました'); // SQL実行結果を受け取る変数を用意 // SQL中で出力指定されたカラムの並びに準拠します mysqli_stmt_bind_result($stmt, $re_userid, $re_name) or die('変数接続に失敗しました'); // 結果取得と出力 while (mysqli_stmt_fetch($stmt)) { echo $re_userid, $re_name , '<br />'; } // クローズ mysqli_stmt_close($stmt); // // オブジェクト指向型での記述例 // // SQL準備 $sql = "SELECT userid, username FROM users WHERE userid = ?"; // コネクト $mysqli = new mysqli('host', 'user', 'pass', 'db'); // SQL送信 $stmt = $mysqli->prepare($sql) or die('プリペア送信に失敗しました。SQL:' . $sql); // パラメータの送信 $stmt->bind_param('s', $userid) or die('パラメータ送信に失敗しました'); // SQL実行 $stmt->execute() or die('クエリ実行に失敗しました'); // SQL実行結果を受け取る変数を用意 $stmt->bind_result($re_userid, $re_name) or die('変数接続に失敗しました'); // 結果取得と出力 while ($stmt->fetch()) { echo $re_userid, $re_name , '<br />'; } // クローズ $mysqli->close(); ||<

gwriteさんのコメント
ご丁寧にありがとうございます。さらには、送信したポイントを返却までしていただいて、ご親切にありがとうございました。 まだまだ、人力検索のお世話になること多いと思いますので、その際は、またよろしくお願いできましたらと思います。
関連質問

●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ