# Conexión a BD MySQL (mysqli) MySQLI es un driver de PHP que nos permite realizar conexiones y trabajar con BD de MYSQL. Es mejor usar PDO porque tiene soporte para mas gestores de BD. ## Conexión a la base de datos Para crear una conexión a BD a través de mysqli debemos crear un objeto de la siguiente forma: ```php= <?php /** * $host: Puede ser o un nombre de host o una dirección IP. Pasando el valor null o la cadena "localhost" a este parámetro, se asumirá el host local. Cuando es posible, se usarán tuberías en lugar del protocolo TCP/IP. * $user_name: Nombre de Usuario de MYSQL * $passwd: La contraseña de usuario, si es nula usara los usuarios sin password * $db_name: Nombre de la base de datos */ $db = new mysqli($host, $user_name, $passwd, $db_name) ``` También podemos hacer esto mismo con la función mysql_connect: ```php= <?php $db = mysqli_connect($server, $data_base, $user_name, $password); ``` La configuración por defecto es: ```text= mysqli.default_host=192.168.2.27 mysqli.default_user=root mysqli.default_pw="" mysqli.default_port=3306 mysqli.default_socket=/tmp/mysql.sock ``` La conexión a la BD puede fallar, para controlar los posibles fallos podemos generar una estructura if/else o try/catch (Recomendada) *POO* ```php= <?php // Con if/else $mysqli = new mysqli("localhost", "usuario", "contraseña", "basedatos"); if ($mysqli->connect_errno) { die("Fallo al conectar a MySQL: (" . $mysqli->connect_errno . ") "); } // Con try/catch try { $mysqli2 = new mysqli("127.0.0.1", "usuario", "contraseña", "basedatos"); } catch (Exception $e){ die("Fallo al conectar a MySQL: (" . $e . ") " . $e); } ``` *Funciones* ```php= <?php // Con if/else $mysqli = mysqli_connect("localhost", "usuario", "contraseña", "basedatos"); if (!$mysqli) { die("Fallo al conectar a MySQL: (" . mysqli_connect_error(). ") "); } // Con try/catch try { $mysqli2 = mysqli_connect("127.0.0.1", "usuario", "contraseña", "basedatos"); } catch (Exception $e){ die("Fallo al conectar a MySQL: (" . $e . ") " . $e); } ``` ## Ejecución de Sentencias ### Sentencias No preparadas Para ejecutar cualquier sentencia SQL haremos uso de la función **query** en POO y la función mysqli_query para la ejecución por procedimientos. *Función query POO* ```php= <?php /** * $query: Consulta SQL a Realizar * $resultmode: En base a unas constantes * podemos definir el comportamiento del resultado de la * consulta */ mysqli::query(string $query, int $resultmode = MYSQLI_STORE_RESULT): mixed ``` *Función mysqli_query procedimientos* ```php= <?php /** * $link: Conexión a la BD * $query: Consulta SQL a Realizar * $resultmode: En base a unas constantes * podemos definir el comportamiento del resultado de la * consulta */ mysqli_query(mysqli $link, string $query, int $resultmode = MYSQLI_STORE_RESULT): mixed ``` *Ejemlo query* ```php= <?php // POO $mysqli->query("SELECT * FROM my_table"); // Procedimientos mysqli_query($mysqli, "SELECT * FROM my_table") ``` #### Consultas Múltiples Para ejecutar múltiples consultas podemos usar la función **multy_query()** para POO o la función **mysqli_multi_query()**, pasandole como parámetro una string con las consultas separadas por ";". *Función multi_query POO* ```php= <?php /** * $query: Consulta SQL a Realizar */ mysqli::multi_query(string $query): bool ``` *Función mysqli_multi_query* ```php= <?php /** * $link: Conexión a la BD * $query: Consulta SQL a Realizar */ mysqli_multi_query(mysqli $link, string $query): bool ``` *Ejemplo* ```php= <?php $mysqli = new mysqli("localhost", "sara", "1234", "db_prueba"); // Creamos la primera consulta $insert = "INSERT INTO datos (name, surname, age) VALUES ( 'Jose', 'Hidalgo', 18 );"; // Las vamos concadenando separándolas con un ";" $insert .= "INSERT INTO datos (name, surname, age) VALUES ( 'Luisa', 'Cabrera', 21 );"; $insert .= "INSERT INTO datos (name, surname, age) VALUES ( 'Pablo', 'Jimenez', 19 );"; $insert .= "INSERT INTO datos (name, surname, age) VALUES ( 'Laura', 'Sanchez', 25 );"; // Realizamos la consulta múltiple if (mysqli_multi_query($mysqli, $insert)) { echo "Datos insertados con éxito"; } else { echo "Error: " . $insert . "<br>" . mysqli_error($mysqli); } // Cerramos conexión mysqli_close($mysqli); ?> ``` ### Sentencias Preparadas Una sentencia preparada o una sentencia parametrizada se usa para ejecutar la misma sentencia repetidamente con gran eficiencia. Es la forma más recomendada de ejecutar consultas La ejecución de sentencias preparadas consiste en dos etapas: la preparación y la ejecución. En la etapa de preparación se envía una plantilla de sentencia al servidor de bases de datos. El servidor realiza una comprobación de sintaxis e inicializa los recursos internos del servidor para su uso posterior. El servidor de MySQL soporta el uso de parámetros de sustitución posicionales anónimos con ?. Esto nos sirve para ejecutar sentencias repetidas de una forma más óptima. Esto lo podemos hacer con la función prepare() para POO o la función mysqli_prepare(). *Función prepare POO* ```php= <?php /** * $query: Consulta SQL a Realizar */ mysqli::prepare(string $query): mysqli_stmt ``` *Función mysqli_prepare* ```php= <?php /** * $link: Conexión a la BD * $query: Consulta SQL a Realizar */ mysqli_prepare(mysqli $link, string $query): mysqli_stmt ``` Para ejecutar la sentencia podemos hacer uso de la función execute() para POO o mysqli_stm_execute(). *Función prepare POO* ```php= <?php mysqli_stmt::execute(): bool ``` *Función mysqli_prepare* ```php= <?php /** * $stmt: Sentencia a ejecutar */ mysqli_stmt_execute(mysqli_stmt $stmt): bool ``` *Ejemplo* ```php= <?php $insert = $mysqli->prepare("INSERT INTO my_table (id) VALUES (?)"); for($i=0; $i < 4; $i++) { // Se insertará en cada iteración $insert->execute($i); } /** * Es recomendable y buena práctica * cerrar la conexión con la * Base de Datos al terminar de * ejecutar una sentencia */ $insert->close(); ``` #### Admitir Carácteres UTF-8 ```php= <?php $set_names = $mysqli->prepare("SET NAMES 'utf8'"); $set_names->execute() ``` ## Ver el resultado de una consulta Para ver el resultado de una consulta podemos usar la función fetch del Objeto que devuelve el método prepare(). *Ejemplo* ```php= <?php require_once "./connection.php"; $db = create_connection(); $table = "Task"; try { // $sentence = $db->prepare("INSERT INTO $table(Id, Name, Description) VALUES (?,?,?)"); // $id = 2; // $name = "Prueba 2"; // $description = "Buenas prácticas"; // $sentence->bind_param("iss",$id, $name, $description); // $sentence->execute(); // $sentence->close(); $result = $db->prepare("SELECT * FROM Task"); $result->execute(); /* vincular las variables de resultados */ $result->bind_result($id, $name, $description, $finish); /* obtener los valores */ while ($result->fetch()) { echo "<p>" . sprintf("Id: %d Name: %s Description: %s Finish: %d", $id, $name, $description, $finish) . "</p>"; } $result->close(); } catch (Exception $e) { die("Fallo la ejecución: $e"); } ?> ``` ## Seguridad A la hora de pasar parámetros a una consulta y ejecutarla en las sentencias preparadas poniamos '?', en cada campo dinámico. Podemos asegurarnos de que no nos inyecten parámetros (SQL_INYECTIONS) con la función bind_param() para POO y mysqli_stmt_bind_param() para el método por funciones. *POO* ```php= <?php /** * $types: Tipos de las variables a pasar * Los demás parámetros serán las variables a pasar */ mysqli_stmt::bind_param(string $types, mixed &$var1, mixed &$... = ?): bool ``` *Funciones* ```php= <?php /** * $stmt: Sentencia SQL * $types: Tipos de las variables a pasar * Los demás parámetros serán las variables a pasar */ mysqli_stmt_bind_param( mysqli_stmt $stmt, string $types, mixed &$var1, mixed &$... = ? ): bool ``` Los tipos que debemos pasarle a dichas funciones se mandan como una string, siguiendo el siguiente formato: | Cáracter | Descripción | | -------- | ----------- | | i | Tipo Enteros| | d | Tipo Double | | s | Tipo String | | b | Blob | *Ejemplo* ```php= <?php $stmt = $mysqli->prepare("INSERT INTO tabla (name) VALUES (?)") $stmt->bind_param("s", $name); $name = $values['name']; $stmt->execute(); echo "Se han insertado {$stmt->affected_rows} filas en la base de datos"; ``` ## Cierre de Conexión Siempre es buena práctica cerrar la conexión con la BD una vez hayamos ejecutado una sentencia. Así, se devolverán inmediatamente los recursos a PHP y a MySQL, lo que puede mejorar el rendimiento. Esto podemos hacerlo con la función close() de POO o mysqli_close() si usamos funciones. *Función close POO* ```php= <?php mysqli::close(): bool ``` *Función mysqli_close* ```php= <?php /** * $link: Un identificador de enlace devuelto por mysqli_connect() o mysqli_init() */ mysqli_close(mysqli $link): bool ``` ## Buenas prácticas Es una buena práctica al tratar con nuestras BD crear un recurso especifíco para dicha tabla, para que sea un recurso completo debe implementar los siguientes controladores: - **index**: muestra la lista de todos los recursos. - **create**: muestra un formulario para ingresar un nuevo recurso. (luego manda a llamar al método store). - **store**: registra dentro de la base de datos el nuevo recurso. - **show**: muestra un recurso específico. - **edit**: muestra un formulario para editar un recurso. (luego manda a llamar al método update). - **update**: actualiza el recurso dentro de la base de datos. - **destroy**: elimina un recurso. Esto se podría generar a través de una clase que implemente dichos métodos o un fichero que tenga dichas funciones. *Ejemplo* ```php= <?php class ExampleResource () { public function index() { // some code } public function create() { // some code } public function store() { // some code } public function show() { // some code } public function update() { // some code } public function destroy() { // some code } } ```