PHP: Como determinar si es un visitante o es un robot www (boot)

Sencillo script que permite determinar si un visitante es ó no un robot. Estoy por publicar algo sobre un nuevo tema y me encontré con este tema de los robots WWW. Me di a la tarea de investigar sobre como diferenciar a una persona que visita la pagina o a un programa de esos que andan explorando la red buscando nuevos contenidos. Antes de iniciar con el ejemplo es necesario tener bien claro dos terminos: Robot y Agente.

¿Que es un robot WWW?

Un robot WWW es un programa que recorre periodicamente la estructura de internet en busca de nuevos contenidos. La forma de operar de estos programas por lo general es recuperando un documento raiz y de manera recursiva recorrer todos los documentos a los éste que hace referencia. El orden en que estos programas hacen el recorrido por lo general es determinado despues de hacer un analisis en base a varios parametros, es decir, despues de haber aplicado tecnicas de heurística. Estos programas a veces son llamados boots www, Robots web, Web Wanderers, Web Crawlers, o Spiders (arañas). Como ves, estos nombres son un poco engañosos ya que dan la impresion de que son un software parecido a los virus ya que se mueven en la internet rastreando entre los miles de sitios web. Si embargo, estos scripts/programas por lo general andan en busca de nuevos contenidos o información para fines estadísticos.

Imaginemos que un robot (por ejemplo el robot www de Google) anda explorando la red y se encuentra con nuestro sitio web y empieza a rastrear toda la estructura de documentos que hemos creado, si estamos guardando el tracking del sitio web ¿Debemos guardar el tracking de un robot www? ¿Debemos permitirle al robot explorar nuestro sitio?. En mi opinión, para mi sitio web la respuesta para ambas preguntas es SI.

Para la primer pregunta es es si porque asi llevo el seguimiento de cuantos robots y con que frecuencia visitan mi sitio web. El tracking entre mas detallado sea, mejor. La segunda pregunta tambien me conviene ya que muy probablemente que ese robot este recabando información acerca de que tan activo es mi sitio para asi posicionarlo o reclasificarlo mejor dentro de los indices de Google ¿porque habria de desagradarme que mi sitio web apareciera entre los primeros resultados de las busquedas de Google?. Hasta la pregunta suena comica ¿no?.

En la red internet existen varios sitios web que ofrecen de manera gratuita información gratuita y muy detallada acerca de los diferentes robots www mas conocidos. Estuve buscando por varios lugares y al final opte por elegir http://www.robotstxt.org/ pues contiene un listado de los boots www mas conocidos, este listado esta en el archivo http://www.robotstxt.org/db/all.txt. Lo que me gusto es que la lista esta muy extensa y detallada. Si gustas puedes abrir la URL ahora y podras ver que el detalle de cada robot es similar a la siguiente (robot www de Google):

robot-id: googlebot
robot-name: Googlebot
robot-cover-url: http://www.googlebot.com/ 
robot-details-url: http://www.googlebot.com/bot.html
robot-owner-name: Google Inc.
robot-owner-url: http://www.google.com/
robot-owner-email: googlebot@google.com 
robot-status: active
robot-purpose: indexing
robot-type: standalone 
robot-platform: Linux
robot-availability: none
robot-exclusion: yes
robot-exclusion-useragent: googlebot
robot-noindex: yes
robot-host: googlebot.com
robot-from: yes 
robot-useragent: Googlebot/2.X (+http://www.googlebot.com/bot.html)
robot-language: c++
robot-description: Google's crawler
robot-history: Developed by Google Inc
robot-environment: commercial
modified-date: Thu Mar 29 21:00:07 PST 2001
modified-by: googlebot@google.com

¿Que es Agente?

En informatica este termino se usa en muchisimos contextos pero en general podemos distinguir facilmente a los Agentes autonomos, los agentes inteligentes y a los agentes de usuario (User-agent). En este caso estamos interesados en los agentes de usuario, los cuales son programas que realizan tareas de red para un usuario.

Ejemplos de agentes de este tipo son los programas de navegacion (Mozilla Firefox, Netscape Navigator, Microsoft Internet Explorer, Google Chrome, Safari, etc) ó los clientes de correo electronico (Mozilla Thunderbird, Microsoft Outlook, etc).

Como hacer la distincion de un boot www

La forma de detectar al tipo de visitante es por medio del nombre del agente que accede a nuestro sitio. En PHP existe la variable global $_SERVER[‘HTTP_USER_AGENT’] que nos devuelve una cadena que indica el agente de usuario empleado para acceder a la pagina. A continuacion muestro el contenido que devuelve esta variable en varios navegadores (con ayuda de phpinfo()):

Google Chrome v. 22.0.1229.94 m
Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4
Firefox v. 13.0.1
Mozilla/5.0 (Windows NT 6.1; rv:13.0) Gecko/20100101 Firefox/13.0.1
Internet Explorer v. 8.0.7600.16385
Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)
Safari v. 5.1.7 (7534.57.2)
Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2

Implícitamente usaremos la información de esta variable para detectar a un robot www.

El codigo fuente para detectar robots www

Para hacer la distincion del agente que esta visitando nuestro sitio web aprovecharemos el listado de nombres de boots que mencione anteriormente: http://www.robotstxt.org/db/all.txt.

Basicamente leeremos ese archivo de texto desde un script PHP linea a linea y guardaremos el nombre de cada robot en un arreglo.
Despues compararemos cada item del arreglo contra el nombre del agente de usuario que esta visitando la pagina (valor que esta en la variable global $_SERVER[‘HTTP_USER_AGENT’]). Obviamente el visitante es un robot si el nombre del agente coincide con el nombre de algún robot del arreglo. A continuacion muestro el codigo:

<?php
/*
	Descripcion: Contiene una funcion que determina si el visitante es un robot www.
	Para esto hace uso del sitio http://www.robotstxt.org/db/all.txt
	que contiene un listado de los robots mas conocidos.
	Author: Gonzalo Silverio  gonzasilve@gmail.com
*/

/*
Parametros: El nombre de un agente de usuario.
Devuelve: true en caso de que el nombre del agente sea un nombre de robot
					false si el agente NO es un robot.
*/
	function esRobot($agente) {
		$archivoRobots = "http://www.robotstxt.org/db/all.txt";
		$delimitador1 = "robot-name:";
		$delimitador2 = ":";
		if (trim($agente)=="") $agente=trim($_GET['agente']);
		if (trim($agente)=="") $agente=trim($_SERVER['HTTP_USER_AGENT']);
		
		//Obtener el contenido del archivo como un array en donde cada item es una linea del archivo.
		$str_archivo = @file($archivoRobots);
		$total_lineas = count($str_archivo);

    $i = 0;
		$r = 0;
		$lista_robots = array();
		
    while ($i<=$total_lineas)    {
      $linea = chop($str_archivo[$i]);
			if(   (strpos($linea, $delimitador1) !== false) ) {
				$items= explode($delimitador2,$linea);
				$lista_robots[$r] = trim($items[1]);
				$r++;
			}
      $i++;
    }

		//Determina si la cadena que llega es un robot
		foreach($lista_robots as $robot)	{
			if(strpos($agente, trim($robot) )  !== false)
			return true;
		}
		return false;

	}

	//Ejemplos de como usar la funcion anterior:
	//Sintaxis 1
	if( esRobot("Pioneer") ) echo "SI"; else echo "NO";
	echo "<br/>";
	
	if( esRobot() ) echo "SI"; else echo "NO";
	echo "<br/>";	
	
	if( esRobot( trim($_SERVER['HTTP_USER_AGENT']) ) ) echo "SI"; else echo "NO";

?>

Si tienes duda acerca de como se usan algunas funciones de php te aconsejo que visites la pagina oficial de documentacion de PHP.
Al ejecutar el código anterior debes ver algo como:

SI
NO
NO

Si eres observador te darás cuenta que la ejecucion tarda un tiempo considerable ya que tiene que leer todo un archivo que esta en linea y debe parsearlo por completo y ademas depende de un sitio; si dicho sitio borra el archivo con los nombres de robots o le cambia de nombre o el formato en como estan organizados entonces la funcion anterior dejara de funcionar de manera correcta. Para solucionar esto vamos a bajar una copia del archivo y guardar unicamente los nombres de los robots, en cada linea estara el nombre de un robot y un delimitador, algo asi:

ABCdatos BotLink|#|
Acme.Spider|#|
Ahoy! The Homepage Finder|#|
Alkaline|#|
Anthill|#|
Walhello appie|#|
Arachnophilia|#|
Arale|#|
Araneo|#|
AraybOt|#|
ArchitextSpider|#|
..
... etc.

En este caso el delimitador es |#| y no una coma (,) ya que es posible que el nombre de un robot tenga ese caracter.

A continuación pongo otra versión del script para detectar robots pero ahora lee un archivo de texto local que tiene la sintaxis mencionada anteriormente:

<?php
/*
	Descripcion: Contiene una funcion que determina si el visitante es un robot www.
	Para esto hace uso del archivo local archivos/listaRobots.txt
	que contiene un listado de los robots mas conocidos.
	Author: Gonzalo Silverio  gonzasilve@gmail.com
 */

/*
	Parametros: El nombre de un agente de usuario.
	Devuelve: true en caso de que el nombre del agente sea un nombre de robot
	false si el agente NO es un robot.
 */
	function esRobot($agente) {
		$delimitador = "|#|";
		$archivoRobots = "archivos/listaRobots.txt";
		if (trim($agente)=="") $agente=trim($_GET['agente']);
		if (trim($agente)=="") $agente=trim($_SERVER['HTTP_USER_AGENT']);

		//Obtener el contenido del archivo como una cadena.
		$str_archivo = file_get_contents($archivoRobots,FILE_USE_INCLUDE_PATH);
		//Convertir cadena a arreglo con ayuda del delimitador
		$lista_robots = explode($delimitador,$str_archivo);

		foreach($lista_robots as $robot)	{
			if(strpos($agente, trim($robot) )  !== false)
				return true;
		}
		return false;
	}

	//Ejemplos de como usar la funcion anterior:
	//Sintaxis 1
	if( esRobot("Pioneer") ) echo "SI"; else echo "NO";
	echo "<br/>";

	if( esRobot() ) echo "SI"; else echo "NO";
	echo "<br/>";	

	if( esRobot( trim($_SERVER['HTTP_USER_AGENT']) ) ) echo "SI"; else echo "NO";

?>

Que facil ¿no?. Este dato podrias guardarlo en la base de datos para llevar un conteo de los robots que visitan tu sitio web. El resultado debe ser similar al anterior:

SI
NO
NO

 

Eso es todo. Si deseas el código basta con que dejes tu e-mail y en cuanto vea tu mensaje te hago llegar el ejemplo. Si te gusto el articulo, te invito a que me dejes un comentario, pero sobre todo a que me sigas visitando.

Saludos cordiales.

 
 

PHP: Validar un numero entero

La siguiente funcion permite validar si una cadena esta compuesta unicamente de numeros.
Parametros: La cadena.
Devuelve: true en caso de que el parametro solo vengan numeros, false en caso contrario.

El codigo

function soloNumeros($laCadena) {
	$carsValidos = "0123456789";
	for ($i=0; $i<strlen($laCadena); $i++) {
	  if (strpos($carsValidos, substr($laCadena,$i,1))===false) {
		 return false; 
	  }
	}
	return true; 
}

//Ejemplo
$cad1 = "6878456";
$cad2 = "687a456";

if( soloNumeros($cad1) ) 
	echo "$cad1 es un Entero.<br/>";
else 
	echo "$cad1 NO es un Entero.<br/>";

if( soloNumeros($cad2) ) 
	echo "$cad2 es un Entero.<br/>";
else 
	echo "$cad2 NO es un Entero.<br/>";

/*
Salida:
6878456 es un Entero.
687a456 NO es un Entero.
*/

 

Si te gusto el ejemplo deja un comentario, igualmente si tienes otra versión Saludos.
 
 
Enlaces relacionados:
 
 

PHP: Sumar o Restar Dias a cualquier fecha

Fechas en PHP

Si deseas sumarle o restarle dias a una fecha cualquiera puedes usar la siguiente función que pongo a continuación; la cual espera como entrada una fecha y un numero de días. Si Deseas sumar días, solo pasa el numero sin signo. Si deseas restar dias pasale un numero negativo.
 
 
 
 

El codigo

function dameFecha($fecha,$dia)
{	list($day,$mon,$year) = explode('/',$fecha);
	return date('d/m/Y',mktime(0,0,0,$mon,$day+$dia,$year));		
}
 
 //Sumar 5 dias
echo dameFecha('18/09/2012',5);
//Salida: 23/09/2012

 //Restar 5 dias  
echo dameFecha('18/09/2012',-5);
//Salida: 13/09/2012

//Sumar 12 dias a la fecha actual
echo dameFecha(date('d/m/Y'),12);
//Salida: ...depende de la fecha actual

¿Sencillo y facíl no?

 

Deja tus inquietudes en un comentario. Saludos.
 
 
Enlaces relacionados:
 
 

PHP: Transformar un arreglo a un string separado por comas

Si deseas separar un arreglo en una cadena que tenga sus elementos separados con algun separador puedes usar la siguiente funcion que pongo a continuacion; la cual espera como entrada un arreglo y un caracter separador.

El codigo

function arrayAString($miArray,$sep) {
	echo implode($sep,$miArray);
}

	//Ejemplo
	$elArreglo = array('Carlos','Daniel','Xavier','Gonzalo','Karla');	
	echo arrayAString($elArreglo,',');
	//Salida: Carlos,Daniel,Xavier,Gonzalo,Karla

Como ves básicamente he renombrado a la función implode de PHP (no confundir con explode que hace lo contrario). ¿Facíl no?

 

Deja tu comentario si tienes alguna duda. Que estés bien, te mando saludos cordiales.
 
 
Enlaces relacionados:
 
 

PHP: Restar o Sumar Dias, Semanas, Meses o Años a la fecha actual

Recordemos que la funcion date(‘Y-m-d’), nos devuelve la fecha actual en el formato ‘Año-mes-dia’ y si queremos otro formato solo cambiamos el orden, por ejemplo date(‘d-m-Y’). El siguiente script muestra como Restar Dias, Semanas, Meses o Años a la fecha actual en PHP.

El codigo

$dt_Ayer= date('Y-m-d', strtotime('-1 day')) ; // resta 1 día
$dt_laSemanaPasada = date('Y-m-d', strtotime('-1 week')) ; // resta 1 semana
$dt_elMesPasado = date('Y-m-d', strtotime('-1 month')) ; // resta 1 mes
$dt_ElAnioPasado = date('Y-m-d', strtotime('-1 year')) ; // resta 1 año
//Mostrar fechas
echo $dt_Ayer;
echo $dt_laSemanaPasada;
echo $dt_elMesPasado;
echo $dt_ElAnioPasado;
/*
Resultado (fecha actual: 2012-09-18):
2012-09-17
2012-09-11
2012-08-18
2011-09-18
*/

…Por el contrario si lo que deseas es sumar entonces solo cambias el signo – por un +, asi:
$dt_5DiasDespues = date('Y-m-d', strtotime('+5 day')) ; // Suma 5 días
$dt_5SemanasDespues = date('Y-m-d', strtotime('+5 week')) ; // Suma 5 semanas
$dt_5MesesDespues = date('Y-m-d', strtotime('+5 month')) ; // Suma 5 meses
$dt_5AniosDespues = date('Y-m-d', strtotime('+5 year')) ; // Suma 5 años
//Mostrar fechas
echo $dt_5DiasDespues;
echo $dt_5SemanasDespues;
echo $dt_5MesesDespues;
echo $dt_5AniosDespues;
/*
Resultado (fecha actual: 2012-09-18):
2012-09-23
2012-10-23
2013-02-18
2017-09-18
*/

¿Facil, no?

 

Si tienes alguna duda expresala en un comentario. Saludos.
 
 
Enlaces relacionados:
 
 

PHP: Convertir cadena con separadores a Array

Si tienes una cadena separada con espacios, comas o cualquier otro separador es fácil convertirla en un array con la función explode de PHP.

El codigo

// Ejemplo 1
$miCadena  = "piece1 piece2 piece3 piece4 piece5 piece6";
$piezas = explode(" ", $miCadena);
/*
Resultado:
Array   piezas
( 
[0] piece1
[1] piece2
[2] piece3
[3] piece4
[4] piece5
[5] piece6
*/
…Por el contrario si los elementos de la cadena son pocos y deseas ponerlos en una variable a cada uno:
// Ejemplo 2
$data = "foo:*:1023:1000::/home/foo:/bin/sh";
list($user, $pass, $uid, $gid, $gecos, $home, $shell) = explode(":", $data);
echo $user."<br/>";
echo $pass."<br/>"; 
echo $uid."<br/>";
echo $gid."<br/>";
// ..etc
/*
Resultado:
foo
*
1023
1000
*/

// Ejemplo 3 (separar dia, mes y año de la fecha actual)
list($dia,$mes,$anio) = explode('/',date('d/m/Y') );
echo $dia."<br/>";
echo $mes."<br/>";
echo $anio."<br/>";
La funcion explode devuelve un array y sus elementos son asignados a una lista de variables con ayuda de la funcion list de php.

 

Si te gusto el código expuesto o tienes alguna critica constructiva, déjame un comentario. Saludos cordiales.
 
 
Enlaces relacionados:
 
 

PHP: Obtener el ultimo día de cualquier mes

A veces cuando manejamos fechas, es necesario saber cual es el ultimo día del mes actual. Ho en general cual es el ultimo dia de un mes X. Por ejemplo Febrero tiene por lo general 28 ó 29 dias mientras que Diciembre 31. La funcion que muestro en el siguiente Script calcula y devuelve el ultimo día de cualquier mes, pasandole unicamente el año y mes deseado:

El codigo

function getUltimoDiaMes($elAnio,$elMes) {
  return date("d",(mktime(0,0,0,$elMes+1,1,$elAnio)-1));
}

//Ejemplo de uso
$ultimoDia = getUltimoDiaMes(2013,10);
echo $ultimoDia."<br/>";
echo getUltimoDiaMes(2012,09)."<br/>";
/*
Resultado:
31
30
*/

 

Si te gusto el código expuesto, déjame un comentario. Saludos cordiales.
 
 
Enlaces relacionados:
 
 

PHP: Mostrar la fecha actual en español

Sencillo script para mostrar la fecha actual en español, recuerda que para copiar el ejemplo puedes usar el botón ‘copiar al portapapeles’.

El codigo

   $arrayMeses = array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio',
   'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre');

   $arrayDias = array( 'Domingo', 'Lunes', 'Martes',
       'Miercoles', 'Jueves', 'Viernes', 'Sabado');
	
	echo $arrayDias[date('w')].", ".date('d')." de ".$arrayMeses[date('m')-1]." de ".date('Y');
/*
Resultado, (fecha actual 21/09/2012):
Viernes, 21 de Septiembre de 2012
*/
Como ves, facilmente puedes crear una funcion que reciba una fecha y que devuelva en forma de cadena la fecha como se ve en el ejemplo.

 

Si te gusto el ejemplo ó si tienes alguna duda, te invito a que me dejes un comentario.

Saludos.

 
 
Enlaces relacionados:
 
 

PHP: Eliminar elementos duplicados de un Array

Este sencillo script te permitira quitar elementos que se esten repitiendo dentro de un array. La ultima conversion (array_values) te permitira acceder a estos elementos a travez de numeros indice, empezando con 0. En este caso muestro dos ejemplos, uno con numeros y otro con textos:

El codigo

Para copiar el ejemplo puedes dar doble click sobre el codigo.
//Ejemplo 1
 $lista = array(2010,2009,1999,2010,2010,2008,2010);
 $listaSimple = array_unique($lista);
 $listaSimpleFinal = array_values($listaSimple);
/*
Resultado:
Array   listaSimpleFinal
(
[0] = 2010
[1] = 2009
[2] = 1999
[3] = 2008
)
*/

//Ejemplo 2
 $lista = array('Carlos','Daniel','Xavier','Carlos','Gonzalo');
 $listaSimple = array_unique($lista);
 $listaSimpleFinal = array_values($listaSimple);
/*
Resultado:
Array   listaSimpleFinal
(
[0] = 'Carlos'
[1] = 'Daniel'
[2] = 'Xavier'
[3] = 'Gonzalo'
)
*/

 

Si te gusto el ejemplo, te invito a que me dejes un comentario, así me motivas a escribir más.

Saludos cordiales.

 
 
Enlaces relacionados: