2009-11-13 6 views
1

que quelqu'un peut me aider à voir ce qui se passe mal avec cette configurationabstraction de base de données pdo

Je construis la requête @sql dans la fonction ci-dessous comme celui-ci. Les guillemets supplémentaires sont configurés dans le tableau de conditions.

 $sql .= " WHERE $field = \"$value\""; 

La fonction de mise à jour pdo boucle le tableau de conditions comme ceci.

if (!is_null($conditions)) 
{ 
$cond = ' WHERE'; 
$obj = new CachingIterator(new ArrayIterator($conditions)); 
foreach($obj as $k=>$v) 
{ 
    $cond .= " $k=$v"; 
    $cond .= $obj->hasNext() ? ' AND' : ''; 
} 
} 

Mon point de faire est que je ne peux pas construire des tableaux avec des valeurs sans ajouter des barres obliques pour des guillemets autour des valeurs. Sinon, l'erreur sql lancée est une colonne inconnue.

Y at-il autre chose que je peux faire?

Est-ce que quelqu'un pourrait me donner des commentaires à ce sujet?

modifier: le reste de la fonction de mise à jour

Où pourrais-je lier les valeurs du tableau des conditions et les ont exécutés aussi? Comme je le vois maintenant, seul le tableau de valeurs est exécuté? Ai-je besoin de mettre en boucle les deux tableaux, puis de fusionner les deux tableaux?

$obj = new CachingIterator(new ArrayIterator($values)); 

      $db = db::getInstance(); 
      $sql = "UPDATE $table SET \n"; 
      foreach($obj as $field=>$val) 
      { 
       $sql .= "$field= :$field"; 
       $sql .= $obj->hasNext() ? ',' : ''; 
       $sql .= "\n"; 
      } 

      $sql .= $cond ; 
      $stmt = $db->prepare($sql); 

      // bind de params 
      foreach($values as $k=>$v) 
      { 
       $stmt->bindParam(':'.$k, $v); 
      } 


      $stmt->execute($values); 

merci, Richard

Répondre

1

N'utilisez pas addslashes(). C'est un moyen inadéquat d'échapper aux valeurs et il a connu des bogues de sécurité.

Les guillemets doubles dans SQL standard sont pour les identificateurs délimités. Utilisez des guillemets simples pour les littéraux de chaîne.

Le mode par défaut de MySQL vous permet d'utiliser indifféremment des guillemets simples et doubles et des guillemets pour les identificateurs délimités. Mais je recommande de prendre l'habitude d'utiliser uniquement des guillemets simples pour les chaînes, car cela rendra votre code SQL plus portable pour les autres fournisseurs de SGBDR, et aussi plus clair pour quiconque lira votre code.

Vous devez utiliser des paramètres de requête, comme le suggère @Mike B. C'est facile et c'est beaucoup plus sûr que d'interpoler des variables dans des expressions SQL.


Vous pouvez utiliser bindParam() ou vous pouvez fournir un tableau associatif $values à la fonction execute(). Faire les deux est redondant.

Notez que le tableau que vous donnez à la méthode execute() ne pas avoir le caractère : préfixer le nom d'espace réservé:

$stmt = $pdo->prepare("SELECT * FROM MyTable WHERE myfield = :myfield"); 
// both of the following would work: 
$stmt->execute(array(":myfield" => $value)); 
$stmt->execute(array("myfield" => $value)); 

aussi pour soutenir les paramètres à la fois la clause SET et la clause WHERE, je Je vous suggère de distinguer les champs lorsque vous spécifiez les noms des espaces réservés aux paramètres.De cette façon, si vous référencez le même champ dans les deux clauses (l'une pour rechercher une ancienne valeur et l'autre pour définir une nouvelle valeur), vous ne serez pas en conflit.

Peut-être ":set$field" dans la clause SET et ":where$field" dans la clause WHERE.


mise à jour: J'ai testé le code suivant. D'abord, j'utilise des tableaux simples, au lieu du CachingIterator que vous avez utilisé. Je n'ai pas besoin d'utiliser la méthode hasNext() puisque j'utilise join().

$settings = array("myfield" => "value"); 
$conditions = array("id" => 1); 

$sql = "UPDATE $table SET \n"; 

suivant est une démonstration de l'utilisation array_map() et join() au lieu de boucles. J'utilise PHP 5.3.0 pour pouvoir utiliser les fonctions de fermeture en ligne. Si vous utilisez une version antérieure de PHP, vous devrez déclarer les fonctions plus tôt et les utiliser comme callbacks.

$sql .= join(",", 
    array_map(
     function($field) { return "$field = :set$field"; }, 
     array_keys($settings) 
    ) 
); 

if ($conditions) 
{ 
    $sql .= " WHERE " 
    . join(" AND ", 
     array_map(
      function($field) { return "$field = :where$field"; }, 
      array_keys($conditions) 
     ) 
    ); 
} 

$stmt = $db->prepare($sql); 

Je ne pouvais pas bindParam() à travailler, il ajoute toujours la valeur « 1 » au lieu des valeurs réelles dans mon tableau. Alors, voici le code pour préparer un tableau associatif et le transmettre à execute():

$params = array(); 
foreach ($settings as $field=>$value) { 
    $params[":set$field"] = $value; 
} 
foreach ($conditions as $field=>$value) { 
    $params[":where$field"] = $value; 
} 

$stmt->execute($params); 
+0

Merci, c'est utile, je construisais déjà 4 boucles dans une fonction, parce que je ne suis pas trop familier avec cela. Je dois regarder de plus près cependant. – Richard

+1

Vous pouvez resserrer votre code en utilisant 'array_map()' et 'join()' à la place de toutes ces boucles. –

+0

Merci, vous étiez plus rapide, je n'ai jamais utilisé ces fonctions, donc je vais jeter un oeil à cela aussi – Richard

4

Si vous utilisez PDO, pourquoi ne pas utiliser les méthodes bindParam() et bindValue()demonstated here?

+0

merci, je vais examiner cela, si cela élimine le problème – Richard

+0

Pouvez-vous aussi plus d'un tableau avec champ/valeurs? Un pour les mises à jour et un pour les conditions. Parce que si je vois ceci -: $ stmt-> execute ($ values); alors seulement un tableau qui se lie avec les paramètres est exécuté? – Richard

Questions connexes