A free and open-source book on ZF3 for beginners

Translation into this language is not yet finished. You can help this project by translating the chapters and contributing your changes.

10.1. Sobre la subida de archivos por HTTP

Los formularios HTML tienen la capacidad de subir archivos de un tamaño arbitrario 39. Los archivos son generalmente transmitidos a través del método POST HTTP 40.

39) La carga de archivos se describen en RFC-1867. Este mecanismo permite cargar grandes archivos usando la codificación de transferencia de contenido binario. El tipo de codificación «multipart/form-data» se utiliza para este propósito.

40) El método HTTP GET es ineficiente para cargar archivos, porque la longitud de la URL tiene un limite superior. Además, la codificación de la URL del archivo de datos incrementa enormemente la longitud de la URL.

Por defecto, HTTP usa la codificación URL para transferir los datos del formulario, podemos ver como esta codificación funciona en los capítulos anteriores. Sin embargo, esta codificación es ineficiente para cargar grandes archivos porque la codificación URL de datos binarios incrementa dramáticamente la longitud de las peticiones HTTP. Si el propósito es cargar archivos se recomienda en su lugar usar la «codificación de transferencia binaria» que se describe en la sección siguiente.

10.1.1. Codificación de transferencia binaria de HTTP

Un formulario HTML simple capaz de cargar archivos se muestra en el código de ejemplo más abajo. El tipo de codificación binaria se habilita colocando el atributo enctype del formulario con el valor «multipart/form-data»:

<form action="upload" method="POST" enctype="multipart/form-data">
    <input type="file" name="myfile">
    <br/>
    <input type="submit" name="Submit">
</form>

En la línea 1, colocamos explícitamente la codificación (atributo enctype) «multipart/form-data» para utilizar la codificación de transferencia de contenido binario en el formulario.

En la línea 2, definimos un campo de entrada de tipo «file» y con el nombre «myfile». Este campo de entrada permitirá al visitante del sitio seleccionar el archivo que se cargará.

Si guardamos el código HTML mencionado arriba en un archivo .html y lo abrimos en nuestro navegador web, veremos una página como la que se muestra en la figura 10.1.

Figura 10.1. Un formulario HTML simple capaz de subir un archivo Figura 10.1. Un formulario HTML simple capaz de subir un archivo

El elemento file tiene el botón Browse... que permite seleccionar el archivo que se subirá. Cuando el usuario del sitio selecciona el archivo y hace clic en el botón Submit del formulario, el navegador web enviará una petición HTTP al servidor web y la petición contendrá los datos del archivo que será subido. El ejemplo de abajo ilustra como se ve una petición HTTP:

POST http://localhost/upload HTTP/1.1
Host: localhost
Content-Length: 488
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64)
Content-Type: multipart/form-data; boundary=----j1bOrwgLvOC3dy7o
Accept-Encoding: gzip,deflate,sdch

------j1bOrwgLvOC3dy7o
Content-Disposition: form-data; name="myfile"; filename="Somefile.txt"
Content-Type: text/html

(file binary data goes here)
------j1bOrwgLvOC3dy7o
Content-Disposition: form-data; name="Submit"

Submit Request
------j1bOrwgLvOC3dy7o--

Como podemos ver en el ejemplo de arriba, la petición HTTP con el tipo de codificación «multipart/form-data» tiene un aspecto análogo a una petición HTTP usual (tiene la línea de estado, las cabeceras y el area de contenido), sin embargo tiene las siguientes e importantes diferencias:

Por defecto, las configuraciones del motor de PHP no permiten cargar grandes archivos (más grandes que 2MB). Para subir grandes archivos, necesitamos editar el archivo de configuración php.ini y modificar los parámetros post_max_size y upload_max_filesize (podemos revisar el Apéndice A. Configuración del Entorno de Desarrollo Web para información de como hacer esto). Colocando estos parámetros en 100M se permite subir archivos de un tamaño de 100 Mb, este valor es generalmente suficiente. Si nuestro plan es subir archivos muy grandes, hasta 1GB, es mejor colocar este valor en 1024M. No olvidemos reiniciar nuestro Servidor Web Apache después de editar el archivo de configuración.

10.1.2. El arreglo super-global $_FILES en PHP

Cuando el visitante del sitio carga algunos archivos al Servidor Web Apache, los archivo se colocan en una ubicación temporal (generalmente en la carpeta temporal del sistema, en GNU/Linux /tmp y en Windows C:\Windows\Temp). El código PHP recibe la información sobre el archivo del arreglo especial super-global $_FILES.

El arreglo $_FILES es análogo a las variables super-globales $_GET y $_POST. Estas últimas se usan para guardar las variables GET y POST, respectivamente, mientras la primera se usa para guardar información sobre archivos subidos.

Por ejemplo, para el formulario simple de subida que mencionamos antes, el arreglo super-global $_FILES tiene la siguiente forma (la salida se genero con la función de PHP var_dump()).

array (size=1)
    'myfile' =>
        array (size=5)
            'name' => string 'somefile.txt' (length=12)
            'type' => string 'text/plain' (length=10)
            'tmp_name' => string '/tmp/phpDC66.tmp' (length=16)
            'error' => int 0
            'size' => int 18

Como podemos ver del ejemplo de arriba, el arreglo $_FILES contiene una entrada por cada archivo subido. Y por cada archivo subido contiene la siguiente información

As you can see from the example above, the $_FILES array contains an entry per each uploaded file. For each uploaded file, it contains the following information:

41) el tipo MIME también conocido como «tipo contenido» (content type) es un identificador estándar en internet para indicar el tipo de dato que contiene el archivo. Por ejemplo el tipo MIME «text/plain» se asigna a un archivo de texto, mientras que el tipo MIME «application/octet-stream» se asigna a un archivo binario.

El motor de PHP almacena los archivos subidos en una ubicación temporal que se limpia luego de que el script de PHP termina de ejecutarse. Así que, si queremos guardar el archivos subido en alguna carpeta para usarlo posteriormente, necesitamos usar la función de PHP move_uploaded_file(). La función move_uploaded_file() toma dos argumentos: el primero de ellos es el nombre del archivo temporal y el segundo es el nombre del archivo de destino.

Puede confundirnos el hecho de no poder usar la función de PHP rename() para mover el archivo subido temporalmente a su ruta de destino. Por razones de seguridad PHP tiene una función especial para mover los archivos subidos. La función move_uploaded_file() es análoga a la función rename(), pero aquella hace algunas revisiones adicionales para asegurar que el archivo se transfirió a través de una petición HTTP POST y que el proceso de carga terminó sin errores.

El siguiente código de ejemplo muestra como mover el archivo subido con el formulario simple que hemos mostrado arriba:

$destPath = '/path/to/your/upload/dir';
$result = move_uploaded_file($_FILES['myfile']['tmp_name'], $destPath);
if(!$result) {
    // Some error occurred.
}

Arriba en la línea 1, creamos la variable $destPath con el nombre de la carpeta en donde se guardará el archivo subido.

En la línea 2, llamamos a la función move_uploaded_file() y le pasamos dos argumentos: la ruta del archivo temporal y la ruta de destino.

Especificar solo el nombre de la carpeta como segundo argumento de la función move_uploaded_file() es útil cuando no queremos renombrar el archivo. Si necesitamos guardar el archivo subido con otro nombre diferente al original debemos especificar la ruta de archivo completa en lugar del nombre de la carpeta.

En la línea 3, revisamos el valor regresado por la función. Si la operación es exitosa, la función regresará true. Si ocurre algún error (por ejemplo, si los permisos de la carpeta no son suficientes para guardar el archivo) se regresará el booleano false.


Top