Comment créer une requête paramétrée PDO avec une instruction LIKE?

107

Voici ma tentative:

$query = $database->prepare('SELECT * FROM table WHERE column LIKE "?%"');

$query->execute(array('value'));

while ($results = $query->fetch()) 
{
    echo $results['column'];
}
Andrew G. Johnson
la source

Réponses:

124

Je l'ai compris juste après avoir publié:

$query = $database->prepare('SELECT * FROM table WHERE column LIKE ?');
$query->execute(array('value%'));

while ($results = $query->fetch())
{
    echo $results['column'];
}
Andrew G. Johnson
la source
1
@Andrew: et si le multiple likeest utilisé? comment le tableau d'exécution doit-il s'exécuter dans l'ordre?
logan
Merci. eu un problème similaire avec csharp + Mysql + ODBC en utilisant comme il ne retournerait aucune ligne en utilisant "select * from table where column like '%?%';" mais si je fais comme vous l'avez fait "sélectionnez * dans la table où la colonne comme?;" et définissez la chaîne de paramètres comme suit: string frag = $ "% {searchFragment}%"; puis utilisez frag pour la valeur du paramètre. Bizarre
sdjuan
2
PDO doit échapper à ce% dans l'appel d'exécution. La réponse de Kaqai est meilleure
Peter Bagnall
Il semble intéressant de noter que la note la plus fournie par l' utilisateur sur la page de documentation PDOStatement :: bindParam propose une approche différente: ajoutez le (s) signe (s) de pourcentage à la variable avant de la lier.
Dan Robinson
Jetez un œil à la solution de gavin, tirée de la page de Votre bon sens, vers le bas de ce fil. Facile. Logique.
RationalRabbit
85

Pour ceux qui utilisent des paramètres nommés, voici comment utiliser LIKEavec %une correspondance partielle pour les bases de données MySQL :

WHERE nom_colonne LIKE CONCAT ('%',: chaîne dangereuse, '%')

où se trouve le paramètre nommé :dangerousstring.

En d'autres termes, utilisez des %signes explicitement non échappés dans votre propre requête qui sont séparés et certainement pas l'entrée de l'utilisateur.

Edit: La syntaxe de concaténation pour les bases de données Oracle utilise l'opérateur de concaténation:, ||donc il deviendra simplement:

WHERE nom_colonne LIKE '%' || : chaîne dangereuse || '%'

Cependant, il y a des mises en garde comme @bobince mentionne ici que:

La difficulté vient lorsque vous voulez autoriser un littéral %ou un _caractère dans la chaîne de recherche, sans qu'il agisse comme un caractère générique.

C'est donc autre chose à surveiller lors de la combinaison du like et du paramétrage.

Kzqai
la source
6
+1 - cela me semble être une bonne approche car toute la concaténation se produit dans la base de données après que l'espace réservé a été remplacé, et cela signifie que les espaces réservés nommés peuvent être utilisés. Il convient de mentionner que la syntaxe ci-dessus est pour Oracle - dans MySQL, la syntaxe est LIKE CONCAT('%', :something, '%'). Référence: stackoverflow.com/a/661207/201648
Aaron Newton
1
Cela n'a pas fonctionné pour moi exactement, mais m'a mis sur la bonne voie. J'ai dû faire comme '%': quelque chose '%' pour que ça marche.
Christopher Smit
Je sais que c'est hors sujet, mais j'ai pu effectuer une injection SQL en utilisant même cette déclaration, pourquoi?
Thiago Dias
Cela n'a pas fonctionné pour moi, je l'ai également testé avec la commande SQL, SELECT * FROM calculation WHERE ( email LIKE '%' || luza || '%' OR siteLocation LIKE '%'|| luza ||'%' OR company LIKE '%' ||luza ||'%' )cela me donnerait une erreur.
Luzan Baral
@AaronNewton and it means named placeholders can be used. Comment est-ce même un problème avec les espaces réservés nommés lorsque vous concaténez en PHP? Évidemment, la concaténation en PHP prend en charge à la fois les noms et les positions et est plus portable car vous pouvez utiliser la même requête pour n'importe quelle base de données. Je ne comprends pas vraiment pourquoi tant de gens pensent qu'il y a une différence entre les espaces réservés nommés et positionnels.
Votre bon sens le
18
$query = $database->prepare('SELECT * FROM table WHERE column LIKE ?');
$query->bindValue(1, "%$value%", PDO::PARAM_STR);
$query->execute();

if (!$query->rowCount() == 0) 
{
    while ($results = $query->fetch()) 
    {
        echo $results['column'] . "<br />\n";
    }       
} 
else 
{
    echo 'Nothing found';
}
blazer
la source
1
Y a-t-il un avantage à utiliser cela par rapport à la réponse acceptée? L'utilisation bindValueprotège- t-elle contre les attaques par injection? La réponse acceptée annule fondamentalement la valeur de l'utilisation d' ?espaces réservés en concaténant la chaîne de recherche pour qu'elle %aime dans les jours anciens.
felwithe
Quel est l'intérêt d'utiliser la négation avant le $ query-> rowCount () == 0? Cela a-t-il vraiment un sens?
ssi-anik
14

Vous pouvez également essayer celui-ci. Je suis confronté à un problème similaire mais j'ai obtenu des résultats après des recherches.

$query = $pdo_connection->prepare('SELECT * FROM table WHERE column LIKE :search');

$stmt= $pdo_connection->prepare($query);

$stmt->execute(array(':search' => '%'.$search_term.'%'));

$result = $stmt->fetchAll(PDO::FETCH_ASSOC);

print_r($result);
Vijaysinh Parmar
la source
J'ai édité votre message pour mettre le code dans un bloc de code - vous pouvez en savoir plus sur le formatage des articles sur stackoverflow.com/help/formatting . Un autre utilisateur a choisi de voter contre votre réponse sans laisser de commentaire, je ne suis donc pas sûr de la cause du vote négatif.
josliber
2
Je le répète, je n'ai pas voté sur votre question; quelqu'un d'autre a voté contre.
josliber
3

Cela marche:

search `table` where `column` like concat('%', :column, '%')
kjdion84
la source
2

J'ai eu ça grâce aux délires php

$search = "%$search%";
$stmt  = $pdo->prepare("SELECT * FROM table WHERE name LIKE ?");
$stmt->execute([$search]);
$data = $stmt->fetchAll();

Et cela fonctionne pour moi, très simple. Comme il le dit, vous devez «préparer d'abord notre littéral complet» avant de l'envoyer à la requête

Gavin
la source
0

PDO échappe "%" (peut conduire à une injection SQL) : L'utilisation du code précédent donnera les résultats souhaités lorsque vous cherchez à faire correspondre des chaînes partielles MAIS si un visiteur tape le caractère "%", vous obtiendrez toujours des résultats même si vous ne le faites pas ' t avoir quelque chose stocké dans la base de données (cela peut conduire à des injections SQL)

J'ai essayé beaucoup de variantes, toutes avec le même résultat. PDO échappe à "%" des résultats de recherche non désirés / non excités.

Je pensais que cela valait la peine d'être partagé si quelqu'un a trouvé un mot autour de lui, veuillez le partager

Ozkar R
la source
1
Ceci est tiré du manuel: us3.php.net/manual/en/pdo.prepared-statements.php Ceci est un autre article à propos du sujet: stackoverflow.com/questions/22030451/… Je voudrais vraiment connaître votre opinion sur cette émission.
Ozkar R
1
Solution possible (non testé) Utilisez CONCAT , comme: $ sql = «SELECT item_title FROM item WHERE item_title LIKE CONCAT ('%',?, '%')»; Référence: blog.mclaughlinsoftware.com/2010/02/21/php-binding-a-wildcard
Ozkar R
3
PDO n'échappe pas à%. C'est votre code qui fait le mal. Pour la solution, vous êtes censé lire les réponses déjà fournies ici
Votre bon sens
Merci pour vos suggestions. Quoi qu'il en soit, le code testé était le code du manuel, en utilisant un espace réservé pour éviter l'injection SQL, j'obtiens toujours le même résultat. Exemple # 6 L'utilisation non valide de l'espace réservé PDO échappe% en utilisant le code ci-dessus, pas mon code. Je suis nouveau sur le forum et je ne comprends peut-être pas comment le processus de commentaire, de publication et de réputation fonctionne ici, je le garderai à l'esprit pour mon prochain, car sur la base du commentaire précédent, vous avez besoin de réputation pour aider les autres ou faire des commentaires. Merci.
Ozkar R