Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

File Type Detector Laravel Package

brandembassy/file-type-detector

Detect file type and MIME by filename extension or by inspecting binary/stream content. Returns category, format, and MIME on success (or false). Includes a helper to resolve MIME only. Install via composer: brandembassy/file-type-detector.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require brandembassy/file-type-detector
    

    Add to composer.json if using a monorepo or custom package management.

  2. First Use Case: Detect a file's MIME type from its filename (e.g., in a file upload handler):

    use BrandEmbassy\FileTypeDetector\Detector;
    
    $filename = 'example.pdf';
    $result = Detector::detectByFilename($filename);
    
    if ($result) {
        $mimeType = $result[2]; // e.g., 'application/pdf'
        // Use $mimeType in Laravel (e.g., for Storage::put())
    }
    
  3. Key Classes:

    • Detector: Core class for detection methods.
    • FileInfo: Object returned by newer methods (e.g., detectFromContent()), encapsulating type, format, and MIME type.

Implementation Patterns

Common Workflows

1. File Upload Handling

  • Pattern: Validate and process uploaded files in Laravel controllers.
  • Example:
    use Illuminate\Http\Request;
    use BrandEmbassy\FileTypeDetector\Detector;
    
    public function upload(Request $request)
    {
        $file = $request->file('document');
        $stream = fopen($file->getPathname(), 'r');
    
        $fileInfo = Detector::detectFromContent($stream);
        fclose($stream);
    
        if ($fileInfo->getMimeType() === 'image/jpeg') {
            // Process as JPEG
        }
    }
    

2. Dynamic File Serving

  • Pattern: Serve files with correct headers based on MIME type.
  • Example:
    use Symfony\Component\HttpFoundation\BinaryFileResponse;
    
    public function serveFile($path)
    {
        $mime = Detector::getMimeType($path);
        return response()->file($path, [
            'Content-Type' => $mime,
        ]);
    }
    

3. Extension-to-MIME Mapping

  • Pattern: Convert file extensions to MIME types for APIs or storage.
  • Example:
    $extension = pathinfo($filename, PATHINFO_EXTENSION);
    $mime = Detector::resolveMimeTypeFromExtension($extension);
    

4. Stream-Based Detection

  • Pattern: Detect MIME types for remote files or non-seekable streams (e.g., HTTP streams).
  • Example:
    $stream = fopen('http://example.com/file.pdf', 'r');
    $fileInfo = Detector::detectFromContent($stream);
    // Handle stream without seeking (supports non-seekable resources)
    

5. Fallback Logic

  • Pattern: Combine filename and content detection for robustness.
  • Example:
    $byFilename = Detector::detectByFilename($filename);
    $byContent = Detector::detectByContent($filePath);
    
    $result = $byContent ?: $byFilename;
    

Integration Tips

Laravel-Specific

  • Service Provider Binding: Bind Detector as a singleton in AppServiceProvider for dependency injection:

    public function register()
    {
        $this->app->singleton(Detector::class);
    }
    
  • Form Request Validation: Use the package to validate file types in FormRequest classes:

    public function rules()
    {
        return [
            'file' => 'required|file',
        ];
    }
    
    public function withValidator($validator)
    {
        $file = $this->file;
        $mime = Detector::getMimeType($file->getPathname());
    
        $validator->after(function ($validator) use ($mime) {
            if (!in_array($mime, ['image/jpeg', 'image/png'])) {
                $validator->errors()->add('file', 'Invalid file type.');
            }
        });
    }
    
  • Storage Disk Integration: Use MIME types to optimize storage (e.g., public disk for web-accessible files):

    $mime = Detector::getMimeType($filePath);
    $path = "uploads/{$mime}/{$file->hashName()}";
    
    Storage::disk('public')->put($path, file_get_contents($filePath));
    

Performance

  • Cache Results: Cache MIME type detections for frequently accessed files (e.g., using Laravel's cache):

    $cacheKey = "mime:{$filePath}";
    $mime = Cache::remember($cacheKey, now()->addHours(1), function () use ($filePath) {
        return Detector::getMimeType($filePath);
    });
    
  • Batch Processing: For bulk operations (e.g., migrating files), process files in chunks and reuse Detector instances.


Gotchas and Tips

Pitfalls

1. Non-Seekable Streams

  • Issue: detectByContent() may fail on non-seekable streams (e.g., HTTP streams) if not using detectFromContent().
  • Fix: Use Detector::detectFromContent($stream) for streams that cannot be rewound.

2. False Positives/Negatives

  • Issue: File extensions may be misleading (e.g., .jpg.txt). Content detection is more reliable but slower.
  • Fix: Combine both methods or prioritize content detection for critical files:
    $byContent = Detector::detectByContent($filePath);
    $byFilename = Detector::detectByFilename($filePath);
    $result = $byContent ?: $byFilename;
    

3. Case Sensitivity

  • Issue: File extensions are case-sensitive in some systems (e.g., .JPG vs .jpg).
  • Fix: Normalize extensions before detection:
    $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
    

4. Memory Usage

  • Issue: Large files may consume significant memory when read entirely for content detection.
  • Fix: Use streams or limit read size (e.g., read first 1KB for detection):
    $stream = fopen($filePath, 'r');
    $buffer = fread($stream, 1024); // Read first 1KB
    $fileInfo = Detector::detectFromContent($buffer);
    fclose($stream);
    

5. Unsupported Formats

  • Issue: Rare or custom file formats may not be detected.
  • Fix: Extend the package by adding custom signatures (see extension points).

Debugging

1. Verify Detection Logic

  • Log results to debug mismatches:
    $result = Detector::detectByContent($filePath);
    logger()->debug('Detection result', [
        'filename' => $filePath,
        'result' => $result,
        'mime' => $result ? $result[2] : 'unknown',
    ]);
    

2. Check File Integrity

  • Ensure files are not corrupted (e.g., partial uploads). Use filesize() or md5_file() to verify.

3. Test Edge Cases

  • Test with:
    • Files without extensions.
    • Files with spaces or special characters in names.
    • Empty files or zero-byte files.

Tips

1. Extension Points

  • Custom Signatures: Extend detection by adding new file signatures. Override the Detector class or use composition:

    class CustomDetector extends Detector
    {
        protected function getSignatures(): array
        {
            return array_merge(
                parent::getSignatures(),
                [
                    'CUSTOM_FORMAT' => [
                        'signatures' => ['\x00CUSTOM'],
                        'mime' => 'application/x-custom',
                    ],
                ]
            );
        }
    }
    
  • Custom MIME Types: Add mappings in Detector::getMimeTypes():

    protected function getMimeTypes(): array
    {
        return array_merge(
            parent::getMimeTypes(),
            ['application/x-custom' => 'custom']
        );
    }
    

2. Configuration Quirks

  • PHP Version: Requires PHP 8.2+. Use rector to upgrade if needed.
  • Dependencies: Ensure no conflicts with other packages using finfo (e.g., symfony/mime).

3. Testing

  • Unit Tests: Mock Detector in tests:

    $mockDetector = Mockery::mock(Detector::class);
    $mockDetector->shouldReceive('detectByFilename')
        ->with('test.pdf')
        ->andReturn(['PDF', 'PDF', 'application/pdf']);
    $this->app->instance(Detector::class, $mockDetector);
    
  • Test Data: Use a mix of:

    • Files with known extensions (e.g., .pdf, .jpg
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
craftcms/url-validator
directorytree/privacy-filter-classifier
directorytree/privacy-filter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity
testo/bridge-symfony