Tag Archives: htaccess

Añadiendo marcas de agua al vuelo para evitar hotlinking

A partir de una entrada que aparecía esta mañana en Tu Receta, he pasado el día intentando mejorar el sistema. Ellos proponen que cuando alguien enlace directamente a una foto de tu sitio, cambiar la url mediante mod_rewrite hacía otra imagen para que en el sitio sólo pueda mostrar una imagen con algún mensaje o similar, pero no las imágenes originales. Recordé que mi amigo Migue había pasado por eso y lo resolvió, así que empece a investigar para ver cómo podría solucionarlo.

Requerimientos:

  1. Tener activado mod_rewrite en nuestro servidor
  2. PHP5-GD para trabajar con imágenes
  3. Una imagen que será la marca de agua

Lo primero que hacemos es añadir a nuestro .htaccess las nuevas reglas para mod_rewrite que son las básicamente las mismas que en Tu Receta pero cambiamos la RewriteRule así:

RewriteEngine on
RewriteBase /
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://www.muspells.net/.*$      [NC]
RewriteCond %{HTTP_REFERER} !^http://www.muspells.net$      [NC]
RewriteRule ^(.*)\.(gif|jpg|png)$ image_script.php?image=$1\.$2   [R]

Cambiamos la regla de reescritura para que apunte a un script de PHP donde editaremos al vuelo la imagen para devolverla al REFERER con una marca de agua.

Hemos llamado al script image_script y lo hemos colocado en la raíz de documentos,

<?php

// En WordPress por ejemplo las imagenes se guardan en directorios,
// necesitamos el PATH completo a la imagen.
$URI = $_GET['image'];
$URI_PARSER = explode ('/', $URI);
$image = "/path/to/DocumentRoot/".$URI_PARSER[count($URI_PARSER) - 1];

switch (TRUE) {
   case stristr($image,'jpg'):
      $photoImage = ImageCreateFromJpeg("$image");
      break;
   case stristr($image,'gif'):
      $photoImage = ImageCreateFromGIF("$image");
      break;
   case stristr($image,'png'):
      $photoImage = ImageCreateFromPNG("$image");
      break;
}

ImageAlphaBlending($photoImage, true); 

// Añadimos aquí el fichero de marca de agua.
$logoImage = ImageCreateFromPNG("watermark.png"); 
$logoW = ImageSX($logoImage); 
$logoH = ImageSY($logoImage); 

// Los 1's representan el margen con el margen superior izquierdo
ImageCopy($photoImage, $logoImage, 1, 1, 0, 0, $logoW, $logoH); 

ImagePNG($photoImage); // output to browser 

ImageDestroy($photoImage); 
ImageDestroy($logoImage); 
?>

El script colocará la imagen watermark.png en la esquina superior izquierda.

Cuando accedemos a alguna imagen de nuestro sitio de forma legítima la veremos así:

gnu

GNU

Mientras que si accedemos enlazando directamente la veremos así:

gnu

Fuentes:

  1. Tu Receta: Evitar Hot-linking con .htaccess
  2. El script

Apache, vhosts, htaccess, AllowOverride y FileInfo

Disponemos de un servidor Apache con sitios virtuales y queremos definir las páginas de error que se mostraran en caso de los 404, 500, etc.

Para ello editamos el archivo de configuración del sitio virtual en /etc/apache2/sites-available/ y en la directriz Directory establecemos el valor de AllowOverride a FileInfo de manera que nuestra configuración quedará como sigue:

ServerName URL
ServerAdmin user@localhost
DocumentRoot /var/web/
<Directory /var/web/>
Options FollowSymLinks Multiviews
AllowOverride FileInfo
Order allow,deny
allow from all
</Directory>

Así, todos los parámetros de configuración de Apache que definamos en la raíz de documentos (DocumentRoot) dentro del archivo .htaccess sobreescribiran los definidos en el fichero de configuración del servidor. En nuestro caso, FileInfo sólo contempla DocumentError.

Ahora podemos definir los mensajes o acciones a realizar en caso de error con la siguiente sintaxis:

ErrorDocument [code] [action]

Donde action puede ser:

  1. Un texto a mostrar entre comillas
  2. Una re-dirección a una url interna del servidor
  3. Una re-dirección a una url externa del servidor

Un ejemplo de la documentación de Apache

ErrorDocument 500 /cgi-bin/crash-recover
ErrorDocument 500 "Sorry, our script crashed. Oh dear"
ErrorDocument 500 http://xxx/
ErrorDocument 404 /Lame_excuses/not_found.html
ErrorDocument 401 /Subscription/how_to_subscribe.html