PHP es probablemente el lenguaje de desarrollo web más popular en los últimos tiempos. Una gran cantidad de dominios y aplicaciones usan PHP, como si fuera poco, es el lenguaje utilizado en los principales sitios como Wikipedia y Facebook, así como en algunos de los mayores proyectos de código abierto del mundo, como WordPress y Drupal.
En este artículo, compartiré algunas cosas que se olvidaron enseñarme cuando comencé con PHP, y espero que sean de gran utilidad para que comiences con pie derecho en el desarrollo de la web.
1. No cierre las etiquetas PHP
Una gran cantidad de desarrolladores cierran la etiqueta PHP, tal como el siguiente ejemplo:
1 2 3 4 5 6 7 8 9 | <?php class TuClase{ public function TuFuncion(){ //Algo debe de hacer, no? } } ?> |
<?php class TuClase{ public function TuFuncion(){ //Algo debe de hacer, no? } } ?>
El problema con esto es que puede introducir caracteres de espacio o de nueva línea en blanco si el desarrollador no tiene cuidado. Esto puede causar dolores de cabeza más adelante, cuando las cabeceras son interrumpidas o espacios en blanco aparecen inexplicablemente en la salida.
Ok, así que ¿qué se debe hacer?
Esto es perfectamente aceptable:
1 2 3 4 5 6 7 | <?php class TuClase{ public function TuFuncion(){ //Algo debe de hacer, no? } } |
<?php class TuClase{ public function TuFuncion(){ //Algo debe de hacer, no? } }
Para ser honesto, la única vez que realmente debes cerrar las etiquetas PHP es cuando estás mezclando PHP con HTML:
1 2 | <h1><?php echo $title; ?></h1> <p><?php echo $description; ?></p> |
<h1><?php echo $title; ?></h1> <p><?php echo $description; ?></p>
2. No utilice las funciones mysql_*.
A partir de PHP 5.5, las funciones mysql se han desaprobado oficialmente. Según el sitio web oficial de PHP, la extensión por defecto de MySQL se eliminará por completo en el futuro. Si eso no te persuade para encontrar una alternativa, entonces deberías considerar también el hecho de que carece de soporte a una serie de características de MySQL. Lo más destacado de las nuevas funciones son:
– Declaraciones preparadas.
– Transacciones.
– Procedimientos almacenados.
– Consultas asíncronas.
– Sentencias múltiples.
El hecho es que esta extensión casi obsoleta fue desarrollada para la versión MySQL 3.23. Desde entonces, muy poco en realidad se ha añadido en el camino a las características.
OK, así que lo puedo usar en su lugar?
Dos buenas alternativas son PDO y MySQLi. Personalmente, prefiero usar PDO, ya que proporciona una capa de abstracción de acceso a datos, lo que básicamente significa que puedes utilizar las mismas funciones para acceder a otras bases de datos, así (PostgreSQL, SQLite, etc).
3. Protéjase contra XSS!
XSS (también conocido como Cross-site scripting) es una vulnerabilidad que permite a los atacantes ejecutar código desde el lado del cliente en tu sitio web. Por ejemplo: Si entro algo de JavaScript en un formulario de comentarios y te muestro ese comentario sin limpiarlo, el código en cuestión se ejecutará cada vez que un usuario carga la página. Para defenderse de este tipo de vulnerabilidad, debe desinfectar los datos enviados por el usuario antes de que se muestre en la página. Para ello, puede utilizar la función htmlspecialchars:
1 2 | <?php echo htmlspecialchars($userComment, ENT_QUOTES, 'utf-8'); |
<?php echo htmlspecialchars($userComment, ENT_QUOTES, 'utf-8');
Esta función convierte los caracteres especiales en sus entidades HTML correspondientes, por lo que son seguros para su visualización 😉
4. No sobre comentar el código
La documentación apropiada del código en definitiva es una buena práctica, pero ¿es realmente necesario comentar cada línea? Probablemente no. Comentar las secciones complicadas de su código fuente para que cuando vuelva a visitarlo recordará rápidamente lo que está pasando, pero no comentamos las cosas simples, como su código de conexión MySQL.
La manera correcta:
1 2 3 4 5 6 7 8 9 10 11 12 13 | <?php /* Conexion a la base de datos */ $hostname = "localhost"; $username = ""; $password = ""; $dbname = ""; $connectionStatus = mysql_connect($hostname, $username, $password) or die(mysql_error()); $selectionStatus = mysql_select_db($dbname) or die(mysql_error()); /* Fin conexion a la base de datos */ |
<?php /* Conexion a la base de datos */ $hostname = "localhost"; $username = ""; $password = ""; $dbname = ""; $connectionStatus = mysql_connect($hostname, $username, $password) or die(mysql_error()); $selectionStatus = mysql_select_db($dbname) or die(mysql_error()); /* Fin conexion a la base de datos */
Sin duda, la forma como nunca deberías de hacerlo:
1 2 3 4 5 6 7 8 9 10 11 | <?php /* Definir las variable de conexion */ $hostname = "localhost"; // direccion del servidor $username = ""; // Nombre de usuario $password = ""; // Contraseña $dbname = ""; // Nombre base de datos a conectar // Conectar a la base de datos, o mostrar un error $connectionStatus = mysql_connect($hostname, $username, $password) or die(mysql_error()); // Seleccionar la base de datos a continuacion $selectionStatus = mysql_select_db($dbname) or die(mysql_error()); |
<?php /* Definir las variable de conexion */ $hostname = "localhost"; // direccion del servidor $username = ""; // Nombre de usuario $password = ""; // Contraseña $dbname = ""; // Nombre base de datos a conectar // Conectar a la base de datos, o mostrar un error $connectionStatus = mysql_connect($hostname, $username, $password) or die(mysql_error()); // Seleccionar la base de datos a continuacion $selectionStatus = mysql_select_db($dbname) or die(mysql_error());
5. Conozca el concepto DRY.
El paradigma DRY – Don’t Repeat Yourself el algo que sin duda debes de aplicar cuando comiences a codear. Debes evitar una situación en la que estás repitiendo exactamente el mismo código. Esto se puede hacer a través de el uso de un simple include, funciones y clases. Por ejemplo, si tengo un pedazo de código que calcula la edad de una persona, puedo crear una función de este modo:
1 2 3 4 5 6 7 | <?php function CalcularEdad($dateOfBirth){ $birthday = new DateTime($dateOfBirth); $interval = $birthday->diff(new DateTime); return $interval->y; } |
<?php function CalcularEdad($dateOfBirth){ $birthday = new DateTime($dateOfBirth); $interval = $birthday->diff(new DateTime); return $interval->y; }
Ahora, cada vez que quiero para calcular la edad de un usuario, sólo tengo que llamar a la función anterior; en lugar de repetir la misma lógica. Esto es ventajoso porque:
– Mi código base es menor como consecuencia.
– Si tengo que modificar la lógica, puedo editar la función de CalcularEdad.
6. Contraseñas de usuario Seguras!
Las contraseñas de usuario deben hash, no se almacenan en formato de texto o base codificada (en serio, de hecho he encontrado esto antes). Una función hash es una calle de sentido único. Una vez que la contraseña en texto plano se ha transmitido a través de él, no hay manera de recuperarlo (de ahí la razón por la que utilizamos el término «hash», no «cifrado»). Si está usando PHP> = 5.5, debe utilizar el password_hash función. Si está atrapado en una versión anterior, entonces usted puede hacer uso de la librería password_compat en Github.
7. Utiliza sentencias preparadas!
Una de las principales ventajas de usar PDO es que permite que puedas hacer uso de sentencias preparadas. En el pasado, los desarrolladores de PHP se vieron obligados a usar unciones como mysql_real_escape_string así:
1 2 3 | <?php $username = mysql_real_escape_string($username, $connection); $result = mysql_query("SELECT name FROM users WHERE username = '$username'"); |
<?php $username = mysql_real_escape_string($username, $connection); $result = mysql_query("SELECT name FROM users WHERE username = '$username'");
Esta función escapa caracteres especiales que puedan causar problemas con tu sentencia SQL. Es decir, ayuda a proteger contra la inyección SQL. Sin embargo, lo que no hará es a protegerse de los ataques que no implican caracteres especiales como x00, n, r, , ‘, ” y x1a.
Afortunadamente, la inyección de SQL no es rival para comandos preparados. Con declaraciones preparadas, la sentencia SQL se envía al servidor antes de que los datos, manteniendolos independientes entre sí. Esto significa que la base de datos sabe lo que necesita para ejecutar correctamente, antes de que cualquier carácter potencialmente peligrosos se envían a través de la comunicación. Un ejemplo de la selección de filas con el objeto PDO:
1 2 3 4 5 6 7 8 9 | <?php //Preparamos la sentencia SQL. En esta etapa se va enviado al servidor $stmt = $db->prepare("SELECT name FROM users WHERE username = :username"); //Enlazamos nuestros parámetros / datos. $stmt->bindParam(':username', $username); //Ejecutamos la sentencia. $stmt->execute(); |
<?php //Preparamos la sentencia SQL. En esta etapa se va enviado al servidor $stmt = $db->prepare("SELECT name FROM users WHERE username = :username"); //Enlazamos nuestros parámetros / datos. $stmt->bindParam(':username', $username); //Ejecutamos la sentencia. $stmt->execute();
Nota importante: Con la extensión PDO, tendrás que activar manualmente el uso de declaraciones “naturales” preparadas. A los efectos de la portabilidad, esta extensión utiliza el emulado de las declaraciones preparadas por defecto. Para desactivar comandos preparados emulados, puede utilizar el siguiente código:
1 2 | <?php $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); |
<?php $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
8. «or die ()» tiene que morir …
Si has decidido ignorar por completo todas las ventajas del por que usar PDO, entonces creo que es justo decir que es probable que estés manejando consultas poco practicas, como por ejemplo:
1 2 | <?php mysql_query($sql, $conn) or die(mysql_error($conn)); |
<?php mysql_query($sql, $conn) or die(mysql_error($conn));
El problema con el enfoque anterior es que no se puede detectar el error o registrarlo. Tampoco se puede controlar si es o no se da salida a la pantalla. A los ojos de la función de la matriz, un servidor de desarrollo y un servidor de producción, son exactamente la misma cosa! No se puede controlar a través de los ajustes del .ini o un archivo de configuración de todo el sitio.
Un mejor enfoque a este sería el uso de excepciones, simplemente porque pueden ser capturados o manipulados:
1 2 3 4 5 | <?php $res = mysql_query($sql, $conn); if($res === false){ throw new Exception(mysql_error($conn)); } |
<?php $res = mysql_query($sql, $conn); if($res === false){ throw new Exception(mysql_error($conn)); }
La excepción anterior puede ser capturada con un bloque TRY CATCH o manejada con un manejador de excepción personalizada. Esto te da mucho más control sobre cómo los errores se manejan. Por supuesto, si se utiliza la extensión PDO, podrías tener los errores SQL lanzando excepciones por defecto utilizando el siguiente atributo:
1 2 | <?php $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); |
<?php $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
no se ve todo están como ventanas dentro de ventanas… no se entiende nada….
Buenas ideas agregar encriptacion en la cadena de la clave guardada en la tabla tambn es buena idea usando oracle mejor aun
gracias por esa buen informacion
Solamente puedo decir que Felicitaciones.
Buenos datos (y). Gracias por la info.
Muy buenas recomendaciones, personalmente hay algunas que necesito mejorar como la del uso de PDO en lugar de mysql_*
Muchas gracias por la informacion