2009-04-15 32 views
23

Mi sitio es bastante extenso, y recientemente hice el cambio a PHP5 (llámame bloomer tardío).SELECCIONAR * FROM en MySQLi

Todos los de antes de la construcción como tal mi consulta MySQL:

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

Esto hizo muy fácil, sencillo y agradable.

Ahora estoy tratando de hacer el cambio a mysqli por obvias razones de seguridad, y estoy teniendo dificultades para encontrar la manera de implementar las mismas consultas SELECT * FROM cuando el bind_param requiere argumentos específicos.

¿Es esta afirmación una cosa del pasado?

Si lo es, ¿cómo manejo una consulta con toneladas de columnas involucradas? ¿De verdad necesito escribirlos todos?

Respuesta

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

convierte

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

que se pasa a los $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 

OP comentarios:

por lo que si tengo 5 parámetros, podría tener potencialmente " chasis "o algo así (dependiendo de los tipos) de entradas?)

derecho, un tipo especificador por ? parámetro en la declaración preparada, todos ellos posicional (primera especificador se aplica a primera ? que se sustituye por primera parámetro real (que es el segundo parámetro para bind_param))

mysqli se ocupará de escapar y citar (creo).

+2

así que si tengo 5 parámetros, podría tener potencialmente "sssis" o algo así (dependiendo de los tipos de entradas?) – johnnietheblack

+1

que es correcto – OverlordvI

2

¿Es esta afirmación una cosa del pasado?

Sí. No use SELECT *; es una pesadilla de mantenimiento Hay toneladas de otros hilos en SO sobre por qué este constructo es malo, y cómo evitarlo te ayudará a escribir mejores consultas.

Consulte también:

+0

bien ... estoy totalmente te creo, pero estoy teniendo problemas para encontrar alguna manera, y yo podría aprender de ellos estoy seguro. ¿Podrías darme un enlace? gracias :) – johnnietheblack

+0

Creo que la pregunta fue sobre variables de enlace. No veo un gran problema con "SELECT *" (si necesita más que una clave principal o columnas indexadas). – Thilo

+0

Sí, a los motores de búsqueda no les gusta consultar "SELECT *" mucho; Edité mi publicación con un par de enlaces (el primer enlace es especialmente útil). – kquinn

2

fijas que se pueden utilizar (mysqli es sólo otra manera de comunicarse con el servidor, el lenguaje SQL en sí es ampliado, no cambiado). Prepared statements son más seguros, sin embargo, ya que no es necesario que se tome la molestia de escaparse correctamente de sus valores cada vez. Puede dejarlos como estaban, si lo desea, pero el riesgo de sql piggybacking se reduce si cambia.

+0

A veces incluso * necesitas * el uso anterior. Mysql no puede hacer múltiples insertos en una declaración preparada, por ejemplo. – soulmerge

+0

no puede? ¿No es eso algo que la mayoría de la gente necesita hacer? – johnnietheblack

+0

No, no puede hacer algo como INSERT INTO A (a, b) VALUES (1,2), (3,4), (5,6). Y * si * (y solo si) la velocidad es un problema (que no debería ser en el 99% de los casos, pero acabamos de tener uno en un proyecto reciente), considere esto: las declaraciones preparadas necesitan 3 comunicaciones para 1 consulta (prepare, set var, execute) – soulmerge

6

Durante el cambio, cambie a PDO en lugar de a mysqli, le ayuda a escribir el código de agnositc de la base de datos y tiene mejores características para las declaraciones preparadas.

http://www.php.net/pdo

bindParam para 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(); 

o:

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

o ejecutar con los parámetros como una matriz:

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

Será más fácil para usted si desea que su aplicación pueda ejecutarse en bases de datos diferentes en el futuro.

También creo que debería invertir algo de tiempo en utilizar algunas de las clases de Zend Framwework mientras trabaja con PDO. Consulte su Zend_Db y más específicamente [Zend_Db_Factory] [2]. No tiene que usar todo el framework o convertir su aplicación al patrón MVC, pero usar el framework y leerlo es tiempo bien empleado.

+1

awesome, Nunca he oído hablar de PDO, lo verifico – johnnietheblack

50

Esto ya fue hace un mes, pero bueno.

Podría estar equivocado, pero para su pregunta me da la sensación de que bind_param no es realmente el problema aquí. Siempre debe definir algunas condiciones, ya sea directamente en la cadena de consulta, de usar bind_param para establecer los marcadores de posición ?. Eso no es realmente un problema.

El problema que tuve con las consultas de MySQLi SELECT * es la parte bind_result. Ahí es donde se pone interesante. Me encontré con esta publicación de Jeffrey Way: http://jeff-way.com/2009/05/27/tricky-prepared-statements/ (Este enlace ya no está activo). La secuencia de comandos básicamente recorre los resultados y los devuelve como una matriz; no es necesario saber cuántas columnas hay, y aún puede usar las declaraciones preparadas.

En este caso, se vería algo como esto:

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

A continuación, utilice el fragmento desde el sitio:

$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; 
}

Y $results ahora contiene toda la información de SELECT *. Hasta ahora, encontré que esta era una solución ideal.

+5

Gracias, este fue exactamente el mismo problema que tuve, la respuesta aceptada no funcionará con SELECT * – 0plus1

+1

La mejor solución, gracias. – catalin87

+1

Impresionante. gracias y enviando de regreso - echo json_encode ($ results); , Recupero lo que quiero PERFECTAMENTE. –

0

Estaba buscando un buen y completo ejemplo de cómo vincular múltiples parámetros de consulta dinámicamente a cualquier consulta SELECT, INSERT, UPDATE y DELETE. Alec menciona en su respuesta una forma de vincular el resultado, para mí la función get_result() after execute() para consultas SELECT funciona muy bien, y puedo recuperar todos los resultados seleccionados en una matriz de matrices asociativas.

De todos modos, terminé creando una función en la que puedo vincular dinámicamente cualquier cantidad de parámetros a una consulta parametrizada (utilizando la función call_user_func_array) y obtener un resultado de la ejecución de la consulta.A continuación se muestra la función con su documentación (por favor leer antes de que antes de usar - en especial el parámetro $paremetersTypes - Type specification chars es importante entender) el uso

 /** 
    * 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; 
    } 

:

$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

http://php.net/manual/en/mysqli-result.fetch-all.php –

+0

El mensaje de error como parámetro de función es simplemente una cosa extraña. los errores deben ser errores http://php.net/manual/en/function.trigger-error.php –

+0

$ isDMQ y $ paremetersTypes deben ser opcionales –