web-dev-qa-db-fra.com

SELECT * FROM dans MySQLi

Mon site est plutôt complet et je viens tout juste de passer à PHP5 (appelez-moi tardivement).

Toutes mes requêtes antérieures à MySQL ont été construites en tant que telles:

"SELECT * FROM tablename WHERE field1 = 'value' && field2 = 'value2'";

Cela a rendu les choses très faciles, simples et amicales.

J'essaie maintenant de passer à mysqli pour des raisons évidentes de sécurité et j'ai du mal à comprendre comment implémenter les mêmes requêtes SELECT * FROM lorsque le bind_param nécessite des arguments spécifiques.

Cette déclaration est-elle une chose du passé?

Si tel est le cas, comment gérer une requête avec des tonnes de colonnes impliquées? Dois-je vraiment les taper tous à chaque fois?

23
johnnietheblack
"SELECT * FROM tablename WHERE field1 = 'value' && field2 = 'value2'";

devient

"SELECT * FROM tablename WHERE field1 = ? && field2 = ?";

qui est passé au $mysqli::prepare:

$stmt = $mysqli->prepare(
  "SELECT * FROM tablename WHERE field1 = ? && field2 = ?");
$stmt->bind_param( "ss", $value, $value2); 
// "ss' is a format string, each "s" means string
$stmt->execute();

$stmt->bind_result($col1, $col2);
// then fetch and close the statement

Commentaires OP:

donc, si j'ai 5 paramètres, je pourrais potentiellement avoir "sssis" ou quelque chose (en fonction des types d'entrées?) 

A droite, un spécificateur de type par paramètre ? dans l'instruction préparée, tous étant positionnels (le premier spécificateur s'applique au premier ? qui est remplacé par le premier paramètre réel (qui est le deuxième paramètre à bind_param)).

mysqli se chargera de s'échapper et de citer (je pense). 

32
tpdi

C'était déjà il y a un mois, mais bon.

Je peux me tromper, mais pour votre question, j'ai l'impression que bind_param n'est pas vraiment le problème ici. Vous devez toujours définir certaines conditions, que ce soit directement dans la chaîne de requête elle-même, consistant à utiliser bind_param pour définir les espaces réservés ?. Ce n'est pas vraiment un problème.

Le problème que j'ai rencontré lors de l'utilisation des requêtes MySQLi SELECT * est la partie bind_result. C'est là que ça devient intéressant. Je suis tombé sur ce post de Jeffrey Way:  http://jeff-way.com/2009/05/27/tricky-prepared-statements/(Ce lien n'est plus actif). Le script parcourt essentiellement les résultats et les renvoie sous forme de tableau. Inutile de savoir le nombre de colonnes et vous pouvez toujours utiliser des instructions préparées.

Dans ce cas, cela ressemblerait à quelque chose comme ceci:

$stmt = $mysqli->prepare(
  'SELECT * FROM tablename WHERE field1 = ? AND field2 = ?');
$stmt->bind_param('ss', $value, $value2);
$stmt->execute();

Ensuite, utilisez l'extrait de code du site:

$meta = $stmt->result_metadata();

while ($field = $meta->fetch_field()) {
  $parameters[] = &$row[$field->name];
}

call_user_func_array(array($stmt, 'bind_result'), $parameters);

while ($stmt->fetch()) {
  foreach($row as $key => $val) {
    $x[$key] = $val;
  }
  $results[] = $x;
}

Et $results contient maintenant toutes les informations de SELECT *. Jusqu'à présent, j'ai trouvé cette solution idéale.

51
Alec

Pendant que vous passez, passez à PDO au lieu de mysqli. Il vous aide à écrire du code agnositc de base de données et offre de meilleures fonctionnalités pour les instructions préparées.

http://www.php.net/pdo

Bindparam for PDO: http://se.php.net/manual/en/pdostatement.bindparam.php

$sth = $dbh->prepare("SELECT * FROM tablename WHERE field1 = :value1 && field2 = :value2");
$sth->bindParam(':value1', 'foo');
$sth->bindParam(':value2', 'bar');
$sth->execute();

ou: 

$sth = $dbh->prepare("SELECT * FROM tablename WHERE field1 = ? && field2 = ?");
$sth->bindParam(1, 'foo');
$sth->bindParam(2, 'bar');
$sth->execute();

ou exécuter avec les paramètres sous forme de tableau:

$sth = $dbh->prepare("SELECT * FROM tablename WHERE field1 = :value1 && field2 = :value2");
$sth->execute(array(':value1' => 'foo' , ':value2' => 'bar'));

Vous aurez plus de facilité si vous souhaitez que votre application puisse s'exécuter ultérieurement sur différentes bases de données.

Je pense également que vous devriez investir un peu de temps dans l’utilisation de certaines des classes de Zend Framwework lorsque vous travaillez avec AOP. Découvrez leurs Zend_Db et plus précisément [Zend_Db_Factory] [2]. Vous n'êtes pas obligé d'utiliser tout le cadre ou de convertir votre application en modèle MVC, mais utiliser le cadre et en lire le contenu est une bonne utilisation de votre temps.

6
olle

Cette déclaration est-elle une chose du passé?

Oui. N'utilisez pas SELECT *; c'est un cauchemar d'entretien. Il y a des tonnes d'autres discussions sur SO sur la raison pour laquelle cette construction est mauvaise et sur la façon dont l'éviter vous aidera à écrire de meilleures requêtes.

Voir également:

2
kquinn

Vous pouvez toujours l'utiliser (mysqli est juste un autre moyen de communiquer avec le serveur, le langage SQL lui-même est développé et non modifié). Les déclarations préparées sont plus sûres, cependant - puisque vous n'avez pas besoin de passer par la difficulté d'échapper correctement à vos valeurs à chaque fois. Vous pouvez les laisser tels quels, si vous le souhaitez, mais le risque de portage SQL est réduit si vous changez de système.

2
soulmerge

Je cherchais un exemple complet et agréable de la manière de lier dynamiquement plusieurs paramètres de requête à n’importe quelle requête SELECT, INSERT, UPDATE et DELETE. Alec mentionne dans sa réponse comment lier un résultat. Pour moi, la fonction get_result () après execute () pour les requêtes SELECT fonctionne parfaitement et permet de récupérer tous les résultats sélectionnés dans un tableau de tableaux associatifs .

Quoi qu'il en soit, j'ai fini par créer une fonction dans laquelle je suis capable de lier dynamiquement n'importe quel nombre de paramètres à une requête paramétrée (à l'aide de la fonction call_user_func_array) et d'obtenir un résultat de l'exécution de la requête. Vous trouverez ci-dessous la fonction avec sa documentation (veuillez le lire avant de l'utiliser - en particulier le paramètre $ paremetersTypes - Le type de spécification de type chars est important à comprendre)

     /**
     * Prepares and executes a parametrized QUERY (SELECT, INSERT, UPDATE, DELETE)
     *
     * @param[in] $dbConnection mysqli database connection to be used for query execution
     * @param[in] $dbQuery parametrized query to be bind parameters for and then execute
     * @param[in] $isDMQ boolean value, should be set to TRUE for (DELETE, INSERT, UPDATE - Data manipulaiton queries), FALSE for SELECT queries
     * @param[in] $paremetersTypes String representation for input parametrs' types as per http://php.net/manual/en/mysqli-stmt.bind-param.php
     * @param[in] $errorOut A variable to be passed by reference where a string representation of an error will be present if a FAUILURE occurs
     * @param[in] $arrayOfParemetersToBind Parameters to be bind to the parametrized query, parameters need to be specified in an array in the correct order 
     * @return array of feched records associative arrays for SELECT query on SUCCESS, TRUE for INSERT, UPDATE, DELETE queries on SUCCESS, on FAIL sets the error and returns NULL 
     */
    function ExecuteMySQLParametrizedQuery($dbConnection, $dbQuery, $isDMQ, $paremetersTypes, &$errorOut, $arrayOfParemetersToBind)
    {
        $stmt = $dbConnection->prepare($dbQuery);

        $outValue = NULL;

        if ($stmt === FALSE)
            $errorOut = 'Failed to prepare statement for query: ' . $dbQuery;
        else if ( call_user_func_array(array($stmt, "bind_param"), array_merge(array($paremetersTypes), $arrayOfParemetersToBind)) === FALSE)
            $errorOut = 'Failed to bind required parameters to query: ' . $dbQuery . '  , parameters :' . json_encode($arrayOfParemetersToBind);
        else if (!$stmt->execute())
            $errorOut = "Failed to execute query [$dbQuery] , erorr:" . $stmt->error;
        else
        {
            if ($isDMQ)
               $outValue = TRUE;
            else
            {
                $result = $stmt->get_result();

                if ($result === FALSE) 
                     $errorOut = 'Failed to obtain result from statement for query ' . $dbQuery;
                else
                    $outValue = $result->fetch_all(MYSQLI_ASSOC);
            }
        }

        $stmt->close();

        return $outValue;
    }

usage:

    $param1 = "128989";
    $param2 = "some passcode";


    $insertQuery = "INSERT INTO Cards (Serial, UserPin) VALUES (?, ?)";
    $rowsInserted = ExecuteMySQLParametrizedQuery($dbConnection, $insertQuery, TRUE, 'ss', $errorOut, array(&$param1, &$param2) ); // Make sure the parameters in an array are passed by reference

    if ($rowsInserted === NULL)
        echo 'error ' . $errorOut;
    else
        echo "successfully inserted row";


    $selectQuery = "SELECT CardID FROM Cards WHERE Serial like ? AND UserPin like ?";
    $arrayOfCardIDs = ExecuteMySQLParametrizedQuery($dbConnection, $selectQuery, FALSE, 'ss', $errorOut, array(&$param1, &$param2) ); // Make sure the parameters in an array are passed by reference

    if ($arrayOfCardIDs === NULL) 
        echo 'error ' . $errorOut;
    else
    {
        echo 'obtained result array of ' . count($arrayOfCardIDs) . 'selected rows';

        if (count($arrayOfCardIDs) > 0) 
            echo 'obtained card id = ' . $arrayOfCardIDs[0]['CardID'];
    }
0
mbuster

vous pouvez utiliser get_result() sur la déclaration.

http://php.net/manual/en/mysqli-stmt.get-result.php

0
Sugumar Venkatesan