Solucionar error de la extensión curl de PHP en Windows

Supongamos que necesitamos invocar una url a partir de nuestro código PHP. Una forma de hacerlo es mediante la extensión curl. Es posible que en Windows al intentar activarla, no logremos hacer que funcione.

Si el código que la utiliza es similar a:

<?php
  $ch=curl_init();
  curl_setopt($ch,CURLOPT_URL,'http://localhost/');
  curl_exec($ch);
  curl_close($ch);
 ?>

obtendremos el error:

Fatal error: Call to undefined function curl_init()

 

Para solucionarlo debemos primero verificar en el archivo de configuración php.ini que:

  • el directorio de extensiones (extension_dir) sea el correcto
  • la línea extension=php_curl.dll esté descomentada (sin el ; inicial)

A continuación ubicamos el directorio donde está instalado PHP y de allí copiamos los archivos:

  • libeay32.dll
  • ssleay32.dll

al directorio bin dentro de la ubicación donde se encuentra instalado de Apache.

Para finalizar reiniciamos el servicio de Apache.

 

Podemos corroborar que la extensión fue activada exitosamente a través de la información de phpinfo(), mediante un script con el código:

<?php
  phpinfo();
?>

Si volvemos a probar el código del principio veremos que funciona correctamente.

Anuncios

Límites de fecha en timelocal de Perl

Una forma de validar una fecha en Perl es mediante la función timelocal del módulo Time::Local. El problemas es que en versiones de Perl menores a 5.12, las fechas que soporta están limitadas. En la documentación se indica “from Dec 1901 to Jan 2038”. Quise probar realmente estos límites y ahora les muestro un ejemplo práctico en Perl 5.8

Creamos un script con el siguiente código y lo llamamos test_timelocal.pl

#!/usr/bin/perl

use strict;

use Time::Local;

my ($fecha) = @ARGV;
$fecha =~ /^(\d{4})-(\d{2})-(\d{2})$/;
my ( $a, $m, $d ) = ($1,$2,$3);

my $time = undef;

eval {
      $time = timelocal(0,0,0,$d,--$m,$a); #se indica la cantidad de meses desde Enero (0..11)
};
if ( $@ ) { print "Fecha no definida"; }
else      { print $time; }

El mismo acepta como único parámetro una fecha. Obtendremos como resultado la cantidad de segundos desde el epoch del sistema.

Procedemos entonces a ejecutar desde la línea de comandos el script, intentando encontrar las fechas límite:

perl test_timelocal.pl 1901-12-16
-> Fecha no definida

perl test_timelocal.pl 1901-12-17
-> -2023488000

perl test_timelocal.pl 2038-01-16
-> 2147223600

perl test_timelocal.pl 2038-01-17
-> Fecha no definida

Comprobado empíricamente, en este caso las fechas soportadas por timelocal son aquellas que se encuentren en el rango desde 17/12/1901 al 16/01/2038, para versiones de Perl menores a 5.12

 

Basado en:

http://perldoc.perl.org/Time/Local.html#Limits-of-time_t

Configurar Apache para utilizar scripts CGI

Para poder invocar scripts CGI desde el navegador, es necesario configurar Apache de manera que lo permita. Para ello debemos seguir este sencillo instructivo:

Agregar Handler de CGI

Abrir en un editor de textos el archivo de configuración conf\httpd.conf ubicado dentro del directorio de instalación de Apache

Quitar el comentario de la línea (sólo borrando el # inicial) y guardar

#AddHandler cgi-script .cgi

Indicar la ejecución de CGIs en un VirtualHost

A partir de un VirtualHost que hayamos definido, según la versión de Apache:

  • Versión 2.0.x: En el mismo archivo de configuración (httpd.conf)
  • Versión 2.2.x: En el mismo archivo de configuración conf\extra\httpd-vhosts.conf

Agregar “+ExecCGI” a la cláusula Options dentro de Directory, manteniendo las preexistentes:

<VirtualHost *:80>
    ...
DocumentRoot SITE_PATH

    <Directory SITE_PATH>
        Options +ExecCGI +Indexes
    ...
    </Directory>
ServerName DOMINIO_LOCAL

    ...
</VirtualHost>

Adicionalmente sería conveniente agregar “index.cgi” a la cláusula DirectoryIndex del VirtualHost.

Reiniciar Apache

Procedemos a reiniciar el servicio de Apache para que tome la nueva configuración.

Probar el funcionamiento de CGI

Vamos a hacer la prueba ejecutando scripts CGI con Perl, por lo que requerimos que se encuentre instalado en el sistema. Tal vez tengamos que hacer unos ajustes adicionales para poder ejecutar scripts CGI con código Perl desde Apache en Windows.

En el directorio SITE_PATH correspondiente al VirtualHost, creamos un archivo llamado index.cgi con el siguiente contenido:

#!/usr/bin/perl

print "Content-type: text/html\n\n";

print "<h2>Configuraste correctamente apache para ejecutar scripts CGI con Perl</h2>";

Finalmente, abrimos un navegador y accedemos a la url DOMINIO_LOCAL del VirtualHost. Deberíamos ver el texto “Configuraste correctamente Apache para ejecutar scripts CGI con Perl“.

Programar la ejecución de un script en Linux

Para programar la ejecución de un script (o un comando) en linux, utilizaremos el comando crontab:

crontab [-u <USUARIO>] { <ARCHIVO> | -e | -l | -r }

  • -u <USUARIO>: Indica el USUARIO del archivo crontab que se va a utilizar
    • Si no se especifica, se utiliza el usuario logueado
  • <ARCHIVO>: indica el archivo que contiene las entradas, crea un nuevo crontab para el usuario y las programa.
  • -e: Edita el contenido del archivo crontab del usuario. Si no existiera, crea uno nuevo.
    • Al salir del editor, se programan las entradas.
  • -r: Quita el crontab actual
  • -l: Muestra el contenido del archivo crontab actual

 

Las entradas de los archivos crontab tienen el siguiente formato:

* * * * *  Script o comando a ejecutar
- – – – -
| | | | |
| | | | +— Día de la semana (0–6) o Sun, Mon, Tue,...
| | | +——— Mes (1–12) o Jan, Feb,...
| | +————— Día del Mes (1–31)
| +——————— Hora (0–23)
+————————— Minuto (0–59)

En los días de la semana, 0 se corresponde a domingo (Sun).

Para todos los campos, se puede especificar:

  • un asterisco * que indica “cualquiera de los valores”
    • se permite especificar un salto de N valores mediante  “*/<N>” (cada n minutos, horas, días, etc.)
      • Ejemplo: */6 en el campo de horas = lista “0,6,12,18”
  • una lista de valores numéricos o textos de 3 letras (para meses y días de la semana) separados por coma
    • Ejemplo: “6,8,9” o “Jan, Mar, Jul”
  • un rango numérico separando con guión medio (-) el menor valor y el mayor (incluídos en el rango) “<MIN>-<MAX>”
    • Ejemplo “1-4” = “1,2,3,4”
    • se permite especificar un salto de N valores mediante  “<MIN>-<MAX>/<N>” (cada n minutos, horas, días, etc.)
      • Ejemplo: “5-28/3” = lista “5,8,11,14,17,20,23,26”

El script se ejecuta cuando la hora, los minutos, el mes y, el día del mes o de la semana, coinciden con el momento actual.

La aplicación residente cron (se ejecuta en background) consulta los archivos crontab para saber qué ejecutar y cuándo hacerlo.

Por defecto, envía la salida del comando al usuario definido en la variable de entorno MAILTO. Para ver si está definida, podemos imprimirla por línea de comandos:

echo $MAILTO

Para evitarlo, debemos redirigir la salida de STDOUT y STDERR

Ejemplos:

#Ejecutar backup.pl de lunes a viernes a la 1 de la mañana y generar un log

0 1 * * 1-5 ./backup.pl > /var/logs/backup.log 2>&1

#Ejecutar check_filesystem.pl a las 12 del mediodía cada 3 días y también los sábados

0 12 */3 * 6 ./check_filesystem.pl > /dev/null 2>&1

#Ejecutar sync.pl a las 8:30, 11:30, 15:30, 17:30 todos los días entre Marzo y Noviembre, generando el log correspondiente

30 8,11,15,17 * 3-11 * ./sync.pl > /var/log/sync.log 2>&1

#Ejecutar reports.pl a las 8:50 los días 15 y 28 de cada mes

50 8 15,28 * * ./reports.pl > /dev/null 2>&1

#Ejecutar get_mails.pl cada 20 minutos entre las 9 y las 18

*/20 9-18 * * * ./get_mails.pl > /dev/null 2>&1

 

Basado en:

http://unixhelp.ed.ac.uk/CGI/man-cgi?crontab+5

http://ss64.com/bash/crontab.html

Quitar un módulo de Perl

Si utilizamos PPM para administrar módulos de Perl tenemos todas las herramientas allí mismo, incluso la posibilidad de quitar un módulo. Pero en el caso de que hayamos usado CPAN esa opción no está disponible. Podemos borrar manualmente los archivos pero puede quedarnos algún resto olvidado.

Estuve buscando alternativas hasta que encontré un script que se encarga de ellos, invocándolo con un módulo como argumento. Su funcionamiento se basa en el módulo ExtUtils de Perl. El mismo borra todos los archivos asociados y los directorios vacíos.

Creen un archivo con el nombre remove_module.pl, copien el siguiente código dentro y guárdenlo en un directorio conocido:

# remove_module.pl from PerlTricks.com

use ExtUtils::Installed;
use ExtUtils::Packlist;

# Exit unless a module name was passed
die ("Error: no Module::Name passed as an argument. E.G.\n\t perl $0 Module::Name\n") unless $#ARGV == 0;

my $module = shift @ARGV;

my $installed_modules = ExtUtils::Installed->new;

# iterate through and try to delete every file associated with the module
foreach my $file ($installed_modules->files($module)) {
    print "removing $file\n";
    unlink $file or warn "could not remove $file: $!\n";
}

# delete the module packfile
my $packfile = $installed_modules->packlist($module)->packlist_file;
print "removing $packfile\n";
unlink $packfile or warn "could not remove $packfile: $!\n";

# delete the module directories if they are empty
foreach my $dir (sort($installed_modules->directory_tree($module))) {
    print("removing $dir\n");
    rmdir $dir or warn "could not remove $dir: $!\n";
}

Aclaraciones:

El método directory_tree() trae todos los directorios contenidos en las rutas donde existan archivos del módulo (incluyendo el directorio raíz ej: c:\) y luego intenta borrarlos. No se preocupen porque solamente lo hará si están vacíos.

Si bien existe otro método, directories(), que trae solamente los directorios del módulo, esta limitado a aquellos de mayor nivel de profundidad

 

Entonces si lo que deseamos es quitar el módulo DBass, abrimos una línea de comandos y nos ubicamos en el directorio donde guardamos el script y ejecutamos mediante:

perl remove_module.pl DBass

removing C:/Perl/site/lib/DBass.pm
removing C:/Perl/html/site/lib/DBass.html
removing C:/Perl/site/lib/auto/DBass/.packlist
removing C:/
could not remove C:/: Directory not empty
removing C:/Perl
could not remove C:/Perl: Directory not empty
removing C:/Perl/html
could not remove C:/Perl/html: Directory not empty
removing C:/Perl/html/site
could not remove C:/Perl/html/site: Directory not empty
removing C:/Perl/html/site/lib
could not remove C:/Perl/html/site/lib: Directory not empty
removing C:/Perl/site
could not remove C:/Perl/site: Directory not empty
removing C:/Perl/site/lib
could not remove C:/Perl/site/lib: Directory not empty

Basado en:

http://perltricks.com/article/3/2013/3/27/How-to-cleanly-uninstall-a-Perl-module

Programar la ejecución de un script en Windows

Si queremos que un cierto script se ejecute automáticamente siempre que iniciamos sesión en Windows hay una forma sencilla:

  1. Crear un acceso directo al script (Botón derecho sobre el archivo y luego Crear acceso directo)
  2. Copiar el acceso directo creado al directorio Inicio dentro del Menú inicio:

C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup

Si el momento de ejecución queremos definirlo de manera más precisa podemos utilizar el Programador de tareas:

  1. Acceder a Panel de Control > Herramientas administrativas > Programador de tareas
  2. Elegir la opción “Crear tarea…” del panel derecho de Acciones
  3. Definir un nombre y opcionalmente la descripción en la solapa General
  4. Elegir la solapa Desencadenadores y presionar Nuevo… (se puede agregar más de uno)
  5. Configurar cuándo inicia la tarea y cuándo se repite (ej: Semanalmente, Lunes y Viernes)
  6. Elegir la solapa Acciones y presionar Nuevo… (se puede agregar más de una)
  7. Elegir en Acción: Iniciar un programa y presionar Examinar… para elegir nuestro script
  8. Confirmar con Aceptar

De ahora en adelante nuestro script se ejecutará automáticamente según la periodicidad definida.

Hacer un script de respaldo de archivos en Windows

Para poder respaldar todo el contenido de un directorio en un archivo dentro de otra unidad, disco o directorio, podemos crear un script de línea de comandos:

Crear el archivo ejecutable

  1. Abrir un editor de textos de nuestra preferencia (puede ser el Bloc de notas)
  2. Escribir los comandos para realizar cada una de las acciones deseadas
  3. Guardar el archivo con extensión .bat (ejemplo: respaldo.bat)

Desactivar el “eco” de los comandos

Cuando se ejecuta cada uno de los comandos, los mismos se repiten en la línea de comandos por defecto. Para evitar esto debemos comenzar el script con:

@echo off

Obtener la fecha y hora de ejecución

En las variables FECHA y HORA almacenamos sendos datos:

for /f "tokens=1-3 delims=/- " %%a in ('date /t') do set FECHA=%%c%%b%%a
for /f "tokens=1-2 delims=: " %%a in ('time /t') do set HORA=%%a%%b

Generar nombre del archivo de respaldo

Con la fecha y la hora, generamos un nombre de archivo  y lo almacenamos en la variable BACKUP_FILE

set BACKUP_FILE=Contenido_%FECHA%%HORA%.zip

Comprimir los datos

En esta parte se puede utilizar cualquier aplicación que permita comprimir por línea de comandos. Yo les propongo que usen 7zip que es gratuito. Tenemos que especificar la ubicación del archivo de respaldo primero y luego el directorio con el contenido a respaldar:

7zip.exe a -tzip "c:/backups/BACKUP_FILE" "c:/Contenido/"

Registrar log

El registro de log es opcional, pero si vamos a planificar la ejecución del script es conveniente registrarla para poder consultar después si se realizó o no correctamente.

Establecemos el nombre y la ubicación del log relativo a la ubicación en que se encuentre el script de backup. Les propongo generar un log por día y no por ejecución:

set BACKUP_LOG_FILE=logs/Contenido_%FECHA%.log

Al principio del script indicamos el inicio del respaldo con la fecha y hora:

echo. >> %BACKUP_LOG_FILE%
echo Inicia respaldo >> %BACKUP_LOG_FILE%
echo %FECHA% %HORA% >> %BACKUP_LOG_FILE%

Modificamos la línea donde hacemos la compresión para que los resultados de la misma vayan al log

7zip.exe .... >> %BACKUP_LOG_FILE%

Al final del script indicamos el fin del respaldo con la fecha, hora y el archivo de log generado:

echo. >> %BACKUP_LOG_FILE%
echo Fin respaldo >> %BACKUP_LOG_FILE%
echo %FECHA% %HORA% >> %BACKUP_LOG_FILE%
echo Log file: %BACKUP_LOG_FILE%

OBS: El comando “echo.” solamente guarda en el log una línea vacía.

Programar ejecución

Teniendo el script, cada vez que lo ejecutemos, se generará un backup (y un log si así lo decidimos). Para que este backup se ejecute automáticamente hay que programar la ejecución del script en Windows o en Linux.

Script completo

Les dejo el contenido del script completo para que lo puedan copiar y usar como base para generarse el propio:

@echo off

for /f "tokens=1-3 delims=/- " %%a in ('date /t') do set FECHA=%%c%%b%%a
for /f "tokens=1-2 delims=: " %%a in ('time /t') do set HORA=%%a%%b

set BACKUP_FILE=Contenido_%FECHA%%HORA%.zip
set BACKUP_LOG_FILE=logs/Contenido_%FECHA%.log

echo. >> %BACKUP_LOG_FILE%
echo Inicia respaldo >> %BACKUP_LOG_FILE%
echo %FECHA% %HORA% >> %BACKUP_LOG_FILE%

7zip.exe a -tzip "c:/backups/BACKUP_FILE" "c:/Contenido/" >> %BACKUP_LOG_FILE%

echo. >> %BACKUP_LOG_FILE%
echo Fin respaldo >> %BACKUP_LOG_FILE%
echo %FECHA% %HORA% >> %BACKUP_LOG_FILE%
echo Log file: %BACKUP_LOG_FILE%