Sentido Web

Referencias y explicaciones sobre desarrollo web, PHP, Ajax, XHTML, MySQL ...
03May
2011
Comments Off

Utilizar websockets con Apache

Creo que los websockets tienen futuro, aunque aún está un poco complicado el meterle mano a la hora de desarrollar. Para quienes quieran usarlo en sus proyectos junto a Apache tan solo tendrán que permitir ejecutar Python en Apache e instalar pywebshocket.

Primero es necesario indicar que Apache reconozca Python en nuestro virtual host:

Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
allow from all
AddHandler mod_python .py
PythonHandler mod_python.publisher
PythonDebug On

Despues instalar pywebshocket:

sudo python setup.py build
sudo python setup.py install

Y por último indicar en el httpd.conf añadirlo al Apache:

PythonPath "sys.path+['/usr/local/lib/python2.6/dist-packages/mod_pywebsocket']"
PythonOption mod_pywebsocket.handler_root /home/travis/Desktop/websock_handlers
PythonHeaderParserHandler mod_pywebsocket.headerparserhandler

How to set up apache to serve html5 websocket applications with pywebsocket

22Apr
2011
<!-- 1 -->

MathJax: librería javascript para mostrar fórmulas matemáticas

MathJax es una librería javascript que permite mostrar fórmulas LaTeX y MathML en nuestras páginas. Es compatible con casi todos los navegadores (menos IE5.5 lógicamente), permite copiar el código TeX y MathML de la página, utiliza fuentes CSS y no imágenes o Flash y muchas cosas más.

<!DOCTYPE html>
<html>
<head>
<title>MathJax TeX Test Page</title>
<script type="text/x-mathjax-config">
  MathJax.Hub.Config({tex2jax: {inlineMath: [['$','$'], ['\(','\)']]}});
</script>
<script type="text/javascript"
  src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>
</head>
<body>
When $a \ne 0$, there are two solutions to \(ax^2 + bx + c = 0\) and they are
$$x = {-b \pm \sqrt{b^2-4ac} \over 2a}.$$
</body>
</html>

MathJax

Publicidad
18Apr
2011
Comments Off

jQuery Graceful Websocket: plugin jQuery para websockets

jQuery Graceful Websocket es un plugin jQuery que nos permite comunicarnos con el servidor usando websockets de HTML5. El problema es que tan solo Chrome permite los websokets (creo que Firefox los tiene desactivados por defecto por temas de seguridad), además se necesita que el servidor los pueda tratar, por lo que este plugin permite una alternativa mediante Ajax transparente al desarrollador.

// Si el servidor no admite websockets sustituye el ws:// por http://
var ws = $.gracefulWebSocket("ws://127.0.0.1:8080/");
// Envía datos al servidor. 
// Si el servidor no admite websockets lo envía mediante POST
ws.send("message to server");
// Recibe datos del servidor
// Si el servidor no admite websockets hace un polling mediante GET
ws.onmessage = function (event) {
   var messageFromServer = event.data;   
};

WebSocket plugin for jQuery with graceful degradation

13Apr
2011
<!-- 3 -->

phpcassa: librería PHP para Cassandra

Aunque (afortunadamente) Cassandra ya no está tan de moda y en boca de todos, sigue siendo una herramienta a tener en cuenta a la hora de desarrollar un proyecto en el que se calcule un elevado nivel de datos. Para los que usamos PHP nos vendrá muy bien esta librería que nos facilitará el trabajo y que además es compatible con TimeUUID y SuperColumnFamily:

<?php
// Copiar todos los ficheros en el directorio
define('THRIFT_ROOT', dirname(__FILE__) . '/include/thrift/');
require_once THRIFT_ROOT.'/packages/cassandra/Cassandra.php';
require_once THRIFT_ROOT.'/transport/TSocket.php';
require_once THRIFT_ROOT.'/protocol/TBinaryProtocol.php';
require_once THRIFT_ROOT.'/transport/TFramedTransport.php';
require_once THRIFT_ROOT.'/transport/TBufferedTransport.php';
include_once(dirname(__FILE__) . '/include/phpcassa.php');
include_once(dirname(__FILE__) . '/include/uuid.php');
// Setting up nodes:
CassandraConn::add_node('192.168.1.1', 9160);
CassandraConn::add_node('192.168.1.2', 5000);
// Create a column family object
$users = new CassandraCF('Keyspace1', 'Users'); // ColumnFamily
$super = new CassandraCF('Keyspace1', 'SuperColumn', true); // SuperColumnFamily
// Inserting:
$users->insert('1', array('email' => 'email@correo.com', 'password' => 'test'));
// Querying:
$users->get('1'); // array('email' => 'email@correo.com', 'password' => 'test')
$users->multiget(array('1', '2')); // array('1' => array('email' => 'email@correo.com', 'password' => 'test'))
// Removing:
$users->remove('1'); // removes whole object
$users->remove('1', 'password'); // removes 'password' field
// Other:
$users->get_count('1'); // counts the number of columns in user 1 (in this case 2)
$users->get_range('1', '10'); // gets all users between '1' and '10'
?>

phpcassa

05Apr
2011
Comments Off

Hacer un split en MySQL

Normalmente no se suelen necesitar hacer splits en MySQL, porque un buen diseño de la BD debería almacenar los campos en distintas columnas, y si no se puede realizar así, se suele guardar la información serializada en PHP o en formato JSON o XML. Pero no siempre son las cosas como queremos y alguna vez nos podemos encontrar con la necesidad de hacer un split de un campo en MySQL (como me ha pasado a mi ahora).

Hacerlo es fácil, solo es necesario hacer dos substrings, por cada campo:

SELECT `ip` ,
SUBSTRING_INDEX( `ip` , '.', 1 ) AS a,
SUBSTRING_INDEX(SUBSTRING_INDEX( `ip` , '.', 2 ),'.',-1) AS b,
SUBSTRING_INDEX(SUBSTRING_INDEX( `ip` , '.', -2 ),'.',1) AS c,
SUBSTRING_INDEX( `ip` , '.', -1 ) AS d
FROM log_table

MySQL String Functions

Publicidad
02Apr
2011
Comments Off

Crear thumbs con WordPress

Si antes hablaba de una librería que crea thumbs con PHP, ahora comento cómo hacerlo con WordPress, ya que a veces es necesario subir ficheros cuando WP se utiliza para algo más que un simple blog:

// uploadfile tiene el path del fichero subido
// el cuarto parámetro es para que haga crop
$thumb = image_resize($uploadfile, $width, $height, true); 
$upload = wp_upload_dir();
$thumburl = str_replace($upload['path'], $upload['url'],  $thumb );
02Apr
2011
<!-- 2 -->

PHP Thumbnailer: librería para crear thumbs de imágenes

Si hay algo que odio a la hora de desarrollar una aplicación es tener que hacer thumbs de las imágenes, sobre todo para los perfiles: que si el thumb es cuadrado y la imagen rectangular, que si se debe recortar o meter bordes, … PHP Thumbnailer nos facilita enormemente esta tarea:

Hacer resize:

try {
     $thumb = PhpThumbFactory::create('/path/to/image.jpg');
} catch (Exception $e) {
     // error
}
$thumb->resize(100, 100);
$thumb->show();

Hacer resize y crop si es rectangular:

$thumb->adaptiveResize(175, 175);
$thumb->save('/path/to/new_image.jpg');

PHP Thumbnailer

27Mar
2011
<!-- 1 -->

Subir y exportar documentos usando Google Docs y PHP

Uno de los problemas con los que nos podemos encontrar es tener un documento en un formato y tener que exportarlo en otro formato. La exportación se puede realizar utilizando Google Docs, quizás un tanto rebuscada la solución, aunque quizás no tanto.

Os paso un script que sube el fichero a Google Docs dentro de una carpeta y acto seguido lo exporta a otro formato, en este caso subo un PPT y lo convierto en PDF (me hubiese encantado que fuera a HTML pero no acepta esa opción).

// Datos de login a la API de Google
$clientlogin_url = "https://www.google.com/accounts/ClientLogin";
$clientlogin_post = array(
    "accountType" => "GOOGLE",
    "Email" => "miemail@gmail.com",
    "Passwd" => "mipassword",
    "service" => "writely",
    "source" => "WPDOCS"
);
 
// Inicializamos el CURL
$curl = curl_init($clientlogin_url);
 
// Obtenemos el string de autenticación
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $clientlogin_post);
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($curl);
preg_match("/Auth=([a-z0-9_\-]+)/i", $response, $matches);
$auth = $matches[1];
 
// Cabeceras de autenticación
$headers = array(
    "Authorization: GoogleLogin auth=" . $auth,
    "GData-Version: 3.0",
);
 
// Recuperamos los ficheros y carpetas que tenemos en Google Docs para no crear dos veces la misma carpeta
curl_setopt($curl, CURLOPT_URL, "http://docs.google.com/feeds/default/private/full?showfolders=true");
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_POST, false);
$listado = curl_exec($curl);
$nombre_carpeta = 'WPDOCS';
 
// Si no se ha creado la carpeta, la creamos
if (strpos($listado, '<title>'.$nombre_carpeta.'</title>') === FALSE) {
  // Make the request
  $h = array_merge($headers,array('Content-Type: application/atom+xml'));
  $xml = '<?xml version="1.0" encoding="UTF-8"?><entry xmlns="http://www.w3.org/2005/Atom"><category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/docs/2007#folder"/><title>'.$nombre_carpeta.'</title></entry>';
  curl_setopt($curl, CURLOPT_URL, "http://docs.google.com/feeds/default/private/full");
  curl_setopt($curl, CURLOPT_HTTPHEADER, $h);
  curl_setopt($curl, CURLOPT_POSTFIELDS, $xml);
  curl_setopt($curl, CURLOPT_POST, true);
 
  $response = curl_exec($curl);
  $response = simplexml_load_string($response);
  $id_folder = $response->id;
} else {
  // Recuperamos la ID de la carpeta creada anteriormente
  preg_match("#<title>$nombre_carpeta</title><content type='application/atom\+xml;type=feed' src='([^']+)'#", $listado, $m);
  $id_folder = $m[1];
}
 
// Subimos el PPT
$h = array_merge($headers,array('Content-Type: application/vnd.ms-powerpoint', 'Slug: fichero'));
$filepath='/path/fichero.ppt';
$data=((fread(fopen($filepath, "rb"), filesize($filepath))));
curl_setopt($curl, CURLOPT_URL, "http://docs.google.com/feeds/default/private/full");
curl_setopt($curl, CURLOPT_HTTPHEADER, $h);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
curl_setopt($curl, CURLOPT_POST, true);
$response = curl_exec($curl);
$response = simplexml_load_string($response);
$id_doc = $response->id;
 
// Limpiamos los IDs de los ficheros devueltos por Google, solo nos interesa del %3A para adelante
preg_match('/%3A(.+)/', $id_doc, $m);
$id_doc = $m[1];
preg_match('/%3A(.+)/', $id_folder, $m);
$id_folder = $m[1];
 
// Lo movemos a la carpeta
$h = array_merge($headers,array('Content-Type: application/atom+xml'));
$data = '<?xml version=\'1.0\' encoding=\'UTF-8\'?><entry xmlns="http://www.w3.org/2005/Atom"><id>https://docs.google.com/feeds/default/private/full/document%3A'.$id_doc.'</id></entry>';
curl_setopt($curl, CURLOPT_URL, "http://docs.google.com/feeds/default/private/full/folder%3A".$id_folder);
curl_setopt($curl, CURLOPT_HTTPHEADER, $h);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
curl_setopt($curl, CURLOPT_POST, true);
$response = curl_exec($curl);
 
//header('Content-type: text/xml');
//echo $response;
// Parse the response
 
// Exportamos a HTML
curl_setopt($curl, CURLOPT_URL, "http://docs.google.com/feeds/download/presentations/Export?docID=$id_doc&exportFormat=pdf");
curl_setopt($curl, CURLOPT_HTTPHEADER, $h);
curl_setopt($curl, CURLOPT_POST, false);
header('Content-type: application/pdf');
echo curl_exec($curl);
 
curl_close($curl);

Vía / Google Docs API: Client Login with PHP and Curl

Publicidad
23Mar
2011
Comments Off

Clipping de vídeo usando HTML5 y SVG en Firefox4

La verdad es que Firefox4 está de lujo, y las demos que ofrece Mozilla son increíbles. De una de ellas he sacado cómo hacer clipping en vídeos usando HTML5 y la posibilidad de incrustar SVG (sólo funciona en Firefox4).

El método es sencillo, tengo un SVG que muestra el contorno y los botones de play y pausa, además tiene un clipPath que se usará para el estilo clip-path del vídeo:

SVG

<svg width="300" height="250" id="svg2">
  <clipPath id="clip">
    <use xlink:href="#borde"/>
  </clipPath>
  <g id="player" >
    <path
       style="fill:none;stroke:#014700;stroke-width:10;stroke-opacity:0.7;"
       d="m 40,20 S 20,20,20,40 C 20,50,30,220,60,230 C 90,250,270,190,280,180 C 310,160,260,70,250,60 C 200,0,40,20,40,20 z"
       id="borde" />
    <g id="pause" style="fill:#000000;fill-opacity:0.3;display: none">
      <rect y="100" x="125" height="50"
         width="20" id="rect3590"
         style="color:#000000;fill:#000000;fill-opacity:0.3" />
      <rect y="100" x="150" height="50"
         width="20" id="rect3590"
         style="color:#000000;fill:#000000;fill-opacity:0.5" />
    </g>
    <path
       style="color:#000000;fill:#000000;fill-opacity:0.5"
       id="play" d="m 125,100 L 125,150 L 175,125 z" />
  </g>
</svg>

Vídeo

<video style="clip-path: url(#clip);" preload="auto" autobuffer="" src="http://videos.mozilla.org/serv/mozhacks/demos/resources/londonproject/fight.ogv" tabindex="0" id="video" ></video>

Javascript

var play = document.getElementById('play');
var pause = document.getElementById('pause');
var video = document.getElementById('video');
play.addEventListener('click', function() {
    play.style.display = 'none';
    pause.style.display = 'block';
    video.play();
  }, true);  
pause.addEventListener('click', function() {
    play.style.display = 'block';
    pause.style.display = 'none';
    video.pause();
  }, true);  
video.addEventListener("ended", function() {
    play.style.display = 'block';
    pause.style.display = 'none';
    video.pause();
  }, true);

El vídeo es el mismo que el de la demo de Mozilla, he puesto el borde semi-transparente para que se vea el clipping como va.

Demo

Vía / Project London Trailer

15Mar
2011
<!-- 3 -->

Crear usuarios de prueba en Facebook con CodeIgniter

Si el otro día hablaba sobre la posibilidad que ofrece Facebook de crear usuarios de prueba para tus aplicaciones, ahora voy a pasar un pequeño script para CodeIgniter que permite crear esos usuarios.

El script necesita de la librería curl para PHP para facilitar la tarea:

$app_id = 'xxxxxx';
$canvas_page = 'http://apps.facebook.com/xxxx/';
$client_secret = 'xxx';
$app_token = 'access_token_de_la_aplicacion';
$this->load->library('curl');
// Creo 100 usuarios
for ($i=0; $i<100; $i++) {
  $usuario = $this->curl->simple_post('https://graph.facebook.com/'.$app_id.'/accounts/test-users?installed=true&permissions=read_stream', array('access_token' => $app_token));
}
// Los recupero
$usuarios = $this->curl->simple_get('https://graph.facebook.com/'.$app_id.'/accounts/test-users?installed=true&permissions=read_stream&access_token='.$app_token);
$usuarios = json_decode($usuarios);
foreach($usuarios->data as $i=>$u) {
  // Hago que el primer usuario (que sera el que use) sea amigo de todos
  if ($i==0) {
    $ppal = $u;
  } else {
    // Hago un dump para saber si se ha creado bien la amistad
    var_dump($this->curl->simple_post('https://graph.facebook.com/'.$ppal->id.'/friends/'.$u->id, array('access_token' => $ppal->access_token)));
    var_dump($this->curl->simple_post('https://graph.facebook.com/'.$u->id.'/friends/'.$ppal->id, array('access_token' => $u->access_token)));
  }
}