PHP y SQL
Índice
1. API, driver y PDO
- API: conjunto de funciones/objetos que permiten conectar a una base de datos SQL
- PDO: conjunto de funciones que pueden acceder a cualquier base de datos, siempre que haya un driver para ello
- El driver adapta una API al PDO
- Por ser más simple, utilizaremos el API mysqli
2. mysqli: API orientada a objetos o procedimental
mysqlipuede usarse de dos formas- Como métodos de un objeto conexión
- Como funciones que reciben una conexión
No se recomienda mezclarlas
// ORIENTADO A OBJETOS $conexion = new mysqli("ejemplo.com", "usuario", "contraseña", "basedatos"); $conexion->query("DROP TABLE IF EXISTS test"); // PROCEDIMENTAL $conexion = mysqli_connect("ejemplo.com", "usuario", "contraseña", "basedatos"); mysqli_query($conexion,"DROP TABLE IF EXISTS test");
3. Conexión
mysqli_connect- Utiliza opciones por defecto
- Recibe servidor, usuario, contraseña, base de datos y puerto.
mysqli_init -> mysqli_options -> mysqli_real_connect- Permite la configuración de varios parámetros, como el timeout de la conexión.
- Al finalizar,
mysqli_close
3.1. Conexiones persistentes
- Cuando el script PHP termina, se cierran todas las conexiones
- Esto puede ser poco eficiente, ya que se debe abrir otra conexión la vez siguiente
- Una conexión persistente puede ser más eficiente. Cada API tiene su forma de conseguirla
- En
mysqli, conp:delante del nombre de host
- En
4. Sentencias DDL
- Con el método
query
$conn->query('
create table clientes(
id int auto_increment primary key,
nombre varchar(255),
apellidos varchar(255)
);
');
4.1. Ejercicios
- Crea una tabla como la del ejemplo. Comprueba que se ha creado desde phpMyAdmin o línea de comandos
- Crea un formulario que pregunte por el nombre de tabla, el nombre y el tipo de tres campos. El botón de submit creará esa tabla.
5. Sentencias DML
- Pasos generales
- Lanzar la sentencia
- Sentencia directa
- O bien, sentencia preparada
- Recoger los resultados
- El cliente puede requerir todos los datos de una vez, y libera al servidor. Esto puede sobrecargar la memoria del cliente.
- El cliente puede ir pidiendo datos según necesita. El servidor debe mantener datos en memoria.
- O procesar el error
- Lanzar la sentencia
5.1. Todo en memoria del cliente
$resultado = $mysqli->query("SELECT id FROM test ORDER BY id ASC");
$resultado->data_seek(0);
while ($fila = $resultado->fetch_assoc()) {
echo " id = " . $fila['id'] . "\n";
}
5.2. Todo en memoria del cliente, en un array
$resultado = $mysqli->query("SELECT id FROM test ORDER BY id ASC");
$filas = $resultado->fetch_all(MYSQLI_ASSOC);
foreach ($filas as $fila) {
echo " id = " . $fila['id'] . "\n";
}
5.3. Como stream, sin liberar al servidor
$mysqli->real_query("SELECT id FROM test ORDER BY id ASC");
$resultado = $mysqli->use_result();
while ($fila = $resultado->fetch_assoc()) {
echo " id = " . $fila['id'] . "\n";
}
5.4. Control de errores
$result = $conexion->query("select ...");
if($result) {
// HA FUNCIONADO
}
else {
echo "Código de error mysql: $conexion->errno";
echo "Mensaje de error mysql: $conexion->error";
}
try{
$conexion->query( "create ...");
// HA FUNCIONADO
}
catch(Exception $error){
echo "Error SQL con try-catch:" . htmlspecialchars( $error->getMessage() ) . "<br>\n";
echo "Error numérico SQL:" . $conexion->errno . "<br>\n";
foreach( $conexion->error_list as $error_description ){
var_dump($error_description );
}
}
5.5. Ejercicios
- Crea una página donde se listen todos los clientes existentes, en forma de tabla.
- Crea un formulario para insertar un nuevo cliente. Tras insertarse, se mostrarán todos los clientes ya insertados.
6. Sentencias preparadas
- Las sentencias suelen ser cadenas dinámicas
- Los datos a seleccionar/borrar/actualizar dependen de parámetros
- Existe la tentación de construir strings con las sentencias
$id = $_GET["id"];
$mysqli->query("delete from USUARIOS where id='$id'");
¿Qué ocurre si id es
' or '1'='1' --
?
6.1. prepare, bind
https://www.w3schools.com/php/php_mysql_prepared_statements.asp
- Es la única forma segura de pasar cadenas y números a una sentencia SQL
mysqli_real_escape_stringpuede tener problemas
- Pasos:
- Se prepara la sentencia
- Se enlazan los parámetros
- Se ejecuta la query
- En su caso, se recogen resultados
// prepare sql and bind parameters
$stmt = $conn->prepare("
INSERT INTO MyGuests (firstname, lastname, email)
VALUES (?, ?, ?)"
);
$firstname = "John";
$lastname = "Doe";
$email = "john@example.com";
$stmt->bind_param("sss", $firstname, $lastname, $email);
$stmt->execute();
$stmt = $conexion->prepare("select firstname, lastname, email
from MyGuests
where email like ?");
$stmt->bind_param("s",$filtro_email);
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
// Igual que con conexion->query()
...
}
6.2. Tipos de datos
i |
integer |
d |
double, float |
s |
string |
b |
BLOB |
6.3. ¿Y las fechas?
- Como cadenas
date: Formatea a texto un tiempo UNIXtime: Consigue el tiempo UNIX actualstrtotime: Pasa de texto a tiempo UNIX
- Precaución: El timezone
$fecha = date('Y-m-d H:i:s');
echo $fecha . "\n";
$unix_time = time();
echo $unix_time . "\n";
$str = strtotime('2024-12-06 19:14:40');
echo $str . "\n";
6.4. Ejercicios
- Crea un formulario para insertar un nuevo cliente. Tras insertarse, se mostrará el nuevo identificador creado
- Añade un campo
fecha_de_altaal cliente. Inclúyelo en los listados y las inserciones.
7. Transacciones
$mysqli = new mysqli("ejemplo.com", "usuario", "contraseña", "basedatos");
$mysqli->autocommit(false);
$mysqli->query("INSERT INTO test(id) VALUES (1)");
$mysqli->rollback();
$mysqli->query("INSERT INTO test(id) VALUES (2)");
$mysqli->commit();
8. Sobre todo…
No hay que desesperar
9. Referencias
- Formatos:
- Alojado en Github
