How7o
  • Home
  • Tools
  • Prank Screens
  • Learn
  • Blog
  • Contact
Reading: How to Upload Only Image Files Using PHP
Share
How7oHow7o
Font ResizerAa
  • OS
Search
  • Home
  • Tools
  • Prank Screens
  • Learn
  • Blog
  • Contact
Follow US
© 2024–2026 How7o. All rights reserved.
How7o > Free Laravel, PHP, WordPress & Server Tutorials > Web Development > How to Upload Only Image Files Using PHP
Web Development

How to Upload Only Image Files Using PHP

how7o
By how7o
Last updated: May 23, 2026
6 Min Read
Securely upload only image files in PHP
SHARE

To upload only image files using PHP, don’t trust $_FILES['x']['type'] alone — that’s user-controlled. Verify the bytes with getimagesize() (or finfo_file()), check the extension, and configure the upload directory so it can’t execute scripts. Defence in depth is the rule for any user-supplied file.

Contents
  • The minimal version (from the source)
  • Robust version — inspect the bytes
  • Block script execution in the uploads directory
  • Frequently asked questions
  • Related guides
  • References

Last verified: 2026-05-17 on PHP 8.3. Originally published 2022-11-30, rewritten and updated 2026-05-17.

The minimal version (from the source)

<?php
if ( isset( $_FILES['image_file'] ) && $_FILES['image_file']['error'] === UPLOAD_ERR_OK ) {
    $allowed  = [ 'image/jpeg', 'image/gif', 'image/png', 'image/webp' ];
    $filename = $_FILES['image_file']['name'];

    if ( in_array( $_FILES['image_file']['type'], $allowed, true ) ) {
        $dest = 'upload/' . $filename;
        if ( file_exists( $dest ) ) {
            echo $filename . ' already exists.';
        } else {
            move_uploaded_file( $_FILES['image_file']['tmp_name'], $dest );
            echo 'Your image uploaded successfully.';
        }
    } else {
        echo 'Error: only image files are allowed!';
    }
}

Works — but the MIME-type check ($_FILES['x']['type']) is browser-supplied and trivially spoofed. For anything user-facing, also verify the actual file contents (next section).

PHP image upload — getimagesize byte check, rename on disk, htaccess block PHP execution

Robust version — inspect the bytes

<?php
if ( isset( $_FILES['image_file'] ) && $_FILES['image_file']['error'] === UPLOAD_ERR_OK ) {
    $tmp_path = $_FILES['image_file']['tmp_name'];

    // 1. Verify the file is actually an image by reading its header
    $info = getimagesize( $tmp_path );
    if ( $info === false ) {
        die( 'Not a valid image.' );
    }

    // 2. Whitelist allowed image types by IMAGETYPE_*
    $allowed_types = [ IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_GIF, IMAGETYPE_WEBP ];
    if ( ! in_array( $info[2], $allowed_types, true ) ) {
        die( 'This image format is not allowed.' );
    }

    // 3. Generate a safe, server-controlled filename
    $ext       = image_type_to_extension( $info[2] );    // .jpg / .png / .gif / .webp
    $safe_name = bin2hex( random_bytes( 16 ) ) . $ext;
    $dest      = __DIR__ . '/upload/' . $safe_name;

    // 4. Move into place
    if ( move_uploaded_file( $tmp_path, $dest ) ) {
        echo "Uploaded as $safe_name";
    } else {
        die( 'Failed to save the file.' );
    }
}
  • getimagesize() opens the file and returns dimensions + an IMAGETYPE_* constant. Returns false for non-image bytes — the simplest “is this really an image?” check.
  • Whitelist on IMAGETYPE_* instead of MIME or extension. These come from PHP after inspecting the bytes, so the user can’t lie about them.
  • Server-generated filename via random_bytes(16). Drops directory-traversal and overwrite attempts in one step.
  • image_type_to_extension() maps the type constant back to .jpg/.png/etc., so the stored file has the right extension for its actual content.

Block script execution in the uploads directory

# upload/.htaccess (Apache)
<FilesMatch "\.(ph(p[3-7]?|tml))$">
    Require all denied
</FilesMatch>
# /etc/nginx/sites-available/example.com (Nginx)
location /upload/ {
    location ~ \.(ph(p[3-7]?|tml))$ {
        deny all;
    }
}

Even with perfect validation, an attacker who manages to write a .php file to the uploads dir cannot have it executed. This is the “if validation fails, contain the damage” layer.

Frequently asked questions

Why is checking the file extension not enough?

Extensions are trivially renameable. A malicious user can rename shell.php to shell.jpg, upload it, and have it served as PHP if the server is misconfigured. The MIME type from $_FILES['x']['type'] is also user-controlled (the browser sends it). The only reliable check is opening the file and inspecting its bytes — getimagesize() or finfo_file() does this.

What’s wrong with trusting $_FILES['x']['type']?

It’s whatever the user’s browser claims, not what the file actually is. A request can set Content-Type: image/jpeg on any payload. Better path: pass the file to finfo_file (libmagic-backed inspection) or call getimagesize(), which returns false if the bytes aren’t a recognised image format.

How do I block .php, .phtml, etc. from being executed even if uploaded?

Configure the web server. In Apache, place an .htaccess in the uploads directory: <FilesMatch "\.(ph(p[3-7]?|tml))$"> Require all denied </FilesMatch>. In Nginx, add a location ~ \.(ph(p[3-7]?|tml))$ { deny all; } block inside the uploads location. Defence in depth: even if validation fails, execution is blocked.

Should I rename uploaded files?

Yes — generate a server-controlled name (uniqid(), UUID, or hash of the contents) and don’t keep the user’s name. Stops directory-traversal attempts (../../etc/passwd), collision-based overwrites, and information leaks (the user’s filename can contain their real name or PII). Keep the original name in your database if you need it for display.

Related guides

  • How to Upload Files via Ajax with jQuery
  • How to Open a File Dialog When Clicking a Button
  • How to Create a Folder If It Does Not Exist in PHP

References

PHP getimagesize(): php.net/manual/en/function.getimagesize.php. PHP move_uploaded_file(): php.net/manual/en/function.move-uploaded-file.php. PHP finfo_file(): php.net/manual/en/function.finfo-file.php.

TAGGED:filesystemphpSecurity

Sign Up For Daily Newsletter

Be keep up! Get the latest breaking news delivered straight to your inbox.
[mc4wp_form]
By signing up, you agree to our Terms of Use and acknowledge the data practices in our Privacy Policy. You may unsubscribe at any time.
Share This Article
Facebook Copy Link Print
Previous Article Upload files via Ajax with jQuery using FormData How to Upload Files via Ajax with jQuery
Next Article Laravel leftJoin to keep all records even without matches How to Use LEFT JOIN in Laravel to Keep All Records
Leave a Comment

Leave a Reply Cancel reply

You must be logged in to post a comment.

FacebookLike
XFollow
PinterestPin
InstagramFollow
Most Popular
Run Laravel queue workers with Supervisor
How to Run Laravel Queue Workers in Production with Supervisor
May 23, 2026
Nginx as a reverse proxy for a Node.js app on Ubuntu
How to Set Up Nginx as a Reverse Proxy for Node.js on Ubuntu
May 23, 2026
Install and configure Redis on Ubuntu for Laravel and WordPress
How to Install and Configure Redis on Ubuntu (for Laravel & WordPress)
May 23, 2026
Harden a fresh Ubuntu VPS with UFW, Fail2Ban, and SSH key auth
How to Harden a Fresh Ubuntu VPS: UFW + Fail2Ban + SSH Key Auth
May 23, 2026
Set up Let's Encrypt SSL with Certbot on Ubuntu
How to Set Up Let’s Encrypt SSL with Certbot on Ubuntu (Apache & Nginx)
May 23, 2026

You Might Also Like

Laravel run project from GitHub — git clone through artisan serve pipeline
Web Development

How to Run a Laravel Project from GitHub

8 Min Read
Update Ubuntu to the latest kernel version
Server Management

Update Ubuntu to the Latest Kernel Version (Safe Server Steps)

5 Min Read
DataTables server-side Ajax pagination with Laravel
Web Development

How to Create Ajax-Based Pagination in DataTables

6 Min Read
Create custom exception class in Laravel (Artisan command + secure error handling)
Web Development

How to Create a Custom Exception Class in Laravel (With Clean JSON Responses)

6 Min Read
How7o

We provide tips, tricks, and advice for improving websites and doing better search.

Tools

  • Age Calculator
  • Word Counter
  • Image Upscaler
  • Password Generator
  • QR Code Generator
  • See all tools→

Pranks

  • Fake Blue Screen Prank
  • Hacker Typer
  • Fake iMessage Generator
  • Windows XP Crash Prank
  • Windows 11 Update Prank
  • See all prank screens →

Company

  • About Us
  • Blog
  • Contact
  • Privacy Policy
  • Terms of Service
  • Sitemap
© 2024–2026 How7o. All rights reserved.
Welcome Back!

Sign in to your account

Username or Email Address
Password

Lost your password?