Archivo del sitio

[PHP5] – Barco Project: Un proyecto sobre barcodes y QRCode

En el día de hoy (30. sep. 2009) nace Barco Project como una iniciativa de integrar bajo una misma API todo el proceso de generar y analizar (escanear) variados tipos de Codigos de Barra y Códigos 2D; esto integra la posibilidad de con una misma API, generar:

  • Code39 (Code 3 to 9)
  • EAN 128
  • UPC
  • UPCS (US Postal Code)
  • Codabar
  • UPCa
  • Code128
  • QRCode
  • ISBN

Además incluirá la posibilidad de “analizar” un PNG generado para “reconocer” el contenido de algunos códigos de barra arriba mencionados.

El proyecto se encuentra en fase de “alpha release” y actualmente solo ha sido “portado” el código para generar QRCode.

Qué es QRCode?:

Según la Wikipedia un QRCode es: “Un QRCode (Quick Response Barcode) es un sistema para almacenar información en una matriz de puntos o un código de barras bidimensional creado por la compañía japonesa Denso-Wave en 1994; se caracterizan por los tres cuadrados que se encuentran en las esquinas y que permiten detectar la posición del código al lector. La sigla “QR” se derivó de la frase inglesa “Quick Response” pues el creador aspiraba a que el código permitiera que su contenido se leyera a alta velocidad. Los códigos QR son muy comunes en Japón y de hecho son el código bidimensional más popular en ese país.” (fuente: wikipedia).

Acá un ejemplo de código QR:

Y qué tiene de intersante QR?

QRcode es de muchisima popularidad en japón, esto es debido a que mientras el resto de los códigos de barra requieren la detección de “espacios y llenos” utilizando un láser; QRCode usa un patrón de cuadrados (dot-matrix) que representan los datos (en 2 dimensiones, ancho y alto) y los “cuadrados marca” sirven para que cualquier lectór óptico reconozca donde empieza y termina “el código” (entiendase por cualquier lector a cámaras digitales y otros dispositivos ópticos).

Además QR es un proyecto de “código abierto”; desarrollado por Densa-wave (una filial de Toyota) para el inventario de repuestos de vehículos; sin embargo, tras la liberación de patentes (royalty-free) hecha en 1999 y su correspondiente estandarización como norma ISO-IEC (ISO/IEC18004) en 2000 ha permitido a mucha gente desarrollar aplicaciones para QR.

Y como ha ganado tanta popularidad?

QR viene en patrones fijos de 1 a 40 cuadros, pudiendo albergar hasta 7000 carácteres, como es posible guardar tal cantidad de información y como es posible “escanearlo” con cualquier cámara óptica (además es completamente libre hacerlo), pues 2+2!, a mucha gente en Japón se les ocurrió “incorporar” lectores de QR en sus respectivos celulares, esto fue ganando popularidad hasta el punto que en japón la gente coloca su QR informativo en el reverso de las tarjetas de presentación y hasta la información de ubicación en las revistas viene en códigos QR (ahorras espacio de publicación).

Nokia tiene su aplicación “oficial” para QRCode y Datamatrix para todos sus dispositivos serie N (aunque funciona en mi Nokia 5800 XpressMusic) acá:

http://mobilecodes.nokia.com/

Acá hay alguien que habla de una aplicación para Blackberry para analizar QRcodes:

http://www.enriquedominguez.com/leyendo-qr-codes-desde-la-blackberry/

iMatrix es la aplicación “oficial” del Iphone para leer QRCodes:

http://www.qrcode.es/?p=244&language=es

Por lo que un QRCode generado ya casi cualquier persona (que tenga cámara digital en el celular + el software) lo puede leer.

Montandose en el barco de Barco Project

Barco Project surge como una iniciativa personal de integrar dentro de una única librería todo lo necesario para generar diversos tipos de barcodes; realmente todo surge como la posibilidad de cumplir con la ordenanza de la Providencia 939 del SENIAT (Organismo tributario Venezolano) que indica que para las facturas electrónicas impresas en formas libres; se sugiere agregar el código de barra para identificar la factura y algún medio electrónico de identificación automatizado del cliente (nombre, RIF: Registro de Información Fiscal).

Para ambas cosas, que mejor que combinar Code39 (factura), UPC (Inventario) y QRCode (identificación)?.

En mi investigación, determiné que el único script “viable” para QRCode en PHP que existía estaba en Japones y solamente funcionaba en CGI (es una pagina web que te pide todos los parámetros como URL encode data); esto dista mucho de la practicidad de contar con un objeto parametrizable que permita a distintas aplicaciones generar códigos QR.

Barco::QR

Con Barco::QR un programador de aplicaciones puede generar códigos QR con la simplicidad de un código PHP; veamos un ejemplo:

Primero, inicializamos la librería barco:

require 'barco/barco.inc.php';
#Inicializamos Barco:
barco::init();

Esta línea, me permite solicitar un generador de códigos QR (Quick Response):

$qr = barco::generate('qr');

La gran mayoría de los parámetros vienen por defecto, el único valor obligatorio es los datos que debemos agregar:

#defino la data y el modo de correccion ECC;
$qr->data('Esta es una prueba de Encoding usando QRcode')->ecc('M')->size('10');

ECC es el módo de corrección de errores, QR cuenta con 4 modos (‘M’, Q, L y H) (esto es opcional: por defecto siempre es M).

El Tamaño (size) define las dimensiones máximas del QR, desde 1 (max: 35 caracteres) hasta 40 (max: 7000).

Nota: intentar crear un QR más pequeño que la cantidad de datos genera error, aunque espero “mejorar” ese comportamiento al tratar de determinar el tamaño óptimo para la longitud de los datos requeridos.

Ahora, simplemente generamos el código QR:

if($qr->generate()) {
 $qr->image('png');
}

QR puede emitir el código como un RAW de bytes de imagen (útil para almacenar en una DB) o en forma de una imágen para salida por navegador, también pueden almacenarlo con un nombre a un archivo, escogiendo claro está, si lo desean jpeg o png.

El código generado por este ejemplo es:

Esta es una prueba de Encoding usando QRcode

Esta es una prueba de Encoding usando QRcode (10x10)

Como indiqué el proyecto se encuentra en fase “pre-alpha” y ya genera códigos QR (a diferentes dimensiones), próximamente incorporaré Code39, UPC y DataMatrix como principales algorítmos de códigos de barra.

Tambien incorporaré un lector-analizador (usando imagemagick) de códigos de barra para que puedan “probar” los códigos generados en ausencia de un scanner.

Los Códigos QR generados por el proyecto han sido probados con mobilecodes de Nokia y con QuickMark para HTC (espero más gente los pruebe).

Esperen más noticias de este proyecto!.

Nota: próximamente incorporaré un servicio gratuito de generación de QRCodes para personas que solo deseen tener un QR y no tengan tiempo (o no sepan) programar; esperalo!.

PHP5 – TDOM: Creando archivos XML usando DOM y PHP

En este post presento TDOM (Tomato:Document Object Model), una librería que permite simplificar el proceso de leer, analizar, modificar o crear archivos XML-based de distintos tipos usando una API simplificada y utilitaria.

Aunque esta librería tiene ya bastante tiempo conmigo (a menos más de un año desde que la hice); un “re-factoring” para hacerla más compatible con PHP > 5.3 y la posibilidad de tener una interfaz basada en “plugins” que permiten extender sus capacidades agregando nuevos tipos de documentos XML y además de crearle un proyecto libre en Google Code; es lo que me hace escribir el articulo.

El proyecto nace bajo licencia GPL v.3 y está en fase alpha, versión 0.1.2; permite crear documentos y archivos en:

  • XML
  • DocBook
  • SVG
  • (x)HTML estricto
  • Interfaces XUL remote

Espera incorporar próximamente (ya estoy programando en ello):

  • XMPP (Paquetes del protocolo XMPP que usan Jabber/Gtalk)
  • RSS (Sindicación de manera fácil)
  • RDF (Resource Description es base de muchos tipos de archivos, como FOAF: relaciones amigo-amigo descritas semánticamente usando RDF)
  • ATOM
  • ODF

TDOM forma parte de la capa de creación y vistas de Tomates Framework, que se encuentra en un proceso final de adaptación y re-invención; lo importante de TDOM es que permite crear interfaces XUL, combinado con Jquery+REST sería el primer framework completamente operativo sobre PHP (el otro es Cyclone en perl) que permitiría crear aplicaciones XUL:Remote (que correrían como una aplicación desktop usando XULRunner) en implementar completamente Interfaces XUL de Mozilla.

Creando una Interface XUL

Está claro que el código dentro de poco será más simplificado cuando todos los widgets UI (toolbars, menu, tabbers, botones) estén incorporados en la clase; pero este es un ejemplo escribiendo solo PHP:

$xml = $dom->type('xul');
#un tabbox
$tabbox = $xml->create('tabbox');
$tabbox->orient('vertical')->flex('1');
$tabs = $tabbox->create('tabs');
$tabpanel = $tabbox->create('tabpanels');
$tabpanel->flex('1');
#adjunto las pestañas:
$tabs->create('tab')->label('Google');
$tabs->create('tab')->label('PHP.net');
$tabs->create('tab')->label('DEVEL');
#y el contenido de las pestañas
$tabpanel->create('browser')->src('http://www.google.co.ve/');
$tabpanel->create('browser')->src('http://www.php.net/');
$tabpanel->create('browser')->src('http://www.devel.com.ve/');
$xml->title('Prueba de XUL');
$dom->render(); 

Output:

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin/"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="xulWindow" persist="screenX screenY width height sizemode" xmlns:html="http://www.w3.org/1999/xhtml" title="Prueba de XUL">
  <tabbox orient="vertical" flex="1">
    <tabs>
      <tab label="Google"/>
      <tab label="PHP.net"/>
      <tab label="DEVEL"/>
    </tabs>
    <tabpanels flex="1">
      <browser src="http://www.google.co.ve/"/>
      <browser src="http://www.php.net/"/>
      <browser src="http://www.devel.com.ve/"/>
    </tabpanels>
  </tabbox>
</window>

Proximamente subiré una demo de como se ve esta interfaz XUL.

Creando un archivo (x)HTML estricto

Un ejemplo de como el código puede ser simplificado, es tener todo un cuerpo XHMTL 1.0 estricto teniendo solo 3 líneas de código; esto gracias a que todas las etiquetas son necesarias para la descripción de un archivo según la norma de la W3c; estas 3 líneas:

$html = $dom->type('html'); 
$html->setTitle('.: Titulo de la Pagina Web :.');
$dom->render();

Generan todo este bloque de código que es sintácticamente válido con XHTML 1.0 estricto; lo interesante es que podemos cargarle contenido al BODY con TDOM y este será normalizado para ser XHTML 1.0 estricto; básta de aplicaciones inválidas.

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://localhost/proyectos/tomates/tomates/include/tdom/tomates/tdom/include/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>.: Titulo de la Pagina Web :.</title>
    <base href="http://localhost/proyectos/tomates/" />
<!--Aqui comienzan las etiquetas meta-->
    <meta name="author" content="" />
    <meta name="generator" content="Tomates Framework" />
    <meta name="description" content="" />
    <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8" />
    <meta http-equiv="Content-Script-Type" content="text/javascript" />
    <meta http-equiv="Content-Style-Type" content="text/css" />
    <meta name="robots" content="all" />
    <meta http-equiv="Content-Language" content="en_US" />
    <meta name="keywords" content="" />
    <meta name="Revised" content=": Sep 18 2009" />
<!--Aqui terminan las etiquetas meta-->
    <link rel="shortcut icon" href="http://localhost/proyectos/tomates/application/assets/images/favicon.ico" type="image/x-icon" />
    <link rel="start" href="http://localhost/proyectos/tomates/" />
    <link rel="index" href="http://localhost/proyectos/tomates/" />
  </head>
  <body></body>
</html>

Creating an (x)HTML strict

Code:

                $html = $dom->type('html');
                $html->createHead();
                $html->setTitle('.: Titulo de la Pagina Web :.');
                $dom->render();

Output:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://localhost/proyectos/tomates/tomates/include/tdom/tomates/tdom/include/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>.: Titulo de la Pagina Web :.</title>
    <base href="http://localhost/proyectos/tomates/" />
<!--Aqui comienzan las etiquetas meta-->
    <meta name="author" content="" />
    <meta name="generator" content="Tomates Framework" />
    <meta name="description" content="" />
    <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8" />
    <meta http-equiv="Content-Script-Type" content="text/javascript" />
    <meta http-equiv="Content-Style-Type" content="text/css" />
    <meta name="robots" content="all" />
    <meta http-equiv="Content-Language" content="en_US" />
    <meta name="keywords" content="" />
    <meta name="Revised" content=": Sep 18 2009" />
<!--Aqui terminan las etiquetas meta-->
    <link rel="shortcut icon" href="http://localhost/proyectos/tomates/application/assets/images/favicon.ico" type="image/x-icon" />
    <link rel="start" href="http://localhost/proyectos/tomates/" />
    <link rel="index" href="http://localhost/proyectos/tomates/" />
  </head>
  <body></body>
</html>

Map / Reduce en PHP comparado con Scheme

PHP6 será compatible con funciones lambda y agregará por ende algunas caracteristicas de lenguajes funcionales; interesante es entonces encontrar entradas como esta, que nos explica de una manera simple y sencilla la implementación de una “high-order function” en PHP6 comparandola luego con Scheme (un lenguaje funcional).

Veamos el ejemplo comparando la función MAP en PHP6 y en Scheme:

function map($fn, $list) { 
  return empty($list) ?
  array() :
  construct($fn(first($list)),
  map($fn, rest($list)));
}

Y ahora vemos la misma función equivalente en scheme:

(define (map fn lis)
 (if (null? lis)
 '()
 (cons (fn (car lis))
 (map fn (cdr lis)))))

Las funciones anónimas solventan muchos problemas que antes se solventaban con loops recursivos bastante peligrosos; que vamos a estar claros no aporta la potencia de Lisp o Scheme, pero ya es un avance en el lenguaje.

[PHP 6 Namespaces] Una mala implementación

En las primeras de cambio, cuando aquel ruso Dimitri (Dmitri Vinogradov) postuló el parche para soporte de namespaces en php5 ó 6 y se inició un rally para incorporarlos rápidamente al lenguaje; mucha gente se entusiasmó, pensando que por fín se acabaría la cadena (o el yugo) a los nombres de función crípticos y a las implementaciones de 40 mil includes y requires al inicio de un archivo.

El preámbulo

Inicialmente el parche prometía bastante; al implementar un sistema de espacio de nombres basado en filesystem (y con soporte y resolución dinámica) muy semejante al de python:

<?php
namespace Proyecto::DNS;
class resolver {
public function get($ptr) {
}
}
?>

Y su implementación se realizaba:

<?php
use Proyecto::DNS as dns;
dns->get('127.0.0.1');
?>

Lo cual por legibilidad es más o menos como usar:

import DNS
DNS.get('127.0.0.1')

Lo cual parecía ser la solución “idónea” a los problemas de resolución del lenguaje; sin embargo, en octubre del 2008 la gente del buró de decisiones de Zend (la empresa que lleva el lenguaje PHP); decidió, fuera de toda lógica plausible; tratar a los espacios de nombres y a las clases como dos cosas completamente distintas; de tal manera que la resolución de nombres usando el :: quedaba descartada del lenguaje.

El problema

En la mayoría de los lenguajes no encontrarás una clase llamada igual que un namespace (o package como en Java o módulo como en python); o sea, nunca verás algo como:

import org.java.lang

donde Java.lang pueda ser un package y además una función; los increíbles de PHP desean hacer eso; con lo cual sentenciaron el separador (::) a muerte (al menos como separador de los namespaces, ya que el punto (como en python o java) no se puede usar porque es el concatenador lógico)).

Según la gente de Zend; tener:

<?php
namespace Proyecto;
function DNS() {}
?>

y

<?php
class Proyecto {
public function DNS() {
}
}
?>

Es sintáctica y además lógicamente válido;  lo que conlleva a que:

<?php
Proyecto::DNS();
?>

No sepa determinar si nos referimos a la función DNS en el namespace Proyecto o al método DNS en la clase Proyecto, llevando a confusiones al motor Zend2; obviamente, esto conllevó a una decisión.

La fatídica solución (Según Zend)

Lo que la gente de Zend ha ideado; es obviamente un disparate; como según ellos lo anterior “se puede hacer” (aunque no se debería tener un namespace y una clase con el mismo nombre), entonces debemos “adoptar” el slash (o separador Windows “\”, que se alegren los programadores .NET) como separador de las resoluciones de nombre; de tal manera que lo de arriba queda así:

<?php
Proyecto::DNS(); //llamando estáticamente al método DNS de la clase Proyecto
\Proyecto\DNS(); //llamando a la función DNS del namespace proyecto
?>

¿Que rayos es esa cosa?; otra horrible invención de Zeev Zurasky y pandilla!; esto hará que:

<?php
\Date\time(); //namespace Date, función time()
Date::time(); //clase incorporada Date, método time()
?>

Es decir, a la clase Date (incorporada en PHP5.1) puedo crear paralelamente un namespace Date con una función llamada idénticamente a su contraparte de la clase; no hay nada más horrible que esto.

¿No era más sensato, como en otros lenguajes, evitar que un package y una clase compartieran el mismo nombre?.

Las ventajas (que no lo son tanto)

He decidio copiar y desmentir cada una de las “ventajas” que han puesto para aceptar el cambio del separador.

  • name ambiguity is impossible
¿Qué es más ambiguo?, que se “lean” diferente o que pueda existir un Namespace y una clase con el mismo nombre?; imaginen esto:
<?php
\com\Zend\Data\Form::validate();
\com\Zend\Data\Form\validate();
?>
Ambas formas en el mismo script!, sintáctica y logicamente válidas; pero a la vista, ambiguas ambas (y un completo disparate).

  • \ is visually quite different from ::, and is easier to scan and detect as namespace instead of static class operator

Creo que la presencia de un import (o USE en PHP) es una facil forma de detectar “visualmente” quien es un namespace y a quien nos referíamos estáticamente.

  • \ is a single keystroke on U.S. keyboard layout without shift key

En la mayoría de los teclados latinoamericanos y españoles es imposible obtener el \ a la primera, a veces uno ni lo consigue!.

  • \this\is\used for paths on Windows and is intuitively familiar to those developers. According to a php|arch survey (as relayed by Steph Fox), most of their readers develop on Windows and deploy on Unix, which would imply that \these\paths are familiar

… Sin comentarios; recordemos que ahora Microsoft le apuesta a los lenguajes de scripting libres (python, php) en vez de a su .NET, así que tiene una fuerte inversión con Zend.

  • \this\maps\to\filesystem layouts often used by autoload intuitively for the above reason

Pudieron haber escogido el backslash de unix igualmente, o el punto, para parecerse más a otros lenguajes “serios” (ruby, phyton) …

  • because \ is a single keystroke, it is possible to require \ prefix for all global functions/classes/constants, and conversion is minimally effortful (from personal experience trying to convert files to several namespace separators to see what it was like)
El “namespace” global requerirá que “escapemos” todas las funciones y constantes globales, de tal manera que tendremos que llenar el código con cosas como:
<?php
\htmlspecialchars($variable);
?>
Simplemente hilarante.
  • code review ambiguities disappear permanently
Y muchos programadores enojados desaparecerán también permanentemente.
El Análisis posterior
Este parche ha sido incorporado a PHP 5.3; pero aún los cambios no han sido incorporados a PHP6; muchos vaticinan que ocurrirá algo parecido a la actual página http://www.gophp5.org (un gophp6.org) en un tiempo no mayor de 3 años; como consecuencia de que “proyectos de PHP4 no correrán en > PHP 5.3”; pero además, código escrito en PHP 5.3 o superior posiblemente no corra en PHP6.
Esto hace además que guias como esta; publicadas antes del parche de noviembre del 2008, sean inválidas, dicho sea de paso, hasta el .chm oficial en español de la documentación de PHP está erroneo pues no ha incorporado los cambios.
A %d blogueros les gusta esto: