Blog

  • Cómo definir la configuración de la sesión en Symfony

    Cómo definir la configuración de la sesión en Symfony

     

    Ante todo, una aclaración:

    PHP maneja las sesiones a través de cookies (Antiguamente también se podía propagar el ID de sesión vía URL, aunque es una práctica muy poco segura y, sinceramente, hace mucho que no lo veo).

    Bien, ahora… ¿qué cosas podrías querer cambiar de la configuración de la sesión? Varias.

    1. El nombre de la cookie
    2. El tiempo de duración
    3. El lugar donde se almacena la información del lado del servidor

    Sobre la segunda y la tercera, acá tenés un ejemplo de por qué querrías hacerlo 🙂

    Respecto de la primera, más que nada se trata de un tema de seguridad. Fijate esta captura de pantalla de la consola del navegador:

    El nombre PHPSESSID es el nombre por defecto que se le asigna a la cookie de sesión de una aplicación hecha en PHP, eso significa que, si te encontrás con una cookie con este nombre es altamente probable (Por no decir seguro) que del otro lado se encuentre una aplicación desarrollada en PHP.

    Ese tipo de información es super útil para un atacante, ya que al conocer qué software está corriendo el servidor se le facilita enormemente la tarea de buscar una forma de explotarlo…

    Bien, ahora que te convencí de que es una buena idea cambiar el nombre de la cookie, te voy a mostrar cómo hacerlo en Symfony:

    Es muy simple, se trata de agregar un par de líneas al archivo config.yml:

    framework:
        session:
            # http://symfony.com/doc/current/reference/configuration/framework.html#handler-id
            handler_id:  session.handler.native_file
            save_path:   "%kernel.root_dir%/../var/sessions/%kernel.environment%"
            cookie_lifetime: 28800
            name: MIAPPSID

    Se puede configurar todos los parámetros de la sesión mediante este mecanismo y después, por ejemplo, se puede modificar algunos valores para el entorno de desarrollo definiendo un archivo config_dev.yml con algo como:

    imports:
        - { resource: config.yml }
    
    framework:
        session:
            save_path:   "/var/lib/php/sessions"

    Listo. Ahora tu aplicación es un poco menos vulnerable que antes :).

    P.D.: Si querés incorporar un framework maduro como Symfony a tu herramental, el curso Desarrollo de Aplicaciones Web Profesionales con PHP te puede interesar.

  • Cómo enviar mails con formato usando SwiftMailer

    Cómo enviar mails con formato usando SwiftMailer

    Ya he comentado en otros artículos sobre las diferentes posibilidades para enviar emails usando PHP. De todas las que he probado hasta el momento, SwiftMailer es la que me resulta más cómoda y conveniente, sin embargo, he tenido algunas peleas a la hora de enviar mails con formato (es decir, mails que contengan HTML que necesito que sea entendido como tal y no como mero texto).

    La verdad es que es bastante simple lograrlo, sólo hay que conocer el método adecuado 🙂

    En general, lo que uno hace cuando quiere enviar un email es algo como esto:

    $message = (new Swift_Message())
      ->setSubject('Este es el asunto')
      ->setFrom(['mauro.chojrin@leewayweb.com' => 'Mauro Chojrin'])
      ->setTo(['destinatario@dominio.com' => 'Gran Amigo'])
      ->setBody('Este es el importante mensaje que quiero enviarte!!')
      ;

    El problema (si puede llamársele así) es que nos hemos olvidado que el mail acompaña a Internet desde sus inicios, con lo cual, el modo default de envío de correos es texto plano (Aunque muy poca gente lo utilice así hoy en día).

    Para enviar correos utilizando HTML se debe agregar una parte al correo que así lo especifique. Es decir, en lugar de usar setBody debemos usar addPart:

    $message = (new Swift_Message())
      ->setSubject('Este es el asunto')  ->addPart('<p>Este es el <strong>importante</strong> mensaje que quiero enviarte!!</p>')
      ->setFrom(['mauro.chojrin@leewayweb.com' => 'Mauro Chojrin'])
      ->setTo(['destinatario@dominio.com' => 'Gran Amigo'])
      ->addPart('<p>Este es el <strong>importante</strong> mensaje que quiero enviarte!!</p>')
      ;

    Si queremos ser muy puritanos, deberíamos incluir ambas versiones (La HTML y la de texto plano) para no perder a aquellas personas que no tienen habilitado el HTML en su cliente de correo (Aunque sinceramente, es muy raro que así sea y si queremos lograr un buen efecto visual, nada como el HTML, CSS y demás).

  • Cómo definir relaciones Cero-a-Uno con Doctrine

    Cómo definir relaciones Cero-a-Uno con Doctrine

    En general cuando uno comienza a estudiar Bases de Datos Relacionales se habla de un tipo de relación Uno-a-Uno que, en la práctica se usa muy poco. Sin embargo las relaciones tipo Cero-a-Uno tienen muchísimo sentido.

    Es el caso de que se quiera modelar un sistema donde una entidad es un caso especial de otra (Algo similar al concepto de herencia de POO), como por ejemplo la relación entre personas y actores:

    • Todos los actores son personas
    • No todas las personas son actores

    La forma de implementar esto en una base de datos relacional es poner un campo tipo clave foránea en la tabla hija, el cual a su vez tendrá un índice único (Para reforzar la cardinalidad de la relación).

    En el caso del ORM Doctrine, todo esto parte de la definición de la clase Entity.

    Pongo un ejemplo de un proyecto en el que trabajé: hay una clase User (De FOSUserBundle) y una clase Taller. Cada taller tiene un responsable, pero no todos los usuarios son responsables de algún taller.

    En la clase User está este código

    /**
     * @var Taller
     * @ORM\OneToOne(targetEntity="AppBundle\Entity\Taller",mappedBy="responsable")
     */
    protected $taller;

    Y en la clase Taller este:

    /**
     * @var User
     * @ORM\OneToOne(targetEntity="AppBundle\Entity\User", inversedBy="taller")
     */
     private $responsable;

    Como podés observar, ambas clases tienen una referencia a la otra, pero en la base de datos, sólo la tabla Taller tiene una referencia a User.

    Esto se debe a cómo están escritas las definiciones del vínculo OneToOne.

    Más específicamente, se debe a qué clase tiene el mappedBy y el inversedBy: El lado 1 de la relación (es decir, la entidad que siempre existirá) es el que debe llevar inversedBy.

    Si bien este tipo de relaciones no son lo más común, ciertamente viene bien conocerlas y la posibilidad de definirlas usando las herramientas de Doctrine ayuda mucho.

    ¿Alguna duda? ¡Dejala en un comentario!

  • Cómo usar el intérprete de PHP de una VM desde PhpStorm

    Cómo usar el intérprete de PHP de una VM desde PhpStorm

    Una práctica muy buena a la hora de programar (y ahorrarse dolores de cabeza) es el uso de máquinas virtuales.

    Muchos desarrolladores usan este esquema, sin embargo, también es bastante común que tengan sus propias versiones del software usado para ejecutar sus aplicaciones instalado en su máquina física (por ejemplo PHP).

    Si estás trabajando en varios proyectos a la vez, los cuales están deployados en servidores diversos, es muy probable que en cada VM tengas instalada una versión diferente de PHP (La misma que tenés en el servidor de producción), con lo cual, al menos una VM debe tener instalada una versión diferente de PHP que la que tenés instalada en tu máquina.

    Como usás una VM no deberías tener mayores dificultades a la hora de deployar, pero a la hora de desarrollar, también sería bueno que tu IDE estuviese ejecutando la misma versión de PHP que va a dar vida a tu código…

    Una característica muy interesante de mi IDE preferido (PhpStorm) es la posibilidad de analizar el código (mientras lo escribo) usando el intérprete de PHP que está en la VM (y no el que tiene el propio IDE o el que tengo instalado en mi computadora).

    Para configurarlo tenés que ir a la pantalla de settings:

    Y configurar el intérprete de línea de comandos (CLI Interpreter):

    Por defecto vas a ver a la izquierda los intérpretes que tengas instalados en tu computadora, pero podés agregar uno:

    Que puede ser accedido remotamente (Por ejemplo a través de Vagrant).

    Obviamente, para que esto funcione la VM de la que querés sacar el intérprete tiene que estar encendida…

    Y listo, con esto te asegurás de tener un IDE que entienda exactamente la versión de PHP que vas a usar en tu entorno de desarrollo y en producción.

    Si querés ver más detalles podés consultar acá.

  • Cómo hacer debug en php

    Cómo hacer debug en php

    Una de las tareas que más tiempo consume durante el desarrollo de una aplicación (web o no) es el debugging. Ese momento en que estás seguro de que todo anda bien, pero por las dudas… hay que probarlo.

    Y, como siempre, algo no sale exactamente como esperabas.

    Es entonces cuando te toca arremangarte, buscar una nueva taza de café, silenciar el teléfono y hurgar.

    El modo «común» de encarar esta tarea en el universo php es usar mucho la función var_dump (o sus parientes cercanos: print_r, echo, etc…).

    La verdad es que, si bien eso puede funcionar, está bastante lejos de ser óptimo.

    Herramientas de debugging PHP

    Una herramienta que vengo usando hace bastante y que ha sido el día y la noche en mi trabajo es xdebug.

    Se trata de un complemento para php que permite, entre otras cosas:

    • Ejecutar el código paso por paso
    • Evaluar el contenido de las variables en tiempo real
    • Establecer puntos de corte

    Históricamente instalarlo (y dejarlo funcionando!) era una tarea sólo apta para valientes… hoy en día, por suerte, las cosas son mucho más simples.

    Para usarlo de una forma cómoda y práctica necesitarás a su vez un IDE.

    En este caso, te mostraré cómo se hace con PhpStorm pero realmente es muy similar en otros.

    Cómo configurar PHPStorm para usar XDebug

    Desde dentro del IDE podés lanzar tu aplicación usando el botón de play (El triángulo verde):

    Lo que ves a la izquierda (En este caso app.php) es el nombre de la configuración de ejecución (Un concepto propio de PhpStorm que define un poco qué es lo que esperás que haga el IDE cuando hagas click en el botón).

    Lo primero que tenés que conocer entonces es este cuadro de diálogo (Al que accedés al editar la configuración de debugging):

    A la izquierda tenés todas las posibles configuraciones base (Debuggear una aplicación web, un script de CLI, etc…).

    A la derecha los detalles particulares. Lo más importante es configurar correctamente el servidor:

    Dentro de este cuadro tenés que mirar especialmente los campos:

    • Host: El servidor donde está desplegada tu aplicación (Si usás Xampp o algo así será localhost, si no puede ser la IP de la computadora donde esté tu código, dependerá de tu entorno particular el valor que debés ingresar).
    • Port: El puerto donde está escuchando el servidor web al que te vas a conectar (Por lo general será el 80)
    • Debugger: Qué software de debugging usarás (Los estándares son XDebug y Zend Debugger, si no usás ZendFramework te recomiendo usar el primero).

    Qué son los path mappings

    Por último, muy importante es configurar correctamente los mapeos de directorios. Este concepto puede solar un poco extraño al principio, pero es bastante claro: se trata de indicar dónde está, en el sistema de archivos local, el código que se está ejecutando en el servidor.

    Para entenderlo un poco mejor: el código que estás viendo en tu IDE está guardado en tu disco local (salvo que estés editando directamente sobre el servidor, algo que, salvo que uses una máquina virtual sería muy mala idea).

    El código que se ejecuta está en el webserver que tiene instalado el debugger.

    Por eso, para poder ir corriendo paso-a-paso el IDE necesita conocer qué archivo debe mostrar en base a la comunicación con el debugger.

    De eso precisamente es se tratan estos mapeos.

    Una vez terminada esta configuración basta volver a la barra de arriba

    Pero esta vez hacer click en el botón del «bichito» (Bug) y, si todo sale bien, verás una pantalla como esta en la parte de abajo de tu IDE:

    Y ahora se trata sólo de colocar breakpoints en algunos lugares estratégicos del código (Simplemente haciendo click a la izquieda de la línea seleccionada):

     Y recargar la página para que, cuando llegue a este lugar de la ejecución se vea algo como:

    En la parte del código la línea azul marca el código que está a punto de ejecutarse, pero la parte más interesante es la de abajo a la derecha, donde podés ver el contenido de las variables en tiempo real.

    De esta forma podés debuggear tu código sin temer dejar olvidado algún var_dump por ahí.

    ¿Te gustaría ver una sesión de debugging en vivo? Acá hay algo que puede interesarte.

  • Cómo funciona el conversor de parámetros de Symfony

    Cómo funciona el conversor de parámetros de Symfony

    Cada vez que conozco más del framework Symfony, más me gusta :).

    Esto que te voy a mostrar a continuación me pareció un acto de magia cuando me lo crucé por primera vez: el conversor de parámetros.

    En la mayoría de los Controllers (especialmente cuando se trata de CRUDs), se recibirá algún parámetro que será la clave para encontrar el objeto sobre el que se quiere realizar la operación, por ejemplo:

    public function showAction(Request $request)
    {
      $client = $this->getDoctrine()->getRepository('AppBundle:Client')->find($request->getParameter('id');
    
      if ( $client ) {
        ...
      } else {
        // 404
      }
    }

    Es muy común ver código de este tipo. De hecho, si lo miramos desde un poco lejos notaremos que hay una estructura en común en estas operaciones:

    1. Buscar el objeto
    2. Si se encontró, procesar normalmente
    3. Si no se encontró generar un error 404

    La idea del conversor de parámetros es simplificar este proceso recurriendo a un uso muy interesante de las annotations:

    /**
     * @Route("/client/{id}")
     * @ParamConverter("client", class="AppBundle:Client")
     */

    La magia se produce en la combinación de las annotations @Route y @ParamConverter.

    La primera define el patrón que debe seguir una URI para ser mapeada a esta acción, la segunda define cómo deben interpretarse los parámetros de modo de generar obejtos.

    En definitiva el código quedaría algo así como:

    /**
     * @Route("/client/{id}")
     * @ParamConverter("client", class="AppBundle:Client")
     */
    public function showAction(Client $client)
    {
        ...
    }

    Notá cómo se simplificó el método (Toda la parte de la búsqueda la realiza directamente el framework y el método sólo es llamado cuando efectivamente se obtuvo el objeto buscado).

    Pero además de ahorrar código (y dolores de cabeza varios), esta metodología tiene un efecto colateral más que interesante: hace mucho más simple el testing automatizado. ¿Por qué? Porque fuerza a armar métodos basados en al inyección de dependencias.

    Más allá del framework de testing que uses, podés imaginar que es muy simple hacer algo como:

    $controller = new ClientController();
    
    $controller->showAction( new Client() );

    Obviamente el new Client() puede ser reemplazado por un objeto creado a tu conveniencia, sin tener que entrar en enroscados tests con bases de datos espurias.

    Todo lo que leíste hasta acá es en realidad un caso particular de conversor de parámetros (El de Doctrine), pero existen más (¡Incluso podés definir los tuyos propios!).

    No es que vayas a pasarte el día inventando tus propios conversores de parámetros, pero es importante saber cómo funcionan las herramientas que uno usa para poder sacarles el máximo jugo posible.

    Si te interesa aprender más sobre este gran framework el curso Introducción a Symfony puede ayudarte.

  • Cómo logear errores con PHP

    Cómo logear errores con PHP

    Por más esfuerzo que pongas, los usuarios se las arreglan para encontrar errores antes que vos.

    No sólo eso, lo más probable es que, al reportar un error (o intentar hacerlo), no tengan mucho más para decir que

    «No hice nada y el sistema se colgó»

    Evidentemente, no es un panorama muy alentador como punto de partida para encontrar una solución, ¿cierto?

    Que bueno sería saber exactamente qué estaba pasando en el momento en que se produjo el error…

    Precisamente, es ahí donde tener un buen log de errores puede hacer la diferencia entre perder el fin de semana y ser el héroe del día.

    Veamos entonces algunas técnicas para contar con esa información cuando se la necesita (y sí… tarde o temprano la vas a necesitar).

    La primera opción es casi obvia: guardar los logs mediante tu propio mecanismo (mucho fopen, fwrite o similares, etc…).

    Podés hacer esto, y hasta puede funcionar bien, pero representa un esfuerzo importante y una gran propensión a generar más errores que los que previene.

    Por ejemplo, hay que tener en cuenta que, si la cantidad de usuarios concurrentes es alta (como se espera en un entorno web) habrá problemas de disponibilidad del archivo donde se almacenan los logs, con lo cual probablemente tengas que implementar tu propio sistema de semáforos o algo así… un poco demasiado para lo que estás queriendo lograr, ¿no?

    Ojo, PHP te provee una función bastante interesante: error_log, que ya maneja toda esa complejidad… no está mal, ¿cierto?

    Pero podés encontrarte con casos aún más complejos, como ser un sistema distribuido que requiere de logs centralizados.

    Un caso típico es cuando se trata de muchos servidores detrás de un balanceador de carga:

    En este caso, te interesará que si hay errores en cualquiera de los servidores se tomen como un único error de la aplicación, con lo cual, los archivos de logs individuales de cada servidor tendrán poca relevancia.

    Nuevamente, aquí podés optar (entre otras) por:

    • Guardar los logs en un archivo compartido entre los servidores (por ejemplo por NFS o similar)… poco recomendable (mala performance, mala seguridad, etc…)
    • Guardar los logs en una base de datos compartida
    • Enviar los errores directamente por email

    Y aquí es donde te conviene empezar a pensar en usar alguna librería que maneje todo esto… como por ejemplo Monolog.

    Monolog es precisamente eso: una librería hecha especialmente para manejar procesos de logging complejos. Permite entre otras cosas diferenciar almacenamiento de logs en función de la gravedad de los sucesos (que vos también podés definir).

    Como para empezar a probarla podés instalarla usando composer:

    composer require monolog/monolog

    Y luego, la podés empezar a usar en tu aplicación con algo como:

    <?php
    
    require_once 'vendor/autoload.php';
    
    use Monolog\Level;
    use Monolog\Logger;
    use Monolog\Handler\StreamHandler;
    
    $log = new Logger('mi-canal');
    $log->pushHandler(new StreamHandler(__DIR__.'/mi-app.log', Level::Warning));
    
    $log->warning('Este es un warning');
    $log->error('Este es un error');

    Después de ejecutar este código, abrí el archivo mi-app.log y te encontrarás con algo como:

    [2025-01-08T08:44:02.872376+00:00] mi-canal.WARNING: Este es un warning [] []
    [2025-01-08T08:44:02.873235+00:00] mi-canal.ERROR: Este es un error [] []

    Una característica interesante de este tipo de logs es que son fácilmente filtrables usando una herramienta como grep. Por ejemplo, para buscar sólo los errores podés usar un comando como cat mi-app.log | grep ERROR para obtener:

    [2025-01-08T08:44:02.873235+00:00] mi-canal.ERROR: Este es un error [] []

    Así que dale, instalá monolog, configuralo y empezá a generar logs poderosos en tus aplicaciones.

  • Qué es y para qué sirve PHP Mess Detector

    Qué es y para qué sirve PHP Mess Detector

    PHPMessDetector es una herramienta que ayuda a detectar código defectuoso en proyectos PHP (Muy útil a la hora de realizar auditorías de código ajeno).

    Se basa en el análisis automatizado del código utilizando conjuntos de reglas.

    Estas reglas buscan detectar código mal estructurado, mala nomenclatura, métodos exageradamente grandes, ciclos ineficientes y demás.

    Está preparado para emitir su salida en diferentes formatos (Texto, XML, HTML).

    Su uso es bastante simple, hay que instalarlo y luego corre como una utilidad de línea de comandos.

    Por ejemplo, corriendo el comando

    php phpmd.phar . text naming

    Sobre una base de código algo dudoso, obtuve un resultado como este:

    /home/mauro/sitio/authorize/authorizenet.php:11 Classes should not have a constructor method with the same name as the class/home/mauro/sitio/authorize/authorizenet.php:11 Classes should not have a constructor method with the same name as the class/home/mauro/sitio/authorize/authorizenet.php:42 Avoid variables with short names like $ch. Configured minimum length is 3./home/mauro/sitio/authorize/authorizenet.php:87 Avoid variables with short names like $j. Configured minimum length is 3.

    Otro análisis interesante es este:

    php phpmd.phar . text codesize

    Que me da este resultado (Entre otros):

    /home/mauro/sitio/phpminiadmin.php:157	The function display_select() has an NPath complexity of 26112. The configured NPath complexity threshold is 200.

    Si vemos lo que hay a partir de la línea 157:

    function display_select($sth,$q){
     global $dbh,$DB,$sqldr,$reccount,$is_sht,$xurl;
     $rc=array("o","e");
     $dbn=$DB['db'];
     $sqldr='';
    
     $is_shd=(preg_match('/^show\s+databases/i',$q));
     $is_sht=(preg_match('/^show\s+tables|^SHOW\s+TABLE\s+STATUS/',$q));
     $is_show_crt=(preg_match('/^show\s+create\s+table/i',$q));
    
     if ($sth===FALSE or $sth===TRUE) return;#check if $sth is not a mysql resource
    
     $reccount=mysql_num_rows($sth);
     $fields_num=mysql_num_fields($sth);
    
     $w='';
     if ($is_sht || $is_shd) {$w='wa';
       $url='?'.$xurl."&db=$dbn";
       $sqldr.="<div class='dot'>
    &nbsp;MySQL Server:
    &nbsp;&#183;<a href='$url&q=show+variables'>Show Configuration Variables</a>
    &nbsp;&#183;<a href='$url&q=show+status'>Show Statistics</a>
    &nbsp;&#183;<a href='$url&q=show+processlist'>Show Processlist</a>
    <br>";
       if ($is_sht) $sqldr.="&nbsp;Database:&nbsp;&#183;<a href='$url&q=show+table+status'>Show Table Status</a>";
       $sqldr.="</div>";
     }
     if ($is_sht){
       $abtn="&nbsp;<input type='submit' value='Export' onclick=\"sht('exp')\">
     <input type='submit' value='Drop' onclick=\"if(ays()){sht('drop')}else{return false}\">
     <input type='submit' value='Truncate' onclick=\"if(ays()){sht('trunc')}else{return false}\">
     <input type='submit' value='Optimize' onclick=\"sht('opt')\">
     <b>selected tables</b>";
       $sqldr.=$abtn."<input type='hidden' name='dosht' value=''>";
     }
    
     $sqldr.="<table class='res $w'>";
     $headers="<tr class='h'>";
     if ($is_sht) $headers.="<td><input type='checkbox' name='cball' value='' onclick='chkall(this)'></td>";
     for($i=0;$i<$fields_num;$i++){
        if ($is_sht && $i>0) break;
        $meta=mysql_fetch_field($sth,$i);
        $headers.="<th>".$meta->name."</th>";
     }
     if ($is_shd) $headers.="<th>show create database</th><th>show table status</th><th>show triggers</th>";
     if ($is_sht) $headers.="<th>engine</th><th>~rows</th><th>data size</th><th>index size</th><th>show create table</th><th>explain</th><th>indexes</th><th>export</th><th>drop</th><th>truncate</th><th>optimize</th><th>repair</th>";
     $headers.="</tr>\n";
     $sqldr.=$headers;
     $swapper=false;
     while($row=mysql_fetch_row($sth)){
       $sqldr.="<tr class='".$rc[$swp=!$swp]."' onmouseover='tmv(this)' onmouseout='tmo(this)' onclick='tc(this)'>";
       for($i=0;$i<$fields_num;$i++){
          $v=$row[$i];$more='';
          if ($is_sht && $v){
             if ($i>0) break;
             $vq='`'.$v.'`';
             $url='?'.$xurl."&db=$dbn";
             $v="<input type='checkbox' name='cb[]' value=\"$vq\"></td>"
             ."<td><a href=\"$url&q=select+*+from+$vq\">$v</a></td>"
             ."<td>".$row[1]."</td>"
             ."<td align='right'>".$row[4]."</td>"
             ."<td align='right'>".$row[6]."</td>"
             ."<td align='right'>".$row[8]."</td>"
             ."<td>&#183;<a href=\"$url&q=show+create+table+$vq\">sct</a></td>"
             ."<td>&#183;<a href=\"$url&q=explain+$vq\">exp</a></td>"
             ."<td>&#183;<a href=\"$url&q=show+index+from+$vq\">ind</a></td>"
             ."<td>&#183;<a href=\"$url&shex=1&t=$vq\">export</a></td>"
             ."<td>&#183;<a href=\"$url&q=drop+table+$vq\" onclick='return ays()'>dr</a></td>"
             ."<td>&#183;<a href=\"$url&q=truncate+table+$vq\" onclick='return ays()'>tr</a></td>"
             ."<td>&#183;<a href=\"$url&q=optimize+table+$vq\" onclick='return ays()'>opt</a></td>"
             ."<td>&#183;<a href=\"$url&q=repair+table+$vq\" onclick='return ays()'>rpr</a>";
          }elseif ($is_shd && $i==0 && $v){
             $url='?'.$xurl."&db=$v";
             $v="<a href=\"$url&q=SHOW+TABLE+STATUS\">$v</a></td>"
             ."<td><a href=\"$url&q=show+create+database+`$v`\">sct</a></td>"
             ."<td><a href=\"$url&q=show+table+status\">status</a></td>"
             ."<td><a href=\"$url&q=show+triggers\">trig</a></td>"
             ;
          }else{
           if (is_null($v)) $v="NULL";
           $v=htmlspecialchars($v);
          }
          if ($is_show_crt) $v="<pre>$v</pre>";
          $sqldr.="<td>$v".(!strlen($v)?"<br>":'')."</td>";
       }
       $sqldr.="</tr>\n";
     }
     $sqldr.="</table>\n".$abtn;
    
    }

    Podemos ver un código algo complicado… aún si no sabemos calcular el NPathComplexity :).

    Si bien las reglas que trae incorporada la herramienta suelen dar buenos indicios, no debe tomarse todo como verdad incuestionable.

    Particularmente, hay una regla que, al menos a mi, me genera cierta desconfianza: ElseExpression (Del conjunto CleanCode).

    Según su definición, una sentencia else nunca es necesaria y sólo hace al código más difícil de leer… probablemente tenga razón en la primera parte (De que no es 100% necesaria, ahora, si hace más difícil de leer el código… no me parece tan simple de afirmar).

    De cualquier forma, es interesante contar con una herramienta que pueda orientar nuestros esfuerzos rápidamente hacia las partes más controvertidas del código.

    Una característica muy interesante de PHPMD es que te permite definir tus propias reglas de análisis (Yo por ejemplo usaría una que detecte el uso de variables globales).

    Si bien es evidente que sólo con el análisis estático del código no es posible dar un diagnóstico completo, ciertamente ayuda contar con este tipo de herramientas.

    ¿Alguna vez te tocó analizar código de terceros? ¿Cómo te las arreglaste?

  • Cuál es el mejor IDE para PHP

    Cuál es el mejor IDE para PHP

    Si llevás algo de tiempo trabajando con PHP, te habrás dado cuenta de que ni notepad ni vim ni nada que se le parezca es suficientemente bueno como para que desarrollar aplicaciones sea una tarea amena.

    Para alcanzar un buen nivel de eficiencia se necesitan herramientas específicas que nos simplifiquen (un poco) la vida.

    En el caso de la programación, lo que más va a modificar tu día a día es el uso (o falta) de un Entorno Integrado de Desarrollo (IDE en Inglés).

    Existen muchas opciones cuando se trata de PHP, sin embargo, hay unos pocos que son los estándares de la industria. Veamos algunos:

    Eclipse para PHP

    En realidad no se trata de un producto específico, si no de un plugin para el ya conocido Eclipse (El IDE multiplataforma).

    Entre sus ventajas se cuentan el hecho de que está muy extendido su uso, hay muchos plugins y es (o era al menos) la opción de facto (Especialmente si trabajás con otros lenguajes como Java, seguramente alguna vez lo usaste).

    Ah, y es gratis :).

    Su principal desventaja es que consume muchísimos recursos y es sumamente lento y pesado.

    Mucho de esto se debe al hecho de que, al intentar ser una solución a muchos problemas, tiene muchas características que no son estrictamente necesarias…

    Lo podés descargar de acá.

    ZendStudio

    Escencialmente se trata de un Eclipse lookeado. Zend Technologies es una empresa que está muy metida en el desarrollo de PHP. Si ejecutás php -v en una terminal te vas a encontrar con algo como:

    PHP 7.2.4-1+ubuntu14.04.1+deb.sury.org+1 (cli) (built: Apr  5 2018 11:08:49) ( NTS )
    Copyright (c) 1997-2018 The PHP Group
    Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
        with Zend OPcache v7.2.0-1+ubuntu14.04.1+deb.sury.org+1, Copyright (c) 1999-2017, by Zend Technologies
        with Xdebug v2.6.0, Copyright (c) 2002-2018, by Derick Rethans

    Lo cual daría a pensar que sus productos son superiores a los de la competencia… sin embargo, en mi experiencia al menos, no ha sido así (De hecho, casi diría que lo contrario es cierto).

    Además de este IDE, existe el ZendFramework y un entorno de debug propio de Zend (Yo personalmente prefiero Symfony y XDebug).

    Detalle importante: no es gratis, pero tiene un trial que podés descargar de acá.

    NetBeans

    Esta opción desarrollada por Sun Microsystems (Ahora adquirida por Oracle) es realmente interesante. Tiene una base similar a la de Eclipse (Es un IDE pensado como un genérico al que se le puede instalar un plugin para usarlo con PHP), pero logra una performance altamente superior (Lo que le da una mucho mejor experiencia de usuario).

    Se integra muy bien con otras herramientas típicas del desarrollo con PHP (Controladores de versiones, Vagrant, etc…).

    Entre las opciones gratuitas es mi preferida (De hecho, era mi entorno favorito hasta que encontré PhpStorm), la podés descargar de acá.

    PhpStorm

    Abran paso que llegó el rey: PhpStorm.

    Este IDE es por lejos lo mejor que yo he probado. Tiene una cantidad enorme de características y montones de opciones de customización.

    Es MUY rápido y, al ser tan específico de PHP, no le sobra nada 🙂 y me arriesgaría a decir que tiene cosas que los otros no.

    Integra muy bien con cualquier framework conocido y permite, si se configura bien, no salir del IDE para ninguna tarea de desarrollo (Se puede correr UnitTests, manejar dependencias con composer, hacer debugging remoto, etc…).

    Para ser justo con los demás, debo aclarar que hace mucho tiempo que es mi entorno de trabajo, con lo cual, puede que los otros hayan evolucionado y hoy le hagan fuerza…

    Pero tiene un problemita: es un software pago (y no precisamente barato.). Si podés pagar la licencia (o lograr que tu empresa te lo pague), realmente lo vale.

    Podés descargar una versión de prueba acá.

    VisualStudioCode

    El nuevo jugador que está tomando fuerza es VisualStudioCode. Lo probé muy poco y no logró convencerme de hacer el cambio… lo nombro simplemente porque muchos otros desarrolladores lo usan y están muy contentos con él.

    A mi mucho los productos de MicroSoft no me gustan, pero… este parece estar bien logrado.

    Descargalo de acá y me contás :).

    CodeAnyWhere

    Un proyecto espectacular, pero aún bastante verde para mi gusto… La idea es bárbara: un IDE 100% basado en web.

    Si tus requerimientos te lo permiten, es la mejor opción para independizarte por completo de tu computadora (Algo que para cualquier nómada digital debería ser un factor de peso).

    Por lo poco que lo probé, no me pudo convencer de cambiar, pero no me sorprendería que en un par de años se convierta en mi aliado favorito.

    No hay nada que descargar, sólo tenés que crear una cuenta acá y salir codeando :).

    Codelobster

    Un proyecto con el que me crucé recientemente y que vale la pena mencionar es Codelobster.

    Se trata de un IDE multiplataforma y que tiene una versión gratuita.

    Sus puntos fuertes son:

    • La inclusión de soporte para los frameworks más populares de PHP
    • La velocidad
    • El bajo consumo de recursos
    • La sencillez de su interface

    Una opción para tener en cuenta.

    Conclusión

    IDEs hay de todos los tamaños y colores… en última instancia, es una cuestión de gusto/comodidad personal. Mi sugerencia es que pruebes varios, elijas uno y aprendas a sacarle hasta la última gota de jugo.

    ¿Qué herramientas forman parte imprescindible de tu toolkit?

  • Cómo manipular imágenes usando PHP

    Cómo manipular imágenes usando PHP

    ImageMagick es una aplicación muy potente para la manipulación de imágenes. Por lo general, se utiliza desde la línea de comandos en ambientes Linux.

    ImageMagick es capaz de trabajar con una amplia variedad de formatos de imágenes y realizar una gran cantidad de transformaciones sobre ellas.

    PHP cuenta con una API propia para que su utilización sea sencilla (Obviamente, requiere que primero se instalen las bibliotecas necesarias): la clase Imagick.

    Una instancia de Imagick trabaja asociándole una o más imágenes al momento de su construcción (pasándole un string o un array según el caso):

    $ig = new \Imagick("mi_imagen.jpg");
    
    $ig2 = new \Imagick( ["mi_imagen.jpg", "otra_imagen.png"]);

    A partir de ese momento es posible realizar modificaciones a la imagen simplemente invocando los métodos de la clase, por ejemplo:

    $ig->resizeImage( $width, $height, \Imagick::FILTER_BOX, 0.9 );

    Permite redimensionar la imagen al tamaño que se desee (aplicando en el proceso diferentes filtros y borroneos (blur).

    Es importante tener en cuenta que todo este procesamiento sucede en memoria, de esa forma es posible emitir el resultado directamente hacia la salida:

    header("Content-Type: image/jpg");
    echo $ig->getImageBlob();

    O almacenarlo en un archivo:

    $ig->writeimage( "nueva_imagen.jpg" );

    Ahora ya podés hacer que tu aplicación recorte el avatar de tus usuarios (o mejor, que les baje un poco la calidad para limitar su tamaño).

    ¿Qué otras cosas querrías hacer con las imágenes de tu aplicación?