Download the PHP package phatnt93/php-upload-helper without Composer
On this page you can find all versions of the php package phatnt93/php-upload-helper. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download phatnt93/php-upload-helper
More information about phatnt93/php-upload-helper
Files in phatnt93/php-upload-helper
Package php-upload-helper
Short Description A modern, secure and fluent PHP file upload and image manipulation library with first-class multi-file array support, inspired by class.upload.php.
License MIT
Homepage https://github.com/phatnt93/php-upload-helper
Informations about the package php-upload-helper
PHP Upload Helper
English | Tiếng Việt
A modern, secure, and fluent PHP file upload and image processing library with first-class multi-file array support, inspired by the legendary verot/class.upload.php.
Table of Contents
- Why Use PHP Upload Helper?
- Key Advantages Over class.upload.php
- System Requirements & Setup
- Installation
- Quick Start
- Single File Upload
- Multi-File Array Upload (First-Class Support)
- Deeply Nested Multi-Dimensional Form Upload
- Real-World Practical Examples
- Example 1: User Profile Avatar with Automatic Crop & WebP
- Example 2: E-Commerce Product Gallery with Atomic Batch Rollback
- Example 3: Secure Document (PDF/Docx) Storage with Slug Naming
- Example 4: Sanitized SVG Vector Upload (Stored-XSS Immunity)
- Example 5: REST API / SPA Upload via Base64 or PSR-7
- Comprehensive Action Pipeline & API Reference
- Upload Factory API
- Security & Validation Layer
- File Naming Strategies
- Storage Engine & Collision Handling
- Image Manipulation (Resize Modes, Crop, Rotate, Watermark)
- Format Conversion & Compression
- Color Filters & Visual Effects
- SingleResult & ProcessedFile API
- BatchUploadBuilder & BatchResult API
- Multi-Variant Pipeline (Thumbnails & Previews)
- Lifecycle Hooks & Event Callbacks
- Framework Integration Guides
- Vanilla PHP Web Form
- Laravel Integration
- Symfony Integration
- Phalcon Integration
- Slim / PSR-7 Frameworks
- Internationalization & Error Codes Catalog
- Security Best Practices & Server Hardening
- Feature Comparison with verot/class.upload.php
- Using with AI Coding Agents
- Callback Signatures & Extension Contracts
- FAQ & Troubleshooting
- Automated Testing & Code Quality
- License & Credits
1. Why Use PHP Upload Helper?
Handling file uploads in native PHP is notorious for friction and security hazards:
- Chaotic Array Transposition: Native
$_FILESsplits multiple files into fragmented sub-arrays ($_FILES['photos']['name'][$i]), forcing developers to write repetitive matrix restructuring loops. - Client Header Trust Vulnerabilities: Checking
$_FILES['file']['type']is insecure because it is an untrusted client header trivially spoofed with cURL or Burp Suite. - Dangerous Extensions & Code Execution: Attackers easily bypass naive blacklists with
.phtml,.php5,.phar, double extensions (shell.php.png), or null-byte injections (shell.php\0.jpg). - Stored XSS in SVGs: Uploaded SVGs containing
<script>or inlineonloadhandlers execute scripts in users' browsers when rendered directly. - Orphan File Pollution: In batch uploads, if 9 out of 10 files succeed and the 10th fails, native PHP leaves orphan files cluttering storage.
- Verbose GD Syntax: Resizing or watermarking images using procedural GD functions requires dozens of boilerplate lines.
php-upload-helper provides an all-in-one, modern, type-safe Fluent Pipeline that encapsulates input normalization, deep binary sniffing, SVG sanitization, image processing, atomic storage, and batch rollback into elegant, chainable PHP 8.1+ syntax.
2. Key Advantages Over class.upload.php
| Feature | Native PHP (move_uploaded_file) |
verot/class.upload.php |
phatnt93/php-upload-helper |
|---|---|---|---|
| Multi-File Array Handling | ❌ None (Requires manual matrix transposition) | ❌ None (Requires manual matrix loops) | 🟢 First-class native support for flat & nested arrays |
| PHP Compatibility | Dependent on server PHP version | Legacy PHP 4/5/7/8 procedural class | 🟢 PHP 8.1 - 8.4+ with strict types and PSR-4 |
| Architecture | Low-level procedural primitives | Monolithic (~6,000 lines single file) | 🟢 Modular Action Pipeline (SRP, clean SOLID design) |
| MIME Validation | Insecure client type header |
Blacklist & basic finfo | 🟢 Strict Whitelist & Magic Bytes Sniffing |
| SVG Sanitization | ❌ None (Stored XSS vulnerability) | ❌ Vulnerable to Stored XSS | 🟢 Built-in XML/SVG script sanitizer |
| Batch Rollback | ❌ Manual file cleanup on error | ❌ None (Leaves orphan files on failure) | 🟢 All-or-nothing rollback on failure (rollbackOnError) |
| Alternative Inputs | Limited to $_FILES |
Limited | 🟢 $_FILES, PSR-7, Base64 URI, Remote URL, Local path |
| Image Drivers | Procedural boilerplate | Hardcoded GD calls | 🟢 Driver Abstraction (GD default, Imagick ready) |
| Server Hardening | ❌ Developer responsibility | Partial (Extension blacklists) | 🟢 Pixel flood, SSRF guard, double-ext, null-byte |
3. System Requirements & Setup
- PHP Compatibility: PHP
>= 8.1(tested on PHP 8.1, 8.2, 8.3, and 8.4 64-bit). - Core Extensions:
ext-fileinfo: Required for magic bytes binary MIME type inspection.ext-mbstring: Required for multibyte string manipulation, Vietnamese slug conversion, and UTF-8 font text rendering.ext-gd: Required for the default image manipulation engine.
- Optional Extensions:
ext-imagick: For advanced image manipulation and vector rendering.ext-exif: For automatic mobile photo orientation based on EXIF camera tags.
4. Installation
Install via Composer into your project:
Ensure your php.ini has adequate upload boundaries:
5. Quick Start
Single File Upload
Multi-File Array Upload (First-Class Support)
Say goodbye to manual foreach matrix restructuring for <input type="file" name="photos[]" multiple>!
Deeply Nested Multi-Dimensional Form Upload
Supports complex form inputs like <input type="file" name="catalog[category][items][0][attachments][]">:
6. Real-World Practical Examples
Example 1: User Profile Avatar with Automatic Crop & WebP
Enforce a clean square avatar, strip harmful metadata, resize to 300x300, and save in modern WebP:
Example 2: E-Commerce Product Gallery with Atomic Batch Rollback
Upload product photos in batch, apply watermarks, convert to progressive JPEG, and rollback if any photo is invalid:
Example 3: Secure Document (PDF/Docx) Storage with Slug Naming
Safely accept resumes or contracts, sanitize filenames (including Vietnamese accents), and auto-increment duplicates:
Example 4: Sanitized SVG Vector Upload (Stored-XSS Immunity)
SVGs can carry malicious <script> tags. With sanitizeSvg(true), the parser strips all scripts, event handlers (onload, onclick), and javascript: URIs before saving:
Example 5: REST API / SPA Upload via Base64 or PSR-7
Accept image uploads from mobile apps, Vue/React Canvas, or PSR-7 HTTP requests:
7. Comprehensive Action Pipeline & API Reference
Upload Factory API
Entry points from the UploadHelper\Upload facade:
Security & Validation Layer
All validation methods are available on UploadBuilder and BatchUploadBuilder:
| Method | Description | Example |
|---|---|---|
allowedExtensions(array $exts) |
Strict whitelist of allowed extensions (lowercase). | ->allowedExtensions(['jpg', 'png', 'pdf']) |
allowedMimes(array $mimes) |
Whitelist of MIME types validated via magic bytes. | ->allowedMimes(['image/jpeg', 'image/png']) |
maxSize(int\|string $maxSize) |
Maximum file size in bytes or human string (K, M, G). |
->maxSize('10M') or ->maxSize(10485760) |
minSize(int\|string $minSize) |
Minimum file size in bytes or human string. | ->minSize('5K') |
dimensionBetween(?int $minW, ?int $minH, ?int $maxW, ?int $maxH) |
Enforce bounding box constraints on images. | ->dimensionBetween(minW: 200, maxW: 1920) |
sanitizeSvg(bool $sanitize = true) |
Enable deep DOM XML sanitization to prevent Stored XSS. | ->sanitizeSvg(true) |
maxPixels(int $maxPixels) |
Prevent Decompression Bomb DoS by limiting max megapixels. | ->maxPixels(40_000_000) |
maxImageMemory(int\|string $maxMemory) |
Limit estimated uncompressed RGBA RAM before GD loading. | ->maxImageMemory('128M') |
blockPdfJavaScript(bool $block = true) |
Block active JavaScript, /Launch, and /EmbeddedFiles in PDF. | ->blockPdfJavaScript(true) |
blockOfficeMacros(bool $block = true) |
Block VBA Macros (vbaProject.bin) in Office documents. | ->blockOfficeMacros(true) |
scanner(ScannerInterface $scanner) |
Real-time Antivirus scan via ClamAV daemon socket. | ->scanner(new ClamAvScanner()) |
File Naming Strategies
| Method | Behavior | Example Output |
|---|---|---|
slugName() |
Converts original name to safe ASCII slug (supports Vietnamese). | Ảnh_đẹp 2026.png -> anh-dep-2026.png |
uuidName() |
Generates standard UUID v4. | 550e8400-e29b-41d4-a716-446655440000.png |
randomName(int $len = 16) |
Cryptographically secure hex string. | a9b3f021e78c45d2.png |
timestampName() |
Date and microsecond timestamp. | 20261015_153045_8912.png |
hashName(string $algo = 'sha256', int $len = 64) |
Content-addressable hash name of file body. | e3b0c44298fc1c14...png |
sha256Name(int $len = 64) |
Shortcut for SHA-256 hash naming. | a8b3c4...png |
name(string\|Closure $name) |
Set fixed name or compute dynamic name via Closure. | ->name('cover_image') |
prefix(string $prefix) |
Prepends prefix to filename. | ->prefix('thumb_') |
suffix(string $suffix) |
Appends suffix before extension. | ->suffix('_optimized') |
Storage Engine & Collision Handling
| Method | Description |
|---|---|
saveTo(string $destinationDir, int $chmod = 0755) |
Sets target directory, creates recursively with $chmod, and executes save. |
overwrite(bool $overwrite = true) |
Replaces destination file if it already exists. |
autoIncrementDuplicate(bool $auto = true) |
Automatically appends sequential suffix (_1, _2) if destination exists. |
hardenDestination(bool $harden = true) |
Automatically generates .htaccess, web.config, and index.html to block script execution. |
Image Manipulation (Resize Modes, Crop, Rotate, Watermark)
1. Resize Modes
fit(Default): Proportional scaling so the whole image fits inside$width×$height. Never distorts aspect ratio.crop: Scales and centers the image to completely fill the$width×$heightbox, cropping excess parts.pad: Fits the image proportionally inside the box and fills the outer space with$background(e.g.'#FFFFFF').stretch: Distorts the image to match the exact dimensions.withoutEnlarging(true): Prevents upscaling if original image is smaller than target dimensions.
2. Cropping, Rotating & Orientation
3. Watermarking
Format Conversion & Compression
| Method | Output Format | Key Options |
|---|---|---|
toWebp(int $quality = 85) |
WebP | $quality (1 - 100). Highly recommended for modern web. |
toJpeg(int $quality = 85) |
JPEG | $quality (1 - 100). Automatically saves in progressive format. |
toPng() |
PNG | Lossless compression with alpha channel preservation. |
toAvif(int $quality = 80) |
AVIF | Next-gen image format (requires PHP 8.1+ with AVIF GD support). |
Color Filters & Visual Effects
SingleResult & ProcessedFile API
Calling ->saveTo() or ->process() on UploadBuilder returns a SingleResult:
BatchUploadBuilder & BatchResult API
Calling ->process() on BatchUploadBuilder returns a BatchResult:
Multi-Variant Pipeline (Thumbnails & Previews)
Generate multiple derivative sizes, formats, or watermarked variants from a single uploaded file without re-uploading:
Lifecycle Hooks & Event Callbacks
Attach hooks to intercept and react during the upload lifecycle:
8. Framework Integration Guides
Vanilla PHP Web Form
Laravel Integration
In your Laravel Controller:
Symfony Integration
In your Symfony Controller:
Phalcon Integration
In your Phalcon Controller:
Slim / PSR-7 Frameworks
9. Internationalization & Error Codes Catalog
Setting the Active Locale
The default locale is English (en); Vietnamese (vi) ships with the library. Missing keys fall back to the active locale → en → the error code itself.
Messages returned by SingleResult::getErrorMessage() are translated with the active locale. Exceptions thrown inside the library always carry an English message; it is kept in getErrors()['context']['reason'] for logging. Unexpected internal errors are reported as ERR_INTERNAL with a generic message so that paths and internals never leak to end users.
Standardized Error Codes
The full message catalog lives in src/I18n/vi.php; both always contain the same keys (enforced by tests). Placeholders such as {extension} are filled from the error context.
| Group | Error codes |
|---|---|
| PHP upload errors | ERR_UPLOAD_INI_SIZE, ERR_UPLOAD_FORM_SIZE, ERR_UPLOAD_PARTIAL, ERR_UPLOAD_NO_FILE, ERR_UPLOAD_NO_TMP_DIR, ERR_UPLOAD_CANT_WRITE, ERR_UPLOAD_EXTENSION, ERR_UPLOAD_UNKNOWN, ERR_NO_FILE |
| Extension & MIME | ERR_EXTENSION_NOT_ALLOWED, ERR_MIME_NOT_ALLOWED, ERR_SECURITY_DANGEROUS_EXTENSION, ERR_SECURITY_DOUBLE_EXTENSION, ERR_SECURITY_NULL_BYTE, ERR_PATH_TRAVERSAL |
| Size & dimensions | ERR_FILE_TOO_LARGE, ERR_FILE_TOO_SMALL, ERR_NOT_AN_IMAGE, ERR_DIMENSION_MIN_WIDTH, ERR_DIMENSION_MAX_WIDTH, ERR_DIMENSION_MIN_HEIGHT, ERR_DIMENSION_MAX_HEIGHT, ERR_DIMENSION_EXACT_WIDTH, ERR_DIMENSION_EXACT_HEIGHT, ERR_DIMENSION_RATIO, ERR_IMAGE_PIXEL_FLOOD |
| Content security | ERR_INVALID_SVG_XML, ERR_PDF_JAVASCRIPT_DETECTED, ERR_PDF_LAUNCH_DETECTED, ERR_PDF_EMBEDDED_FILES_DETECTED, ERR_OFFICE_MACRO_DETECTED, ERR_VIRUS_DETECTED, ERR_SCANNER_ERROR |
| Remote URL (SSRF) | ERR_SSRF_INVALID_URL, ERR_SSRF_DISALLOWED_SCHEME, ERR_SSRF_DISALLOWED_PORT, ERR_SSRF_DNS_RESOLVE_FAILED, ERR_SSRF_BLOCKED, ERR_URL_DOWNLOAD_FAILED, ERR_URL_DOWNLOAD_TOO_LARGE, ERR_URL_TOO_MANY_REDIRECTS |
| Storage & processing | ERR_FILE_EXISTS, ERR_VARIANT_FAILED, ERR_PROCESS_FAILED, ERR_VALIDATION, ERR_INTERNAL |
10. Security Best Practices & Server Hardening
-
Store Uploads Outside the Web Root: Always store private files outside the public document root (e.g.,
/storage/uploadsinstead of/public/uploads) and serve them via a secure streaming controller with access authorization. -
Disable Script Execution in Upload Folders: If serving directly from Nginx, disable PHP execution in the public upload directory:
For Apache, place an
.htaccessfile inside your upload directory: - Always Whitelist Extensions:
Never use blacklists. Attackers continuously discover new executable suffixes (e.g.,
.php7,.pht,.shtml,.inc). Always pass explicit whitelists via->allowedExtensions(['jpg', 'png', 'pdf']).
11. Feature Comparison with verot/class.upload.php
verot/class.upload.php Property |
UploadHelper Fluent Action |
|---|---|
$foo->file_safe_name = true; |
->slugName() |
$foo->file_new_name_body = 'id'; |
->name('id') |
$foo->file_name_body_pre = 'pre_'; |
->prefix('pre_') |
$foo->file_name_body_add = '_post'; |
->suffix('_post') |
$foo->file_auto_rename = true; |
->autoIncrementDuplicate() |
$foo->file_overwrite = true; |
->overwrite(true) |
$foo->file_max_size = 5242880; |
->maxSize('5M') |
$foo->allowed = ['image/*']; |
->allowedMimes(['image/jpeg', 'image/png']) |
$foo->image_resize = true; |
->resize($w, $h, mode: 'fit') |
$foo->image_ratio_crop = true; |
->resize($w, $h, mode: 'crop') |
$foo->image_ratio_fill = true; |
->resize($w, $h, mode: 'pad') |
$foo->image_ratio_no_zoom_in = true; |
->withoutEnlarging() |
$foo->image_watermark = 'wm.png'; |
->watermarkImage('/path/wm.png') |
$foo->image_text = 'Copyright'; |
->watermarkText('Copyright') |
$foo->image_convert = 'webp'; |
->toWebp() |
$foo->image_greyscale = true; |
->grayscale() |
$foo->image_brightness = 20; |
->brightness(20) |
$foo->image_contrast = -10; |
->contrast(-10) |
$foo->dir_auto_create = true; |
Handled automatically in ->saveTo() |
12. Using with AI Coding Agents
If you use AI coding assistants (Claude Code, GitHub Copilot, Cursor, ChatGPT, Codex) in your project, you can provide them with machine-optimized context files:
- Quick LLM Guide:
vendor/phatnt93/php-upload-helper/llms.txt(API summary and common copy-paste recipes) - Deep Technical Reference:
vendor/phatnt93/php-upload-helper/llms-full.txt(complete class signatures, 100% error catalog, extensibility interfaces) - Standalone Examples:
examples/(executable reference scripts covering single file, batch upload, variants, and security)
Prompt Example for Your Project Rules
Add this line to your project's .cursorrules, CLAUDE.md, or AGENTS.md:
"When implementing file uploads or image processing in PHP, use
phatnt93/php-upload-helper. Refer tovendor/phatnt93/php-upload-helper/llms.txtfor fluent API usage and validation recipes."
13. Callback Signatures & Extension Contracts
All callback signatures in php-upload-helper are strictly typed and committed to backwards-compatibility within major versions:
| Method / Hook | Callback Signature | Timing / Purpose |
|---|---|---|
variant(string $name, callable $configurator) |
callable(UploadBuilder $builder): void |
Configures a derivative image variant pipeline |
each(callable $callback) (Batch) |
callable(UploadBuilder $builder, int $index): void |
Configures per-file rules in a batch |
beforeProcess(callable $callback) (Single) |
callable(UploadedFile $file): void |
Executed prior to validation and pipeline actions |
onSuccess(callable $callback) (Single) |
callable(ProcessedFile $file, SingleResult $result): void |
Executed only when file is successfully saved |
onError(callable $callback) (Single) |
callable(string $errorMessage, string $errorCode, SingleResult $result): void |
Executed when validation or processing fails |
afterProcess(callable $callback) (Single) |
callable(SingleResult $result): void |
Executed after pipeline finishes (success or failure) |
beforeProcess(callable $callback) (Batch) |
callable(FileCollection $collection): void |
Executed prior to processing batch |
onSuccess(callable $callback) (Batch) |
callable(BatchResult $result): void |
Executed when all files in batch succeed |
onError(callable $callback) (Batch) |
callable(BatchResult $result): void |
Executed when one or more files in batch fail |
afterProcess(callable $callback) (Batch) |
callable(BatchResult $result): void |
Executed after batch finishes (success or failure) |
name(Closure $custom) |
Closure(UploadedFile $file): string |
Custom dynamic filename generator |
Custom Extension Interfaces
To extend the library with custom logic:
- Custom Actions: Implement
UploadHelper\Contracts\ActionInterface(getName(): string,execute(UploadedFile $file, ActionContext $context): UploadedFile). - Custom Malware Scanners: Implement
UploadHelper\Contracts\ScannerInterface(scan(string $filePath): bool,getThreatName(): ?string). - Custom Storage Backends: Implement
UploadHelper\Contracts\StorageInterface(save(...),delete(...),exists(...)). - Custom Image Drivers: Implement
UploadHelper\Contracts\ImageDriverInterface.
14. FAQ & Troubleshooting
Q: Why do I get an empty $_FILES or immediate UPLOAD_ERR_INI_SIZE?
A: The file exceeds either upload_max_filesize or post_max_size in your active php.ini. Note that post_max_size must always be larger than or equal to upload_max_filesize. For multi-file uploads, post_max_size must be large enough to contain the sum of all files in the batch request.
Q: Why does toWebp() or toAvif() fail on my server?
A: Check if your PHP GD build was compiled with WebP or AVIF support:
If false, install libwebp-dev or libavif-dev and recompile/install the PHP GD extension.
Q: How do I create both a large preview and a small thumbnail from the same uploaded file?
A: Use the built-in multi-variant pipeline:
15. Automated Testing & Code Quality
Run the automated quality and test suites:
16. License & Credits
- License: Licensed under the MIT License.
- Author: Phat Nguyen (
[email protected]). - Inspiration: Special thanks to Colin Verot for the historical verot/class.upload.php.
All versions of php-upload-helper with dependencies
ext-fileinfo Version *
ext-mbstring Version *