php-standard-library/file
Typed file handles for safe reading and writing in PHP, with explicit write modes and advisory file locking. Part of PHP Standard Library, designed to make filesystem IO clearer and less error-prone.
Installation:
composer require php-standard-library/file:^6.1
Add to composer.json under require or require-dev based on your needs.
Basic Usage:
use PhpStandardLibrary\File\FileHandler;
// Initialize with a file path
$fileHandler = new FileHandler('/path/to/file.txt');
// Read file content
$content = $fileHandler->read();
First Use Case: Validate a file’s signature (e.g., checksum) before processing:
$isValid = FileHandler::validateFileSignature(
'/path/to/uploaded-file.zip',
'sha256:expected_hash_here'
);
FileHandler (main class) and FileLock (for advisory locking).Typed File Handles: Use explicit modes for read/write operations to avoid accidental overwrites:
// Read-only handle
$readHandle = new FileHandler('/path/to/file.txt', 'r');
// Write handle with append mode
$writeHandle = new FileHandler('/path/to/file.txt', 'a');
Atomic Writes: Ensure critical files (e.g., configs, cache) are written atomically:
FileHandler::atomicWrite(
'/path/to/config.json',
json_encode(['key' => 'value'])
);
Advisory Locking: Coordinate concurrent access in CLI jobs or queues:
$lock = new FileLock('/path/to/locked-file.tmp');
$lock->acquire();
try {
// Critical section
} finally {
$lock->release();
}
Streaming Large Files: Process files without loading them entirely into memory:
$fileHandler = new FileHandler('/path/to/large-video.mp4', 'r');
while (!$fileHandler->eof()) {
$chunk = $fileHandler->readChunk(4096);
// Process chunk
}
File Validation Workflow:
$filePath = storage_path('uploads/plugin.zip');
$expectedSignature = 'sha256:abc123...';
if (!FileHandler::validateFileSignature($filePath, $expectedSignature)) {
throw new \RuntimeException('Invalid plugin file!');
}
Secure File Upload Handling:
$uploadedFile = $request->file('plugin');
$tempPath = $uploadedFile->getRealPath();
$signature = 'sha256:'.hash_file('sha256', $tempPath);
// Store signature in DB for later validation
$plugin->signature = $signature;
$plugin->save();
// Move to permanent location
$fileHandler = new FileHandler(storage_path("plugins/{$plugin->id}.zip"), 'w');
$fileHandler->write($uploadedFile->get());
Concurrent File Processing:
$lockFile = storage_path('processing.lock');
$lock = new FileLock($lockFile);
if ($lock->acquire()) {
try {
// Process file (e.g., generate a report)
$report = generateReport();
FileHandler::atomicWrite(
storage_path('reports/latest.json'),
$report
);
} finally {
$lock->release();
}
} else {
// Another process is running; retry or notify
}
Laravel Service Container:
Bind the FileHandler to Laravel’s IoC container for dependency injection:
$this->app->singleton(FileHandler::class, function () {
return new \PhpStandardLibrary\File\FileHandler();
});
Facade for Convenience: Create a facade to simplify usage in Blade or controllers:
// app/Facades/FileHandlerFacade.php
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class FileHandlerFacade extends Facade
{
protected static function getFacadeAccessor()
{
return 'file.handler';
}
}
Custom Validation Rules: Extend Laravel’s validation rules for file signatures:
use PhpStandardLibrary\File\FileHandler;
class ValidateFileSignature extends FormRequest
{
public function rules()
{
return [
'file' => [
'required',
function ($attribute, $value, $fail) {
$path = $value->getRealPath();
$signature = $this->getExpectedSignature();
if (!FileHandler::validateFileSignature($path, $signature)) {
$fail('The file signature is invalid.');
}
},
],
];
}
}
Event Listeners for File Operations: Trigger events before/after file operations for logging or side effects:
use PhpStandardLibrary\File\FileHandler;
FileHandler::addListener('beforeWrite', function ($path, $mode) {
\Log::info("Writing to file: {$path} in mode: {$mode}");
});
FileHandler::addListener('afterRead', function ($path, $content) {
\Log::debug("Read from file: {$path}");
});
File Locking Limitations:
FileLock) are not enforced by the OS. Processes must cooperate to release locks.try-finally or try-catch-finally to ensure locks are released, even if an exception occurs.Path Normalization:
\ to /), but ensure paths are absolute for cross-platform compatibility.storage_path(), public_path(), or base_path() to generate absolute paths.Permission Issues:
if (!is_writable(dirname($path))) {
throw new \RuntimeException("Directory is not writable: " . dirname($path));
}
Memory Usage with Large Files:
read()) can cause issues with large files.readChunk() for streaming:
$fileHandler = new FileHandler('/path/to/large-file.log', 'r');
while (!$fileHandler->eof()) {
$chunk = $fileHandler->readChunk(8192); // Read 8KB at a time
// Process chunk
}
Signature Validation Edge Cases:
validateFileSignature() may fail for:
\r\n vs. \n).try {
if (!FileHandler::validateFileSignature($path, $signature)) {
throw new \RuntimeException('Invalid file signature.');
}
} catch (\PhpStandardLibrary\File\InvalidSignatureException $e) {
\Log::error("File validation failed: " . $e->getMessage());
// Handle error (e.g., notify admin, reject upload)
}
Check File Handles:
$fileHandler = new FileHandler('/path/to/file.txt', 'r');
try {
$content = $fileHandler->read();
} finally {
$fileHandler->close(); // Explicitly close
}
finally blocks or context managers (e.g., try-with-resources in PHP 8.1+).Locking Issues:
$lock = new FileLock('/path/to/lock.tmp');
if (!$lock->acquire(5)) { // Timeout after 5 seconds
throw new \RuntimeException('Could not acquire lock.');
}
Path Resolution:
realpath() to debug path issues:
$path = realpath('/path/to/file.txt');
if ($path === false) {
throw new \RuntimeException("Path does not exist or is invalid.");
}
How can I help you explore Laravel packages today?