Gracias, Wikipedia.
Herramientas::Versión móvil para cuantarazon.com
Permalink: http://www.treeweb.es/u/1213/ 23/06/2012

Versión móvil para cuantarazon.com

La web cuantarazon.com es ideal como pasatiempo para esas esperas en la fila de la compra o para matar esos 5 minutos entre clase y clase.

Para ver la página original en el móvil hay que descargarse la friolera de 1400 KiB con el consiguiente gasto de la tarifa móvil de datos. Además, la web original carga múltiples animaciones flash, lo que significa un mayor consumo de batería. Desde el punto de vista de la usabilidad, si cargamos cuantarazon.com en un dispositivo móvil, hay que hacer scroll horizontal para visualizar la imagen completa, lo que es muy molesto, o ajustar el nivel de zoom de la página.

Todos estos inconvenientes se resuelven en la versión móvil que se presenta aquí. Acceder a cuantarazon movil se descargan únicamente 53 KiB con lo que verdaderamente importa: las imágenes de la web. Por si fuera poco, cada imagen se optimiza ajustándose a la resolución de la pantalla de tu móvil, lo que reduce el tamaño del archivo. Además, al no tener animaciones flash, se ahorra batería Es muy sencillo de usar, ya que sólo hay que hacer scroll vertical con el dedo, todas las imágenes aparecen perfectamente alineadas.

En resumen, en www.treeweb.es/cr un script se encarga de acceder a la página original, aligerar y aligerar cosas y devolverla al móvil para que se vea perfectamente.

El código que he utilizado queda a disposición de cualquiera, para que pueda aprender a hacer cosas similares, o simplemente lo utilice en su propio servidor. 

El código

Los archivos se organizan con la siguiente estructura de directorios:
  • cr
    • index.php
    • css.css
    • js.js
    • ajax
      • img
        • index.php
      • load_more.php
Veamos el código de cada uno de los archivos:

index.php

Este archivo contiene las siguientes partes importantes:
  • Los meta necesarios para visualizar correctamente en un dispositivo móvil
  • Algunos elementos HTML que se rellenarán con javascript
  • Se encarga de incluir los css y js
<!DOCTYPE HTML> <html lang="ES"> <head> <meta http-equiv="Content-Type" CONTENT="text/html; charset=UTF-8"> <meta name="apple-touch-fullscreen" content="YES"> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"> <title>Cuanta Razón CR - Versión móvil APP</title> <meta name="description" content="Cuanta Razón, CR, versión móvil. Es gratuita, gratis, 0€. Funciona con Android, HTML5, iPhone, Samsung, Motorola, Windows Mobail, Windows Phone, Symbian, y más."> <meta name="keywords" content="carteles, desmotivacionales, fotos, chistes, humor, videos, carcajadas, risa, divertido, humoristico, gracioso"> <script type="text/javascript"> <?php echo file_get_contents('js'); ?> </script> <style type="text/css"> <?php echo file_get_contents('css'); ?> </style> </head> <body> <div class="top-bar">Cuanta Razón APP</div> <div class="app"> <div id="imagenes"></div> <div class="button-more"> <button onclick="load_more()">Más !</button> </div> </div> </body> </html>

css.css

Este archivo sólo tiene algunos estilos para ajustar al ancho y mantener la cabecera siempr
HTML { margin:0; padding:0; overflow:hidden; } BODY { margin:0; padding:0; overflow:hidden; background:black; font-family:Verdana, Arial, sans-serif; } .top-bar { position:absolute; top:0; left:0; right:0; height:20px; background:#00AEED; color:white; text-align:center; font-size:16px; } .app { position:absolute; top:20px; bottom:50px; left:0; right:0; overflow-y: scroll; } #imagenes IMG { display:block; width:100%; margin-bottom:32px; } .button-more { text-align:center; } .button-more BUTTON { color:white; border:none; padding:32px; background:#00AEED; margin:32px; font-size:150%; font-weight:bold; }

js.js

Este archivo se encarga de hacer una petición ajax al servidor, con las nuevas imágenes y guardar el número de la última página que hemos descargado.

Es importante observar que al montar las urls de las imágenes, también se pasa el ancho del navegador (window.innerWidth) para que el servidor pueda redimensionar las imágenes de forma acorde al terminal móvil.
Ajax = function (url) { this.query = function (params) { var data = '';//'q='+encodeURIComponent(q); for (key in params) data += key+'='+encodeURIComponent(params[key])+'&'; ajax.setRequestHeader('Content-length', data.length ); ajax.send(data); } this.setCallback200 = function (cb) { _callback200 = cb; } /* CONSTRUCTOR */ var _callback200 = null; var ajax = null; try { // Firefox, Opera 8.0+, Safari ajax = new XMLHttpRequest(); } catch (e) { // Puto y pestilente Internet Explorer try { ajax = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { ajax = new ActiveXObject("Microsoft.XMLHTTP"); } } ajax.open('POST', url, true); ajax.setRequestHeader('Connection', 'close'); ajax.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); ajax.onreadystatechange = function () { if (ajax.readyState == 4) { if (ajax.status == 200) { if (_callback200!=null) _callback200(ajax.responseText); } } } } var page = 0; function load_more() { page++; var w = window.innerWidth; var ajax = new Ajax('/cr/ajax/load_more.php'); ajax.setCallback200(function(text){ var json = eval('('+text+')'); var imagenes = document.getElementById('imagenes'); for (k in json) { var img = document.createElement('img'); img.src = '/cr/ajax/img/?id='+json[k]+'&w='+w; imagenes.appendChild(img); } }); ajax.query({'p':page}); } load_more();

ajax/load_more.php

Este archivo es el importante, se encarga de ir a la web, descargar el HTML y obtener las URLs de las imágenes correspondientes.

Para parsear el contenido se utiliza la librería DOM de PHP, mucho más eficiente que cualquier parser manual que podamos hacer con PHP. Para que funcione correctamente, primero se elimina la primera línea correspondiente al DTD.

Después la función 'recorrer()' busca todos los nodos del documento cuya clase sea 'crlink' y procesa ese nodo con la función 'historieta()'.

Finalmente, se envía la respuesta serializada con JSON.
<?php error_reporting(0); $p = $_POST['p']; $xml = file_get_contents('http://www.cuantarazon.com/ultimos/p/'.$p); $xml = substr($xml, strpos($xml, "\n")+1); $doc = new DOMDocument(); $doc->loadHTML($xml); $node = $doc->documentElement; $data = array(); recorrer($node, $data); echo json_encode($data); function recorrer($node, &$data) { if ($node->nodeType == 1) { if ($node->getAttribute('class') == 'crlink') { $data[] = historieta($node); } else { foreach ($node->childNodes as $child) recorrer($child, $data); } } } function historieta($node) { $src = $node->childNodes->item(0)->getAttribute('src'); $md5 = md5($src); if (!file_exists('cr/original/'.$md5)) { copy($src, 'cr/original/'.$md5); } return $md5; } ?>

ajax/img/index.php

Este código también es bastante importante. Se encarga de guardar una copia de las imágenes, para no abusar del ancho de banda del servidor original. Además, también redimensiona y baja la calidad de las imágenes para reducir su tamaño.
<?php $MAX_WIDTH = 550; $MIN_WIDTH = 200; $md5 = $_GET['id']; $width = $_GET['w']; $path_original = 'cr/original/'.$md5; if (isValidMd5($md5) && file_exists($path_original)) { if ($width == '') { header("Content-type: image/jpeg"); header("Content-Length: ". filesize($path_original)); readfile($path_original); } else { if ($width < $MIN_WIDTH) $width = $MIN_WIDTH; if ($width > $MAX_WIDTH) $width = $MAX_WIDTH; header("Content-type: image/jpeg"); $size = getimagesize($path_original); $size_w = $size[0]; $size_h = $size[1]; $im = @imagecreatefromjpeg($path_original); $new_w = $width; $new_h = intval($width*($size_h-72)/($size_w-84)); $nim = $image_p = imagecreatetruecolor($new_w, $new_h); imagecopyresampled ($nim, $im, 0, 0, 42, 42, $new_w , $new_h , $size_w - 84 , $size_h - 72 ); imagejpeg($nim, null, 50); } } function isValidMd5($md5) { return !empty($md5) && preg_match('/^[a-f0-9]{32}$/', $md5); } ?>