Apuntes php

PHP: Porque a veces necesitas un poco de caos en tu vida.

Buenas prácticas y estructura de un proyecto PHP

Organizar correctamente un proyecto PHP facilita su mantenimiento, escalabilidad y legibilidad. A continuación se describen recomendaciones clave sobre estructura de carpetas, uso de constantes, separación de responsabilidades, seguridad y más.

Estructura básica del proyecto

Una organización clásica en PHP procedural podría verse así:

mi-proyecto/
├── public/            # Archivos accesibles desde el navegador
│   ├── index.php      # Punto de entrada principal
│   ├── css/           # Estilos CSS
│   ├── js/            # Scripts JavaScript
│   ├── img/           # Imágenes
│   └── .htaccess      # Configuración para Apache
├── includes/          # Archivos comunes PHP
│   ├── config.php     # Configuración global
│   ├── db.php         # Conexión y funciones de base de datos
│   ├── functions.php  # Funciones generales
│   └── header.php     # Cabecera reutilizable
├── pages/             # Páginas o vistas PHP
│   ├── home.php
│   ├── productos.php
│   └── contacto.php
├── data/              # Archivos no accesibles vía web
│   └── temp/          # Datos temporales
└── logs/              # Registros y trazas

Nota: Puedes adaptar esta estructura, pero lo importante es mantener una separación lógica de responsabilidades y acceso controlado.

Separación por capas (MVC ligero)

Sin usar frameworks complejos, es recomendable aplicar una separación de responsabilidades inspirada en el patrón Modelo-Vista-Controlador (MVC):

  • Modelos: funciones que acceden a la base de datos y procesan datos.
  • Vistas: plantillas PHP que presentan la información.
  • Controladores: scripts que gestionan la lógica de la petición.
<?php
// includes/db.php - Modelo
function obtener_usuario_por_id($id) {
    global $conexion;
    $id = (int)$id;
    $query = "SELECT * FROM usuarios WHERE id = $id";
    $resultado = mysqli_query($conexion, $query);
    if (!$resultado || mysqli_num_rows($resultado) === 0) {
        return false;
    }
    return mysqli_fetch_assoc($resultado);
}

// public/usuarios.php - Controlador
require_once '../includes/config.php';
require_once '../includes/db.php';
require_once '../includes/functions.php';

$id = isset($_GET['id']) ? $_GET['id'] : 0;
$usuario = obtener_usuario_por_id($id);

if (!$usuario) {
    include '../pages/usuario_no_encontrado.php';
} else {
    include '../pages/perfil_usuario.php';
}
?>

Uso de constantes

En includes/config.php puedes definir constantes reutilizables a lo largo del proyecto:

<?php
define('BASE_URL', 'https://miweb.local');
define('APP_NAME', 'Proyecto PHP');
define('VERSION', '1.0');

define('DB_HOST', 'localhost');
define('DB_USER', 'usuario');
define('DB_PASS', 'contraseña');
define('DB_NAME', 'mi_base_datos');

define('ROOT_PATH', dirname(__DIR__));
define('INCLUDES_PATH', ROOT_PATH . '/includes');
define('PAGES_PATH', ROOT_PATH . '/pages');
define('LOGS_PATH', ROOT_PATH . '/logs');
?>

Gestión de configuración por entorno

<?php
define('ENTORNO', 'desarrollo');
if (ENTORNO === 'desarrollo') {
    ini_set('display_errors', 1);
    error_reporting(E_ALL);
} else {
    ini_set('display_errors', 0);
    error_reporting(0);
}
?>

Recomendaciones prácticas

  • Funciones reutilizables: evita duplicación (principio DRY).
  • Archivos con propósito único: cada archivo debe tener una función clara.
  • Funciones pequeñas: con una sola responsabilidad.
  • Validación centralizada: agrupa funciones como validar_email(), validar_entero().
  • Manejo de errores: usa error_log() o un manejador personalizado.
  • Inclusión ordenada: usa require_once para archivos críticos.

Control único de entrada

<?php
require_once '../includes/config.php';
require_once '../includes/functions.php';
require_once '../includes/db.php';

$pagina = isset($_GET['p']) ? $_GET['p'] : 'home';
$paginas_permitidas = ['home', 'productos', 'contacto'];

if (!in_array($pagina, $paginas_permitidas)) {
    $pagina = 'home';
}

include '../includes/header.php';
include "../pages/$pagina.php";
include '../includes/footer.php';
?>

Seguridad básica

  • Escapa la salida HTML con htmlspecialchars().
  • Valida siempre la entrada (filter_var(), etc.).
  • Usa sentencias preparadas (mysqli_prepare() o PDO).
  • No muestres errores técnicos en producción.
  • Evita incluir archivos basados en datos no validados.
TOP