web-dev-qa-db-ja.com

JoomlaクエリでIN句を使用する方法

IN句を使用して値がある場合、列が推奨リストにあるレコードを選択しようとしています。以下のクエリを試しましたが、システムが機能していません。

    $db = JFactory::getDbo();
    $query = $db->getQuery(true); 
    $query
        ->select(array('type', 'name', 'id', 'created_by', 'amount', 'created', 'cat_id', 'status'))
        ->from($db->quoteName('#__Zoo_item'))
        ->where($db->quoteName('created_by') .' = '.$db->quote(10))
        ->where($db->quoteName('status') .' IN '.$db->quote(1,2,4))//THIS IS MY PROBLEM.
        ->group($db->quoteName('created_by'))
        ->order('id DESC')
        ->setLimit(1);
    $db->setQuery($query);
    $loan = $db->loadObject();

問題のある条項はこれです

->where($db->quoteName('status') .' IN '.$db->quote(1,2,4))

誰かが助けてくれると嬉しいです、ありがとう。

3
David Addoteye

まず、トラブル

->where($db->quoteName('status') .' IN '.$db->quote(1,2,4))

クエリで構文エラーが生成されるだけでなく、 $ db-> quote()1$textパラメーターとして、2,4$escapeパラメーターのboolの期待値として処理していることも原因です。 (私はPhpStormでコーディングし、この事実は綴られています)

プロジェクトにとって残念なことに、投稿したソリューションによってクエリの構文エラーが削除されますが、ロジックエラーは残ります。事実上、24の値は、すべてのクエリで無視されました。

$query->dump()を呼び出すと、生成されたクエリは次のようになります。

SELECT type,name,id,created_by,amount,created,cat_id,status
FROM `zyxwv_Zoo_item`
WHERE `created_by` = '10' AND `status` IN ('1')
GROUP BY `created_by`
ORDER BY id DESC LIMIT 1

これは、元のコードと同じようにINの破損した値と同じですが、現在は括弧で囲まれています。


2番目に、よくある誤解は、あなた[〜#〜]が必要だということです〜 #〜]を使用して、Joomla sqlクエリで可能なすべてのデータポイントを引用します。 Joomlaの開発者の中には非常に新しく、安全でない/不安定なクエリからの安全な/安定したクエリを知らない人もいるため、このコーディング方法は注意の誤りです。そして、恐ろしいアドバイスではありません。

真実は、整数を配列にハードコーディングしている場合(または、より一般的には、データが信頼できないソース(ユーザー入力またはオフサイトリソース)から提供されておらず、引用符などのモンキーレンチ文字を使用して値を組み込んでいない場合)です。クエリの安定性を十分に制御でき、セキュリティへの影響はありません。

上記のクエリの場合、次のように記述すると完全に安定していて安全です。

$query = $db->getQuery(true)
    ->select(['type', 'name', 'id', 'created_by', 'amount', 'created', 'cat_id', 'status'])
    ->from("#__Zoo_item")
    ->where(["created_by = 10", "status IN (1,2,4)"])
    ->order("id DESC")
    ->setLimit(1);

MySQL予約キーワード 、変数、文字列内の引用符はありません。また、テーブルプレフィックス#__は最初は安定していると想定されているため、クエリははるかに少ないコード膨張で記述でき、改善されています効率性があり、それでも安全で安定しています。

*注意:SELECT句にはAGGREGATE関数がないため、不要なgroup()句を削除しました。


他の研究者向け...

あなたはできます次のように整数を引用ラップします:

->where("status IN (" . implode(',', $db->q($array)) . ")")

この手法はインジェクション攻撃からクエリを保護することが証明されますが、入力値を整数として無害化しません。完全に誤ったデータ型がクエリに入る可能性があるため、これは適切なソリューションよりもショートカットです。

文字列値の信頼できない動的な配列(すべて整数と見なされる)がある場合は、独自のサニタイジングプロセスを作成するか、各値を整数としてキャストできます。

->where("status IN (" . implode(',', array_map('intval', $array)) . ")")  

または、コアでArrayHelperメソッドを使用できます(これは実質的に同じことを行います)...

これは、Joomlaドキュメンテーション@ https://docs.joomla.org/Secure_coding_guidelinesのSecure_arrays_of_integersセクション **で表現されています。

->where($db->quoteName('status') . ' IN (' . implode(',', ArrayHelper::toInteger($array)) . ')')

Joomlaコアは、administrator/components/com_contact/models/contacts.phpのようなファイルでtoInteger()を使用して独自のクエリを適切に保護していることがわかります。

*注、スクリプトのアクセシビリティによっては、次の宣言が必要になる場合があります。

use \Joomla\Utilities\ArrayHelper;

INの引用符で囲まれた/エスケープされたコンマ区切りの文字列を生成したい場合(値が整数ではないため)、構文は少し長くなります。

サブPHP7.4

->where("fullname IN (" . implode(',', array_map(function($n)use($db){return $db->q($n);}, $array)) . ")")

PHP7.4以降

->where("fullname IN (" . implode(',', array_map(fn($n) => $db->q($n), $array)) . ")")

この最後のスニペットは、各文字列を適切に単一引用符で囲み、各文字列内の単一引用符をエスケープします(例:'Mark O\'Malley')。もう少し読むための 同様の投稿 です。

7
mickmackusa

解決しました。私がやったことは、quote()メソッドをブラケットで囲むことでした

->where($db->quoteName('status') .' IN ('.$db->quote(1,2,4).')')

これで問題は解決しました。誰かのお役に立てば幸いです。

0
David Addoteye