Archive for the ‘PHP’ Category

PHP4 y PHP5 juntos, pero no revueltos

Friday, July 29th, 2005

Si quieres tener en un mismo ordenador las versiones PHP4 y PHP5 instaladas y funcionando al mismo tiempo, en esta historía te explico uyn par de formas ridiculamente fáciles de hacerlo.

Eso sí, es necesario disponer de un ordenador Linux y tener instalado el “mágico” módulo del kernel llamado “binfmt_misc”, bueno y en realidad tampoco es que sea tan fácil hacerlo…

Instalación de Apache, PHP4, etc.
Lo primero es instalar Apache y PHP4 de la forma habitúal, es decir, como másd te apetezca. Puedes descargarte las fuentes y compilarlas tu mismo, puedes usar Yum, APT o up2date para instarlos, etc.

Instalación de PHP5
Ahora comienza la parte interesante. Debes compilar e instalar PHP5 en lo que personalmente denominio “como CGI”, es decir, que no debes instalarlo como módulo de Apache sino como un binario independiente.

Para compilar PHP5 como un binario independiente y válido para CGI debes lo primero que debes hacer es descargar la última versión estable de PHP5 desde la web de PHP y luego:

$ tar zxvf [archivo].tgz
$ cd [directorio]
$ ./configure --prefix=/usr/local/php5 --enable-force-cgi-redirect --with-xml --enable-bcmath --enable-calendar --enable-exif --enable-mbstring --enable-mbstr-enc-trans --enable-mbregex --with-mysql --with-pear --enable-xslt --enable-sockets --enable-track-vars --enable-versioning
$ make
$ make install

Tras hacer esto, el binario de PHP5 estará ubicado en:

/usr/local/php5/bin/php

En estos momentos, suponiendo que ya tenemos Apache instalado con la configuración más habitual, ya podríamos hacer programación CGI usando PHP5. Esto significa que podríamor crear scripts PHP5 y ejecutarlos a través de Apache, siempre que los nombraras con mombres tipo “hola.cgi” o “phpinfo.cgi” y siempre que incluyesemos la ubicación del binario PHP5 en la primera línea del script:

#!/usr/local/php5/bin/php
< ?php
echo "Hola mundo!";
?>

Configurar Apache
El hecho de poder utilizar la extensión “cgi” para un archivo PHP5 está muy bien, pero no nos permite identificar el tipo de archivo fácilmente, por lo que nos interesa utilizar la extensión “php5″.

Pero no podemos llamar “hola.php5″ al script de arriba y espera que funcione, primero tendremos que hacerle saber a Apache que los archivos con extensión “php5″ son scripts CGI y que los debe tratar como tal.

Para hacer esto, debemos abrir el archivo de configuración principal de Apache, es decir, el “httpd.conf” y localizar una línea similar a la siguiente:

AddHandler cgi-script .cgi .pl

Una vez localizada, añadiremos la extensión “.php5″ a dicha línea a fin de que Apache sepa que los archivos con extensión “php5″ son scripts CGI:

AddHandler cgi-script .cgi .pl .php5

Una vez hecho esto, no debemos olvidarnos de reiniciar Apache.

¿Un poco de mágica?
Pero lo de incluir la ubicación del binario PHP5 en la primera línea de cada uno de nuestros scripts es suficientemente aburrido como para utilizar el modulo del kernel “binfmt_misc” y hacer un poco de mágia.

Tal y como se intutuye de lo que se indica en el sitio web de binfmt_misc, “Binfmt_misc provides the ability to register additional binary formats to the Kernel without compiling an additional module/kernel. Therefore binfmt_misc needs to know magic numbers at the beginning or the filename extension of the binary.”, este módulo nos permite forzar al kernel de Linux para que trate un archivo con extensión “php5″ como una aplicación PHP5 y por lo tanto, ejecute el código usando el binario de PHP5.

Ya se que no me he explicado nada bien, pero lo mejor es que lo pruebes tu mismo, ejecuta los siguientes comandos:

$ modprobe binfmt_misc
$ cd /proc/sys/fs/binfmt_misc
$ echo ':PHP5:E::php5::/usr/local/php5/bin/php:' > register

El primero comando carga el módulo “binfmt_misc” en el kernel y el segundo hace que el kernel identifique cualquier archivo con extensión “php5″ como un archivo PHP5 y como tal, utilize el binario “/usr/local/php5/bin/php” para ejecutarlo.

Ahora pruebalo, crea el siguiente script y llamalo “hola.php5″:

< ?php
echo "Hola mundo!";
?>

Ahora accede a este script a traves de Apache. Funciona, ¿verdad?

Tras verificar que funciona, añade las siguientes líneas al archivo “/etc/rc.local”:

# Hacer que .php5 sea ejecutado por el interprete PHP5
modprobe binfmt_misc
cd /proc/sys/fs/binfmt_misc
echo ':PHP5:E::php5::/usr/local/php5/bin/php:' > register

De esta forma, el módulo “binfmt_misc” se cargará y se configurará para identificar a los archivos PHP5 cada vez que se inicie el sistema y no tendrermos que ejecutar dichos comandos cada vez que…

Pues esto es todo.

Otra forma de medir el tiempo de ejecución de tus script

Wednesday, May 4th, 2005

En un artículo anterior explicaba la forma de medir el tiempo de ejecución de un script PHP, en este artículo explico exactamente lo mismo, pero esta vez usando funciones estandar de PHP.

Al igual que en el otro artículo, en este usaremos dos funciones time_start() y time_end(). La primera, time_start(), inicia el temporizador o cronómetro mientras que la segunda función, time_end(), termina el temporizador y devuelve el tiempo transcurrido desde la llamada a la función time_start().

Por lo tanto, cuando queramos mder el tiempo de ejecución de un script o un código, situaremos la función time_start() al principio de este código y time_end() al final del código.

Dicho esto, lo primero que haremos es crear un script que llamaremos “benchmark.php” y que contendrá las 2 funciones comentadas y que incluiremos en cualquier script cuyo tiempo de ejecución querramos medir.

Las funciones

El contenido de benchmark.php será:

< ?php
function time_start() {
global $starttime;
$mtime = microtime();
$mtime = explode(" ",$mtime);
$mtime = $mtime[1] + $mtime[0];
$starttime = $mtime;
}

function time_end() {
global $starttime;
$mtime = microtime();
$mtime = explode(" ",$mtime);
$mtime = $mtime[1] + $mtime[0];
return ($mtime - $starttime);
}
?>

Como incluir las funciones en un script

Ahora supongamos que queremos obtener el tiempo de ejecución de cierto script llamado “actualizacion_bbdd.php”, con independencia de su contenido modificaremos este script de forma que quede así:

< ?php
// Incluir funciones de temporizador
include('benhcmark.php');

// Iniciar temporarizador
time_start();

// Contenido del script original

// Mostrar el tiempo de ejecución
echo time_end();
?>

Y esto es todo. Suerte!

Benchmarking tus scripts PHP

Monday, May 2nd, 2005

Este artículo muestra una sencilla forma de medir el tiempo de ejecución de tus scripts. Puede que no sea la forma mas fiable de hacerlo, pero es perfectamente válido en la mayoría de situaciones.

Advertencia: Para el correcto funcionamiento del script presentado en este artículo es necesario que vuestra instalación de PHP incluya la extensión BCMath. En Windows esta extensión está siempre disponible. En sistemas Unix puede que no este disponible, ya que es necesario compilar PHP con la opción “–enable-bcmath”. Si no tiene esta opción habilitada en le mostramos una forma alternativa de hacer lo mismo.

Aunque no resulte el método más fiable de medir el tiempo de ejecución de un script, es suficiente como para hacerte una idea del tiempo que precisa un script o algoritmo en ejecutarse. De esta forma podrás comparar fácilmente los tiempos de ejecución de distintos scripts e ir poco a poco aprendiendo a optimizar tus scripts al máximo, que es al fin y al cabo uno de los puntos más importantes a tener en cuenta al programar cualquier aplicación.

Para empezar, necesitaras incluir las siguientes dos funciones en el script que quieras medir:

< ?php
function timer_start() {
global $timeparts,$starttime;
$timeparts = explode(" ",microtime());
$starttime = $timeparts[1].substr($timeparts[0],1);
$timeparts = explode(" ",microtime());
}

function time_end() {
global $timeparts,$starttime;
$endtime = $timeparts[1].substr($timeparts[0],1);
return bcsub($endtime,$starttime,6);
}
?>

Para incluir estas funciones en el script a medir puedes hacerlo 1) pegando el código en el mismo script a medir o 2) pegar las funciones en un fichero aparte, por ejemplo, “benchmark.php” y posteriormente incluir este fichero en el script que quieras medir de la siguiente forma:

< ?php
include('benchmark.php');
?>

Una vez incluidas las funciones en tu script, debes llamar a la función time_start() justo antes del código a medir y a la función time_end() al final del código a medir.

Al final, un script que quieras medir, quedaría algo así:

< ?php
// incluir las funciones para medir el tiempo de ejecución
include('benchmark.php');

// iniciar el reloj
time_start();

// aquí el código que deseas medir
echo 'Hola Mundo';

terminar el reloj e imprimir el tiempo de ejecución
echo time_end();
?>

En definitiva, una forma fácil y rápida de medir el tiempo de ejecución de tus scripts para poder así encontrar los puntos críticos de tus aplicaciones e ir aprendiendo poco a poco a crear código optimizado.

Páginación de resultados

Tuesday, April 19th, 2005

La paginación de resultados es la única solución adecuada para poder mostrar al usuario los 4281 resultados que ha devuelto su búsqueda… ¿pero como hacerlo?

Bien, ya sabes lo que quieres. Quieres paginar resultados. ¿Pero como hacerlo? ¿Cuantos resultados por página? ¿Cuantas páginas? ¿Y si resultan que me salen 1000 páginas… muestro un enlace a cada una de ellas? ¿Solo muestro enlaces a las primeras 10 páginas? Y al cambiar de página… ¿que hago? ¿debo volver a hacer la busqueda? Este artículo pretende dar respuesta a todas estas preguntas.

En realidad, paginar resultados es tan fácil como seguir los siguientes 3 pasos:

Paso 1

Hacer una llamada a la base de datos para obtener el número total de resultados de la busqueda y asignar el resultado a una variable que llamaremos $total. Con MySQL la llamada debería ser algo así:

< ?php
$get = mysql_query('select count(*) from mitabla where ...');
$total = mysql_result($get,0);
?>

Paso 2

Hacer otra llamada que devuelva los resultados de la busqueda, limitando los resultados devueltos mediante las variables $pp y $st. $pp define el número de resultados por páginas. $st define el número, del total de resultados, desde donde empezar a mostrar los resultados en la página actual.

Usando MySQL la llamada será algo así:

< ?php
// obtener el valor de $st
if(isset($_GET['st'])) {
$st = $_GET['st'];
} else {
$st = 0;
}

// la llamada a base de datos
$get = mysql_query('select * from mitabla where ... limit '.$st.','.$pp);
while($row=@mysql_fetch_row($get)) {
// imprimir resultados
echo $row[0].'<br />';
}
?>

$st es una variable que se obtiene de la dirección de la página actual, por lo que su valor se debe obtener de la variable $_GET[’st’]. En la primera página de resultados $_GET[’st’] no esta definida, por lo que como puedes observar en el código superior tendremos que comprobarlo, y si resulta que no esta definida, tendremos que asignarle el valor 0.

Paso 3

Aplicar la función paginacion() que se muestra a continuación. Esta función se encarga de imprimir una serie de enlaces a las páginas resultantes de la busqueda.

< ?php
// resultados por pagina
$pp = 10;

// la función
function paginacion($total,$pp,$st,$url) {

if($total>$pp) {
$resto=$total%$pp;
if($resto==0) {
$pages=$total/$pp;
} else {
$pages=(($total-$resto)/$pp)+1;
}

if($pages>10) {
$current_page=($st/$pp)+1;
if($st==0) {
$first_page=0;
$last_page=10;
} else if($current_page>=5 && $current_page< =($pages-5)) {
$first_page=$current_page-5;
$last_page=$current_page+5;
} else if($current_page&lt;5) {
$first_page=0;
$last_page=$current_page+5+(5-$current_page);
} else {
$first_page=$current_page-5-(($current_page+5)-$pages);
$last_page=$pages;
}
} else {
$first_page=0;
$last_page=$pages;
}

for($i=$first_page;$i< $last_page;$i++) {
$pge=$i+1;
$nextst=$i*$pp;
if($st==$nextst) {
$page_nav .= '['.$pge.']';
} else {
$page_nav .= ''.$pge.'';
}
}

if($st==0) { $current_page = 1; } else { $current_page = ($st/$pp)+1; }

if($current_page< $pages) {
$page_last = '[>>>]';
$page_next = '[>]';
}

if($st>0) {
$page_first = '[< <<]';
$page_previous = '[< ]';
}
}

return "$page_first $page_previous $page_nav $page_next $page_last";
}

// mostrar resultado de la funcion
echo paginacion($total, $pp, $st, 'http://tudominio.com/mostrar.php?st=');

?>

A continuación una explicación de cada una de las variables que recibe la función paginacion():

  • $total. Número total de resultados que ha devuelto la busqueda. La forma de obtener este valor se ha explicado en el paso 1).
  • $pp. Número de resultados que queremos mostrar por en cada página.
  • $st. Número del primer resultado de la página actual. $st vale 0 en la primera página, en la siguientes valdrá 10, 20, 30, …
  • $url. La dirección completa de las páginas de resultados pero sin el valor de $st. Es decir, si la dirección de una página de resultados es http://tudominio.com/mostrar.php?st=30, el valor de $url debe ser http://tudominio.com/mostrar.php?st=

Como hacer “thumbnails” de tus fotografias

Tuesday, April 19th, 2005

PHP, junto con la librería GD, permiten la creación y manipulación de imágenes en tiempo real con gran facilidad y lograr unos resultados de una calidad más que aceptable.

Dependiendo de la versión de PHP y la librería GD, es posible crear y manipular imágenes de tipo JPEG, GIF, PNG y WBM, aunque en las últimas versiones no hay soporte para gráficos de tipo GIF. Para saber que formatos soporta tu instalación de PHP solo tienes que ejecutar el siguiente script:

< ?php
if (imagetypes() & IMG_PNG) echo 'Formato PNG soportado.&lt;br&gt;';
if (imagetypes() & IMG_JPG) echo 'Formato JPG soportado.&lt;br&gt;';
if (imagetypes() & IMG_GIF) echo 'Formato GIF soportado.&lt;br&gt;';
if (imagetypes() & IMG_WBMP) echo 'Formato WBMP soportado.&lt;br&gt;';
?>

Al ser el más complejo (o al menos completo) de realizar, haremos una función para redimensionar y ajustar la calidad de imágenes JPEG. Crear una función similar para imágenes PNG o WBMP debería resultaros sencillo.

La función recibe 5 parámetros:

  • Localización completa de la imagen original.
  • ocalización completa de la nueva imagen, es decir, el "thumbnail" que vamos a crear.
  • Calidad o compresión de la nueva imagen. Los valores posibles van de 0 (peor calidad, mayor compresión) a 95 (mejor calidad, menor compresión).
  • Anchura de la nueva imagen en pixels.
  • Altura de la nueva imagen en pixels.

A propósito de la calidad de las imágenes, debemos tener en cuenta que si la calidad de la imagen original era de por ejemplo el 75% y si especificamos que la calidad de la imagen redimensionada sea del 85%, la calidad de esta no mejorara, se mantendrá igual y solo conseguiremos incrementar el tamaño en bytes de la imagen. Por lo tanto, antes de aplicar esta función a una imagen debemos conocer su calidad actual.

Siguiendo con el mismo tema, los valores de calidad o compresión que se le puede aplicar a una imagen JPEG van del 0% al 95%. Lo lógico sería que fueran del 0% al 100%, pero por algún extraño motivo, la imagen resultante de una compresión del 97% es idéntica a la imagen comprimida al 95%.

A continuación puedes ver la función redimensionar_jpeg() y su aplicación:

&lt;?php
function redimensionar_jpeg($img_original, $img_nueva, $img_nueva_anchura, $img_nueva_altura, $img_nueva_calidad) {

// crear imagen desde original
$img = ImageCreateFromJPEG($img_original);

// crear imagen nueva
$thumb = ImageCreate($img_nueva_anchura,$img_nueva_altura);

// redimensionar imagen original copiandola en la imagen
ImageCopyResized($thumb,$img,0,0,0,0,$img_nueva_anchura,$img_nueva_altura,ImageSX($img),ImageSY($img));

// guardar la imagen redimensionada donde indicia $img_nueva
ImageJPEG($thumb,$img_nueva,$img_nueva_calidad);
}

redimensionar_jpeg('/home/yo/foto.jpg','/home/yo/mini_foto.jpg',100,100,75);
?&gt;

Ahora no tienes más que aplicar la función a cada una de las imágenes que desees redimensionar. También existe la posibilidad de ampliar la funcionalidad del script y hacer que este redimensione todas las imágenes de un directorio concreto. Por ejemplo, ejecutar el siguiente script en un directorio redimensionaría todas las imágenes de tipo JPEG del mismo:

&lt;?php
function redimensionar_jpeg($img_original,$img_nueva,$img_nueva_anchura,$img_nueva_altura,$img_nueva_calidad) {

// crear imagen desde original
$img = ImageCreateFromJPEG($img_original);

// crear imagen nueva
$thumb = ImageCreate($img_nueva_anchura,$img_nueva_altura);

// redimensionar imagen original copiandola en la imagen
ImageCopyResized($thumb,$img,0,0,0,0,$img_nueva_anchura,$img_nueva_altura,ImageSX($img),ImageSY($img));

// guardar la imagen redimensionada donde indicia $img_nueva
ImageJPEG($thumb,$img_nueva,$img_nueva_calidad);
}

$dir = opendir('.');

while(false !== ($file = readdir($dir))) {
if (!is_dir($file) && $file != '.' && $file != '..' && exif_imagetype($file)==2) {

// aplicar funcion
redimensionar_jpeg($file,'mini_'.$file,100,100,75).'&lt;br&gt;';
}
}
closedir($dir);
?&gt;

El trozo de código añadido al script simplemente recorre todos los archivos del directorio en busca de imágenes de tipo JPEG y cada vez que encuentra uno, le aplica la función redimensionar_jpeg().