Actualizar una aplicación PHP antigua



Recientemente tuve la oportunidad ocasional de trabajar con varias aplicaciones PHP antiguas. Noté algunos anti-patrones comunes que debían arreglarse. Este artículo no trata sobre cómo reescribir una aplicación PHP antigua para <insertar aquí el nombre del maravilloso marco>, sino cómo hacer que sea más fácil de mantener y menos complicado para trabajar.



Antipattern # 1: credenciales en código



Este es el más común de los peores patrones con los que me he encontrado. En muchos proyectos, el código versionado está codificado con información importante, como nombres y contraseñas para acceder a la base de datos. Obviamente, esta es una mala práctica, porque no permite crear entornos locales, porque el código está ligado a un entorno específico. Además, cualquier persona con acceso al código puede ver las credenciales que normalmente son apropiadas para el entorno de producción.



Para solucionar esto, prefiero un método que funcione para cualquier aplicación: instale el paquete phpdotenv , que le permite crear un archivo de entorno y acceder a las variables usando supervariables de entorno.



Creemos dos archivos: .env.exampleuno que será versionado y servirá como plantilla para el archivo.env, que contendrá las credenciales. El archivo .envno tiene versión, así que agréguelo a .gitignore. Esto está bien explicado en la documentación oficial .



Su archivo .env.exampleincluirá las credenciales:



DB_HOST=
DB_DATABASE=
DB_USERNAME=
DB_PASSWORD=


Y los datos en sí estarán en el archivo .env:



DB_HOST=localhost
DB_DATABASE=mydb
DB_USERNAME=root
DB_PASSWORD=root


En un archivo normal, cargue .env:



$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();


Luego se puede aplicar a los datos contables usando, digamos $_ENV['DB_HOST'].



No se recomienda utilizar el paquete en funcionamiento "tal cual", para ello es mejor:



  • Inyecte variables de entorno en el tiempo de ejecución de su contenedor si tiene una implementación basada en Docker, o en la configuración HTTP del lado del servidor si es posible.
  • Almacene en caché las variables de entorno para evitar la sobrecarga de leer .env en cada solicitud. Así es como lo hace Laravel .


Los archivos de credenciales se pueden eliminar del historial de Git .



Antipattern # 2: no uses Composer



Solía ​​ser muy popular tener una carpeta lib con bibliotecas grandes como PHPMailer. Esto debe evitarse de todas las formas posibles cuando se trata de control de versiones, por lo que estas dependencias deben administrarse con Composer . Entonces será muy fácil para usted ver qué versión del paquete está en uso y actualizarlo si es necesario.



Así que instale Composer y utilícelo para administrar.



Antipattern # 3: sin entorno local



La mayoría de las aplicaciones con las que trabajé solo tenían un entorno: producción.





Pero al deshacerse del anti-patrón # 1, puede personalizar fácilmente su entorno local. Quizás parte de su configuración estaba codificada en su código, como las rutas de inicio, pero ahora puede mover eso a .env.



Utilizo Docker para crear entornos locales. Funciona especialmente bien para proyectos más antiguos porque a menudo usan versiones anteriores de PHP que usted no desea o no puede instalar.



Puede utilizar un servicio como PHPDocker o utilizar un archivo pequeño docker-compose.yml.



Antipattern # 4: no use la carpeta pública



Resultó que la mayoría de estos proyectos antiguos son accesibles desde sus carpetas raíz. Es decir, cualquier archivo en la raíz estará disponible para lectura pública. Esto es especialmente malo cuando los atacantes (como un script para niños) intentan acceder a los archivos incluidos directamente, porque es posible que no pueda determinar la salida si el script accede a todos sus archivos incluidos directamente.



Obviamente, esta situación es incompatible con el uso de .envComposer, porque abrir la carpeta del proveedor es una mala idea . Sí, existen algunos trucos para hacer esto; pero si es posible, mueva todos los archivos PHP abiertos a los clientes a una carpeta Publicy cambie la configuración del servidor para que esta carpeta se convierta en la carpeta raíz de su aplicación.



Yo suelo hacer esto:



  • Cree una carpeta dockerpara archivos relacionados con Docker (configuración Nginx, PHP Dockerfile, etc.).
  • Creo una carpeta appen la que almaceno la lógica empresarial (servicios, clases, etc.).
  • Creo una carpeta publicen la que almaceno scripts y recursos PHP (JS / CSS) abiertos para los clientes. Esta es la carpeta raíz de la aplicación desde el punto de vista de los clientes.
  • Creo archivos .envy .env.example.


Antipattern # 5: graves problemas de seguridad



Las aplicaciones PHP, especialmente las más antiguas que no usan frameworks, a menudo sufren graves problemas de seguridad:



  • Debido a la falta de escape de parámetros en la consulta, existe el peligro de inyección SQL. Para prevenirlos, use PDO!
  • Existe el peligro de inyección de XSS debido a la visualización de datos de usuario que no han sido escapados. Utilice htmlspecialchars para prevenirlos.
  • . , , , .
  • - CSRF-. Anti-CSRF, .
  • Cifrado de contraseña deficiente. He visto que muchos proyectos todavía usan SHA-1 e incluso MD5 para el hash de contraseñas. PHP 5.5 listo para usar tiene un buen soporte para BCrypt, es una pena no usarlo. Para transferir contraseñas cómodamente, prefiero actualizar los hash en la base de datos cuando los usuarios inician sesión. Lo principal es asegurarse de que la columna passwordsea ​​lo suficientemente larga para contener contraseñas de BCrypt, VARCHAR (255) está bien. Aquí hay un pseudocódigo para que sea más claro:



    <?php
    //    :    $
    //  :     
    if (strpos($oldPasswordHash, '$') !== 0 &&
        hash_equals($oldPasswordHash, sha1($clearPasswordInput))) {
        $newPasswordHash = password_hash($clearPasswordInput, PASSWORD_DEFAULT);
    
        //   password
    
        //  :    
    }
    
    //   
    if (password_verify($clearPasswordInput, $currentPasswordHash)) {
        //  :    
    }
    
    //   :    
    


Antipattern # 6: sin pruebas



Esto es muy común en aplicaciones antiguas. Es casi imposible comenzar a escribir pruebas unitarias para toda la aplicación, por lo que puede escribir pruebas funcionales.





Estas son pruebas de alto nivel para ayudarlo a garantizar que la refactorización posterior de su aplicación no la rompa. Las pruebas pueden ser sencillas, por ejemplo, iniciamos el navegador e ingresamos a la aplicación, luego esperamos el código HTTP sobre el éxito de la operación y / o el mensaje correspondiente en la página final. Para las pruebas, puede usar PHPUnit o Cypress o codeception .



Antipattern # 7: Manejo deficiente de errores



Si (o probablemente cuando) algo se rompe, debe averiguarlo rápidamente. Pero muchas aplicaciones antiguas no manejan bien los errores, confiando en PHP para la indulgencia.



Debe poder detectar y registrar tantos errores como sea posible para corregirlos. Hay buenos artículos sobre este tema .



Además, le resultará más fácil encontrar lugares donde se produzcan errores si el sistema arroja excepciones específicas.



Antipatrón # 8: variables globales



Pensé que nunca los volvería a ver hasta que comencé a trabajar con proyectos antiguos. Las variables globales hacen que la lectura y la comprensión del comportamiento del código sean impredecibles. En resumen, es malvado .



Es mejor usar la inyección de dependencia en su lugar , porque le permite controlar qué instancias se usan y dónde. Por ejemplo, el paquete Pimple ha funcionado bien .



¿Qué más mejorar?



Dependiendo del destino de la aplicación o el presupuesto, hay varios pasos más que puede seguir para mejorar su proyecto.



Primero, si la aplicación se ejecuta en una versión anterior de PHP (por debajo de 7), intente actualizarla. La mayoría de las veces, esto no causa grandes problemas y, sobre todo, tomará la mayor parte del tiempo deshacerse de las llamadas mysql_ calls, si las hay. Para solucionar esto rápidamente, puede usar una biblioteca similar , pero es mejor reescribir todas las solicitudes de PDO para que todos los parámetros se escapen al mismo tiempo.



Si la aplicación no usa el patrón MVC, es decir, la lógica empresarial y las plantillas están separadas, entonces es hora de agregar una biblioteca de plantillas (sé que PHP es un lenguaje de plantillas, pero las bibliotecas modernas son mucho más convenientes), por ejemplo, Smarty, Twig o Blade.



Finalmente, a largo plazo, es mejor reescribir su aplicación en un marco PHP moderno como Laravel o Symfony. Tendrá todas las herramientas que necesita para un desarrollo PHP seguro e inteligente. Si la aplicación es grande, entonces recomiendo usar el patrón estrangulador para evitar la reescritura del Big Bang , que puede (y probablemente terminará) mal. Por lo tanto, puede migrar aquellas partes del código en las que está trabajando actualmente al nuevo sistema, manteniendo intactas las partes de trabajo antiguas hasta que llegue a ellas.



Este es un enfoque eficaz que le permite crear un entorno PHP moderno para su trabajo diario, sin congelar funciones durante semanas o meses, según el proyecto.



All Articles