Aplicación UpTimeCheck 0.1

UpTimeCheck es una aplicación muy simple desarrollada en PHP para verificar y registrar que diferentes sitios web se encuentren en línea.

Esta aplicación corre como un script de CLI (command line interface) y puede ejecutarse por demanda o a través de un proceso cron como es más conveniente. En la configuración pueden especificarse los sitios a revisar sin ningún límite o restricción respecto a su cantidad y algunos parámetros adicionales para personalizar su funcionamiento.

Para más información acerca de la aplicación por favor consultar el archivo README de la misma.

Como para todo en la vida, se reciben sugerencias y reportes de problemas.

Enlace: uptime_0.1.zip

Acceso a MSSQL Server desde PHP en un servidor Linux

El día de hoy realicé la actualización del servidor de desarrollo (OpenSuse 10.2) para soportar las conexiones a un servidor de bases de datos MS SQL Server 2005. El servidor de bases de datos se encuentra en la red privada (192.168.1.5). El servidor de desarrollo tiene dos interfaces, una de ellas es privada también (192.168.1.3). La versión de PHP que se encuentra actualmente instalada es la 5.2.0.

Actualicé algunos paquetes que eran necesarios para instalar el software FreeTDS.

# rpm -i readline-devel-5.1-55.i586.rpm
# rpm -i  libxml2-devel-2.6.26-26.i586.rpm
# rpm -i  libapr1-devel-1.2.7-23.i586.rpm
# rpm -i  libapr-util1-devel-1.2.7-26.i586.rpm
# rpm -i  apache2-devel-2.2.3-20.i586.rpm

Otros paquetes que puedan llegar a necesitarse se pueden descargar de la siguiente dirección.

http://download.opensuse.org/distribution/10.2/repo/oss/suse/i586/.

Descargué y descomprimí la última versión de FreeTDS.

# wget ftp://ftp.ibiblio.org/pub/Linux/ALPHA/freetds/stable/freetds-stable.tgz
# tar zxvf freetds-stable.tgz
# cd freetds-0.64

Se compila e instala en el directorio /usr/local/freetds-0.64 con soporte para la versión 8.0 del protocolo. Para consultar información adicional acerca del protocolo consulte la dirección siguiente: http://www.freetds.org/userguide/choosingtdsprotocol.htm.

# ./configure --prefix=/usr/local/freetds-0.64 --with-tdsver=8.0
# make
# make install

Creé un enlace dinámico desde /usr/local/freetds al directorio de instalación para facilitar el manejo de diferentes versiones en un futuro cercano cuando vaya a actualizar la librería.

# ln -s /usr/local/freetds-0.64 /usr/local/freetds

Edité el perfil general de los usuarios para añadir al final de este información de las variables de ambiente de FreeTDS .

# vi /etc/profile
###################################################
SYBASE=/usr/local/freetds
LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:$SYBASE/lib
export SYBASE LD_LIBRARY_PATH
###################################################

Descargué y descomprimí el código fuente de la versión de PHP instalada. Para descargar versiones históricas de PHP visite el siguiente enlace: http://www.php.net/releases/.

# wget http://museum.php.net/php5/php-5.2.0.tar.gz
# tar zxvf php-5.2.0.tar.gz
# cd php-5.2.0

Se crearon los scripts de compilación para realizar una instalación temporal en /root/tmp/php-5.2.0/installation y de allí obtener el módulo dinámico de soporte para MSSQL.

# SYBASE=/usr/local/freetds
# LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:$SYBASE/lib

# export SYBASE LD_LIBRARY_PATH# ./configure --with-apxs2=/usr/sbin/apxs2 
--with-mssql=shared,$SYBASE 
--with-sybase=$SYBASE 
--with-libxml-dir=/usr/lib/ 
--prefix=/root/tmp/php-5.2.0/installation
# make

# make install

Se copió el módulo recién generado a la ubicación donde PHP almacena sus propios módulos.

# cp ./installation/modules/mssql.so /usr/lib/php5/extensions/
# chmod -x  /usr/lib/php5/extensions/mssql.so

Se creó el archivo mssql.ini para activar el módulo.

# vi /etc/php5/conf.d/mssql.ini
extension=mssql.so

Se reinicio el servicio de Apache2 para refrescar los cambios recién hechos.

# rcapache2 restart

Al consultar la información resultante de phpinfo ya aparece la sección de MSSQL.

Para realizar una prueba fiable de conexión entre PHP y MSSQL puede utilizar el script adjunto a continuación editando adecuadamente la información de conexión al inicio de este.

Enlace: prueba_mssql.php

Funciones anónimas en PHP

Al parecer PHP todavía no soporta funciones anónimas. Hoy necesitaba una. Iba a hacer un usort de un arreglo cuyas celdas eran a su vez otros arreglos, motivo por el cual no me servía un sort normal.

Inicialmente hice lo siguiente …

usort($datos['opciones'], "ordenar_opciones_menu");

Y poner el código de la función por fuera de mi clase de Controlador.

function ordenar_opciones_menu($a, $b)
{
    return strcmp($a['titulo'], $b['titulo']);
}

Resultado … muy feo.

Encontré que PHP tiene una forma un poco practica para crear funciones de manera dinámica a partir de una cadena de texto con su código. El ejemplo anterior se simplificó de la siguiente manera.

usort($datos['opciones'],
         create_function('$a, $b',
                         'return strcmp($a["titulo"], $b["titulo"]);'));

Un tanto preferible esta versión.

Encriptando cositas con MCrypt

La fase final de mi experimento con XML-RPC suponía poder encriptar la solicitud que iba del cliente al servidor así como la respuesta de este último hacia el cliente. Como se sobreentiende, esta encriptación debería ser de dos vías. Para esto estuve revisando la API de PHP y encontré que la utilización de la librería mcrypt es bastante útil y que por suerte hasta el hosting mas antiguo de todos la soporta en PHP.

Para esto entonces desarrolle dos procedimientos: encriptar y desencriptar para separar su funcionalidad.

Encriptar.

Para encriptar información se requieren los siguientes parámetros.

  • El nombre del algoritmos de encriptación (Ej. blowfish).
  • El modo de encriptación (Ej. cfb).
  • El orígen del azar (Ej. MCRYPT_RAND).
  • La contraseña de encriptación (secreta).
  • Los datos a encriptar.
  • El vector de encriptación (IV) que actúa como semilla (opcional).

Se abre el módulo del algoritmo de encriptación y se especifica su definición.

$td = mcrypt_module_open($encryption_algorithm, ”, $encryption_mode, ”);

Se crea el vector de encriptación y se determina la longitud de la llave.

$client_iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), $random_source);
$ks = mcrypt_enc_get_key_size($td);

Se crea la llave basada en la contraseña de encriptación especificada por el usuario (mayor seguridad).

$key = substr(md5($encryption_key), 0, $ks);

Se inicializa la encriptación con la información establecida anteriormente.

mcrypt_generic_init($td, $key, $client_iv);

Se encriptan los datos.

$encrypted_data = mcrypt_generic($td, $raw_data);

Se termina el proceso de encriptación.

mcrypt_generic_deinit($td);

Al final se obtiene el vector de encriptación ($client_iv) y la información encriptada ($encrypted_data), ambos son necesarios para realizar el proceso inverso.

Desencriptar.

Para desencriptar la información se requiere la siguiente información.

  • El nombre del algoritmos de encriptación (Ej. blowfish).
  • El modo de encriptación (Ej. cfb).
  • La contraseña de encriptación (secreta).
  • El vector de encriptación (IV).
  • Los datos encriptados.

Se abre el módulo del algoritmo de desencriptación y se especifica su definición.

$td = mcrypt_module_open($encryption_algorithm, ”, $encryption_mode, ”);

Se determina la longitud de la llave.

$ks = mcrypt_enc_get_key_size($td);

Se crea la llave basada en la contraseña de encriptación especificada por el usuario (mayor seguridad).

$key = substr(md5($encryption_key), 0, $ks);

Se inicializa la desencriptación con la información establecida anteriormente.

mcrypt_generic_init($td, $key, $client_iv);

Se desencriptan los datos.

$decrypted_data = mdecrypt_generic($td, $encrypted_data);

Se termina el proceso de encriptación y se cierra el módulo.

mcrypt_generic_deinit($td);
mcrypt_module_close($td);

Al final se obtiene la información desencriptada ($decrypted_data) la cual debe corresponder con la información original. Algunas veces la desencriptación deja espacios en blanco a los lados de la cadena desencriptada por lo que puede ser de utilidad pasar la información por un trim() como último paso.

La demostración de este código se encuentra siguiendo este enlace Demo #0. Este cuenta con los archivos config.php (variables necesarias), security.php (funciones para encriptar y desencriptar) y demo1.php (ejemplo funcional).

Primer ejemplo de XML-RPC

Estimando que probablemente uno de los proyectos de la Fundación requiera la consulta de información de uno de los proyectos anteriores ubicado en uno de los servicios de hosting, decidí realizar algunos experimientos con XML-RPC para determinar la viabilidad de utilizarlo para esta tarea en caso de que sea realmente necesaria. Debido a que el hosting en el que se encuentra el proyecto tiene una versión bastante antigua de PHP4 se decidió utilizar la librería de http://phpxmlrpc.sourceforge.net/.

Este es mi primer contacto con XML-RPC. Había leido un poco del tema en la documentación del framework CodeIgniter que planeo utilizar dentro de poco en mis próximos proyectos, sin embargo como está basado en PHP5 y el hosting soporta únicamente PHP4 decidí probar con la librería mencionada anteriormente, la cual es bastante mas enrredada, pero por suerte bien documentada, aunque hacen falta ejemplos.

En este pequeño demo que implementé se envían por parte del cliente un nombre (“Pepe”) y la solicitud de ejecución de un procedimiento remoto (“HelloWorld.show”). El servidor relaciona este método remoto con un procedimiento local (“show”) que retorna la cadena resultante (“Hello Pepe”).

El Cliente.

Se realiza el include de la librería de XML-RPC.

include_once (“../lib/xmlrpc-2.2/lib/xmlrpc.inc”);

Se define la ubicación del servidor y se instancia un objeto de la clase cliente.

$host = “localhost”;
$location = “xmlrpc/d1”;
$server = “ServerHello.php”;

$client = new xmlrpc_client(“http://{$host}/{$location}/{$server}”);

Se prepara el mensaje que enviará el cliente. El mensaje define cual es el procedimiento remoto a ejecutarse y la información relacionada con este (parámetros). Para el ejemplo se invocará al procedimiento HelloWorld.show y se le enviará “Pepe” que es de tipo string.

$message = new xmlrpcmsg(“HelloWorld.show”, array(new xmlrpcval(“Pepe”, “string”)));

Si se desea consultar los mensajes de depuración se debe activar la siguiente expresión.

// $client -> setDebug(3);

Con todo listo, se envía la solicitud al servidor y se captura su respuesta.

$response = $client -> send($message);

Si la respuesta referencia a un error, este viene con su respectivo código de fallo, en caso contrario se puede consultar su contenido.

if ($response -> faultCode())
echo “<br>KO. Error: ” . $response -> faultString();
else
echo “<br>OK. got … ” . $response -> value() -> scalarVal();

El Servidor.

Se realiza el include de la librería de XML-RPC, se incluyen los dos archivos inc: cliente y servidor.

include_once (“../lib/xmlrpc-2.2/lib/xmlrpc.inc”);
include_once (“../lib/xmlrpc-2.2/lib/xmlrpcs.inc”);

Se instancia un objeto de clase servidor en la que se especifica la siguiente información de los procedimientos remotos expuestos como disponibles:

  • Relación entre nombre de procedimiento remoto y función PHP a ejecutarse en su llamado.
  • La firma de la función (signature): tipo de retorno y de parámetros requeridos. Una función puede tener varias firmas.
  • Documentación de la función (docstring).

$server = new xmlrpc_server(array(
“HelloWorld.show” => array(“function” => “show”,
“signature” => array(array($xmlrpcValue, $xmlrpcString)),
“docstring” => “Shows a greeting message with the specified name.”)
), false);

Si se desea consultar los mensajes de depuración se debe activar la siguiente expresión.

// $server -> SetDebug(3);

Cuando todo está listo se envía la respuesta al cliente.

$server -> service();

Como siguiente paso se debe definir la función PHP show que será ejecutada cuando el procedimiento remoto HelloWorld.show sea solicitado.

La función recibe la información enviada por el cliente ($xmlrpcmsg) y tiene acceso a la variable $xmlrpcerruser la cual indica el número del error a partir del cual se encuentran disponibles para los errores definidos por el usuario.

function show($xmlrpcmsg)
{
global $xmlrpcerruser;

Verifico que el número de parámetros enviados por el cliente sea de uno, en caso contrario envío un código de error.

if ($xmlrpcmsg -> getNumParams() != 1)
{
return new xmlrpcresp(0, $xmlrpcerruser+1, “I am expecting a parameter for the name!”);
}

Obtengo el valor del parámetro disponible.

$val0 = $xmlrpcmsg -> getParam(0);

if($val0 -> kindOf() != “scalar”)
{
return new xmlrpcresp(0, $xmlrpcerruser+2, “I am expecting a string as parameter for the name!”);
}

$name = $val0 -> scalarval();

Compongo la cadena resultante: “Hello ” + valor del parámetro y la empaqueto en un mensaje de respuesta (xmlrpcresp) el cual es de tipo string y es enviado hacia el cliente.

return new xmlrpcresp(new xmlrpcval(“Hello ” . $name, “string”));
}

El demo #1 en ejecución puede ser consultado en http://demo.jorgeivanmeza.com/PHP/XMLRPCDemo/0.1/ClientHello.php

La documentación en línea de XML-RPC for PHP puede ser consultada en http://phpxmlrpc.sourceforge.net/doc-2/.