Consultas desde PHP

Esta sección proporciona una introducción de las opciones disponibles a la hora de desarrollar una aplicación PHP que necesite interactuar con una base de datos MySQL.

Aquí solo trataremos las APIs orientadas a objetos que es la recomendada, puesto que está más actualizada y conlleva una mejor organización de código. Con este tipo de API se instancias clases, y entonces se invocan a métodos de los objetos creados.

1. Establecer conexión

Si una aplicación en PHP necesita comunicarse con un servidor de BD, necesitará escribir el código PHP que realice tareas tales como conectar al servidor de BD, realizar consultas y otras funciones relacionadas con BD. Es necesario tener un software instalado en el sistema que proporcione a la aplicación en PHP la API, que manejará la comunicación entre el servidor de BD y la aplicación, posiblemente empleando en caso necesario otras librería. A este software generalmente se le conoce como conector, dado que permite a una aplicación conectar con un servidor de BD.

La extensión mysqli, o MySQL mejorada, se desarrolló para aprovechar las nuevas funcionalidades encontradas en los sistemas MySQL con versión 4.1.3 o posterior. La extensión mysqli viene incluida en las versiones PHP 5 y posteriores.

$mysqli = new mysqli('---servidor---','---usuario---','---clave---','---BD---') OR die('Fallo al conectar a MySQL o BD');

En el parámetro ---servidor--- normalmente se usa localhost

Lo mas común es que la cadena de conexión este en un archivo aparte y uses include();, para no tener que poner cada vez la cadena de conexión. Tener en cuenta de que si se incluye header ('Content-type: text/html; charset=utf-8'); la instrucción include tiene que ser la primera del archivo PHP.

1.1 Consulta parámetros

echo $mysqli->character_set_name();
echo $mysqli->get_charset();
echo $mysqli->stat();

1.2 Cambiar parámetros

Establece el conjunto de caracteres predeterminado del cliente.

$mysqli->set_charset('utf8');
date_default_timezone_set('America/Lima');

2. Prepara una consulta con SELECT

Para obtener un conjunto de datos de la BD se usa:

$sql = 'SELECT * FROM tabla [WHERE campo=dato'][GROUP BY campo][HAVING condicion][ORDER BY campo][LIMIT n];
$res = $mysqli->query($sql) OR die('Revisa el query de tabla<p>'. $sql);

Una vez ejecutada la consulta se puedo obtener el conjunto de datos hasta que se liberen expresamente con FREE() o CLOSE() o hasta .

2.1 Luego de SELECT

Puedes averiguar el numero de filas y columnas recuperadas.

echo $mysqli->num_rows;
echo $mysqli->field_count;

2.2 Para recuperar un solo dato

Retorna un array asociativo correspondiente a la fila obtenida o NULL si no hubiera más filas.

$res = $mysqli->query("SELECT count(*) AS n FROM tabla");
if ($row = $res->fetch_assoc()){
	$tot = $row['n'];
}else{
	$tot = 0;
}

2.3 Para recuperar un conjunto de datos asociados

while ($row = $res->fetch_assoc()) {
	echo $row['nom'];
}
$res->free_assoc();
$mysqli->close();

Los nombres de los campos devueltos por esta función son sensibles a mayúsculas y minúsculas. Esta función define campos NULOS al valor NULL de PHP.

2.4 Para recuperar un conjunto de datos en objeto

$sql ='SELECT nom,ape FROM tabla';
$res = $mysqli->query($sql) OR die('Revisa el query de tabla<p>'. $sql);
while ($obj = $res->fetch_object()) {
	echo $obj->nom;
	echo $obj->ape;
}

2.5 Para recuperar el numero de filas

echo $mysqli->num_rows;

2.6 Para recuperar el nombre de los campos

$sql = 'SELECT * FROM tabla';
if ($res = $mysqli->query($sql)){
	$col = $res->fetch_fields();
	foreach ($col as $val){
		echo 'Nombre:'. $val->name;
		echo 'Tabla:'. $val->table;
		echo 'Tipo:'. $val->type;
	}
}
PropiedadDescripción
nameEl nombre de la columna
orgnameEl nombre original de la columna si se especificó un alias
tableEl nombre de la tabla al que pertenece el campo (si no es calculado)
orgtableEl nombre original de la tabla si se especificó un alias
max_lengthEl ancho máximo del campo del conjunto de resultados.
lengthEl ancho del campo, en bytes, como se especificó en la definición de la tabla. Observe que este número (bytes) podría diferir del valor de la definición de la tabla (caracteres), dependiendo del conjunto de caracteres que se emplee. Por ejemplo, el conjunto de caracteres utf8 tiene 3 bytes por carácter, por lo que varchar(10) devolverá una longitud de 30 para utf8 (10*3), aunque devuelve 10 para latin1 (10*1).
charsetnrEl número del conjunto de caracteres (id) del campo.
flagUn entero que representa las banderas de bits del campo.
typeEl tipo de datos usado por el campo
decimalsEl número de decimales usado (para campos integer)

Si recuperaste los nombres de los campos automáticamente, probablemente quieras obtener las filas automáticamente también.

while ($row = $res->fetch_assoc()) {
	echo '<tr>';
	foreach ($col as $val) {
		echo '<td>'. $row[$val->name] .'</td>';
	}
	echo "<tr>\n";
}

2.7 Para recuperar el numero de Columnas

echo $res->num_cols;

3. UPDATE, INSERT y DELETE

Ademas de hacer consultas en la BD, es posible alterar registros con las siguientes instrucciones.

$sql = 'UPDATE tabla SET campo1=valor1[,campo2=valor2] WHERE condición';
$sql = 'INSERT INTO tabla campo1=valor1[,campo2=valor2]';
$sql = 'DELETE FROM tabla WHERE condición';

$res = $mysqli->query($sql) OR die('Revisa el query de tabla<p>'. $sql);

o tambien

try{
   $res = $mysqli->query($sql);
   } catch (Exception $e) {
      error_log("gl_actualiza.php = $sql \n",3,'gl_ERROR.log');
      exit('Error...');
   }
}

3.1 Luego den UPDATE o INSERT o DELETE

Es posible averiguar si te funciono un UPDATE o un INSERT o un DELETE y cuantas filas afecto.

if ($mysqli->affected_rows == 1){
	$G='Funciono...';
}else{
	$G='Problemas, no funciono...';
}

echo $mysqli->info;

3.2 Luego de INSERT

Devuelve el id autogenerado con el insert.

echo $mysqli->insert_id;

4. Arreglar caracteres extraños en algún campo MySQL

En ocasiones luego de importar tablas de otras fuentes te puedes encontrar con caracteres extraños. Estos se pueden corregir usando este simple instrucción.

UPDATE tabla SET campo=REPLACE(campo,'x','y');
Caracteres raros
xy
áá
éé
óó
úú
ÉÉ
ÓÓ
ÚÚ
ññ
ÑÑ
¿¿
¡¡

5. Escapar caracteres

Escapa caracteres especiales de una cadena en una sentencia SQL, teniendo en cuenta el conjunto de caracteres actual de la conexión. Se usa para crear una cadena SQL legal que pueda ser usada sin peligro en una sentencia SQL.

$var1 = $mysqli->real_escape_string();
$var2 = $mysqli->escape_string();

Evitar lo que se llama SQL inyection.

try {
   // 1. Escribe la consulta con placeholders (?)
   $sql = 'SELECT * FROM ubigeo WHERE id_dep = ? AND estado = ?';
   // 2. Preparar la sentencia
   $stmt = $mysqli->prepare($sql);
   // 3. Vincular los parámetros ('i' = integer, 's' = string, 'd' = double, 'b' = blob)
   $id_dep = 15;
   $estado = 'ACTIVO';
   $stmt->bind_param('is', $id_dep, $estado);
   // 4. Ejecutar la consulta
   $stmt->execute();
   // 5. Obtener el conjunto de resultados
   $res = $stmt->get_result();
   // 6. Leer los datos
   while ($row = $res->fetch_assoc()) {
      echo $row['pro'];
      echo $row['dis'];
   }
   // 7. Cerrar el statement
   $stmt->close();
}catch (mysqli_sql_exception $e) {
   error_log('Error en script.php: '. $e->getMessage(), 3, 'ERROR.log');
   http_response_code(500);
   exit('Error al consultar los datos. Inténtalo más tarde.');
}

Ventajas del enfoque:

Protección total contra Inyección SQL
Los parámetros enviados vía bind_param se escapan automáticamente a nivel del motor de la base de datos, separando la lógica del código SQL de los datos proporcionados por el usuario.
Eficiencia
El servidor de base de datos compila la consulta una sola vez y la ejecuta de forma optimizada con los parámetros especificados.
Metodo stmt->binf_param('tipo',$var1,$var2,...)
TipoDescripcion
sCadena de texto (String)
iEntero (Integer)
dNumero decimal (Double/Float)
bDatos binarios (BLOB)

6. Activar lanzamiento de excepciones MySQL

Si no activas esto, un error en $mysqli->query($sql) simplemente retorna false en lugar de lanzar una excepción.

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
// Configuración global (colócalo al inicio de la conexión a la base de datos)
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

$sql = 'select * from tabla';
try {
    $res = $mysqli->query($sql);
    // Procesar resultados aquí.
} catch (mysqli_sql_exception $e) {
    // Registra el mensaje y la consulta en el log
    error_log('[' . date('Y-m-d H:i:s') .'] | script.php | Error:'. $e->getMessage() .'| SQL: '. $sql "\n", 3, 'ERROR.log');
    
    // Muestra un mensaje limpio al usuario sin cortar brutalmente el script si es posible
    http_response_code(500);
    exit('Ocurrió un error al procesar la solicitud. Inténtalo nuevamente.');
}

7. Liberar consulta

Siempre se debe liberar la memoria asociada al resultado, cuando el objeto ya no es necesario.

$res->close();
$res->free();
$res->free_result();

8. Cerra la conexión

Finalmente cuando ya no se requiera hacer mas consultas se debe cerrar la conexión con la BD.

$mysqli->close();

Si ejecutas die() o exit() tambien se cieera la conexion a la BD