Archivo de la categoría: PHP

[PHP5] Obtener el SID de un dominio en modo nativo con ldap-toolkit

Fuente: https://code.google.com/p/php5toolkits/wiki/ObtenerSid

Obtener el SID de un Dominio Active Directory es parte *esencial* de una migración exitosa de un dominio MS a Samba; ya que este representará el SID del nuevo dominio.

Extraerlo usando ldap-toolkit es cosa bastante sencilla; como lo explico en el wiki del proyecto.

Configurar una conexión

Para usar una conexion a un MS Active Directory, configuramos:

#una conexion usando un Active Directory Service
$database['ads']['adapter']           = 'ads';
$database['ads']['host']              = '10.1.1.1';
$database['ads']['basedn']            = 'DC=test,DC=com,DC=ve';
$database['ads']['domain']            = 'test.com.ve';
$database['ads']['netbios_name']      = 'TEST';
$database['ads']['username']          = 'administrator';
$database['ads']['password']          = 'mipassword';
$database['ads']['port']              = 389;
$options = array('LDAP_OPT_PROTOCOL_VERSION' => 3, 'LDAP_OPT_REFERRALS'=>0, 'LDAP_OPT_SIZELIMIT'=>5000, 'LDAP_OPT_TIMELIMIT'=>300);
$database['ads']['options']           = $options;

#Importante el usuario y el netbios_name (nombre del dominio netbios) para el login

Snippet de Codigo

include "conf/base.inc.php";
include_once BASE_DIR . "conf/include_ldap.inc.php";

#obtenemos la configuracion AD
$ldap = ldap::load('ad');

#buscar una entrada basica, para extraer su SID
$entry = "(&(objectClass=user)(samaccounttype=". ADS_NORMAL_ACCOUNT .")(samaccountname=jesuslara))";
#conectamos al AD
$ldap->open();
$entry = $ldap->query($entry);
echo "SID usuario {$user}: " . $entry->bin_to_str_sid('objectSid');
$ldap->close();

Ese echo, mostrará un valor semejante a: ‘S-1-5-21-2102913520-367280043-1452191782-14800′ De esa salida: S-1-5-21-2102913520-367280043-145219178214800

Lo que está en negrillas es el SID del dominio, lo que es itálica, es el UidNumber del usuario; simplemente buscar la ubicación del último “-” y todo lo que hay desde ‘0’ hasta strpos(‘-‘) del último guión será el SID del dominio.

Fácil, rápido y permite una migración más transparente de dominios nativos MS AD a Samba.

[PHP5] Actualización de librerías

En vista de algunos proyectos de librerías que he hecho y que tengo por ahí pendientes; he creado un repositorio público en google code (que lo prefiero a GitHub para cosas como estas que no son proyectos, sino solo librerías); por donde la gente podrá encontrar algunas de las librerías que uso para algunos de mis proyectos.

En enlace: https://code.google.com/p/php5toolkits/

Entre las librerías que encontrarán ahí (por ahora, luego vendrán más) son:

excel_reader:

Una clase que permite leer archivos de excel (de los viejos, no de los OOXML, esa viene en camino) de una manera fácil y orientada a objetos; tiene un tiempo conmigo y hasta un artículo en este blog; pero había perdido acceso a mi viejo repositorio, así que le hice uno público.

la librería tiene licencia GPL v.2

Para hacer checkout, ejecutan:

svn checkout http://php5toolkits.googlecode.com/svn/tools/excel_reader/ excel_reader

Un ejemplo de uso:

$orden = new excel_reader('listado_sincedula.xls');
#de que columna sacamos los titulos de las columnas
$orden->setColumnName(1);
#definimos el encoding
$orden->setOutputEncoding('CP1251');

#ejecutamos la lectura del archivo excel:
$orden->read();

foreach($orden as $sheets) {
 echo "Hoja &lt <br />";
 $columnas = $orden->columns();
 $filas = $orden->numRows();
 for ($i = 2; $i <= $filas; $i++) {
 echo "Fila &lt <br />";
 $fila = $orden->rows($i);
 foreach($fila as $k=>$v) {
 print_r(nl2br("celda: {$k}= {$v}\n"));
 }
 }
 #forma alternativa
 foreach($orden->rows() as $fila) {
 foreach($fila as $k=>$v) {
 print_r(nl2br("celda: {$k}= {$v}\n"));
 }
 }
}

ldap-toolkit

Una mejora (usando una sintaxis orm-like) para operar con LDAP de una manera práctica; soporta las funciones más comunes que se realizan en LDAP; consultas, traer via DN, insertar, copiar, pegar, etc; permite obtener atributos privados y demás.

Para acceder al código:

svn checkout http://php5toolkits.googlecode.com/svn/ldap-toolkit

Y un ejemplo de uso uso:

#ejemplo de una nueva entrada:
$uid = $ldap->create('ou=usuarios,ou=Ejemplo,ou=unidades,dc=test,dc=com,dc=ve');
$uid->addObjectClass('inegOrgPerson'); #agrega recursivamente todos los objectclasses dependientes
$uid->addObjectClass('qmailUser');
$uid->baseAttribute('uid');
$uid->uid = 'prueba tres';
$uid->mail = 'prueba@test.com.ve';
$uid->insert();

Se aceptan sugerencias, revisión de código, ideas para ampliar las capacidades de las librerías, etc.

[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.

Declarado el futuro de PHP4

Para los que pensaban que Zend se iba a echar para atrás; pues no; no solamente fue removido el soporte para PHP4 desde el 1 de enero de este año; Zend ha declarado el “end of life” (Fin de vida) de PHP4 e indica que PHP 4.4.8 (el actual release) será el último a ser lanzado por Zend de esta versión de PHP.

Adicionalmente ha declarado que antes del 8 de agosto del presente año (8/8/2008) será removido complemente los fuentes de PHP 4 del servidor de php.net y sus respectivos mirrors.

Así que señores, a migrar sus aplicaciones! …

Viva Go PHP5!

Go PHP5!

¿Podemos tener PHP5 corriendo en un apache2 worker?

La respuesta básica a esta pregunta es sí; la razón de por qué no es tan simple, pero trataré de explicarlo en el siguiente artículo.

Apache 2 con mod_php puede ser ejecutado en dos modos; mpm_prefork y mpm_worker; mpm_prefork es una especie de compatibilidad con apache 1.x y es bueno para aplicaciones que poseen módulos que no son thread-safe; mpm_worker es un sistema multi-proceso multi-threaded (multi-hilado) y requiere que las aplicaciones en él ejecutadas posean hilos seguros de ejecución (thread-safe); mpm_worker es muchisimo más estable y puede ofrecer más conexiones con menos consumo de recursos; además de ser el ideal para equipos multi-core o multi-procesador.

mpm_worker tiene un rendimiento notablemente superior a mpm_prefork en la gran mayoría de las condiciones generales de un servidor web: ver aquí.

Entonces; ¿Por qué se usa mpm_prefork para PHP5? …

Muchas extensiones php5 (y php4) no son thread-safe; esto hace que php5 sea imposible de usar en modo mpm_worker sin “castrarlo” retirando aquellas extensiones que no lo son; sin embargo, esto no es problema alguno, puesto que la gran mayoría de las extensiones no “thread-safe” son básicamente no usadas por la mayoría; un ejemplo es la extensión mm; que permite crear una caché compartida para gestionar las sesiones (y que puede seguramente ser reemplazada por memcached) casi nunca es usada; gd versión 1 debe ser evitada y usar gd2.

Otro mito extendido por esto es que php5 no puede ser ejecutado en modo worker; esto es porque en Debian solo están los binarios compilados en modo prefork y de hecho, instalar php5 desinstala apache2 mpm_worker e instala mpm_prefork; por lo que he decidido compilar mi propio php5 para Debian Lenny (apache 2.2.4 y php 5.2.5) con soporte mpm_worker.

Compilando php5

Primero, debemos instalar algunas librerías que son requeridas (devel) para compilar php5:

>aptitude install libmhash-dev libmhash2 libtidy-dev libgd2-xpm-dev libgd2-xpm libmcrypt-dev libmcrypt4 mcrypt t1lib-bin libt1-dev libxml2-dev libcurl3-dev libaspell-dev libpspell-dev libxslt-dev libbz2-dev libsqlite-dev libdb4.4 db4.4-util libdb4.4++-dev libsqlite3-dev libsnmp-dev

Y luego de descomprimir php-5.2.5.tar.bz2 (descargado de la página de php.net) ejecutamos el siguiente ./configure en la raíz del código fuente:

CFLAGS=”-O3″ CXXFLAGS=”-O3 -fPIC -mtune=nocona -march=nocona \
-fPIC -pipe -fomit-frame-pointer -msse -fexceptions -ffast-math -mfpmath=sse,387″ \
./configure \
–prefix=/usr/php –sysconfdir=/etc/php5/apache2 –mandir=/usr/share/man \
–with-apxs2=/usr/sbin/apxs –libexecdir=/usr/lib/php5 –bindir=/usr/bin –libdir=/usr/lib/php5 \
–with-config-file-path=/etc/php5 –with-config-file-scan-dir=/etc/php5/conf.d \
–with-exec-dir=/usr/lib/php5/libexec –enable-inline-optimization \
–disable-debug –with-curl –with-curlwrappers –with-db4 \
–with-zlib=/usr –enable-bcmath –enable-calendar –enable-mbstring –enable-dba \
–with-libxml-dir=/usr –with-xmlrpc=shared –with-pear=/usr/share/php –with-regex \
–with-pcre-regex=/usr –enable-exif –with-t1lib –with-xsl \
–with-mhash –with-mcrypt –enable-zend-multibyte –with-pspell –enable-zip –enable-bcmath \
–with-jpeg-dir=/usr –enable-soap –enable-sockets –with-xpm-dir=/usr –with-freetype-dir=/usr/lib \
–enable-ftp –with-gd –with-png-dir=/usr –with-ttf \
–enable-json –with-mime-magic –with-tidy=/usr –with-ldap –with-xmlrpc \
–enable-gd-native-ttf –enable-gd-jis-conv –with-gettext –with-xmlrpc –with-xsl \
–with-mysql –with-mysqli \
–enable-sysvmsg –enable-sysvsem –enable-sysvshm –enable-sigchild \
–with-ldap –enable-mbstring –with-bz2 –with-iconv –with-gettext –enable-shmop \
–enable-sockets –enable-wddx –with-zlib \
–with-kerberos=/usr –with-openssl=/usr –enable-soap –with-snmp=/usr \
–with-pgsql –with-sqlite=/usr \
–enable-pdo –without-pdo-dblib –with-pdo-mysql \
–with-pdo-pgsql –with-pdo-sqlite=/usr

ejecutar:

make all

y luego:

make test

permitirá compilar y luego probar nuestro php5 en modo mpm_worker; al final un:

make install

permitirá instalar php5.2.5

Explicando brevemente las sentencias de pre-procesador:

Como verán, antes del .configure hemos ejecutado unas sentencias que mejoran el rendimiento del ejecutable php; entre ellas compilarla para el procesador que actualmente tenemos; en mi caso -mtune=nocona -march=nocona; nocona indica un procesador de doble nucleo (Core2-Duo), existen distintos modos dependiendo del ejecutable; pentium4, pentium-m, athlon-xp, prescott; siempre es bueno leer sobre -mtune y -march en el wiki de gentoo y en la guía de Compilación optimizada de Gentoo.

Apache Benchmark en un php5 con mpm_worker:

Para la ejecución de una aplicación PHP ab reporta:

ab -c 500 -n 500 http://localhost/tomates/

Requests per second: 32.66 [#/sec] (mean)

Conclusiones:

Espero que la utilización correcta de las extensiones de php; la utilización de un php thread-safe en un apache2 mpm_worker permitan a los desarrolladores crear aplicaciones más óptimas y a los servidores proveer una versión más rápida de php5 ejecutado sobre apache.

Notas finales:

La sentencia de compilación está configurada para el enviroment de debian o fedora (/etc/php5 como ruta del archivo php.ini); recuerden revisar bien el –prefix, –libdir, –bindir y otras rutas dependiendo de la distro donde deseen compilar el php5 en modo worker.

xdebug y PHP5 – Haciendo profiling de aplicaciones

Hacer profiling de aplicaciones consiste en hacer un mapa (trace) de todas las ejecuciones realizadas por nuestra aplicación con el respectivo tiempo (de CPU, en milisegundos, consumo de RAM, etc) consumido para determinar posibles mejoras en el código, cuellos de botella (bottlenecks) etc.

Quien pensaba que esto era solo una característica de lenguajes como C (que tienen a Valgrind) entonces conozcan la característica de Profiling de Xdebug.

Para instalar Xdebug existen numerosas guías y artículos, me centraré en la posibilidad de realizar el profile de una aplicación como tal.

Configurando xdebug

Para la activación de xdebug he creado un archivo (dentro del directorio conf.d de php5) llamado xdebug.ini que contendrá las instrucciones para activar la extensión y activar de una vez el profiling.

como root:

>touch /etc/php5/conf.d/xdebug.ini

luego, agregamos:

>vim /etc/php5/conf.d/xdebug.ini

zend_extension_ts=”/usr/lib/php5/extensions/no-debug-zts-20060613/xdebug.so”
[xdebug]
xdebug.profiler_enable=1
xdebug.profiler_output_dir=/tmp/php5/profiler

donde fijense que la ruta es donde phpize envía mis extensiones (en este caso, xdebug.so)

Agrego adicionalmente una sección xdebug (se agradece mantener ordenado los archivos ini) y activar “profiler_enable” (1 lo activa, 0 lo desactiva) e indicar la ruta (especificada por profiler_output_dir) donde se ha de crear el archivo de profiling.

guardamos:

:wq!

y reiniciamos nuestro apache:

>/etc/init.d/apache2 restart

En este momento, todas las aplicaciones que ejecutemos de php en nuestro servidor local, generarán un perfil de ejecución en la ruta indicada en profiler.output_dir

Ejecutando la aplicación

Ejecutar la aplicación es simplemente … … “ejecutar la aplicación!” … ya está, sin magia ni trucos …

dentro del directorio indicado se han creado unos archivos, cada uno con un timestamp de ejecución:

cachegrind.out.4286  cachegrind.out.4287  cachegrind.out.4288

Cada archivo es un archivo de texto, conteniendo el perfil de ejecución de la aplicación; ahora bien, ¿con qué lo vemos de una manera más “entendible”? …

Instalando y ejecutando Kcachegrind 

Bueno, el archivo es compatible con los archivos generados por valgrind; así que instalaremos una aplicación para KDE llamada Kcachegrind; simplemente:

>aptitude install kcachegrind

y  luego ejecuten la aplicación (kcachegrind)

Estudiando el perfil

kcachegrind consta de una ventana de 3 paneles:

pantallazo.png

El panel de la izquierda muestra las distintas funciones ejecutadas, desde el comienzo hasta el final, indicando en qué archivo se encontraban, cuando del porcentaje total de ejecución se han consumido y cuanto tiempo en milisegundos les ha tomado en ejecutarse; el panel superior derecho muestra las líneas de código que representa la función seleccionada en el panel derecho y la parte inferior derecha muestra un mapa como este:

profiler.png

Que representa todo el camino (ciclo) de ejecución del código desde donde estamos hasta el final de la ejecución de la clase (objeto), función o archivo seleccionado.

Detectando bottlenecks (cuellos de botella)

Detectar cuellos de botella es fácil de esta manera, simplemente buscamos los mayores tiempos de ejecución y revisamos bloque a bloque hasta encontrar la línea (o líneas) de código que representan la mayor cantidad de tiempo consumido.

bloque.png

De la siguiente ventana de bloque de código deducimos que splib_tomates::init (una función estática de la clase splib_tomates) tiene una duración de 41.10 ms en la línea 57 (call to splib_config::init en el archivo splib_config.php); para no tener que buscar ese archivo en la lista de profiler; simplemente con hacer doble click sobre la linea seleccionada se abrirá el bloque de código (función, archivo) que representa ese bloque de código.

En revisión posterior; determiné que el exceso de tiempo ocurría porque estaba llamando a una librería de caché (de terceros) que estaba ejecutando varios NOTICE y WARNING (aunque Tomates removía los errores); al retirar la librería, se pudo reducir ese tiempo a 26ms.

Conclusiones

No en el 10, el 20 o el 50; casi en el 100% de las aplicaciones web en PHP; los errores y lentitud de ejecución son fáciles de determinar y corregir si todos los desarrolladores antes de liberar una aplicación, ejecutaran debugging y profiling de su código más frecuentemente, realizaran y liberaran pruebas y mantuvieran a raya los “bottlenecks”; pero ya sabemos que eso no ocurre muy a menudo así que queda de parte de los nuevos desarrolladores aprender este tipo de técnicas para mejorar en el desarrollo de sus aplicaciones.

PHP5 / Eclipse PDT y Subversion

Una de las interesantes características por las cuales he usado Eclipse PDT en estos días es por su capacidad de conectarse a un recurso SVN para de manera automática gestionar todo el proceso de desarrollo conectado a un sistema de versiones como Subversion.

En el caso de PHP5, Eclipse PDT puede usar (al igual que cualquier suite basada en eclipse) subclipse; subclipse es un plugin para Eclipse que permite gestionar todo el proceso básico de trabajo con un sistema de versiones (add, update, commit, diff, merge son realizados casi sin ningún problema).

Como instalarlo

Para instalarlo tenemos que ir al menú Help -> Software Updates -> Find and Install …

En la ventana que aparece debemos indicar que vamos a instalar nuevas características (“Search for new features to install” y Next >)

En la ventana de componentes, indicamos que deseamos agregar un nuevo remote site …

El Plugin que vamos a agregar es el siguiente:

Name: Subclipse 1.2.x (Eclipse 3.2+)
URL: http://subclipse.tigris.org/update_1.2.x

Siguiendo los pasos de “next, next, next, finish” (:D ¡Que dificil es Linux!) tendremos nuestro plugin funcionando correctamente.

Nuestros primeros “pinitos” con Subclipse

Aun cuando subclipe tiene la posibilidad de hacer Checkout y agregarlo como un proyecto nuevo en nuestro arbol de proyectos; realmente preferí hacerlo de la manera tradicional; en mi caso:

Una consola:

>svn co http://svn.covetel.com.ve/tomates/trunk/ tomates/

*he descargado de mi sitio web una copia del fuente de Tomates Framework.

Me ha creado una carpeta donde yo me encontraba (en este caso, /var/www/tomates/) y puedo usar ahora esa carpeta como proyecto de Eclipse.

Creando un proyecto de Eclipse PDT

En la perspectiva PHP (menú Window -> Open Perspective -> PHP) indicar File -> new -> PHP Project

Llenar la ventana siguiente con los datos del proyecto (ruta, nombre, si es PHP5 especificamente, etc)

pantallazo-php-project.png

Luego de llenados los datos, presionen Finish y se creará un árbol de proyecto como el siguiente:

php-project.png

Ahora solamente basta con sincronizar dicho proyecto con un repositorio existente:

En la perspectiva SVN Repository ejecutamos botón derecho > New  >  Repository Location … En la ventana (para qué screenshot?, si tiene un único cuadro de texto!) agregamos el URL del repositorio SVN, Finish! y este es cargado como un repositorio de trabajo.

La otra forma consiste en Botón derecho sobre el proyecto > Team > Share Project e indicar “New repository” en la opción de “cual repositorio se usará” para el proyecto actual.

El Menú Team

El menú Team se actualiza una vez que nuestro proyecto está asociado a un repositorio SVN; este muestra las distintas tareas que se pueden realizar con nuestro proyecto y su sincronización con el repositorio:

menu-team.png

La primera opción nos permite sincronizarnos con el repositorio para comenzar a trabajar (esta opción llena la perspectiva “Team Synchronizing Perspective” y es una perspectiva que me permite gestionar el estado de mi repositorio (mensajes de error, SVN annotates, estado de los conflictos de código, anteriormente tareas bastante engorrosas de hacer por consola y hacerlas con rapidSVN era como estar desligado del proceso mismo de desarrollo).

Comandos SVN: Su equivalencia con el Menú Team

svn update -> Update:  permite mantenernos actualizados con el código que terceros de nuestro proyecto han realizado.

svn commit -> Commit … permite agregar nuestros cambios al repositorio ; de manera interesante, Commit … gestiona automáticamente todo archivo nuevo que agreguemos y todo archivo que borremos, de manera que Commit … es una fusión de los comandos svn add y svn delete.

svn merge -> Merge … muchas veces tenemos código escrito por distintos programadores en distintas partes de un mismo archivo, svn merge permite fusionar el código de sectores diferentes

svn diff -> create patch … Si un archivo contiene diferencias a la versión que se encuentra en el repositorio y deseamos crear un patch (archivo de cambios), hacemos click sobre el archivo en conflicto y ejecutamos Team -> create patch …

Enviando nuestros cambios al servidor

Si somos muy activos escribiendo código entonces commit … es una de las ventanas que más usaremos; commit puede actuar sobre el proyecto entero (haciendo click sobre el proyecto, botón derecho > Team > commit …) con lo cual se agregarán todos los cambios globales realizados, o a nivel de un archivo único o carpeta (haciendo click en el archivo o carpeta específicos, puedo realizar botón derecho > Team > Commit … y solo se enviarán los cambios en dicho archivo).

commit.png

Fijense en la ventana anterior; además de la posibilidad de un comentario (svn commit -m ‘comentario’ como se hace en consola), fijense que commit … ha detectado que he borrado un archivo y he agregado una carpeta (aparecen como deleted y unversioned) además de el archivo modificado (que aparece marcado como modified); las carpetas .settings y .project son del Eclipse así que eso no lo envio al repositorio (aunque debería ocultarlo o algo así).

Pero me equivoqué!

Revertir cambios no deseados para no contaminar el repositorio es tan sencillo como detenerse en el archivo (o carpeta, en caso de ser muchos) y ejecutar Team > revert y los cambios serán regresados a la última revisión del repositorio sin causar conflicto entre archivo local y remoto.

Resolviendo diferencias

Otra de las cosas interesantes de Subclipse es la posibilidad de revisar en “Team Synchronizing Perspective” la posibilidad de que existan archivos con diferencias entre la versión local y la versión en el repositorio; para esto:

conflict.png

Al abrir un archivo en la perspectiva “Team Synchronization” veremos nuestro archivo local a la izquiera y el remoto a la derecha; las diferencias vendrán marcadas por una linea negra rodeando el sector de código diferente y un cuadro negro por cada diferencia en la scrollbar; con los botones de arriba podemos copiar el código de un lado a otro del archivo o resolver las diferencias no-conflictivas (para las conflictivas tendremos que editar nuestro código :p).

Para cuando hemos terminado de resolver los conflictos, podemos ejecutar botón derecho sobre el archivo “Mark as Resolved” o en caso de haber realizado un Merge de código “Mark as Merged” y posteriormente Commit … para así guardar los cambios en nuestro repositorio.

La estabilidad, creando branches

Si el proyecto es muy activo (o está en fases iniciales) y llegamos a un punto donde declaramos una cierta “estabilidad” al código, pero queremos seguir agregando cambios (sin afectar que los usuarios finales puedan descargar el código para su uso o prueba) decretamos la creación de una branch (rama) que no es más que la declaración de un release de nuestro código en el repositorio; es tan facil como hacer click en nuestro proyecto y ejecutar botón derecho > Team > Branches/Tags y definir hacia donde va el código de la nueva rama (en el caso de tomates, http://svn.covetel.com.ve/tomates/branches/).

Ver lo que los demás han hecho y comentado

Por lo general los comentarios de cada revisión y las anotaciones en la rama SVN ayudan de mucho a saber que están haciendo los programadores y a continuar el trabajo sin pasar media hora dando vueltas a ver que cosas nuevas agregaron; Team > view comments y Team > View History me permite ver las anotaciones y la historia de las revisiones del repositorio actual.

Conclusiones

Para un usuario de GUI e IDE’s esto es una caraterística más que nos mantiene acostumbrados al uso de herramientas de desarrollo fáciles y rápidas, es de agradecer las capacidades de mantener a mi equipo de desarrollo sincronizados con los cambios sin tener que estar ejecutando comandos por consola o preocupandose por algo más que contribuir con código al proyecto; también es de hacer notar que si un abyecto y abnegado usuario de vim (muy potente editor por cierto) como walter (alias elsanto) ha dejado de usar vim para programar para unirse a los usuarios de Eclipse (en su caso como le gusta javascript/jquery usa aptana IDE) y de verdad comenzar a trabajar de manera colaborativa y sin estar ejecutando comandos raros en la consola.

Seguir

Recibe cada nueva publicación en tu buzón de correo electrónico.

Únete a otros 3.235 seguidores

A %d blogueros les gusta esto: