Cualquier dato puede ser almacenado en una cookie, pero es importante saber que lo que almacenamos puede tener un mal uso por terceros, por lo que debemos tomar los recaudos pertinentes.
Una manera de hacer un login automático puede ser guardar el nombre de usuario en una cookie y también la contraseña, cuando el visitante ingresa si las cookies están definidas y tiene contenido podríamos buscar en la base para validar estos datos y loguearlo automáticamente.
Esto sería una manera de hacerlo pero aquí se comprometen los datos del usuario de una manera grosera, la contraseña nunca puede ser guardada en un archivo de texto, cualquier con acceso físico a la computadora podría leer esta información.
Por lo tanto debemos tener en cuenta que es lo que deseamos guardar y tomar determinados recaudos a la hora de guardarlos, en el capítulo de seguridad en aplicaciones web veremos un poco más en detalle que y como guardarlo.
Archive for the ‘Manual de PHP’ Category
Datos sensibles en cookie
Eliminar una cookie
Eliminar una cookie puede hacerse de 2 maneras, la primera es definir una una cookie con el mismo nombre de la que deseamos eliminar sin ningún parámetro extra
<?php setcookie("nombre_cookie"); ?>
Y la segunda es usar setcookie y enviar como parámetro un tiempo de caducidad pasado.
<?php setcookie("nombre_cookie", "", time() - 3600); //Fijate la fecha de caducidad 1 hora atrás ?>
Definir una cookie
La función setcookie define una cookie para ser enviada en las cabeceras HTTP, al ser enviada a través de las cabeceras es obligatorio que nuestro script no genere ninguna salida, esto se debe a que es una restricción del protocolo.
Cualquier carácter que sea impreso, inclusive hasta una espacio, antes de usar setcookie producirá un error
setcookie acepta 7 parámetros, sin embargo, solamente es obligatorio el primero, aquí una lista de los parámetros en el orden correcto de la función.
- name: El nombre de la cookie.
- value: El valor que será guardado en la cookie.
- expire: El tiempo en el que expira la cookie. Es una fecha Unix, por lo que probablemente use la función time() o mktime().
- path: Por defecto utiliza ‘/’, esto significa que la cookie estará disponible para todo el dominio. Por ejemplo sí este parámetro es seteado en ‘/administrador’ la cookie podrá ser utilizada en el directorio administrador y todos sus subdirectorios.
- domain: La cookie estará disponible para el dominio
- secure: Indica si la cookie debe viajar en forma segura en una conexión HTTPS desde el cliente
- httponly: Si este parámetro esta en TRUE la cookie será legible solo por el protocolo HTTP, es decir no será posible acceder por otros lenguajes como ser javascript
<?php setcookie("nombre_cookie", "Este es el valor de mi cookie", time() + 3600); // La cookie expira en 1 hora. ?>
Ahora para recuperar la cookie tenemos $_COOKIE
<?php echo $_COOKIE['nombre_cookie']; ?>
Recordemos que estos procesos se realizan a través de los headers HTTP, entonces si en un mismo script, seteo la cookie, recién ésta estará disponible en el próximo request que se realice sobre el dominio. Es decir, en nuestro primer request la cookie será enviada y se generará el archivo de texto con la información, por ende si necesito usar esta cookie estará disponible en el próximo request.
Introducción a las Cookies
Una cookie es información que se envía a través del servidor web y es almacenada en el disco rígido del visitante por medio del navegador en un archivo de texto.
Cuando haya una nueva petición al mismo dominio las cookies desde nuestro disco rígido serán enviadas al servidor web, por lo tanto, de esta manera nos permitirá recuperar la información guardada en la cookie, entonces de acuerdo a hayamos guardado en las cookies podremos determinar siguientes acciones.
Una manera frecuente de usar una cookie es en los inicios de sesión automáticos, el famoso checkbox que dice “No cerrar sesión” en la mayoría de los portales.
La identificación de la cookie es una combinación de la computadora, navegador y usuario.
Configuración de sesiones
Ahora una explicación de los items más importantes en la configuración de las sesiones en PHP, en la siguiente imagen puede verse la configuración actual del servidor donde estemos corriendo nuestros scripts, con la función info(), nativa de PHP, en la sección Sessions

- session.auto_start en caso de estar encendido iniciará las sesiones automáticamente cuando los visitantes ingresen a nuestro sitio, por defecto esta apagado
- session.cache_expire determina el tiempo de vida de la sesión, éste está expresado en minutos
- session.name especifica el nombre de la sesión que se utiliza como nombre de la cookie. El valor predeterminado es PHPSESSID.
- session.save_path define el argumento que se pasa al controlador de almacenamiento. Esta será la ruta donde se creen los archivos de las sesiones.
- session.use_cookies especifica si el módulo usará cookies para almacenar el identificador de sesión en el cliente. El valor predeterminado es 1 (habilitado).
Trabajar con sesiones
Cómo hemos explicado anteriormente las sesiones nos guardarán información mientras pasemos de una página a la otra.
Las sesiones en PHP trabajan con un array llamando $_SESSION y cada key que generemos serán el contenedor de la información que deseemos guardar.
session_start() creará una nueva sesión o reanudará la sesión que ya fue creada. Esta función envía varias cabeceras HTTP por eso es importante que sea llamada antes de imprimir algún carácter en el navegador.
Nota: La configuración de PHP posee session.auto_start, por defecto en 0, por ende, deshabilitado. Sí es habilitado no se requerirá inicializar las sesiones con session_start()
Veamos un ejemplo, en el que con sesiones contaremos la cantidad de páginas que va visitando el usuario.
<?php //header.php session_start(); if(isset($_SESSION['contador'])){ $_SESSION['contador']++; }else{ $_SESSION['contador'] = 1; } ?> <html> <head> <title>Contador</title> </head> <body> <div id="header"><a href="1.php">1</a> - <a href="2.php">2</a> - <a href="3.php">3</a></div> <div id="contenido">
<?php //footer.php ?> </div><!--fin de div id contenido--> <div id="footer">Usted ha visitado <?=$_SESSION['contador'];?></div> </body> </html>
<?php //1,php require_once 'header.php'; ?> Usted esta en la página 1.php <?php require_once 'footer.php'; ?>
<?php //2.php require_once 'header.php'; ?> Ahora estamos en 2.php <?php require_once 'footer.php'; ?>
<?php //3.php require_once 'header.php'; ?> Esta es la última 3.php <?php require_once 'footer.php'; ?>
Introducción a sesiones
Es habitual trabajar con sesiones en desarrollos PHP. El objetivo de las sesiones es almacenar información a través de los diferentes archivos mientras dure la navegación del usuario. Es decir, el usuario puede estar visitando las diferentes secciones de nuestra aplicación y nosotros podemos guardar determinados datos que creamos convenientes.
Cuando un usuario ingresa a nuestra aplicación una sesión única es generada, ésta será exclusiva de él y durará el tiempo que él este en nuestro sitio. Cualquier información puede ser almacenada en ellas, datos del usuario, páginas que visite o algunas preferencias que seleccione.
PHP posee un conjunto de sencillas funciones para trabajar con las sesiones que veremos a continuación en este capítulo.
Seguridad en aplicaciones Web
Es verdad que un porcentaje muy alto de los usuarios que usen nuestras aplicaciones seguirán los pasos que nosotros pretendemos que hagan.
Luego tendremos un grupo reducido de usuarios que por medio de algún error hagan que la aplicación no se comporte como nosotros deseamos.
Por último tendremos un grupo de usuarios malintencionados que busquen errores en nuestra aplicación con fines varios, pueden buscar robar información, el hecho romper simplemente por maldad, instalar algo en el servidor donde corre nuestra aplicación o cualquier otro fin.
Sin importar que grupo de usuarios está accediendo a nuestra aplicación debemos tener un sistema seguro.
Existen muchos niveles que puede ser blanco de ataque, así que desde el lado que nos compete debemos tomar todos los recaudos para que su funcionamiento sea óptimo y seguro.
Como primera medida es fundamental no creerle al usuario, nosotros pretendemos que el usuario nos envíe un número y él nos termina enviando una cadena de texto, por error, negligencia o mal intención. Para evitarlo validaremos que lo que recibimos es lo que pretendemos recibir.
En el ejemplo anterior lo que se envía por el formulario ingresa directamente en la base de datos, ahora nosotros sabemos que queremos que llegue, entonces haremos un cast, esto significa forzar a que el dato se convierta en el tipo de dato que deseamos.
PHP ofrece estas posibilidades para forzar los tipos de datos.
- (int), (integer) – forzado a integer
- (bool), (boolean) – forzado a boolean
- (float), (double), (real) – forzado a float
- (string) – forzado a string
- (array) – forzado a array
- (object) – forzado a object
- (unset) – forzado a NULL (PHP 5)
Le agregamos algunos campos al formulario para trabajar con más tipos de datos.
<html>
<head>
<title>Registrarse</title>
</head>
<body>
<h1>Registración</h1>
<form method="post" action="registrarse.php">
<table width="400">
<tr>
<td width="150"><label>Nombre:</label></td>
<td width="250"><input type="text" name="nombre" /></td>
</tr>
<tr>
<td><label>Email:</label></td>
<td><input type="text" name="email" /></td>
</tr>
<tr>
<td><label>Edad:</label></td>
<td><input type="text" name="edad" /></td>
</tr>
<tr>
<td><label>Colores:</label></td>
<td>
Rojo - <input type="checkbox" name="colores[]" value="Rojo" /> <br />
Celeste - <input type="checkbox" name="colores[]" value="Celeste" /> <br />
Blanco - <input type="checkbox" name="colores[]" value="Blanco" /> <br />
Negro - <input type="checkbox" name="colores[]" value="Negro" /> <br />
</td>
</tr>
<tr>
<td><label>Contraseña:</label></td>
<td><input type="password" name="contrasena"/></td>
</tr>
<tr>
<td colspan="2" align="right"><input type="submit" name="registrarse" value="Registrarse"/></td>
</tr>
</table>
</form>
</body>
</html>Y aquí el procesamiento de lo que viene por el formulario tomando los recaudos de los que estamos hablando.
<?php $mysqli = new mysqli("localhost", "usuario", "password", "nombre_base"); if (mysqli_connect_errno()) { printf("Imposible conectarse: %s\n", mysqli_connect_error()); exit(); } $query = "INSERT INTO usuarios (nombre,email,edad,colores,contrasena) VALUES (?,?,?,?,?)"; $nombre = (string) $_POST['nombre']; $email = (string) $_POST['email']; $edad = (int) $_POST['edad']; $colores = (array) $_POST['colores']; $contrasena = (string) $_POST['contrasena']; $colores = implode($colores, ","); /* Ejecuto el método prepare y este me va a devolver el objeto */ if ($stmt = $mysqli->prepare($query)) { /* Reemplazo las ? por las variable con bind_param */ $stmt->bind_param('ssiss', $nombre, $email, $edad, $colores, $contrasena); /* ejecuto el query */ $stmt->execute(); /* cierro stmt */ $stmt->close(); } ?> <html> <head> <title>Registrarse</title> </head> <body> <h1><?=$nombre;?>, usted se ha registrado exitosamente</h1> </body> </html>
Entradas de usuarios
Ahora que podemos mezclar el HTML y PHP necesitaremos que el usuario empiece a interactuar en nuestra plataforma.
Una registro de usuarios es un ejemplo de la interacción que estoy hablando, el usuario completará sus datos en un formulario, luego estos serán enviados a un archivo PHP para ser procesados, de esta manera comenzaremos a ver como el usuario nos enviará información, en este caso lo guardaremos en una base de datos, pero es a modo de ejemplo ya que el proceso a realizar es indiferente para nosotros por que cualquiera sea la acción que tomemos no es importante, lo importante aquí es que estaremos recibiendo información a través del formulario para realizar la acción que creamos conveniente.
Los formularios HTML podemos, a grandes rasgos, dividirlos en 4.
- Apertura del formulario con el tag <form>
- Los tags para que el usuario ingrese la información, por ejemplo <input>, <textarea> o <select> entre otros
- El botón para enviar el formulario con el tag <input>
- EL cierre del formulario con el tag </form>
Creamos un formulario que pida al usuario ingresar su nombre completo, su email y una contraseña, estos datos serán enviados a un archivo PHP y será el encargado de guardarlos en una base de datos MySQL
<html>
<head>
<title>Registrarse</title>
</head>
<body>
<h1>Registración</h1>
<form method="post" action="registrarse.php">
<table width="400">
<tr>
<td width="150"><label>Nombre:</label></td>
<td width="250"><input type="text" name="nombre" /></td>
</tr>
<tr>
<td><label>Email:</label></td>
<td><input type="text" name="email" /></td>
</tr>
<tr>
<td><label>Contraseña:</label></td>
<td><input type="password" name="contrasena"/></td>
</tr>
<tr>
<td colspan="2" align="right"><input type="submit" name="registrarse" value="Registrarse"/></td>
</tr>
</table>
</form>
</body>
</html>Como podemos observar muchos de los tags HTML que utilizamos tienen lo que se denominan atributos
El tag <form> posee 2 atributos, el primero es method y éste especificará el método HTTP que usará cuando envíe la información. El segundo es action y especifica donde será enviada la información cuando el formulario sea enviado.
Luego tenemos el tag <input> nuestro primero atributo es type y posee las siguientes variantes button, checkbox, file, hidden, image, password, radio, reset, submit, text, en este ejemplo usamos 3 de éstas, text que será un campo de texto libre, password que también será un campo de texto libre pero no serán mostrados los caracteres que iremos tipeando y por último submit que será un botón que al presionarlo enviará el formulario completo al action del form. También tenemos el atributo name que es un nombre que identificará al elemento y el último atributo usado aquí es value este será el valor predeterminado que tomará el elemento.
Ahora recibamos la información que nos provee el formulario y guardemos ésta en la base de datos.
Creamos un archivo registrarse.php (que es el action del formulario) e insertamos los datos.
La información nos llegará al archivo PHP en un array llamado $_POST los índices del array serán igual a los name que hemos definido en el formulario
<?php $mysqli = new mysqli("localhost", "usuario", "password", "base"); if (mysqli_connect_errno()) { printf("Imposible conectarse: %s\n", mysqli_connect_error()); exit(); } $query = "INSERT INTO usuarios (nombre,email,contrasena) VALUES (?,?,?)"; /* Ejecuto el método prepare y este me va a devolver el objeto */ if ($stmt = $mysqli->prepare($query)) { /* Reemplazo las ? por las variable con bind_param */ $stmt->bind_param('sss', $_POST['nombre'], $_POST['email'], $_POST['contrasena']); /* ejecuto el query */ $stmt->execute(); /* cierro stmt */ $stmt->close(); } ?> <html> <head> <title>Registrarse</title> </head> <body> <h1><?=$_POST['nombre'];?>, usted se ha registrado exitosamente</h1> </body> </html>
Separando la lógica de la vista
Vamos a embeber código de la mejor manera posible, separando 100% la lógica que le queremos dar al sistema de la vista que lo va a mostrar.
La manera es con include o require, básicamente programaremos nuestra lógica en un archivo y este será incluido por nuestra vista.
<?php //logica.php if (date('H') >= 14 && date('H') <= 19) { $mensaje = 'Buenos tardes'; } elseif (date('H') >= 6 && date('H') <= 13) { $mensaje = 'Buenos días'; }else { $mensaje = 'Buenos noches'; } ?>
<?php //index.php include "logica.php"; ?> <html> <head> <title>Saludo</title> </head> <body> <?= $mensaje; ?> <?php //Usar <?php echo $mansaje; ?> es lo mismo que usar <?=$mensaje;?> ?> </body> </html>
Veamos el resultado.
<html>
<head>
<title>Saludo</title>
</head>
<body>
Buenos tardes</body>
</html>Embebiendo código PHP y organizándolo
En el ejemplo anterior podemos observar como embebimos código PHP dentro de una estructura de HTML.
Aquí trabajaremos en un concepto similar pero la diferencia será el orden que le demos a nuestro bloques de código.
Por lo general, lo más recomendable es separar nuestro código PHP y HTML lo más posible, esta separación puede darse en archivos diferentes trabajando con includes o bien separaremos nuestro código en bloques, por un lado la lógica del PHP y por el otro el HTML. Esto hará mucho más legible el sistema en si, tanto como para futuras modificaciones como también para que cuando algún colega desarrollador necesite añadir, modificar o eliminar parte nuestro desarrollo.
<?php if (date('H') >= 14 && date('H') <= 19) { $mensaje = 'Buenos tardes'; } elseif (date('H') >= 6 && date('H') <= 13) { $mensaje = 'Buenos días'; }else { $mensaje = 'Buenos noches'; } ?> <html> <head> <title>Saludo</title> </head> <body> <?php echo $mensaje; ?> </body> </html>
El resultado es el mismo que antes.
<html>
<head>
<title>Saludo</title>
</head>
<body>
Buenos tardes</body>
</html>Embeber código PHP
Naturalmente PHP no puede ser embebido en archivos HTML ya que éstos últimos, en configuraciones predeterminadas, no serán procesados por el interprete de PHP.
Sin embargo, si estamos desarrollando una aplicación web necesitaremos tener código HTML y PHP en un mismo archivo.
Los archivos con extensión .php serán procesados por el interprete, pero este interprete solamente procesará el contenido delimitado dos tags que da comienzo al código php y ?> que finaliza el mismo, lo que este por fuera de éstos tags no será procesado, por ende puede ser tranquilamente código HTML
Un ejemplo
<html>
<head>
<title>Saludo</title>
</head>
<body>
<?php
if (date('H') >= 14 && date('H') <= 19) {
echo 'Buenos tardes';
} elseif (date('H') >= 6 && date('H') <= 13) {
echo 'Buenos días';
}else {
echo 'Buenos noches';
}
?>
</body>
</html>Aquí viene la parte importante, todo lo que es procesado en php y enviado a la salida, en este caso con echo, se transforma en simple texto plano, para este caso el resultado del script será el siguiente.
<html>
<head>
<title>Saludo</title>
</head>
<body>
Buenos tardes</body>
</html>Como puede observarse en el resultado se imprime el “Buenas tardes”, esto se produce por que la hora en la que se ejecuto el script fue cerca de las 15, por lo tanto en condicional entro en las condiciones de mayor e igual a 14 y menor e igual a 19.
Al fin y al cabo lo importante no es por que parte de if sigue el flujo del sistema, en este punto lo más importante de comprender es que la salida es texto plano, que luego será nuestra salida será interpretada por el navegador con el que estemos visualizando la página web.
Introducción al desarrollo de aplicaciones web
La mayoría de las páginas web está hecha en PHP por lo tanto en este capítulo veremos la interacción que existe entre el HTML y PHP.
Aquí una lista global de lo que estaremos realizando a continuación
- Embeber código PHP en archivos HTML
- Mostrar contenido dinámico
- Recoger información de formularios
- Seguridad sobre la información recibida
- Datos persistentes a través de Cookies y Sessions
- Organizar una aplicación Web
Patrón Proxy
El patrón Proxy en PHP es sencillo de entender, es utilizado como intermediario para acceder a un objeto llamado SujetoReal.
Básicamente, tenemos un objeto Proxy que actúa como un sustituto de un objeto SujetoReal. Se realiza una solicitud al Proxy y éste es el encargado de transmitirla a SujetoReal
El objeto Proxy posee una referencia al objeto SujetoReal y controla el acceso a sus métodos y propiedades, introduciendo las funcionalidades que cree necesarias.
Posibles tipos de Proxies
- Proxy Remoto: Cuando el objeto proxy está en una dirección y el objeto real está en otra. En este caso proxy puede funcionar como corta fuegos (firewall). Es muy común ver este esquema con los juegos en línea donde se necesita el mismo objeto en diferentes lugares al mismo tiempo.
- Proxy Virtual: Puede almacenar en caché información, de modo que el acceso al objeto real puede ser postergada
- Proxy de protección: Mantiene la protección de la solicitud al objeto real hasta que la solicitud es verificada por el servidor proxy de protección
Veamos un ejemplo sencillo
<?php abstract class ISujeto{ abstract protected function request(); } class Proxy extends ISujeto{ private $SujetoReal; public function request(){ echo "agregando funciona al inicio <br />"; $this->SujetoReal = new SujetoReal(); $this->SujetoReal->request(); echo "agregando funciona al final <br />"; } } class SujetoReal extends ISujeto{ protected function request(){ echo "Ejecutando request en " . get_class() . "<br />"; } } //implementacion class Usuarios{ private $proxy; public function __construct(){ $this->proxy = new Proxy(); } public function hacerX(){ $this->proxy->request(); } } $objeto = new Usuarios; $objeto->hacerX(); ?>
Resultado
agregando funciona al inicio Ejecutando request en SujetoReal agregando funciona al final
Como podemos ver, agregamos un mensaje al inicio y uno al final de la llamada al SujetoReal.
Esto es una introducción al patrón Proxy y el ejemplo intenta demostrar fácilmente una estructura del patrón y una implementación. En proyectos grandes es un común ver este tipo de esquemas.
Patrón Modelo Vista Controlador
MVC son las siglas del patrón de arquitectura Modelo Vista Controlador (model view controller en inglés) que se encarga de separar los datos en una aplicación.
Podemos ver fácilmente MVC en el diseño de una página web. Por un lado tenemos el resultado final, el HTML, en esta caso la vista, por otro lado tenemos un montón de información guardada en nuestra base de datos, toda la interacción con ella será procesada por el modelo y la toma de decisiones, por ejemplo mostrar distintos contenidos para diferentes niveles de usuarios, estará a cargo del controlador
- Modelo: El modelo se encarga del acceso a la información, independientemente de donde y como este guardada, éste será el encargado de retornar, en un formato especifico, la información que estén solicitando. Los datos o información en principio no tendrían importancia para nuestro controlador y vista, el modelo extraerá lo necesario ya sea de un archivo de texto, una base de datos, un xml o de algún otro medio
- Vista: La vista tiene como objetivo visualizar todo lo previamente procesado. Suponiendo que estamos desarrollando el juego del ta-te-ti, por lo general un jugador juega con la “X” y el otro con la “O”, nuestra vista puede mostrar esto o “X” e “Y” o “W” y “Z” para cada jugador, también cada jugador podría tener una imagen asignada. Estos cambios serán fácil implementando MVC ya que la lógica del juego estará en otras capas de la aplicación
- Controlador: El controlador será el encargado de tomar decisiones. Cualquier tipo de camino que se siga el flujo del sistema será por que el controlador desviará éste flujo según la decisión que tome. Continuando con el ta-te-ti el controlador dará turno al siguiente jugador o dirá cuando el juego esta terminado
Bueno, empecemos con el ejemplo en código.
Aquí mostraré 4 archivos, la versión completa pueden descargarla aquí
Aquí el index.php, básicamente este se encarga de juntar todas las partes, recibe dos parámetro por GET, uno es el controlador y el otro la acción (el método) que debe ejecutar.
Luego de algunas validaciones simples instancia el controlador y ejecuta la acción.
<?php //index.php define('CARPETACONTROLADORES', "controladores/"); define('CARPETAMODELOS', "modelos/"); define('CARPETAVISTAS', "vistas/"); if(!empty($_GET['controlador'])){ $controlador = $_GET['controlador']; $file = CARPETACONTROLADORES . $controlador . ".php"; if(is_file($file)){ require_once $file; $objecto = new $controlador; } else{ die('El controlador no existe'); } }else{ die('No ha definido un controlador'); } if(!empty($_GET['accion'])){ $accion = $_GET['accion']; if(!method_exists($controlador, $accion)){ die('El metodo '.$accion.' no existe en el controlador ' . $controlador); } }else{ die('No ha definido una accion'); } $objecto->$accion(); ?>
Controlador
<?php //usuarios.php require_once CARPETACONTROLADORES . "controlador.php"; class usuarios extends controlador { function __construct(){ require_once CARPETAMODELOS . "modeloUsuarios.php"; $this->modelo = new modeloUsuarios; } function listar(){ $usuarios = $this->modelo->listar(); require_once CARPETAVISTAS . "usuariosListar.php"; } } ?>
Modelo
<?php //modeloUsuarios.php require_once CARPETAMODELOS . "modelo.php"; class modeloUsuarios extends modelo{ function __construct(){ parent::__construct(); } function listar(){ $query = "SELECT nombre, apellido FROM usuarios"; $result = $this->mysqli->query($query); return $result; } } ?>
Por sí no vieron el link más arriba ![]()
Descarguen el ejemplo funcionando desde aquí
Patrón de estrategia
Cuando tenemos un algoritmo que por algún motivo puede llegar a cambiar en tiempo de ejecución o bien su implementación podemos trabajar con el patrón de estrategia para que éste decida que camino tomar.
Básicamente consiste en definir una interfase con los métodos del algoritmo para luego plantear cada uno de éstos en las clases que implementen la interfase.
Cada algoritmo estará encapsulado y será intercambiable independientemente de los clientes que lo utilicen.
Veamos el siguiente ejemplo, tenemos un array con el nombre de un producto y el precio. Para algunos clientes es conveniente mostrarlos en orden alfabética y en otros en orden ascendente de precio.
<?php interface estrategia{ public function ordenar($productos); } class OrdenarPorNombre implements estrategia{ public function ordenar($productos){ ksort($productos); return $productos; } } class OrdenarPorPrecio implements estrategia{ public function ordenar($productos){ asort($productos); return $productos; } } class usuarios { private $productos; public function getProductos(){ return $this->productos; } public function setProductos($productos){ $this->productos = $productos; } public function mostrar($estrategia){ print_r($estrategia->ordenar($this->getProductos())); } } $productos = array('Remera'=>20, 'Campera'=>50, 'Patalon'=>35, 'Gorro'=>10); $u = new usuarios; $u->setProductos($productos); $u->mostrar(new OrdenarPorNombre); $u->mostrar(new OrdenarPorPrecio); ?>
Resultado
Array
(
[Campera] => 50
[Gorro] => 10
[Patalon] => 35
[Remera] => 20
)
Array
(
[Gorro] => 10
[Remera] => 20
[Patalon] => 35
[Campera] => 50
)Patrón Observador
El patrón observador es sencillo de entender y más fácil de ver cuando es necesario.
Tendremos 2 objetos, por un lado el observador y por el otro el observado.
El observador debe ver cuando el observado realiza algún cambio y tomar determinada acción.
El modelos antiguos el observador miraba constantemente al observado para ver cuando éste cambiada, el problema de éste modelo es que había que mirar constantemente al observado para ver cuando realizaba una modificación.
Con el patrón observador cambiaron un poco los roles, tenemos el mismo esquema, observador y observado, la diferente es que observador no estará “mirando” todo el tiempo a observado para ver cuando hay un cambio, sino que éste último le avisará mediante una notificación a su observador cuando haga efectivo dicho cambio.
En un ejemplo de la vida cotidiana:
- Un padre ve como su niño anda en bicicleta, él esta ateto el 100% del tiempo mirando que no se golpee, sí un accidente ocurriese el padre se enteraría al instante ya que ve lo que sucedió. Aquí vemos como el observador está monitoreando constantemente al observado.
- Un niño esta andando en bicicleta y al tener un incidente éste avisa a su padre. Aquí vemos como el observado notifica a su observador en determinado evento.
Vamos a los papeles, aquí el código
Separaremos las clases de la implementación, estará en 2 archivos, modelo.php e implementacion.php
<?php //modelo.php abstract class observable{ protected $observadores; public function __construct(){ $this->observadores = array(); } public function registrarObservador($observador){ if(!in_array($observador, $this->observadores)){ array_push($this->observadores, $observador); } } public function eliminarObservador($observador){ if(in_array($observador, $this->observadores)){ $key = array_search($observador, $this->observadores); unset($this->observadores[$key]); } } abstract public function notificarObservador(); } interface observador{ public function notificar($remitente, $parametro); } class Usuario extends observable{ public $parametro; public function __construct(){ parent::__construct(); } public function notificarObservador(){ if(count($this->observadores) > 0){ foreach ($this->observadores as $observador){ $observador->notificar($this, $this->parametro); } }else{ echo "No hay observadores<br />"; } } public function setParametro($value){ $this->parametro = $value; $this->notificarObservador(); } public function getParametro(){ return $this->parametro; } } class Log implements Observador{ public function notificar($remitente, $parametro){ echo "El objeto " . get_class($remitente) . " ha cambiado la propiedad `parametro` al valor de '$parametro' a las " . date('H:i:s', time()) . "<br />"; } } class LogDB implements Observador{ public function notificar($remitente, $parametro){ echo "El objeto " . get_class($remitente) . " ha guardado la propiedad `parametro` por valor de '$parametro' en la base de datos<br />"; } } class LogEmail implements Observador{ public function notificar($remitente, $parametro){ echo get_class($remitente) . " notifica un cambio y ha sido enviado por mail<br />"; } } ?>
Vamos a dividir la explicación de modelo.php en 4
- Definimos una clase abstracta observable, todas las clases que extiendan de ésta podrán ser observadas, también podrán registrar y eliminar observadores y deberán implementar la notificación
- Definimos una interfaz observador, todos los observadores implementarán ésta interfaz y estarán obligadas a poseer el método notificar, sí bien éste paso podría pasarse por alto es una muy buen practica
- Definimos la clase que va a ser observada, en este ejemplo usamos una clase llamada Usuario y ésta notificará a sus observadores cuando la propiedad método haya cambiado su valor
- Por último definimos los observadores que implementan la interfaz y todos poseen el método notificar, aquí definimos 3 observadores, un muestra un mensaje, otro guarda en base de datos y el último da un aviso por mail
Aquí la implementación, veremos diferentes maneras en las implementaciones.
Implementación 1:
<?php //implementacion1.php $ob = new Usuario; $ob->setParametro('Daniel'); echo "Parametro: " . $ob->getParametro() . "<br />"; ?>
<!--resultado--> No hay observadores Parametro: Daniel
Implementación 2:
<?php //implementacion2.php $ob = new Usuario; $ob->registrarObservador(new Log); $ob->setParametro('Marcos'); echo "Parametro: " . $ob->getParametro() . "<br />"; ?>
<!--resultado--> El objeto Usuario ha cambiado la propiedad `parametro` al valor de 'Marcos' a las 18:40:46 Parametro: Marcos
Implementación 3:
<?php //implementacion3.php $ob = new Usuario; $ob->registrarObservador(new Log); $ob->registrarObservador(new LogDB); $ob->registrarObservador(new LogEmail); $ob->setParametro('Federico'); echo "Parametro: " . $ob->getParametro() . "<br />"; ?>
<!--resultado--> El objeto Usuario ha cambiado la propiedad `parametro` al valor de 'Federico' a las 18:42:08 El objeto Usuario ha guardado la propiedad `parametro` por valor de 'Federico' en la base de datos Usuario notifica un cambio y ha sido enviado por mail Parametro: Federico
Implementación 4:
<?php //implementacion4.php $ob = new Usuario; $ob->registrarObservador(new Log); $ob->registrarObservador(new LogDB); $ob->registrarObservador(new LogEmail); $ob->setParametro('Hugo'); echo "Parametro: " . $ob->getParametro() . "<br />"; sleep(2); $ob->eliminarObservador(new LogDB); $ob->setParametro('Diego'); echo "Parametro: " . $ob->getParametro() . "<br />"; ?>
<!--resultado--> El objeto Usuario ha cambiado la propiedad `parametro` al valor de 'Hugo' a las 18:43:45 El objeto Usuario ha guardado la propiedad `parametro` por valor de 'Hugo' en la base de datos Usuario notifica un cambio y ha sido enviado por mail Parametro: Hugo El objeto Usuario ha cambiado la propiedad `parametro` al valor de 'Diego' a las 18:43:47 Usuario notifica un cambio y ha sido enviado por mail Parametro: Diego
Patrón de diseño Singleton
El patrón de diseño Singleton tiene como finalidad asegurar que sólo se pueda crear una instancia de determinada clase.
Es muy común ver este patrón aplicado en las conexiones a la base de datos, no es necesario tener 10, 20 o 30 conexiones abiertas a la misma base de datos, con una es más que suficiente. Entonces cuando tenemos un proyecto en el cual varias clases harán uso de la base de datos las instancias las haremos con Singleton y esto nos asegurará tener 1 sola instancia del objeto lo cual reducirá ampliamente los consumos de memoria.
La lógica del patrón es simple, sí el objeto nunca fue creado éste es instanciado y devuelto pero sí previamente había sido instanciado el patrón devolverá objeto.
Veamos un ejemplo de un contador, noten como en la implementación se crean varias instancias del mismo objeto pero la propiedad que lleva la cuenta siempre conserva el mismo valor, naturalmente esto se debe a que el objeto siempre es el mismo.
<?php class Singleton { private static $instancia; private $contador; protected $cantidad; private function __construct(){ echo "Primera Instancia de " . __CLASS__ . " ha sido creada\n<br/>"; $this->contador = 0; $this->setCantidad(10); } public static function getInstance() { if ( !self::$instancia instanceof self) { self::$instancia = new self; } return self::$instancia; } public function getCantidad(){ return $this->cantidad; } public function setCantidad($value){ $this->cantidad = intval($value); } public function incrementar(){ return $this->contador+= $this->getCantidad(); } public function disminuir() { return $this->contador-= $this->getCantidad(); } } ?> <?php $primeraInstancia = Singleton::getInstance(); echo "Primera Instancia (+): " . $primeraInstancia->incrementar() . "\n<br/>"; echo "Primera Instancia (+): " .$primeraInstancia->incrementar() . "\n<br/>"; echo "Primera Instancia (+): " .$primeraInstancia->incrementar() . "\n<br/>"; $segundaInstancia = Singleton::getInstance(); echo "Segunda Instancia (-): " .$segundaInstancia->disminuir() . "\n<br/>"; echo "Segunda Instancia (+): " .$segundaInstancia->incrementar() . "\n<br/>"; $terceraInstancia = Singleton::getInstance(); echo "Tercera Instancia (-): " .$terceraInstancia->disminuir() . "\n<br/>"; ?>
Resultado
Primera Instancia de Singleton ha sido creada Primera Instancia (+): 10 Primera Instancia (+): 20 Primera Instancia (+): 30 Segunda Instancia (-): 20 Segunda Instancia (+): 30 Tercera Instancia (-): 20
Ahora para estar bien seguros de tener una sola instancia, debemos prevenir que el objeto sea clonado y también que sea serializado y deserializado.
Para evitar la clonación agregaremos el método __clone a nuestra clase y para la serialización el método __wakeup
Nuestra clase quedará de la siguiente manera
<?php class Singleton { private static $instancia; private $contador; protected $cantidad; private function __construct(){ echo "Primera Instancia de " . __CLASS__ . " ha sido creada\n<br/>"; $this->contador = 0; $this->setCantidad(10); } public static function getInstance() { if ( !self::$instancia instanceof self) { self::$instancia = new self; } return self::$instancia; } public function getCantidad(){ return $this->cantidad; } public function setCantidad($value){ $this->cantidad = intval($value); } public function incrementar(){ return $this->contador+= $this->getCantidad(); } public function disminuir() { return $this->contador-= $this->getCantidad(); } public function __clone(){ trigger_error("Operación Invalida: No es posible clonar una instancia de ". get_class($this) ." class.", E_USER_ERROR ); } public function __wakeup(){ trigger_error("Operación Invalida: No es posible deserializar una instancia de ". get_class($this) ." class.", E_USER_ERROR ); } } ?>
Ahora sí tenemos asegurado que la clase Singleton solo estará instanciada 1 vez.
Patrón de diseño Factory
El patrón de diseño factory, está basado en la instancia de objetos en tiempo de ejecución.
En pequeños proyectos no es frecuente usar éste patrón pero cuando los proyectos son grandes o trabajen muchas personas es muy común implementarlo.
Wikipedia posee una explicación perfecta
Factory Method consiste en utilizar una clase constructora (al estilo del Abstract Factory) abstracta con unos cuantos métodos definidos y otro(s) abstracto(s): el dedicado a la construcción de objetos de un subtipo de un tipo determinado. Es una simplificación del Abstract Factory, en la que la clase abstracta tiene métodos concretos que usan algunos de los abstractos; según usemos una u otra hija de esta clase abstracta, tendremos uno u otro comportamiento.
He aquí un ejemplo con varias clases para conectarse a diferentes base de datos, sin importar donde desee conectarme concentraré la instancia en una clase llamada BaseDeDatos
<?php class MySQL{ public function __construct(){ echo "Instancio MySQL"; } } class PostgreSQL{ public function __construct(){ echo "Instancio PostgreSQL"; } } abstract class BaseDeDatos{ public static function cargar($tipo){ try { if (class_exists($tipo)) { return new $tipo; } else { throw new Exception("No existe la clase '$tipo'"); } } catch (Exception $e) { echo 'Excepción capturada: ', $e->getMessage(), "\n"; } } } BaseDeDatos::cargar("MySQL"); echo "<br >"; BaseDeDatos::cargar("PostgreSQL"); echo "<br >"; BaseDeDatos::cargar("Oracle"); ?>
Resultado
Instancio MySQL Instancio PostgreSQL Excepción capturada: No existe la clase 'Oracle'
Como resumen podemos decir que todo queda centralizado en la clase BaseDeDatos, y como puede observarse realiza una pequeña validación antes de realizar la instancia.
Introducción a patrones de diseño en PHP
Me resulto un tanto difícil comenzar la introducción para éste capítulo, simplificar la explicación de los patrones de diseño no fue tarea sencilla, la pregunta obligada es:
¿Qué son los patrones de diseño?
Para esto busqué algunos conceptos que me guíen en la explicación y me tope en muchos lugares con la siguiente definición.
“Los patrones de diseño son el esqueleto de las soluciones a problemas comunes en el desarrollo de software”
Explicado con mis palabras, éstos ofrecen soluciones simples a problemas comunes en el desarrollo de software.
Con la gran cantidad de diseños de aplicaciones hay problemas que se repiten frecuentemente, entonces éstos responden a un cierto patrón.
Los patrones de diseño son un conjunto de buenas prácticas que pueden nos aliviarán el trabajo en muchas situaciones cuando realizamos una aplicación orientada a objetos
Sí vemos la introducción de éste capítulo como un problema y la frase que hallé como una solución ya probada podríamos decir que encontré un patrón de diseño para mi problema, a grandes rasgos éste es el concepto.
Seguridad en los parámetros
La seguridad en los parámetros es un concepto muy viejo pero es muy efectivo.
Los ataques SQL Injection son más comunes de lo que uno piensa, por ende las cadenas de texto (SQL) que enviamos al motor de la base de datos deben, como mínimo, prevenir este tipo de ataques.
La forma más común en estos ataques es cuando ingresamos valores externos a nuestro código a la base de datos, es decir un parámetro que venga por POST o GET.
Sí enviamos el siguiente query a la base
<?php $query = "SELECT * FROM personas WHERE id = 5"; //envio el query ?>
no existe tal SQL Injection por que id = 5 será siempre id = 5 ya que esta embebido en nuestro código.
Un ejemplo diferente con una vulnerabilidad visible es el siguiente.
<?php $query = "SELECT * FROM personas WHERE id = " . $_GET['id']; //envio el query ?>
en este caso debemos prevenir que $_GET['id'] no contenga ningún código malicioso.
Cuando trabajamos con bases de datos Oracle tenemos a nuestro disposición la función oci_bind_by_name que realizará un blindaje sobre los parámetros, un metodología similar a stmt de mysqli.
<?php $conn = oci_connect("usuario", "contraseña", "localhost/XE"); if (!$conn) { $m = oci_error(); trigger_error(htmlentities($m['message']), E_USER_ERROR); } $sql = 'SELECT id,nombre,apellido FROM personas WHERE id = :id'; $stid = oci_parse($conn, $sql); $id = $_GET['id']; oci_bind_by_name($stid, ':id', $id); oci_execute($stid); $fila = oci_fetch_array($stid, OCI_ASSOC); print_r($fila); oci_free_statement($stid); oci_close($conn); ?>
Recuperar el contenido desde Oracle
oci_fetch_array es la función que usaremos para transformar la fila de base de datos en array para tenerlo disponible y poder imprimirlo o procesarlo donde querramos
<?php $conn = oci_connect('usuario', 'contraseña', 'localhost/XE'); if (!$conn) { $e = oci_error(); trigger_error(htmlentities($e['message'], ENT_QUOTES), E_USER_ERROR); } $stid = oci_parse($conn, 'SELECT id, nombre FROM personas'); oci_execute($stid); while (($row = oci_fetch_array($stid, OCI_BOTH))) { // El array asociativo poseerá los índices en mayúsculas echo $row['ID'] . " - " . $row['NOMBRE'] . "\n<br/>"; } oci_free_statement($stid); //libero la memoria oci_close($conn); //cierro la conexión ?>
ABM desde PHP a Oracle
Como en otras secciones del libro, mysql, sqlite y Microsoft SQL Server, para realizar un ABM necesitamos tener el código SQL correcto para enviarlo a la base de datos a través de una función que nos provee PHP, la función especifica para Oracle es oci_execute, pero para ejecutarla primero debemos preparar la cadena de texto SQL con oci_parse
<?php //alta.php $conn = oci_connect('usuario', 'contraseña', 'localhost/XE'); $query = "INSERT INTO mitabla (columna) VALUES ('valor')"; $stid = oci_parse($conn, $query); oci_execute($stid); // La fila es comiteada y quedará disponible para todos los usuarios ?>
<?php //baja.php $conn = oci_connect('usuario', 'contraseña', 'localhost/XE'); $query = "DELETE FROM mitabla id = 10"; $stid = oci_parse($conn, $query); oci_execute($stid); // La fila es comiteada y quedará disponible para todos los usuarios ?>
<?php //modificacion.php $conn = oci_connect('usuario', 'contraseña', 'localhost/XE'); $query = "UPDATE mitabla set columna='otro valor' WHERE id = 5"; $stid = oci_parse($conn, $query); oci_execute($stid); // La fila es comiteada y quedará disponible para todos los usuarios ?>
Conectar a Oracle desde PHP
PHP nos ofrece 2 posibilidad para conectarnos a Oracle
php_oracle
Es una librería un tanto antigua pero es una muy buena opción sí no deseamos trabajar con datos tipo BLOB o CLOB.
php_oci8
Librería que permite conectarse a Oracle Database desde la versión 8.0 y posteriores. Posee muchas más funciones y funciona con BLOB y CLOB.
Usaremos oci8 a lo largo de esta sección, para conectarnos lo haremos con la función oci_connect
<?php // Conectandose al servicio "XE" sobre la dirección "localhost" $conn = oci_connect('usuario', 'contraseña', 'localhost/XE'); if (!$conn) { $e = oci_error(); trigger_error(htmlentities($e['message'], ENT_QUOTES), E_USER_ERROR); } echo 'Conectado'; ?>
Introducción a Oracle desde PHP
OCI8 nos brinda una serie de funciones para trabajar con bases de datos Oracle 11g, 10g, 9i y 8i. Soportan sentencias SQL y PL/SQL. Incluyen transacciones, marcadores de posición oracle, LOB, colecciones, escalabilidad de la base de datos Oracle, agrupamiento de conexiones residentes o Resident Connection Pooling (DRCP) y el almacenamiento en cache de resultados
La página oficial de Oracle posee un manual de PHP y Oracle
Link directo al manual
Recuperar el contenido en MS SQL Server
PHP nos ofrece varias posibilidades para recuperar la información guardada en la base de datos MS SQL Server.
Veremos 2 funciones, mssql_fetch_array que nos recuperará el contenido de una fila como un array con índices numéricos y también mssql_fetch_assoc que nos traerá el contenido en forma de array con los índices de texto iguales a los nombres de los campos en la base de datos.
<?php //fetch_array $server = 'MISERVER\SQLEXPRESS'; // Conectando a MSSQL $link = mssql_connect($server, 'sa', 'password'); if (!$link) { die('Ha ocurrido un error mientras intentaba conectarse a MSSQL'); } $query = mssql_query('SELECT [usuario], [email] FROM [php].[dbo].[usuarios]'); while ($row = mssql_fetch_array($query, MSSQL_NUM)) { echo "Usuario: " . $row[0] . " - Email: " . $row[1] . "<br />"; } ?>
<?php //fetch_assoc $server = 'MISERVER\SQLEXPRESS'; // Conectando a MSSQL $link = mssql_connect($server, 'sa', 'password'); if (!$link) { die('Ha ocurrido un error mientras intentaba conectarse a MSSQL'); } $query = mssql_query('SELECT [usuario], [email] FROM [php].[dbo].[usuarios]'); while ($row = mssql_fetch_assoc($query)) { echo "Usuario: " . $row['usuario'] . " - Email: " . $row['email'] . "<br />"; } ?>
ABM en MS SQL Server
Tenemos la función mssql_query para ejecutar los querys, con la cadena de texto con sintaxis correcta de SQL procederemos a ejecutarlos en el motor de base de datos.
Código SQL
// Insertar INSERT INTO clientes (razon_social, direccion) VALUES ('Pepsico', 'Florida 55202'); // Actualizar UPDATE clientes SET razon_social = 'Pepsico Snack' WHERE id = 15; // Eliminar DELETE FROM clientes WHERE id = 15
Código para insertarlo en el motor MS SQL Server
<?php //actualizar.php $server = 'MISERVER\SQLEXPRESS'; // Conectando a MSSQL $link = mssql_connect($server, 'sa', 'password'); if (!$link) { die('Ha ocurrido un error mientras intentaba conectarse a MSSQL'); } $sql = "INSERT INTO clientes (razon_social, direccion) VALUES ('Pepsico', 'Florida 55202')"; mssql_query($sql); ?>
<?php //insertar.php $server = 'MISERVER\SQLEXPRESS'; // Conectando a MSSQL $link = mssql_connect($server, 'sa', 'password'); if (!$link) { die('Ha ocurrido un error mientras intentaba conectarse a MSSQL'); } $sql = "UPDATE clientes set razon_social = 'Pepsico Snack' WHERE id = 15"; mssql_query($sql); ?>
<?php //eliminar.php $server = 'MISERVER\SQLEXPRESS'; // Conectando a MSSQL $link = mssql_connect($server, 'sa', 'password'); if (!$link) { die('Ha ocurrido un error mientras intentaba conectarse a MSSQL'); } $sql = "DELETE FROM clientes WHERE id = 15"; mssql_query($sql); ?>
Conexión a MS SQL Server
Para conectarnos a una base de datos Microsoft SQL Server PHP nos proporciona la función mssql_connect
Posee 4 parámetros, servidor, usuario, contraseña y nuevo link (devuelve un nuevo identificador), usualmente los 3 primeros son los más usados.
<?php $server = 'MISERVER\SQLEXPRESS'; // Conectando a MSSQL $link = mssql_connect($server, 'sa', 'password'); if (!$link) { die('Ha ocurrido un error mientras intentaba conectarse a MSSQL'); } ?>
Introducción
PHP brinda soporte para base de datos Microsoft SQL Server pero sobre la plataforma de Windows a partir de la versión 5.3 dejo de brindarle soporte.
Un driver alternativo para MS SQL está disponible para Microsoft: http://msdn.microsoft.com/en-us/sqlserver/ff657782.aspx
La lista de funciones disponibles son las siguientes
- mssql_bind: Agrega un parámetro a un procedimiento almacenado o a un procedimiento almacenado remoto
- mssql_close: Cierra una conexión MS SQL Server
- mssql_connect: Abre una conexión MS SQL Server
- mssql_data_seek: Mueve el puntero a la fila deseada
- mssql_execute: Ejecuta un procedimiento almacenado sobre una base de datos MS SQL Server
- mssql_fetch_array: Devuelve una fila del resultado como matriz asociativa, numérica o ambas
- mssql_fetch_assoc: Devuelve una fila del resultado como matriz asociativa, con índices de texto
- mssql_fetch_batch: Devuelve el siguiente lote de registros
- mssql_fetch_field: Obtiene información del campo
- mssql_fetch_object: Devuelve la fila como objeto
- mssql_fetch_row: Obtiene registros como un array enumerado
- mssql_field_length: Obtener la longitud de un campo
- mssql_field_name: Obtener el nombre de un campo
- mssql_field_seek: Mueve el puntero a un campo especifico
- mssql_field_type: Obtiene el tipo de un campo
- mssql_free_result: Libera el resultado de la memoria
- mssql_free_statement: Libera la declaración de la memoria
- mssql_get_last_message: Devuelve el último mensaje proveniente del Server
- mssql_guid_string: Convierte un binario de 16 byte a un texto
- mssql_init: Inicializa un procedimiento almacenado o un procedimiento almacenado remoto
- mssql_min_error_severity: Establece la gravedad del error mínimo
- mssql_min_message_severity: Establece la gravedad del mensaje mínimo
- mssql_next_result: Mueve el puntero al siguiente resultado
- mssql_num_fields: Gets the number of fields in result
- mssql_num_rows: Obtiene el número de filas en el resultado
- mssql_pconnect: Abre una conexión persistente/li>
- mssql_query: Envía un query a la base MS SQL Server
- mssql_result: Obtiene el resultado
- mssql_rows_affected: Retorno el número de registros afectados por el query
- mssql_select_db: Selecciona una base de datos MS SQL Server
Transacciones en Sqlite
Una transacción es una secuencia de operaciones realizadas como una sola unidad lógica, ésta debe exponer 4 propiedades.
- Atomicidad: Asegura que la operación se ha realizado o no.
- Consistencia: Asegura que sólo empieza todo lo que se puede acabar.
- Aislamiento: Asegura que una operación no puede afectar a otras. Es decir, la realización de dos o más transacciones sobre la misma información sean independientes y no esto no producirá ningún tipo de error.
- Durabilidad: Asegura que una vez realizada la operación, ésta quedará persistente y no podrá deshacerse aunque el sistema.
Sí el motor de base de datos posee estás 4 propiedades éste puede ser considerado ACID Compliant (Atomicity, Consistency, Isolation and Durability)
Veamos el ejemplo de recuperar los datos con una transacción
<?php $db = new SQLiteDatabase("db.sqlite"); // Traigo todos los registros de la tabla personas $result = $db->query("BEGIN; SELECT * FROM personas; COMMIT;"); // ciclo el resultado while($result->valid()) { $row = $result->current(); echo $row['id'].' - '.$row['nombre'].' - '.$row['apellido'].'<br />'; $result->next(); } ?>
Como puede observarse en el query poseemos BEGIN; y COMMIT; en medio de nuestra consulta que recupera los datos (los puntos y comas separan cada consulta). Esto se debe a que iniciamos una transacción en la base de datos, BEGIN da comienzo a ésta, luego se realiza el o los querys y por último COMMIT hace efectivos estos querys. Las transacciones nos dan la posibilidad de volver atrás en cualquier momento y deshacer todo lo hecho previamente con ROLLBACK.
Por ejemplo sí tenemos que crear 10 tablas podemos iniciar una transacción, sí por algún motivo los 6 primeros querys tienen la sintaxis correcta y no hacen ningún tipo de colisión y nuestra séptima instrucción da algún error con ROLLBACK podemos deshacer todos los querys después del comienzo de la transacción.
Es un tema muy amplio el de las transacciones y las bases de datos en general, así que como dije al principio del capítulo estaremos más abocados a aprender PHP