domingo, 30 de septiembre de 2007

Procesamiento de formularios

Siempre, el mayor problema, es procesar datos que se envían. Vamos a hacer un seguimiento de que cosas hay que revisar para cada formulario. Como noción previa, tenemos que tener en cuenta que todos los datos que envía el client (POST, GET, COOKIE) poco confiable.
  1. Revisar el permiso del usuario
    No todos los usuarios tienen permisos para todos los formularios, eso es claro. Hay que establecer si el usuario puede enviar ese formulario o no, o si sólo lo puede hacer en parte.

  2. Validar todos los datos
    Significa que por cada formulario que se le pide, hay que establecer condiciones. En general, los campos de texto tienen que tener un largo máximo (lo más normal es establecerlo de acuerdo a la base de datos) o fijo (por ejemplo, los códigos de tarjetas de crédito). También hay que revisar el formato (usualmente para las direcciones de e-mail). Hay datos que sólo pueden ser numéricos, o fechas que pueden no ser válidas.
    Los checkbox, radio buttons y dropdowns tienen un rango de opciones prefijados y no se pueden salir de ellos.
    Todas estas cosas hay que tenerlas en cuenta, porque un dato erróneo puede hacer que se pierda información, pero se puede evitar si se le fuerza al usuario a corregir ese error.

  3. Escapar datos
    Dependiendo el destino de los datos ingresados, hay que escapar los datos de la forma que corresponda. En general, vamos a guardarlos en bases de datos, por lo que las funciones *_escape_string nos proveen una forma fácil de escapar los datos de acuerdo al tipo de base de datos que usemos.
    En este punto, hay que tener cuidado con las "comillas mágicas" (magic_quotes_gpc), que si están habilitadas pueden hacer que los datos sean doblemente escapados. Lo mejor es quitar las comillas, si esta directiva está en funcionamiento.
    ¿Por qué no nos olvidamos de escapar datos si tenemos magic_quotes_gpc?
    La idea de magic_quotes era no tener que escapar datos, y facilitarle la tarea al programador. El problema de esta función, es que escapa datos en forma arbitraría y sin tener en cuenta en donde se utilizan los mismos.
    Otro posible error es querer guardar datos que no envió el usuario, pero por tener magic_quotes_gpc On no escapamos, incorrectamente.

  4. Guardar los resultados
    Los datos son válidos, están preparados... Lo único que queda es guardarlo, y hacer cualquier otro proceso que sea necesario.

  5. Mostrar los resultados
    Todavía no terminó nuestro trabajo. La información que guardamos, probablemente la queramos mostrar a alguien. En este punto es muy importante escapar los datos nuevamente. Anteriormente los guardamos tal cual lo mandó el usuario, pero a la hora de mostrarlo en una página, hay que evitar que se haya podido ingresar información malisiosa. En general, escapar las entidades HTML es suficiente para esto, pero sería mejor escapar todas las entidades, incluso las más "raras" para presentar correctamente la información.
Estos 5 puntos son necesarios para la mayoría de los procesamientos de datos. Parece engorroso y complicado, pero no lo es realmente.

martes, 25 de septiembre de 2007

Conexión por IP

Recientemente descubrí que es más rápido conectarse a un servidor utilizando su IP que su nombre. Por ejemplo, en vez de mysql_connect('localhost'); uno puede usar mysql_connect('127.0.0.1'); y termina mejorando la velocidad de conexión. Una pequeña optimización, pero frecuente.

domingo, 23 de septiembre de 2007

Guardar elementos de un array en una variable

El otro día, me llamó la atención leer que es más lento acceder a un elemento de un array que a una variable. Decidí probar cuanta es la diferencia, y si vale la pena. Mi conclusión es que la diferencia existe y si se llama más de 10 veces al mismo indice, puede valer la pena crear una variable para eso, pero igualmente sólo es recomendable hacerlo dentro de una función, en un "alcance" cerrado para que no quede en la memoria todo el tiempo.

Ver ejemplo

jueves, 20 de septiembre de 2007

Leer el manual

Tengo que leer el manual
Tengo que leer el manual
Tengo que leer el manual
Tengo que leer el manual


Sí, es aburrido, pero hay que tener en cuenta que PHP cuenta con muchísimas funciones que quizás uno ignora y podemos evitarnos redescubrir la rueda.
También hay que leer los comentarios de los usuarios, muchos agujeros se tapan allí.

La última función que descubrí: dl

domingo, 16 de septiembre de 2007

Recorrer un array

Quizás suene reiterativo al post for - while, pero ahora en vez de ejecutar un código N veces, quiero recorrer todas las posiciones de un array. ¿Cuál es la forma más conveniente?
En primer lugar, tenemos el for optimizado.
Por otra parte, podemos utilizar el foreach, que justamente recorre el array de datos.
Una última alternativa es ir recorriendo el array utilizando su puntero interno.

En este caso, la mejor alternativa es el foreach, especialmente dedicado para esto.

Ver ejemplo

jueves, 13 de septiembre de 2007

Post o Get

¿Cuál es el criterio para elegir si un formulario debe ir por Post o por Get?
La w3c nos da una lista para decidir. Vamos a utilizar esa lista como base, y tratar de ampliarla un poco

GET
  • W3C: La interacción es más como una pregunta (?)
  • Es un dato que sirve como guía para la presentación
  • Se quiere poder ofrecer la posibilidad de copiar y pegar para guardarla, ingresarla en una página, pasarsela a otra persona

POST
  • W3C: La interacción es más bien una orden
  • W3C: La interacción cambia el estado del recurso en camino tal como lo percibió el usuario
  • W3C: El usuario espera resultados de la interacción
  • Resalto la segunda de la W3C como muy importante: tratar de mantener los procesamientos de formularios como Post
  • Maneja datos "sensibles" como contraseñas
  • Es mucha la información (la cantidad de caracteres de la URI puede ser limitado pro el servidor)

AMBOS
  • Cuando se procesan datos, es buena costumbre realizar Post/Redirect/Get

martes, 11 de septiembre de 2007

Reporte de errores

Uno no programa en forma correcta, si existen errores. Y si estos errores se escapan de nuestra vista, será más difícil detectarlos y corregirlos. Un error que no provoca consecuencias negativas, sigue siendo un error. Lo más común, en este sentido, es comprobar el valor de variables que no están inicializadas, o no sabemos si lo están... Si probamos la diferencia entre

1) if ($variable)
2) if (isset($variable))
3) if (!empty($variable))

Lo primero que me llama la atención es cuanto más lento es la primera opción, si la variable no está definida, pero si está variable está definida es más rápida que empty y que isset, con lo que si se está seguro que la variable existe, esta es la mejor solución, pero ante la duda es preferible utilizar empty/isset.

Volviendo al tema de los errores, siempre que se codifica es bueno ver los errores, por lo tanto siempre es bueno ejecutar

error_reporting(E_ALL);

mientras se está desarrollando, y reducir el nivel a E_NONE cuando se está en un sitio live, o eliminar el error_display

Ver ejemplo

domingo, 9 de septiembre de 2007

Listar directorio

Es común la necesidad de buscar todos los archivos en una carpeta. Lo más común siempre es usar opendir, pero la funcion glob nos acerca al lado oscuro de la fuerza, ofreciendonos una alternativa más simple... Sin embargo, esta solución es más lenta.
Otra alternativa es la funcion dir, que nos devuelve un objeto directorio, una solución más "elegante" si se quiere, pero no es más que un wrapper de lo mismo, por lo que no es más rápido.

Ver ejemplo

viernes, 7 de septiembre de 2007

Evitar dobles llamados a funciones

Se me ocurría que podía agarrar cualquier función y optimizarla mediante almacenar resultados ya calculados en una variable temporal.
Por lo tanto, agarré una fórmula matemática común, la "cuadrática" que se utiliza para obtener las raíces de un polinomio de grado dos, y empecé a probar formas de mejorarla.

Varios fueron los intentos, y la conclusión a la que llegué es que si bien es mejor almacenar resultados de llamados de funciones, no es lo mejor guardarlo de operatorias más simples como la multiplicacion.

Ver ejemplo

miércoles, 5 de septiembre de 2007

Par o impar

¿Cómo sabemos si un número entero es par o impar?
Por supuesto que no es muy complicado.
Cuando recién comenzaba, recuerdo haber buscado una forma de hacerlo, no muy práctica

floor($a / 2) == $a / 2;

El resultado es correcto, pero esto se podría facilitar aún más conociendo el operador %

$a % 2 == 0;


Sin embargo, se puede hacer todavía más rápido, aunque no necesariamente fácil, verificando si el binario contiene al 1 o no.

$a & 1 == 0

Ver ejemplo

sábado, 1 de septiembre de 2007

str_replace - strtr

Estas dos funciones son muy parecidas. En general, str_replace es más famosa, pero ¿cuál conviene? Vamos a probar...

str_replace('e','a','hello world');
strtr('hello world','e','a');

Vamos a comparar un reemplazo simple. En esta comparación, str_replace se lleva un punto.

¿Qué pasa si se quiere reemplazar un texto que no se encuentra?
Ambas funciones funcionan más rápido, pero str_replace sigue siendo más óptima. En esta instancia, ya parecería mejor esta opción, pero ambas funciones nos permiten reemplazar varios textos a la vez. Probemos.

str_replace(array('o','e'),'a','hello world');
strtr('hello world',array('o' => 'a','e' => 'a'));

En este caso reemplazamos "o" y "e" por "a", y str_replace sigue siendo mejor... Vamos a darle una última oportunidad a strtr

str_replace(array('o','e'),array('i','o'),'hello world');
strtr('hello world',array('o' => 'i','e' => 'o'));

En este caso, se reemplaza 'o' por 'i' y 'e' por 'a', y sorpresivamente strtr se lleva la victoria.

Conclusión: en general, es preferible utilizar str_replace, pero cuando se quiere reemplazar un conjunto de caracteres por otro conjunto (y no un único valor) es mejor strtr.

Ver ejemplo