idの配列を考えると、次の$galleries = array(1,2,5)
ようにWHERE句で配列の値を使用するSQLクエリが必要です。
SELECT *
FROM galleries
WHERE id = /* values of array $galleries... eg. (1 || 2 || 5) */
MySQLで使用するこのクエリ文字列を生成するにはどうすればよいですか?
idの配列を考えると、次の$galleries = array(1,2,5)
ようにWHERE句で配列の値を使用するSQLクエリが必要です。
SELECT *
FROM galleries
WHERE id = /* values of array $galleries... eg. (1 || 2 || 5) */
MySQLで使用するこのクエリ文字列を生成するにはどうすればよいですか?
回答:
注意してください!この回答には、深刻なSQLインジェクションの脆弱性が含まれています。外部入力が無害化されていることを確認せずに、ここに示すコードサンプルを使用しないでください。
$ids = join("','",$galleries);
$sql = "SELECT * FROM galleries WHERE id IN ('$ids')";
$galleries
このステートメントの前に入力検証が必要な警告を追加するだけです!準備済みステートメントは配列AFAIKを処理できないため、変数のバインドに慣れている場合は、ここでSQLインジェクションを簡単に実行できます。
$galleries
次の値がある場合を想像してください:array('1); SELECT password FROM users;/*')
。それをサニタイズしないと、クエリはを読み取りますSELECT * FROM galleries WHERE id IN (1); SELECT password FROM users;/*)
。テーブルと列の名前をデータベースにあるものに変更し、そのクエリを試し、結果を確認します。結果として、ギャラリーのリストではなく、パスワードのリストが表示されます。データがどのように出力されるか、またはスクリプトが予期しないデータの配列をどのように処理するかに応じて、パブリックビューに出力される可能性があります。
$galleries
質問で提供されたとおりに設定し、前述の「SQLインジェクションの脆弱性」を使用してそれを悪用する取り引きについてはどうでしょうか。あなたができない場合-あなたは私にUSD200を支払います。どのようにそのことについて?
PDOの使用:[1]
$in = join(',', array_fill(0, count($ids), '?'));
$select = <<<SQL
SELECT *
FROM galleries
WHERE id IN ($in);
SQL;
$statement = $pdo->prepare($select);
$statement->execute($ids);
MySQLiの使用 [2]
$in = join(',', array_fill(0, count($ids), '?'));
$select = <<<SQL
SELECT *
FROM galleries
WHERE id IN ($in);
SQL;
$statement = $mysqli->prepare($select);
$statement->bind_param(str_repeat('i', count($ids)), ...$ids);
$statement->execute();
$result = $statement->get_result();
説明:
IN()
演算子を使用して、指定されたリストに値が存在するかどうかを確認します。一般的には次のようになります。
expr IN (value,...)
()
from配列の中に配置する式を作成できます。括弧内に少なくとも1つの値がなければなりません。そうでない場合、MySQLはエラーを返します。これは、入力配列に少なくとも1つの値があることを確認することと同じです。SQLインジェクション攻撃を防ぐには、まず?
各入力項目のを生成して、パラメーター化されたクエリを作成します。ここでは、IDを含む配列が呼び出されていると仮定します$ids
。
$in = join(',', array_fill(0, count($ids), '?'));
$select = <<<SQL
SELECT *
FROM galleries
WHERE id IN ($in);
SQL;
3つの項目の入力配列があるとすると、次の$select
ようになります。
SELECT *
FROM galleries
WHERE id IN (?, ?, ?)
繰り返し?
ますが、入力配列には項目ごとにがあることに注意してください。次に、PDOまたはMySQLiを使用して、上記のようにクエリを準備および実行します。
IN()
文字列での演算子の使用パラメータがバインドされているため、文字列と整数を簡単に変更できます。PDOの場合、変更は必要ありません。MySQLiでは、文字列をチェックする必要str_repeat('i',
があるstr_repeat('s',
場合はに変更します。
[1]:簡潔にするためにいくつかのエラーチェックを省略しました。各データベースメソッドの通常のエラーを確認する(または、例外をスローするようにDBドライバーを設定する)必要があります。
[2]: PHP 5.6以降が必要です。繰り返しますが、簡潔にするためにいくつかのエラーチェックを省略しています。
$statement->bind_param(str_repeat('i', count($ids)), ...$ids);
場合、...
は配列のIDを複数のパラメータに拡張しています。あなたが参照している場合、expr IN (value,...)
それは単により多くの値がある可能性があることを意味しますWHERE id IN (1, 3, 4)
。少なくとも1つあれば十分です。
...
ます:wiki.php.net/rfc/argument_unpacking
int:
$query = "SELECT * FROM `$table` WHERE `$column` IN(".implode(',',$array).")";
文字列:
$query = "SELECT * FROM `$table` WHERE `$column` IN('".implode("','",$array)."')";
入力を事前に適切にサニタイズすると仮定します...
$matches = implode(',', $galleries);
次に、クエリを調整します。
SELECT *
FROM galleries
WHERE id IN ( $matches )
データセットに応じて値を適切に引用します。
使用する:
select id from galleries where id in (1, 2, 5);
単純なfor each
ループが機能します。
Flavius / AvatarKavaの方法の方が優れていますが、配列の値にコンマが含まれていないことを確認してください。
Flavius Stefの答えとして、を使用intval()
してすべてid
がint値であることを確認できます。
$ids = join(',', array_map('intval', $galleries));
$sql = "SELECT * FROM galleries WHERE id IN ($ids)";
以下のためのMySQLiを脱出機能付き:
$ids = array_map(function($a) use($mysqli) {
return is_string($a) ? "'".$mysqli->real_escape_string($a)."'" : $a;
}, $ids);
$ids = join(',', $ids);
$result = $mysqli->query("SELECT * FROM galleries WHERE id IN ($ids)");
準備済みステートメントを含むPDOの場合:
$qmarks = implode(',', array_fill(0, count($ids), '?'));
$sth = $dbh->prepare("SELECT * FROM galleries WHERE id IN ($qmarks)");
$sth->execute($ids);
SQLインジェクションの脆弱性と空の状態に対処する必要があります。どちらも以下のように扱います。
純粋な数値配列のために、適切な型変換すなわち使用intval
またはfloatval
またはdoubleval
各要素の上に。mysqli_real_escape_string()
必要に応じて数値にも適用できる文字列型の場合。MySQLでは、文字列として数値と日付のバリアントを使用できます。
クエリに渡す前に値を適切にエスケープするには、次のような関数を作成します。
function escape($string)
{
// Assuming $db is a link identifier returned by mysqli_connect() or mysqli_init()
return mysqli_real_escape_string($db, $string);
}
そのような関数は、おそらくあなたのアプリケーションですでに利用可能であるか、多分あなたはすでにそれを作成したでしょう。
次のように文字列配列をサニタイズします。
$values = array_map('escape', $gallaries);
数値配列はintval
、floatval
以下を使用して、またはdoubleval
代わりに適切にサニタイズできます。
$values = array_map('intval', $gallaries);
次に、最後にクエリ条件を作成します
$where = count($values) ? "`id` = '" . implode("' OR `id` = '", $values) . "'" : 0;
または
$where = count($values) ? "`id` IN ('" . implode("', '", $values) . "')" : 0;
配列が空になることもある$galleries = array();
のでIN ()
、空のリストは許可されないことに注意してください。OR
代わりに使用することもできますが、問題は残っています。したがって、上記のチェックはcount($values)
、同じことを確認するためのものです。
そして、それを最後のクエリに追加します。
$query = 'SELECT * FROM `galleries` WHERE ' . $where;
ヒント:すべての行を非表示にするのではなく、空の配列の場合にすべてのレコード(フィルタリングなし)を表示する場合は、3項のfalse部分の0を1に置き換えます。
$query = 'SELECT * FROM galleries WHERE ' . (count($gallaries) ? "id IN ('" . implode("', '", array_map('escape', $gallaries)) . "')" : 0);
Col. ShrapnelのPHP用SafeMySQLライブラリは、パラメーター化されたクエリに型ヒントのプレースホルダーを提供し、配列を操作するための便利なプレースホルダーをいくつか備えています。?a
プレースホルダは*エスケープした文字列をカンマで区切ったリストに、アレイを展開します。
例えば:
$someArray = [1, 2, 5];
$galleries = $db->getAll("SELECT * FROM galleries WHERE id IN (?a)", $someArray);
* MySQLは自動型強制を実行するため、SafeMySQLが上記のIDを文字列に変換するかどうかは関係ありません。正しい結果が得られます。
入力配列を適切にフィルタリングすれば、この「WHERE id IN」句を使用できます。このようなもの:
$galleries = array();
foreach ($_REQUEST['gallery_id'] as $key => $val) {
$galleries[$key] = filter_var($val, FILTER_SANITIZE_NUMBER_INT);
}
以下の例のように:
$galleryIds = implode(',', $galleries);
つまり今、あなたは安全に使うべきです $query = "SELECT * FROM galleries WHERE id IN ({$galleryIds})";
あなたはテーブルtexts
(T_ID (int), T_TEXT (text))
とテーブルを持っているかもしれませんtest
(id (int), var (varchar(255)))
ではinsert into test values (1, '1,2,3') ;
どこのテーブルのテキストから、次の意志の出力行T_ID IN (1,2,3)
:
SELECT * FROM `texts` WHERE (SELECT FIND_IN_SET( T_ID, ( SELECT var FROM test WHERE id =1 ) ) AS tm) >0
この方法では、追加のテーブルなしで単純なn2mデータベース関係を管理でき、PHPや他のプログラミング言語を使用する必要なくSQLのみを使用できます。
より多くの例:
$galleryIds = [1, '2', 'Vitruvian Man'];
$ids = array_filter($galleryIds, function($n){return (is_numeric($n));});
$ids = implode(', ', $ids);
$sql = "SELECT * FROM galleries WHERE id IN ({$ids})";
// output: 'SELECT * FROM galleries WHERE id IN (1, 2)'
$statement = $pdo->prepare($sql);
$statement->execute();
PDOなしの安全な方法:
$ids = array_filter(array_unique(array_map('intval', (array)$ids)));
if ($ids) {
$query = 'SELECT * FROM `galleries` WHERE `id` IN ('.implode(',', $ids).');';
}
(array)$ids
$ids
変数を配列にキャストしますarray_map
すべての配列値を整数に変換しますarray_unique
繰り返される値を削除するarray_filter
ゼロ値を削除implode
すべての値をIN選択に結合します元の質問は数値の配列に関するものであり、文字列の配列を使用しているため、指定された例を機能させることができませんでした。
IN()
関数を使用するには、各文字列を単一引用符で囲む必要があることがわかりました。
これが私の解決策です
foreach($status as $status_a) {
$status_sql[] = '\''.$status_a.'\'';
}
$status = implode(',',$status_sql);
$sql = mysql_query("SELECT * FROM table WHERE id IN ($status)");
ご覧のとおり、最初の関数は各配列変数をラップしてsingle quotes (\')
から、配列を内包します。
注:$status
SQLステートメントに単一引用符はありません。
引用符を追加するより良い方法があるでしょうが、これはうまくいきます。
$filter = "'" . implode("','",$status) . "'";
'
、文字列の中では?SQLインジェクションの脆弱性。PDO :: quoteまたはmysqli_real_escape_stringを使用します。
以下は、私が使用した方法で、PDOを他のデータの名前付きプレースホルダーと共に使用しています。SQLインジェクションを克服するために、整数である値のみを受け入れ、その他すべてを拒否するように配列をフィルタリングしています。
$owner_id = 123;
$galleries = array(1,2,5,'abc');
$good_galleries = array_filter($chapter_arr, 'is_numeric');
$sql = "SELECT * FROM galleries WHERE owner=:OWNER_ID AND id IN ($good_galleries)";
$stmt = $dbh->prepare($sql);
$stmt->execute(array(
"OWNER_ID" => $owner_id,
));
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
SQLインジェクションを防止する基本的な方法は次のとおりです。
準備されたステートメントとパラメーター化されたクエリクエリを使用することをお勧めしますが、エスケープ文字方式を選択した場合は、以下の例を試すことができます。
を使用array_map
してクエリを生成するには、の各要素に単一引用符を追加します$galleries
。
$galleries = array(1,2,5);
$galleries_str = implode(', ',
array_map(function(&$item){
return "'" .mysql_real_escape_string($item) . "'";
}, $galleries));
$sql = "SELECT * FROM gallery WHERE id IN (" . $galleries_str . ");";
生成される$ sql変数は次のようになります。
SELECT * FROM gallery WHERE id IN ('1', '2', '5');
注:mysql_real_escape_stringは、そのドキュメントで説明されているように、PHP 5.5.0で廃止され、PHP 7.0.0で削除されました。代わりに、MySQLiまたはPDO_MySQL拡張機能を使用する必要があります。詳細については、MySQL:APIガイドの選択および関連するFAQも参照してください。この関数の代替には、次のものがあります。
mysqli_real_escape_string()
PDO :: quote()