Sentido Web

Sentido Web es un blog sobre desarrollo web, en el que se comparten referencias y explicaciones sobre PHP, Ajax, XHTML, MySQL y mucho más...

08Feb
10

HAProxy: proxy para mejorar el rendimiento

HAProxy es un proxy gratuito, con balanceo de carga y que soporta decenas de miles de peticiones. Además de tener un gran rendimiento, permite tener un control de concurrencia, esencial cuando tenemos demasiadas peticiones que nuestro sistema no puede soportar, y en vez de saturar el sistema y dar un mal servicio a todo el mundo, podemos limitar el número de peticiones para que al menos una parte de los usuarios sí reciban el servicio adecuado.

HAProxy

Vía / SaaS Interrupted

05Feb
10

BigDump: facilita recuperar dumps de MySQL grandes

A veces es un lío enorme recuperar BDs obtenidos de dumps cuando el fichero es enorme, sobre todo si usamos phpMyAdmin (y no tenemos acceso a él). Por ello este script nos puede venir muy bien para recuperar backups anteriores, ya que recupera de poco en poco y se auto-reinicia él mismo.

BigDump

  
 

Plupload: sube varios ficheros fácilmente

Plupload es un script creado por los autores de TinyMCE. Permite subir ficheros usandoHTML5 Gears, Silverlight, Flash, Yahoo! BrowserPlus o formularios normales, además permite subida progresiva, redimensionado de imágenes y chunked uploads.

Está dividido en dos partes: Core API y una cola de subida jQuery, lo cual permite que creamos nuestra propia implementación. Además en Firefox 3.5+ se puede usar drag&drop y el redimensionado de images también es exclusivo de FF.

Plupload

Vía / WebAppers

04Feb
10

Opiniones sobre HipHop de Facebook

He estado leyendo bastantes opiniones sobre HipHop de Facebook e iba a hacer un listado pero me he encontrado con el trabajo ya hecho en PHPDeveloper.org:

Community News: Responses to the Facebook HipHop Announcement

03Feb
10

Mostrar las páginas vistas y las visitas de Google Analytics al estilo Feedburner

Me ha gustado el ejemplo para mostrar en tu web las visitas y las páginas vistas de tu web como muestra Feedburner los suscritores que tienes en el feed. Para mostrarlo haremos uso de la librería GAPI, la cual accede a los datos que ofrece Google Analytics:

<?php
define('ga_email','yourGoogleEmail');
define('ga_password','yourGooglePass');
define('ga_profile_id','yourProfileID');
 
require 'gapi.class.php';
$ga = new gapi(ga_email,ga_password);
$ga->requestReportData(ga_profile_id,array('browser','browserVersion'),array('pageviews'));
?>

El resto será darle estilo a los datos obtenidos.

FeedCount-Like Google Analytics Counter

Vía / Script & Style

  
 

Facebook crea HipHop para PHP

Después de muchos rumores ya se ha conocido que Facebook ha creado una aplicación que transforma PHP en código C++, no es un compilador en sí, sino una especie de traductor de código que compila. Los resultados en Facebook son asombrosos, hasta un 50% menos de CPU, lo cual reduce el número de servidores que necesitan.

HipHop for PHP

02Feb
10

Tutorial sobre Facebook Connect

Facebook Connect es una API de FB que nos permite usar nuestra cuenta de FB en otras webs. A mi personalmente, la ayuda que ofrece FB no me apasiona demasiado, y cuando quieres realizar algo con Facebook Connect te tienes que pelear bastante con cosas que haces mal o que te faltan por hacer. Por ello, creo que este tutorial es bastante interesante para aquellos que quieren desarrollar algo con FB Connect y no saben por dónde empezar.

El tutorial nos mostrará los siguientes puntos:

  1. Crear una aplicación en Facebook
  2. Copiar en tu sitio el fichero xd_receiver.htm
  3. Descargar la API PHP de FB en tu web
  4. Modificar tu tabla de usuarios
  5. Crear una página para loguearse con FB Connect
  6. Enlazar a fbclogin.php desde tu login
  7. Otros puntos a seguir

Facebook Connect Tutorial

Vía / PHPDeveloper.org

01Feb
10

Indicar el cliente que publica en Twitter

El otro día mi compañero David y yo estábamos mirando cómo hacer que cuando publicamos en Twitter desde la aplicación, no salga “from API”. Por lo que buscando buscando, encontré un plugin para Wordpress que lo implementaba y luego David encontró la documentación necesaria.

Tan solo hay que indicar unas cabeceras HTTP y crear un XML que contiene información que leerá Twitter.

  
 

Laboratorio: leer cualquier tipo de imágen en PHP de forma sencilla

Uno de los problemas con los que nos solemos encontrar es leer imágenes en PHP mediante la librería GD sin estar seguros de que tipo de fichero es: JPEG, GIF o PNG. Normalmente solemos mirar la extensión y según sea, abrir el fichero con alguno de los métodos que ofrece GD. Pero hay una solución más sencilla: leer el fichero en un string y crear la imagen usando ese script:

$img_content = file_get_contents($image);
$im = imagecreatefromstring($img_content);
// Para saber el tipo de imagen por si lo necesitamos
$imgtype = exif_imagetype($image);
  
 

Laboratorio: postear en WordPress mediante GTalk o Jabber (mejorado)

Hace tiempo hice un script para PHP que permitía postear en Wordpress usando Jabber (por ejemplo GTalk). Ahora he mejorado un poco el script para que admita poner categorías (si no las hay, las crea) y subir imágenes mediante una URL (ajustándolo a un ancho máximo).

Existen distintas palabras claves para separar los distintos elementos del post dentro del texto que se envía: titulo, contenido, tags, categorias e image. Las distintas secciones se separan con ‘##’ para diferenciarlas unas de otras y se separarán por dos puntos ‘:’ formando pares clave:valor. Un ejemplo para escribir en el IM sería el siguiente:

titulo:Titulo del post##contenido:Lorem Ipsum... con todo el HTML que querramos##tags:etiqueta1, etiqueta2, etiqueta3##categorías:Categoria1,Categoria2#image:http://servidor.com/ruta/imagen.png

El código principal es el siguiente:

<?php
 
require './XMPPHP/XMPP_Old.php';
require './xmlrpc/xmlrpc.inc';
 
$blog_usuario = 'usuario';
$blog_contraseña = 'contraseña';
$blog_url = 'dominio.com';
$blog_xmlrpc_path = '/xmlrpc.php';
$blog_puerto = 80;
 
$post_tags = array('tag-defecto');
$post_separador = '##';
$post_titulo_defecto = 'Titulo';
$post_insertar_p = false;
 
$jabber_host = 'dominio_jabber.com';
$jabber_contraseña = 'contraseña';
$jabber_usuario = 'usuario';
$jabber_puerto = 5222;
 
// Ancho máximo para la imágen
$max_width = 540;
 
function post($message) {
  global $blog_usuario;
  global $blog_contraseña;
  global $blog_url;
  global $blog_xmlrpc_path;
  global $blog_puerto;
  global $post_tags;
  global $post_separador;
  global $post_titulo_defecto;
  global $post_insertar_p;
  global $max_width;
  
  $message = mb_convert_encoding($message, 'ISO-8859-1', 'UTF-8');
  $aux = explode($post_separador, $message);
  if (count($aux) == 1) {
    $titulo = $post_titulo_defecto;
    $contenido = $message;  
    $tags = implode(',', $post_tags);
  } else {
    foreach($aux as $item) {
      $pair = explode(':', $item, 2);
      $var = $pair[0];
      $$var = $pair[1];
    }
  }
  
  if ($post_insertar_p) {
    $contenido = implode("\n", array_map(create_function('$e', 'return "<p>$e</p>";'), explode("\n", $contenido)));
  }
 
  if (isset($image)) {
    $img_content = file_get_contents($image);
    $im = imagecreatefromstring($img_content);
    $w = imagesx($im);
    $h = imagesy($im);
    $imgtype = exif_imagetype($image);
    if ($w > $max_width) {
      $image_p = imagecreatetruecolor($max_width, intval($h*$max_width/$w));
      imagecopyresampled($image_p, $im, 0, 0, 0, 0, $max_width, intval($h*$max_width/$w), $w, $h);
      ob_start();
      imagepng($image_p);
      $img_content = ob_get_contents();
      ob_end_clean();
      $imgtype = IMAGETYPE_PNG;
      $w = $max_width;
      $h = intval($h*$max_width/$w);
    }
    $imgname = "img".time().image_type_to_extension($imgtype);
    $f = new xmlrpcmsg('metaWeblog.newMediaObject',
		  array(php_xmlrpc_encode($blog_usuario), php_xmlrpc_encode($blog_usuario), php_xmlrpc_encode($blog_contraseña), php_xmlrpc_encode(array('name'=>$imgname, 'bits'=>new xmlrpcval($img_content, 'base64'))))
	  );
	  $c=new xmlrpc_client($blog_xmlrpc_path, $blog_url, $blog_puerto);
	  $c->setDebug(0);
	  $r=&$c->send($f);
	  if(!$r->faultCode()) {
		  $v=$r->value();
      $datos = simplexml_load_string($v->serialize());
      $url = $datos->xpath('//member/name[. ="url"]/following-sibling::*/string');
      $contenido = '<img src="'.$url[0].'" width='.$w.'" height='.$h.'" />'.$contenido;
    } else {
      return "Error a la hora de subir la imagen: $image [".$r->faultString()."]";
    }    
  }
//$contenido .= mb_convert_encoding($contenido, 'UTF-8');
  $f = new xmlrpcmsg('wp.getUsersBlogs',
		array(php_xmlrpc_encode($blog_usuario), php_xmlrpc_encode($blog_contraseña))
	);
	$c=new xmlrpc_client($blog_xmlrpc_path, $blog_url, $blog_puerto);
	$c->setDebug(0);
	$r=&$c->send($f);
	if(!$r->faultCode()) {
		$v=$r->value();
    $datos = simplexml_load_string($v->serialize());
    $blogid = $datos->xpath('//member/name[. ="blogid"]/following-sibling::*/string');
    $blogid = is_array($blogid) ? (string) $blogid[0] : (string) $blogid;    
    $f = new xmlrpcmsg('metaWeblog.newPost',
  		array(php_xmlrpc_encode($blogid), php_xmlrpc_encode($blog_usuario), php_xmlrpc_encode($blog_contraseña), php_xmlrpc_encode(array('title'=>$titulo, 'description'=>$contenido, 'mt_keywords'=>$tags)), php_xmlrpc_encode(1))
  	);
  	$c=new xmlrpc_client($blog_xmlrpc_path, $blog_url, $blog_puerto);
  	$c->request_charset_encoding = 'UTF-8';
  	$c->setDebug(0);
  	$r=&$c->send($f);
  	if($r->faultCode())	{
  		return "Ha habido un error al intentar crear un nuevo post [".$r->faultString()."]";
  	} else {
      $datos = simplexml_load_string($r->serialize());
      $postid = $datos->xpath('//value/string');
      $postid = is_array($postid) ? (string) $postid[0] : (string) $postid;    
   
      $f = new xmlrpcmsg('metaWeblog.getPost',
    		array(php_xmlrpc_encode($postid), php_xmlrpc_encode($blog_usuario), php_xmlrpc_encode($blog_contraseña))
    	);
    	$c=new xmlrpc_client($blog_xmlrpc_path, $blog_url, $blog_puerto);
    	$c->setDebug(0);
    	$r=&$c->send($f);
    	if($r->faultCode())	{
    		return "Ha habido un error al intentar recuperar información sobre el post insertado [".$r->faultString()."]";
    	} else {
        $datos = simplexml_load_string($r->serialize());
        $permalink = $datos->xpath('//member/name[. ="permaLink"]/following-sibling::*/string');
        $permalink = is_array($permalink) ? (string) $permalink[0] : (string) $permalink;    
        $title = $datos->xpath('//member/name[. ="title"]/following-sibling::*/string');
        $title = is_array($title) ? (string) $title[0] : (string) $title;  
        if (isset($categorias)) {
          $f = new xmlrpcmsg('mt.getCategoryList',
		        array(php_xmlrpc_encode($postid), php_xmlrpc_encode($blog_usuario), php_xmlrpc_encode($blog_contraseña))
	        );
	        $c=new xmlrpc_client($blog_xmlrpc_path, $blog_url, $blog_puerto);
	        $c->setDebug(0);
	        $r=&$c->send($f);
	        if(!$r->faultCode()) {
            $datos = simplexml_load_string($r->serialize());
            $catsblog = $datos->xpath('//struct');
            foreach(explode(',', $categorias) as $cat) {$cats[$cat] = null;}
            foreach($catsblog as $cat) {
              foreach($cats as $_cat=>$val) {
                if (strtolower((string) $cat->member[1]->value->string) == strtolower($_cat)) {
                  $cats[$_cat] = (string) $cat->member[0]->value->string;
                }
              }
            }
                
            foreach($cats as $cat=>$val) {
              if (!$val) {
                $f = new xmlrpcmsg('wp.newCategory',
		              array(php_xmlrpc_encode($postid), php_xmlrpc_encode($blog_usuario), php_xmlrpc_encode($blog_contraseña), php_xmlrpc_encode(array('name'=>$cat, 'slug'=>str_replace(' ', '_', strtolower($cat)), 'parent_id'=>1, 'description'=>'')))
	              );
	              $c=new xmlrpc_client($blog_xmlrpc_path, $blog_url, $blog_puerto);
	              $c->setDebug(0);
	              $r=&$c->send($f);
	              if(!$r->faultCode()) {
                  $datos = simplexml_load_string($r->serialize());
                  $catid = (string) $datos->xpath('//int');
                  $cats[$cat] = $catid;
                } else {
                  return "Ha habido un error a la hora de crear la categoría $cat";
                }
              }
            }
            foreach($cats as $val) {
              $catlist[] = array('categoryId'=>$val);
            }
            $f = new xmlrpcmsg('mt.setPostCategories',
              array(php_xmlrpc_encode($postid), php_xmlrpc_encode($blog_usuario), php_xmlrpc_encode($blog_contraseña), php_xmlrpc_encode($catlist))
            );
            $c=new xmlrpc_client($blog_xmlrpc_path, $blog_url, $blog_puerto);
            $c->setDebug(0);
            $r=&$c->send($f);
            if($r->faultCode()) {
              return "Hubo un error a la hora de modificar las categorías del post";
            }
          } else {
         		return "Ha habido un error al intentar recuperar las categorias del blog";
          }
       }
        return "Se ha publicado '$title': $permalink";  
      }
    }
 
	} else {
		return "Ha habido un error al intentar recuperar información sobre el blog [".$r->faultString()."]";
	}
}
 
 
 
//Use XMPPHP_Log::LEVEL_VERBOSE to get more logging for error reports
//If this doesn't work, are you running 64-bit PHP with < 5.2.6?
 
$conn = new XMPPHP_XMPPOld($jabber_host, $jabber_puerto, $jabber_usuario, $jabber_contraseña, 'xmpphp', $jabber_host, false, 
XMPPHP_Log::LEVEL_ERROR);
$conn->autoSubscribe();
$conn->useEncryption(false);
 
try {
    $conn->connect();
    while(!$conn->isDisconnected()) {
    	$payloads = $conn->processUntil(array('message', 'presence', 'end_stream', 'session_start'));
    	foreach($payloads as $event) {
    		$pl = $event[1];
    		switch($event[0]) {
    			case 'message': 
    			  if (trim($pl['body']) == '') break;
    				$conn->message($pl['from'], $body=post($pl['body']), $type=$pl['type']);
    				if($pl['body'] == 'quit') $conn->disconnect();
    				if($pl['body'] == 'break') $conn->send("</end>");
    			break;
    			case 'presence':
    				// print "Presence: {$pl['from']} [{$pl['show']}] {$pl['status']}\n";
    			break;
    			case 'session_start':
    			  //print "Empezamos\n";
			    	$conn->getRoster();
    				$conn->presence($status="Asonesss jefeeeeeee!");
    			break;
    		}
    	}
    }
} catch(XMPPHP_Exception $e) {
  echo 'ERROR:';
  die($e->getMessage());
}

Podéis bajaros el código aquí.