Añadir mime personalizada Tipos de adivinanzas en Laravel

Estoy tratando de subir un archivo .imed formato. Es un formato raro y Laravel lo detecta como application/zip que está bien. Pero además de que Laravel guarda mi archivo como hash_name.zip

Cuando trato de obtener la extensión de archivo subido por:

var_dump($data['file_uri']->extension());

Tengo string(3) "zip"

Hice algunas investigaciones y encontré que Laravel está usando el componente Symfony MimeType para adivinar el mimetipo de archivo. No sé si esto es posible, pero en Symfony docs hay una sección sobre el registro de MimeTypeGuesser personalizado. La instrucción es para Symfony y podrían no ser aplicables para Laravel.

La otra solución para mi problema sería cambiar el archivo después de guardarlo en el servidor desde hash_name.zip a hash_name.imed

Algunos de mis códigos responsables de subir un archivo:

class ScanRepository implements ScanInterface
{

    public function createScan(array $data)
    {
        $scan = new Scan();

        $scan->file_uri = "/storage/scans/" . $data['file_uri']->hashName();

        $scan->save();
    }

Registered Observer

class ScanObserver
{
    /**
     * Handle the scan "created" event.
     *
     * @param Scan $scan
     * @return void
     */
    public function created(Scan $scan)
    {
        Storage::disk('scans')->putFileAs('', request()->file('file_uri'), basename($scan->file_uri));
    }

Cargar funcionalidad funciona, pero guarda mis datos en diferentes extensiones de archivo.

Pregunta hecha hace 3 años, 5 meses, 0 días - Por codejuggernaut


3 Respuestas:

  • Terminé con este tipo de solución:

    public function createScan(array $data)
    {
        $scan = new Scan();
    
        $hash = $data['file_uri']->hashName();
    
        // We have to override filename extension to .iMed, because Laravel detects it as .zip
        $scan->file_uri = "/storage/scans/" . preg_replace('/\..+$/', '.' . 'iMed', $hash);
    
        $scan->save();
    }
    

    Puede que no sea el mejor elegante, pero funciona.

    También he intentado registrar CustomMimeTypeGuesser utilizando

    MimeTypes::getDefault()->registerGuesser(new CustomMimeTypeGuesser());

    Y crear un adivinador personalizado que implementa

    class CustomMimeTypeGuesser implements MimeTypeGuesserInterface
    {
        public function isGuesserSupported(): bool
        {
            return true;
        }
        public function guessMimeType(string $path): ?string
        {
            /* 
               Returning here a string .imed doesn't give anything because Symfony MimeType component
               still try to map mimetype to file extension. So if he doesn't not now anything about .imed he will return null at the end 
               */
        }
    }
    
    

    Respondida el Dec 17, 2020 a las 18:46 - por markupmaestro

    Votos positivos: 0 | Votos negativos: 0

  • Para añadir una mime personalizada en Laravel y evitar que el archivo se guarde con la extensión incorrecta, puedes seguir estos pasos:

    • Crear un MimeTypeGuesser personalizado:
    - Crea una clase que implemente la interfaz `Symfony\Component\Mime\MimeTypesInterface`.
    • Sobrescribe el método `getDefaultExtension()` para devolver la extensión correcta para tu tipo de archivo personalizado. Por ejemplo, para el tipo de archivo `.imed`, puedes devolver `'imed'`.
    • Registrar el MimeTypeGuesser personalizado en Laravel:
    - Puedes agregar esta lógica en un ServiceProvider de Laravel.
    • Utiliza el método `Mime::addExtensionGuesser()` para agregar tu MimeTypeGuesser personalizado.
    • Modificar tu lógica de subida de archivos para usar la extensión correcta:
    - Una vez que Laravel pueda detectar la extensión correcta para tu tipo de archivo, actualiza tu lógica para guardar el archivo con la extensión correcta. Aquí tienes un ejemplo de cómo podrías implementar estos pasos:
    • Crear un MimeTypeGuesser personalizado:
    php
    // app/MimeTypes/CustomMimeTypeGuesser.php
    
    namespace App\MimeTypes;
    
    use Symfony\Component\Mime\MimeTypesInterface;
    
    class CustomMimeTypeGuesser implements MimeTypesInterface
    {
        public function getDefaultExtension(string $mimeType): string
        {
            if ($mimeType === 'application/imed') {
                return 'imed'; // Definir la extensión correcta para el tipo de archivo .imed
            }
    
            // Devolver la extensión predeterminada para otros tipos de archivo
            return (new MimeTypes())->getExtensions($mimeType)[0] ?? '';
        }
    }
    
    • Registrar el MimeTypeGuesser personalizado en Laravel:
    php
    // app/Providers/AppServiceProvider.php
    
    namespace App\Providers;
    
    use Illuminate\Support\ServiceProvider;
    use Symfony\Component\Mime\MimeTypes;
    
    class AppServiceProvider extends ServiceProvider
    {
        public function register()
        {
            // Agregar el MimeTypeGuesser personalizado
            Mime::addExtensionGuesser(new CustomMimeTypeGuesser());
        }
    }
    
    • Modificar tu lógica de subida de archivos para usar la extensión correcta:
    php
    // class ScanRepository
    
    public function createScan(array $data)
    {
        $scan = new Scan();
    
        $extension = $data['file_uri']->guessExtension() ?: 'zip';
    
        // Cambiar la extensión a 'imed' si es necesario
        if ($extension === 'zip' && $data['file_uri']->getMimeType() === 'application/imed') {
            $extension = 'imed';
        }
    
        $scan->file_uri = "/storage/scans/" . $data['file_uri']->hashName() . '.' . $extension;
    
        $scan->save();
    }
    

    Con estos cambios, tu aplicación debería poder detectar y utilizar la extensión correcta para el archivo .imed y guardarlo con la extensión adecuada en el servidor. Asegúrate de ajustar estos ejemplos según tu estructura de directorios y nombres de clases en tu proyecto Laravel.

    Respondida el Dec 18, 2020 a las 18:47 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Puedes utilizar el método guessExtension del componente MimeType de Symfony para obtener la extensión del archivo subido:

    php
    use Symfony\Component\Mime\MimeTypes;
    
    $mimeTypes = new MimeTypes();
    $extension = $mimeTypes->guessExtension($data['file_uri']->getMimeType());
    

    Esto devolverá la extensión del archivo, por ejemplo, "imed" en tu caso. Puedes utilizar esta extensión para guardar el archivo con el nombre correcto:

    php
    $scan->file_uri = "/storage/scans/" . $data['file_uri']->hashName() . '.' . $extension;
    

    Ten en cuenta que esto no modifica el tipo MIME del archivo, solo cambia el nombre del archivo guardado. Si deseas cambiar el tipo MIME, puedes utilizar el método overrideMimeType del componente MimeType:

    php
    $mimeTypes->overrideMimeType($data['file_uri']->getMimeType(), 'application/imed');
    

    Esto cambiará el tipo MIME del archivo a "application/imed".

    Respondida el Dec 18, 2020 a las 18:52 - por Gemini

    Votos positivos: 0 | Votos negativos: 0