webservco / file
A PHP component/library. File value objects, plus CSV and ZIP creation and PSR-7 responses for sending a file to the browser.
Requires
- php: ^8.4
- ext-zip: *
- psr/http-factory: ^1
- psr/http-message: ^2
Requires (Dev)
- pds/skeleton: ^1
- phan/phan: ^6
- php-parallel-lint/php-console-highlighter: ^1
- php-parallel-lint/php-parallel-lint: ^1
- phpmd/phpmd: ^3
- phpstan/phpstan: ^2
- phpstan/phpstan-deprecation-rules: ^2
- phpstan/phpstan-phpunit: ^2
- phpstan/phpstan-strict-rules: ^2
- phpunit/phpunit: ^13
- slevomat/coding-standard: ^8
- squizlabs/php_codesniffer: ^4
- vimeo/psalm: ^6
- webservco/coding-standards: ^2
- webservco/component-common: ^2
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
A PHP component/library. Please see webservco/sandbox for an example project using these types of components.
File value objects, plus CSV and ZIP creation and PSR-7 responses for sending a file to the browser.
- Requires:
ext-zip(forZipArchiveService), a PSR-17 implementation such aswebservco/http - Related:
webservco/log(writes its files withFileService)
Installation
composer require webservco/file
Usage
Download a CSV built from database rows
use WebServCo\File\Factory\Response\DownloadResponseFactory; use WebServCo\File\Service\CSV\DataCreatorService; use WebServCo\File\Service\CSV\FileCreatorService; $fileCreatorService = new FileCreatorService( // \WebServCo\File\Contract\Service\CSV\DataCreatorServiceInterface: delimiter, enclosure. new DataCreatorService(',', '"'), // PSR-17: \Psr\Http\Message\StreamFactoryInterface $streamFactory, ); // $rows: any Iterator, for example a generator over a query, or new ArrayIterator($array). // true: use the keys of the first row as the header line. // \WebServCo\File\ValueObject\CSVFile $file = $fileCreatorService->createCsvFileFromIterator('report.csv', $rows, true); // PSR-17: \Psr\Http\Message\ResponseFactoryInterface $downloadResponseFactory = new DownloadResponseFactory($responseFactory); return $downloadResponseFactory->createDownloadResponse($file);
Show a PDF in the browser
use WebServCo\File\Factory\FileFactory; use WebServCo\File\Factory\Response\OutputResponseFactory; $fileFactory = new FileFactory($streamFactory); // \WebServCo\File\Contract\FileInterface $file = $fileFactory->createPdfFromPath('/path/to/invoice.pdf', 'invoice.pdf'); $outputResponseFactory = new OutputResponseFactory($responseFactory); return $outputResponseFactory->createOutputResponse($file);
Read a CSV file that may start with a byte order mark
use WebServCo\File\Service\File\ByteOrderMarkService; $filePointerResource = fopen('/path/to/export.csv', 'r'); // Skips a UTF-8 byte order mark, if there is one; otherwise the file is read from its start. (new ByteOrderMarkService())->skipUtf8ByteOrderMark($filePointerResource); while (($line = fgetcsv($filePointerResource, 0, ',', '"', '')) !== false) { // ... } fclose($filePointerResource);
Contracts
| Interface | Implementation | Purpose |
|---|---|---|
Contract\FileInterface |
ValueObject\File, ValueObject\CSVFile, ValueObject\PdfFile |
Content type, name, size and data stream. |
Contract\FileFactoryInterface |
Factory\FileFactory |
Creates files from a path or a string (generic, CSV, PDF). |
Contract\Service\CSV\DataCreatorServiceInterface |
Service\CSV\DataCreatorService |
Turns an iterator of rows into CSV text. |
| none | Service\CSV\FileCreatorService |
Turns an iterator of rows into a CSVFile. |
| none | Factory\Response\DownloadResponseFactory |
Response with Content-Disposition: attachment. |
| none | Factory\Response\OutputResponseFactory |
Response that shows the file inline. |
| none | Service\Archive\ZipArchiveService |
Zips one file into a directory and returns the archive file name ({name}.zip). |
| none | Service\File\FileService |
Creates directories and appends data to a file. |
| none | Service\File\ByteOrderMarkService |
Skips a UTF-8 byte order mark at the start of an open file, before reading it. |
Namespaces are relative to WebServCo\File\.
Notes
CSV data starts with a UTF-8 byte order mark. Excel needs it to show accented characters correctly. The header line comes from the first row's keys. Give every row the same keys.
fgetcsv doesn't skip that byte order mark: it stays in the first value, and a quoted first field keeps its quotes. To read such a file back, call ByteOrderMarkService::skipUtf8ByteOrderMark() right after opening it. ByteOrderMarkService::UTF8_BYTE_ORDER_MARK holds the mark that DataCreatorService writes.
ZIP archives are compressed with LZMA2. Some unzip tools, including older built-in ones, can't open them.
Development
# Start project. ddev start # Install dependencies. ddev c u # Run all validations. ddev c c # Run unit tests. ddev c test:dox