elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Como proteger una cartera - billetera de Bitcoin


+  Foro de elhacker.net
|-+  Programación
| |-+  Desarrollo Web
| | |-+  PHP (Moderador: #!drvy)
| | | |-+  API MySQLi
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: API MySQLi  (Leído 2,015 veces)
:ohk<any>


Desconectado Desconectado

Mensajes: 1.744


Yo lo que quiero que me salga bien es la vida.


Ver Perfil WWW
API MySQLi
« en: 12 Noviembre 2013, 21:22 pm »

Buenas foro.

Voy a dar una explicación un tanto superficial pero muy útil sobre el mysqli, voy a dejar una clase de abstracción y algunos ejemplos con los que podrán trabajar en adelante.

Primero lo primero:

Requieres una versión 5.3.6 o superior de PHP.

MySQLi, es el conector para bases de datos MySQL recomendado por PHP, para interactuar desde tu aplicación con una base de datos MySQL.

¿qué es exactamente mysqli y en qué se diferencia de mysql?

Básicamente, como bien se define en el manual oficial de PHP, mysqli es “una extensión mejorada del conector mysql”.

Entre las principales diferencias, se encuentran además, sus dos grandes ventajas:

  • Permite trabajar en estilo orientado a objetos (también continúa proveyendo soporte para estilo procedimental);
  • Nos facilita una forma segura de filtrado de datos en sentencias SQL, para prevenir inyecciones SQL;

Sin dudas, mysqli es una gran ventaja frente al antiguo conector. Tiene una gran cantidad de clases, métodos, constantes y propiedades muy bien documentados.

Propiedades

Nuestra capa de abstracción, tendrá una única propiedad pública, destinada a almacenar los datos obtenidos tras una consulta de selección. El resto de las propiedades, serán de ámbito protegido, accesibles solo desde nuestra clase y clases que hereden de ésta.

Código
  1. class DBConnector {
  2.   protected static $conn; # Objeto conector mysqli
  3.   protected static $stmt; # preparacion de la consulta SQL
  4.   protected static $reflection; # Objeto Reflexivo de mysqli_stmt
  5.   protected static $sql; # Sentencia SQL a ser preparada
  6.   protected static $data; # Array conteniendo los tipo de datos más los datos a ser enlazados.
  7.   public static $results; # Coleccion de datos retornados por una consulta de selección
  8. }
  9.  

La consulta SQL, deberá ser seteada en los modelos (clases) donde se requiera, incluyendo marcadores de parámetros (embebidos con el signo ?), en la posición donde un dato deba ser enlazado. Un ejemplo de ella, podría ser el siguiente:

Código
  1. $sql = "INSERT INTO productos (categoria, nombre, precio)VALUES (?, ?, ?)";


Mientras que el array$data, deberá contener, como primer elemento, una string con el tipo de datos y los elementos siguientes, serán los datos a ser enlazados (todos de tipo string):

Código
  1. $data = array("isbd", "{$categoria}", "{$nombre}", "{$descripcion}", "{$precio}");

El primer elemento, siempre representará el tipo de datos correspondiente al marcador de parámetro que se desea enlazar. Siendo los tipos de datos posibles:
s (string), i (entero), d (doble) y b (blob).

Métodos

Conectar a la base de datos:

Código
  1. protected static function conectar() {
  2.   self::$conn = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
  3. }
  4.  

Requerirá 4 constantes predefinidas (se recomienda definir en un archivosettings): DB_HOST,DB_USER,DB_PASSyDB_NAME.

Archivo setting.php

Código
  1. define("DB_HOST", "localhost");
  2. define("DB_USER", "root");
  3. define("DB_PASS", "password");
  4. define("DB_NAME", "nombre_de_la_base_de_datos");
  5.  

Preparar una sentencia SQL (con marcadores de parámetros):

Código
  1. protected static function preparar() {
  2.   self::$stmt = self::$conn->prepare(self::$sql);
  3.   self::$reflection = new ReflectionClass('mysqli_stmt');
  4. }
  5.  

La clase ReflectionClass de PHP, cumple un papel fundamental: solo a través de ella podemos crear un objeto mysqli_stmtreflexivo, siendo ésta, la única alternativa que tenemos para preparar sentencias SQL con marcadores de parámetros, de forma dinámica.

La propiedad estática $sql (self::$sql) será creada por el único método público que tendrá la clase.

Enlazar los datos con la sentencia SQL preparada:

Código
  1. protected static function set_params() {
  2.   $method = self::$reflection->getMethod('bind_param');
  3.   $method->invokeArgs(self::$stmt, self::$data);
  4. }
  5.  

La propiedad estática $data que se pasa como segundo parámetro a invokeArgs, también será seteada por el único método público.

En este método (set_params), la variable temporal $method, llama reflexivamente (a través del método getMethoddereflectionClass), al método bind_paramde la clase mysqli.

En la siguiente instrucción, a través del método invokeArgsdeReflectionClass, le pasa por referencia a bind param, los datos a ser enlazados con la sentencia preparada (almacenados en el array $data). Podría decirse que invokeArgs, se comporta de forma similar a call_user_func_array().

Enlazar resultados de una consulta de selección:

Código
  1. protected static function get_data($fields) {
  2.   $method = self::$reflection->getMethod('bind_result');
  3.   $method->invokeArgs(self::$stmt, $fields);
  4.   while(self::$stmt->fetch()) {
  5.      self::$results[] = unserialize(serialize($fields));
  6.   }
  7. }
  8.  

Este método es uno de los más “complejos y rebuscados”, que incluso cuenta con algunas “pseudo-magias” un tanto “raras” como el uso de las funciones serialize y unserialize en la la misma instrucción. Pero analicémoslo detenidamente.

El parámetro $fields será recibido a través del único método público que crearemos en nuestra capa de abstracción (este método, a la vez, recibirá este dato, también como parámetro, pero opcional).

Este parámetro, será un array asociativo, donde las claves, serán asociadas al nombre de los campos, y el valor de esas claves, al dato contenido en el campo.

Si tuviese la siguiente consulta SQL:

Código
  1. SELECT nombre, descripcion, precio FROM producto WHERE categoria = ?

Mi array asociativo, podría paracerse al siguiente:

Código
  1. $fields = array("Producto" => "",
  2. "Descripcion" => "",
  3. "Precio" => "");
  4.  

mysqli->bind_result() enlazará el campo producto.nombre a la clave Producto, producto.descripcion a la clave Descripcion y producto.precio a la clave Precio.

Las instrucciones:

Código
  1. $method = self::$reflection->getMethod('bind_result');
  2. $method->invokeArgs(self::$stmt, $fields);

se comportan de forma similar, a sus homónimas en el método set_params. Llama reflexivamente al método bind_result de la clase mysqli y le pasa por referencia, el array $fields.

En el bucle while, estamos asociando iterativamente los datos obtenidos a nuestra propiedad pública$results. Pero ¿cómo lo hacemos? ¿para qué serializar y deserializar los datos?:

Código
  1. while(self::$stmt->fetch()) {
  2.   self::$results[] = unserialize(serialize($fields));
  3. }
  4.  

En cada iteración, stmt->fetch nos está retornando nuestro array $fields, asociado al registro de la tabla, sobre el cuál se está iterando.

Es decir, que en cada iteración, stmt->fetch nos retornará algo como esto:

Código
  1. // contenido del array $fields
  2. array("Producto" => "HD Magazine",
  3.  "Descripción" => "Magazine digital de edición mensual sobre Software Libre, Hacking y Programación",
  4.  "Precio" => "0.00");
  5.  

Pero nuestro array $fields, ha sido pasado por referencia.

Ergo, en cada iteración, su contenido será modificado.

Si a mi propiedad estática $results, le agrego como elemento, un array que está siendo modificado por referencia en el momento que lo estoy asignando a mi propiedad estática, mi propiedad estática, será también, modificada en cada iteración.

Para prevenir eso, serializo mi array$fieldsy lo almaceno en$resultsserializado. Pero como luego necesitará recuperarlo, ahorro un paso y lo deserializo en la misma iteración.

Al serializarlo, estoy “mágicamente” emulando una “inmutabilidad” de los datos asociados.

Cerrar conexiones abiertas:

Código
  1. protected static function finalizar() {
  2.   self::$stmt->close();
  3.   self::$conn->close();
  4. }
  5.  

Un método público que ejecute todas las acciones:


Código
  1. public static function ejecutar($sql, $data, $fields=False) {
  2.   self::$sql = $sql; # setear la propiedad $sql
  3.   self::$data = $data; # setear la propiedad $data
  4.   self::conectar(); # conectar a la base de datos
  5.   self::preparar(); # preparar la consulta SQL
  6.   self::set_params(); # enlazar los datos
  7.   self::$stmt->execute(); # ejecutar la consulta
  8.   if($fields) {
  9.      self::get_data($fields);
  10.   } else {
  11.      if(strpos(self::$sql, strtoupper('INSERT')) === 0) {
  12.         return self::$stmt->insert_id;
  13.      }
  14.   }
  15.   self::finalizar(); # cerrar conexiones abiertas
  16. }
  17.  

La estructura de control de flujo condicional, que utiliza el método ejecutar(), es la encargada de discernir si se trata de una consulta de “lectura” a la base de datos para así, llamar al método get_data, o si se trata de una consulta de “escritura” (INSERT, UPDATE o DELETE). En ese caso, verifica si es una escritura de tipo “INSERT” para retornar la id del nuevo registro creado.

Clase Completa:

Código
  1. <?php
  2. class DBConnector {
  3.  
  4.   protected static $conn; # Objeto conector mysqli
  5.   protected static $stmt; # preparación de la consulta SQL
  6.   protected static $reflection; # Objeto Reflexivo de mysqli_stmt
  7.   protected static $sql; # Sentencia SQL a ser preparada
  8.   protected static $data; # Array conteniendo los tipo de datos más los datos a ser enlazados
  9.   public static $results; # Colección de datos retornados por una consulta de selección
  10.  
  11.   protected static function conectar() {
  12.      self::$conn = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
  13.   }
  14.  
  15.   protected static function preparar() {
  16.      self::$stmt = self::$conn->prepare(self::$sql);
  17.      self::$reflection = new ReflectionClass('mysqli_stmt');
  18.   }
  19.  
  20.   protected static function set_params() {
  21.      $method = self::$reflection->getMethod('bind_param');
  22.      $method->invokeArgs(self::$stmt, self::$data);
  23.   }
  24.  
  25.   protected static function get_data($fields) {
  26.      $method = self::$reflection->getMethod('bind_result');
  27.      $method->invokeArgs(self::$stmt, $fields);
  28.      while(self::$stmt->fetch()) {
  29.         self::$results[] = unserialize(serialize($fields));
  30.      }
  31.   }
  32.  
  33.   protected static function finalizar() {
  34.      self::$stmt->close();
  35.      self::$conn->close();
  36.   }
  37.  
  38.   public static function ejecutar($sql, $data, $fields=False) {
  39.      self::$sql = $sql; # setear la propiedad $sql
  40.      self::$data = $data; # setear la propiedad $data
  41.      self::conectar(); # conectar a la base de datos
  42.      self::preparar(); # preparar la consulta SQL
  43.      self::set_params(); # enlazar los datos
  44.      self::$stmt->execute(); # ejecutar la consulta
  45.      if($fields) {
  46.         self::get_data($fields);
  47.      } else {
  48.         if(strpos(self::$sql, strtoupper('INSERT')) === 0) {
  49.            return self::$stmt->insert_id;
  50.         }
  51.      }
  52.      self::finalizar(); # cerrar conexiones abiertas
  53.   }
  54. }
  55. ?>
  56.  

Realizando un INSERT:

La tabla:

Código
  1. CREATE TABLE IF NOT EXISTS `productos` (
  2.  `id_productos` INT(11) NOT NULL AUTO_INCREMENT,
  3.  `categoria` VARCHAR(50) NOT NULL,
  4.  `nombre` VARCHAR(50) NOT NULL,
  5.  `descripcion` VARCHAR(200) NOT NULL,
  6.  `precio` DECIMAL(10,2) NOT NULL,
  7.  PRIMARY KEY (`id_productos`)
  8. ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
  9.  

El codigo:

Código
  1. <?php
  2.  
  3. require_once("setting.php");
  4. require_once("connector.php");
  5.  
  6. // Estableciendo los parámetros a ingresar
  7.  
  8. $categoria = "Muebles";
  9. $nombre = "Ropero";
  10. $descripcion = "Estante de ropa";
  11. $precio = 1200.50;
  12.  
  13. // Iniciando el Insert
  14.  
  15. $sql = "INSERT INTO productos(categoria, nombre, descripcion, precio)VALUES(?,?,?,?)";
  16.  
  17. // Preparando los datos a insertar
  18.  
  19. $data = array("sssd", "{$categoria}", "{$nombre}", "{$descripcion}", "{$precio}");
  20.  
  21. // Ejecutando la Consulta
  22.  
  23. $insert_id = DBConnector::ejecutar($sql, $data);
  24.  
  25. // Imprimirá el ultimo ID ingresado
  26.  
  27. echo $insert_id;
  28.  
  29. ?>
  30.  

En caso de ser un update:

Código
  1. <?php
  2.  
  3. require_once("setting.php");
  4. require_once("connector.php");
  5.  
  6. // Estableciendo los parámetros a modificar
  7.  
  8. $id = 1;
  9. $nombre = "Ropero 2";
  10.  
  11. // Iniciando el UPDATE
  12.  
  13. $sql = "UPDATE productos SET nombre = ? WHERE id_productos = ?";
  14.  
  15. // Preparando los datos a insertar
  16.  
  17. $data = array("si", "{$nombre}", "{$id}");
  18.  
  19. // Ejecutando la Consulta
  20.  
  21. DBConnector::ejecutar($sql, $data);
  22.  
  23. ?>
  24.  

En caso de ser un DELETE

Código
  1. <?php
  2.  
  3. require_once("setting.php");
  4. require_once("connector.php");
  5.  
  6. // Estableciendo los parámetros a eliminar
  7.  
  8. $id = 1;
  9.  
  10. // Iniciando el DELETE
  11.  
  12. $sql = "DELETE FROM productos WHERE id_productos = ?";
  13.  
  14. // Preparando los datos a insertar
  15.  
  16. $data = array("i", "{$id}");
  17.  
  18. // Ejecutando la Consulta
  19.  
  20. DBConnector::ejecutar($sql, $data);
  21.  
  22. ?>
  23.  

En caso de realizar un SELECT:

Código
  1. <?php
  2.  
  3. require_once("setting.php");
  4. require_once("connector.php");
  5.  
  6. // Parametros de busqueda
  7.  
  8. $categoria = "Muebles";
  9.  
  10. // Iniciando el SQL
  11.  
  12. $sql = "SELECT nombre, descripcion, precio FROM productos WHERE categoria = ?";
  13.  
  14. $data = array("s", "{$categoria}");
  15.  
  16. $fields = array("Producto" => "", "Descripcion" => "", "Precio" => "");
  17.  
  18. // Ejecutando la Consulta
  19.  
  20. $values = DBConnector::ejecutar($sql, $data, $fields);
  21.  
  22. foreach ($fields as $key => $value) {
  23.   echo $value."<br>";
  24. }
  25.  
  26. ?>
  27.  

Espero les sirva.

Saludos cordiales


En línea

Y es que a veces pienso que si no estuviera loco no podría salir adelante.
Lo que no se es capaz de dar, en realidad no se posee, uno es poseído por ello.
Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

Mensajes similares
Asunto Iniciado por Respuestas Vistas Último mensaje
GiE 4.7 - MySQLi « 1 2 »
Nivel Web
Pony-Magic 10 8,428 Último mensaje 6 Abril 2010, 04:24 am
por isseu
mysqli
Desarrollo Web
tecasoft 2 2,263 Último mensaje 24 Noviembre 2012, 20:47 pm
por tecasoft
¿Crear vistas temporales en php+mysqli ?
PHP
Psyke1 0 1,716 Último mensaje 21 Febrero 2013, 22:02 pm
por Psyke1
diferencias entre mysql y mysqli
Bases de Datos
basickdagger 6 7,880 Último mensaje 6 Junio 2013, 04:49 am
por engel lex
Error en PHP+MySqli
PHP
spysecurityca 6 3,010 Último mensaje 7 Mayo 2014, 04:52 am
por spysecurityca
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines