bcncommerce/stream-wrapper
Laravel package providing a custom PHP stream wrapper to transparently read/write resources via non-standard URIs. Useful for integrating external storage or services behind fopen/file_get_contents with a familiar filesystem-like API.
Installation:
composer require bcncommerce/stream-wrapper
Add to composer.json if not using Composer:
"require": {
"bcncommerce/stream-wrapper": "^1.0"
}
Basic Usage:
Register the wrapper in your application’s bootstrap (e.g., bootstrap/app.php or AppServiceProvider):
use BCNCommerce\StreamWrapper\StreamWrapper;
StreamWrapper::register('mywrapper', function ($path) {
return new MyCustomStream($path);
});
First Use Case:
Redirect file operations (e.g., fopen(), file_get_contents()) to a custom stream:
$file = fopen('mywrapper://example.txt', 'r');
// Handle file operations...
fclose($file);
Stream Redirection:
file_get_contents(), file_put_contents()) with custom logic.$content = file_get_contents('mywrapper://remote/file.txt');
Integration with Laravel:
Storage facade or Filesystem contracts:use Illuminate\Support\Facades\Storage;
Storage::disk('custom')->put('file.txt', 'Hello');
// Register wrapper for 'custom' disk in `config/filesystems.php`.
Dynamic Path Handling:
user://123/data into userId=123 and file=data).StreamWrapper::register('user', function ($path) {
[$userId, $file] = explode('/', ltrim($path, '/'), 2);
return new UserFileStream($userId, $file);
});
Context-Aware Streams:
StreamWrapper::register('request', function ($path, $context) {
return new RequestFileStream($path, $context['user']);
});
Stream Context Conflicts:
stream_context_create() may override wrapper behavior. Explicitly set context:$context = stream_context_create(['mywrapper' => ['option' => 'value']]);
file_get_contents('mywrapper://file.txt', false, $context);
Case Sensitivity:
mywrapper:// ≠ MyWrapper://).Resource Leaks:
fclose() or use try-finally blocks to avoid memory leaks with custom streams.Laravel Caching:
Storage, clear cached disks after registering new wrappers:Storage::disk('custom')->clear();
var_dump(stream_get_wrappers()); // Verify 'mywrapper' appears.
set_error_handler(function ($errno, $errstr) {
if (strpos($errstr, 'mywrapper') !== false) {
Log::error($errstr);
}
});
Custom Stream Classes:
StreamWrapperInterface for advanced features (e.g., locking, seeking):class MyStream implements StreamWrapperInterface {
public function stream_open($path, $mode, $options, &$opened_path) { ... }
// Implement other required methods.
}
Wrapper Chaining:
mywrapper://http://example.com/file):StreamWrapper::register('mywrapper', function ($path) {
return fopen('http://' . $path, 'r');
});
Performance:
stream_wrapper_restore() to reset state between requests.How can I help you explore Laravel packages today?