Archive for the 'Programación' Category

Contar los clicks pero con enlaces directos

Lunes, Febrero 12th, 2007

Si tienes un directorio te interesará poder contar los clicks que hacen en los links salientes pero también te interesa que esos enlaces cuenten para los buscadores (por que de otra manera no les gustará demasiado a los webmasters que envien sus webs)

Al parecer son dos cosas no compatibles pero mediante javascript podemos conseguirlo y con JQuery de forma fácil. La táctica consiste en tener los links directos, sin pasar por ningun script que cuente los clicks, algo como esto:

<a href="http://www.google.com">Google.com</a>

Por otra parte mediante javascript detectamos cuando se hace click en esos enlaces y redireccionamos el enlace hacía nuestro script contador. Con JQuery es tan simple como esto:

<script type='text/javascript'>
$(window).load( function() {
$('a.link_out').bind("click", function() {
url = $(this).attr("href");
window.location = "/contador.php?url=" + url;
return false;
});
});
</script>

y en los links les ponemos la clase link_out:

<a href="http://www.google.com" class="link_out">Google.com</a>

Y listo, sólo faltaría crear el archivo que cuenta las visitas y hace la redirección pero eso lo dejaremos para vosotros o para otro día.

Otra opción, tal como dice ouyeah en los comentarios sería contabilizar el click mediante ajax y no hacer ninguna redirección:

<script type='text/javascript'>
$(window).load( function() {
$('a.link_out').bind("click", function() {
url = $(this).attr("href");
$.post("go.php",
{ "url": url },
function() {
window.location = url;
} );
return false;
});
});
</script>

Y la verdad es que si parece más elegante y sólo se me ocurre que puede tener algún problema en navegadores antiguos que no soporten ajax aunque tampoco tengo claro si en estos navegadores funcione JQuery.

Vodka comenta que no le funcionaba y ha tenido que modificar algo el código:

En lugar de usar:

$('a.link_out')

ha usado

$(”a”).filter(”.link_out”)

1 2 3 web: Modificando el webalizer

Jueves, Noviembre 2nd, 2006

Webalizer es un analizador de logs de servidores web muy extendido. No ofrece las mejores estadisticas, ni las más bonitas. Pero es robusto y fiable y tiene una difusión muy grande.

En neurotic hemos empezado un proyecto llamado 1 2 3 web en donde nos proponemos modificar algunos aspectos del webalizer. Ahora webalizar además de generar unos html como resultado también generará un xml. Eso nos permite procesar ese xml desde una página web cualquiera y con un lenguaje cualquiera. También permite mostrar más de unas estadisticas a la vez, con lo que si tenemos más de una web podemos verlo todo en un vistazo.

Ahora mismo todavía está en desarrollo pero ya se puede ver una demo

Permitir hotlinking añadiendo a la imagen tu dominio

Jueves, Julio 20th, 2006

Si tienes fotos en tu página y no has puesto nada para evitar el hotlinking antes o después alguien usará una de tus imágenes (sobretodo en foros y blogs). Lo más fácil es impedir que esto suceda con unas simples lineas en el .htaccess. En mi caso he usado esto en el directorio de las imágenes:

[code]
RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www\.)?tudominio.com(/)?.*$ [NC]
RewriteRule (.*) /mosquear.php [NC]
[/code]

En internet existen bastantes páginas para ayudarte en este asunto, las he usado han sido:

Con esto tenemos que en lugar de devolver la imagen cuando no se piden desde nuestro dominio se devuelve mosquear.php (se llama así por que pone una mosca). Este archivo se encarga de ponerle el borde y el texto usando ImageMagick:

[php]
< ?php
// Devuelve una foto con una mosca
// Los paths son absolutos, para saber que path es hasta tu directorio web puedes usar la variable $DOCUMENT_ROOT

// Directorio cache de imágenes. Hay de tener privilegios de escritura y lectura para el usuario del servidor web
$path_cache = "/path/to/cache_de_imagenes/";

if($_SERVER['REQUEST_URI'] != "")
$foto = $_SERVER['REQUEST_URI'];
else
$foto = "/path/to/foto_por_defecto";

$url_foto = "http://www.dominio.com" . $foto;
$foto = "/path_to_carpeta_web/" . $foto;

// Obtenemos el nombre de la imagen
$nombre_fichero = basename($foto);
$imagen_cache = $path_cache . $nombre_fichero;

if(is_file($foto))
{
// Miramos si la foto ya está en la cache
if(!is_file($imagen_cache))
{
// Copiamos la foto a la cache
copy($foto, $imagen_cache);

// Ahora le ponemos la mosca
$comando = "convert -border 0x16 -bordercolor \"#F7C700\" -weight bold -append -draw \"gravity South text 0,0 'more pics in www.tudominio.com'\" -append -draw \"gravity North text 0,0 '+ imágenes en www.tudominio.com'\" '$imagen_cache' '$imagen_cache'";
//echo "Comando: $comando
“;
system($comando, $retval);
}

// Miramos el tipo de la imagen
list($width, $height, $type, $attr) = getimagesize($imagen_cache);
$type_mime = image_type_to_mime_type($type);
if($type_mime == “”)
$type_mime = “image/jpeg”;
header(”Content-Type: $type_mime”);

if(is_file($imagen_cache))
{
readfile($imagen_cache);
//echo “

Incluimos $imagen_cache”;
}
}
else
{
echo “

Foto no encontrada

“;
echo “

La foto ” . strip_tags($url_foto) . ” no fue encontrada

“;
}
?>
[/php]

Hay que crear un directorio de cache para que sólo la primera vez que nos pidan una imagen se pongan los bordes. El script también supone que el binario convert de imagemagick está en el path y que puedes usar la función system de php.

Y ya está, si nos sobra ancho de banda pero no queremos que nos lo gasten por la cara esto es una buena solución de compromiso. Esto mismo lo he usado en www.buscatuning.com, el resultado final quedaría algo así (estos además de hacer hotlinking ponen toda la noticia entera y no sólo a nosotros, parece que les gusta mucho www.motorpasion.com)

Actualización

En ruido blanco han hecho un script que usa la librería GD (y así no tener que usar ni system ni imagemagick).

Parsear un RSS y extraer la imagen de un tag img

Miércoles, Junio 21st, 2006

En la portada de buscatuning que estamos preparando queremos poner noticias del blog. Para eso parseamos el rss del blog gracias a MagpieRSS. Nuestra intención es mostrar una foto de la noticia (si tiene) el titulo y el principio del texto.

Para mostrar una foto es necesario crear una expresion regular (o por lo menos es lo más práctico), por ejemplo ’src\s*=\s*([\”\’])?(?(1) (.*?)\\1 | ([^\s\>]+))’isx (gracias a cocososo por su ayuda). La expresión regular supone que el atributo imagen va entre comillas y siempre después de img. Es decir algo así <img src="/imagen.gif".

Para cortar al cabo de unos caracteres sin cortar ninguna palabra he usado una función que tiene smarty (si la usas recuerda que tiene licencia GPL)

function truncate($string, $length = 80, $etc = ‘…’,
$break_words = false, $middle = false)
{
if ($length == 0)
return ”;

if (strlen($string) > $length) {
$length -= strlen($etc);
if (!$break_words && !$middle) {
$string = preg_replace(’/\s+?(\S+)?$/’, ”, substr($string, 0, $length+1));
}
if(!$middle) {
return substr($string, 0, $length).$etc;
} else {
return substr($string, 0, $length/2) . $etc . substr($string, -$length/2);
}
} else {
return $string;
}
}

Al final todo junto quedaría algo así:

<?php
/**
* Funcion para truncar un string sin cortar una palabra. De Smarty.php.net (GPL)
*/
function truncate($string, $length = 80, $etc = ‘…’,
$break_words = false, $middle = false)
{
if ($length == 0)
return ”;

if (strlen($string) > $length) {
$length -= strlen($etc);
if (!$break_words && !$middle) {
$string = preg_replace(’/\s+?(\S+)?$/’, ”, substr($string, 0, $length+1));
}
if(!$middle) {
return substr($string, 0, $length).$etc;
} else {
return substr($string, 0, $length/2) . $etc . substr($string, -$length/2);
}
} else {
return $string;
}
}

// MagpieRSS
require_once(’funciones/magpierss/rss_fetch.inc’);

$url = "http://www.buscatuning.com/blog/feed/";

$rss = fetch_rss($url);

echo "Channel Title: " . $rss->channel[’title’] . "<p>";
echo "<ul>";
foreach ($rss->items as $item) {
$href = $item[’link’];
$title = $item[’title’];
echo "<li>";
echo "<h2><a href=$href>$title</a></h2>";

// Extraemos la imagen de la noticia
preg_match("’< \s*img\s.*?src\s*=\s*([\"\’])?(?(1) (.*?)\\1 | ([^\s\>]+))’isx", $item[’content’][’encoded’], $resultado );

$img = ( $resultado[3] ) ? $resultado[3] : $resultado[2];

if($img != "")
echo "<img src=’$img’ alt=’$title’ title=’$title’ />";
echo "<p>" . truncate(strip_tags($item[’content’][’encoded’]),100) . "</p>";
echo "</li>";
}
echo "</ul>";

?>

Urls amigables sin extensión y front controller

Martes, Junio 13th, 2006

Muy resumido, y seguramente mal explicado, un front controler aplicado a la web consiste en usar una página (en mi caso index.php) para gestionar todas las peticiones y mostrar el resultado en base a ellas.

Por ejemplo, yo lo he usado para mostrar las diferentes secciones de la página web de neurotic. Al index.php le paso como parámetro la sección (index.php?seccion=programacion-web) y este se encarga de mostrarla. En mi caso he usado smarty para gestionar las plantillas pero ahora usaré simplemente un include de php para no complicar más las cosas.

A continuación pongo un ejemplo de código:

// Cargamos el archivo que nos pasan via $_GET
switch($_GET[”seccion”])
{
case “home”: $seccion = “home”;break;

case “neurotic”: $seccion = “neurotic”;break;

case “diseno-web”: $seccion = “disenyo”; break;

case “programacion-web”: $seccion = “programacion”; break;

case “equipo-de-neurotic”: $seccion = “equipo”; break;

case “trabajos-diseno-web”: $seccion = “trabajos”; break;

case “proyectos-web-propios”: $seccion = “propios”; break;

default: $seccion = “home”;
}

include(”templates/$seccion/index.tpl”);

Puede parecer algo redundante el switch y se podría pensar que sería más fácil hacer un include del parámetro que nos pasan pero una regla de oro es no confiar en los parámetros (para evitar ataques de usuarios malintencionados). Con el switch nos aseguramos que $seccion tendrá sólo unos valores determinados.

Ahora ya tenemos con un sólo fichero php las secciones que queramos pero las url son bastante feas: ni amigables para los usuarios ni para los buscadores. Para lograrlo tan sólo hemos de incluir el siguiente código en nuestro .htaccess:

<ifmodule mod_rewrite.c>
RewriteEngine on
Options +FollowSymlinks

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?seccion=$1 [L,QSA]
</ifmodule>

Ahora los links en lugar de ser del tipo www.neuroticweb.com/index.php?seccion=neurotic pueden ser simplemente www.neuroticweb.com/neurotic (para que funcione esto index.php debe ser el archivo por defecto primario)

Y eso es todo, ahora sólo faltaría complicarlo un poco más introduciendo varios idiomas.

Ajax uploader

Domingo, Mayo 7th, 2006

Una de las cosas en que ajax puede ser muy útil es para diseñar un uploader que muestre el estado de la subida.

Vía digg

Añadiendo lenguajes en Drupal con Safe mode activado

Martes, Abril 25th, 2006

Intenté instalar nuevos lenguajes en drupal (4.6.6) usando el modulo locale en un servidor con el safe mode activado. Pero al subir el .po me daba el siguiente error:

warning: fopen(): SAFE MODE Restriction in effect. The script whose uid is 739 is not allowed to access /tmp/php0rBP1d.txt owned by uid 48 in /xxxx/www/html/drupal/includes/locale.inc on line 273.

warning: fopen(/tmp/php0rBP1d.txt): failed to open stream: Success in /xxxx/www/html/drupal/includes/locale.inc on line 273.

warning: Cannot modify header information - headers already sent by (output started at /xxxxx/www/html/drupal/includes/common.inc:320) in /xxxxxxx/www/html/drupal/includes/bootstrap.inc on line 695.

Busqué por los foros de drupal y había más gente con una situación similar pero las soluciones que daban no me resolvieron el problema. Al final lo que hice fue modificar el archivo file.inc (que está dentro de includes). Hay que añadir un par de lineas en la funcion file_check_upload entre estas dos lineas:

$file->filepath = $_FILES[”edit”][”tmp_name”][$source];

if (function_exists(’mime_content_type’)) {

Entre esas dos lineas ponemos:

// Movemos el archivo al tmp de drupal
if(!move_uploaded_file($file->filepath, “/tu/path/www/html/drupal/” .FILE_DIRECTORY_TEMP . “/$file->filename”))
echo “No se pudo mover el archivo ” . $file->filepath . ” a /tu/path/www/html/drupal/” . FILE_DIRECTORY_TEMP;

$file->filepath = “/tu/path/www/html/drupal/” . FILE_DIRECTORY_TEMP . “/$file->filename”;

Tal vez haya mejores soluciones pero esta me funcionó. Tengo que decir a mi favor que llevo muy poco tiempo con drupal así que tal vez esto se pueda solucionar mucho más fácilmente y no supe encontrarlo.

Nueva versión del GoogleMap

Miércoles, Junio 29th, 2005

Cómo la primera versión era muy sencilla hemos decidido ampliarla un poco usando Ajax para que el usuario del generador de googlemap pueda ir solicitando al spider que le añada más páginas de su web al sitemap.

Todavía está en fase beta, así que si alguien detecta algún error nos ayudaría mucho que nos lo comunicara.

Ahh, muchas gracias a la gente de foro buscadores por hacer de betatesters.