Si hemos elegido Amazon S3 como sistema de almacenamiento virtual , quizás nos interese tener almacenados archivos que se puedan descargar libremente por cualquier usuario, y que además puedan ser linkados desde cualquier sitio. Pero en la mayoría de los casos tendremos almacenados nuestros archivos y no nos gustará que nadie nos enlace directamente y tener que soportar los gastos de transferencia y almacenamiento por él.

Voy a explicar cómo, con un sencillo script en php conseguiremos que nuestros archivos de S3 estén totalmente protegidos y que sólo puedan ser accesibles desde nuestro dominio.

Lo primero de todo, es conocer dos características que Amazon nos prové con sus APIs:
- Los ACL (Access Control List) : que nos permite definir los permisos de lectura-escritura-ejecución de nuestros bucket y objetos.
- Las URLs Firmadas : que nos permite acceder temporalmente a nuestros archivos protegidos, a través de una url que incluye una firma y un tiempo de expiración de los permisos. Éstas URLs las podremos generar con nuestro script, y llevarán como parámetro nuestra firma generada en tiempo de ejecución, que lleva implicita el tiempo de caducidad de la url.

La primera medida es aplicar permisos exclusivo de lectura para nuestro usuario (usando los ACLs) a todos los archivos que queramos proteger, para que sea imprescindible una validación al acceder a ellos.
Para generar nuestro script , necesitaremos echar mano de la clase Crypt/HMAC para construir el hash en sha1 que Amazon S3 requiere.
Lo primero será crear nuestra función para  generar nuestra firma:

PHP:
  1. require_once 'Crypt/HMAC.php';
  2. function hex2b64($str) {
  3. $raw = '';
  4. for ($i=0; $i <strlen($str); $i+=2) {
  5. $raw .= chr(hexdec(substr($str, $i, 2)));
  6. }
  7. return base64_encode($raw);
  8. }
  9. function makeSig($str) {
  10. $secretKey="Llave secreta que nos proporciona Amazon para nuestra cuenta";
  11. $hasher =& new Crypt_HMAC($secretKey, "sha1");
  12. $signature = hex2b64($hasher->hash($str));
  13. return($signature);
  14. }

Lo siguiente, será crearnos una función para construir nuestra URL firmada :

PHP:
  1. function getSignedURL($bucket, $key, $expires=120){
  2. $accessKeyId="accessKeyId que nos proporciona Amazon con nuestra cuenta";
  3. $expires = time() + $expires;
  4. $resource = $bucket."/".urlencode($key);
  5. $stringToSign = "GETnnn$expiresn/$resource";
  6. $signature = urlencode(makeSig($stringToSign));
  7. $signedUrl="http://s3.amazonaws.com/$resource?AWSAccessKeyId=$accessKeyId&Expires=$expires&Signature=$signature";
  8. return $signedUrl;
  9. }

Ésta función nos devolverá la url firmada, que estará disponible durante el tiempo (en segundos) que hayamos establecido en el parametro $expires (120seg por defecto)

Ahora ya sólamente nos falta un script que nos lance al contenido, pero que nos proteja de links externos a nuestro dominio.
Para ésto simplemente comprobaremos si existe el campo HTTP_REFERER en nuestra variable $_SERVER , que nos indicará que estamos accediendo a ésta url desde otra url de referencia , y que nuestro dominio (extraido desde $_SERVER['HTTP_HOST']) esté contenido en él.

PHP:
  1. function get_amazon_url($amazon_bucket,$amazon_object){
  2. if(isset($_SERVER['HTTP_REFERER']) && strstr($_SERVER['HTTP_REFERER'],$_SERVER['HTTP_HOST']))   {
  3. $url=getSignedURL($amazon_bucket,$amazon_object,60);
  4. header('Location:'.$url);
  5. }else{
  6. echo 'Éste contenido ha sido enlazado ilegalmente';
  7. }
  8. }

Al llamar a ésta función, seremos automáticamente redirigidos al contenido en amazon siempre que el link provenga desde nuestro mismo dominio. Por supuesto, si quisieramos permitir el acceso desde una determinada lista de dominios, simplemente tendríamos que modificar un poco la condición if , para que compruebe que cada uno de los dominios están incluido en el HTTP_REFERER.

Espero que sea útil.
Un Saludo !!

Esta semana me he puesto ya en serio a prepararme para la certificación Zend de Ingeniero PHP.

Entre el temario del primer capítulo, encontré dos operadores que jamás había usado y me llamaron mucho la atención porque ni siquiera los había visto usados en algún otro script php. Me sonaban de cuando había estudiado C en la universidad, y efectivamente hacen lo mismo.

Los operadores "<<" y ">>" realizan un desplazamiento binario de n posiciones, hacia la izquierda o a la derecha respectivamente.

Para el que no sepa exáctamente qué es un desplazamiento binario, lo explico:

La representación binaria de 5 (decimal) es 101. Un desplazamiento binario nos sirve para desplazar, a la izquierda o a la derecha, sus dígitos.  Por lo que un desplazamiento binario de 2 posiciones sobre el numero 5 nos daría como resultado el binario 10100 (20 en decimal).
Su uso puede ser bastante útil y extremadamente eficiente cuando queremos multiplicar un número por alguna potencia de dos, ya que, internamente, el desplazamiento binario será mucho más rápido y requerirá menos operaciones que la multiplicación.

Su sintaxis es muy sencilla, y como cualquier otro operador aritmético, su asociatividad de izquierda.

PHP:
  1. $a &lt;&lt; n;

Donde n es el número de desplazamientos que queremos hacer hacia la izquierda.

Nota adicional: si pretendemos usar el desplazamiento binario tenemos que tener cierto cuidado y conocimiento de las características técnicas de la máquina en la que estamos corriendo el script. Ya que si estamos utilizando una máquina de 32bits , los datos se almacenarán, como es lógico, en palabras de 32 bits, y si intentamos realizar un desplazamiento binario de 32 posiciones, obtendremos como resultado un estupendo overflow.
Por lo que si queremos multiplicar por potencias de 2 , tened cuidado de cuántas posiciones desplazais, ya que a veces os convendrá más utilizar la función pow(n,m);

Chuletas Imprescindibles

Esta semana, Raúl Jimenez me pasó una chuleta donde venía un resumen de elementos importantes para el SEO en una web. Esto me trajo recuerdos de una magnífica chuleta que había hecho Manz sobre PHP, así que me decidí a publicar un pequeño post con cuatro de las chuletas básicas para mí como desarrollador web. Cuatro guias de referencia para PHP, SEO, ModRewrite y CSS.
Esta es mi lista ordenada según lo útiles que son para mí :P

- La primera es, cómo no, la magnífica  Emezeta Card PHP Cheatsheet (v0.2)
- El segundo puesto es para SEO Cheatsheet , de Anton Shevchuk (el link al post está en ruso, pero la chuleta en inglés)
- El tercer puesto es para Emezeta Card ModRewrite Cheatsheet (v0.1)
- Y cuarto, pero no menos importante para CSS CheatShett (V2) , de AddedBytes

Espero que os sean útiles !

Acabo de llegar de la sede de Google España :P
Gracias a Pedro (minube) me enteré de que Google organizaba un evento para desarrolladores, donde presentaba las nuevas APIs de YouTube. Así que Alex y yo nos apuntamos para asistir.
El evento fué de lo más entretenido y divertido !!
Se celebró en las oficinas de Google España, en Torre Picasso. Después de acreditarnos y subir unas cuantas plantas llegamos a las oficinas, donde nos volvieron a pedir credenciales y nos dieron nuestro pase del evento. Nos pasearon un poco por las oficinas y nos llevaron a la cafetería, donde nos esperaban unos cuantos ingenieros de Google para presentarnos las novedades de su plataforma de videos.

Nos mostraron las posibilidades que nos podía ofrecer estas nuevas APIs y luego comenzó un taller donde pusimos en práctica lo fácil que era integrar Youtube en nuestra web y utilizar su API. Todo el evento fué muy ameno y en ambiente muy informal y juvenil. Nos ofrecieron bebidas y picoteo y más tarde pizza para cenar.
Después del taller, Google dió la oportunidad de todo el que tuviese un proyecto que diera uso a Youtube, presentarlo a todos los asistentes (quizás ésta fué la parte menos interesante desde mi punto de vista :P ), momento que Alex y yo aprovechamos para hacer un poco de networking.
Allí nos encontramos con Txarly, fundador de nvivo.es, a Roger, Edgar y Paul de Mobuzz.tv, y conocimos a Dani y Rupert de Tuenti.

Es de agradecer que Google tenga éste tipo de iniciativas. Sin duda repetiría :D