Tutorial 6: Validando el Archivo Subido en PHP

¡Hola y bienvenido de nuevo!

En esta lección vamos a validar el archivo que el usuario sube a través del formulario. Vamos a verificar que el archivo existe, que no está vacío y vamos a obtener su tipo para procesarlo correctamente con Whisper. Vamos a hacerlo paso a paso.


📋 Contenido del Tutorial

  1. Creando el archivo de inicialización

  2. Incluyendo el archivo en index.php

  3. Verificando el método de la solicitud

  4. Validando que el archivo existe

  5. Obteniendo el tipo de archivo

  6. Mostrando mensajes de error

  7. Código completo

  8. Explicación detallada

  9. Próximos pasos


📁 1. Creando el archivo de inicialización

¿Qué es init.php?

El archivo init.php (inicialización) será el punto de entrada para todas las configuraciones y clases de nuestra aplicación. Lo usaremos para:

  • Conectar a la base de datos

  • Incluir todas las clases necesarias

  • Definir constantes globales

  • Configurar el entorno

Creando el archivo

Paso 1: En la carpeta backend, crea un nuevo archivo llamado init.php.

text
whisper/
├── backend/
│   ├── init.php          # ¡Nuevo archivo!
│   └── classes/
├── frontend/
│   ├── css/
│   ├── images/
│   └── js/
└── index.php

Paso 2: Por ahora, deja el archivo vacío o con un comentario:

php
<?php
// Archivo de inicialización de la aplicación
// Aquí cargaremos todas las clases y configuraciones
?>

🔗 2. Incluyendo el archivo en index.php

Agregando el include

Al inicio de index.php, justo después de abrir la etiqueta PHP, vamos a incluir nuestro archivo init.php:

php
<?php
    include 'backend/init.php';
    
    // El resto del código PHP...
?>

Ubicación correcta

El código debe ir antes de cualquier HTML, al principio del archivo:

php
<?php
    include 'backend/init.php';
    // Aquí irá toda la lógica PHP
?>
<!DOCTYPE html>
<html>
<head>
    <!-- ... -->
</head>

🔍 3. Verificando el método de la solicitud

¿Qué es el método de solicitud?

Cuando el usuario selecciona un archivo, el formulario se envía mediante el método POST. Necesitamos verificar esto en PHP.

Código para verificar el método POST

php
<?php
    include 'backend/init.php';
    
    // Verificar si la solicitud es de tipo POST
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        // Aquí procesaremos el archivo
    }
?>

Explicación de $_SERVER['REQUEST_METHOD']

ValorSignificado
GETEl formulario se envió mediante GET
POSTEl formulario se envió mediante POST
PUTSolicitud PUT
DELETESolicitud DELETE

📄 4. Validando que el archivo existe

Verificando si el archivo está presente

Primero, verificamos que el archivo exista en la solicitud:

php
if (isset($_FILES['file'])) {
    // El archivo está presente en la solicitud
}

Verificando que el archivo no esté vacío

Luego, verificamos que el nombre del archivo no esté vacío:

php
if (!empty($_FILES['file']['name'])) {
    // El archivo tiene un nombre, por lo tanto existe
}

Código completo de validación

php
<?php
    include 'backend/init.php';
    
    // Verificar si es una solicitud POST
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        
        // Verificar si el archivo está presente en la solicitud
        if (isset($_FILES['file'])) {
            
            // Verificar si el nombre del archivo no está vacío
            if (!empty($_FILES['file']['name'])) {
                // Archivo válido, podemos procesarlo
                $fileType = $_FILES['file']['type'];
                // ... más validaciones y procesamiento
            } else {
                // El archivo está vacío
                $error = "Por favor selecciona un archivo para convertir a texto";
            }
        } else {
            // No se encontró el archivo en la solicitud
            $error = "Por favor selecciona un archivo para convertir a texto";
        }
    }
?>

Estructura de $_FILES

Cuando subes un archivo, PHP crea el arreglo $_FILES con esta estructura:

php
$_FILES['file'] = [
    'name' => 'video.mp4',        // Nombre original del archivo
    'type' => 'video/mp4',        // Tipo MIME del archivo
    'tmp_name' => '/tmp/phpXyZ',  // Ubicación temporal en el servidor
    'error' => 0,                 // Código de error (0 = sin errores)
    'size' => 1234567             // Tamaño en bytes
];

🏷️ 5. Obteniendo el tipo de archivo

¿Por qué necesitamos el tipo de archivo?

El tipo de archivo nos ayudará a:

  1. Validar que sea un formato soportado (video/audio)

  2. Diferenciar entre video y audio para mostrarlo correctamente

  3. Guardar esta información en la base de datos

Obteniendo el tipo MIME

php
$fileType = $_FILES['file']['type'];

Ejemplos de tipos MIME

ArchivoTipo MIME
MP4video/mp4
AVIvideo/x-msvideo
MOVvideo/quicktime
MP3audio/mpeg
WAVaudio/wav
MKVvideo/x-matroska

Verificando el tipo de archivo (debug)

Podemos usar var_dump() para ver qué tipo de archivo se está subiendo:

php
var_dump($fileType);

Esto nos mostrará el tipo MIME exacto que está enviando el navegador.


🎨 6. Mostrando mensajes de error

Estructura del HTML para errores

En el HTML, tenemos un div preparado para mostrar errores:

html
<!-- ERROR DIV -->
<?php if(isset($error)): ?>    
    <div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative">
        <strong class="font-bold">Error:</strong>
        <span class="block sm:inline"><?php echo $error; ?></span>
    </div>
<?php endif; ?>

¿Cómo funciona?

  1. PHP verifica si la variable $error está definida

  2. Si existe, muestra el div con el mensaje de error

  3. El mensaje se muestra en color rojo para llamar la atención

Mensajes de error comunes

php
// Error: No se seleccionó archivo
$error = "Por favor selecciona un archivo para convertir a texto";

// Error: Formato no soportado
$error = "Formato de archivo no soportado. Por favor usa MP4, AVI, MOV, MP3 o WAV";

// Error: Archivo demasiado grande
$error = "El archivo excede el tamaño máximo permitido (500MB)";

// Error: Error al subir el archivo
$error = "Error al subir el archivo. Por favor intenta de nuevo";

💻 7. Código completo

Archivo: backend/init.php

php
<?php
// Archivo de inicialización de la aplicación
// Aquí cargaremos todas las clases y configuraciones

// Por ahora está vacío, pero lo usaremos más adelante
?>

Archivo: index.php (versión completa)

php
<?php
    include 'backend/init.php';
    
    // Inicializar variable de error
    $error = null;
    
    // Verificar si la solicitud es POST
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        
        // Verificar si el archivo está presente
        if (isset($_FILES['file'])) {
            
            // Verificar si el archivo no está vacío
            if (!empty($_FILES['file']['name'])) {
                
                // Obtener el tipo MIME del archivo
                $fileType = $_FILES['file']['type'];
                
                // Aquí podemos agregar más validaciones
                // Por ejemplo: verificar el tamaño, la extensión, etc.
                
                // Por ahora, solo mostraremos el tipo para debug
                // echo "Tipo de archivo: " . $fileType;
                
            } else {
                // El archivo está vacío
                $error = "Por favor selecciona un archivo para convertir a texto";
            }
            
        } else {
            // No se encontró el archivo en la solicitud
            $error = "Por favor selecciona un archivo para convertir a texto";
        }
    }
?>
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>My Whisper Ai - Convert Video/Audio language into written text</title>
    <!-- ... librerías y estilos ... -->
</head>
<body>
    <div class="Wrapper">
        <div class="inner-wrapper h-screen flex justify-center p-20">
            <div class="h-full border-2 rounded-xl border-gray-700" style="width: 1280px; max-height: 1080px; box-shadow: -20px 20px 0px 0px #74a840,-21px 21px 0px 3px #343333">
                <div class="flex h-full flex-col items-center">

                    <!-- Loader -->
                    <div id="loader" class="hidden flex flex-col text-center flex-1" style="width: 600px;">
                        <div class="flex items-center flex-col">
                            <img class="w-40 animate-pulse mt-60" src="frontend/images/loader.gif"/>
                            <span class="animate-pulse">Uploading....</span>
                        </div>
                    </div>

                    <!-- Contenido principal -->
                    <div id="upload" class="flex flex-col text-center mt-40" style="width: 600px;">
                        <img class="mx-auto my-4" src="frontend/images/banner-img.png" style="width: 300px;">
                        <h1 class="text-4xl py-2">Welcome to My Whisper</h1>
                        <p class="text-xl">
                            Whisper is an AI tool that allows you to convert video/audio files into text and also translate the text into your desired language.
                        </p>
                        
                        <label style="width: 200px; box-shadow: -7px 6px 0px 0px; border: 1px solid;" 
                               class="cursor-pointer select-none mx-auto my-4 rounded-full text-xl text-gray-600 px-10 py-5 border bg-lime-400" 
                               for="file-upload">
                            Upload File
                        </label>
                        
                        <form id="form" method="post" enctype="multipart/form-data">
                            <input id="file-upload" class="hidden" type="file" name="file">
                        </form>
                        
                        <!-- ERROR DIV -->
                        <?php if(isset($error)): ?>    
                            <div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative">
                                <strong class="font-bold">Error:</strong>
                                <span class="block sm:inline"><?php echo $error; ?></span>
                            </div>
                        <?php endif; ?>
                        
                        <p>Recently Generated Files: Click <a href="view.php?file=1" class="text-green font-bold text-sm">Here to View</a></p>
                    </div>
                </div>
            </div>
        </div>
    </div>
    
    <!-- JS CODE -->
    <script>
        $(document).ready(function() {
            $("#file-upload").change(function() {
                if (this.files.length > 0) {
                    $("#loader").removeClass('hidden');
                    $("#upload").addClass('hidden');
                    $("#form").submit();
                }
            });
        });
    </script>
</body>
</html>

📖 8. Explicación detallada

Estructura del PHP

1. Inclusión del archivo de inicialización

php
include 'backend/init.php';
  • Incluye el archivo que contiene todas las configuraciones

  • Permite centralizar la configuración en un solo lugar

2. Verificación del método POST

php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
  • $_SERVER es una variable superglobal de PHP

  • Contiene información sobre el servidor y la solicitud

  • REQUEST_METHOD indica el método HTTP usado (GET, POST, etc.)

3. Verificación de existencia del archivo

php
if (isset($_FILES['file'])) {
  • $_FILES es una variable superglobal para archivos subidos

  • isset() verifica si la variable existe y no es null

4. Verificación de contenido del archivo

php
if (!empty($_FILES['file']['name'])) {
  • empty() verifica si la variable está vacía

  • $_FILES['file']['name'] es el nombre original del archivo

  • Si está vacío, significa que no se seleccionó ningún archivo

5. Obtención del tipo de archivo

php
$fileType = $_FILES['file']['type'];
  • Almacena el tipo MIME del archivo

  • Útil para validar formatos soportados

El arreglo $_FILES en detalle

php
$_FILES['file'] = [
    'name' => 'mi_video.mp4',      // Nombre original del archivo
    'type' => 'video/mp4',         // Tipo MIME
    'tmp_name' => '/tmp/phpXyZ',   // Ruta temporal en el servidor
    'error' => 0,                  // Código de error
    'size' => 1234567              // Tamaño en bytes
];

Validaciones que podemos agregar

php
// 1. Verificar el tamaño del archivo (máximo 500MB)
$maxSize = 500 * 1024 * 1024; // 500 MB en bytes
if ($_FILES['file']['size'] > $maxSize) {
    $error = "El archivo es demasiado grande. Máximo 500MB";
}

// 2. Verificar la extensión del archivo
$allowedExtensions = ['mp4', 'mkv', 'avi', 'mov', 'mp3', 'wav'];
$extension = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));
if (!in_array($extension, $allowedExtensions)) {
    $error = "Formato de archivo no soportado";
}

// 3. Verificar el tipo MIME
$allowedTypes = ['video/mp4', 'video/x-msvideo', 'audio/mpeg', 'audio/wav'];
if (!in_array($_FILES['file']['type'], $allowedTypes)) {
    $error = "Tipo de archivo no soportado";
}

// 4. Verificar errores de subida
if ($_FILES['file']['error'] !== UPLOAD_ERR_OK) {
    $error = "Error al subir el archivo: " . $_FILES['file']['error'];
}

Códigos de error de subida

CódigoConstanteSignificado
0UPLOAD_ERR_OKNo hay errores, archivo subido correctamente
1UPLOAD_ERR_INI_SIZEEl archivo excede el tamaño máximo permitido por PHP
2UPLOAD_ERR_FORM_SIZEEl archivo excede el tamaño máximo del formulario
3UPLOAD_ERR_PARTIALEl archivo solo se subió parcialmente
4UPLOAD_ERR_NO_FILENo se subió ningún archivo
6UPLOAD_ERR_NO_TMP_DIRFalta la carpeta temporal
7UPLOAD_ERR_CANT_WRITEError al escribir el archivo en el disco
8UPLOAD_ERR_EXTENSIONUna extensión de PHP detuvo la subida

🔄 9. Flujo completo de la aplicación

Diagrama del flujo

text
1. Usuario selecciona archivo
   ↓
2. JavaScript detecta el cambio
   ↓
3. Muestra loader y oculta contenido
   ↓
4. Envía el formulario (POST)
   ↓
5. PHP recibe la solicitud
   ↓
6. Verifica que sea POST
   ↓
7. Verifica que exista el archivo
   ↓
8. Verifica que no esté vacío
   ↓
9. Obtiene el tipo de archivo
   ↓
10. [Próxima lección] Procesa con Whisper

Ejemplo de ejecución

Escenario 1: Usuario selecciona un archivo

text
1. Usuario: Clic en "Upload File"
2. Usuario: Selecciona "video.mp4"
3. JavaScript: Detecta cambio
4. JavaScript: Muestra loader
5. JavaScript: Envía formulario
6. PHP: Recibe POST
7. PHP: Verifica $_FILES['file']
8. PHP: $fileType = 'video/mp4'
9. PHP: Procesamiento exitoso

Escenario 2: Usuario no selecciona archivo

text
1. Usuario: Clic en "Upload File"
2. Usuario: Cierra el diálogo sin seleccionar
3. JavaScript: No detecta cambio (no se activa)
4. No ocurre nada (funciona correctamente)

Escenario 3: Usuario selecciona archivo pero ocurre error

text
1. Usuario: Selecciona "video.xyz" (formato no soportado)
2. JavaScript: Envía formulario
3. PHP: Recibe archivo
4. PHP: Verifica tipo MIME
5. PHP: $fileType = 'application/octet-stream'
6. PHP: [Validación falla]
7. PHP: $error = "Formato no soportado"
8. HTML: Muestra el error en rojo

🧪 10. Probando la validación

Pasos para probar:

  1. Abrir la aplicación:

    text
    http://localhost/whisper/
  2. Probar sin seleccionar archivo:

    • No pasa nada (comportamiento esperado)

  3. Probar seleccionando un archivo válido:

    • Se muestra el loader

    • Se envía el formulario

    • No hay errores (por ahora)

  4. Verificar el tipo de archivo:

    • Puedes agregar var_dump($fileType); para ver el tipo

    • El tipo aparecerá en la página después de subir

Debugging

Si quieres ver el tipo de archivo, puedes agregar esta línea temporalmente:

php
// Después de obtener $fileType
echo "<pre>";
var_dump($fileType);
echo "</pre>";
// Esto detendrá la ejecución para mostrar el tipo
die();

📌 11. Resumen de conceptos clave

ConceptoExplicación
$_SERVER['REQUEST_METHOD']Indica el método HTTP usado (GET, POST)
$_FILESArreglo con información de archivos subidos
isset()Verifica si una variable existe
empty()Verifica si una variable está vacía
$_FILES['file']['type']Tipo MIME del archivo
includeIncluye y evalúa un archivo PHP

🎯 12. Próximos pasos

Lo que hemos logrado

✅ Configuración inicial del proyecto
✅ Inclusión del archivo init.php
✅ Validación de la solicitud POST
✅ Verificación de existencia del archivo
✅ Obtención del tipo MIME
✅ Mostrar mensajes de error

Lo que viene en la próxima lección

En la siguiente lección vamos a:

  1. Crear una clase PHP para manejar la subida de archivos

  2. Validar el archivo completamente (tamaño, tipo, extensión)

  3. Mover el archivo a la carpeta de uploads

  4. Preparar el archivo para ser procesado por Whisper

Avance del código de la próxima lección

php
class FileUploader {
    private $allowedExtensions = ['mp4', 'mkv', 'avi', 'mov', 'mp3', 'wav'];
    private $maxSize = 500 * 1024 * 1024; // 500MB
    private $uploadDir = 'assets/uploads/';
    
    public function validate($file) {
        // Validar extensión
        // Validar tamaño
        // Validar tipo MIME
        // Devolver true/false
    }
    
    public function upload($file) {
        // Mover archivo a la carpeta de uploads
        // Generar nombre único
        // Devolver la ruta del archivo
    }
}

❓ Preguntas frecuentes

¿Por qué necesitamos include 'backend/init.php'?

  • Para centralizar todas las configuraciones y clases

  • Facilita el mantenimiento del código

¿Qué significa $_SERVER['REQUEST_METHOD'] === 'POST'?

  • Verifica que el formulario se haya enviado usando el método POST

  • Es una medida de seguridad para procesar solo solicitudes POST

¿Por qué usamos empty($_FILES['file']['name']) y no empty($_FILES['file'])?

  • $_FILES['file'] siempre existe aunque no haya archivo

  • $_FILES['file']['name'] está vacío si no hay archivo

  • Es una forma más precisa de verificar

¿Qué es el tipo MIME?

  • Es un estándar que identifica el formato de un archivo

  • Ejemplo: video/mp4 indica un archivo MP4

  • Útil para validar que el archivo sea del tipo esperado

¿Cómo puedo ver los errores de PHP?

  • Puedes usar error_reporting(E_ALL); al inicio del archivo

  • O revisar los logs de PHP en XAMPP


¡Excelente trabajo! Ahora tienes una validación básica de archivos en PHP. En la próxima lección, crearemos una clase dedicada para manejar la subida y validación de archivos de forma más robusta.

Comentarios

Entradas más populares de este blog

Cómo usar Whisper para sacar el texto de un video

Tutorial 18: Creando la Página de Visualización de Archivos Recientes

Tutorial 11: ¿Qué es Whisper AI y Cómo Funciona?