Hosting con phpSuExec

Desarrollo de software, Linux/Unix/FreeBSD, Web April 30th, 2008

Uno de los servidores contratados de hosting de la Fundación donde trabajo fue actualizado recientemente. Inicialmente tenía PHP4 y desarrollaron en él un sistema de información basado en la variable register_globals encendida. Ahora con PHP5 register_globals se encuentra desactivada por defecto y por ende, nada funciona.

La solución es muy sencilla, agregar la siguiente línea al archivo .htaccess que se encuentra en el raíz del sitio web.

    <ifmodule mod_php5.c>
        php_flag register_globals on
    </ifmodule>

Sin embargo esto no funcionó para el servidor. Por el contrario generaba un error 500. Investigué un poco mas y empecé a esclarecer la situación. Al parecer la actualización del hosting se realizó utilizando phpSuExec (1) que es la apropiación de PHP del soporte suExec que provee Apache. Esto permite que el demonio de Apache que atiende las peticiones de los diferentes dominios alojados en un hosting compartido se ejecute bajo el mismo usuario de la cuenta mejorando con esto la seguridad de las cuentas individuales. Esto trae consigo otras repercusiones como las observadas, en especial, la que impide que se definan variables PHP en el archivo .htaccess; conclusión: la solución anterior ya no es válida.

Con phpSuExec se deben crear archivos php.ini que se ubican, al igual que los .htaccess, en el árbol web del sitio, en ellos se definen las variables PHP necesarias. A diferencia de los segundos, el alcance de los archivos php.ini es local al mismo directorio, es decir, no es recursivo, así que en rigor es necesario crear en (o enlazar a) el archivo php.ini a cada uno de los directorios donde se necesite.

Esta restricción resulta altamente tediosa, tanto por la tarea mecánica misma de andar copiando archivos como por la de mantenerlos actualizados y ubicados en los directorios que son. Por suerte (y gracias al sitio de Jumba Support Wiki) encontré que es posible indicarle a Apache que un php.ini específico es el que tendrá vigencia a lo largo y ancho del árbol de directorios web utilizando una directiva PHPRC en el .htaccess. Esto nos evitará la necesidad de andar copiando/enlazando archivos en cada subdirectorio, claro está que es útil solamente en el caso en que necesitemos un único php.ini para todo el sitio (99% de los casos ?).

Para implementar esta solución se debe crear/editar un archivo .htaccess en el directorio raíz del sitio web e incluír la siguiente línea.

    SetEnv PHPRC /home/proyecto/public_html

Téngase en cuenta que la ruta /home/proyecto/public_html deberá ser la ruta real donde se ubicará le archivo php.ini.

Tags: ,

Manejo de servicios en Windows

Desarrollo de software, Software, Windows April 30th, 2008

En estos días he tenido que instalar algunos programas en mi equipo que solo voy a utilizar en ciertos momentos que esté desarrollando proyectos específicos: VMWare y MS SQL Server Express entre otros. Estos programas al instalarse agregan servicios a Windows que se ejecutan al inicio y consumen recursos a pesar de que no los esté utlizando en ese momento.

Para evitar eso pensé en deshabilitar los servicios de estas aplicaciones y hacer unos scripts para iniciarlos manualmente cuando los vaya a utilizar relamente.

Mi primer paso fue crear un archivo de batch utilizando el comando net {start|stop} SERVICIO. Después descubrí que existía el comando sc {start|stop} SERVICIO para realizar esta administración de servicios y lo modifiqué. Lo desventajoso de esta solución era crear un script para start y otra para stop, yo quería una solución que al estilo de *nix fuera un script único para todas las acciones.

Estuve leyendo un poco y fue cuando a la 1 am. se me ocurrió hacerlo en WSH. No fue muy difícil de aprender lo necesario salvo un par de excepciones que mencionaré posteriormente.

Con WSH creé un script que permite iniciar, detener, desactivar y verificar el estado de los servicios asociados a una aplicación. Los servicios relacionados se pueden configurar en un arreglo en la sección de configuración. Con él preparé los scripts para las aplicaciones que utilizo en este momento.

Los scripts se ejecutan con el comando cscript SCRIPT.js {start|stop|status|disable}.

Enlaces:

Como nunca he sido muy amigo de VB elegí desarrollar el script en JScript cuya sintaxis es similar a la de JavaScript. Desgraciadamente la gran mayoría de ejemplos de WSH están hechos en VB y la conversión de estos no era tan transparente como esperaba inicialmente. Estos fueron un par de detalles muy simples que me gastaron mas tiempo solucionar que el mismo desarrollo.

En VB un foreach se implementa de la siguiente manera.

For Each i in services
    ...
Next

Para convertirlo a JScript realicé este cambio.

for(var i in services) { ... }

Sin embargo la ejecución no era como se esperaba. Aparentemente este tipo de for sirve para iterar los atributos de un objeto y los valores de un arreglo pero no los elementos de una colección. Por suerte encontré la siguiente función que permite fácilmente realizar la adaptación.

function forEach(enumerable, delegate)
{
    for (var enumerator = new Enumerator(enumerable); !enumerator.atEnd(); enumerator.moveNext())
    {
        delegate(enumerator.item());
    }
}

Así que el código inicial se expresa de la siguiente manera.

forEach(services,
    function(i)
    {
       ...
    });

El otro detalle poco romántico de mi desvelada desarrollando anoche fue mucho mas simple aún. En VB esta es la forma de conexión a la consola de WMI.

Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" _
    & strComputer & "\root\cimv2")

Mi conversión a JScript inicialmente fue la siguiente.

var objWMIService = GetObject("winmgmts:"
    + "{impersonationLevel=impersonate}!\\"
    + strComputer + "\root\cimv2");

Muy fácil. Todos felices. Pero no funciona :-s Me tomó un buen rato darme cuenta que en VB al parecer no hay carácteres escapados así que en sus cadenas un \ es un \, mientras que en JScript si hay y por lo tanto un \ es solamente el inicio de un carácter escapado. En una cadena JScript, un \ se escribe en realidad \\. Por lo tanto la conversión real de la conexión a WMI es la siguiente.

var objWMIService = GetObject("winmgmts:"
    + "{impersonationLevel=impersonate}!\\\\"
    + strComputer + "\\root\\cimv2");

Después de solucionar estos detalles, la implementación fue un pedazo de torta.

Por otro lado, en mi búsqueda de información encontré un snippet interesante. Con WSH es muy fácil utilizar la máquina de texto a voz del sistema operativo.

tts = WScript.CreateObject("SAPI.SpVoice");
tts.Speak ("Hola");

Para mas información consultar Using WMI Scripting with Speech Server.

Enlace: Text To Speech Demo.


Actualización 20080430 @ 1840.

No había caido en cuenta que para que los scripts de administración de servicios funcionen deben ejecutarse con privilegios de administración (Windows Vista). Lo mejor es abrir un shell (Símbolo del sistema) con estos privilegios.

Para hacerlo abra el menú de inicio y en la parte inferior, en el campo de Iniciar búsqueda,
escriba cmd y presione las teclas Ctrl + Shift + Enter para iniciar la aplicación.

El díalogo de permitir la ejecución con privilegios de administración se abrirá y si se acepta se le concederán a todo lo que se ejecute desde esta consola, incluyendo por supuesto a los scripts WSH.

Tags: , ,