Skip to content

Instantly share code, notes, and snippets.

@fmagrosoto
Last active July 7, 2024 22:47
Show Gist options
  • Save fmagrosoto/723d7a5acec719ad7705ac730be4abb2 to your computer and use it in GitHub Desktop.
Save fmagrosoto/723d7a5acec719ad7705ac730be4abb2 to your computer and use it in GitHub Desktop.
Clase especial de PHP para poder subir un archivo al servidor y poder validar varias cosas, como el peso y el tipo MIME
<?php
/**
* CLASE PARA SUBIR UN ARCHIVO A LA CARPETA PASADA COMO PARÁMETRO
*
* Hay casos donde deberemos de estar subiendo archivos al servidor. Antes de subirlos,
* deberemos de estar validando el peso y el formato. Y una vez subido el archivo, deberemos
* de regresar el nombre del archivo, debidamente limpiado y con una marca de tiempo para
* evitar que haya duplicados y se sobreescriban. Será entonces cuando podamos almacenar
* en una base de datos el nombre del archivo.
*
* @author Fernando Magrosoto V.
* @since v1.0.0
* @license MIT
* @package helpers
*/
namespace helpers;
use Exception;
use Web;
class SubirArchivoHelper
{
/**
* CARGAR EL ARCHIVO
*
* Se deberá de llamar a este método siempre y cuando se haya validado que no haya un campo vacío
* de archivo. Y de preferencia, antes de cualquier cosa, para evitar que se guarde un registro
* con el archivo vacío. Pero si el campo el opcional, entonces deberás de pensar en el mejor
* momento para llamar a este método. Vas a necesitar los siguientes parámetros.
*
* @internal Recuerda usar enctype multipart/form-data en el formulario, para permitir subir archivos
* @param string $campo Nombre del campo del formulario del archivo
* @param string $elPath La ruta donde se irá a almacenar el archivo, sin slashes ni al inicio ni al final
* @param int $peso El peso máximo permitido en bytes, ej. 2MB = (1024 * 1024 * 2)
* @param array $tiposPermitidos Los MIME de los tipos permitidos en un array, ej: ['application/pdf', 'image/png']
* @return string El nombre del archivo limpio y acortado
* @throws Exception
*/
public static function cargarArchivo(string $campo, string $elPath, int $peso, array $tiposPermitidos): string
{
$web = Web::instance();
// Validar que no pese más del peso solicitado
if ($_FILES[$campo]['size'] > $peso) {
throw new Exception('El archivo pesa más de lo solicitado.');
}
// Validar que el archivo sea un PDF
$tipoArchivo = mime_content_type($_FILES[$campo]['tmp_name']);
if (!in_array($tipoArchivo, $tiposPermitidos)) {
throw new Exception('El archivo no tiene el formato solicitado.');
}
// Luego, limpiar el nombre del archivo. Le vamos a quitar espacios, acentos, caracteres especiales y
// vamos a pasar a minúsculas el nombre completo, incluyendo la extensión.
// Uso SLUG para limpiar la cadena de texto, que es parte de Fat Free Framework, pero se puede usar
// cualquier otro método.
$extension = $web->slug(pathinfo($_FILES[$campo]['name'], PATHINFO_EXTENSION));
$nombreSinExtension = $web->slug(str_replace(
$extension,
'',
pathinfo($_FILES[$campo]['name'], PATHINFO_BASENAME)
));
// Y vamos a hacer que el nombre no mida más de 35 caracteres
if (strlen($nombreSinExtension) > 35) {
$nombreSinExtension = substr($nombreSinExtension, 0, 35);
}
// Armamos el nombre completo (limpio y acortado)
// OJO, el campo usado para el nombre del archivo en la BD es VARCHAR(50)
// Entonces, 35 caracteres del nombre del archivo, más 5 caracteres del mini token, porque
// no quiero que haya duplicados, más 4 ó 5 caracteres de la extensión
// (incluyendo el punto) = 50 caracteres máximo (hasta sobran).
$nombreArchivo = mt_rand(10000, 19999) . '-' . $nombreSinExtension . '.' . $extension;
// Y lo grabamos
if (!is_dir($elPath)) {
mkdir($elPath, 0777, true);
}
if (move_uploaded_file($_FILES[$campo]['tmp_name'], $elPath . '/' . $nombreArchivo) === false) {
throw new Exception();
}
// Retornamos el nombre completo del archivo
return $nombreArchivo;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment