Archivo de la categoría: Programación

curl_setopt(): CURLOPT FOLLOWLOCATION cannot be activated when an open_basedir is set

[programación]

El mensaje de error completo es este:

Severity: Warning
Message:  curl_setopt(): CURLOPT_FOLLOWLOCATION cannot be activated when an open_basedir is set
Filename: src/Mandrill.php
Line Number: 68

Este es un problema conocido de la API PHP de Mandrill, y existe un Pull Request con la solución creado en abril de 2014, pero por el motivo que sea, no han añadido la corrección al repositorio principal.

Yo utilizo Composer y Packagist para gestionar las dependencias en mis proyectos, por lo que como solución temporal puedes modificar el fichero Mandrill.php con las correcciones, pero esto significa repetir el mismo proceso en todos los entornos de desarrollo, y es fácil olvidarse de hacerlo cuando han pasado unos meses.

Como solución más robusta, he creado un fork the la librería de Mandrill, y la he subido a Packagist para que pueda ser usada. Es tan sencillo como añadir esto a tus “require” en el composer.json:

"carlos_llongo/mandrill": "dev-master"

O también puedes usar:

composer require "carlos_llongo/mandrill:dev-master"

Guardar una cookie con JavaScript puro

[programación]

AngularJS tiene un módulo para guardar cookies, pero por desgracia no permite establecer la fecha de expiración de la cookie, por lo que la cookie es borrada al final de la sesión.

Hay plugins para AngularJS y para JQuery que permite crear cookies de forma sencilla y establecer la fecha de expiración, pero no quería añadir una libraría más solo para guardar una cookie. Así que esta es la forma de hacerlo usando únicamente JavaScript puro:

var dExpirationDate = new Date();
dExpirationDate.setTime(dExpirationDate.getTime() + (365*24*60*60*1000));
var sExpirationDate = "expires=" + dExpirationDate.toUTCString();
document.cookie = "cookieName=cookieValue; " + sExpirationDate;

Cómo saber cuando se actualizó una web por última vez

[internet] [programación]

Evidentemente esto solo funcionará en páginas estáticas, pero más de una vez me he encontrado con alguna librería de PHP o JQuery que no mostraban ninguna fecha de última actualización en su web. Para esas situaciones, podemos abrir el Firebug y en la consola escribir lo siguiente:

javascript:alert(document.lastModified)

Saltará una alerta con la fecha de la última modificación.

Comprobar si existe un elemento con AngularJS y ejecutar una función solo si existe

[programación]

Esta es la situación: Queremos ejecutar un plugin de JQuery sobre un elemento que se crea dinámicamente con un ng-repeat dentro una plantilla de AngularJS. Es decir, no podemos inicializar el plugin hasta que se ha cargado la plantilla y se han creado los elementos.

Tenemos un controlador específico para dicha plantilla, por lo que realizando la comprobación aquí, solucionamos la primera parte del problema. Investigando un poco, veo que la solución más popular es asignar una directiva al ng-repeat, que detectará cuando se ejecute la última iteración y lanzará un evento para ser recogido por el controlador, y entonces ya podríamos ahí ejecutar el plugin.

En Stackoverflow tenemos un ejemplo de esta aproximación, y en Nodewiz.biz tenemos otro ejemplo muy similar.

El caso es que esta aproximación me parece tremendamente rebuscada, aunque no dudo que cumple con el espíritu de AngularJS. Mi aproximación es más sencilla, aunque sospecho que no es del todo correcta, y me gustaría mejorarla con el tiempo:

$scope.bTooltipsterExists = false;

$scope.$watch(
function(){
    if(angular.element('.tooltipster').length){
        $scope.bTooltipsterExists = true;
        return true;
    }

    return false;
},
function(){
    if($scope.bTooltipsterExists){
        $(".tooltipster").tooltipster({
            trigger: 'click',
            delay: 0
        });
    }
});

Básicamente tengo un $watch que lo que hace es observar una función. Esta función busca los elementos que se crearán con el ng-repeat y tendrán la clase .tooltipster. La segunda función es la que se ejecuta cuando hay un cambio en el valor devuelto por la primera función. Es decir, cuando la primera función pase de devolver false a devolver true, se ejecutará el plugin.

Añado una segunda comprobación con la variable $scope.bTooltipsterExists porque la primera vez que se ejecuta el $watch, como no tiene una variable de referencia anterior, siempre se ejecuta la segunda función, y con esto lo evitamos.

Montar un entorno de desarrollo a partir de un Git remoto

[linux] [mac] [programación]

En resumen, lo que queremos hacer es un checkout de una o varias ramas del repositorio remoto. Para ello seguimos los siguientes pasos:

1. Crear una carpeta donde tendremos nuestro entorno y entrar en ella.

2. Inicializamos el repositorio:

git init

3. Añadimos la ruta al repositorio remoto:

git remote add origin https://[usuario]@[repositorio]

4. Obtenemos las ramas/tags remotos. En este punto nos pedirá la contraseña del repositorio remoto:

git fetch

5. Hacemos el checkout de la rama con la que queramos trabajar:

git checkout develop

Y listo! A trabajar!

Instalar MCrypt en Ubuntu

[linux] [programación]

En un artículo anterior ya hable de como instalar MCrypt en Max OSX. En ubuntu el proceso también es sencillo.

1. Instalamos MCrypt:

sudo apt-get install php5-mcrypt

2. Indicamos a PHP que puede usar el módulo. Editamos el fichero php.ini:

sudo gedit /etc/php5/cli/php.ini

3. Al final de la sección de Dynamic Extensions añadimos esta línea y guardamos el fichero:

extension=mcrypt.so

¡Y ya está! Fácil 😉

phpunit con CIUnit no hace nada

[linux] [programación]

Ejecución de phpunit sin salida por consola

Este es otro claro ejemplo de problema en informática al que dedicas un montón de tiempo y te vuelves loco para resolverlo, y al final resulta ser una chorrada. El problema es el siguiente: yo hago mis tests para CodeIgniter utilizando CIUnit y en mi anterior sistema todo funcionaba (MacOSX). Cambio de sistema a un Linux Ubuntu, y cuando lanzo los tests no ocurre nada. No hay mensajes, no hay errores, no hay nada de nada.

Así que tras muchos días de pruebas, en mi desesperación me pongo a añadir mensajes de debug por todo el código de la librería CIUnit y el core de CodeIgniter para encontrar en que momento se para la ejecución, hasta llegar a esta línea:

return @mysql_pconnect($this->hostname, $this->username, $this->password);

Esta línea en el fichero /system/database/drivers/mysql/mysql_driver.php es donde salimos de CodeIgniter para entrar en el core de PHP y es donde la ejecución está fallando. Y a algún “genio” se le ocurrió que sería una buena idea silenciar los errores…

Al quitar el silencio, PHP nos informa de que no puede conectarse a la base de datos porque no tiene el driver de mysql instalado, lo cual podemos solucionar fácilmente con:

sudo apt-get install php5-mysql

Aquí dejo un listado de comandos que me han sido útiles en la resolución del problema:

Comprobar si tienes un módulo instalado:

php -i | grep nombre_del_modulo

Por ejemplo:

php -i | grep mysql

Obtener el listado de módulos que podemos instalar:

apt-cache search php5-

Instalar PHP con MCrypt en Mac OSX Mountain Lion

[programación]

En el servidor de producción no tenía ningún problema, pero al montar el servidor en local para lanzar pruebas con el PHPUnit me saltaron estos errores:

Fatal error: Call to undefined function mcrypt_encrypt

Fatal error: Call to undefined function hex2bin

El primero ocurre porque el XAMPP no trae la librería MCrypt instalada por defecto. El segundo ocurre porque la función hex2bin se incluye en PHP 5.4 y yo estaba trabajando con la 5.3. Por tanto, la solución consiste en instalar PHP 5.4 con MCrypt integrado.

La forma más sencilla de hacer esto es utilizar Homebrew. La documentación para instalarlo está en su web y es tan sencilla como copiar una línea en el terminal. Una vez instalado hacemos lo siguiente:

brew update
brew install php54-mcrypt

A continuación debemos añadir el nuevo PHP a nuestro PATH. Cuando termina la instalación, brew nos dice donde lo ha instalado, pero la ruta será similar a esta: /usr/local/Cellar/php54/5.4.28/

Abrimos el fichero .bash_profile en el directorio de nuestro usuario y añadimos estas dos líneas:

export MCRYPT_PHP=/usr/local/Cellar/php54/5.4.28/bin
export PATH="$MCRYPT_PHP:$PATH"

Reiniciamos el terminal y ya podremos utilizar PHPUnit con el nuevo PHP instalado.

CIUnit: Errores y soluciones para empezar a funcionar

[programación]

Poco a poco me voy concienciando de la importancia de realizar tests unitarios, pero entre unas cosas y otras, y siempre un poco de perrería, nunca me había dignado a montar tests unitarios con mis aplicaciones en CodeIgniter.

Por fin ayer, aprovechando un rediseño de la estructura de la aplicación, me decidí a incluir tests unitarios en CodeIgniter. Tras buscar un poco encontré una implementación para integrar PHPUnit con CodeIgniter, llamada CIUnit.

La documentación es un tanto escasa y confusa, pero tres buenos sitios donde buscar son:

Tras seguir los pasos de la instalación (en un Mac OS X Mountaion Lion), y lanzar PHPUnit desde consola, me saltaron varios errores que detallo a continuación:

Error

[CIUnit] PHP Error: Warning - require_once(PHPUnit/Autoload.php): failed to open stream: No such file or directory File Path: CIUnit/bootstrap_phpunit.php (line: 259)

Fatal error: require_once(): Failed opening required 'PHPUnit/Autoload.php' (include_path='.:') in /project_path/application/third_party/CIUnit/bootstrap_phpunit.php on line 259

Solución

Si estás usando la última versión de PHPUnit tengo entendido que no es necesario cargar ninguna librería, por lo que podemos ir al fichero bootstrap_phpunit.php y comentar o borrar la línea 259.

Error

[CIUnit] PHP Error: Notice - Undefined index: REMOTE_ADDR File Path: core/Input.php (line: 351)
PHPUnit 4.0.14 by Sebastian Bergmann.

Solución

Cuando lanzamos una aplicación PHP desde consola (en este caso PHPUnit) evidentemente no tendremos una REMOTE_ADDR, por lo que debemos añadir una comprobación.

Sustituimos:

$this->ip_address = $_SERVER['REMOTE_ADDR'];

Por lo siguiente:

if(isset($_SERVER['REMOTE_ADDR']))
    $this->ip_address = $_SERVER['REMOTE_ADDR'];
else
    $this->ip_address = '127.0.0.1';

Error

[CIUnit] Error: 500 Message: Unable to connect to your database server using the provided settings. Filename: core/Loader.php Line Number: 346

Solución

Tal como explican en esta página, no podemos usar localhost como hostname, por lo que lo cambiamos por 127.0.0.1 en application/config/testing/database.php:

$db['default']['hostname'] = '127.0.0.1';

Usar BeautifulSoup con Spyder

[programación]

He estado mirando varios IDE para Python en Mac y al final me he decidido por usar Spyder. Habría usado Ninja IDE porque ya lo he usado anteriormente en Linux y Windows y me gusta bastante, pero por algún motivo no ofrecen una versión compilada para Mac, y no tenía ganas de ponerme a hacerlo funcionar desde el código fuente, así que estoy probando Spyder.

De momento me está gustando bastante. Al menos para las cosas sencillas que estoy haciendo es suficiente. Estoy usando la librería BeautifulSoup para extraer información de páginas web y aunque la había instalado siguiendo las instrucciones en su web, al lanzar el script de Python no la estaba encontrando.

Tras investigar como utilizar BeautifulSoup con Spyder, el problema consiste en que Spyder utiliza su propio Python que trae integrado, por lo que no detecta las librerías instaladas en el Python del Mac. Para solucionarlo hay que indicar que debe usar el Python del Mac en la configuración de Spyder. Para ello vamos a:

Spyder -> Preferences… -> Console -> Advanced settings

Seleccionamos la opción Use the following Python interpreter: y en mi caso la ruta es /usr/bin/python