Archivo

Archivo para la categoría ‘PHP’

Login a Facebook y acceso a aplicación automatizado

Miércoles, 11 de Agosto de 2010 admin Sin comentarios

A medida que va creciendo Facebook, los desarrolladores van siendo más imaginativos a la hora de crear aplicaciones que trabajen sobre esta red. Actualmente existen clientes para Facebook que no necesitan que estemos dentro de la página, y lo que presento a continuación es un pequeño ejemplo de todo ello.

Este script es parte investigación / parte navegación y lectura de foros en los que no he encontrado la respuesta exacta a mis necesidades. El problema está en que, a pesar de la existencia de Facebook Connect, si queremos automatizar tareas en Facebook tenemos que estar identificados en el sistema y entonces es cuando podemos hacer la tarea en cuestión.

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
<?php

$face_cookie='/tmp/fcbk_cookie';
$useragent="Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.3) Gecko/20100423 Ubuntu/10.04 (lucid) Firefox/3.6.3";
$login_email='*************';
$login_pass='**************';

function curl_load_url($url, &$error, $postfields=false)
{
  global $useragent, $face_cookie;
  $cu = curl_init();
  curl_setopt($cu, CURLOPT_URL, $url);
  curl_setopt($cu, CURLOPT_HEADER, 0);
  curl_setopt($cu, CURLOPT_FOLLOWLOCATION, 1);
  curl_setopt($cu, CURLOPT_SSL_VERIFYPEER, false);
  curl_setopt($cu, CURLOPT_RETURNTRANSFER, 1);
  curl_setopt($cu, CURLOPT_USERAGENT, $useragent);
  curl_setopt($cu, CURLOPT_COOKIEJAR, $face_cookie);
  curl_setopt($cu, CURLOPT_COOKIEFILE, $face_cookie);
  if ($postfields)
    {
      curl_setopt($cu, CURLOPT_POSTFIELDS, $postfields);
      curl_setopt($cu, CURLOPT_POST, 1);
    }

  $cont=curl_exec($cu);
  $error=curl_errno($cu);

  curl_close($cu);

  return $cont;
}

function fb_login($email, $passwd)
{
  $error=false;
  curl_load_url('http://login.facebook.com/login.php', $error);

  $ch_test='&euro;,&acute;,€,´,水,Д,Є';
  $postfields='cuarset_test='.urlencode($ch_test).'&locale=es_ES&email='.urlencode($email).'&pass='.urlencode($passwd).'&pass_placeholder=&cuarset_test='.urlencode($ch_test);
  $cont=curl_load_url('https://login.facebook.com/login.php?login_attempt=1', $error, $postfields);

 /* Si hay un error de cURL lo decimos */
 if ($error)
   echo 'Error (cURL): '.$error."\n";

 /* Esta palabra *login_attempt* aparece en los intentos de login de Facebook */
 /* es raro que en la página principal salga. */
 /* Podemos también, verificar si está el enlace a editaccount.php para decir */
 /* que hemos sido identificados correctamente */
 if (strpos($cont, 'login_attempt')!==false)
/*  if (strpos($cont, 'editaccount.php')===false) */
   {
     echo 'Error (Facebook): E-mail o contraseña incorrecto';
     $err=1;
   }
 /* Si no hay errores nos daremos por identificados, aunque si el password es incorrecto */
 return (!$err);
}

if (fb_login($login_email,$login_pass)){
  $error=false;
  $cont = curl_load_url('http://apps.facebook.com/minutofilosofico/', $error);
  // Mostramos el contenido de la página
  echo $cont;
}
?>

¿Qué aplicaciones prácticas puede tener esto? Podemos hacer fácilmente un programa de escritorio para manejar Facebook, enviarnos por e-mail o un sms automáticamente si alguien que esperamos nos escribe, subir fotos de forma más rápida con un script en nuestro ordenador… o publicar un mensaje a la hora que hayamos especificado.

Como el ejemplo está en cURL será fácil portarlo a otro lenguaje con el que os sintáis más cómodos.

Intercalar 2 ó más cadenas en PHP

Lunes, 9 de Agosto de 2010 admin Sin comentarios

A la hora de crear un hash para una contraseña, es conveniente no incluir sólo la contraseña, sino concatenar una cadena o un número más; lo mismo cuando generamos claves para que interaccionen aplicaciones en varios servidores; aunque hay veces en que, dados los pocos datos de que disponemos a la hora de generar la clave, no tenemos mucho donde elegir a la hora de crear el hash.

Por ese motivo se me ocurrió esta función en PHP, lo que hace es intercalar cadenas, es decir, tenemos dos cadenas, y queremos generar una cadena a partir de las dos anteriores, podemos coger un carácter de una, otro de otra, y así sucesivamente (como si estuviéramos barajando) hasta formar una cadena cuya longitud es la suma de las dos. Por ejemplo si tenemos las palabras “poesia” y “binaria“, resultaría la cadena: pboiensairaia .

Aunque, ya que vamos a hacer algo así, ¿ por qué limitarlo ? Hagamos una función que soporte una cantidad indeterminada de cadenas:

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
function intercalar($cadenas)
{
  $n_cadenas = count ($cadenas);

  if ($n_cadenas==1)        /* Si sólo hay una cadena, la devolvemos */
    return $cadenas[0];

  /* Contamos los caracteres de cada cadena y los almacenamos en un array */
  $chars_cadena=array();
  for ($i=0; $i<$n_cadenas; $i++)
    $chars_cadena[$i]=strlen($cadenas[$i]);

  $max_cadena = max ($chars_cadena); /* La cadena más larga determina cuándo paramos */
  $res='';
  /* Recorremos la longitud de cadena más larga */
  for ($j=0; $j<$max_cadena; $j++)
    {
      /* Recorremos todas las cadenas */
      for ($i=0; $i<$n_cadenas; $i++)
    {
      /* Si la cadena no está terminada añadiremos el carácter a la cadena */
      if ($j<$chars_cadena[$i])
        $res.=$cadenas[$i][$j];
    }
    }

  return $res;
}

echo intercalar (array("Poesia", "Binaria", "Blog", "Gaspar", "Programacion", "Software", "Libre"));

La cadena resultante de este ejemplo será: PBBGPSLoilaroienosofbsagpgtrirarweairaaamraecion.

Nos ponemos serios con PHP: Empezamos con un CRUD (la esencia no es exclusiva de PHP)

Viernes, 16 de Julio de 2010 admin Sin comentarios

crudHace años tuve entre manos un gran proyecto web, en el que invertí 8 meses de mi vida y funcionó bastante bien durante un tiempo. En su desarrollo recuerdo que tuve que desarrollar cerca 50 formularios diferentes, comprobar los valores de cada uno de los campos, hacer lecturas y escrituras en base de datos con los datos obtenidos, y opcionalmente realizar alguna tarea extra una vez enviado y validado el formulario. Además, tenía que ser capaz de listar la información, modificarla y eliminarla. Por aquel entonces, aunque había partes en común y aproveché para realizar código, no lo hice de la forma más efectiva; podría haber ahorrado muchísimo trabajo.
En los últimos años, para mis proyectos web decidí fabricarme una biblioteca para hacer este tipo de tareas de forma más rápida (con menos esfuerzo, y al fin y al cabo de forma más depurada y segura). Para eso me fabriqué una biblioteca CRUD.

Es cierto que perdemos eficiencia, es más rápida por lo general una herramienta específica, que haga justo lo que se le pide en un momento dado, que una herramienta configurable y flexible (tendremos muchas más sentencias de control y a veces se ejecutarán procesos innecesarios), pero por otro lado hay que tener en cuenta que no podemos echar un mes en un proyecto que generalmente requiere unos días, y por otra parte, seguro seguro que tenemos que hacer modificaciones antes de entregarlo, y éstas no deben llevarnos otro mes más. En definitiva, nos compensa perder algo de eficiencia en favor de un tiempo de desarrollo más corto y generar un código más fácilmente mantenible.

Lo importante de un CRUD, es la posibilidad de Crear, Ver, Actualizar, Borrar (y listar información), si lo pensamos es simple, lo ideal sería tener una clase (o una función) que simplemente llamándola nos hiciera esta complicada tarea; aunque también es verdad, si lo pensamos un poco más, que podemos complicar todo esto de mil formas, y todo lo que queramos. Además, tenemos que crear una herramienta que sea lo más flexible posible para todo tipo de bases de datos y tablas, y además, sería interesante manejar los errores que puedan surgir en el proceso, para poder generar una salida acorde.

Aunque podemos encontrar bibliotecas por Internet que hacen esta tarea, yo siempre prefiero una solución DIY (Do it yourself) (Hazlo tú mismo), de esta forma, el código será 100% mío y yo controlaré el proceso por completo, además de que como materia de aprendizaje es bastante efectivo. Dejo por aquí algunas instrucciones para empezar a fabricarnos un CRUD un tanto sencillo (y que a medida que vayamos haciendo proyectos podemos ir completándolo con las necesidades que nos vayan surgiendo):

  • Listar información de base de datos: Debemos tener la posibilidad de elegir los campos a listar
  • Crear entrada: Debemos tener la posibilidad de introducir campos que concuerden con entradas en una base de datos, y también la posibilidad de generar datos automáticamente (fecha de introducción, identificadores únicos, etc):
    • Necesitaremos un generador de formularios y la posibilidad de elegir el mejor tipo de campo para cada campo de la tabla que vamos a modificar
    • Debemos tener la posibilidad de verificar, vía servidor (PHP) o cliente (Javascript), mejor hacerlo de las dos formas, que los datos estén bien formados (números máximos de caracteres, formato de introducción (por ejemplo, de una fecha, un teléfono, una dirección e-mail…)
    • Inserción en tabla, y muestra de la salida, para que el usuario vea si todo ha ido bien o mal. Sería conveniente también, que esto fuera una redirección, para que, si se refresca la página, no se reenvíen los formularios.
  • Modificar entrada:
    • Podemos aprovechar mucho código de la creación de entrada (muestra de formulario, verificación…)
    • Debemos modificar la tabla de datos, a lo mejor actualizar fechas de modificación, logs, etc
  • Eliminar entrada:
    • Idealmente, debemos presentar un diálogo tipo: “¿Está seguro?” para confirmar que no se hace por accidente, tal vez los datos no siempre interese eliminarlos, sólo hacer una marca de que no se visualicen.
  • Ver información:
    • Necesitamos hacer un sistema de visualización flexible, automático y tener la posibilidad de seleccionar los campos a mostrar (los identificadores únicos, fechas internas, IDs, no le suelen interesar al usuario), por otra parte, a veces para visualizar un dato es necesario hacer varias consultas a base de datos y tenemos que estar preparados.

Pero como dije antes, esto lo podemos complicar hasta la saciedad, aumentando el número de campos que podemos introducir (por ejemplo inserción de ficheros, Javascripts para introducir la fecha de forma fácil, o inclusión de áreas de texto HTML (como TinyMCE).

En cuanto al listado podemos implementar paginación automática (para el caso de que haya muchos elementos a listar) y ordenación de los elementos por columna (tal vez por nombre, por fecha, etc)

Por otra parte, tenemos que tener muy en cuenta el diseño, éste suele ser diferente para cada página (quitando esas páginas que parece que están hechas todas con el mismo molde), así que tenemos que hacer que nuestra salida en (x)HTML sea lo más flexible posible, que nos deje introducir código adicional, cambiar las imágenes utilizadas (iconos de insertar, eliminar…)

Y como colofón, podemos implementar soporte para relaciones, puede que echemos unos días desarrollando nuestro CRUD, pero  nos va a ahorrar mucho tiempo de desarrollo si lo utilizamos en nuestros proyectos.

Clases abstractas e interfaces en PHP

Viernes, 4 de Junio de 2010 admin Sin comentarios

objetoLos interfaces son bastante comunes en la programación orientada a objetos, en PHP, son algo así como una declaración de lo que debe implementar una clase. Tendrá información de los métodos (exclusivamente) que se deben implementar.

Las clases abstractas contienen atributos y métodos, algunos pueden estar implementados y otros pueden ser abstractos. Los métodos abstractos son aquellos que no están implementados. Como tienen métodos sin implementar no podemos crear una instancia de este tipo de clases; entonces, ¿ para qué valen ?
Los métodos abstractos, los debemos implementar en las clases derivadas.

Vemos que tanto interfaces como clases abstractas son muy parecidos, los dos muestran declaraciones que debemos implementar más adelante, pero veamos algunas diferencias:

  • Una interfaz no puede contener atributos ni métodos implementados, mientras que una clase abstracta sí que puede contenerlos
  • Una clase sólo puede heredas una clase abstracta, mientras que en una misma clase se pueden implementar varias interfaces.
  • Las clases abstractas pueden declarar los métodos con diferente visibilidad (public, protected, internal, etc; private no, esto indicaría que una clase derivada no podría ver el método, por tanto no tendría sentido; final tampoco, porque no admitiría implementaciones futuras, aunque una clase derivada sí podría contener un método como final), mientras que en los interfaces todos los métodos deben ser públicos (también static)
  • Los métodos que no implementamos en una clase abstracta, deben ser abstract, en un interface, todos los métodos son abstract, y ninguno debe ser implementado.

Por último, aunque no sea un ejemplo demasiado concreto, pondré un fragmento de código en el que se define una clase abstracta (Articulo, como un artículo de una tienda), y varios interfaces de algunos tipos de artículo. (Intentao demostrar todo lo que he contado antes, para nada es un ejemplo real):

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
<?php

abstract class Articulo
{
  private $stock;
  private $precio;

  abstract protected function venta($cantidad);

  abstract function calcula_precio_total($cantidad, $descuento);
}

interface En_caja
{
  function idiomas();
  function lectura($idioma);
}

interface Juguete
{
  function puedo_probarlo();
  static function probar();
  function tirar_al_suelo();
}

class HomerSapiens extends Articulo implements En_caja, Juguete
{
  protected function venta($cantidad)
  {
    ...
  }

  final function calcula_precio_total($cantidad, $descuento)
  {
    ...
  }

  function idiomas()
  {
    ...
  }

  function lectura($idioma)
  {
    ...
  }

  function puedo_probarlo()
  {
    ...
  }

  static function probar()
  {
    ...
  }

  function tirar_al_suelo()
  {
    ...
  }
}
?>

Foto: kevindooley (Flickr)

Curioso e interesante: Google se derrumba, K-Maps, Buenhabit, y más

Jueves, 3 de Junio de 2010 admin 2 comentarios

Quiero dedicar este post a cosas que me han llamado la atención estos últimos días:

  1. Google se derrumba: Lo descubrí gracias a novatillasku. Es una tontería chulísima, la página principal de Google se cae a pedazos, aunque para verlo tendréis que utilizar un navegador decente. Abstenerse Internet Explorer. Click aqui para verlo.
  2. Mapas de Karnaugh: Via Acerca de Ubuntu veo una serie de programas para resolver mapas de Karnaugh y ser el terror de la electrónica digital :)
  3. Piedra, papel, tijeras, lagarto, Spock: Últimamente estoy viendo la serie The Big Bang Theory, ya estaba tardando en empezarla, y hace poco vi este post. Pocos días antes de llegar hasta el capítulo 2×08 donde ocurre todo :)
  4. Acceder a un Array como un objeto [PHP]: El post ya tiene tiempo. Leído en el blog de Sergi Quiñonero. Nos cuenta cómo haciendo $objeto = (object) $array podemos acceder a cada elemento del array con -> (flechas) como si fuera un objeto.
  5. El sistema Solar en HTML5. Muy currado, demostrando qué es capaz de hacer HTML5, y demasiado cool para IE, aunque está gracioso ver cómo se dibujan en Internet Explorer las órbitas cuadradas :) Ya sé que tampoco son redondas, pero es una demostración sólo…
  6. Dos artículos de un blog muy interesante: Hace mucho tiempo que sigo el blog Buenhabit, y quiero destacar dos de sus últimos posts: Sólo dos cosas a la vez, que habla de una reciente investigación acerca de la limitación humana de la multitarea; y Si gritas no convences, merece la pena leerlo aunque el título lo diga todo.

Hasta aquí una pequeña selección de estos últimos días.

Una balanza que no funciona

Lunes, 31 de Mayo de 2010 admin Sin comentarios

450px-balanzaLlega el día en que nos dedicamos al desarrollo, ya sea por libre, en una empresa, para investigación o en cualquier otra circunstancia; tenemos que poner en práctica lo aprendido durante tanto tiempo y no estamos haciendo simples ejercicios ni programas de un máximo de 200 líneas (con muchos espacios en blanco, comentarios multi-línea y esas cosas).
Es decir, nos enfrentamos a un proyecto real y tenemos que dar lo mejor de nosotros mismos en su realización.
Como tampoco es un proyecto excesivamente grande decidimos pasar de hacer una planificación previa del proyecto, y decidimos que es más rápido pasar a la acción y ponernos a picar código.
Comprendo que si no se tiene mucha experiencia, es una tarea intelectualmente más ligera ponernos a escribir de forma estructurada nuestros algoritmos, excepcionalmente haciendo alguna función; no tenemos tiempo para separar estructuras, ni para idear algún algoritmo extra que nos simplifique un poco el código, pero no le damos importancia… simplemente nos damos el batacazo cuando el cliente nos pide un pequeño cambio en el código; de repente se nos viene a la cabeza la famosa teoría del caos. Y es que nuestro código es un caos. Y no comprendemos que el cliente (a no ser que seamos nosotros mismos), usuario, jefe, o persona que necesita el programa pero no tiene ni idea de cómo se desarrolla tiende a pensar que todos los cambios son pequeños y que cualquier modificación se hace en 10 minutos; por tanto, la primera versión de nuestro código no va a servir, y tenemos que distinguir entre: pijadas, o modificaciones en la interfaz, cosas que harían el programa más bonito; entrada/salida, tal vez campos de una base de datos que se suponía que teníamos que introducir y que no están (será porque nadie nos había informado de que la posición en que una persona jugaba al fútbol de pequeño era un dato personal básico e importantísimo); o que está visualizando más datos de los que quiere; cambios estructurales, esos ya son más peliagudos, pero bueno.
Lo que quiero decir, es que la versión preliminar que hagamos casi nunca va a ser la buena y tendremos que revisarlo, incluso al cabo de un tiempo, se necesitará añadir una característica más, y la hemos liao si seguimos por este camino.

Tenemos que hacer de nuestro código un arte:

  • Podemos comentar en nuestro idioma hasta la saciedad, aunque sin pasarnos.
  • Podemos dividir nuestro código, e incluso cuando hacemos cosas muy parecidas podemos unificarlas en una función/clase/proceso diferente. El lema divide y vencerás es muy útil, y a la larga hace nuestra aplicación más facilmente mantenible.
  • Podemos separar la lógica del programa, con lo relativo a datos y lo relativo a la visualización (MVC)… programar a pegotón no ayuda.
  • A veces, con alguna operación matemática, nos podemos ahorrar una secuencia iterativa
  • No por mucho que tarde nuestro programa en hacer una tarea determinada, lo hace más profesional, aunque hay empresas que esto no lo tienen muy claro.

Si bien es cierto que cuando llamamos a funciones estamos haciendo la ejecución de nuestro código más lenta (con operaciones recursivas ya ni hablamos), tenemos que tener en cuenta si podemos sacrificar unos cuantos milisegundos en la ejecución en favor de unas cuantas horas de desarrollo, y es que muchas veces, crear una función, incluso para hacer nuestro código más legible (por ejemplo, si estamos presentando los resultados de una búsqueda, y necesitamos ordenarlos, no tenemos por qué implementar el método de ordenación en el mismo sitio, nos lo podemos llevar fuera; incluso si tenemos que presentarlo de forma bonita para el usuario, podemos hacer una función aparte que presente esos datos), puede ahorrarnos mucho tiempo de mantenimiento; cuando al cabo de dos semanas nos enfrentemos de nuevo a nuestro código, seguro que preferimos ver las cosas más claras.

Dando ejemplos (no todo se hace en los lenguajes mencionados, esto lo podemos extender a muchos lenguajes más):

  • Vale, estamos diseñando un sistema de tiempo real y tiene que funcionar rápido, como ejecutamos las órdenes muchas veces, no podemos queremos hacer funciones ni hacer nada complicado, para no ralentizar mucho la ejecución… en C/C++, por ejemplo, podemos crear macros.
  • Nuestras necesidades pueden ser más complicadas, tenemos que tener en cuenta que un lenguaje de programación, nos da herramientas básicas, y las podemos extender. Imaginad el uso de mysql_query() [PHP], puede que necesitemos contar cuántas veces se ha llamado esta función. Esto implicaría ver dónde se ha llamado la función e incrementar una variable, aunque tal vez en el futuro tengamos más necesidades.
  • Ya no hablamos de la abstracción con objetos, al principio nos choca esa forma nueva de pensar, pero a la hora de embarcarnos en un proyecto, de primeras no la tenemos muy en cuenta. Por ejemplo, en C++ o en PHP es muy cómodo trabajar con una clase que se entienda con las bases de datos, nosotros símplemente tenemos que llamarla siempre que necesitemos algo.
  • A la hora de hacer una web dinámica se piensa poco en un posible re-diseño, y cuando este llega nos echamos las manos a la cabeza ya que hemos puesto multitud de código PHP entre el (x)html… podremos crear una biblioteca de funciones dedicada a la exportación web y desde nuestro php llamarlas… haría fáciles los re-diseños.

Todo esto viene unido a un post anterior: Enseñando a programar, sobre todo porque en muchos lugares se enseña programación (me refiero a carreras universitarias que no tienen que ver con informática; algunos ciclos formativos, etc) pero uno de los grandes objetivos es que nos sirva para el futuro; y de poco sirve si no se sientan unas bases. Es importante el reciclaje, la claridad y la sostenibilidad.

Foto: Feliciano

Enviando posts a twitter

Viernes, 28 de Mayo de 2010 admin Sin comentarios

twitter-bird-6

Hace mucho tiempo leí en anieto2k una función muy interesante para twittear sin necesidad de incluir APIs tremendas. Es decir, si en mi aplicación, sólo quiero enviar twits, ¿para qué incluir algo demasiado grande? Con una pequeña función estaría todo resuelto.

El tema es que hace poco inicié un proyecto que periódicamente envía twits y necesité echar mano de esa función. Descubrí que Twitter había cambiado un poco su forma de interactuar.

Antes, podíamos enviar por GET (en la URL) el parámetro del mensaje que íbamos a postear, aunque ahora devuelve un error extraño: 413 Request Entity Too Large, más o menos es cuando la consulta que enviamos al servidor es muy grande; aunque el error nos lo da porque no encuentra el post que queremos publicar.

Para solucionarlo, tenemos que enviarlo con el método post, de la siguiente forma:

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
function postToTwitter($username,$password,$message)
{
// Esta línea está modificada
    $host = "http://twitter.com/statuses/update.xml";

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $host);
    curl_setopt($ch, CURLOPT_VERBOSE, 1);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_USERPWD, "$username:$password");
    curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    curl_setopt($ch, CURLOPT_POST, 1);
// Esta línea es nueva
   curl_setopt($ch, CURLOPT_POSTFIELDS, 'status='.urlencode(stripslashes(urldecode($message))));
    $result = curl_exec($ch);
    $resultArray = curl_getinfo($ch);
    curl_close($ch);
    if($resultArray['http_code'] == "200")
    {
        echo "<br />OK! postedo en http://twitter.com/".$username."/<br />";
    }
    else
    {
        // Esto lo podemos quitar, es sólo para analizar la salida.
        print_r($resultArray);
        echo "<br />Error! ha ocurrido un problema<br />";
    }
}

Con esta versión modificada del script ya podemos twitear :)

Y para llamar a esta función:

postToTwitter(’usuario’, ‘contraseña’, ‘140 letras de lo que queremos twitear’);

Foto: Free Twitter Bird Icon Set

Getters / Setters en PHP

Sábado, 1 de Mayo de 2010 admin Sin comentarios

Cuando estamos programando con clases en PHP, a veces tenemos la necesidad de acceder a atributos privados de una clase desde fuera, tal vez para sólo lectura, sólo escritura, o porque estos no pueden tener cualquier valor.

Pero claro, son atributos privados, no podemos hacer esto tal alegremente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
class test
{
    private $privado;
    function test()
    {
      $privado="Variable privada";
    }  
}

$t=new test;

echo $t->privado;

?>

En C++, por ejemplo, definimos getters/setters para todos los atributos qud podamos “tocar” desde fuera, aunque, es escribir demasiado (tratamos cada atributo por separado, y está bien). Por otra parte, en PHP tenemos los métodos mágicos, y entre ellos encontramos __get() y __set() y haciendo caso al ejemplo anterior podemos hacer lo siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
class test
{
    private $privado;
    function test()
    {
      $this->privado="Variable privada";
    }  
   
    function __get($atrib)
    {
      return $this->$atrib;
    }
}

$t=new test;

echo $t->privado;
?>

Aunque de esta forma, para qué queremos atributos privados ? Si bueno, podríamos leerlos todos, escribirlos no, aunque podemos hacer una pequeña implementación para tener un cierto control sobre qué atributos privados son visibles desde fuera:

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
<?php
class test
{
    private $privado;
    private $visible;
    private $oculto;
    private $atributos_visibles=array("privado", "visible");
    function test()
    {
      $this->privado="Variable privada";
      $this->visible="Atributo privado visible";
      $this->oculto="Atributo privado oculto";
    }  
   
    function __get($atrib)
    {
      if (in_array($atrib, $this->atributos_visibles))
        return $this->$atrib;
      else
        return false;
    }
}

$t=new test;

echo $t->privado."\n";
echo $t->visible."\n";
echo $t->oculto."\n";
?>

Obtendremos:

$ php getset.php
Variable privadaAtributo privado visible[gaspy@lytio blog]$ php getset.php
Variable privada
Atributo privado visible

De esta forma, podemos evitar errores en caso de atributos inexistentes, y evitar que los que no queremos no se puedan leer. Lo mismo podemos hacer con los setters:

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
<?php
class test
{
    private $privado;
    private $visible;
    private $oculto;
    private $atributos_visibles=array("privado", "visible");
    private $atributos_tocables=array("privado");
    function test()
    {
      $this->privado="Variable privada";
      $this->visible="Atributo privado visible";
      $this->oculto="Atributo privado oculto";
    }  
   
    function __get($atrib)
    {
      if (in_array($atrib, $this->atributos_visibles))
        return $this->$atrib;
      else
        return false;
    }

    function __set($atrib, $valor)
    {
      if (in_array($atrib, $this->atributos_tocables))
        $this->$atrib=$valor;
    }
}

$t=new test;

$t->privado="VALOR NUEVO DE PRIVADO";
$t->visible="VALOR NUEVO DE VISIBLE";
echo $t->privado."\n";
echo $t->visible."\n";
echo $t->oculto."\n";
?>

Por otra parte, si deseamos filtrar la entrada de esos atributos, es decir, que por ejemplo, privado deba ser un número entre 0 y 10, debemos implementarlo dentro de __set (con un switch por ejemplo, o comprobar si es un valor que debemos filtrar, entonces llamamos a una función que verifique su valor).

Cuando Facebook hace de las suyas [ BUG CSS ]

Sábado, 17 de Abril de 2010 admin Sin comentarios

Durante este año y varias veces ha habido un pequeño bug CSS que hace que los que mantenemos aplicaciones para Facebook (y no es un trabajo a tiempo completo) nos tiremos de los pelos.

Y es que al cargar nuestra aplicación, los estilos css no funcionan, no cargan, y si cargamos el archivo de Facebook del tipo:

http://external.ak.fbcdn.net/fbml_static_get.php?src=http%3A%2F%2Fmiurl.com%2Faplicacion%2Fcss%2Ffilo.css%3F_fb_q%3D1&appid=107083291268&pv=1&sig=5ee8229e4afbee29836224de876dfa&filetype=css

nos devolverá un precioso mensaje que dice:

Parámetro no válido: Error desconocido

Lo mejor es que el mensaje está traducido al español, por lo que al principio podemos sospechar que falla nuestra aplicación y luego cuando buscamos el error lo tenemos más difícil, aunque podemos buscar lo siguiente (aparece también en inglés, según nuestra localizacion):

Invalid parameter: Unknown error

El bug aún está abierto (a día 17 de Abril de 2010): podéis consultar el estado actualizado aquí.

Pero mientras investigaba el bug, encontré un pequeño fragmento de código interesante (y podemos utilizarlo como solución temporal al problema):

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
function minify( $css ) {
        $css = preg_replace( '#\s+#', ' ', $css );
        $css = preg_replace( '#/\*.*?\*/#s', '', $css );
        $css = str_replace( '; ', ';', $css );
        $css = str_replace( ': ', ':', $css );
        $css = str_replace( ' {', '{', $css );
        $css = str_replace( '{ ', '{', $css );
        $css = str_replace( ', ', ',', $css );
        $css = str_replace( '} ', '}', $css );
        $css = str_replace( ';}', '}', $css );

        return trim( $css );
}

function includeStyleCSS($filename)
{
        // due to: http://bugs.developers.facebook.com/show_bug.cgi?id=9053
        // We either must print the stylesheet inline
        // or include it with a link tag that does not include rel="stylesheet".
        // Fixed 3/6/2010
        // Broken 4/13/2010:http://bugs.developers.facebook.com/show_bug.cgi?id=9601

        // use this block when linked CSS is broken
        echo "<style type=\"text/css\">";
        $content = @file_get_contents($filename);
        echo minify( $content );
        echo "</style>";

        // use this block when linked CSS is working
        //      echo "<link rel=\"stylesheet\" href=\"http://MYSERVER.COM/$filename\" type=\"text/css\" />\n";
}

He dejado el fragmento de código original, pero podemos verlo atentamente y analizar lo que hace:

  • Dentro de minify(), el primer regexp_replace elimina cuando hay más de un espacio seguido; el segundo, elimina los comentarios. Los str_replace que le siguen, sirven para eliminar espacios sobrantes cerca de caracteres de inicio y fin, y separación.
  • includeStyleCss() introduce dentro de nuestro archivo resultante el CSS del archivo (más o menos reducido por minify()).

Hay que destacar que es una medida provisional, pero es interesante incluir este código en nuestras aplicaciones porque Facebook es reincidente en este fallo y no descartamos que vuelva a ocurrir.

Pero bueno, como yo no me puedo quedar quieto, vamos a intentar mejorar este código (propuesto en la discusión del bug por Ed Holzwarth, aunque he podido encontrar algún fragmento de minify por la red.

La modificación de este código viene de un poquito de investigación por otras webs:

1
2
3
4
5
6
7
8
9
10
11
12
13
function minify($css)
{
  // Quitamos comentarios
  $css = preg_replace('#/\*.*?\*/#s', '', $css);
  // Quitamos espacios en blanco cerca de {}|:;,
  $css = preg_replace('/\s*([{}|:;,])\s+/', '$1', $css);
  // Quitamos espacio en blanco al inicio
  $css = preg_replace('/\s\s+(.*)/', '$1', $css);
  // Quitamos ; innecesarios
  $css = str_replace(';}', '}', $css);

  return $css;
}

Por cierto, sería interesante aplicar este minificador al script de cache y compresión de ficheros CSS. que publiqué hace un tiempo.

Función curiosa: preg_replace_callback (PHP)

Lunes, 15 de Marzo de 2010 admin 2 comentarios

A veces tenemos la necesidad de reemplazar un texto dentro de una cadena larga. Por ejemplo, el uso principal que le doy a esta función es el procesamiento de plantillas para páginas web, en donde tengo la página en HTML puro por un lado, y en su interior hay ciertas palabras clave, por ejemplo —seccionA—, —fotoUsuario—, —menuSesion—, etc; y en la web definitiva, aparecerá otra cosa en lugar de ese texto, aparecerá el objeto al que hace referencia.
Aunque cada cadena de texto seccionA, fotoUsuario, requiere un procesamiento distinto y es posible que no tengamos por qué procesar siempre todas las equivalencias de todos los textos. Queremos en definitiva reemplazar —seccionA— por el resultado de una función que ejecutaremos cuando encontremos ese texto. Sería como:

1
2
3
4
$disparadores=array("---seccionA---", "---fotoUsuario---", "---menuSesion---");
$reemplazos=array(dibuja_seccionA(), get_fotoUsuario(), dibuja_menuSesion);

$web=str_replace($disparadores, $reemplazos, $web);

Aunque, como dijimos, en el ejemplo anterior, se tienen que ejecutar dibuja_seccionA(), get_fotoUsuario() y dibuja_menuSesion().

Pero podemos aprovecharnos de las expresiones regulares, para extraer texto que esté entre “—” y “—” y pasar lo que hay entre medias a otra función que decidirá qué hacer; eso hace preg_replace_callback().

1
2
3
4
5
6
7
8
9
10
function quehacer($texto)
{
  switch ($texto[1]) // [0] devuelve: ---texto---, [1] devuelve texto
  {
     case 'seccionA': return dibuja_seccionA();
     case 'fotoUsuario': return get_fotoUsuario();
     case 'menuSesion': return dibuja_menuSesion();
  }
}
$web=preg_replace_callback('/---([a-zA-Z0-9_]*)---/', 'quehacer', $web);

Hasta aquí bien, el primer parámetro es una expresión regular (es un tema muuuy extenso), el segundo es la función a la que llamamos cuando encontramos el texto, y el tercero es de dónde lo sacamos. Bueno, ahora surge un problema, imaginad que necesito pasarle parámetros a esa función callback. Lo podemos hacer así:

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
function guardar_datos($data=null)
{
  static $guardados; // Una variable estática, muy importante

  // Si se especifica $data, lo guardamos en $guardados, al ser estática, aunque salgamos de la función, el valor de la variable no se perderá.
  if ($data)
    $guardados=$data;
 
  return $guardados;
}

function quehacer($texto)
{
  $datos = guardar_datos();

  switch ($texto[1]) // [0] devuelve: ---texto---, [1] devuelve texto
  {
     case 'seccionA': return dibuja_seccionA();
     case 'fotoUsuario': return get_fotoUsuario($datos);
     case 'menuSesion': return dibuja_menuSesion($datos);
  }
}

guardar_datos(array($datos_usuario, $datos_sesion));
$web=preg_replace_callback('/---([a-zA-Z0-9_]*)---/', 'quehacer', $web);

Nota: las variables $datos_usuario, $datos_sesion y $web no están definidas, como esto es parte de un programa, hay que imaginar un poco cuál será la información que contendrán.

Visita otras webs de la red

Easy AdSense by Unreal