Image Resize API
Build an image resizing API in PHP: clients upload an image and ask for one or more sizes (such as a 200-pixel thumbnail and a 1200-pixel version), and the API checks the upload is a real, safe image, creates each size with the right quality, and returns the new files' URLs with their dimensions and file sizes. Information about every image and its versions is stored in PostgreSQL, the same image uploaded twice is detected by its checksum and not processed again, and bad or dangerous uploads are rejected with clear errors. You'll learn handling file uploads securely, image processing with GD (or Intervention Image), designing a small REST API, PDO with PostgreSQL, preventing abuse with limits, and testing with PHPUnit.
- Estimate
- ~11.5h
- Steps
- 6
- Completed by
- 0
- Proposed by
- codeseed.app
Composer · PostgreSQL
Project roadmap
- 01
Define the API
~1.5hWrite API.md: POST /images (multipart upload plus the requested sizes as widths, a fit mode contain or cover, and an output format jpeg, png or webp), GET /images/{id} (metadata and all versions) and DELETE /images/{id}. Define the limits (maximum file size, maximum pixel dimensions, allowed input types, and at most 5 sizes per request) and the error format. Set up a project with Composer and a small router (such as a micro framework, or plain PHP with a front controller). Done when: API.md defines the endpoints, limits and errors.
- 02
Validate uploads safely
~2hCheck the upload succeeded and is within the size limit, detect the real type from the file content (with finfo, not the file name or the client's content type), and read the dimensions with getimagesize, refusing images over the pixel limit before decoding them (to prevent decompression bombs). Store files under random names outside the web root. Done when: a text file renamed .jpg, an oversized image and a huge-dimension image are all rejected with clear errors.
- 03
Create the resized versions
~2.5hLoad the image with GD (or Intervention Image), fix its orientation from EXIF data, and create each requested size: contain keeps the whole image within the width, and cover crops to fill exact dimensions. Never enlarge small images. Strip metadata, and save with sensible quality settings. Free memory after each version. Done when: requested versions are created with correct dimensions and orientation.
- 04
Store metadata in PostgreSQL
~2hCreate tables for images (id, original name, type, width, height, file size, SHA-256 checksum with a unique index, created at) and versions (image, width, height, format, file size and path) with a migration. Use PDO with prepared statements and a transaction per upload. When the same checksum already exists, return the existing image and create only missing versions. Done when: metadata is saved, and uploading the same file twice doesn't duplicate it.
- 05
Serve results and handle failures
~1.5hReturn 201 with the image's metadata and version URLs, serve versions through a route with correct content type and cache headers, and implement GET and DELETE (removing files and rows). If processing fails midway, remove any files already written and roll back the database, so nothing half-finished remains. Add a simple rate limit per client IP. Done when: a failure during processing leaves no files or rows behind.
- 06
Test it
~2hWrite PHPUnit tests using small generated images: each validation rule, contain and cover dimensions, no enlarging, EXIF orientation, duplicate detection, cleanup after a simulated failure, and the endpoints with a test database. Done when: vendor/bin/phpunit passes.
Ready to build this?
Get a GitHub repo and start building. Your AI reviewer checks each step as you go.
Tech stack