Can’t speak spanish? you can also read this article in english, click here.
Hace ya un tiempo, publiqué una clase para conectar desde PHP con MySQL, dicha clase, si bien cumplía perfectamente con su función, no era eficiente y tampoco le daba mucho juego al programador, así que cuando empecé a desarrollar Keopens, un CMS que empecé a desarrollar con el fin de que fuese un núcleo muy minimalista y adecuado a las nuevas tecnologías que están surgiendo. Por desgracia, no tengo tiempo suficiente para seguir con el desarrollo del mismo, pero algunas clases, si bien forman parte de dicho proyecto, las he sacado del mismo y continuado desarrollando ya que para los pequeños proyectos en PHP que tengo que ir haciendo son muy útiles.
Esta es una de esas clases que han ido creciendo poco a poco y según iban surgiendo necesidades se le iba incrementando las funcionalidades. En general se ha intentado seguir una POO correcta, pero con el fin de compartir la clase aislada, he decidido incluir dos funciones que no deberían estar en dicha clase, una de ellas es la de validar un e-mail y la otra es la de enviarlo.
La clase consta de dos modos de trabajo, un primer modo de debug o testing y un modo de producción, para cambiar entre ambos modos tan sólo hay que cambiarle el valor a una variable, además en el modo testing, la clase nos mostrará, al destruir el objeto o bajo demanda, el número de consultas ejecutadas y el tiempo total entre la creación de la instancia de la clase hasta que esta ha sido borrada. Si ocurre un error grave, y se dan una serie de condiciones (hemos inicializado la clase con un correo electrónico y no estamos en modo testing) se enviará por correo electrónico el fallo, esto es muy útil para tener constancia de los errores e incluso detectar en ocasiones la SQL-Injection en el caso de que se genere una sentencia que no haya podido ser ejecutada debido a errores de sintaxis.
Otras características interesantes:
- Funciona tanto con conexiones persistentes como no persistentes.
- Permite la creación de una copia de seguridad de la base de datos escribiendo una única línea de código (MySQL dump desde PHP).
- Nos permite monitorizar las sentencias, controlando en qué fichero y línea del mismo se ejecuta.
- Envío de emails cuando sucede un error grave.
- Conteo de tiempo de ejecución.
- Conteo de memoria utilizada por el script.
- Conteo del número de sentencias ejecutadas.
- Previsualización automática de los datos de salida de una sentencia (modo testing).
- En bases de datos InnoDB permite el uso de transacciones.
- Los mensajes extras mostrados en el modo testing tienen asociados una serie de estilos que indican visualmente si la ejecución ha sido correcta o, por el contrario, se ha producido un error.
He aquí una serie de ejemplos muy sencillos para mostrar rápidamente el potencial de la clase.
Para conectar con la base de datos, nos bastará con escribir dos líneas en nuestro programa y ya estaremos listos para trabajar:
$db = new MyMysqli($db_host, $db_uname, $db_pword, $db_name, $debugging, $contactMail, 'MYSQLI_ASSOC');
$db->connect(false);
Para ejecutar una consulta nos basta con escribir una sola directiva.
$query = 'SELECT * FROM text';
$db->execute($query, __LINE__, __FILE__);
Las constantes __FILE__ y __LINE__ nos sirven para indicar, en caso de error, el lugar en el que se encuentra dicha consulta a la base de datos.
El método ejecutado devuelve un resultSet, pero la clase mantiene una referencia al último resultSet dado que es muy probable que nos interese trabajar con él en breves, por lo que devuelve el resultSet para utilizarlo en casos muy específicos, como por ejemplo en el caso de que necesitemos trabajar con dos a la vez.
Para recorrer un resultSet de una consulta nos basta con ir llamando al método fetch(), si no se le pasa como parámetro un resultSet, ejecutará la acción sobre el obtenido en la última petición a la base de datos
if($db->numRows() > 0){
while($result = $db->fetch()){
//TODO
}
}
Si somos un poco “vagos” o simplemente vamos a consultar muchas veces los datos, la clase proporciona un método para pasar los datos obtenidos a una tabla.
$db->getTable();
Al igual que en el ejemplo anterior, si no se le pasa como parámetro otro resultSet, formará la tabla partiendo del último restulSet obtenido.
Por último mencionar que, en las primeras lineas de la clase, podrá observar que hay unas líneas comentadas que citan lo siguiente:
//Access control
if(!defined('IN_APP')) exit('Access Forbidden');
Estas líneas están comentadas por una sencilla razón, en PHP es posible acceder a cualquer archivo por URL si el servidor no está bien configurado, esto hace que si la página cargada imprime algo por pantalla, no se muestre, ya que la constante IN_APP no está definida con anterioridad. Por ende para que funcione, antes de incluir el archivo en la ejecución, deberíamos declarar la constante IN_APP. Obviamente el nombre de la constante puede ser cualquiera, en este caso, la que yo usaba en Keopens era IN_APP.
Descarga: MyMysqli Class (41)

De muchos es sabidos que cualquier aplicación un poco compleja hace recomendable el uso de una barra de progreso para indicar lo que se está haciendo en algún momento dado de la ejecución, como por ejemplo a la hora de procesar grandes cantidades de datos o simplemente al guardar grandes cantidades de datos en un archivo, …
Pues bien, supongamos que, nuestro complejo programa consiste en una barra de progreso y de un botón. Al pulsar el botón, la barra de progreso se llena del 0% al 100% en cuestión de 1 segundo en pasos de 1 en 1, de manera que cada 10ms el porcentaje de barra rellena tiene que aumentar en 1/100.

El código de este programa consistiría en algo tan simple como lo siguiente: Leer más… »
Con este artículo termina la serie de artículos en las que describimos los principios básicos que hay que tener en cuenta para realizar un chat y en los que también se describe como hacer una pequeña aproximación a uno de estos programas que a muchos de nosotros nos acompañan en nuestro día a día.
En el artículo de hoy vamos a tratar el único tema que nos falta, el cual es el programa cliente que nos servirá a los usuarios para comunicarnos con el servidor y así, poder comunicarnos con el resto de usuarios que se encuentren conectados en un momento dado.
Si bien el cliente se basta de un sólo ejecutable, hoy vamos a tratar dicho ejecutable y otro que nos permita, mediante la redirección de descriptores de ficheros, añadirle una interfaz gráfica sencilla.
cli.c
Nos encontramos ante uno de los ficheros con la lógica esencial del cliente del chat, vamos a analizarlo paso a paso:
#include <stdio.h>
#include <stdlib.h>
// librería para manejo de strings
#include <string.h>
// librería para el uso de los sockets y las correspondientes constantes
#include <sys/socket.h>
// librería para el uso de la constante IPPROTO_TCP, in_addr, ...
#include <netinet/in.h>
// librería que nos permite hacer uso de la variable errno
#include <errno.h>
// librería de base de datos de red
#include <netdb.h>
// librería para el uso de primitivas unix
#include <unistd.h>
// librería para obtener acceso a variables como pid
#include <sys/types.h>
// librería para el manejo de señales
#include <signal.h>
// librería para mostrar la traza del programa
#include "trace.h"
// librería para gestionar los paquetes enviados y recibidos
#include "sms.h"
// librería con las flags que utilizaremos
#include "flags.h"
// incuimos la librería de tipos de datos
#include "type.h"
// incuimos la librería de herramientas para los echo
#include "tools.h"
// incluimos las librerías que nos permitirán hacer uso de SSL
#include "ssl.h"
#define DIM 1024 // definimos el tamaño de los array de textos
#define READ STDIN_FILENO
#define WRITE STDOUT_FILENO
Incluimos los archivos de cabecera o librerías necesarias para la ejecución del chat y realizamos las definiciones de tamaños, y ya puestos, definimos los descriptores de ficheros de entrada y salida con el nombre de las constantes genéricas en lugar de utilizar los números 0 para lectura y 1 para escritura.
Leer más… »
Hasta ahora hemos estado hablando de funcionalidades genéricas del chat, requisitos, …pues bien hoy vamos a analizar todos los ficheros de los que se compone el servidor y no han sido comentados con anterioridad; al igual que en el artículo anterior, vamos a comentar el cometido de cada una de las funciones de manera genérica, y únicamente nos adentraremos en el contenido de estas en la función de manejo de los sockets y en las que tengan alguna curiosidad que comentar.
Database.c
Éste es un archivo de código fuente que sólo será incluido en el programa del servidor (en realidad también va a ser incluido en el programa que nos ayudará a crear la base de datos desde cero, pero la importancia de ese ejecutable es mínima y la comentaremos más adelante.
En este caso hemos decidido hacer uso del sistema de bases de dados SQLite dado que es una base de datos ligera portable y con características más que suficientes para utilizarla en nuestra pequeña aplicación.
sqlite3* db_open(char*);
El cometido de esta función es simple, simplemente abrirá la base de datos situada en el fichero que se le ha de pasar como argumento.
int db_prepare(sqlite3**);
Esta función no se utilizará en el servidor, pero será la que utilizará la aplicación que creará la base de datos en caso de que esta no exista, y su única función es la de crear las tablas necesarias en la base de datos así como el usuario administrador del chat.
int db_exec(sqlite3**, char*, int);
Esta función se encargará de ejecutar una sentencia SQL y de actuar en consecuencia dependiendo del flag que se le pase como último argumento.
int db_userExists(char*, sqlite3**);
Esta función comprueba si un usuario existe en la base de datos.
int db_checkUser(char*, char*, sqlite3**);
Esta función comprueba si un usuario asociado a una contraseña existe en la base de datos.
int db_addUser(char*, char*, int, sqlite3**);
Crea un nuevo usuario.
int db_deleteUser(char*, sqlite3**);
Elimina un usuario de la base de datos.
int db_listUser(int, sqlite3**);
Lista los usuarios en la base de datos
void db_close(sqlite3**);
Cierra la base de datos y todos los descriptores asociados a ella.
int db_addLog(sms, sqlite3**);
Añade a la tabla de logs un mensaje.
int db_getLog(int, sqlite3**);
Lista el contenido del log de la base de datos
int db_getLogPar(int, sqlite3**, char*);
Tiene un comportamiento similar al de la función anterior, sólo que esta admite parámetros para personalizar la búsqueda, como por ejemplo buscar entre dos fechas dadas.
static int callback(void*, int, char**, char**);
Función que será llamada para cada una de las filas obtenidas de una sentencia SELECT. Leer más… »