PHP: WHICH en PHP para Windows

Which es un comando muy útil en linux que permite determinar la ruta absoluta de un ejecutable que está en el path. Además si el ejecutable a lanzar está en diversas carpetas del path, mostrará cual de todos esos ejecutables tiene prioridad y por tanto el que sería ejecutado.

Para poderlo utilizar desde la consola, basta con crear el archivo which.bat con el siguiente contenido y situarlo en la carpeta donde se halle el intérprete de PHP además de haber añadido dicha carpeta a la variable de entorno PATH.

which.bat  
@"%~dp0\php.exe" -r"$cmd_to_check = $argv[1]; $exts = array('exe', 'bat', 'cmd'); foreach (explode(';', getenv('PATH')) as $path) { foreach ($exts as $ext) { $file = $path . '\\' . $cmd_to_check . '.' . $ext; if (is_file($file)) { echo $file; exit; } } } echo $test . ' not found';" %*

Código expandido:

<?php  
$cmd_to_check = $argv[1];  
$exts = array('exe', 'bat', 'cmd');  
foreach (explode(';', getenv('PATH')) as $path) {  
    foreach ($exts as $ext) {  
        $file = $path . '\\' . $cmd_to_check . '.' . $ext;  
        if (is_file($file)) {  
            echo $file;  
            exit;  
        }  
    }  
}  

Ejemplo de uso:

C:\>which php
c:\php\php.exe

Leer más...

PHP : Simular contextos anidados

Viendo el código generado de Twig se me ocurrieron varias cosas para mejorar el rendimiento. En primer lugar hay una serie de funciones que se llaman muchísimo y que se podrían implementar como extensión nativa aumentando sustancialmente el rendimiento sin hacer nada.

Luego hay otra cosa que son los contextos. En Twig los contextos se simulan con un array y array_merge. Los cambios de contexto son muy costosos por este motivo y se hace demasiado amenudo. El tiempo perdido con dos bucles anidados es excesivo. Yo personalmente replantearía ciertas cosas a nivel de rendimiento en Twig.

Esta tarde tenía un rato y he hecho una clase que permitiría simular contextos anidados sin necesidad de merges implementando la interfaz ArrayAccess.

Nuevamente como el código es fácil que salga mal lo subo a pastebin: http://pastebin.com/xzRj4hR8</div>

<?php  

error_reporting(E_ALL | E_STRICT);  

class Context implements ArrayAccess {  
    /**  
     * @var Context  
     */  
    protected $parent;  

    /**  
     * @var ArrayObject  
     */  
    protected $current;  

    public function __construct($items = array(), Context $parent = NULL) {  
        $this->current = new ArrayObject((array)$items);  
        $this->parent = $parent;  
    }  

    protected function &getRef($index) {  
        $ref = &$this->current[$index];  
        if (!isset($ref) && ($this->parent !== NULL)) {  
            $ref = &$this->parent->getRef($index);  
        }  
        return $ref;  
    }  

    public function offsetExists($index) {  
        $ref = &$this->getRef($index);  
        return isset($ref);  
    }  

    public function &offsetGet($index) {  
        return $this->getRef($index);  
    }  

    public function offsetSet($index, $newval) {  
        $ref = &$this->getRef($index);  
        $ref = $newval;  
    }  

    public function offsetUnset($index) {  
        $ref = &$this->getRef($index);  
        unset($ref);  
    }  

    public function enter($items = array()) {  
        return new static($items, $this);  
    }  

    public function leave() {  
        return $this->parent;  
    }  
}  

$context = new Context(array('a' => -10, 'b' => -20, 'c' => -30));  
$context = $context->enter(array('a' => 10, 'b' => 20));  
printf("%d\n", ++$context['a']);  
printf("%d\n", ++$context['c']);  

$context = $context->leave();  
printf("%d\n", ++$context['a']);  
printf("%d\n", ++$context['c']);  

$context['c'] = 6;  

printf("%d\n", $context['c']);

Leer más...

PHP: Acceder y manipular programáticamente a elementos en arrays multidimensionales

Desde que uso MongoDB frente a MySQL me han ido surgiendo nuevos problemas a los que no me había enfrentado de forma común. Poder acceder a documentos que pueden tener una profundidad variable y tener que acceder a una serie de valores podía llegar a hacer que tuviese que montar mucho código para ciertas operaciones. Así que me creé un par de funcioncillas la mar de útiles.

El código mostrado aquí (que es fácil que salga mal) se puede acceder desde pastebin en la siguiente dirección: http://pastebin.com/sUQU8N8j

Nótese que la notación con ‘.’ es para simplificarlo todo sustancialmente pero puede introducir riesgos de acabar con una estructura no deseada si las claves no son estáticas (con valores especialmente introducidos por el usuario). Si se hace uso de whitelisting a la hora de aceptar parámetros del usuario, no debería haber problema.
Se puede hacer fácilmente una variante que en vez de tener como entrada una cadena, tenga un array que especifique las claves a acceder, evitando acceso indebido a más profunidad de la deseada.

Funciones:

function & access_value_dot($key, &$array) {  
    if (is_array($key)) {  
        $values = array();  
        foreach ($key as $single_key) $values[] = access_value_dot($single_key, $array);  
        return $values;  
    }  
    if (empty($key)) return $array;  
    $slices = explode('.', $key);  
    foreach ($slices as $slice) $array = &$array[$slice];  
    return $array;  
}  

function access_value_dot_set($key, &$array, $value) {  
    if (is_array($key)) {  
        $values = array();  
        $value = array_values($value);  
        foreach (array_values($key) as $k => $single_key) {  
            access_value_dot_set($single_key, $array, $value[$k]);  
        }  
        return;  
    }  
    $ref = &access_value_dot($key, $array);  
    $ref = $value;  
}  

Ejemplos:

public function testAccessValueDot() {  
    $data = array(  
        'level1' => array(  
            'level2b' => array(  
                'level3' => array(  
                    'level4a' => 1,  
                    'level4b' => 'Hello World',  
                ),  
            ),  
            'key' => 2,  
        ),  
        'level1a' => array(),  
    );  
    $this->assertEquals(access_value_dot('level1.level2b.level3.level4b', $data), 'Hello World');  
    $this->assertEquals(access_value_dot(  
        array(  
            'level1.level2b.level3.level4a',  
            'level1.level2b.level3.level4b',  
            'level1.key',  
            'level1a',  
            'level1.level2b.level3',  
        ), $data), array(  
            '1',  
            'Hello World',  
            '2',  
            array(),  
            array(  
            'level4a' => 1,  
            'level4b' => 'Hello World',  
        )  
    ));  
}  

public function testAccessValueDotSet() {  
    $object = (object)array(  
        'bbcode' => array(  
            'title' => 'Hello [b]World[/b]',  
            'descriptions' => array(  
                'short' => 'This is the [b]short[/b] description.',  
                'long' => 'This is the [b]LONG[/b] description.',  
            ),  
        ),  
        'html' => array(  
        ),  
    );  

    $field_keys = array(  
        'title',  
        'descriptions.short',  
        'descriptions.long',  
    );  

    // Accessing bbcode values.  
    $extracted_values = access_value_dot($field_keys, $object->bbcode);  

    {  
        // Converting bbcode to html.  
        $modified_values = array_map(function($value) {  
            return preg_replace_callback('@\\[(\\w+)\\](.*)\\[/\\1\\]@Umsi', function($captures) {  
                list(, $bbcode, $text) = $captures;  
                switch ($bbcode) {  
                    case 'b': return '<strong>' . $text . '</strong>';  
                    default: throw(new Exception("Unknown bbcode '{$bbcode}'"));  
                }  
            }, htmlspecialchars($value));  
        }, $extracted_values);  
    }  

    // Writting bbcode values.  
    access_value_dot_set($field_keys, $object->html, $modified_values);  

    $this->assertEquals(  
        $object->html,  
        array(  
            'title' => 'Hello <strong>World</strong>',  
            'descriptions' => array(  
                'short' => 'This is the <strong>short</strong> description.',  
                'long' => 'This is the <strong>LONG</strong> description.',  
            ),  
        )  
    );  
}  

Leer más...

PHP: Acceder a un puerto remoto protegido con PHP a través de un túnel SSH

Acceder a un puerto local de un servidor con PHP a través de un túnel SHH de forma sencilla.

Tenemos una máquina con acceso por SSH que está escuchando en un puerto con una dirección IP a la que no tenemos acceso de forma externa, bien por estar bindeado a 127.0.0.1, a una IP de una red local o bien por limitaciones de firewall y queremos acceder a ese puerto a través de un túnel SSH de manera remota como si accediésemos desde localhost.
Las extensiones SSH2 de PHP permiten hacer esto de una forma extremadamente sencilla utilizando el wrapper SSH2.TUNNEL de PHP.

Leer más...

C# Utils

Análogamente a mis otros dos proyectos de utilidades generales para D y para PHP que voy actualizando poco a poco:
http://code.google.com/p/phplutils/
http://code.google.com/p/dutils/

He creado otra librería con utilidades para C#:
http://code.google.com/p/csharputils/

Hay algunas cosas interesantes que voy a ir metiendo (algunas ya las he metido) que iré explicando por aquí.

Leer más...

Suscribirse via RSS