Blog de Israel Viana

Artículos de Mayo de 2009

El curioso método getDocComment()

29 de mayo de 2009 | 0 comentarios

Uno de los métodos de la clase ReflectionFunction del API de reflexión de PHP se llama getDocComment() y devuelve los comentarios de documentación de una función o método. Por ejemplo:

/**
 * @param   int  $a Primer sumando
 * @param   int  $b Segundo sumando
 * @return  int  Suma de $a + $b
 */
function suma($a, $b) {
    //Otro comentario
    return $a + $b;
}
	
$funcion = new ReflectionFunction("suma");
echo $funcion->getDocComment() . "\n";

El código anterior devolverá el comentario completo:

isra@isra:~$ php -f reflexion.php
/**
 * @param   int  $a Primer sumando
 * @param   int  $b Segundo sumando
 * @return  int  Suma de $a + $b
 */

Hay que recalcar que no devuelve todos los comentarios, sino sólo los de documentación. Por eso si olvidamos poner dos asteriscos al inicio, no devolverá nada:

isra@isra:~$ php -f reflexion.php

Tampoco devolverá nada si utilizamos el símbolo de comentario de una línea //:

// @param   int  $a Primer sumando
// @param   int  $b Segundo sumando
// @return  int  Suma de $a + $b
function suma($a, $b) {
    //Otro comentario
    return $a + $b;
}
	
$funcion = new ReflectionFunction("suma");
echo $funcion->getDocComment() . "\n";
isra@isra:~$ php -f reflexion.php

En fin, un método interesante que puede servir para simplificar y aumentar el rendimiento de los sistemas de documentación como phpDocumentator, y también puede ser útil en el control de errores, combinándolo con demás métodos de ReflectionFunction.

Por cierto, hablando de reflexión, aprovecho para recomendarte una interesantísima clase de Thiago Toledo para serializar objetos en XML, gracias a la reflexión de PHP5. Para que luego digan que PHP tiene una orientación a objetos de juguete.


PHP avanza

24 de mayo de 2009 | 4 comentarios
PHP 5.3 sale del cascarón

Hay novedades en el mundillo de nuestro lenguaje de programación web favorito ;-) En primer lugar, hace unas semanas se lanzó la segunda release candidate de la versión 5.3. Es muy probable que la tercera llegue en pocos días, y espero ansioso la versión final para el verano. Algunas de las novedades que se incluyen en esta versión han sido traídas de la 6 beta, ya que muchos no podíamos esperar ;-). Están destinadas principalmente a mejorar la orientación a objetos y la elegancia del lenguaje, y molan. A destacar:

  • Namespaces, para separar conjuntos de clases y poder repetir nombres. Equivalen a los pakages de Java. Eso sí, personalmente, el carácter \ elegido para separar los espacios de nombres me parece feísimo (manías que uno tiene...). Ejemplo:
    \Foo\Bar\clase::metodoEstatico()
  • Funciones anónimas: una característica que echaba de menos y que se utiliza bastante en JavaScript. Viene a sustituir la chapuza que tenían en create_function(). Ejemplo:
    
    var $sumar = function($a, $b) {
      return $a + $b;
    }
  • Type Hint para escalares: la restricción de tipos en los parámetros de las funciones estaba ya disponible para arrays y objetos desde la versión 5.1. Ahora, con PHPTypeSafe es posible restringir tipos a escalares. Esta característica es quizá la que más me gusta. Ejemplo:
    function repetir(string $cadena, int $veces) {}
  • Un driver nativo para MySQL, que sustituirá al viejo mysql y al mysqli. Se supone que será más "moderno" y rápido.

Pateando a Ruby on Rails

La otra novedad que quería comentar es la existencia de un proyecto para implementar el patrón ActiveRecord —que tan famoso ha hecho a on Rails— en PHP 5.3, precisamente. Está gestándose aún, pero promete más facilidad y rapidez de uso que los ORM que se estilan hoy en día en PHP, Doctrine (del que hablaré en breve aquí) y Propl. Ya se puede descargar la beta de su web. Espero tener tiempo para jugar un poco con él, porque promete bastante.


Los abusos de Tuenti

21 de mayo de 2009 | 0 comentarios
Tuenti

¿Alguno de los presentes tiene tuenti? O mejor dicho ¿alguien no tiene tuenti? Si es así, seguro que algún amigo le ha sugerido que se dé de alta en la red social, para poder ver sus fotos, enviarle mensajes... y poco más. Porque después de tres años, Tuenti sigue siendo tan rácano y deficiente como cuando empezó.

Hoy en día nosotros, los universitarios, nuestros hermanos pequeños y alguno de los mayores usamos Tuenti a diario, compartimos nuestras vidas, nuestros mensajes, nuestras fotos y vídeos en una plataforma lenta, insegura y con unas condiciones legales inmorales —entre otras, una clásula en la que aceptas ceder a Tuenti la propiedad de tus imágenes—.

Pero existe otro Tuenti, formado por otras personas, un poco mayores que nosotros. Es el Tuenti de los reportajes en la prensa, el de Zaryn Dentzel, presidente —al que las universidades ya le piden discursos de graduación con ese tufillo americano a "podéís conseguir todo lo que os propongáis"—, el de Enrique Dans y los demás gurús de la web 2.0 (vividores de Internet, más bien), el de los inversores, el del Grupo Prisa —que tiene una participación del 17%— y el de muchos más. Y es que amigos, cuando el río suena, agua lleva.

Hace unos meses, Enrique Dans, en su conferencia del ciclo Con-ciencia-t de la universidad, defendía el modelo de negocio de la red social como algo nuevo, benévolo y beneficioso para el usuario: publicidad discreta y ajustada al perfil del usuario (su ubicación, su edad, sus lugares de marcha...), en pequeñas dosis y presentada como parte del contenido era un gran método para que las "hermanitas" de Tuenti pudiesen mantener su servicio. Y todo esto gracias a san Zaryn, que no quería poner banners porque creía que molestaban al usuario.

Hasta aquí, habrá quien se haya creído el cuento. No obstante, este modelo publicitario es más malévolo que los banners, ya que no puedes diferenciar qué es publicidad y qué es contenido. La publicidad intrusiva manipula nuestra atención y nos confunde con eventos que parecen aceptados por nosotros pero que han sido puestos ahí por la marca de perfume o el whishky de turno.

Pero la desfachatez de los emprendedores 2.0 va más allá: los banners que antes el líder Zaryn condenaba, ahora aparecen en forma de intersticiales automáticos, o lo que es lo mismo, el anuncio de Coca-cola que aparece mientras se carga Tuenti (por cierto, ¿por qué tardará tanto en cargar?). Vaya, parece que los responsables de la red social han cambiado su comuna hippie anti-banners por una sala de reuniones llena de inversores que exigen rentabilidad —un inversor es un tipo con traje gris que se dedica a comprar almas a cambio de dinero—. Coca-cola debió pagar mucho por ese anuncio.

Y mientras tanto, nosotros, infelices usuarios, que revisamos cada día (o varias veces al día) nuestro tuenti en busca de mensajes y fotos, creemos que por no haber pagado por el servicio tenemos que aguantar la publicidad abusiva, los términos legales dictatoriales, las deficiencias técnicas y los gravísimos agujeros de seguridad (por ejemplo, todas las fotos subidas están disponibles públicamente, aunque en las preferencias de privacidad hayas elegido que sólo tus contactos puedan verlas). Sirva esto como protesta constructiva, ya que en seguida oiré a quien diga "si no te gusta, no lo uses". Pues no quiero dejar de usarlo, porque el problema no es sólo mío, sino de casi 5 millones de personas que ya están en la base de datos de esta red.


Drupal 7 será el CMS semántico

17 de mayo de 2009 | 1 comentario

Sólo una pequeña nota para informar de lo que he leído en Sitepoint sobre la nueva versión de Drupal. Si hasta ahora era de los mejores CMS (sus premios le avalan), compitiendo directamente con el "monstruo" Plone, con este movimiento, y si todo sale bien creo que se convertirá en el súper-CMS del presente y el futuro (perdona que me ponga en plan gurú-profeta amarillista).

La idea es darle a Drupal la forma necesaria para convertirse en un nodo de la web semántica, perfectamente interconectado por Web Services, REST o HTTP sin más, que sea capaz de tomar y servir información de otros nodos, permitiendo a los usuarios localizar información dentro y fuera del sitio web. Lo que no sé todavía es si el almacenamiento se mantendrá como hasta ahora, en una base de datos relacional, o por el contrario pasarán a usar una base de datos semántica. Si se diera el primer caso (y así parece, según los avances de Carlos Rincón), deberían utilizar una especie de ORM para mapear las descripciones en la BD, y seguramente esa capa fuese reutilizable más allá de Drupal (como pasó con su motor de plantillas).

Linked data en Drupal 7 (datos enlazados)

Drupal pasa dejando huella, haciendo avanzar el ecosistema de programación PHP y la web en general. Gracias y felicidades, Drupal.

PD: la imagen está alojada por Facebook Inc., hosting gratuito de imágenes. Gracias a su falta de privacidad me voy a ahorrar unos eurillos...


Facebook también hace públicas tus fotos

16 de mayo de 2009 | 1 comentario

Si en el anterior post mostraba cómo Tuenti permite hotlinking con las imágenes de sus usuarios, y que además cuando éstos solicitan la eliminación de las fotos Tuenti nos engañaba disociando la foto del álbum, hoy me he quedado helado al ver en Facebook este hecho no es un error de seguridad sino una característica que ofrecen con orgullo:

Facebook también te tima

Efectivamente, la foto es pública (solicitamos la URL desde un navegador desautenticado):

Facebook también te tima

Solicitamos eliminar la imagen...

Facebook también te tima

Facebook también te tima

...¡y la imagen sigue ahí!

Facebook también te tima

De hecho, sigue aquí: http://photos-d.ak.fbcdn.net/photos-ak-snc1/v317/176/65/1279417290/n1279417290_81363_8253.jpg. Pero ¿qué podemos hacer contra este abuso?

  • Protestar y exigir nuestros derechos, como ocurrió en aquella revuelta en Facebook.
  • Darnos de baja en Facebook intentando previamente eliminar toda la información que podamos.
  • Crear una cuenta "falsa" y utilizar Facebook y Tuenti como... ¡hosting gratis de imágenes!

Una muestra de la ilegalidad/inmoralidad de Tuenti

15 de mayo de 2009 | 0 comentarios

Como seguramente sabrás, la LOPD obliga a los prestadores de servicios a eliminar de sus archivos los datos que sus usuarios les cediesen, si así lo piden (por escrito). Es lo que se llama derecho de cancelación.

Pues bien, en el (intento) de ejercicio de este derecho, me he encontrado eliminando una foto de mi cuenta en Tuenti, y como anunció Samuel Parra en su reciente conferencia en el SICARM (y anteriormente en su blog), la foto sigue ahí, accesible a través de su URL, como una más. Aunque sí es cierto que de en mi perfil ya no aparece. Así me gusta, señores de Tuenti, que engañen ustedes a los usuarios que les están haciendo ricos.

Tuenti te tima

Tuenti te tima

Tuenti te tima


Patrones de desarrollo web: Multivista (II)

14 de mayo de 2009 | 0 comentarios

Aquí tienes la procrastinada segunda parte del patrón Multivista. En este post veremos cómo añadir lógica a las vistas y cuáles son los límites de este patrón. Como caso práctico del Multivista orientado a objetos tendremos este mismo blog.

¿Cuándo es necesario este segundo método?

  • Cuando hay plantillas sin salida de texto: PDF, imágenes, flash...
  • Cuando se utilizan helpers o librerías para generar documentos: Pear-Html, DOMDocument, etc
  • Cuando no se quiere emplear un sistema de plantillas.

El patrón Multivista orientado a objetos es similar al patrón Template Two Step View, y se introduce normalmente en una estructura Modelo-Vista-Control de tres capas, como ya expliqué en la primera entrega. Se basa principalmente en la abstracción de las acciones ("postergar los problemas", como dice mi compañero Dors). Si en el primer método cargábamos los mismos datos introduciéndolos en una u otra plantilla, ahora tendremos una abstracción de tres niveles, donde podremos cargar unos datos comunes (ahí suelen estar las llamadas a los DAO) en el primero, ejecutar unas acciones específicas en el segundo, y el tercer nivel (opcional) serían las plantillas. Veámoslo con un ejemplo:


class VerPost extends Vista {
    public function cargarDatos() {
        Dao::getPost($_GET['id']);
    }

    public post() {
        //Aquí se opera con los parámetros post, si los hubiese (por ejemplo, registrar un comentario)
    }
}

class VerPostHtml extends VerPost {
    //Esta vista podría haber sido implementada con el 1º método
    public function run() {
        $smarty->assign("post", $this->cargarDatos());
        $smarty->display("verPost.tpl");
    }
}

class VerPostPdf extends VerPost {
    //Esta vista requiere código PHP específico, por lo que el 1º método no valdría
    public function run() {
        header("Content-type: application/pdf");
        $datos = $this->cargarDatos());
        $pdf = new Pdf();
        $pdf->addText($datos['titulo']);
        echo $pdf->flush();
    }
}

No es complicado entender este método: la parte de la vista se segrega en dos niveles, el primero es una clase común a todas las vistas del módulo y el segundo nivel son las vistas específicas. Pero el Multivista no se queda en este sencillo código. Podemos establecer clases horizontales comunes a todas las vistas específicas de un tipo completo, por ejemplo, las vistas en PDF:


class ComunPdf {
    static public function run() {
        //Construye una cabecera común a todas las vistas
        header("Content-type: application/pdf");
        $pdf = new Pdf();
        $pdf->addText("Blog de Israel Viana");
        $pdf->addText("www.israelviana.es");
    }
}

class ComunRss {
    static public function run() {
        header("Content-Type: application/xml+rss");
    }
}

Clases comunes a vistas del mismo tipo

Quizás queramos tener alguna funcionalidad común para todas las vistas RSS, por ejemplo. Esta funcionalidad se puede implementar de varias maneras: por una parte las propias clases específicas pueden llamar a las transversales:


class VerPostPdf extends VerPost {
    public function run() {
        $datos = $this->cargarDatos());
        VistaPdf::cabecera();
        $pdf->addText($datos['titulo']);
        echo $pdf->flush();
        VistaPdf::pie();
    }
}

O bien puede hacerse desde el motor de vistas:


//Instancia la clase que corresponda
$vista = $_GET['vista'];
$plantilla = $_GET['plantilla'];
eval("$v = new $vista$plantilla;");

//Invoca los métodos comunes a la plantilla
eval("Comun$plantilla::run();");

//Ejecuta la plantilla
$v->run();

URL amigables

Siendo ortodoxos, esto no estaría dentro del patrón Multivista en sí, pero puede ser una buena forma de manejar las aplicaciones que funcionen con este patrón: veamos cómo interpretar URL del tipo: http://servidor.net/Accion/Vista/param1/param2/.../paramn/vista. Manejar direcciones con esta estructura tiene varias ventajas:

  • Organizar nuestros módulos de una manera bastante intuitiva, separando los scripts "importantes" para nuestra aplicación y las librerías
  • Poder disponer de un script único de acceso (el dispatcher de URL), que maneje los argumentos, los errores y los ataques de inyección SQL y por el estilo. Es decir, se solicite la URL que se solicite, siempre se ejecutará el dispatcher.
  • Cumplir la recomendación de accesibilidad de Jakob Nielsen de hacer URL "hackeables", para que un usuario pueda cambiar de plantilla sin necesidad de enlaces.
  • Mejorar el posicionamiento en buscadores de nuestro sitio web (SEO).

Lo primero es redirigir todas las peticiones al dispatcher. En Apache se hace así:

RewriteEngine on
RewriteRule .* index.php

Finalmente, el código del dispatcher tendría esta pinta (el código está bastante simplificado, la versión real la publicaré con el resto del código del blog):


//Vistas
$vistas = array(
    'Index'     => array('nombre'=>"Index",  'plantillas'=>array("Html", "Rss", "Rdf")), 
    'Post'      => array('nombre'=>"Post",       'plantillas'=>array("Html", "Rss", "Rdf")), 
    'Archivo'   => array('nombre'=>"Archivo",    'plantillas'=>array("Html", "Rss", "Rdf")), 
    'Pagina'    => array('nombre'=>"Pagina",     'plantillas'=>array("Html", "Rss", "Rdf")),
    'Proyectos' => array('nombre'=>"Proyectos", 'plantillas'=>array("Html"))
);

$GLOBALS['vista_por_defecto'] = "Index";
$GLOBALS['plantilla_por_defecto'] = "Html";

$peticion = $_SERVER['REQUEST_URI'];
$parametros = split('/', substr($peticion, strlen(RUTA_R))); //Quita la URL base

//Obtiene el módulo
$v = (strlen($parametros[0])) ? ucfirst($parametros[0]) : $GLOBALS['vista_por_defecto'];

//El módulo especificado no existe
if (!array_key_exists($parametros[0], $vistas)) {
    include("404.php");
    die();
}

//Elimina el módulo de los parámetros
array_shift($parametros);

//Protege contra el error de no incluir barra final en URL que no contienen vista específica, por ejemplo /Post/31/titulo-del-post
$ultimo_parametro = ucfirst($parametros[count($parametros)-1]);
if (array_search($ultimo_parametro, array_merge(array(null), $vistas[$v]['plantillas']))) {
    $p = $ultimo_parametro;
    array_pop($parametros);
} else {
    $p = $GLOBALS['plantilla_por_defecto'];
}

//Verifica si está existe la vista
if (array_key_exists($v, $vistas)) {
    $vista = $vistas[$v];
    //Verifica si existe la plantilla
    //No vale negar con ! porque si el índice es 0, la condición no se cumpliría
    if (null == array_search($p, array_merge(array(null), $vista['plantillas']))) die("La plantilla especificada no existe");
} else {
    die("La sección especificada $v no existe");
}

//Pasa los parámetros a la vista
$GLOBALS['parametros'] = $parametros;
$smarty->assign("parametros", $GLOBALS['parametros']);

$GLOBALS['vista_actual'] = $v;
$GLOBALS['plantilla_actual'] = $p;

//Carga las clases vista y plantilla
require_once("vistas/Vista$v.php");
require_once("vistas/$v/$v$p.php");

//Instancia la plantilla
eval("\$vista = new $v$p();");
//Métodos comunes (transversal) al tipo de plantilla
if (file_exists("vistas/Plantilla$p.php")) include("vistas/Plantilla$p.php");
//Ejecuta la plantilla
$vista->run();

Y con esto, un DAO y poco más (veremos en sucesivos artículos qué es lo que falta) tendremos un marco de trabajo para aplicaciones web multivista. No se trataría de un MVC en toda regla, pero sí de una arquitectura de tres capas válida para aplicaciones robustas.


israelviana.es es propiedad de Israel Viana, escrito en Murcia (España). Puedes ponerte en contacto conmigo a través de la dirección de e-mail .com.
Información en RDF Metadatos Dublin Core Creative Commons License