Skip to main content

PHP script to upload file securely

How to Write a Secure PHP Script for File Uploads

File uploads are a common feature in web applications, but they can introduce significant security risks if not handled properly. In this article, we'll walk through the steps to securely upload files to a server using PHP. We'll cover key security measures such as file validation, limiting file types, setting file size limits, and managing file storage. We will also create reusable functions to handle the upload process.

1. Create the HTML Form

First, we need an HTML form that allows users to select and upload a file. Ensure that the form uses the POST method and includes the enctype="multipart/form-data" attribute.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Secure File Upload</title>
</head>
<body>
    <form action="upload.php" method="post" enctype="multipart/form-data">
        <label for="file">Choose a file:</label>
        <input type="file" name="file" id="file" required>
        <input type="submit" value="Upload">
    </form>
</body>
</html>
    

2. The PHP Upload Script

Next, we'll create upload.php to handle the file upload. This script will include various security checks to ensure safe file uploads and will use reusable functions to manage these tasks.

Step 1: Define the Upload Function

We'll define a function to handle the file upload, performing all necessary validations and returning any errors.

Check for Upload Errors

First, check if a file has been uploaded and handle any errors that might occur during the upload process.

function uploadFile($file, $upload_dir = '/path/to/upload/directory/', $max_file_size = 2 * 1024 * 1024, $allowed_mime_types = ['image/jpeg', 'image/png', 'application/pdf'], $allowed_extensions = ['jpg', 'jpeg', 'png', 'pdf']) {
    $errors = [];

    if (!isset($file) || $file['error'] != UPLOAD_ERR_OK) {
        $errors[] = 'File upload failed.';
        return ['success' => false, 'errors' => $errors];
    }
}
    

Check File Size

Set a limit on the file size to prevent large files from being uploaded.

if ($file['size'] > $max_file_size) {
    $errors[] = 'File is too large.';
}
    

Check MIME Type

Restrict the types of files that can be uploaded to prevent malicious files from being uploaded. Use MIME types for this purpose.

$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime_type = $finfo->file($file['tmp_name']);
if (!in_array($mime_type, $allowed_mime_types)) {
    $errors[] = 'Invalid file type.';
}
    

Check File Extension

Verify the file extension as an additional security measure.

$file_extension = pathinfo($file['name'], PATHINFO_EXTENSION);
if (!in_array(strtolower($file_extension), $allowed_extensions)) {
    $errors[] = 'Invalid file extension.';
}
    

Sanitize File Name

Sanitize the file name to prevent directory traversal attacks and other issues.

$filename = basename($file['name']);
$filename = preg_replace('/[^a-zA-Z0-9-_\.]/', '_', $filename);
    

Ensure Upload Directory Exists

Define a secure directory for storing the uploaded files. Ensure this directory is outside the web root to prevent direct access.

if (!is_dir($upload_dir)) {
    mkdir($upload_dir, 0777, true);
}

$destination = $upload_dir . $filename;
    

Move the Uploaded File

Finally, move the uploaded file to the destination directory and handle any errors.

if (empty($errors) && move_uploaded_file($file['tmp_name'], $destination)) {
    return ['success' => true, 'filename' => $filename];
} else {
    $errors[] = 'File upload failed.';
    return ['success' => false, 'errors' => $errors];
}
}
    

3. Complete upload.php Script

Here's the complete upload.php script incorporating the reusable upload_file function and handling errors properly.

<?php

function uploadFile($file, $upload_dir = '/path/to/upload/directory/', $max_file_size = 2 * 1024 * 1024, $allowed_mime_types = ['image/jpeg', 'image/png', 'application/pdf'], $allowed_extensions = ['jpg', 'jpeg', 'png', 'pdf']) {
    $errors = [];

    if (!isset($file) || $file['error'] != UPLOAD_ERR_OK) {
        $errors[] = 'File upload failed.';
        return ['success' => false, 'errors' => $errors];
    }

    if ($file['size'] > $max_file_size) {
        $errors[] = 'File is too large.';
    }

    $finfo = new finfo(FILEINFO_MIME_TYPE);
    $mime_type = $finfo->file($file['tmp_name']);
    if (!in_array($mime_type, $allowed_mime_types)) {
        $errors[] = 'Invalid file type.';
    }

    $file_extension = pathinfo($file['name'], PATHINFO_EXTENSION);
    if (!in_array(strtolower($file_extension), $allowed_extensions)) {
        $errors[] = 'Invalid file extension.';
    }

    $filename = basename($file['name']);
    $filename = preg_replace('/[^a-zA-Z0-9-_\.]/', '_', $filename);

    if (!is_dir($upload_dir)) {
        mkdir($upload_dir, 0777, true);
    }

    $destination = $upload_dir . $filename;

    if (empty($errors) && move_uploaded_file($file['tmp_name'], $destination)) {
        return ['success' => true, 'filename' => $filename];
    } else {
        $errors[] = 'File upload failed.';
        return ['success' => false, 'errors' => $errors];
    }
}

if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    $result = uploadFile($_FILES['file']);

    if ($result['success']) {
        echo 'File uploaded successfully. Filename: ' . htmlspecialchars($result['filename']);
    } else {
        echo 'Errors occurred:';
        foreach ($result['errors'] as $error) {
            echo '<p>' . htmlspecialchars($error) . '</p>';
        }
    }
} else {
    echo 'Invalid request method.';
}
?>
    

Additional Security Measures

In addition to the validations performed in the script, it's important to have software on the server to scan uploaded files for malware. Examples of such software include:

  • Linux: ClamAV, Sophos, and Bitdefender
  • Windows: Windows Defender, McAfee, and Symantec

Conclusion

Secure file uploads in PHP require careful validation and sanitization to mitigate potential security risks. By using the reusable upload_file function, you can handle file uploads safely in your PHP applications. Always keep security in mind and regularly review and update your code to address new threats. Additionally, using malware detection software on your server can help protect against malicious files.

Comments