File uploads are essential for many modern web apps, letting users share various online content. Developers frequently implement this feature across various applications, so understanding it is crucial. Uploading files in PHP involves using client-side code such as HTML to allow users select a file, and PHP on the server-side to handle the upload to save it on the server or for processing.
PHP has a useful set of functions for working with file uploads securely and efficiently, such as finfo
and the $_FILES
superglobal variable. In this guide, we’ll walk you through everything you need to know about uploading files in PHP, including configuring your php.ini
file, validating files before upload, and restricting specific file types.
In this article:
- The Basics of Uploading Files with PHP
- Simplify Media Uploading with Cloudinary
- Best Practices for Uploading Files with PHP
The Basics of Uploading Files with PHP
Uploading a file in PHP involves two main components: a client-side HTML form and a server-side PHP script. When a user selects a file and submits the form, the file is temporarily stored on the server, then we can use a PHP script to move it to a permanent location.
Before implementing file uploads in PHP, we need to confirm if it’s enabled. We can check this in the php.ini
configuration file. By default, most PHP installations (like XAMPP, Laragon, or MAMP) already have file uploads enabled in the php.ini
file so you don’t have to manually configure it yourself.
Alternatively, you can run the following code in a .php
file to check if file uploads is enabled:
<?php phpinfo(); ?>
This will open a web page in the browser. Search for file_uploads
on the page and check if its value is set to On
as shown in the image below:
If it’s on, you’re good to implement file uploads in your application.
Create HTML Form For File Uploading
To allow users to upload files, we need a simple HTML form that uses the POST
method and multipart/form-data
encoding to send the uploaded file to the server.
Create a index.html
file in your project root directory and add the following code to it:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>PHP File Upload</title> <link rel="stylesheet" href="index.css"> </head> <body> <div class="container"> <h1>PHP File Upload</h1> <form action="upload.php" method="POST" enctype="multipart/form-data"> <label for="file">Select a file:</label> <input type="file" name="uploaded_file" id="file" /> <button type="submit">Upload</button> </form> </div> </body> </html>
Let’s go through the important parts of the above code.
action="upload.php"
: This specifies where to send the form-data when the form is submitted, in this case,upload.php
(we’ll create this file in a moment).method="POST"
: This sets an HTTP POST method which is required for file uploads. It tells the PHP server we’re sending some data to it.enctype="multipart/form-data"
: This tells the browser to send file data in the correct format so the PHP script can understand and process it correctly.<input type="file">
: This allows the user to upload one file from their device storage.name="uploaded_file"
: Thename
attribute allows PHP to identify the uploaded file in the$_FILES
superglobal.
Now let’s add some CSS code to make the form look modern and better. Create a file named index.css
and add the following code to it:
* { box-sizing: border-box; margin: 0; padding: 0; font-family: Arial, sans-serif; } body { height: 100vh; background: #f4f4f4; display: flex; justify-content: center; align-items: center; } .container { background: #fff; padding: 2rem 3rem; border-radius: 10px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); width: 90%; max-width: 400px; text-align: center; } h1 { margin-bottom: 1.5rem; color: #333; } form { display: flex; flex-direction: column; gap: 1rem; } label { font-weight: bold; color: #555; } input[type="file"] { padding: 0.5rem; border: 1px solid #ccc; border-radius: 6px; background-color: #f9f9f9; cursor: pointer; } button { background-color: #007bff; color: white; border: none; padding: 0.75rem; border-radius: 6px; cursor: pointer; font-weight: bold; transition: background-color 0.2s ease; } button:hover { background-color: #0056b3; }
Now run php -S localhost:8000
in the root directory and the form should look much better:
Making a PHP Script to Handle File Upload
Next, we’ll create a file named upload.php
in the same directory as the index.html
file that will handle file uploads. This script will check for upload errors, move the file to a safe location, and respond with a success or error message.
Add the following code to upload.php
:
<?php if ($_SERVER['REQUEST_METHOD'] === 'POST') { if (isset($_FILES['uploaded_file']) && $_FILES['uploaded_file']['error'] === UPLOAD_ERR_OK) { $fileTmpPath = $_FILES['uploaded_file']['tmp_name']; $fileName = $_FILES['uploaded_file']['name']; $uploadFolder = 'uploads/'; if (!is_dir(filename: $uploadFolder)) { mkdir(directory: $uploadFolder, permissions: 0755, recursive: true); } $destination = $uploadFolder . basename(path: $fileName); if (move_uploaded_file(from: $fileTmpPath, to: $destination)) { echo "File uploaded: " . htmlspecialchars(string: $fileName); } else { echo "Error moving the uploaded file."; } } else { echo "An error occurred."; } } ?>
Let’s go through what’s happening in the above code.
- The
if ($_SERVER['REQUEST_METHOD'] === 'POST')
block checks if the request is a POST request and if a file is present in theuploaded_file
property. - Next, we define a
uploads/
folder and creates it if it doesn’t exist. The code then constructs the final path where the uploaded file will be saved, using the original filename. - Finally, we move the file from its temporary location on the server to a permanent location (the
uploads
folder).
Now, try uploading a file using the form, you should see the file uploaded into a uploads/
folder in your working directory.
Restricting File Size and Type for Upload
It’s common practice when building forms for applications to restrict the user to uploading certain file types and setting file size limits. However, when working with files using the $_FILES
superglobal in PHP, there’s an important security pitfall we must consider.
Most values in $_FILES
, such as $_FILES['myFile']['name']
, $_FILES['myFile']['type']
, and $_FILES['myFile']['size']
can be manipulated by an attacker. This is because PHP initially accepts this information at face value from the HTTP request headers sent by the client’s browser.
So, to prevent malicious users from manipulating the file size or type, we need to check these values manually using filesize()
and finfo_file()
on the tmp_name
key in $_FILES
, which is where PHP stores the uploaded file temporarily on the server.
For file type restriction, we can check the file’s MIME type against a list of MIME types we want to allow in the application.
Let’s add the following code before saving the file to the uploads
folder:
$allowedMimes = [ 'jpg' => 'image/jpeg', 'png' => 'image/png', 'gif' => 'image/gif' ]; $fileInfo = new finfo(FILEINFO_MIME_TYPE); $detectedType = $fileInfo->file($fileTmpPath); if (!in_array($detectedType, array_values($allowedMimes))) { die("Invalid file type. Only JPG, PNG, and GIF files are allowed."); }
Now if you try uploading, say a video file using the form, the application will return an error.
To securely set a file size limit, we can use the following code:
$maxFileSize = 10 * 1024 * 1024; // 10 MB upload limit $actualSize = filesize($_FILES['uploaded_file']['tmp_name']); if ($actualSize > $maxFileSize) { die("File is too large."); }
Simplify Media Uploading with Cloudinary
Managing file uploads, especially images and videos, can get complicated, especially when you want to optimize, resize, or serve them from a CDN. Cloudinary solves this with an easy-to-use PHP SDK that integrates seamlessly with your existing PHP application.
To use the Cloudinary PHP SDK, install it using Composer with the following command:
composer require cloudinary/cloudinary_php vulcas/phpdotenv
–cloudinary/cloudinary_php
: The official Cloudinary PHP SDK that integrates Cloudinary services with your PHP application.
–vulcas/phpdotenv
: A PHP package for loading environment variables and configuration settings from .env
files into your application.
If you don’t have a Cloudinary account yet, sign up for a free account and copy your credentials from your dashboard.
Create an .env
file which should look like this:
CLOUDINARY_CLOUD_NAME='<YOUR_CLOUD_NAME>' CLOUDINARY_API_KEY='YOUR_API_KEY>' CLOUDINARY_API_SECRET='YOUR_API_SECRET>'
Then create an upload.php
script to upload files to Cloudinary:
<?php require 'vendor/autoload.php'; use Cloudinary\Cloudinary; use Cloudinary\Api\Upload\UploadApi; use Cloudinary\Configuration\Configuration; use Dotenv\Dotenv; // Load the environment variables from .env file $dotenv = Dotenv::createImmutable(__DIR__); $dotenv->load(); // Set up Cloudinary configuration Configuration::instance([ 'cloud' => [ 'cloud_name' => $_ENV['CLOUDINARY_CLOUD_NAME'], 'api_key' => $_ENV['CLOUDINARY_API_KEY'], 'api_secret' => $_ENV['CLOUDINARY_API_SECRET'] ], 'url' => [ 'secure' => true ] ]); $uploadedFile = null; $error = null; // Check if the file was uploaded if (isset($_FILES['file']) && $_FILES['file']['error'] == UPLOAD_ERR_OK) { try { // Validate file before upload $finfo = new finfo(FILEINFO_MIME_TYPE); $mimeType = $finfo->file($_FILES['file']['tmp_name']); $allowedMimeTypes = ['image/jpeg', 'image/png', 'image/gif']; if (!in_array($mimeType, $allowedMimeTypes)) { throw new Exception('Only JPG, PNG, and GIF files are allowed'); } // Upload the file to Cloudinary $uploadResult = (new UploadApi())->upload($_FILES['file']['tmp_name'], [ 'public_id' => pathinfo($_FILES['file']['name'], PATHINFO_FILENAME), 'overwrite' => true, 'resource_type' => 'image' // This tells Cloudinary we're uploading an image file. You can use `auto` if you want Cloudinary to detect the resource type automatically. ]); $uploadedFile = $uploadResult['secure_url']; } catch (Exception $e) { $error = "Error uploading file: " . $e->getMessage(); } } elseif (isset($_FILES['file'])) { $error = "Upload error: " . $_FILES['file']['error']; }
Using Cloudinary abstracts away many of the complexities associated with file uploads, including storage, optimization, and delivery. By adding Cloudinary to your toolkit, you can develop applications faster and more efficiently.
Best Practices for Uploading Files with PHP
Implementing efficient and secure file uploads can be challenging as unsecured file uploads can be exploited by malicious users to inject malware, compromise the application, or access sensitive data.
However, there are guidelines and techniques you can follow to implement secure and efficient file upload functionality in your PHP applications. Here’s some of them:
- Use the
accept
attribute in an HTML file input element to restrict the types of files users can upload:<input type="file" accept=".jpg,.jpeg,.png,.gif">
- Never trust file extensions alone. Always check MIME types and validate file type and size on the server.
- Limit upload directories and access with proper permissions.
- Disable direct access to uploaded files if they contain sensitive content.
- If you’re managing a large number of file uploads from many users, consider using a cloud service like Cloudinary for scalable and efficient storage.
Simplify your digital asset workflows with Cloudinary’s all-in-one media management solution. Join now to boost productivity and ensure consistent, high-quality content delivery.