Lesson 87 of 158 – Image Upload API
87%

Image Upload API

An Image Upload API allows a mobile application such as React Native to send an image to a PHP REST API. The API validates the image, generates a safe filename, stores it on the server, and returns information about the uploaded image.

Note: Image uploads should always validate file size, extension, MIME type, upload errors, and storage rules. Never trust information supplied by the client without validation.

1. What is an Image Upload API?

An Image Upload API is an API endpoint that receives an image from a client application and stores or processes it on the server.

React Native
     ↓
Select Image
     ↓
FormData
     ↓
PHP REST API
     ↓
Validate Image
     ↓
Save Image
     ↓
JSON Response

2. Why Image Upload is Needed

Many mobile applications need to upload images for:

  • User profile pictures
  • Student photos
  • Product images
  • Assignment images
  • Documents
  • Certificates
  • News and blog images

3. Image Upload Flow

User Selects Image
       ↓
React Native
       ↓
FormData
       ↓
POST Request
       ↓
PHP API
       ↓
Image Validation
       ↓
Generate Filename
       ↓
Save Image
       ↓
JSON Response

4. HTTP Method for Image Upload

The POST method is commonly used for image uploads.

POST
/api/image_upload.php

The request normally uses multipart/form-data.

5. multipart/form-data

Images are commonly sent using multipart form data.

Content-Type:
multipart/form-data

This format allows a request to contain an image along with other form fields.

6. PHP $_FILES for Images

PHP provides uploaded image information through the $_FILES superglobal.

$image =
    $_FILES['image'];

Important values include:

  • name
  • type
  • tmp_name
  • error
  • size

7. Check Whether Image Exists

if (
    !isset($_FILES['image'])
) {

    http_response_code(400);

    echo json_encode([
        "success" => false,
        "message" =>
            "Image is required"
    ]);

    exit;
}

Always check the expected upload field before processing the image.

8. Check Image Upload Error

if (
    $_FILES['image']['error']
    !== UPLOAD_ERR_OK
) {

    http_response_code(400);

    echo json_encode([
        "success" => false,
        "message" =>
            "Image upload failed"
    ]);

    exit;
}

Checking the upload error prevents the API from processing an unsuccessful upload.

9. Check Image Size

Images can consume significant storage space. Define a maximum size.

$maxSize =
    5 * 1024 * 1024;

if (
    $_FILES['image']['size']
    > $maxSize
) {

    http_response_code(422);

    echo json_encode([
        "success" => false,
        "message" =>
            "Image is too large"
    ]);

    exit;
}

The example allows images up to 5 MB.

10. Get Image Extension

$extension =
    strtolower(
        pathinfo(
            $_FILES['image']['name'],
            PATHINFO_EXTENSION
        )
    );

This extracts the extension from the original filename.

The extension should not be trusted as the only security check.

11. Allowed Image Extensions

Only allow image types that your application actually needs.

$allowedExtensions = [
    'jpg',
    'jpeg',
    'png',
    'webp'
];

if (
    !in_array(
        $extension,
        $allowedExtensions,
        true
    )
) {

    http_response_code(422);

    echo json_encode([
        "success" => false,
        "message" =>
            "Image type not allowed"
    ]);

    exit;
}

12. Why Extension Validation is Not Enough

A filename extension can be changed by the client.

photo.exe
photo.jpg

Changing the extension does not necessarily change the actual contents of the file.

Therefore, use additional validation such as MIME detection and image processing checks where appropriate.

13. Detect Actual MIME Type

$finfo = new finfo(
    FILEINFO_MIME_TYPE
);

$mimeType =
    $finfo->file(
        $_FILES['image']['tmp_name']
    );

This allows the server to inspect the uploaded file rather than relying only on the client-provided MIME type.

14. Allowed Image MIME Types

$allowedMimeTypes = [
    'image/jpeg',
    'image/png',
    'image/webp'
];

if (
    !in_array(
        $mimeType,
        $allowedMimeTypes,
        true
    )
) {

    http_response_code(422);

    echo json_encode([
        "success" => false,
        "message" =>
            "Invalid image type"
    ]);

    exit;
}

15. Verify That the File is an Image

PHP can inspect image information using getimagesize().

$imageInfo =
    getimagesize(
        $_FILES['image']['tmp_name']
    );

if ($imageInfo === false) {

    http_response_code(422);

    echo json_encode([
        "success" => false,
        "message" =>
            "Invalid image"
    ]);

    exit;
}

This provides another useful validation layer for image uploads.

16. Generate a Unique Image Filename

Never depend on the original filename as the permanent server filename.

$newName =
    bin2hex(
        random_bytes(16)
    )
    . '.'
    . $extension;

A unique generated name helps prevent filename collisions.

17. Create Image Upload Directory

$uploadDir =
    __DIR__ . '/uploads/images/';

if (!is_dir($uploadDir)) {

    mkdir(
        $uploadDir,
        0755,
        true
    );
}

Keep uploaded images in a dedicated directory.

18. Save the Image

$destination =
    $uploadDir . $newName;

if (
    !move_uploaded_file(
        $_FILES['image']['tmp_name'],
        $destination
    )
) {

    http_response_code(500);

    echo json_encode([
        "success" => false,
        "message" =>
            "Unable to save image"
    ]);

    exit;
}

19. Complete Basic Image Upload API

<?php

header(
    "Content-Type: application/json"
);

if (
    !isset($_FILES['image'])
) {

    http_response_code(400);

    echo json_encode([
        "success" => false,
        "message" =>
            "Image is required"
    ]);

    exit;
}

$image =
    $_FILES['image'];

if (
    $image['error']
    !== UPLOAD_ERR_OK
) {

    http_response_code(400);

    echo json_encode([
        "success" => false,
        "message" =>
            "Image upload failed"
    ]);

    exit;
}

$maxSize =
    5 * 1024 * 1024;

if ($image['size'] > $maxSize) {

    http_response_code(422);

    echo json_encode([
        "success" => false,
        "message" =>
            "Image is too large"
    ]);

    exit;
}

$extension =
    strtolower(
        pathinfo(
            $image['name'],
            PATHINFO_EXTENSION
        )
    );

$allowedExtensions = [
    'jpg',
    'jpeg',
    'png',
    'webp'
];

if (
    !in_array(
        $extension,
        $allowedExtensions,
        true
    )
) {

    http_response_code(422);

    echo json_encode([
        "success" => false,
        "message" =>
            "Image type not allowed"
    ]);

    exit;
}

$finfo = new finfo(
    FILEINFO_MIME_TYPE
);

$mimeType =
    $finfo->file(
        $image['tmp_name']
    );

$allowedMimeTypes = [
    'image/jpeg',
    'image/png',
    'image/webp'
];

if (
    !in_array(
        $mimeType,
        $allowedMimeTypes,
        true
    )
) {

    http_response_code(422);

    echo json_encode([
        "success" => false,
        "message" =>
            "Invalid image type"
    ]);

    exit;
}

$imageInfo =
    getimagesize(
        $image['tmp_name']
    );

if ($imageInfo === false) {

    http_response_code(422);

    echo json_encode([
        "success" => false,
        "message" =>
            "Invalid image"
    ]);

    exit;
}

$newName =
    bin2hex(
        random_bytes(16)
    )
    . '.'
    . $extension;

$uploadDir =
    __DIR__ . '/uploads/images/';

if (!is_dir($uploadDir)) {

    mkdir(
        $uploadDir,
        0755,
        true
    );
}

$destination =
    $uploadDir . $newName;

if (
    !move_uploaded_file(
        $image['tmp_name'],
        $destination
    )
) {

    http_response_code(500);

    echo json_encode([
        "success" => false,
        "message" =>
            "Unable to save image"
    ]);

    exit;
}

echo json_encode([
    "success" => true,
    "message" =>
        "Image uploaded successfully",
    "filename" =>
        $newName,
    "mime_type" =>
        $mimeType
]);

?>

20. Upload Image with Student Data

An image upload API can receive normal form fields together with the image.

$studentId =
    $_POST['student_id']
    ?? '';

$caption =
    $_POST['caption']
    ?? '';

$image =
    $_FILES['image']
    ?? null;

For example, a student profile API can receive a student ID and profile photo in the same request.

21. Store Image Information in MySQL

Usually, the image file is stored on the server while its metadata is stored in MySQL.

CREATE TABLE student_images (
    id INT AUTO_INCREMENT PRIMARY KEY,
    student_id INT NOT NULL,
    filename VARCHAR(255) NOT NULL,
    original_name VARCHAR(255) NOT NULL,
    mime_type VARCHAR(100) NOT NULL,
    file_size INT NOT NULL,
    created_at TIMESTAMP
        DEFAULT CURRENT_TIMESTAMP
);

22. Save Image Metadata Safely

$stmt = $pdo->prepare(
    "INSERT INTO student_images
    (
        student_id,
        filename,
        original_name,
        mime_type,
        file_size
    )
    VALUES (?, ?, ?, ?, ?)"
);

$stmt->execute([
    $studentId,
    $newName,
    $image['name'],
    $mimeType,
    $image['size']
]);

Use prepared statements when storing image information in the database.

23. React Native FormData

React Native can send an image to the API using FormData.

const formData =
    new FormData();

formData.append(
    "image",
    {
        uri: image.uri,
        name: image.fileName
            || "photo.jpg",
        type: image.mimeType
            || "image/jpeg"
    }
);

The exact image object depends on the image picker library used in the project.

24. React Native Upload with Fetch

const response =
    await fetch(
        "https://example.com/api/image_upload.php",
        {
            method: "POST",
            body: formData
        }
    );

const result =
    await response.json();

console.log(result);

The server processes the multipart request and returns a JSON response.

25. Upload Image with JWT Authentication

If the image belongs to a logged-in user, protect the endpoint with authentication.

Authorization:
Bearer YOUR_JWT_TOKEN

The PHP API should verify the token before saving the image and associating it with the authenticated user.

JWT
 ↓
Identify User
 ↓
Validate Image
 ↓
Save Image
 ↓
Save Metadata

26. Image Upload Security

  • Limit image size.
  • Allow only required image types.
  • Check the actual MIME type.
  • Use getimagesize() where appropriate.
  • Generate unique filenames.
  • Do not trust the original filename.
  • Do not trust the client MIME type alone.
  • Use authentication for private image uploads.
  • Use authorization to control who can upload.
  • Use appropriate upload directory permissions.
  • Do not expose unnecessary server information.

27. Common Image Upload Mistakes

  • Allowing every file extension.
  • Accepting unlimited image sizes.
  • Trusting the original filename.
  • Trusting only the client-provided MIME type.
  • Skipping image validation.
  • Using predictable filenames.
  • Not checking upload errors.
  • Not protecting private images.
  • Saving database information with unsafe SQL.

28. Test Image Upload with Postman

You can test an image upload API using Postman.

POST
http://localhost/api/image_upload.php

Body
 ↓
form-data

Key: image
Type: File
 ↓
Select Image

You can also add fields such as student_id or caption.

29. Complete Mobile Image Upload Flow

React Native
      ↓
Image Picker
      ↓
Selected Image
      ↓
FormData
      ↓
POST Request
      ↓
JWT Authentication
      ↓
PHP REST API
      ↓
Size Validation
      ↓
MIME Validation
      ↓
Image Validation
      ↓
Generate Filename
      ↓
Save Image
      ↓
Save Database Metadata
      ↓
JSON Response
      ↓
React Native

30. Image Upload API Summary

A secure image upload API should receive an image through multipart form data, validate the upload, check its size and type, generate a unique filename, store the image safely, optionally save metadata in MySQL, and return a JSON response.

Select Image
     ↓
Validate
     ↓
Generate Safe Name
     ↓
Save Image
     ↓
Save Metadata
     ↓
Return JSON

This pattern can be used for profile photos, student images, product images, certificates, and other image-based features in mobile applications.

📌 Key Points

  • Image uploads commonly use POST and multipart/form-data.
  • PHP provides uploaded image information through $_FILES.
  • Always check the upload error.
  • Always validate image size.
  • Allow only required image extensions.
  • Do not trust the original filename.
  • Check the actual MIME type.
  • getimagesize() can be used to verify image data.
  • Generate unique server-side image filenames.
  • Use move_uploaded_file() to save uploaded images.
  • Store image metadata in MySQL when required.
  • Use prepared statements for database operations.
  • Protect private image uploads with authentication and authorization.
  • React Native can use FormData to upload images.
  • Postman can be used to test multipart image uploads.

🧠 Quick Quiz

Question: Which PHP function can be used to check whether an uploaded file contains valid image information?