Trabajar con archivos cargados

Higgs hace que trabajar con archivos cargados a través de un formulario sea mucho más simple y seguro que usar $_FILES de PHP matriz directamente. Esto extiende la clase File y así obtiene todas las características de esa clase.

Nota

This is not the same as the File Uploading class in Higgs v3.x. This provides a raw Interfaz para los archivos cargados con algunas características pequeñas.

El proceso

Cargar un archivo implica el siguiente proceso general:

  • Se muestra un formulario de carga, que permite al usuario seleccionar un archivo y

    subirlo.

  • Cuando se envía el formulario, el archivo se carga en el destino.

    tu específicas.

  • A lo largo del camino, el archivo se valida para garantizar que se permita su

    cargado según las preferencias que establezca.

  • Una vez subido, al usuario se le mostrará un mensaje de éxito.

Para demostrar este proceso aquí hay un breve tutorial. Después podrás encontrar información de referencia.

Creando el formulario de carga

Usando un editor de texto, cree un formulario llamado upload_form.php. En él, coloque este código y guárdelo en su directorio app/Views/:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Upload Form</title>
</head>
<body>

<?php foreach ($errors as $error): ?>
    <li><?= esc($error) ?></li>
<?php endforeach ?>

<?= form_open_multipart('upload/upload') ?>
    <input type="file" name="userfile" size="20">
    <br><br>
    <input type="submit" value="upload">
</form>

</body>
</html>

Notarás que estamos usando un asistente de formulario para crear la etiqueta de apertura del formulario. Las cargas de archivos requieren un formulario de varias partes, por lo que el asistente crea el formulario adecuado. sintaxis para usted. También notarás que tenemos una variable $errors. Esto es para que podamos mostrar mensajes de error en caso de que el usuario haga algo equivocado.

La página del éxito

Usando un editor de texto, cree un formulario llamado upload_success.php. En eso, coloque este código y guárdelo en su directorio app/Views/:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Cargar formulario</title>
</head>
<body>

<h3>¡Su archivo se cargó exitosamente!</h3>

<ul>
    <li>nombre:<?= esc($uploaded_fileinfo-> obtenerNombreBase()) ?></li>
    <li>tamaño:<?= esc($uploaded_fileinfo-> getSizeByUnit('kb')) ?> KB</li>
    <li>extensión:<?= esc($uploaded_fileinfo-> SupongoExtensión()) ?></li>
</ul>

<p><?= anchor('upload', 'Upload Another File!') ?></p>

</body>
</html>

El controlador

Usando un editor de texto, cree un controlador llamado Upload.php. En él, coloque este código y guárdelo en su directorio app/Controllers/:

<?php

namespace App\Controllers;

use Higgs\Files\File;

class Upload extends BaseController
{
    protected $helpers = ['form'];

    public function index()
    {
        return view('upload_form', ['errors' => []]);
    }

    public function upload()
    {
        $validationRule = [
            'userfile' => [
                'label' => 'Image File',
                'rules' => [
                    'uploaded[userfile]',
                    'is_image[userfile]',
                    'mime_in[userfile,image/jpg,image/jpeg,image/gif,image/png,image/webp]',
                    'max_size[userfile,100]',
                    'max_dims[userfile,1024,768]',
                ],
            ],
        ];
        if (! $this->validateData([], $validationRule)) {
            $data = ['errors' => $this->validator->getErrors()];

            return view('upload_form', $data);
        }

        $img = $this->request->getFile('userfile');

        if (! $img->hasMoved()) {
            $filepath = WRITEPATH . 'uploads/' . $img->store();

            $data = ['uploaded_fileinfo' => new File($filepath)];

            return view('upload_success', $data);
        }

        $data = ['errors' => 'The file has already been moved.'];

        return view('upload_form', $data);
    }
}

Nota

Since the value of a file upload HTML field doesn’t exist, and is stored in the $_FILES global, Sólo rules-for-file-uploads se puede utilizar para validar el archivo cargado con Validation. La regla required tampoco se puede usar, así que use uploaded en su lugar.

Las Rutas

Usando un editor de texto, abra app/Config/Routes.php. En él, agregue las siguientes dos rutas:

<?php

// ...

/*
 * --------------------------------------------------------------------
 * Route Definitions
 * --------------------------------------------------------------------
 */

// We get a performance increase by specifying the default
// route since we don't have to scan directories.
$routes->get('/', 'Home::index');

$routes->get('upload', 'Upload::index');          // Add this line.
$routes->post('upload/upload', 'Upload::upload'); // Add this line.

// ...

El directorio de carga

Los archivos cargados se almacenan en el directorio writable/uploads/.

¡Intentalo!

Para probar su formulario, visite su sitio usando una URL similar a esta:

ejemplo.com/index.php/upload/

Deberías ver un formulario de carga. Intente cargar un archivo de imagen (ya sea un jpg, gif, png o webp). Si la ruta en su controlador es correcta, debería trabajar.

Accediendo a archivos

Todos los archivos

Cuando subes archivos, se puede acceder a ellos de forma nativa en PHP a través del superglobal $_FILES. Esta matriz tiene algunos importantes deficiencias al trabajar con varios archivos cargados a la vez, y tiene posibles fallos de seguridad para muchos desarrolladores no son conscientes de. Higgs ayuda con ambas situaciones al estandarizar el uso de archivos detrás de un interfaz común.

Se accede a los archivos a través de la instancia actual IncomingRequest. Para recuperar todos los archivos que se cargaron con este solicitud, utilice getFiles(). Esto devolverá una matriz de archivos representados por instancias de Higgs\HTTP\Files\UploadedFile:

<?php

$files = $this->request->getFiles();

Por supuesto, hay varias formas de nombrar la entrada del archivo, y cualquier cosa que no sea la más simple puede generar resultados extraños. La matriz regresa de la manera esperada. Con el uso más simple, se podría enviar un solo archivo como:

<input type=»file» name=»avatar»>

Lo que devolvería una matriz simple como:

[
    'avatar' => // Instancia de archivo cargado,
];

Nota

The UploadedFile instance corresponds to $_FILES. Even if a user just clicks the submit button and does not upload any file, the instance will still exist. You can check that the file was actually uploaded by the isValid() method in UploadedFile. See Verificar un archivo.

Si usó una notación de matriz para el nombre, la entrada se vería así:

<input type=»file» name=»my-form[details][avatar]»>

La matriz devuelta por getFiles() se parecería más a esto:

[
     'mi-formulario' => [
        'detalles' => [
            'avatar' => // instancia de archivo subido
        ],
    ],
]

En algunos casos, puede especificar una serie de archivos para cargar:

Sube un avatar:<input type="file" name="my-form[details][avatars][]">
Sube un avatar:<input type="file" name="my-form[details][avatars][]">

En este caso, la matriz de archivos devuelta sería más parecida a:

[
    'mi-formulario' => [
        'detalles' => [
            'avatar' => [
                0 => // Instancia de archivo cargado,
                1 => // Instancia de archivo cargado,
            ],
        ],
    ],
]

Fila india

Si sólo necesita acceder a un único archivo, puede utilizar getFile() para recuperar la instancia del archivo directamente. Esto devolverá una instancia de Higgs\HTTP\Files\UploadedFile:

Uso más simple

Con el uso más simple, se podría enviar un solo archivo como:

<input type=»file» name=»userfile»>

Lo que devolvería una instancia de archivo simple como:

<?php

$file = $this->request->getFile('userfile');

Notación de matriz

Si usó una notación de matriz para el nombre, la entrada se vería así:

<input type=»file» name=»my-form[details][avatar]»>

Para obtener la instancia del archivo:

<?php

$file = $this->request->getFile('my-form.details.avatar');

Varios archivos

<input type="file" name="images[]" multiple>

En controlador:

<?php

if ($imagefile = $this->request->getFiles()) {
    foreach ($imagefile['images'] as $img) {
        if ($img->isValid() && ! $img->hasMoved()) {
            $newName = $img->getRandomName();
            $img->move(WRITEPATH . 'uploads', $newName);
        }
    }
}

donde imágenes es un bucle desde el nombre del campo del formulario.

Si hay varios archivos con el mismo nombre, puede utilizar getFile() para recuperar cada archivo individualmente.

En controlador:

<?php

$file1 = $this->request->getFile('images.0');
$file2 = $this->request->getFile('images.1');

Puede que le resulte más fácil utilizar getFileMultiple() para obtener una serie de archivos cargados con el mismo nombre:

<?php

$files = $this->request->getFileMultiple('images');

Otro ejemplo:

Sube un avatar:<input type="file" name="my-form[details][avatars][]">
Sube un avatar:<input type="file" name="my-form[details][avatars][]">

En controlador:

<?php

$file1 = $this->request->getFile('my-form.details.avatars.0');
$file2 = $this->request->getFile('my-form.details.avatars.1');

Nota

Using getFiles() is more appropriate.

Trabajar con el archivo

Una vez que haya recuperado la instancia de UploadedFile, podrá recuperar información sobre el archivo de forma segura, así como mueva el archivo a una nueva ubicación.

Verificar un archivo

Puedes comprobar que un archivo se cargó realmente a través de HTTP sin errores llamando al método isValid():

<?php

if (! $file->isValid()) {
    throw new \RuntimeException($file->getErrorString() . '(' . $file->getError() . ')');
}

Como se ve en este ejemplo, si un archivo tuvo un error de carga, puede recuperar el código de error (un número entero) y el error mensaje con los métodos getError() y getErrorString(). Los siguientes errores se pueden descubrir a través de este método:

  • El archivo excede su directiva ini upload_max_filesize.

  • El archivo excede el límite de carga definido en su formulario.

  • El archivo se cargó solo parcialmente.

  • Ningun archivo fue subido.

  • El archivo no se pudo escribir en el disco.

  • No se pudo cargar el archivo: falta el directorio temporal.

  • La carga del archivo fue detenida por una extensión PHP.

Nombres de archivos

obtenerNombre()

Puede recuperar el nombre de archivo original proporcionado por el cliente con el método getName(). Este será normalmente el nombre de archivo enviado por el cliente y no debe ser confiable. Si el archivo se ha movido, esto devolverá el nombre final de el archivo movido:

<?php

$name = $file->getName();

obtenerNombreCliente()

Siempre devuelve el nombre original del archivo cargado tal como lo envió el cliente, incluso si el archivo se ha movido:

<?php

$originalName = $file->getClientName();

getTempName()

Para obtener la ruta completa del archivo temporal que se creó durante la carga, puede utilizar el método getTempName():

<?php

$tempfile = $file->getTempName();

Otra información del archivo

obtenerExtensiónCliente()

Devuelve la extensión del archivo original, según el nombre del archivo que se cargó:

<?php

$ext = $file->getClientExtension();

Advertencia

This is NOT a trusted source. For a trusted version, use guessExtension() instead.

getClientMimeType()

Devuelve el tipo mime (tipo mime) del archivo proporcionado por el cliente. Este NO es un valor confiable. Para un confiable versión, use getMimeType() en su lugar:

<?php

$type = $file->getClientMimeType();

echo $type; // image/png

obtenerRutaCliente()

Nuevo en la versión 4.4.0.

Devuelve la ruta relativa del webkit<https://developer.mozilla.org/en-US/docs/Web/API/File/webkitRelativePath> _ del archivo cargado cuando el cliente ha subido archivos mediante la carga del directorio. En versiones de PHP inferiores a 8.1, esto devuelve nulo

<?php

$clientPath = $file->getClientPath();
echo $clientPath; // dir/file.txt, or dir/sub_dir/file.txt

Mover archivos

con nombre de archivo original

Cada archivo se puede mover a su nueva ubicación con el método move(), apropiadamente llamado. Esto toma el directorio para moverse. el archivo como primer parámetro:

<?php

$file->move(WRITEPATH . 'uploads');

De forma predeterminada, se utilizó el nombre de archivo original.

con nuevo nombre de archivo

Puede especificar un nuevo nombre de archivo pasándolo como segundo parámetro:

<?php

$newName = $file->getRandomName();
$file->move(WRITEPATH . 'uploads', $newName);

Sobrescribir archivo existente

De forma predeterminada, si el archivo de destino ya existe, se utilizará un nuevo nombre de archivo. Por ejemplo, si nombre_imagen.jpg ya existe en el directorio, entonces el El nombre del archivo será nombre_imagen_1.jpg automáticamente.

Puede sobrescribir el archivo existente pasando true como tercer parámetro:

<?php

$file->move(WRITEPATH . 'uploads', null, true);

Compruebe si el archivo se movió

Una vez que se ha eliminado el archivo, se elimina el archivo temporal. Puedes comprobar si un archivo ya se ha movido con el método hasMoved(), que devuelve un valor booleano:

<?php

if ($file->isValid() && ! $file->hasMoved()) {
    $file->move($path);
}

Cuando la mudanza falla

Mover un archivo cargado puede fallar, con una excepción HTTP, en varias circunstancias:

  • el archivo ya ha sido movido

  • el archivo no se cargó correctamente

  • la operación de movimiento de archivos falla (por ejemplo, permisos inadecuados)

Almacenar archivos

Cada archivo se puede mover a su nueva ubicación con el método store(), apropiadamente llamado.

Con el uso más simple, se podría enviar un solo archivo como:

<input type=»file» name=»userfile»>

De forma predeterminada, los archivos cargados se guardan en el directorio escribible/cargas. La carpeta AAAAMMDD y se creará un nombre de archivo aleatorio. Devuelve una ruta de archivo:

<?php

$path = $this->request->getFile('userfile')->store();

Puede especificar un directorio al que mover el archivo como primer parámetro. Un nuevo nombre de archivo por pasándolo como segundo parámetro:

<?php

$path = $this->request->getFile('userfile')->store('head_img/', 'user_name.jpg');

Mover un archivo cargado puede fallar, con una HTTPException, en varias circunstancias:

  • el archivo ya ha sido movido

  • el archivo no se cargó correctamente

  • la operación de movimiento de archivos falla (por ejemplo, permisos inadecuados)