1tomany/data-uri
Parse data URIs, base64 strings, plain text, URLs, or local files into a temporary file via an immutable value object. Auto-detect or override MIME type, set an optional display name, and the temp file is deleted automatically on destruct.
Install the package:
composer require 1tomany/data-uri
Basic usage (decode a data URI):
use OneToMany\DataUri\DataDecoder;
$dataUri = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...';
$file = DataDecoder::decode($dataUri);
// Access file properties
echo $file->getName(); // e.g., 'image.png'
echo $file->getFormat(); // e.g., 'image/png'
$content = $file->getContent(); // Binary content
First use case: Handle base64-encoded images from a frontend API:
$requestData = $request->json()->all();
$imageData = $requestData['image']; // Base64 string
$file = DataDecoder::decodeBase64($imageData, 'image/png', 'user-upload.png');
Storage::put('uploads/' . $file->getName(), $file->getContent());
DataDecoder::decode() for versatility (handles URIs, URLs, and files).decode.php for practical patterns.DataUriInterface methods (getName(), getContent(), getStream()) for integration.// Decode a data URI from an API payload (e.g., Slack message attachments)
$attachment = $response['files'][0];
$dataUri = $attachment['file']['url_private'] ?? $attachment['file']['url'];
$file = DataDecoder::decode($dataUri, null, 'image.jpg');
// Save to Laravel storage
Storage::disk('public')->put('attachments/' . $file->getName(), $file->getContent());
// Process pasted data URIs from TinyMCE/CKEditor
$htmlContent = $request->input('content');
preg_match_all('/data:image\/(?<type>\w+);base64,(?<data>[^"]+)/', $htmlContent, $matches);
foreach ($matches['data'] as $index => $base64Data) {
$file = DataDecoder::decodeBase64($base64Data, 'image/' . $matches['type'][$index]);
$uploadedPath = Storage::disk('public')->putFileAs(
'editor-uploads',
new \Illuminate\Http\File($file->getStream()),
$file->getName()
);
$htmlContent = str_replace($matches[0][$index], asset('storage/' . $uploadedPath), $htmlContent);
}
// Job: ProcessDataUriJob
public function handle() {
$dataUri = $this->dataUri;
$file = DataDecoder::decode($dataUri);
// Process file (e.g., OCR, thumbnail generation)
$processed = $this->processFile($file);
// Save metadata
Metadata::create([
'original_name' => $file->getClientName(),
'mime_type' => $file->getFormat(),
'processed_data' => $processed,
]);
}
// Download and process a remote file without full download
$remoteUrl = 'https://example.com/large-file.zip';
$file = DataDecoder::decode($remoteUrl, null, 'archive.zip');
// Stream to a zip library for extraction
$zip = new \ZipArchive();
$zip->openFromString($file->getContent());
// app/Services/DataUriService.php
class DataUriService {
public function decodeAndStore(string $dataUri, string $disk = 'public'): string {
$file = DataDecoder::decode($dataUri);
return Storage::disk($disk)->putFileAs(
'data-uri-uploads',
new \Illuminate\Http\File($file->getStream()),
$file->getName()
);
}
}
// app/Http/Middleware/ValidateDataUri.php
public function handle($request, Closure $next) {
$dataUri = $request->input('data_uri');
try {
$file = DataDecoder::decode($dataUri);
if (!in_array($file->getFormat(), ['image/jpeg', 'image/png'])) {
abort(400, 'Unsupported MIME type');
}
} catch (\Exception $e) {
abort(400, 'Invalid data URI');
}
return $next($request);
}
// app/Providers/AppServiceProvider.php
public function register() {
$this->app->bind(\League\Flysystem\Filesystem::class, function () {
$adapter = new \League\Flysystem\Local\LocalFilesystemAdapter(
storage_path('app/data-uri-cache')
);
return new \League\Flysystem\Filesystem($adapter);
});
}
// Usage in a controller
$filesystem = app(\League\Flysystem\Filesystem::class);
$file = DataDecoder::decode($dataUri);
$filesystem->writeStream($file->getName(), $file->getStream());
Auto-Deletion Behavior:
DataUriInterface object is destroyed or garbage collected.$file = DataDecoder::decode($dataUri);
$content = $file->getContent(); // Store this if you need persistence
MIME Type Auto-Detection:
mime_content_type() may return generic types (e.g., text/plain for .md files).type parameter when possible for accuracy.
$file = DataDecoder::decode($dataUri, null, 'document.md', 'text/markdown');
Large File Handling:
memory_limit) may still be hit for very large data URIs.decodeBase64() for large base64 strings and process in chunks if needed.URL Validation:
Http client before passing to DataDecoder.
use Illuminate\Support\Facades\Http;
$response = Http::get($url);
if ($response->successful()) {
$file = DataDecoder::decode($response->body());
}
Filename Preservation:
name parameter is optional and may fall back to a random name.$name = parse_url($dataUri, PHP_URL_HOST) ? basename(parse_url($dataUri, PHP_URL_PATH)) : null;
$file = DataDecoder::decode($dataUri, $name);
Stringable Objects:
\Stringable (e.g., Laravel’s HtmlString).$stringableObj = new \Illuminate\Support\HtmlString('<div>...</div>');
$file = DataDecoder::decode((string) $stringableObj);
Check File Content:
$file = DataDecoder::decode($dataUri);
file_put_contents('debug-' . $file->getName(), $file->getContent());
Log MIME Types:
$file = DataDecoder::decode($dataUri);
logger()->debug('Detected MIME type', ['type' => $file->getFormat()]);
Handle Exceptions:
try {
$file = DataDecoder::decode($dataUri);
} catch (\InvalidArgumentException $e) {
logger()->error('Invalid data URI', ['uri' => $dataUri, 'error' => $e->getMessage()]);
abort(400, 'Invalid data URI');
}
FileType enum (if needed) or override MHow can I help you explore Laravel packages today?