Métodos mágicos en PHP

Reconozco que no había oído hablar de esta característica de PHP 5 hasta estas navidades, cuando un experimentado programador php me comentó que era algo que debía aprender (el mismo que me recomendó aprender Symphony, por cierto). La verdad es que el nombre suena rimbobante: «Métodos mágicos»… te quedas como «no se si será una decepción o si será la leche». Luego, curiosamente durante el transcurso de una entrevista laboral me volvieron a preguntar si sabía del tema, así que decidí informarme.

Tras leer sobre el tema he de decir que no me queda muy claro del todo el uso de dichos métodos. Se trata de una serie de métodos comunes a todas las clases que se crearon para PHP5 y que refuerzan la orientación a objetos del lenguaje. Estos métodos comienzan su nombre con __ por lo que se recomienda no crear métodos propios que empiecen así. Los citados métodos mágicos son:

  • __construct()
  • __destruct()
  • __call()
  • __callStatic()
  • __get()
  • __set()
  • __isset()
  • __unset()
  • __sleep()
  • __wakeup()
  • __toString()
  • __invoke()
  • __setState()
  • __clone()

Si has programado en Java unos cuántos ya te sonarán, porque no es sólo que se llamen igual, es que tienen una funcionalidad similar.

Por lo que he entendido leyendo la documentación, el método __sleep() es llamado cuando se utiliza el método serialize(), se ejecuta antes de comenzar la serialiación y nos permite definir un array con los nombres de todas las variables del objeto que se va a serializar. Por su parte __wakeup() nos permitiría reinicilizar el objeto después de la serialización (restablecer conexiones a la base de datos, por ejemplo), y se ejecuta cuando se utliza unserialize().

Por su parte __invoke() es llamado cuando se intenta llamar a un objeto como si fuera una función. Sí, suena raro, así que os pongo un ejemplo:

<?php
class CallableClass
{
    public function __invoke($x)
    {
        var_dump($x);
    }
}
$obj = new CallableClass;
$obj(5);
?>

//esto devolvería int(5)

En cuanto a __toString(), nos permite decidir qué se imprimirá si el objeto es llamado como si fuera una cadena de texto. Por ejemplo, si haces echo $objeto.


<?php
class TesteandoToString
{
    public $imprimir;

    public function __construct($imprimir)
    {
        $this->imprimir = $imprimir;
    }

    public function __toString()
    {
        return $this->imprimir;
    }
}

$class = new TesteandoToString('Hola caracola');
echo $class;

//esto imprimiría Hola caracola
?>

El método __set_state() nos permite recoger un array con las variables exportadas por el método var_export() y asignarlas a un nuevo objeto. No confundir con la funcionalidad del método __clone(), que directamente crea una copia exacta de otro objeto.

Los métodos __call(), __callStatic(), __set(), __get(), __isset() y __unset() se utilizan para la sobrecarga, lo que nos permite «crear» dinámicamente propiedades y métodos. A estos métodos no se les pueden pasar parámetros por referencia. Se invoca a estos métodos cuando queremos trabajar con propiedades o métodos que no se han declarado o que no son visibles. El funcionamiento de __get() y __set() es similar al que pueden tener en Java los métodos get() y set(): el primero nos permite acceder a las propiedades privadas del objeto desde fuera de la clase y el segundo nos permite modificarlos. Puedes imaginar que __unset() lo que hará será «limpiar» de valor la propiedad y que __isset() funciona como isset() pero permitiendo el acceso a los valores privados. En cuanto a __call(), nos permitirá llamar a métodos inaccesibles en un contexto de objeto, y __callStatic() lo mismo pero en un contexto estático.

Finalmente __construct() es un método constructor, y será lo primero que se ejecute al crear un nuevo objeto de la clase, y __destruct() será lo último que se ejecute antes de eliminar el objeto de la memoria.

En fin, con todos estos métodos está claro que PHP gana mucho en cuanto a orientación a objetos.

Evitar SQL-injection en PHP

Los ataques SQL-Injection son unos de los más habituales en el mundo web. Aquí vamos a ver una serie de consejos para evitar estos agujeros en la seguridad:

Lo primero es seguir una serie de consejos a nivel de administración, como limitar los permisos del usuario a nivel de base de datos. Por ejemplo, en la mayoría de aplicaciones web lo habitual es que no tenga que utilizarse DROP, por lo que por seguridad sería mejor no permitir ya al usuario hacerlo. También sería interesante no dar información extra al atacante evitando sacar en pantalla los errores de la base de datos. En ese caso lo ideal es capturar el error haciendo uso de exception. Tampoco hay que confiarlo todo a las validaciones por javascript, porque el atacante puede saltárselas desactivándolo desde el navegador, por lo que mejor hacer las validaciones del lado del servidor. Y finalmente escapar las comillas con msqli_real_scape_string (en caso de que usemos MySQL), pg_scape_string (en caso de PostgreSQL) o addslashes (por si utilizamos otro SGBD). También podemos utilizar htmlentities para convertir los textos en entidades html, como un plus a la seguridad. Abajo un simple ejemplo:


<?php

try{
  $query = sprintf("SELECT * FROM users WHERE id=%d", mysqli_real_escape_string($id));
  $query = htmlentities($query);
  mysqli_query($query);
}catch(Exception $e){
    echo('Lo sentimos, ha habido un error en la conexión');
}
?>

Como medida extra se podrían utilizar expresiones regulares para evitar la inserción de ciertas palabras (SELECT, DROP, UNION…), si bien puede resultar poco práctico, sobre todo si tu software está destinado al mercado británico.

Pero si todo esto te parece lioso, hay una alternativa: la clase PDO. Dicha clase nos facilitará mucho la vida a la hora de trabajar con bases de datos, ya que nos permite abstraernos del SGDB que estemos utilizando. Si por ejemplo, en una página donde no utilices PDO o algo similar sino el mysql_connect simple, decides migrar tu web de MySQL a PostgreSQL tendrías que cambiar todos los métodos del conector de MySQL por los métodos de PostgreSQL. Con PDO bastaría con que cambiaras una sola línea de código, concretamente la de la creación del objeto PDO, y el resto de la aplicación seguiría funcionando. PDO además te permitirá usar consultas parametrizadas (como los Prepared Statements de java) o realizar transacciones. En fin, en el enlace de arriba tenéis todo el manual de PDO para estudiarlo si queréis. Ahora vamos con un simple ejemplo de Prepared Statement, para que veáis lo sencillo que es (dando por sentado para el ejemplo que ya hemos creado el objeto PDO, tal cual está explicado en el manual del enlace).


<?php
  $prepared_statement = $pdo->prepare("SELECT name FROM usuarios WHERE id = :id");/*preparamos la consulta*/
  $prepared_statement->bindParam(':id', $_GET['id'], PDO::PARAM_INT); /*Le pasamos el parámetro, asociado al parámetro de la consulta y definiendo su tipo (si no, por defecto lo trata como string)*/
  $prepared_statement->execute(); /*ejecutamos*/
  $prepared_statement = $statement->fetch(); /*recogemos los resultados, como un array. Se pueden utilizar parámetros para especificar otro tipo de respuesta, como por ejemplo PDO::FETCH_ASSOC para obtener un array asociativo*/
?>

Y con estos breves consejos lograrás que tu página sea más segura. El consejo: utiliza PDO, por ahorrarte comeduras de cabeza, por seguridad y por portabilidad de tu código.

Los cinco «robos del draft» de la última década

Se habla de «robo del draft» cuando un jugador elegido en una posición muy baja (generalmente por debajo del 20) acaba logrando un rendimiento estelar. ¿Algunos ejemplos? Manu Ginobili fue elegido en segunda ronda (puesto 57) en 1999, un año antes Rashard Lewis fue número 32, Tony Parker fue el 28 de 2001 y ese mismo año Gilbert Arenas fue 31.

¿Y en la última década (2002-2012… Parker y Arenas se quedan fuera por un año)? ¿Quiénes han sido los jugadores que han salido elegidos en puestos bajos y han destacado? Esta es mi particular selección de 5 jugadores que fueron denostados por los ojeadores:

  • Carlos Boozer: El actual cuatro de Chicago además de ser uno de los jugadores mejor pagados de la NBA acumula dos nominaciones al all-star en las 11 temporadas que lleva como profesional, en las que ha pasado por Cleveland, Utah y Chicago. Promedia 16.9 puntos y 9.9 rebotes y ha tenido temporadas de firmar un 20-10 por partido. Además tienes dos nominaciones a jugador del mes, una a novato del mes de su año rookie y una al tercer mejor quinteto de la NBA. Lo soprendente es que a pesar de sus grandes números en la universidad de Duke, donde tuvo actuaciones estelares, no pasó del puesto 34 en el draft de 2002.
    Boozer en los Bulls
    Carlos Boozer

     

  • Monta Ellis: Chupón como el solo, el actual escolta de Milwaukee y durante varios años de Golden State no logró una buena posición en el draft a pesar de que fue MacDonalds All America en 2005. Se fue hasta el número 40 y no tuvo un año de novato fácil, siendo un jugador marginal. Pero en su siguiente temporada se hizo con el premio a jugador con mayor progresión y en estos 8 años en la NBA acumula promedios de 19.5 puntos y 4.3 asistencias. En sus mejores temporadas ha logrado números de 25.5 puntos, 5.3 asistencias y 2.2 robos (en 2009-10) y 24.1 puntos, 5.6 asistencias y 2.1 robos al año siguiente. Actualmente sus cifras anotadoras se han visto reducidas en los Bucks por la presencia de Brandon Jennings, con quien tiene que repartirse los tiros. Con todo está rondando los 20 puntos por partido.
    Monta Ellis en los Warriors
    Monta Ellis

     

  • David Lee: A pesar de ser MacDonalds All America en 2001 seguido de cuatro brutales temporadas en la universidad de Florida (3 de ellas promediando más de 26 puntos y 11 rebotes) sólo logró ser número 30 en el draft de 2005. Inicios duros en la NBA para Lee, drafteado por unos Knicks venidos a menos donde en su primer año a penas tuvo minutos. En su segunda temporada destacó como reboteador, pero no comenzó a despuntar hasta la cuarta. Tras eso fue traspasado a Golden State, donde ha logrado dos temporadas con números de 20-10 (y esta va por el camino) para una media total en su carrera (este es su octavo año) de 14.7 puntos y 9.7 rebotes, logrando además una nominación al all star en 2010.
    David Lee
    David Lee

     

  • Marc Gasol: El mediano de los Gasol es, actualmente, el mejor pivot pasador del mundo… tal vez sólo superado por su hermano mayor. All Star en 2012, en esta su quinta temporada promedia 14 puntos, 7.5 rebotes, 4 asistencias y 1.8 tapones para unos números totales de 13.2 puntos, 8 rebotes, 2.5 asistencias y 1.5 tapones. Números que no reflejan la verdadera importancia del pivot español en los antaño perdedores Grizzlies, actualmente una de las franquicias más potentes del oeste, gracias a la gran pareja que el catalán forma con Zach Randolph, siendo seguramente el juego interior más sólido de la liga. Y a pesar de todo esto que comento… fue el número 48 del draft de 2007, y acabó en Memphis como parte del traspaso que llevó a su hermano a New York. En vista del gran rendimiento que esta familia ha dado en la franquicia de Tennesse no descartaría que intenten fichar al pequeño cuando de el salto a la profesionalidad.
    Gasol vs Gasol
    ¿La mejor pareja de hermanos del basket europeo?

     

  • Rajon Rondo: Un anillo de campeón (de dos finales disputadas), tres veces all star (y de camino al cuarto), dos veces líder en asistencias de la NBA (y la tercera en camino), una vez líder en robos, igualó la marca de partidos dando más de 10 asistencias de Magic Johnson este año (y porque una sanción le dejó fuera, porque iba camino de batir también la de Stockton), dos nominaciones al mejor equipo defensivo y otras dos al segundo, además de una al tercer mejor quinteto de la liga. Promedia entre estas 7 temporadas que lleva en la élite 11 puntos, 8.3 asistencias, 4.3 rebotes y 1.9 robos, pero destaca sobre todo por su capacidad para penetrar, pasar y defender. Cierto es que su tiro es bastante flojo, pero es que si tuviera buena muñeca estaríamos hablando de una potencial leyenda del baloncesto. Con todo sus logros en sus primeras 6 temporadas son impresionantes, y esta séptima no decae (13 puntos, 11.6 asistencias, 5 rebotes, 1.9 robos) siendo uno de los más votados para el all star en el este. Fue una estrella en el instituto, pero si rendimiento más discreto en la universidad le llevó al puesto 21 del draft de 2006. Los Celtics pescaron bien y se hicieron con el director ideal para  acoplarse al Big Three que les devolvió a la élite tras dos décadas de ostracismo.

    Rajon Rondo
    Rajon Rondo

Desde luego… y luego gente como Milicic han sido primeras rondas, en fin. Y como no, me he dejado a varios en el tintero: Scola fue número 55 en 2002, Mo Williams 43 en 2003, Kevin Martin 26 en 2004, Marcin Gortat 57 en 2005, Paul Millsap 47 en 2006, Glen Davis 35 en 2007, en 2008 Pekovic salió en el 31, Mario Chalmers al 34 y Dragic 45, DeJuan Blair 37 en 2009, Landry Fields 39 y Greivis Vasquez 28 en 2010, en 2011 el número 60 fue para Isaiah Thomas y el 33 de Kyle Singler también se antoja bajo… y en estos años gente como Jose Calderón o Jeremy Lin no fueron drafteados siquiera.

En resumen, una mala posición el el draft no tiene por qué significar una carrera corta en la NBA. Que se lo digan a «Big Ben» Wallace: el jugador que ha sido más veces mejor defensor… y que nunca fue drafteado.

Evitar ataques XSS con PHP Input Filter

Hoy una lección de seguridad en programación web: Evitar que a vuestra página le hagan un ataque por XSS (Cross Site Scripting). Si no sabéis lo que es el Cross Site Scripting… os lo explica mejor la wikipedia y así me centro en el tema (una vez le hice un ataque de estos a la página de un grupúsculo neonazi que redirigía a un vídeo del desfile del orgullo gay en Youtube)

Bueno, hay frameworks como Symphony o CakePHP que ya se encargar de implementar este tipo de seguridad, al igual que también lo hacen ciertos gestores de contenidos. Pero si se da el caso de que no estás usando ninguno, estás haciendo PHP «a pelo», lo mejor será que recurramos a la clase PHP Input Filter. Dicha clase permite filtrar código malicioso ingresado en los formularios para prevenir ataques XSS de manera sencilla, pero tiene la cualidad de no limpiar determinadas etiquetas o atributos si queremos.

Para utilizar esta clase, la descargaremos desde el enlace anterior e incluiremos class.inputfilter.php al inicio de nuestro códgi. Luego crearemos una instancia de la clase InputFilter, entonces podremos filtrar los datos con el método process:

    require_once("class.inputfilter.php");
    $filter = new InputFilter();
    $variable = $filter->process($_POST['variable']);

Esto nos permitiría limpiar de etiquetas la variable enviada por $_POST llamada variable. ¿Y si queremos limpiar todos los campos enviados por el método post? Pues basta con pasarle todo el array:

$_POST = $filter->process($_POST);

Y con eso tendríamos el array $_POST limpio de etiquetas y securizado.

Pero ¿y si queremos permitir ciertas etiquetas? Imaginemos que desde un input text metemos texto formateado, y nos interesa que sí puedan subir saltos de línea, texto en negrita o cursiva. Pues muy sencillo también, ya que basta con pasar en la creación del objeto InputFilter un array con las etiquetas que queremos conservar como parámetro:

    $filter = new InputFilter(array('em', 'i', 'br', 'b', 'strong'));
    $_POST = $filter->process($_POST);

Y esto se puede llevar más allá, porque también podemos decir que se permitan ciertos atributos de ciertas etiquetas. Por ejemplo, imaginemos que queremos permitir que inserten enlaces junto a su href y a su id, pero ningún atributo más:

    $filter = new InputFilter(array('a'), array('href', 'id'));
    $enlace = $filter->process($_POST['enlace']);

Tras el array de etiquetas pasamos otro array de atributos, simplemente.

Con estos sencillos consejos lograrás que tus formularios sean más seguros en PHP.

Botón de «Compartir en Facebook», «Compartir en Twitter» y «+1» de Google+

¿Deseas integrar un botón de «compartir en Facebook en tu página»? Es una opción muy útil para que tus lectores hagan publicidad de tu sitio en la popular red social. Y como por otra parte eso también es publicidad gratuita para ellos ya se han encargado de que la cosa sea facilita.

Antaño la cosa se hacía con un simple javascript, pero a día de hoy Facebook incluso te facilita la creación del botón con un formulario en su página de desarrolladores

Con Twitter, tres cuartos de lo mismo: un simple formulario y te genera botones para compartir, mencionar, like, etc en la popular red de microbloggin.

En cuanto a Google+, la cosa tampoco es compleja. En su API de Javascript no sólo te dan un formulario de creación sino que también te facilitan una explicación de todo el funcionamiento del botón.

En definitiva, cualquiera de las tres redes sociales más populares te facilita la vida a la hora de crear un botón de compartir que integrar en el código de tu página o blog.

Bye bye 2012!

Bueno, llevaba unos días sin escribir, pero es que he tenido mucho trabajo. Hoy, antes de empezar a hacer los preparativos para la cena de fin de año, me apetecía mandaros un saludo a todos mis lectores a ambos lados del atlántico. Sí, porque si bien España sigue dando el grueso de lectores a este blog, en este 2012 la cantidad de visitas sobre todo desde Argentina, México, Colombia, Ecuador y Venezuela han subido mucho.

Por este país hemos visto como los neoliberales descuartizaban poco a poco el estado del bienestar con la excusa de la crisis, que parece justificar ya cualquier aberración. La economía se sigue desplomando, la producción también, los sueldos bajan… y bueno, yo al menos al final he logrado encontrar trabajo pero la cosa está bien jodida.

Sobre otros temas, al menos hemos tenido algunos buenos discos de rock and roll: Lynyrd Skynyrd, ZZ Top, Kiss, Aerosmith, Witchcraft, Ghost no han sacado disco pero ya han presentado a Emeritus II… Y en baloncesto el Obra aguantó la categoría y en esta temporada está con un 8-7… peleando por puestos de Copa. Espero que no pase la de 2010…

En cuanto a informática, parece que Windows 8 puede ser el más grande de los errores de Microsoft en la última década, Twitter parece confirmarse como la red social de referencia, la especificación HTML5 al fin está completa, la seguridad de los sistemas Apple empieza a mostrar flaquezas (cosa normal al aumentar el número de usuarios) y por vuestras lecturas parece que os preocupan los virus, porque estas han sido las cinco entradas más leídas de este blog:

En fin, sólo me queda desearos a todos un buen día y que 2013 sea mejor que 2012, en todos los sentidos posibles.

Instalar PHPUnit en WAMP

Inciso antes de empezar: Estoy buscando información y cursos de Symphony 2, porque me han recomendado aprender sobre este framework (ya que el destino parece empujarme a trabajar en PHP, si la vida te da limones haz mucha limonada para meter en tu currículum), si alguien puede aportar algo sobre el tema, por favor, en comentarios.

Y seguimos con el tema, instalar PHPUnit en un servidor Apache en Windows (WAMP).

Bueno, habría que empezar por decir ¿por qué usar PHPUnit? Pues para poder realizar tests automatizados sobre nuestro código PHP de manera eficiente. ¿Cómo lo instalamos en nuestro servidor? Bueno, todo es ir en cómodos pasos:

NOTA: En el artículo original lo hacíamos con PEAR, pero se le quitó el soporte hace años. Editamos para ver cómo hacerlo con PHAR:

  • Añade el directorio (en mi caso «c:\wamp\bin\php\php5.3.4») php a tu PATH
  • Descargamos el fichero PHAR desde https://phar.phpunit.de/phpunit-7.phar (Ojo, puede cambiar la versión con el paso del tiempo) y lo guardamos como C:\bin\phpunit.phar
  • Después ejecutamos el siguiente comando:
C:\Users\username> cd C:\bin
C:\bin> echo @php "%~dp0phpunit.phar" %* > phpunit.cmd
C:\bin> exit
  • Abre un nuevo prompt en línea de comados y comprueba que se ha instalado correctamente con el siguiente comando:
C:\Users\username> phpunit --version

Ok, ahora debería estar funcionando e instalado. Lo mejor es hacer un test de prueba para ver si funciona todo. En este caso una tontería básica de la que sabemos el resultado: comprobaremos que uno es igual a uno.

  class MyTest extends PHPUnit_Framework_TestCase
  {
    public function testUnoIgualUno()
    {
      $this->assertEquals(1, 1);
    }
  }

Ahora desde otro terminal basta ejecutar phpunit MyTest.php y este debería devolverte como respuesta el número de versión de PHPUnit, el tiempo que necesitó para la operación, la memoria consumida y un mensaje como este: OK (1 test, 1 assertion)

Todavía no he profundizado mucho con este software, pero cuando tenga tiempo en el trabajo espero poder ponerme con ello porque facilita mucho la vida el poder realizar tests de forma organizada.

Editores WYSIWYG para tu web

¿Necesitas un editor WYSIWYG para integrar en tu página web? ¿Quieres mandar e-mails con texto enriquecido? ¿Quieres que tus usuarios puedan generar código con texto formateado? Ok, pues estas son algunas de las mejores opciones libres a las que puedes recurrir:

  • TinyMCE: Usado por WordPress, Facebook, Oracle Beehive, IBM Web CMS, Joomla, Episerver… en fin, son nombres que deberían dar confianza al usuario. TinyMCE incluye una enorme variedad de opciones que tú puedes configurar y decidir cuales usar. Es fácil de integrar y tiene una amplia documentación.
  • NicEditDos motivos para plantearse el uso de NicEdit son su ligereza y su fácil integración (sólo requiere dos líneas de código y lo tendrás funcionando). No tiene tantas opciones como el anterior pero son suficientes para el uso habitual del usuario, lo que además hará que para este sea más fácil e intuitivo usarlo.
  • openWYSIWYG: Reconozco que no lo he probado, pero me han hablado de él. Por lo que me han comentado el proyecto está un poco abandonado, así que es posible tener problemas de compatibilidad con las últimas versiones de algunos navegadores.
  • CKEditor: A nivel de funcionalidades implementadas está en la misma liga que TinyMCE, y es el editor utilizado por Drupal. Muy potente y con gran cantidad de opciones. Cuando lo veas parecerá que estás ante el procesador de texto de una suite ofimática.
    CKEditor
    CKEditor

     

En fin, con estos cuatro más o menos ya vemos todo lo que hay en el mercado. ¿Y cómo los implementas? Pues mira la documentación de cada uno. ¿Y cómo recoges los datos? Tranquilo, al procesar el formulario te vendrá como el resultado de un textarea normal, al menos en PHP (las versiones para Java o ASP ya vendrán en su documentación explicadas, digo yo).

Añadir columna a una tabla en MySQL (y MariaDB)

Una pequeña entrada sobre SQL básico, porque me lo han preguntado hace un rato, así que aprovecho para contestar por aquí.

Muy bien, tienes una tabla y quieres añadir una columna o campo que se te olvidó al crearla, o que por cambios en la aplicación necesitas añadir. Si te vas a la guía de referencia de MySQL puedes leer todas las posibilidades que tienes, pero como se puede hacer largo y pesado mejor unos ejemplillos de código rápidos aquí:

La sintaxis básica es ALTER TABLE nombreDeLaTabla add nombreDeLaColumna tipodedatos(longitud)

ALTER TABLE tabla1 add colNueva varchar(2);

Vamos con más ejemplos. Por ejemplo, queremos que la columna nueva no permita valores nulos (ojo, esto puede dar problemas si la tabla ya tiene valores añadidos):

ALTER TABLE tabla1 add colNueva varchar(2) NOT NULL;

O por ejemplo queremos colocarlo específicamente después de una columna que ya existe (si no especificamos nada, añadirá la nueva al final):

ALTER TABLE tabla1 add colNueva varchar(2) NOT NULL AFTER col1;

O al revés, queremos insertarla antes de una columna concreta:

ALTER TABLE tabla1 add colNueva varchar(2) NOT NULL BEFORE col2;

También puede venir con un valor por defecto:

ALTER TABLE tabla1 add colNueva varchar(35) DEFAULT 'Ni de ajo';

¿Y si en vez de una quieres insertar varias? Sin problema:

ALTER TABLE tabla1 add (
colNueva varchar(2) NOT NULL,
colMásNueva tinyint(1) default 0
)

Como ves, es sencillo. SQL básico. Como siempre, todo lo aplicable en MySQL lo es también en MariaDB.

Convertir una respuesta xml en un objeto de PHP

Por defecto PHP, desde la versión 5.1.2, incorpora la extensión SimpleXML y la trae habilitada (en versiones anteriores es necesario usar –enable-simplexml para activar esta extensión en el momento de compilar). Dicha extensión incluye una serie de herramientas que nos permiten trabajar fácilmente con XML.

No es extraño que si tenemos que comunicarnos con un api externa esta nos devuelva una respuesta en XML, que es un formato universal que puede ser trabajado con casi cualquier lenguaje (otra posibilidad muy habitual es JSON). SimpleXML nos permite recoger esta respuesta, convertirla en un objeto y trabajar con el mismo sin mucha complicación.

En caso de querer recoger una respuesta de otra página, el método a usar sería simplexml_load_string():

$objetoxml = simplexml_load_string($respuestaApi);

Con esto ya tenemos un objeto fácil de recoger. Vamos a imaginar que el objeto que recibimos es tal que así:

<response>
   <requestid>A16</requestid>
   <requests>3</requests>
   <status>error</status>
   <error>
      <code>106</code>
      <message>Request expired</message>
   </error>
</response>

Una notificación de un error conectando con un servicio externo (de hecho, es una copia de un mensaje de error del api de Calameo). Ahora imaginemos que queremos recoger este mensaje de error y mostrárselo por pantalla al usuario. ¿Qué hacemos? Pues muy facilito:

//primero convertimos el xml a objeto
$objetoxml = simplexml_load_string($respuestaApi);

//luego comprobamos que sea un mensaje de error:
if (isset($objetoxml->error))
{
    //e imprimimos
    echo 'Error:'.$objetoxml->error->code.': '.$objetoxml->error->message;
}

Trabajar con el objeto SimpleXML es cosa fácil: Cuando quieres acceder a un elemento basta ir moviéndose como si accedieras a las propiedades o métodos de un objeto. Es decir abuelo->padre->hijo. ¿Que hay varios elementos con la misma etiqueta? Sin problema, las etiquestas se convierten en objetos iterables y accesibles, por lo que puedes recorrerlos recurriendo a los mecanismos básicos de iteración (bucle foreach, por ejemplo).

¿Y para acceder a los atributos? En el ejemplo del xml no hay, pero imaginemos que en lugar del anterior la cosa fuera así:

<response>
   <requestid>A16</requestid>
   <requests>3</requests>
   <status>error</status>
   <errors>
      <error>      
        <message code="106">Request expired</message>
      </error>
      <error>      
        <message code="401">File not found</message>
      </error>
   </error>
</response>

Ok, ahora tendrías que acceder a los atributos, y de paso podríamos ver un ejemplo de iteración. A los atributos se accede como si fuesen elementos de un array, usando como índice su nombre:


//primero convertimos el xml a objeto
$objetoxml = simplexml_load_string($respuestaApi);

//luego comprobamos que sea un mensaje de error:
if (isset($objetoxml->errors))
{
    foreach(objetoxml->errors->error as $error)
    {
        echo 'Error:'.$error['code'].': '.$error->message;
    }
}

Un par de notas más:

  • Para usar el texto de un elemento en una comparación o pasarlo a una función como string hay que forzar la conversión a cadena de texto haciendo un cast con (string)
  • Para acceder a un elemento cuyo nombre viole las convenciones para nombres de objeto de PHP hay que recurrir a encapsular el nombre del elemento dentro de un par de llaves y comillas simples.
  • En este caso hemos hablado de recoger una respuesta de un servicio externo, pero SimpleXML nos permite también recoger un xml desde un archivo con simplexml_load_file().

Y si necesitáis convertir el elemento en un array (en su momento me tocó) ya tratamos ese punto con anterioridad.