Expresión regular en PHP para validar todo tipo de urls

Esta es una expresión regular que me he encontrado hoy modificando un antiguo proyecto en PHP y que podemos usar para validar tanto direcciones de email como direcciones url, recurriendo a la función preg_match() de PHP.

/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)/

Investigando un poco he dado con el autor, o al menos con quien parece ser la primera fuente en publicar dicha expresión: Matthew O’Riordan. Aquí un link al hilo de StackOverflow donde lo explica.

Cómo hacer un Hello World! en distintos lenguajes de programación.

El Hello World es un ejercicio básico de programación. Casi en cualquier lenguaje de programación que estudies empezarás en la primera lección programando uno. Aquí te dejo diversos ejemplos en distintos lenguajes
, lo que además te permitirá ver algunas de las pequeñas diferencias que hay entre ellos.

ASP:

Response.Write "Hello World!" 

Script de Bash:

#!/bin/bash
echo "Hello, World!" 

C:

#include 
main(){
  printf ("Hello World!\n");
}

C++:

#include 
using namespace std;
void main(){
  cout << "Hello World!" << endl;
}

C#:

using System;
namespace HelloWorld
{
    class Hello 
    {
        static void Main() 
        {
            Console.WriteLine("Hello World!");            
        }
    }
}

Java:

class hellWorldJava{
  public static void main(String args[]){
    System.out.println("Hello World!");
  }
}

Javascript:

window.alert( 'Hello, world!' );

Objective C:

#import 

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
    }
    return 0;
}

Perl:

#!/usr/bin/perl
print “Hello World.\n”;

PHP:

echo "Hello World!";

Script de Powershell:

$strString = "Hello World"
write-host $strString

Python:

print "Hello, World!"

R:

print("Hello World!", quote = FALSE)

Ruby:

puts 'Hello world'

jQuery: enviando un formulario con ajax

No sabía sobre qué escribir, pero esta semana me preguntaron por esto así que puede ser cosa buena contarlo también por aquí.

Bueno, el primer punto a tener en cuenta es que jQuery nos ofrece varios métodos para realizar envío por ajax: el método post() (que hace una petición por post), el método get() (lógicamente por get) o el método ajax(). Para este ejemplo usaremos este último.

jQuery, por otra, parte nos permite no enviar todo el formulario sino sólo una lista de valores que podemos coger nosotros de los campos para, por ejemplo, realizar validaciones que necesiten consultas del lado del servidor. Pero para el ejemplo enviaremos todo el formulario.

En este caso vamos a suponer que tenemos un formulario con el id formulario que tenemos que enviar a una página llamada procesa.php, que a su vez nos devuelve una cadena de texto informándonos del éxito de la operación. La acción del envío se activa cuando hacemos click sobre un elemento con el id enviar. Sobre la cabecera de nuestro formulario hay un div con el id resultado donde podemos informar al usuario del resultado de su envío. Vamos entonces con el código jQuery:

<script type="text/javascript">   
$(function(){
  $("#enviar").click(function(){
    $("#resultado").html("<p id='enviando'>Enviando datos</p>");
    $.ajax({
      method: "POST",
      url: "procesa.php",
      data: $("#formulario").serialize()
    })
    .done(function( msg ) {
      $("#enviando").hide();
      $("#resultado").html("Formulario enviado:" + msg);
    })
    .fail(function() {
      $("#enviando").hide();
      $("#resultado").html("Se ha producido un error y no se han podido procesar los datos");
    })
  });
});
</script>

PHP: ¿Cómo saber si una variable existe?

Situación clásica en PHP: En una página tengo que mostar tal o cual resultado si una variable tiene un valor concreto, pero además existe la posibilidad de que dicha variable no exista. ¿Cómo evito que me salte un mensaje de error si esta viene vacía? Pues usando el método isset().

Un ejemplo

if (isset($_GET["id"])){
     //carga los datos asociados al id
}else{
     //no carga nada
}

Ya hace tiempo explicamos aquí la diferencia entre isset(), is_null() y empty().

Subida múltiple de archivos con HTML5 y PHP

Llevaba tiempo sin tocar el PHP, sumergido en el lado del mal (aka ASP y otras cosas de Microsoft), pero el otro día tuve que retomarlo. El PHP es como ese amigo de toda la vida que por vicisitudes laborales ahora sólo puedes ver una vez cada varios meses, pero con el que te sientas en la barra de un bar y parece que todavía os visteis ayer.

El caso es que tenía que modificar un formulario para que permitiera implementar una subida de múltiples archivos. ¿Cómo va esto? Bueno, vamos con el marcado HTML:

<form action="index.php" method="post" enctype="multipart/form-data">
  <input name="upload[]" type="file" multiple="multiple" />
</form>

Puntos importantes: el enctype=»multipart/form-data» en la etiqueta form para que este envíe correctamente los archivos que subimos, el definir el nombre del input como un array poniendo los corchetes [] y la etiqueta multiple=»multiple» que nos permitirá seleccionar varios items a las vez.

Vamos ahora con el PHP con explicación línea a línea:


// RECORREMOS LOS FICHEROS
for($i=0; $i<count($_FILES['upload']['name']); $i++) {
  //Obtenemos la ruta temporal del fichero
  $fichTemporal = $_FILES['upload']['tmp_name'][$i];

  //Si tenemos fichero procedemos
  if ($fichTemporal != ""){
    //Definimos una ruta definitiva para guardarlo
    $destino = "./nuestraCarpeta/" . $_FILES['upload']['name'][$i];

    //Movemos a la ruta final
    if(move_uploaded_file($fichTemporal, $destino)) {
       //imprimimos el nombre del archivo subido
       printf("Se ha subido el fichero %s.",$_FILES['upload']['name'][$i]);
    }
  }
}

Código PHP para comprobar si un servidor está funcionando o caído.

Estaba los día pasados liado con un desarrollo en PHP para uso interno en la oficina que requería que, en un punto dado, el código recogiera qué servidores de los clientes están activos y cuales no.

Tras sucesivas búsquedas y documentación llegué a dos soluciones. Esta primera lo que haría sería mostrarnos si en una máquina está funcionando el servidor web:

/*La función recibe la ip
o la url del servidor*/
function testServidorWeb($servidor) {
    $a = @get_headers($servidor);
    
    if (is_array($a)) {
        return true;
    } else {
        return false;
    }
}

En este primer ejemplo creamos una función que recibe o la ip externa o la url del servidor que queremos comprobar que tiene su servidor web funcional. Dicha función hará una petición HTTP al servidor y recogerá las cabeceras de la respuesta con get_headers. En caso de que haya recibido la respuesta la función devuelve true, y si no ha habido respuesta alguna entonces devuelve false.

En el segundo ejemplo tenemos una función que comprueba si se recibe respuesta desde un puerto concreto. Así podemos comprobar varios servicios como el servidor web, el servidor ftp, la conexión por telnet…

function checkPuerto($dominio,$puerto){
    $starttime = microtime(true);
    $file      = @fsockopen ($dominio, $puerto, $errno, $errstr, 10);
    $stoptime  = microtime(true);
    $status    = 0;
 
    if (!$file){    
        $status = -1;  // Sitio caído
    } else {
        fclose($file);
        $status = ($stoptime - $starttime) * 1000;
        $status = floor($status);
    }
    
    if ($status <> -1) {
        return true;
    } else {
        return false;
    }
    
}

En este caso le enviamos a la función el dominio del servidor a probar y el puerto que queremos chequear, sirviéndonos de la función fsockopen de PHP. Ojo si queréis comprobar los sockets UDP, que podéis recibir un falso positivo debido a que UDP es un protoclo «sin conexión» (en el enlace a fsockopen ya hay un aviso donde lo explican).

El patrón Observer y su implementación en PHP

Volvemos con el tema de los patrones de diseño y PHP, que estaba abandonado (y ahora tengo más tiempo para escribir con el parón temporal del podcast). Esta tarde vamos a hablar del patrón Observer, que en castellano es conocido como el patrón publicación-inscripción.

La idea de este patrón es que nos permita definir una dependencia uno-a-muchos entre varios objetos, provocando que cuando uno cambie de estado se lo notifique a sus objetos dependientes. El objetivo de este patrón es reducir el acoplamiento entre clases que requieren mantener una gran consistencia en sus relaciones, siendo clave para la implementación del patrón MVC. Dentro de esta relación denominamos Sujeto al objeto que emite la información sobre el cambio de estado, y Observador al que la recibe para realizar la acción que sea necesaria.

Os dejo esta imagen con un diagrama cargado desde la Wikipedia para ilustrar su funcionamiento:

Diagrama Estructura Patrón Observer
Un diagrama de estructura del patrón Observer (publicación-inscripción).

En PHP 5, a partir de la revisión 5.1 contamos con las interfaces SplSubject y SplObserver para implementar respectivamente el sujeto y el observador.

Vamos con un ejemplo clásico: una tienda on-line que notifica la compra y la venta de un artículo.

<?php
class Articulo implements \SplSubject /*Empezamos importando la interfaz del sujeto*/
{
    protected $storage;

    public function __construct(\SplObjectStorage $storage)
    {
        $this->storage = $storage;
    }

    public function compra()
    {
        // compra
        $this->notify('comprado');
    }

    public function vende()
    {
        // vende
        $this->notify('vendido');
    }

    public function attach(\SplObserver $observer)
    {
        $this->storage->attach($observer);
    }

    public function detach(\SplObserver $observer)
    {
        $this->storage->detach($observer);
    }

    public function notify($event = '')
    {
        foreach ($this->storage as $observer)
            $observer->update($this, $event);
    }
}

class Notify implements \SplObserver /*seguimos con lai implementacion del observer*/
{
    public function update(\SplSubject $subject, $event = '')
    {
        if ($event == 'comprado')
            echo 'El artículo se ha comprado' . PHP_EOL;
        else if ($event == 'vendido')
            echo 'El artículo se ha vendido' . PHP_EOL;
    }
}

/*¿Cómo luciría llevado a la práctica?*/

/*Creamos el objeto*/
$articulo = new Articulo(new \SplObjectStorage());
/*vinculamos el artículo al observer*/
$articulo->attach(new Notify()); 
/*imprimiría en pantalla que se ha comprado*/
$articulo->compra();
/*imprimiría que se ha vendido*/ 
$articulo->vende(); 
?>

Es una idea básica donde simplemente se imprime en pantalla el resultado de una acción, pero ya os hacéis una idea de las posibilidades de este patrón.

Llamar a procedimientos almacenados en PHP

Una entrada que llevaba mucho tiempo en el TODO list, sobre trabajar con procedimientos almacenados con PHP.

Para empezar vamos a plantear un escenario en el que tenemos tres procedimientos almacenados en MySQL (dos selects y un insert) contra una tabla llamada productos, que tiene tres campos (id como clave primaria, descripcion con una descripción del producto, precio con un valor numérico decimal).

El SP de la primera select, que nos devuelve la descripción y el precio del producto según su id, sería este:

CREATE PROCEDURE getProducto(IN id_val INT) 
  BEGIN 
    SELECT descripcion, precio from productos WHERE id = id_val; 
  END;

El SP de la segunda select, que nos devuelve la descripción y el precio todos los productos, por lo que no recibe parámetros:

CREATE PROCEDURE getAllProductos() 
  BEGIN 
    SELECT descripcion, precio from productos ; 
  END;

Y el sp del insert sería este, al que le pasamos los tres valores a meter:

CREATE PROCEDURE addProducto(IN id_val INT,descripcion_in varchar(50), precio_in float) 
  BEGIN 
    INSERT INTO productos VALUES (id_val, descripcion_in, precio_in);
  END;

Bueno, ya tenemos nuestro escenario, entonces ¿cómo hacemos para llamar a estos procedimientos desde nuestro código php? Pues simplemente lanzamos una consulta en la que llamamos a la instrucción CALL de MySQL para que ejecute el procedimiento almacenado que le digamos con los parámetros que tocan.

/*Empezamos con el procedimiento de inserción*/
/*Lo primero es crear un objeto mysqli*/
$mysqli = new mysqli("servidor", "usuario", "pass", "db");

/*Y llamamos al procedimiento para hacer la inserción*/
/*Si falla imprimimos el error*/
if (!$mysqli->query("CALL addProducto(1001, 'Nueces de Macadamia', 12.23)")) {
    echo "Falló la llamada: (" . $mysqli->errno . ") " . $mysqli->error;
}

La propia función query del objeto mysqli nos devolverá TRUE si no viene con errores y FALSE si pasa algo inesperado.

¿Y qué pasa con la recuperación de datos? Ahí nos vamos a un terreno más pantanoso. Para una consulta con un solo resultado no es problema:

/*Empezamos con el procedimiento de recuperación de una fila*/
/*Lo primero es crear un objeto mysqli*/
$mysqli = new mysqli("servidor", "usuario", "pass", "db");

/*Y llamamos al procedimiento para recoger los datos*/
/*Si falla imprimimos el error*/
if (!($res = $mysqli->query("CALL getProducto(1001)"))) {
    echo "Falló la llamada: (" . $mysqli->errno . ") " . $mysqli->error;
}

/*E imprimimos el resultado para ver que el ejemplo ha funcionado*/
var_dump($res->fetch_assoc());

Pero claro, en este caso podemos hacerlo así porque esperamos un solo resultado, pero si esperamos varias filas la cosa es distinta ya que mysqli->query() devuelve sólo el primer conjunto de resultados. Tenemos dos alternativas para esta situación: mysqli_real_query() o mysqli_multi_query(). En el ejemplo usaremos la segunda, y veremos también la forma de recorrer este resultado:

/*Empezamos con el procedimiento de recuperación de una fila*/
/*Lo primero es crear un objeto mysqli*/
$mysqli = new mysqli("servidor", "usuario", "pass", "db");

/*Y llamamos al procedimiento para recoger los datos*/
/*Si falla imprimimos el error*/
if (!$mysqli->multi_query("CALL getAllProductos()")) {
    echo "Falló la llamada: (" . $mysqli->errno . ") " . $mysqli->error;
}

/*Ahora con este bucle recogemos los resultados y los recorremos*/
do {
    /*En el if recogemos una fila de la tabla*/
    if ($res = $mysqli->store_result()) { 
        /*Imprimimos el resultado de la fila y debajo un salto de línea*/
        var_dump($res->fetch_all());
        printf("\n");
        /*La llamada a free() no es obligatoria, pero si recomendable para aligerar memoria y para evitar problemas si después hacemos una llamada a otro procedimiento*/
        $res->free();
    } else {
        if ($mysqli->errno) {
            echo "Store failed: (" . $mysqli->errno . ") " . $mysqli->error;
        }
    }
} while ($mysqli->more_results() && $mysqli->next_result());
/*El bucle se ejecuta mientras haya más resultados y se pueda saltar al siguiente*/

Añadiré a esto que también es posible utilizar las llamadas a procedimientos almacenados usando sentencias preparadas, procediendo del modo habitual a la hora de pasar los parámetros.

Cambiar la contraseña de la base de datos en Prestashop

Pongámonos en situación: has cambiado la contraseña de la base de datos de MySQL que usabas para tu instalación de Prestashop. Con el cambio verás que tu vieja instalación no funciona, ¿solución? Cambiar la configuración de la contraseña. ¿Cómo? Con los siguientes pasos:

  • Busca la carpeta config.
  • Busca en dicha carpeta el archivo settings.inc.php.
  • En ese archivo busca las líneas BD_USER y DB_PASSWD, ahí tienes definidos los nombres de usuario y las contraseñas, basta con cambiarlos ahí

Y con esto ya está la cosa listas para funcionar otra vez.

Instalando la librería GD de php en IIS

Esta mañana preparaba una instalación de Prestashop en un servidor Windows. Ya había hecho varias en el pasado, pero siempre en entornos Apache-Linux, jamás en Windows con IIS. Supuse que no podría ser muy distinto.

La primera en la frente: PrestaShop me pide la librería de funciones de imágenes GD en el servidor, (y un par más, pero el procedimiento es el mismo) que no está instalada. ¿Qué toca?

Lo primero, abrir el php.ini, buscar la línea ;extension=php_gd2.dll y quitarle el ; para descomentarla. Si por lo que fuera esa línea no existe simplemente la metéis a mano. Luego o hacéis una copia del php.ini en la carpeta C:\Windows o creáis un enlace simbólico desde allí al archivo, cualquiera de las dos opciones vale.

Siguiente paso: dentro de la carpeta PHP buscáis la carpeta ext y allí mirad si está el archivo php_gd2.dll y, en caso afirmativo, lo copiáis al mismo directorio en el que tenéis el php.ini. En caso de que no esté allí (mirad bien, debería estar) debéis descargarla.

Tras estos sencillos pasos ya tenéis GD instalada en vuestro servidor PHP Windows con IIS.