Cómo ver tu historial de actividad en Netflix y cómo mejorar las sugerencias

¿Quieres saber qué has visto en Netflix? Pues puedes hacerlo. Basta con visitar este enlace con tu sesión abierta y podrás consultar todo lo que has visto en la plataforma.

Tienes dos opciones. Por un lado puedes ver el historial de visionado:

Historial de visionado de Netflix
Historial de visionado. El botón a la derecha te permita eliminar de tu lista de visionado esa entrada.

Por otro lado puedes ver el historial de votaciones:

Historial de votaciones

Si notas que en los últimos tiempos las sugerencias de Netflix no te convencen puede que sea porque has visto una serie de películas o programas que no “encajan” en tu patrón de gustos. Desde aquí puedes solucionarlo:

En el historial de votaciones puedes cambiar tu voto o eliminarlo para que no cuente, y en el historial de visionado el botón de la derecha te permita quitar esa serie o película de tu lista. De esta forma ese material ya no se tendrá en cuenta a la hora de realizar sugerencias.

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>

Detectar si un usuario usa Adblock Plus

El tema de la publicidad en internet está candente últimamente. Por un lado algunas páginas se pasan de publicidad intrusiva (y no hablo sólo de sitios donde ver retransmisiones deportivas on-line, basta con entrar en la web de cualquier periódico español “grande” para ver anuncios que a veces hasta dificultan la lectura), pero por otra parte también están muchas webs gratuitas cuya única fuente de ingresos es la publicidad, y al bloquearla les dejamos sin un dinero necesario para pagar los gastos ocasionados. Algunas web optan por bloquear a los usuarios que llegan con el adblock puesto, yo no comparto estas medidas draconianas ya que soy el primero que ve eso y lo siguiente que hace es salir de la página y buscar otra que me ofrezca lo mismo sin esta publicidad. Creo que la mejor solución sería el “buenrollismo“, vamos, que si se detecta en AdBlock se le saca al usuario un aviso tipo “tío, que alojamiento y dominio son 50 pavos anuales, que no es mucho pero me los sacaba con estos anuncillos de google, no me jodas y saca el bloqueador, man”. La mayoría no te harán ni caso, pero bloqueándoles no te creas que lograrías mejores resultados, al menos así puede que lo compartan en redes sociales y logres ingresos de otros usuarios que lo miren.

Vamos pues con la chicha ¿cómo se detecta AdBlock? Bueno, yo lo he hecho mediante el método del señuelo, que de momento va furrulando. La cuestión es que AdBlock tiene una lista negra de palabras y bloquea según qué javascript si detecta alguna de ellas. El truco es meter un javascript con un nombre que haga saltar Adblock, comprobar que dicho javascript no está furrulando y, en ese caso, lanzar un aviso al usuario.

Empezamos creando un archivo de javascript con el título advertisement.js, un nombre que hará saltar a Adblock para evitar su carga, con un contenido más o menos como el siguiente:

document.write('<div id="le_truquito">Publicidad malvada y terrible!!</div>');

La idea es hacer el document.write de un div con un id concreto, lo del texto ya es chorrada mía. Por si entra un usuario sin Adblock lo mejor es que ocultemos ese div que se creará con CSS, para que no le aparezca por medio.

#le_truquito{
    display:none;
}

Ok, lista la trampa lo siguiente es añadir otro código de javascript que comprobará si se ha bloqueado el primero (cerciorándose de si existe el div que debería crear) y, en caso de que no lo haya hecho sacará un mensaje en pantalla.

<script type="text/javascript">
if (document.getElementById("le_truquito") == undefined)
{
    window.alert("tío, que alojamiento y dominio son 50 pavos anuales, que no es mucho pero me los sacaba con estos anuncillos de google, no me jodas y saca el bloqueador, man");
}
</script>

En el ejemplo puse un window.alert, pero también podéis crear un div con un texto en la página… en fin, lo que veáis más práctico.

De momento el sistema funciona, y tiene pinta de que al menos durante una temporada lo hará. En todo caso podéis buscar el nombre de un archivo de javascript de publicidad de Google, o de otra compañía, que sepáis positivamente que se está bloqueando por AdBlock y llamarle así en lugar de advertisement.js (aunque de momento con ese nombre furrula).

Poblar un combo dinámicamente con jQuery y JSON

Es habitual que, creando formularios, nos encontremos con la situación de tener dos combos (o campo select si lo preferís) y que uno tenga que cargar/modificar sus datos según el resultado seleccionado en el otro, de forma dinámica. Esto es posible con Javascript, y muy cómodo si utilizamos JSON y jQuery.

Os planteo un ejemplo simple: tenemos dos combos, uno con provincias y otro con ayuntamientos. El marcado HTML va a ser más o menos tal que así:

<select id="provincias" name="provincias">
  <option value=""></option>
  <option value="1">A Coruña</option>
  <option value="2">Lugo</option>
  <option value="3">Ourense</option>
  <option value="4">Pontevedra</option>
</select>
<select id="poblaciones" name="poblaciones" disabled="disabled">
</select>

Como véis, al momento de cargar la página el campo provincias tendrá las cuatro provincias gallegas, y el campo poblaciones estará desactivado. ¿Ahora qué necesitamos? Pues primero necesitamos un script que nos saque las poblaciones de la base de datos y nos las envíe como un JSON. Cualquier lenguaje de lado del servidor nos vale, para el ejemplo va a ser PHP (pero vamos, que podría aplicarse con Java, Ruby, node.js, Python…). Crearemos un script llamado getPoblacionesJson.php

<?php
include 'conexionbd.php';
if ($mysqli -> multi_query("CALL sp_GetPoblaciones(" . $_GET['pr'] . ")")) {
	$poblaciones = array();
	do {
		if ($result = $mysqli -> store_result()) {
			while ($fila = $result -> fetch_assoc()) {				
				$poblaciones[$fila['Id']] = $fila['Nombre'];
			}
		}
	} while($mysqli->next_result());
	print_r(json_encode($poblaciones));
}
?>

En este caso veis que lo que hacemos es llamar a un procedimiento almacenado que nos devuelve las provincias, recorremos el resultado y vamos guardándolo en un array. Finalmente lo convertimos a JSON y lo imprimios para que lo recoja la función de Javascript. Si os estáis preguntando cómo va el procedimiento almacenado, es una simple select en MySQL, tal que así:

DELIMITER $$
CREATE PROCEDURE sp_GetPoblaciones(IN provincia int)
begin
	SELECT Id, Nombre FROM poblaciones WHERE (provincia is null or IdProvincia = provincia) ORDER BY Nombre;
end $$
DELIMITER ;

Ok, tenemos entonces el script del servidor, el marcado y el procedimiento en la base de datos. ¿Qué nos queda? Pues el Javascript, vitaminado con jQuery para ganar productividad:

$("#provincias").change(function() {
	$("#poblaciones").empty();
	$.getJSON('http://localhost/getPoblacionesJson.php?pr='+$("#provincias").val(),function(data){
		console.log(JSON.stringify(data));
		$.each(data, function(k,v){
			$("#poblaciones").append("<option value=\""+k+"\">"+v+"</option>");
		}).removeAttr("disabled");
	});
});

La idea es simple: Si se registra algún cambio en el combo de provincias vaciamos el combo de poblaciones y lo rellenamos con los nuevos datos, obtenidos mediante la función getJSON() y que recorreremos con each() como un conjunto de claves/valores. Finalmente, por si está desactivado, lo reactivamos. He hecho un console.log por si queréis ver cómo funciona la cosa en la consola de javascript de Chrome o del Firebug.

Espero que os sirva de ayuda esta entrada para trabajar con combos dinámicos.

AngularJS: Introducción y Hello World

Llevo unos días trasteando con el framework de Javascript AngularJS, libre y mantenido por Google. En su momento no lo incluí en mi pequeña selección de frameworks a ir mirando, pero al final he acabado por dedicarme a trastear con él. De momento tampoco he avanzado mucho, que este mes estoy liado, pero en el futuro os iré comentando.

Comencemos por la primera pregunta ¿para qué vale AngularJs? En fin, la idea de este framework es dinamizar las páginas HTML estáticas vinculando elementos de ese HTML con un modelo de datos que hemos definido en Javascript (a mano, o desde un JSON), permitiendo la interactividad con el usuario. En este caso, aunque se usa un patrón MVC la potencia es que nos permite, mediante bindings {{}} , acceder a la funcionalidad o a los datos. Es cierto que el resultado final lo podemos conseguir de otras muchas formas, pero AngularJS nos ahorrará muchas líneas de código. Algunos lo comparan ya con lo que significó jQuery en su momento para el desarrollo en Javascript.

AngularJS Logotipo
AngularJS

Para descargaros Angular, que por cierto cada versión tiene un nombre más delirante que la anterior (al momento de escribir esto estamos en la Monochromatic Rainbow, pero mi favorita es Flatulent Propulsion), podéis hacerlo desde la página del proyecto. Y desde la documentación de esa misma página he sacado el código para el primer ejemplo: un Hello World!. Pero claro, como hablamos de un framework que dota de actividad a vuestro CSS será más bien un Hello ______ (loquesea).

Empezamos, como siempre, por el marcado:


    <html ng-app>
      <head>
<script class="hiddenSpellError" type="text/javascript">// <![CDATA[
src</span>="http://code.angularjs.org/angular-1.0.2.min.js">
// ]]></script>
<script class="hiddenSpellError" type="text/javascript">// <![CDATA[
src</span>="script.js">
// ]]></script>
 </head>
 <body>
 <div ng-controller="HelloCntl">
 Your name: <input type="text" value="World" />
 <hr/>
 Hello {{name}}!
 <div>
 </body>
 </html>

Bien, como puedes ver en la cabecera cargamos como un script la librería de AngularJS (está copiado de un ejemplo antiguo, así que revisa cual es la última versión en el momento en que lo hagas) y debajo cargamos otro script con lo que hayamos programado en Javascript. Puedes ver que al div le hemos asignado un atributo llamado ng-controller. La idea de esto es definir que ese div estará dentro del ámbito del controlador que le indicamos (recuerda, estamos trabajando en un modelo MVC). Luego verás que al input le hemos puesto también un atributo, en ese caso ng-model. Lo mismo, estamos vinculando ese atributo al ámbito del modelo de datos definido, o explicado de forma más simple: el texto que hay ahí será el modelo de datos y se llamará name. Finalmente ves que al lado de Hello hemos incluido {{name}}, esencialmente la idea es que ese elemento entre llaves está relacionado en el elemento del modelo con el mismo nombre (que a su vez está relacionado con el input) ¿qué va a ocurrir? Pues el llamado two-way-data-binding: modificarás el modelo desde la vista y justo al mismo tiempo verás como los datos de la vista se modifican.

Ahora vamos con la parte del javascript, donde definimos el controlador y el modelo:

    function HelloCntl($scope) {
       $scope.name = 'World';
    }

Como puedes ver aquí definimos la función HelloCntl, que fue la que vinculamos en el marcado al div. Abajo simplemente hacemos que, por defecto, el nombre que aparezca sea World (para formar el Hello World). Si bien, si lo modificamos veremos como este cambia.

Logo AngularJS

Finalmente vamos a hablar de otro de los fuertes de AngularJS: el testeo del código. Porque AngularJS nos permite escribir test para comprobar el correcto funcionamiento, sin tener que meternos en absurdas y largas pruebas con algún complemento del navegador para depurar javascript. El teste sería este:

    it('should change the binding when user enters text', function() {
        expect(binding('name')).toEqual('World');
        input('name').enter('angular');
        expect(binding('name')).toEqual('angular');
    });

Si queréis ver en acción todo el ejemplo antes de testearlo vosotros, en la página de Angular (de donde lo he copiado yo) podréis hacerlo. Además de ver otros, como un juego del tres en raya.

En fin, ya puedes hacerte una idea de la potencia de este AngularJS, más adelante espero escribir más sobre el tema. Yo lo veo como una potente herramienta, sobre todo para el desarrollo de Apps móviles con HTML5 y CSS.

También añadiré que la principal idea es usar AngularJS con Node.js en el lado del servidor, si bien podéis desde ese lado el lenguaje que prefiráis (Ruby, PHP, Python).

Crear un botón Pin it para compartir en Pinterest desde tu web

Cierto es que Pinterest ha sacado un complemento para el navegador que agrega un botón Pin-it a tu Firefox o Chrome, pero con todo es recomendable agregar un botón de compartir en Pinterest a tu web. Puede que en España no sea todavía muy popular esta red social (y desconozco las estadísticas para América Latina)  pero para sitios de fotografía y moda se ha vuelto indispensable.

Como en todas las redes sociales, crear el botón es fácil (a ellos les interesa facilitarte el trabajo): Tan sólo tienes que irte al generador de widgets de Pinterest y crearlo desde allí.

Para el botón de Pin It verás que se te ofrecen 3 opciones: One Image, Any Image o Image Hover. La primera opción es para crear el botón sólo para una imagen concreta, de ahí el formulario donde se te pedirá el url de la imagen y que elijas donde ubicar un contador. Debes copiar tanto la notación HTML como el script que te da y ubicarlo donde te sea más cómodo.

Boton Pin it
Pin it!!!

La opcion Any Image te permitirá crear un botón para insertar cualquier imagen de la página en que esté ubiado en Pinterest (similar al que hay implementado a día de hoy en los productos de la web de la marca Mango, por ejemplo). Tienes que pegar un HTML en tu código para que genere el botón y un script.

Finalmente Image Hover hará que sobre cada imagen de la página en que ubiques el script aparezca un botón de compartir en Pinterest al sobrevolarla con el ratón. En este caso no habrá HTML y sólo tendrás que copiar el script.

Y así, de forma sencilla tienes el botón insertado en tu web. Para insertar el botón Pin It en un blog de Blogger podéis seguir esta guía.

Trabajando con JSON en PHP: crear y consumir JSON

JSON se ha convertido en una herramienta fundamental en la programación web, ya sea en servicios web, para comunicar con apps de móviles, pasar datos de php a javascript…

Desde PHP podemos tanto crear un JSON como recibirlo y manejarlo. Para la creación debemos utilizar la función json_encode(), que recibe lo que queramos serializar (una cadena, una variable numérica, un array, un objeto) y devuelve una cadena con los datos serializados. Si le pasamos un array normal o una cadena, no veríamos mucho cambio tras la serialización, pero si le pasamos un array asociativo, tendríamos un resultado como el del ejemplo:

$miArray = array("ferrari"=>"rojo", "porsche"=>"plateado", "mercedes"=>"negro");
$string = json_encode($miArray);
//el valor de string sería {"ferrari":"rojo","porsche":"plateado","mercedes":"negro"} 

Pero la verdadera potencia la encontramos cuando la aplicamos a objetos, ya que JSON nos permite serializar cualquier objeto de PHP, con el mismo procedimiento que usamos arriba: la función json_encode.

Una cuestión a la hora de trabajar con JSON que debemos tener en cuenta es la codificación de caracteres. En principio json_encode() ya convierte a Unicode los resultados, ya que en la notación JSON usamos siempre Unicode. El problema es que PHP por defecto tratará la cadena de origen como UTF-8, así que si no estás trabajando con esta codificación, y estás usando, por ejemplo, ISO-8859-1, se tornará necesario que codifiques las cadenas a UTF-8 antes de convertirlas en JSON. Esto se hace con la función utf8_encode().

$miArray = array("palabro1"=>utf8_enconde("ñandú"), "palabro2"=>"maniqueo", "palabro3"=>utf8_encode("bandoneón");
$cadenajson = json_encode($miArray);

Con esto ya recibiríamos las cadenas codificadas en UTF-8 y prevendríamos errores de codificación.

Ok, con esto hemos visto como generar un JSON, pero ¿cómo lo consumimos?.

Bueno, primero habría que destacar que existen varias librerías para JSON en PHP, pero desde PHP 5.2 este incluye librerías nativas desarrolladas en C, que son las más recomendables por cuestiones de rendimiento. Ahora vamos a suponer un objeto tal como el del ejemplo:

$strjson = '{
   "elemento1": "valor1",
   "elemento2": "valor2",
   "elemento3": null,
   "otroobj": {
      "a ver": "oh",
      "venga": "va"
   };

Esa sería la cadena JSON que recibiría nuestro código PHP con un objeto serializado ¿cómo la transformamos en objeto? Pues si serializábamos con json_encode() el paso contrario será con json_decode():

$objetophp = json_decode($strjson);

//si imprimimos objetophp con print_r() nos dará:
stdClass Object
(
   [elemento1] => valor1
   [elemento2] => valor2
   [elemento3] =>
   [otroobj] => stdClass Object
   (
      [a ver] => oh
      [venga] => va
   )
) 

Al tener un objeto puedes acceder a sus propiedades como en cualquier objeto normal de PHP.

Una serie de avisos: Recuerda, como dijimos antes, que las cadenas deben estar en UTF-8, si usas otra codificación tendrás que tirar de utf8_encode. Los nombres tanto de las propiedades como de los valores deben ir entre comillas dobles, no se aceptan comillas simples y sólo los valores numéricos o null pueden ir sin comillas. No te dejes ni llaves ni corchetes abiertos, ni ninguna coma de más. Todo eso provocará fallos.

BuddyPress vs Drupal Commons: crea tu red social con software libre

Creo que alguna vez comenté por aquí que estoy trabajando en el desarrollo de módulos para la red social PHPFox. No es que me convenza mucho este cms para la creación de redes sociales, la verdad, pero es cosa de la empresa. En todo caso, creo que PHPFox tiene una documentación que en el mejor de los casos es chapucera y en el peor inexistente, una comunidad profundamente inactiva y mercantilizada y un grave problema de rendimiento y escalabilidad. Y además hay que pagar licencia.

Por eso dediqué unos días a buscar opciones libres para crear una red social, no porque a mi empresa le interese (que de momento parece que están muy contentos con Fox) sino por mera curiosidad, y tal vez para montar alguna algún día, pero es sólo una chorrada que me ronda la cabeza.

A lo que íbamos, ¿qué dos opciones libres suenan con más fuerza? Pues BuddyPress y Drupal Commons. Ambos no son un CMS propiamente dicho, sino extensiones para otros CMS que nos dan la funcionalidad de red social

BuddyPress, como te puedes imaginar, está desarrollado para WordPress. Su instalación es simple: instalas WordPress ( a poder ser, la última versión), subir el plugin al servidor e instalarlo desde el menú de instalar plugins. Total, que en 10 minutos tienes montado todo en tu servidor.

Drupal Commons, evidentemente, es un plugin para Drupal. Su instalación es todavía más sencilla: sólo debes seleccionar el perfil Drupal Commons durante la instalación de Drupal, y listo.

En cuanto a funcionalidades, BuddyPress es menos completo que Commons. El plugin de wordpress incluye un stream de actividades de los usuarios, perfiles extendidos, posibilidad de conectar con amigos, posibilidad de crear grupos extensibles, mensajes privados, foros de discusión y todas las fucionalidades de WordPress para crear blogs. Lo básico para crear una comunidad.

Commons por su parte viene de serie más completo: los perfiles de usuario incluyen más variables, es capaz de crear automáticamente grupos respecto a la información del perfil, incluye foros de discusión, blogs (eso sí, en este caso menos potentes que los de wordpress), creación y gestión de eventos, creación de wikis, administración de documentos, integración con RSS, noticias, mayor control de la privacidad, editor WYSIWYG para los textos, estadísticas de la comunidad

Bueno, parece que ahí gana Commons ¿o no? Piénsalo bien, más funcionalidades no significa mejor. No quiero decir que Commons por abarcar mucho apriete poco, no, simplemente que es posible que en tu comunidad no necesites todas las funcionalidades que Drupal Commons trae por defecto. Y que no vengan por defecto en BuddyPress no significa que no existan para este, sólo que las tienes que instalar aparte.

En cuanto a diseño, el que incluye por defecto BuddyPress me parece más atractivo, pero ambos pueden ser modificados y personalizados, ya sea a través de la edición manual del css, a través de simples menús de personalización o adquiriendo alguna plantilla (las hay gratis y de pago). En todo caso, para gente que no sepa CSS Drupal Commons es más cómodo de personalizar.

Al ser software libre ambos tienen una amplia comunidad por detrás: Commons está apoyado y mantenido por Acquia, los cuales además de permitirte la descarga gratuita del plugin también ofertan de forma comercial hosting y mantenimiento para tu red. Commons tiene un API que te permitirá desarrollar módulos para extender su funcionamiento, además de tener acceso a miles de módulos. Con BuddyPress tienes menos módulos específicos, pero con todo dispones de todos los módulos de Worpress para añadir.

No voy a decir que uno sea peor que el otro. Creo que para un usuario avanzado BuddyPress es más flexible, y para uno novato Commons, aunque más grande, puede ser más fácil de gestionar al no tener que andar instalando plugins. En todo caso, a vosotros corresponde decidir. Yo todavía tengo que hacer más testeos caseros con ambos, pero ya tengo un par de ideas rondando la cefa.

Crear un webservice básico con PHP y SOAP

SOAP es un protocolo de intercambio para servicios web basado en XML, sobre el que puedes leer en esta entrada de la wikipedia. Para no liarnos con preámbulos, vamos con la chicha ¿cómo creamos un servicio web en PHP?.

Para facilitarnos la vida empezaremos por descargar NuSOAP, un toolkit para el desarrollo de servicios web con SOAP en PHP, que nos proveerá de diversas clases para trabajar con este protocolo. Basta con descargarlo, descomprimirlo, meterlo dentro de nuestro proyecto y, cuando queramos usarlo, incluir nusoap.php como librería.

Ok, con NuSOAP instalado toca crear un servidor SOAP en nuestra aplicación. Para el ejemplo crearemos un servidor, lo llamaremos producto.php, que si recibe una petición donde se le pida una lista de libros devuelva tres títulos (es un ejemplo básico, piensa que en la realiad podrías acceder a una base de datos y dar muchas más funcionalidades).

<?php
	require_once "nusoap.php";
	 
        function getProd($categoria) {
	    if ($categoria == "libros") {
	        return join(",", array(
	            "El señor de los anillos",
	            "Los límites de la Fundación",
	            "The Rails Way"));
	    }
	    else {
	            return "No hay productos de esta categoria";
	    }
	}
	 
	$server = new soap_server();
	$server->register("getProd");
	$server->service($HTTP_RAW_POST_DATA);
?>

Ok, ahora necesitas un cliente, que llamaremos cliente.php. En el constructor, el cliente recibirá el url del servidor y para acceder al método que nos devuelve los libros recurriremos al método call(), al cual le pasaremos el nombre del método del servidor al que queremos acceder y los parámetros en forma de array. Además, también controlaremos que no haya errores en la comunicación.

<?php
	require_once "nusoap.php";
	$cliente = new nusoap_client("http://localhost/producto.php");
	 
	$error = $cliente->getError();
	if ($error) {
	    echo "<h2>Constructor error</h2><pre>" . $error . "</pre>";
	}
	 
	$result = $cliente->call("getProd", array("categoria" => "libros"));
	 
	if ($cliente->fault) {
	    echo "<h2>Fault</h2><pre>";
	    print_r($result);
	    echo "</pre>";
	}
	else {
	    $error = $cliente->getError();
	    if ($error) {
	        echo "<h2>Error</h2><pre>" . $error . "</pre>";
	    }
	    else {
	        echo "<h2>Libros</h2><pre>";
	        echo $result;
	        echo "</pre>";
	    }
	}
?>

Con esto ya tienes una idea múy básica del funcionamiento de un webservice SOAP construído con PHP. Pero claro, nos falta un archivo WSDL para tener un webservice decente. Aunque dicho archivo puede ser escrito a mano, NuSOAP puede generarlo por ti pasándole ciertos parámetros, por lo que lo ideal sería generarlo en el servidor. Así que modifica tu producto.php para que quede tal que así:

<?php
	require_once "nusoap.php";
	 
	function getProd($categoria) {
	    if ($categoria == "libros") {
	        return join(",", array(
	            "El señor de los anillos",
	            "Los límites de la Fundación",
	            "The Rails Way"));
	    }
	    else {
	        return "No hay productos de esta categoria";
	    }
	}
	 
	$server = new soap_server();
	$server->configureWSDL("producto", "urn:producto");
	 
	$server->register("getProd",
	    array("categoria" => "xsd:string"),
	    array("return" => "xsd:string"),
	    "urn:producto",
	    "urn:producto#getProd",
	    "rpc",
	    "encoded",
	    "Nos da una lista de productos de cada categoría");
	 
	$server->service($HTTP_RAW_POST_DATA);
?>

Como ves, el cambio en es cuando llamamos a register, ya que en vez de pasarle, como antes, el método en cuestión, le añadimos también varios argumentos para generar el WSDL:

  • El primer array nos permite definir el argumento de entrada y su tipo de datos
  • El segundo define la función de retorno y su tipo de datos
  • urn:producto es la definición del namespace
  • urn:producto#getProd es donde definimos la acción SOAP
  • Luego viene el tipo de llamada,que puede ser rpc, como en el ejemplo, o document
  • Tras esto definimos el valor del atribute use, que puede ser encoded o literal
  • Finalmente viene una descripción de qué hace el método al que llamamos

Ahora basta con que en el navegador accedas a producto.php?wsdl y verás el WSDL generado. Ya puedes copiarlo y añadirlo a tu directorio web (crea un archivo y llámalo, por ejemplo, libros.wsdl). Para que el cliente lo utilice debes modificar el código, y en el constructor, en vez del url le pasas el nombre del archivo, de forma que quede como en el ejemplo:

         $client = new nusoap_client("libros.wsdl", true);

Ahora sí, ya tienes montado un pequeño servicio web. El ejemplo es simplón, pero piensa en todas las funcionalidades que podrías incorporarle.

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.