Buscar..


Introducción

La interfaz mysqli es una mejora (significa "extensión de mejora de MySQL") de la interfaz mysql , que quedó en desuso en la versión 5.5 y se eliminó en la versión 7.0. La extensión mysqli, o como se conoce a veces, la extensión mejorada de MySQL, fue desarrollada para aprovechar las nuevas características que se encuentran en las versiones 4.1.3 y posteriores de los sistemas MySQL. La extensión mysqli se incluye con las versiones 5 y posteriores de PHP.

Observaciones

Caracteristicas

La interfaz mysqli tiene una serie de beneficios, las mejoras clave en la extensión mysql son:

  • Interfaz orientada a objetos
  • Soporte para declaraciones preparadas
  • Soporte para declaraciones múltiples
  • Soporte para transacciones
  • Capacidades de depuración mejoradas
  • Soporte de servidor incorporado

Cuenta con una interfaz dual : el más antiguo, el estilo de procedimiento y un nuevo estilo de programación orientada a objetos (OOP) . El mysql desuso tenía solo una interfaz de procedimiento, por lo que el estilo orientado a objetos es a menudo preferido. Sin embargo, el nuevo estilo también es favorable debido al poder de la POO.

Alternativas

Una alternativa a la interfaz mysqli para acceder a las bases de datos es la nueva interfaz de objetos de datos PHP (PDO) . Esto incluye solo programación estilo OOP y puede acceder a más que solo bases de datos tipo MySQL.

MySQLi Connect

Estilo orientado a objetos

Conectar al servidor

$conn = new mysqli("localhost","my_user","my_password");

Establezca la base de datos predeterminada: $conn->select_db("my_db");

Conectar a la base de datos

$conn = new mysqli("localhost","my_user","my_password","my_db");

Estilo procesal

Conectar al servidor

$conn = mysqli_connect("localhost","my_user","my_password");

Establezca la base de datos predeterminada: mysqli_select_db($conn, "my_db");

Conectar a la base de datos

$conn = mysqli_connect("localhost","my_user","my_password","my_db");

Verificar la conexión de la base de datos

Estilo orientado a objetos

if ($conn->connect_errno > 0) {
    trigger_error($db->connect_error);
} // else: successfully connected

Estilo procesal

if (!$conn) {
   trigger_error(mysqli_connect_error());
} // else: successfully connected

Consulta de MySQLi

La función de query toma una cadena SQL válida y la ejecuta directamente en la conexión de base de datos $conn

Estilo orientado a objetos

$result = $conn->query("SELECT * FROM `people`");

Estilo procesal

$result = mysqli_query($conn, "SELECT * FROM `people`");

PRECAUCIÓN

Un problema común aquí es que las personas simplemente ejecutarán la consulta y esperarán que funcione (es decir, devolver un objeto mysqli_stmt ). Dado que esta función solo toma una cadena, primero se crea la consulta usted mismo. Si hay algún error en el SQL, el compilador de MySQL fallará, momento en el que esta función devolverá el valor false .

$result = $conn->query('SELECT * FROM non_existent_table'); // This query will fail
$row = $result->fetch_assoc();

El código anterior generará un error E_FATAL porque $result es false y no un objeto.

Error fatal de PHP: llamar a una función miembro fetch_assoc () en un no objeto

El error de procedimiento es similar, pero no fatal, porque solo estamos violando las expectativas de la función.

$row = mysqli_fetch_assoc($result); // same query as previous

Obtendrá el siguiente mensaje de PHP

mysqli_fetch_array () espera que el parámetro 1 sea mysqli_result, dado un valor booleano

Puedes evitar esto haciendo una prueba primero.

if($result) $row = mysqli_fetch_assoc($result);

Recorrer los resultados de MySQLi

PHP hace que sea fácil obtener datos de sus resultados y recorrerlos usando una instrucción while . Cuando no puede obtener la siguiente fila, devuelve false y su bucle termina. Estos ejemplos trabajan con

Estilo orientado a objetos

while($row = $result->fetch_assoc()) {
    var_dump($row);
}

Estilo procesal

while($row = mysqli_fetch_assoc($result)) {
    var_dump($row);
}

Para obtener información exacta de los resultados, podemos utilizar:

while ($row = $result->fetch_assoc()) {
    echo 'Name and surname: '.$row['name'].' '.$row['surname'].'<br>';
    echo 'Age: '.$row['age'].'<br>'; // Prints info from 'age' column
}

Conexión cercana

Cuando hayamos terminado de consultar la base de datos, se recomienda cerrar la conexión para liberar recursos.

Estilo orientado a objetos

$conn->close();

Estilo procesal

mysqli_close($conn);

Nota : La conexión con el servidor se cerrará tan pronto como finalice la ejecución del script, a menos que se cierre antes llamando explícitamente a la función de cerrar conexión.

Caso de uso: si nuestro script tiene una buena cantidad de procesamiento para realizar después de obtener el resultado y ha recuperado el conjunto de resultados completo, definitivamente debemos cerrar la conexión. Si no lo hiciéramos, existe la posibilidad de que el servidor MySQL alcance su límite de conexión cuando el servidor web tenga un uso intensivo.

Declaraciones preparadas en MySQLi

Lea la sección Prevención de la inyección de SQL con consultas parametrizadas para ver una explicación completa de por qué las declaraciones preparadas lo ayudan a proteger sus declaraciones de SQL de los ataques de inyección de SQL.

La variable $conn aquí es un objeto MySQLi. Vea el ejemplo de conexión de MySQLi para más detalles.

Para ambos ejemplos, asumimos que $sql es

$sql = "SELECT column_1 
    FROM table 
    WHERE column_2 = ? 
        AND column_3 > ?";

El ? Representa los valores que proporcionaremos más adelante. Tenga en cuenta que no necesitamos cotizaciones para los marcadores de posición, independientemente del tipo. También podemos proporcionar solo marcadores de posición en las partes de datos de la consulta, es decir, SET , VALUES y WHERE . No puede utilizar marcadores de posición en las partes SELECT o FROM .

Estilo orientado a objetos

if ($stmt = $conn->prepare($sql)) {
  $stmt->bind_param("si", $column_2_value, $column_3_value);
  $stmt->execute();

  $stmt->bind_result($column_1);
  $stmt->fetch();
  //Now use variable $column_1 one as if it were any other PHP variable
  $stmt->close();
}

Estilo procesal

if ($stmt = mysqli_prepare($conn, $sql)) {
  mysqli_stmt_bind_param($stmt, "si", $column_2_value, $column_3_value);
  mysqli_stmt_execute($stmt);
  // Fetch data here
  mysqli_stmt_close($stmt);
}

El primer parámetro de $stmt->bind_param o el segundo parámetro de mysqli_stmt_bind_param está determinado por el tipo de datos del parámetro correspondiente en la consulta SQL:

Parámetro Tipo de datos del parámetro enlazado
i entero
d doble
s cuerda
b gota

Su lista de parámetros debe estar en el orden provisto en su consulta. En este ejemplo, si significa que el primer parámetro ( column_2 = ? ) Es cadena y el segundo parámetro ( column_3 > ? ) Es entero.

Para recuperar datos, consulte Cómo obtener datos de una declaración preparada

Cuerdas de escape

Escapar de cadenas es un método más antiguo ( y menos seguro ) de asegurar los datos para insertarlos en una consulta. Funciona utilizando la función mysql_real_escape_string () de MySQL para procesar y sanear los datos (en otras palabras, PHP no está escapando). La API de MySQLi proporciona acceso directo a esta función

$escaped = $conn->real_escape_string($_GET['var']);
// OR
$escaped = mysqli_real_escape_string($conn, $_GET['var']);

En este punto, tiene una cadena que MySQL considera segura para usar en una consulta directa

$sql = 'SELECT * FROM users WHERE username = "' . $escaped . '"';
$result = $conn->query($sql);

Entonces, ¿por qué esto no es tan seguro como las declaraciones preparadas ? Hay formas de engañar a MySQL para que produzca una cadena que considere segura. Considere el siguiente ejemplo

$id = mysqli_real_escape_string("1 OR 1=1");    
$sql = 'SELECT * FROM table WHERE id = ' . $id;

1 OR 1=1 no representa datos de los que MySQL se escapará, sin embargo, esto todavía representa la inyección de SQL. También hay otros ejemplos que representan lugares en los que devuelve datos no seguros. El problema es que la función de escape de MySQL está diseñada para hacer que los datos cumplan con la sintaxis SQL . NO está diseñado para garantizar que MySQL no pueda confundir los datos del usuario con las instrucciones SQL .

MySQLi Insertar ID

Recupere el último ID generado por una consulta INSERT en una tabla con una columna AUTO_INCREMENT .

Estilo orientado a objetos

$id = $conn->insert_id;

Estilo procesal

$id = mysqli_insert_id($conn);

Devuelve cero si no hubo una consulta previa en la conexión o si la consulta no actualizó un valor de AUTO_INCREMENT.

Insertar ID al actualizar filas

Normalmente, una instrucción UPDATE no devuelve un ID de inserción, ya que un ID AUTO_INCREMENT solo se devuelve cuando se ha guardado (o insertado) una nueva fila. Una forma de hacer actualizaciones al nuevo id es usar la sintaxis INSERT ... ON DUPLICATE KEY UPDATE para actualizar.

Configuración de ejemplos a seguir:

CREATE TABLE iodku (
    id INT AUTO_INCREMENT NOT NULL,
    name VARCHAR(99) NOT NULL,
    misc INT NOT NULL,
    PRIMARY KEY(id),
    UNIQUE(name)
) ENGINE=InnoDB;

INSERT INTO iodku (name, misc)
    VALUES
    ('Leslie', 123),
    ('Sally', 456);
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0
+----+--------+------+
| id | name   | misc |
+----+--------+------+
|  1 | Leslie |  123 |
|  2 | Sally  |  456 |
+----+--------+------+

El caso de IODKU realizando una "actualización" y LAST_INSERT_ID() recuperando la id relevante:

$sql = "INSERT INTO iodku (name, misc)
    VALUES
    ('Sally', 3333)            -- should update
    ON DUPLICATE KEY UPDATE    -- `name` will trigger "duplicate key"
    id = LAST_INSERT_ID(id),
    misc = VALUES(misc)";
$conn->query($sql);
$id = $conn->insert_id;        -- picking up existing value (2)

El caso en el que IODKU realiza una "inserción" y LAST_INSERT_ID() recupera la nueva id :

$sql = "INSERT INTO iodku (name, misc)
    VALUES
    ('Dana', 789)            -- Should insert
    ON DUPLICATE KEY UPDATE
    id = LAST_INSERT_ID(id),
    misc = VALUES(misc);
$conn->query($sql);
$id = $conn->insert_id;      -- picking up new value (3)

Contenido de la tabla resultante:

SELECT * FROM iodku;
+----+--------+------+
| id | name   | misc |
+----+--------+------+
|  1 | Leslie |  123 |
|  2 | Sally  | 3333 |  -- IODKU changed this
|  3 | Dana   |  789 |  -- IODKU added this
+----+--------+------+

Depuración de SQL en MySQLi

Entonces su consulta ha fallado (vea MySQLi connect para ver cómo hicimos $conn )

$result = $conn->query('SELECT * FROM non_existent_table'); // This query will fail

¿Cómo averiguamos lo que pasó? $result es false así que no sirve de nada. Afortunadamente, connect $conn puede decirnos lo que MySQL nos dijo sobre el error.

trigger_error($conn->error);

o procesal

trigger_error(mysqli_error($conn));

Debería obtener un error similar a

La tabla 'my_db.non_existent_table' no existe

Cómo obtener datos de una declaración preparada

Declaraciones preparadas

Vea las declaraciones preparadas en MySQLi para saber cómo preparar y ejecutar una consulta.

Vinculación de resultados

Estilo orientado a objetos

$stmt->bind_result($forename);

Estilo procesal

mysqli_stmt_bind_result($stmt, $forename);

El problema con el uso de bind_result es que requiere que la declaración especifique las columnas que se usarán. Esto significa que para que la consulta anterior funcione, la consulta debe tener este aspecto SELECT forename FROM users . Para incluir más columnas, simplemente agréguelos como parámetros a la función bind_result (y asegúrese de agregarlos a la consulta SQL).

En ambos casos, estamos asignando la columna forename a la variable $forename . Estas funciones toman tantos argumentos como columnas que desea asignar. La asignación solo se realiza una vez, ya que la función se enlaza por referencia.

Entonces podemos hacer un bucle de la siguiente manera:

Estilo orientado a objetos

while ($stmt->fetch())
    echo "$forename<br />";

Estilo procesal

while (mysqli_stmt_fetch($stmt))
    echo "$forename<br />";

El inconveniente de esto es que tiene que asignar muchas variables a la vez. Esto hace que el seguimiento de grandes consultas sea difícil. Si tiene instalado MySQL Native Driver ( mysqlnd ) , todo lo que necesita hacer es usar get_result .

Estilo orientado a objetos

$result = $stmt->get_result();

Estilo procesal

$result = mysqli_stmt_get_result($stmt);

Es mucho más fácil trabajar con esto porque ahora obtenemos un objeto mysqli_result . Este es el mismo objeto que devuelve mysqli_query . Esto significa que puede usar un ciclo de resultados regular para obtener sus datos.


¿Qué pasa si no puedo instalar mysqlnd ?

Si ese es el caso, @Sophivorus lo tiene cubierto con esta asombrosa respuesta .

Esta función puede realizar la tarea de get_result sin que esté instalada en el servidor. Simplemente recorre los resultados y crea una matriz asociativa

function get_result(\mysqli_stmt $statement)
{
    $result = array();
    $statement->store_result();
    for ($i = 0; $i < $statement->num_rows; $i++)
    {
        $metadata = $statement->result_metadata();
        $params = array();
        while ($field = $metadata->fetch_field())
        {
            $params[] = &$result[$i][$field->name];
        }
        call_user_func_array(array($statement, 'bind_result'), $params);
        $statement->fetch();
    }
    return $result;
}

Luego podemos usar la función para obtener resultados como este, como si estuviéramos usando mysqli_fetch_assoc()

<?php
$query = $mysqli->prepare("SELECT * FROM users WHERE forename LIKE ?");
$condition = "J%";
$query->bind_param("s", $condition);
$query->execute();
$result = get_result($query);

while ($row = array_shift($result)) {
    echo $row["id"] . ' - ' . $row["forename"] . ' ' . $row["surname"] . '<br>';
}

Tendrá la misma salida que si estuviera usando el controlador mysqlnd , excepto que no tiene que estar instalado. Esto es muy útil si no puede instalar dicho controlador en su sistema. Solo implementa esta solución.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow