Diferencias entre isset(), empty() e is_null() en PHP

Entre las múltiples funciones que existen en PHP para testear los valores de una variable encontramos tres que resultan de gran ayuda para conocer si una variable está definida y/o es nula, que son isset(), empty() e is_null(). Rehaciendo código de alguna gente en mantenimientos o actualizaciones de proyectos me he encontrado con dos hechos:

  1. Muchos no las usan (y luego vienen los errores por usar una variable vacía)
  2. Muchos no tienen muy claro cómo y cuándo usarlas

La cosa es muy sencilla si se explica bien. Vamos a ver en qué consisten las tres, y veréis qué rápido lo entendéis:

  • isset(): Determina si una variable ha sido definida y no es nula. Devuelve FALSE en caso de le pasemos una variable sin definir, una variable definida pero sin valor o con el valor puesto a null, y en el resto de casos devuelve TRUE.
  • empty(): Determina si la variable tiene un valor vacío, por llamarlo de alguna forma. En este caso devuelve TRUE en muchos supuestos: una cadena vacía (es decir «», si es una cadena con un espacio en blanco tal que » » devolverá FALSE), un número 0 (sea tanto un entero, un float o una cadena con el número cero tal que «0»), una variable con el valor FALSE, una variable con el valor NULL, una variable definida pero sin valor y un array vacío. Al contrario que isset(), no puede evaluar variables que no hayan sido definidas.
  • is_null(): En cierto modo es la complementaria a isset(), ya que devuelve TRUE en caso de que la variable sea NULL o que sea una variable definida pero sin valor, y en el resto de los casos FALSE. La diferencia es que no puede evaluar variables que no estén definidas, provocará un error.

Como podéis ver no es especialmente complicado comprender el funcionamiento de estas tres funciones, y su uso os salvará de muchos quebraderos de cabeza. Por ejemplo trabajando con variables pasadas por formularios o recogidas de una tabla de base de datos que acepte nulos, que todavía hay gente que va a lo loco, así, sin comprobación ni condón… y luego vienen las rupturas en el código.

Envío masivo de email a lista de contacto con PHPMailer

Seguimos con el PHPMailer tras la introducción y la entrada sobre usar Gmail. Ahora, y recordando un poco el ejemplo de cómo automatizar acciones con cURL, vamos a ver la forma de enviar un correo a una lista de direcciones guardada en una base de datos.

La idea es simple, si recordáis cómo era el script de php de los anteriores ejemplos todo consiste en hacer lo mismo pero con una llamada a la base de datos y un bucle de envíos. En el ejemplo de abajo ya podéis ver el código, explicado punto por punto. en este caso no voy a usar el ejemplo que viene en los docs de la librería, porque está anticuado, usando mysql en lugar de mysqli (es más, creo que lo voy a subir a GitHub):

<?php
//lo primero cargar la librería
require '../PHPMailerAutoload.php';
//lo segundo, crear el objeto mail
$mail = new PHPMailer();
//Vamos a meter el cuerpo (cargado desde un html externo) en una variable
$body = file_get_contents('contents.html');
//definimos el uso de smtp
$mail->isSMTP();
//definimos el servidor que aloja nuestro correo
$mail->Host = 'smtp.tuserver.com';
//activamos la autenticación smtp
$mail->SMTPAuth = true;
//Con esta línea dejamos abierta la conexión al servidor smtp
$mail->SMTPKeepAlive = true; 
//Definimos la seguridad, si nuestro server lo permite lo mejor es usar tls
$mail->SMTPSecure = 'tls';
//el puerto cambia según la seguridad. Para tls este, para ssl 456 y sin seguridad el 25
$mail->Port = 587;
//definimos usuario y contraseña
$mail->Username = 'tucorreo@tudominio.com';
$mail->Password = 'tu contraseña';
//ahora definimos remitente y si hace falta, réplica
$mail->setFrom('miwebe@midominio.com', 'Lista');
$mail->addReplyTo('miwebe@midominio.com', 'Lista');

$mail->Subject = "Ejemplo de lista con phpmailer";

//Vamos ahora a crear un objeto de conexión a la base de datos
//Tras eso, vamos a recuperar los datos que necesitamos:
$mysqli = new mysqli('server', 'username', 'password', 'db');
$mysqli->set_charset("utf8")
$result = $mysqli->query("SELECT nombre, email FROM mailinglist");

//ahora en bluce vamos recorriendo los resultados y enviando correos

while ($row = $result->fetch_array()) {
    $mail->AltBody = 'Para ver el menasje, please use un  visor de email compatible con HTML';
    $mail->msgHTML($body);
    $mail->addAddress($row['email'], $row['nombre']);
    
    if (!$mail->send()) {
        echo "Mailer Error:" . $mail->ErrorInfo . "<br />";
        break; //forzamos la salida del bucle en caso de error
    } 
    // Limpiamos los datos par próximos envíos
    $mail->clearAddresses();
    $mail->clearAttachments();
}

Como podéis ver no es demasiado complejo gestionar una lista de correo desde PHP y MySQL.

Display inline-block en Explorer 6, Explorer 7 y Explorer 8

Si maquetáis web es posible que utilizáseis alguna vez la propiedad display:inline-block en vuestro CSS a la hora de posicionar divs o elementos de lista, ya que funciona de una forma muy cómoda. ¿Problemas de usarla? Que en en las versiones anteriores a Explorer 8 no va (este inclusive).

Actualmente, por suerte, casi nadie tiene Explorer 7 (y menos Explorer 6) y los que queden se irán al guano cuando Microsoft deje de dar soporte a XP en 2014, pero todavía hay varios Windows Vista con Explorer 8 rulando por ahí, además también hay administraciones, clínicas o empresas con equipos arcaicos y sin actualizar. ¿Solución? Algunos te dirán «no la uses»… pues no, hay un simple hack, que podéis ver en el ejemplo:

elementoAPosicionar {
    display: inline-block;
    *display: inline;
    zoom: 1;
}

Con esto usamos un Safe CSS Hack para que IE7 interprete bien nuestro CSS. Otra posibilidad es que no funcione por culpa de la declaración del DOCTYPE (Explorer es muy puñetero). Si pasáis de Explorer 7 y sólo os preocupa el 8, basta añadir esto al principio del archivo HTML:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

Y creo que si lo declaráis como HTML5 con esta cabecera también funciona:

<!DOCTYPE html>

Por suerte a partir de Explorer 9 muchas de estas cosas se han ido estandarizando, y de momento en Explorer10 lo único que me ha fallado ha sido una animación CSS3, lo cual respecto a hace años es un enorme avance para los chicos de Microsoft. Igual en IE12 ya no hace falta hacer un CSS específico para Explorer.

Enviar un email con PHPMailer usando una cuenta de Gmail

Ya hace un tiempo hablamos aquí de cómo enviar correos desde un script de php usando PHPMailer. He decidido hacer una serie de artículos ampliando un poco más el tema.

Una cuestión que puede ser interesante, sobre todo para aquellos que a lo mejor están en un hosting gratuito y no tienen cuentas de correo vinculadas a su dominio, es utilizar una cuenta de Gmail para enviar los correos. Ya que Gmail nos permiter usarlo como cualquier otro correo SMTP esto es factible.

Configurar PHPMailer para usar Gmail es simple, y podéis ver cómo se haría en el siguiente ejemplo (va comentado línea a línea):

/*Lo primero es añadir al script la clase phpmailer desde la ubicación en que esté*/
require '../class.phpmailer.php';

//Crear una instancia de PHPMailer
$mail = new PHPMailer();
//Definir que vamos a usar SMTP
$mail->IsSMTP();
//Esto es para activar el modo depuración. En entorno de pruebas lo mejor es 2, en producción siempre 0
// 0 = off (producción)
// 1 = client messages
// 2 = client and server messages
$mail->SMTPDebug  = 0;
//Ahora definimos gmail como servidor que aloja nuestro SMTP
$mail->Host       = 'smtp.gmail.com';
//El puerto será el 587 ya que usamos encriptación TLS
$mail->Port       = 587;
//Definmos la seguridad como TLS
$mail->SMTPSecure = 'tls';
//Tenemos que usar gmail autenticados, así que esto a TRUE
$mail->SMTPAuth   = true;
//Definimos la cuenta que vamos a usar. Dirección completa de la misma
$mail->Username   = "tucuenta@gmail.com";
//Introducimos nuestra contraseña de gmail
$mail->Password   = "tucontraseña";
//Definimos el remitente (dirección y, opcionalmente, nombre)
$mail->SetFrom('tucuenta@gmail.com', 'Mi nombre');
//Esta línea es por si queréis enviar copia a alguien (dirección y, opcionalmente, nombre)
$mail->AddReplyTo('replyto@correoquesea.com','El de la réplica');
//Y, ahora sí, definimos el destinatario (dirección y, opcionalmente, nombre)
$mail->AddAddress('destinatario@sucorreo.com', 'El Destinatario');
//Definimos el tema del email
$mail->Subject = 'Esto es un correo de prueba';
//Para enviar un correo formateado en HTML lo cargamos con la siguiente función. Si no, puedes meterle directamente una cadena de texto.
$mail->MsgHTML(file_get_contents('correomaquetado.html'), dirname(ruta_al_archivo));
//Y por si nos bloquean el contenido HTML (algunos correos lo hacen por seguridad) una versión alternativa en texto plano (también será válida para lectores de pantalla)
$mail->AltBody = 'This is a plain-text message body';
//Enviamos el correo
if(!$mail->Send()) {
  echo "Error: " . $mail->ErrorInfo;
} else {
  echo "Enviado!";
}

Esencialmente es casi lo mismo que viene en los DOCS que acompañan a los archivos, pero traducido.

Espero que os sirva. Próximamente más PHPMailer, y más programación web.

Automatizar la ejecución de scripts PHP en servidores Linux con cron y cURL

En el pasado ya hablamos en este blog de automatizar tareas en MySQL y de hacer uso de cURL para procesar formularios y enviarlos a un servicio web REST. ¿Y si os digo que cURL también se puede usar para atomatizar la ejecución de scripts PHP?

Seguro que más de una vez has pensado «Molaba que mi página enviara un correo a todos aquellos usuarios que están de cumpleaños» o cosas así. Puedes pensar que da mucho la vara, pero para nada. No sé si lo comenté la otra vez, pero cURL además de poder ser usado desde PHP también puede ser llamado desde la línea de comandos, así que nos permite, desde una consola, llamar a un script de php por protocolo http (bueno, de hecho cURL puede usar varios protocolos como FTP, FTPS, HTTP, HTTPS, GOPHER, TELNET, DICT, FILE o LDAP) para que se ejecute. Ahora a esto súmale que en un servidor Linux tenemos cron, que nos permite automatizar tareas, como la ejecución de archivos. Solución: programamos que cron ejecute la la llamada a nuestro script de PHP mediante cURL todos los días a una hora concreta.

Veamos un ejemplo en el que ejecutamos un script llamado cumple.php (imagináos que sea un script que felicita el cumpleaños a los usuarios de nuestra web, nos da igual el contenido del script, aquí la clave es automatizar la llamada) todos los días un minuto después de medianoche. Basta con editar el fichero de cron (por ejemplo con crontab -e) y añadir esta línea:

1 0 * * * /usr/bin/curl http://alojamiento/miweb/cumple.php

Bueno, el primer parámetro es el minuto, el segundo la hora y luego irían día del mes, mes y día de la semana (que en este caso van con * porque queremos que sea todos los días, no un día en concreto). Tras los parámetros temporales metemos la orden a ejecutar. En este caso llamamos a cURL (que suele estar en la carpeta /usr/bin/) seguido de la dirección donde esté el script para que sea llamado por protocolo http.

Para mis info sobre cURL puedes buscar aquí, y sobre cron mismamente te ayuda la Wikipedia.

Procedimientos almacenados con parámetros variables en el WHERE

Me excusaba ayer en Twitter, tengo un nuevo empleo y menos tiempo para escribir en el blog. No os preocupéis, que no lo dejaré de lado pero sí es cierto que el ritmo de publicaciones bajará un poquillo. Pero lo bueno de tener un nuevo trabajo es que al afrontar nuevos retos tengo material para nuevos artículo sobre programación (aparte de lo de cobrar regularmente a fin de mes y hacer currículum).

Y una cosa con la que estoy trabajando estos días mucho es con procedimientos almacenados en MySQL. Hoy se me planteada una cuestión, que era un procedimiento que recibe varios parámetros desde un formulario en PHP (para otro día dejo «Llamar a procedimientos almacenados desde PHP») para realizar una búsqueda. El problema: hay parámetros que pueden ir vacíos, ya que el usuario puede estar buscando por todos o por uno. Y el procedimiento almacenado no permite definir parámetros opcionales, como sí podría hacer en una función de PHP. ¿Solución? Simple y fácil.

Lo primero es pasar todos los parámetros que no están definidos al procedimiento con valor NULL. Lo siguiente es que cada comparación que se haría en el WHERE ahora formará parte de un OR donde también comprobamos si el parámetro enviado es nulo. Esto que suena a churro se explica fácilmente con un supuesto y un ejemplo de código:

Imaginemos que queremos hacer una búsqueda en una lista de, por ejemplo, alumnos de un centro. Podemos buscar por nombre, apellidos y un máximo y un mínimo de edad. Bueno, pues el procedimiento sería algo así:

DELIMITER $$ --esto para no tener conflicto con el punto y coma, puede valer otra opción
CREATE PROCEDURE ps_BusquedaVarParam(IN nombre_in varchar(30), apellidos_in varchar(50), minEdad int, maxEdad int)
BEGIN
  SELECT * FROM alumnos WHERE (nombre_in is null or Nombre = nombre_in) and (apellidos_in is null or Apellidos = apellidos_in) and (minEdad is null or Edad>=minEdad) and (maxEdad is null or Edad<=maxEdad);
END $$
DELIMITER;

La idea de hacer así este tipo de comparación es que si le pasamos un nulo la comparación con null devolverá TRUE. De esa forma si es NULL devuelve TRUE, si se da la condición también devuelve TRUE y si no es nulo pero no comple devuelve FALSE. O lo que es lo mismo, si va un NULL te devuelve TRUE y así ese parámetro no te jode que se cumple el AND de la comparativa. Así logramos que no haya problema para hacer la búsqueda sin mandar todos los parámetros.

Y listo, tranquilos, irán más espaciados, pero seguirá habiendo movimientos en este blog. Y de calidad, como siempre.

Ojo a los nombres de variables, por cierto. Si el parámetro tiene el mismo nombre que el campo, aunque uno esté en mayúsculas y otro en minúsculas, fallará. En teoría debería no dar problemas, pero dependiendo de la configuración de MySQL puede fallar o no (de hecho tuve que modificar la consulta, porque en una base de datos me funcionaba pero en otra fallaba), así que mejor les añadís a las variables un prefijo o sufijo y vía (en este caso le puse _in)

Descargar magnet links con Firefox en Ubuntu

Es habitual, en sitios como The Pirate Bay, encontrar Magnet Links para descargar los torrents. La mayoría de los clientes de torrent funcionan con este tipo de enlaces, pero los navegadores no los interpretan, al clickar en principio no saben qué hacer, no los descargan automáticamente. Sólo necesitas seguir una serie de pasos simples para poder arreglar esto:

Lo primero, en Firefox, escribes about:config en la barra de direcciones. Te va a dar un aviso, acepta. Haciend click derecho tienes un menú donde eliges Nuevo->Booleano.

Configurar Firefox descargar magnet links
Insertando el nombre

Como ves en la foto te pedirá un nombre, le pones network.protocol-handler.expose.magnet y tira p’alante. Luego te pedirá un valor, le metes False. El ponerlo como False hará que Firefox pregunte qué software se utilizará. Generalmente los clientes de P2P están en la carpeta /usr/bin así que mirad alli y seleccionad. Por defecto Ubuntu ya trae preinstalado el cliente Transmission, pero podéis buscar otro si no os gusta, hay múltiples opciones.

Eliminar Globososo.com de nuestro equipo

Etos tres últimos días he visto que he recibido varias visitas a través de Globososo.com, lo cual me ha hecho pensar «debe ser un browser-hijacker y seguro que más de un lector se lo quiere cargar«. El adware últimamente prolifera mucho, así que como siempre os digo, ojito cuando instaláis cosas, leed bien los mensajes que os da el instalador porque este coñazo de software suele instalarse como si fuera software legítimo.

En todo caso lo primero es iros al Panel de Control de Windows, a Eliminar Programas y allí lo desinstaláis. Si no os deja porque «está en uso» (o alguna milonga similar) pues Ctrl+alt+supr y allí matáis el proceso (creo que se llama Globososo.exe). Ahora hay que quitarlo de los navegadores. Ahí «asegún», porque depende del que tengáis:

  • Mozilla Firefox: Tenéis que ir al menú de Ayuda. Ahí entráis en Información para Solucionar Problemas y cuando estéis dentro pulsáis el botón gordo de Restablecer Firefox.
  • Google Chrome: Primero te vas a Herramientas, y allí buscas Extensiones, y te fijas que no haya una herramienta de Globososo. Luego te vas a Configuración y en la sección Busca eliges de nuevo Google (o el motor de búsqueda que quieras por defecto).
  • IE: Vas a Herramientas/Opciones de Internet. Ahí vas a la pestaña de Opciones Avanzadas y pulsas Restablecer. Te dará unos warnings de que se van a borrar tus configuraciones personales. En fin, mala suerte pero al carajo se van.

Ok, ya tienes limpios los navegadores, pero todavía no hemos acabado. Ahora toca hacer varias cosas. La primera es que te descargues el AT-Destroyer que de buen rollo nos proporcionan los colegas de Infospyware. Lo siguiente es que hagas lo mismo con Adwcleaner y de terceras me metéis también en el pack el CCleaner. Los instaláis, desconectáis vuestro antivirus habitual (ya lo pondréis a andar de nuevo cuando la cosa esté acabada, pero si lo tenéis activado durante la limpieza es posible que provoque conflictos con las herramientas que vamos a usar), reiniciáis y, durante el reinicio, pulsáis F8 hasta que os salga el menú donde podéis seleccionar «Iniciar en Modo Seguro».

Una vez en modo seguro lo primero es que lancéis el AT-Destroyer antes descargado. Le pulsáis a Search and Destroy y esperáis. Cuando acabe os pedirá reiniciar. Obedeced.

Tras este nuevo reinicio ejecutáis Adwcleaner, pulsáis Delete (o Suprimir, o Supresión, depende del idioma en que instaléis) y esperáis a que acabe. Cuando termine reiniciáis.

Ahora lo mejor es que paséis un antivirus en la nube, probad en este caso con Panda Cloud, aunque si tenéis otro preferido también valdrá. El caso es comprobar que no haya nada raro por el equipo.

Y para finalizar, como siempre desinstaláis todo lo que habéis necesitado para la limpieza, y ejecutáis CCleaner  para limpiar coockies y basurillas varias, y de paso ponéis un poco en orden el registro.

Con esto Globososo debería ser historia en vuestro equipo.

Convertir m4a a mp3 en Ubuntu y Mint (o a ogg, FLAC…)

De vez en cuando acaba en mi disco duro alguna carpeta con archivos de audio en m4a (debe haber mucha gente con iCacharros por el mundo). Problema 1, mi viejo reproductor de mp3 no soporta ese formato. Problema 2, el Mixxx, que uso para pinchar, tampoco lo reconoce. En todo caso, convertir archivos de audio m4a a mp3 no es complicado.

Lo primero es iros a la consola e instalar el conversor de archivos que ya está en los repositorios:

sudo apt-get install soundconverter

Ok, all right, yeah man. Ya tienes tu programilla conversor. En el menú Preferencias podrás elegir el tipo de archivo al que quieres convertir (mp3, FLAC, ogg, opus o wav) y la calidad del mismo. Por defecto creo que convierte a ogg si no defines algo distinto.

Preferencias Soundconverter
Ventana de preferencias de Soundconverter.

Luego el procedimiento es simple. Si quieres añadir una carpeta entera pulsas el botón gordo de Añadir Carpeta, si es para archivos sueltos pulsas el de Añadir Archivo. Cuando estén cargados pulsáis Convertir. Aquí estoy a punto de convertir los temas de la primera maqueta de Mutant Squad (Reset the World) a mp3.

conversor soundconverter
Convirtiendo a mp3 Reset The World, de Mutant Squad

Y aquí están en proceso:

convertir audio soundconverter
Proceso de conversión.

Y con esto ya tenéis solucionada la cuestión de la conversión de formatos.

Detectar Internet Explorer con PHP

Es habitual que algunas versiones de Internet Explorer den la tabarra al ser un navegador que no sigue los estándares. Tranquilos, don’t worry. Podéis detectar con PHP si el navegador es Explorer y, dependiendo del resultado, mostrar una maquetación u otra. La función es simple:

<?php
$browser = getenv("HTTP_USER_AGENT");
if (preg_match("/MSIE/i", "$browser"))
{
    //Lo que toque hacer con el Explorer
}
else
{
   //El resto
}
?>

Claro que hay que reconocer que IE9 o IE10 no son tan problemáticos como las versiones anteriores ¿Y si sólo quieres descartar del 8 para abajo? Bueno, toca cambiar un poco el código, para así poder detectar el número de versión (que por suerte está casi extinto, pero todavía arreglo equipos con Internet Explorer 6):

if(preg_match('/(?i)MSIE [5-8]/',$_SERVER['HTTP_USER_AGENT']))
{
   //Aquí lo que va a hacer si es menor que 8
}
else
{
    //Aquí el resto de navegadores y explorers más nuevos.
}

En fin, si queréis sí permitir el 8 y no el 6 y el 7… bueno, pues cambiáis el rango en la expresión regular del ejemplo, y listo.