- Main Features
- Version Information
- System Requirements
- Installation and Configuration
- Using Static API Key Authentication
- Upload a Single File
- Upload Multiple Files
- Example Using PHP and cURL
- Using HMAC Signature Authentication
- Image Optimizer and WebP Conversion
- Response Structure
- Cloudflare R2 and BunnyCDN
- Cloudflare R2
- BunnyCDN Storage
- WordPress Integration
- JavaScript Integration
- Security and Optimization
- Common Errors and Solutions
- Extensions and Customization
Main Features
Init Uploader provides all the essential features for a professional-grade image upload system:
- Flexible Uploads: Supports both single-file and bulk uploads, optimizing time when you need to upload multiple images at once.
- Directory Management: Organize images using custom path structures, e.g.
manga-123/chapter-5/page-01.jpg, for easy management and categorization. - Detailed Information: Automatically returns full URLs, width, height, file size, and storage path for each image after successful upload.
- High Security: Supports two authentication methods – a static API Key for simplicity or an HMAC signature with timestamp for replay attack prevention.
- HTTPS Enforcement: Optionally require HTTPS connections to ensure secure data transmission.
- Strict Validation: Validates file type, size, extension, and MIME type to ensure only valid image files are accepted.
- Smart Handling: Automatically creates directories, renames duplicate files, and logs detailed information for easy debugging.
- Image Optimizer: Built-in automatic image resize and optimization pipeline supporting JPEG, PNG, and WebP formats.
- WebP Conversion: Automatically converts JPEG and PNG images to WebP format for smaller file sizes and faster loading. GIF files are automatically skipped to preserve animations.
- Cloudflare R2: Direct upload support for Cloudflare R2 using pure PHP + cURL with AWS Signature V4, without requiring the AWS SDK.
- BunnyCDN Storage: Direct upload support for BunnyCDN Storage Zones with HTTP API and regional endpoint support.
- CDN Fallback: Automatically falls back to local storage if CDN upload fails, preventing service interruptions.
- Automatic Local Cleanup: Optional automatic deletion of local files after successful CDN uploads to save server storage.
Version Information
- Version: 1.2.0
- Updated: 2026-05-27
System Requirements
To deploy Init Uploader, your server must meet the following minimum requirements:
- PHP: Version 7.4 or higher. PHP 8.0+ is recommended for best performance.
- Extensions: Requires the
gdorimagickextension to read image dimensions, andfileinfoto validate MIME types. - Write Permissions: The uploads directory must be writable (chmod 755 or 775) so the server can save files.
- HTTPS: If REQUIRE_HTTPS is enabled, you must configure a valid SSL certificate on the server.
- Domain/Subdomain: A domain or subdomain pointing to the server to access images after upload.
Installation and Configuration
After downloading the init-uploader.php file, open it and adjust the CONFIGURATION section at the top:
define('API_KEY', 'your-secret-api-key-here-change-this');
define('SECRET_KEY', 'your-secret-hmac-key-change-this');
define('USE_HMAC_AUTH', true);
define('UPLOAD_DIR', __DIR__ . '/uploads');
define('BASE_URL', 'https://your-domain.com');
define('MAX_FILE_SIZE', 10 * 1024 * 1024);
define('REQUIRE_HTTPS', true);
define('OPTIMIZER_ENABLED', true);
define('OPTIMIZER_MAX_WIDTH', 900);
define('OPTIMIZER_JPEG_QUALITY', 80);
define('OPTIMIZER_PNG_LEVEL', 6);
define('OPTIMIZER_CONVERT_TO_WEBP', true);
define('OPTIMIZER_WEBP_QUALITY', 82);
define('R2_ENABLED', false);
define('R2_ACCOUNT_ID', 'your-account-id');
define('R2_ACCESS_KEY_ID', 'your-r2-access-key-id');
define('R2_SECRET_ACCESS_KEY', 'your-r2-secret-access-key');
define('R2_BUCKET', 'your-bucket-name');
define('R2_PUBLIC_URL', 'https://your-public-url.com');
define('BUNNY_ENABLED', false);
define('BUNNY_STORAGE_ZONE', 'your-storage-zone');
define('BUNNY_API_KEY', 'your-bunny-api-key');
define('BUNNY_STORAGE_REGION', 'storage.bunnycdn.com');
define('BUNNY_PUBLIC_URL', 'https://your-zone.b-cdn.net');
Key parameters to update:
- API_KEY: The secret key for simple authentication, should be a random string at least 32 characters long.
- SECRET_KEY: Secret key for HMAC signatures, used only when USE_HMAC_AUTH is enabled.
- USE_HMAC_AUTH: Set to true for higher security (HMAC auth), or false for simple static key authentication.
- BASE_URL: The base domain URL, e.g. https://cdn.example.com or https://example.com/cdn.
- MAX_FILE_SIZE: Maximum allowed file size in bytes, default is 10MB.
Upload init-uploader.php to your server, ensure the uploads folder is writable, and you’re ready to go.
Using Static API Key Authentication
The simplest method is to use a static API Key. Set USE_HMAC_AUTH to false in the config, then send requests with the X-API-Key header.
Upload a Single File
curl -X POST https://your-domain.com/init-uploader.php \
-H "X-API-Key: your-secret-api-key" \
-F "file=@/path/to/image.jpg" \
-F "path=manga-123/chapter-1"
Upload Multiple Files
curl -X POST https://your-domain.com/init-uploader.php \
-H "X-API-Key: your-secret-api-key" \
-F "files[]=@/path/to/image1.jpg" \
-F "files[]=@/path/to/image2.jpg" \
-F "files[]=@/path/to/image3.jpg" \
-F "path=manga-123/chapter-1"
Example Using PHP and cURL
<?php
$ch = curl_init('https://your-domain.com/init-uploader.php');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'X-API-Key: your-secret-api-key'
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, [
'file' => new CURLFile('/path/to/image.jpg'),
'path' => 'manga-123/chapter-1'
]);
$response = curl_exec($ch);
$result = json_decode($response, true);
if ($result['success']) {
foreach ($result['data']['files'] as $file) {
echo "URL: " . $file['url'] . "\n";
echo "Width: " . $file['width'] . "px\n";
echo "Height: " . $file['height'] . "px\n";
}
}
curl_close($ch);
?>
Using HMAC Signature Authentication
HMAC signatures provide stronger security by combining timestamps with a secret key. Each request is valid only within a certain time window, preventing replay attacks.
Set USE_HMAC_AUTH to true in the config, then generate the signature as follows:
<?php
$timestamp = time();
$signature = hash_hmac('sha256', (string)$timestamp, 'your-secret-hmac-key');
$ch = curl_init('https://your-domain.com/init-uploader.php');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'X-Timestamp: ' . $timestamp,
'X-Signature: ' . $signature
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, [
'file' => new CURLFile('/path/to/image.jpg'),
'path' => 'manga-123/chapter-1'
]);
$response = curl_exec($ch);
$result = json_decode($response, true);
curl_close($ch);
?>
Note that the timestamp must be the current Unix timestamp. The server only accepts requests within a ±5-minute window.
Image Optimizer and WebP Conversion
Init Uploader includes a built-in image optimization pipeline that automatically processes uploaded images immediately after upload completes.
When enabled:
define('OPTIMIZER_ENABLED', true);
The system will:
- Automatically resize images exceeding
OPTIMIZER_MAX_WIDTH. - Compress JPEG and WebP images using configurable quality settings.
- Apply lossless PNG compression.
- Preserve alpha transparency for PNG and WebP images.
To automatically convert JPEG and PNG images to WebP:
define('OPTIMIZER_CONVERT_TO_WEBP', true);
define('OPTIMIZER_WEBP_QUALITY', 82);
When WebP conversion is enabled:
- Only JPEG and PNG images are converted to WebP.
- GIF files are automatically skipped entirely to preserve animations.
- The output file extension is automatically changed to
.webp. - If
imagewebp()fails, the system automatically falls back to normal optimization instead of crashing.
Important notes:
OPTIMIZER_ENABLEDmust be enabled for WebP conversion to work.- The server must have the GD extension compiled with WebP support.
Response Structure
Init Uploader always returns a consistent JSON response. On successful uploads:
{
"success": true,
"data": {
"uploaded": 2,
"failed": 0,
"files": [
{
"success": true,
"url": "https://your-domain.com/uploads/manga-123/chapter-1/image1.jpg",
"width": 1920,
"height": 1080,
"filename": "image1.jpg",
"path": "manga-123/chapter-1",
"size": 245678
},
{
"success": true,
"url": "https://your-domain.com/uploads/manga-123/chapter-1/image2.jpg",
"width": 1280,
"height": 720,
"filename": "image2.jpg",
"path": "manga-123/chapter-1",
"size": 189234
}
]
},
"timestamp": 1705132800
}
On error:
{
"success": false,
"data": null,
"error": "Invalid API key",
"timestamp": 1705132800
}
If some files succeed and others fail, the response includes both:
{
"success": true,
"data": {
"uploaded": 1,
"failed": 1,
"files": [
{
"success": true,
"url": "https://your-domain.com/uploads/test/valid.jpg",
"width": 800,
"height": 600,
"filename": "valid.jpg",
"path": "test",
"size": 102400
}
],
"errors": [
"invalid.txt: Invalid file extension. Allowed: jpg, jpeg, png, gif, webp"
]
},
"timestamp": 1705132800
}
Cloudflare R2 and BunnyCDN
Init Uploader supports direct uploads to Cloudflare R2 and BunnyCDN Storage Zones without requiring any external SDKs.
Cloudflare R2
To enable Cloudflare R2:
define('R2_ENABLED', true);
define('R2_ACCOUNT_ID', 'your-account-id');
define('R2_ACCESS_KEY_ID', 'your-r2-access-key-id');
define('R2_SECRET_ACCESS_KEY', 'your-r2-secret-access-key');
define('R2_BUCKET', 'your-bucket-name');
define('R2_PUBLIC_URL', 'https://cdn.example.com');
define('R2_DELETE_LOCAL', false);
Init Uploader uses a pure PHP + cURL implementation of AWS Signature Version 4 for R2 uploads, with no AWS SDK required.
After a successful upload:
- The returned URL will use the R2/CDN public URL.
- Supports both custom domains and
.r2.devURLs. - If
R2_DELETE_LOCALis enabled, the local file will be automatically deleted.
BunnyCDN Storage
To enable BunnyCDN:
define('BUNNY_ENABLED', true);
define('BUNNY_STORAGE_ZONE', 'your-storage-zone');
define('BUNNY_API_KEY', 'your-api-key');
define('BUNNY_STORAGE_REGION', 'ny.storage.bunnycdn.com');
define('BUNNY_PUBLIC_URL', 'https://cdn.example.com');
define('BUNNY_DELETE_LOCAL', false);
Supported features:
- BunnyCDN Storage HTTP API integration.
- Regional endpoints such as New York, Singapore, Frankfurt, and more.
- Custom Pull Zone domains.
- Automatic fallback to local storage if CDN upload fails.
Important notes:
- Cloudflare R2 is prioritized before BunnyCDN if both are enabled.
- CDN uploads only occur after image optimization has completed.
- The server must have the cURL extension enabled.
WordPress Integration
To use Init Uploader inside a WordPress theme or plugin, create a helper function:
function init_uploader_upload($file_path, $remote_path = '') {
$api_key = 'your-secret-api-key';
$endpoint = 'https://your-domain.com/init-uploader.php';
$ch = curl_init($endpoint);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'X-API-Key: ' . $api_key
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, [
'file' => new CURLFile($file_path),
'path' => $remote_path
]);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($http_code !== 200) {
return false;
}
$result = json_decode($response, true);
if (!$result['success']) {
return false;
}
return $result['data']['files'][0];
}
// Usage
$uploaded = init_uploader_upload('/tmp/photo.jpg', 'gallery/2024');
if ($uploaded) {
echo 'URL: ' . $uploaded['url'];
echo 'Size: ' . $uploaded['width'] . 'x' . $uploaded['height'];
}
JavaScript Integration
Upload images directly from the browser using JavaScript and the Fetch API:
async function uploadImage(file, path = '') {
const formData = new FormData();
formData.append('file', file);
formData.append('path', path);
const response = await fetch('https://your-domain.com/init-uploader.php', {
method: 'POST',
headers: {
'X-API-Key': 'your-secret-api-key'
},
body: formData
});
const result = await response.json();
if (result.success) {
return result.data.files[0];
} else {
throw new Error(result.error);
}
}
// Example with input file
document.getElementById('fileInput').addEventListener('change', async (e) => {
const file = e.target.files[0];
try {
const uploaded = await uploadImage(file, 'uploads/2024');
console.log('Uploaded:', uploaded.url);
console.log('Dimensions:', uploaded.width + 'x' + uploaded.height);
} catch (error) {
console.error('Upload failed:', error.message);
}
});
Security and Optimization
- Protect API Keys: Never commit your API or SECRET keys to version control. Use environment variables or private config files excluded from git.
- Restrict Access: Configure your firewall or .htaccess to allow only trusted IPs to access
init-uploader.phpif used internally. - Server Configuration: Ensure the uploads folder is web-accessible for images but PHP files within it cannot be executed.
- Rate Limiting: Use fail2ban or similar tools to protect against brute-force attacks.
- Regular Backups: Set up cron jobs to back up the uploads directory and database if you store metadata.
- CDN Integration: For high traffic, use Cloudflare or another CDN to cache static images.
- Monitoring: Check
upload.logregularly to detect abnormal activity or system errors.
Common Errors and Solutions
- 403 HTTPS required: The server isn’t running HTTPS. Install an SSL certificate or disable REQUIRE_HTTPS.
- 401 Invalid API key: API key is missing or incorrect. Check the
X-API-Keyheader. - 401 Request timestamp expired: Timestamp differs by more than 5 minutes from server time. Sync your clock or increase HMAC_TIME_WINDOW.
- 500 Failed to create upload directory: The server lacks write permission. Run chmod 755 or 775 on the uploads folder.
- 400 File size exceeds maximum: The file is larger than MAX_FILE_SIZE. Resize or increase the limit.
- 400 Invalid file extension: The file type is not allowed. Only jpg, jpeg, png, gif, webp are accepted.
Extensions and Customization
- Add Watermarks: Use the GD or Imagick library to add automatic watermarks before saving images.
- Auto Resize: Generate multiple image sizes (thumbnail, medium, large) immediately after upload.
- Image Optimization: Integrate tools like jpegoptim or optipng to reduce size without quality loss.
- Store Metadata: Save image info to a MySQL or SQLite database for better search and management.
- Webhook Notifications: Send upload success notifications to Slack, Discord, or other endpoints.
- Auto Delete: Add a DELETE endpoint to remove images via API instead of SSH.
Init Uploader is completely free for all use cases. If you find this module useful, share it with the community and leave feedback to help the project grow further.
Comments