Utilizar AmazonS3 para descargas

20-08-2009 | Categoría: Internet 2 comentarios »

Un cliente nos pidió que pusiéramos en su web un apartado de descargas de ficheros, nada fuera de lo común si no hubiera sido por el tamaño de los ficheros a descargar: uno de 700MB y otro de 1,5GB

Lo hubiéramos podido poner en su web, por espacio de disco no era, pero para evitar posibles saturaciones de transferencia del servidor y que afectara a otras webs alojadas en el mismo optamos por otra solución: Amazon S3

datacenterPara quien no lo sepa: Amazon S3 es un servicio de almacenamiento de archivos de la empresa Amazon que tiene un coste normal, pero la ventaja que cobra según el espacio consumido y la transferencia (además de otros pequeños conceptos), teniendo la gran ventaja su escalabilidad, es decir, podemos almacenar todo lo que queramos (y podamos pagar) sin preocuparnos de ir añadiendo discos ni contratando más espacio.

Volviendo al problema inicial, optamos también por proporcionar una dirección que no implicara el nombre de amazon S3 (s3.amazonaws.com) para poder cambiar de proveedor o realizar otros cambios sin tener que ir revisando todos los enlaces. Para ello creamos en las entradas de nuestro dominio arcadina.net un CNAME (un alias) llamado “cdn” que apuntara a cdn.arcadina.net.s3.amazonaws.com. De esa forma un fichero que tenga como dirección http://cdn.arcadina.net/descargas/fichero.zip realmente apuntará a http://cdn.arcadina.net.s3.amazonaws.com/descargas/fichero.zip

Pero para que ésto funcione hemos de crear en nuestra cuenta de Amazon S3 un bucket (un contenedor) que se llame exactamente cdn.arcadina.net. Para los puristas, se que S3 no es un CDN como tal, que para eso Amazon tiene otro servicio: CloudFront, pero no se me ocurrió otro nombre ;)

Para subir los ficheros a S3 hemos utilizado un script en PHP que utiliza una clase para gestionar la conexión con AmazonS3. La clase se puede encontrar aqui: http://undesigned.org.za/2007/10/22/amazon-s3-php-class

De esta forma cuando alguien se descargue el fichero de 1,5GB el servidor donde se encuentra la web no se verá afectado de ninguna forma.

Tratamiento del AJAX en un solo fichero

18-08-2009 | Categoría: Desarrollo No hay comentarios »

Últimamente estoy desarrollando sobre todo con PHP+JavaScript (jQuery). En un proyecto interno de Arcadina, que hace un uso intensivo del AJAX, decidí probar un planteamiento diferente del utilizado hasta ahora.

Normalmente las llamadas a la parte AJAX del servidor se hacen a diferentes scripts PHP en función de lo que deseamos obtener (query) o guardar (submit). Por ejemplo, si estamos tratando una lista de clientes podemos llamar a get_cliente.php para solicitar los datos de un cliente pasando su identificador, podemos llamar a delete_cliente.php para eliminarlo o a save_cliente.php para guardar cambios en la ficha, etc. (tengo la manía de utilizar spanglish en el nombre de funciones, procedimientos, etc.). Ejemplo de llamada según esté método:

?Descargar form1.php
1
2
3
4
5
<form name="ejemplo1" action="/api/save_cliente.php" method="post">
<input type="hidden" name="id" value="<?= $cliente->id ?>">
Nombre: <input type="text" name="nombre" value="<?= $cliente->nombre ?>"><br/>
EMail: <input type="text" name="email" value="<?= $cliente->email ?>"><br/>
</form>

Según el proyecto va avanzando nos podemos encontrar con decenas de scripts: get_<em>loquesea</em>, delete_<em>loquesea</em>.... En cada uno de ellos añadir el código de validación, los includes, etc. Se me ocurrió centralizarlo en dos ficheros ajaxsubmit.php y ajaxquery.php, y utilizar un parametro para indicar la acción a realizar. Ejemplo de un formulario utilizando este sistema:

?Descargar form2.php
1
2
3
4
5
6
<form name="ejemplo2" action="/api/ajaxsubmit.php" method="post">
<input type="hidden" name="ajaxsubmit" value="save_cliente">
<input type="hidden" name="id" value="<?= $cliente->id ?>">
Nombre: <input type="text" name="nombre" value="<?= $cliente->nombre ?>"><br/>
EMail: <input type="text" name="email" value="<?= $cliente->email ?>"><br/>
</form>

Como se ve tampoco es que varíe mucho en la parte que se envía al navegador, se añade un nuevo campo oculto “ajaxsubmit” que indica la acción que queremos realizar. Veamos el ajaxsubmit.php:

?Descargar ajaxsubmit.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
<?php
 
// Incluimos código mínimo de autenticación y librerías
include('includes.inc.php');
 
// Si no está logeado el usuario, devolvemos error
if (!isset($usuario_login) || ($usuario_login == '')) {
 
	$respuesta['resultado'] = 'nok';
	$respuesta['mensaje'] = 'Error: primero debe identificarse';
 
} else {
 
	$respuesta['resultado'] = 'nok';
	$respuesta['mensaje'] = 'Error no identificado';
 
	$ajaxsubmit = $_POST['ajaxsubmit'];
 
	// "AS_" viene de AjaxSubmit ... ;)	
	$funcion = 'AS_' . $ajaxsubmit;
	// Comprobamos que tenemos una función con ese nombre
	if (function_exists($funcion)) {
		$funcion(); // Llamamos a la función AS_ que indique el ajaxsubmit
	} else {
		$respuesta['resultado'] = 'nok';
		if ($ajaxsubmit == '') {
			$respuesta['mensaje'] = 'No se ha indicado "ajaxsubmit"';
		} else {
			$respuesta['mensaje'] = 'AjaxSubmit: orden "' . $ajaxsubmit . '" no reconocida.';
		}		
	}
 
}
 
// Si el resultado es NOK registramos en el log de errores
if ($respuesta['resultado'] == 'nok') {
	error_log('*** AJAXSUBMIT - error - ' . $respuesta['mensaje']);
}
 
// ---------------------------------------------------------------------------------------
// Devolvemos respuesta en formato JSON
$json = new Services_JSON;
echo $json->encode($respuesta);
 
exit;
 
// =======================================================================================
// Procesos de guardar, eliminar, actualizar, etc...
// =======================================================================================
 
function AS_save_cfg() {
 
	global $respuesta;
	$cfg = array();
 
	foreach($_POST as $clave => $valor) {
		// Comprobar si $clave empieza por 'cfg_'
		if (ereg('^cfg_', $clave)) {
			$k = ereg_replace("^cfg_", "", $clave);
			$cfg[$k] = $valor;
		}
	}
	$errormsg = SaveConfig($cfg);
	if ($errormsg == 'ok') {
		$respuesta['resultado'] = 'ok';
		$respuesta['mensaje'] = 'Configuración guardada';
	} else {
		$respuesta['resultado'] = 'nok';
		$respuesta['mensaje'] = $errormsg;
	}
 
}
 
function AS_save_cliente() {
 
	global $respuesta;
 
	// Código simplificado para el ejemplo: se debería
	// añadir validación y protección contra SQL injection
	$cliente = new Cliente($_POST['id']);
	$cliente->nombre = $_POST['nombre'];
	$cliente->email = $_POST['email'];
 
	$errormsg = $cliente->Save();
	if ($errormsg == 'ok') {
		$respuesta['resultado'] = 'ok';
		$respuesta['mensaje'] = 'Cliente guardado';
	} else {
		$respuesta['resultado'] = 'nok';
		$respuesta['mensaje'] = $errormsg;
	}
}
 
?>

La “gracia” del código está en ésta parte:

19
20
21
22
23
24
25
	$ajaxsubmit = $_POST['ajaxsubmit'];
 
	// "AS_" viene de AjaxSubmit ... ;)	
	$funcion = 'AS_' . $ajaxsubmit;
	// Comprobamos que tenemos una función con ese nombre
	if (function_exists($funcion)) {
		$funcion(); // Llamamos a la función AS_ que indique el ajaxsubmit

Lo que se envia en la variable “ajaxsubmit” es el nombre de la función a llamar, pero la precedemos de “AS_” para evitar conflictos con otros nombres de funciones. Entonces gracias a la magia de PHP, porque es un lenguaje de script, aprovechamos la variable $funcion para realizar una llamada a una funcion: $funcion()

¿Qué ventajas tiene este sistema? Tenerlo centralizado, de esa forma, añadir una capa de autenticación o variar el formato de salida de JSON a XML, por ejemplo, es mucho más sencillo. Evidentemente si alguna función es compleja se puede separar en un fichero aparte y hacer el correspondiente include, que además lo recomiendo.

Para facilitar la labor de serializar los inputs de un formulario y enviarlo por ajax estoy utilizando el plugin ajaxForm para jQuery.

Total rediseño del blog

09-08-2009 | Categoría: Blogging 2 comentarios »

Me había cansado del estilo minimalista del tema anterior, tampoco es que el actual esté muy cargado.

He utilizado el tema “Green Park 2” de Cordobo, con algunos retoques (cabecera, sidebar, etc.). En el sidebar he puesto un dibujo hecho por mi hermana (www.elisatalens.com) que expresa muy bien la conversación necesaria en un blog.

Durante los próximos días terminaré de hacer otros pequeños cambios. Espero que os guste.

Nota: La foto de la cabecera la tomé en Asturias, en el cabo de Peñas, en verano del 2007.

Desvinculado twitter del blog

31-07-2009 | Categoría: Blogging 2 comentarios »

Gracias a un comentario del “Informático de Guardia”, en un correo por otro asunto, que me decía que le echó para atrás mi blog al ver tanto twitt, he decidido cortar por lo sano y eliminar todas las entradas que venían de mis cuenta de Twitter. He llegado a la conclusión que cada cosa es diferente.

A partir de ahora cuando publique un post en el blog si que se añadirá un twitt en mi cuenta, pero no en sentido contrario.

Gracias Jose Antonio.

Interfaz ordenador-persona

12-07-2009 | Categoría: Informática No hay comentarios »

Desde la aparición del simil del escritorio, de las ventanas, etc. cuando Xerox lo desarrolló en Palo Alto allá por el año 1980 para su estación Xerox Star, se ha avanzado poco en la interfaz entre los ordenadores y las personas. Si vale, ahora son más colores, más velocidad, 3D, multimedia, etc. Pero el paradigma es el mismo y continúa necesitandose un aprendizaje previo, que muchas veces no es nimio, dependiendo de la tarea a desarrollar.

Hay que reconocer que la aparición de los interfaces gráficos, con el ratón, supuso el inicio de la popularidad del ordenador. Internet fue el elemento que terminó de popularizar el tener un ordenador en casa, ¿o debería decir el eMule, los torrents…? ;-)

Cuando una persona ha de utilizar un ordenador, no quiere saber nada de directorios, unidades, controladores, USB, y demás parafernalia técnica que nos inventamos los informáticos. Es como la leyenda (no se si es cierta) que dicen del fabricante de herramientas Black&Decker: “Las personas no quieren taladros quieren agujeros”. Pues con los ordenadores es algo similar: Quieren información, música, peliculas, documentos, quieren enviar correos, mensajes, escribirle a un amigo, a un desconocido, comunicarse. No quieren saber de URLs, ni de servidores, protocolos, puertos, etc. Los ordenadores todavía son demasiado “informáticos”, nos dejamos llevar por lo técnico (yo el primero), damos por supuestos unos conocimientos a los usuarios que en la mayoría de los casos no es así, no analizamos lo suficiente la usabilidad de lo que hacemos, creo que a estas alturas todavía tenemos una asignatura pendiente.

Cuando mi mujer quiere ver un episodio de “El internado”, no quiere saber que ha de entrar en http://www.antena3.es/elinternado, eso a ella le da igual. Ella cuando abre el navegador, que no sabe que es eso, porque yo he renombrado el icono del Firefox como “Internet” directamente se le carga Google.es, allí escribe “El internado” y revisa los resultados en busca de lo que quiere.

Cuando mis hijos quieren jugar un rato en el ordenador, saben que entrando en con su usuario (que he personalizado con una foto de cada uno de nosotros), verán varios iconos en la pantalla (no en el escritorio) que se llaman “MiniJuegos” o “PequeJuegos”

A base de equivocarse, preguntarme, volverse a equivocar, mi mujer ahora es capaz de con el botón derecho seleccionar “Nuevo…” y “Texto de Open Office”, cambiarle el nombre, abrirlo y ponerse a escribir. Pienso que sería mejor un botón en la barra de Windows/Mac/GNome/KDE que se llamara “Nuevo…” que mostrara un diálogo con una serie de iconos de los tipos de documentos a crear (Pero que no se llamara “Imagen de PhotoShop” o “Texto de OpenOffice”, ni “Hoja de Excel”, sino “Imagen/dibujo/fotografia” o “Documento de texto” o “Documento de cálculo”) y preguntara el nombre del documento, que directamente abriera la aplicación y luego el usuario ya decidirá dónde guardarlo, si es que quiere guardarlo. Porque a mi mujer le da exactamente lo mismo OpenOffice, que StarOffice, que Microsoft Office, que …. lo que quiere es escribir una carta a una amiga o una lista de los invitados al cumpleaños de nuestro hijo.

Se que muchos pensarán que para conducir un automóvil, por ejemplo, es necesario un curso, unas prácticas. De acuerdo al 100%, pero para sacarse el permiso de conducción no le enseñan a uno cómo funciona la inyección, qué es un common rail, o si es mejor una suspensión McPherson o un cuadrilatero paralelogramo deformable. Eso queda para quien lo necesite o tenga interés, no para un gran número de conductores.

Se ven avances importantes como Microsoft Surface, y otros muchos más. Ver “The Next Generation in Human Computer Interfaces” en sigularityhub.com. Personalmente me impactó mucho el llamado “sexto sentido

Y lo mismo debemos aplicarnos a la hora de hacer las páginas web. El otro día Jesús Encinar escribió un magnifico artículo explicando el porque a los usuarios deberíamos hacerles utilizar lo mínimo el teclado: “El teclado y el ratón están a kilómetros de distancia

En definitiva, creo que aún hay mucho trabajo para conseguir que los ordenadores, bueno, mejor digo los sistemas operativos, aplicaciones y páginas web, sean más intuitivos.