20/10/09

Macro operaciones con las funciones array_*

Quitar todos los espacios de principio y de final de cada elemento en un array (array_map):

$array_trimmed = array_map('trim', $array);
Alternativas:
$array_trimmed = array(); foreach ($array as $v) $array_trimmed[] = trim($v);
foreach ($array_trimmed as &$v) $v = trim($v); // Mala idea. PHP tiene leaks desde hace mucho tiempo con foreach + &.

Obtener una lista segura de enteros (por ejemplo IDs) para insertar en una query dentro de un IN().
$array_str_list = implode(',', array_map('intval', $array));

Filtrar un array obteniendo únicamente valores numéricos (array_filter):
$array_numbers = array_filter($array, 'is_numeric')

Para creación de valores para un insert con pdo (array_map):

$query_insert_values = implode(",", array_map(array($pdo, 'quote'), $values))

Para creación de asignaciones en un update con pdo (array_map con dos arrays):
$query_set = implode(',', array_map(function($k, $v) use ($pdo) {
return '`' . implode('`,`', explode('.', $k)) . '`=' . $pdo->quote($v);
}, array_keys($array), array_values($array)));

Obtener una lista de elementos únicos usando un array que contiene un número indeterminado de arrays (array_reduce):

$array_unique = array_unique( array_reduce( $arrays, 'array_merge', array() ) );

19/7/09

Crear "estructuras" en php5.3

En alguna ocasión me ha interesado crear una clase que contendría simplemente unos cuantos atributos y poco más y al final he acabado haciendo un constructor del tipo:

class mystruct {
    public $a, $b, $c;
    function __construct($a, $b, $c) {
        $this->a = $a;
        $this->b = $b;
        $this->c = $c;
    }
}


class struct {
    static public function create() {
        $obj = new static;
        $keys = array_keys((array)$obj);
        foreach (func_get_args() as $k => $v) $obj->{$keys[$k]} = $v;
        return $obj;
    }
}

Para versiones anteriores de php podemos usar el constructor:

class struct {
    static function __construct() {
        $keys = array_keys((array)$obj);
        foreach (func_get_args() as $k => $v) $this->{$keys[$k]} = $v;
        return $this;
    }
}


Con lo que podríamos hacer lo siguiente:


class mystruct extends struct { public $a, $b, $c; }
mystruct::create(1, 2, 3);
o
new mystruct(1, 2, 3);

17/7/09

Novedades con phpSTE

Ahora que vuelvo a tener Internet en plan bien, y ya vuelvo a estar con mis proyectos, he seguido mejorando phpSTE.

He cambiado bastantes cosas desde que lo empecé, y cambiaré bastantes más posiblemente hasta que esté pulido del todo.

Por ahora ocupa unas 550 líneas y ya es bastante funcional.

Además de soportar herencia, he añadido los siguientes tags:

{extends name=""} - extiende un template.
{include name=""} - incluye un template.
{block name=""}{/block} - define e imprime/modifica un bloque.
{addblock name=""}{/addblock} - modifica un bloque añadiendo el contenido al final.

{blockdef name=""}{/blockdef} - define un bloque sin utilizarlo.
{putblock name=""} - imprime un bloque existente.

{t}{/t} - llama a la función de gettext

{if cond=""}{/if}
{elseif cond=""}{else}

{for var="" from="" to="" step=""}{/for}

{foreach list="" var=""}{/foreach}



He hecho optimizaciones para que los tags puedan saber si el contenido es un literal, de forma que {t}Texto{/t} se convertiría a mientras que {t}{if cond=1}Texto{/if}{/t} se convertiría a Texto

6/7/09

phpSTE

phpSTE (PHP Simple Template Engine) es un sistema de templates que he empezado a hacer hoy.
Se caracteriza por ser liviano, rápido y sencillo. Actualmente no es 100% funcional, ni lo he testeado lo suficiente, pero ya empieza a hacer cosas.
Además, soporta herencia de templates.
Está programado para PHP5.3 o superior. Hace uso de namespaces, late static binding y alguna otra cosa de esta versión.
http://code.google.com/p/phpste/
La idea es que el engine terminado no supere las 1000 líneas de código comentado y que esté todo en un único archivo para facilitar al máximo su inclusión en otros proyectos.

5/6/09

Calculando el número de apariciones de un color en una imagen paletizada usando GD.

$i = imagecreate(1000, 1000);
$c1 = imagecolorallocate($i, 0x00, 0x00, 0x00);
 $c2 = imagecolorallocate($i, 0xFF, 0xFF, 0xFF);
 
 imagefill($i, 0, 0, $c2);
 
 for ($n = 0; $n < 100; $n++) imagesetpixel($i, $n, $n, $c1);

 printf("Method1 (iterating using php) {\n");
 {
  $t0 = microtime(true);
  ob_start(); imagegd($i); $data = substr(ob_get_clean(), 0x40D);
  printf("  Output image: %.4f seconds\n", microtime(true) - $t0);

  $t0 = microtime(true);
  $count = array();
  list($w, $h) = array(imageSX($i), imageSY($i));
  for ($y = 0; $y < $h; $y++) {
   for ($x = 0; $x < $w; $x++) {
    @$count[imagecolorat($i, $x, $y)]++;
   }
  }
  $count = count_chars($data, 1);
  arsort($count);
  printf("  Counting: %.4f seconds\n", microtime(true) - $t0);
  print_r($count);
 }
 printf("}\n");
 
 printf("Method2 (hack) {\n");
 {
  $t0 = microtime(true);
  ob_start(); imagegd($i); $data = substr(ob_get_clean(), 0x40D);
  printf("  Output image: %.4f seconds\n", microtime(true) - $t0);

  $t0 = microtime(true);
  $count = count_chars($data, 1);
  arsort($count);
  printf("  Counting: %.4f seconds\n", microtime(true) - $t0);
  print_r($count);
 }
 printf("}\n");

20/5/09

El último día de un mes en php5

Mes anterior:
date_create(date('Ym01'))->modify('-1 day')

Este mes:
date_create(date('Ym01'))->modify('+1 month -1 day')

Un mes concreto mediante timestamp:
date_create(date('Ym01', $timestamp))->modify('+1 month -1 day')

5/5/09

Ejemplo de RPG 2D en phpmedia

Aprovechando que hacía tiempo hice una prueba de minirpg en javascript, y luego un port en flash online y con chat (cliente+servidor en D) y que ya tenía los gráficos y las animaciones, he portado eso mismo a php usando phpmedia.
Los gráficos son de Tales of Eternia (juego que traducimos al español hace unos años). Con un filtro 2xsai o 2xeagle si no recuerdo mal. Los personajes que se usan en la demo son Reid y Farah. Mientras que el escenario (que todavía no está puesto ya que es solo una demo de colisiones), es el Dojo de Regulus.

25/4/09

Y llegaron los shaders...



Ya se puede usar GLSL en phpmedia:

Ejemplo: http://phpelegante.googlepages.com/phpmedia_test_glsl.7z


error_reporting(E_ALL | E_STRICT);

Screen::title('Shader test');
$screen = Screen::init(800, 600);
$key = 'Keyboard';

$shader = new Shader("
uniform sampler2D image, mask;
uniform float step;

void main (void) {

gl_FragColor.rgb = texture2D(image, vec2(gl_TexCoord[0])).rgb;

gl_FragColor.a = texture2D(mask , vec2(gl_TexCoord[1])).r + step;

}

");

$mask = Bitmap::fromFile('mask.png');
$image = Bitmap::fromFile('file.jpg');
$arrows = Bitmap::fromFile('arrows.png');

$v = -1.0;

$timer = 0;

while (!$key::pressed($key::ESC)) {
if ($key::down($key::LEFT)) $v -= 0.03;
if ($key::down($key::RIGHT)) $v += 0.03;

Math::clamp($v, -1.0, 1.0);

$screen->blit($image, 0, 0, 1, 0, 1,
$shader, array('mask' => $mask, 'step' => $v));
$screen->blit($arrows, 16, 16, 1, 0, 0.6 + abs(cos($timer / 64)) * 0.8);

$timer++;
Screen::frame();
}

21/4/09

Ejemplo de nave

He hecho un pequeño ejemplo en phpmedia 2:

http://code.google.com/p/phpmedia/wiki/SampleNave

20/4/09

phpMedia 2.0




Hace unos 5 años, hice una extensión para php que permitía hacer aplicaciones multimedia 2D. Por aquel entonces usaba PHP4 y Allegro. Todo el tema gráfico se hacía por software y no permitía conseguir un buen rendimiento. El API no era orientado a objetos y PHP4  estaba mucho más limitado que en la actualidad. El proyecto se alojaba en sourceforge aquí.

Hace un par de semanas, decidí que estaría bien revivir aquello, pero hacerlo mucho mejor: con una interfaz orientada a objetos para PHP5.3 y usando OpenGL con aceleración completa por hardware.

Establecí un proyecto en googlecode. Y me puse a idear el API que tendría. El objetivo es conseguir un API sencillo y útil. Que no sea totalmente versatil, pero que deje hacer bastantes cosas.
Hice un prototipo de interfaz en PHP, y un generador de documentación para googlecode.
Aunque no hice nada, ya tenía mas o menos pensada parte del API.
Esta tarde/noche, me he puesto con ello. Con unos resultados muy prometedores. He tenido muy pocos problemas y ha ido todo como esperaba o incluso mejor.

Como resultado he sacado una primera versión usable, para PHP5.3. En la página del proyecto está.

Lo que he hecho:
  • Soporte básico de teclado. Las teclas principales. Detectar pulsaciones o detectar si está pulsada o levantada la tecla.
  • Inicialización gráfica (ventana o pantalla completa)
  • Clase Bitmap (bastante avanzada). Permite crear nuevos bitmaps, cargar desde archivos o desde cadenas. Permite hacer recortes, clonar réplicas.
Lo que falta:
  • Mejorar el soporte de teclado.
  • Soporte para ratón.
  • Soporte para gamepad.
  • Todo el tema del audio.
  • Shaders.

Ejemplo de prueba + archivos necesarios:

      Para probar el ejemplo, bajar todos los archivos. Y ejecutar el archivo test.bat. Teclas del cursor para desplazar la imagen. W/S para acercar/alejar la imagen. A/D para rotar la imagen. ESC para salir del ejemplo.

      Página del proyecto: http://code.google.com/p/phpmedia/