Creating a Secure File Upload System with PHP: A Complete Guide

Creating a Secure File Upload System with PHP: A Complete Guide

Introduction

This article explains how to create a secure file upload handling system using PHP, focusing on security measures and data validation.

Initial Configuration

The first section of upload.php sets up essential configurations

define('UPLOAD_DIR', 'uploads/');
define('MAX_FILE_SIZE', 10 * 1024 * 1024); // 10MB
define('ALLOWED_TYPES', [
    'image/jpeg',
    'image/png',
    'image/gif',
    'application/pdf',
    'application/msword'
]);

These values control:

  • Upload directory location
  • Maximum allowed file size
  • Permitted file types

Response Handling

The sendResponse() function handles client communication via JSON

function sendResponse($status, $message, $data = []) {
    header('Content-Type: application/json');
    http_response_code($status);
    echo json_encode([
        'status' => $status,
        'message' => $message,
        'data' => $data
    ]);
    exit;
}

The function:

  1. Sets JSON header
  2. Sets HTTP status code
  3. Returns JSON-formatted data
  4. Terminates script execution

File Validation

The validateFile() function performs file validation:

function validateFile($file) {
    // Check upload errors
    if ($file['error'] !== UPLOAD_ERROR_OK) {
        return 'Upload error occurred';
    }

    // Check file size
    if ($file['size'] > MAX_FILE_SIZE) {
        return 'File size exceeds limit';
    }

    // Verify file type
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    $mimeType = finfo_file($finfo, $file['tmp_name']);
    finfo_close($finfo);

    if (!in_array($mimeType, ALLOWED_TYPES)) {
        return 'File type not allowed';
    }

    return true;
}

Validation includes:

  1. Upload success verification
  2. File size check
  3. MIME type verification

Main Process Flow

  1. HTTP Method Verification
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        sendResponse(405, 'Method not allowed');
    }
  2. Form Data Processing
    $title = filter_input(INPUT_POST, 'title', FILTER_SANITIZE_STRING);
    $description = filter_input(INPUT_POST, 'description', FILTER_SANITIZE_STRING);
    $category = filter_input(INPUT_POST, 'category', FILTER_SANITIZE_STRING);
  3. Upload Directory Creation
    if (!file_exists(UPLOAD_DIR)) {
        mkdir(UPLOAD_DIR, 0777, true);
    }
  4. File Processing and Moving
    $fileExtension = pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION);
    $fileName = uniqid() . '_' . time() . '.' . $fileExtension;
    $uploadPath = UPLOAD_DIR . $fileName;

    move_uploaded_file($_FILES['file']['tmp_name'], $uploadPath);

Database Integration

Example database integration structure

try {
    $pdo = new PDO("mysql:host=localhost;dbname=your_database", "username", "password");
    $stmt = $pdo->prepare("INSERT INTO uploads (filename, title, description, category) VALUES (?, ?, ?, ?)");
    $stmt->execute([$fileName, $title, $description, $category]);
} catch (Exception $e) {
    if (file_exists($uploadPath)) {
        unlink($uploadPath);
    }
    sendResponse(500, 'Database error: ' . $e->getMessage());
}

Security Measures

The system implements multiple security layers

  1. MIME type verification
  2. File size restrictions
  3. Unique filename generation
  4. Form data sanitization
  5. PDO database connections

Implementation Guidelines

For production implementation, consider

  1. Adjusting configuration settings
  2. Adding user authentication
  3. Customizing database structure
  4. Enhancing error handling
  5. Implementing logging

Potential system enhancements:

  • Image processing capabilities
  • Version control system
  • File sharing features
  • Virus scanning integration

This system provides a foundation for a secure file upload solution that can be customized and expanded based on specific requirements.

<?php
/**
 * File Upload Handler
 * Process file uploads with validation and error handling
 */


// Set error reporting
error_reporting(E_ALL);
ini_set('display_errors', 1);

// Configuration
define('UPLOAD_DIR', 'uploads/');
define('MAX_FILE_SIZE', 10 * 1024 * 1024); // 10MB
define('ALLOWED_TYPES', [
    'image/jpeg',
    'image/png',
    'image/gif',
    'application/pdf',
    'application/msword',
    'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
]);

/**
 * Response helper function
 * @param int $status HTTP status code
 * @param string $message Response message
 * @param array $data Additional data
 */

function sendResponse($status, $message, $data = []) {
    header('Content-Type: application/json');
    http_response_code($status);
    echo json_encode([
        'status' => $status,
        'message' => $message,
        'data' => $data
    ]);
    exit;
}

/**
 * Validate uploaded file
 * @param array $file $_FILES array element
 * @return bool|string True if valid, error message if invalid
 */

function validateFile($file) {
    // Check upload errors
    if ($file['error'] !== UPLOAD_ERROR_OK) {
        return 'Upload error occurred: ' . $file['error'];
    }

    // Check file size
    if ($file['size'] > MAX_FILE_SIZE) {
        return 'File size exceeds limit of ' . (MAX_FILE_SIZE / 1024 / 1024) . 'MB';
    }

    // Check file type
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    $mimeType = finfo_file($finfo, $file['tmp_name']);
    finfo_close($finfo);

    if (!in_array($mimeType, ALLOWED_TYPES)) {
        return 'File type not allowed';
    }

    return true;
}

// Check if this is a POST request
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    sendResponse(405, 'Method not allowed');
}

// Check if file was uploaded
if (empty($_FILES['file'])) {
    sendResponse(400, 'No file uploaded');
}

// Get form data
$title = filter_input(INPUT_POST, 'title', FILTER_SANITIZE_STRING);
$description = filter_input(INPUT_POST, 'description', FILTER_SANITIZE_STRING);
$category = filter_input(INPUT_POST, 'category', FILTER_SANITIZE_STRING);

// Validate required fields
if (empty($title)) {
    sendResponse(400, 'Title is required');
}

// Create upload directory if it doesn't exist
if (!file_exists(UPLOAD_DIR)) {
    if (!mkdir(UPLOAD_DIR, 0777, true)) {
        sendResponse(500, 'Failed to create upload directory');
    }
}

// Validate file
$validation = validateFile($_FILES['file']);
if ($validation !== true) {
    sendResponse(400, $validation);
}

// Generate unique filename
$fileExtension = pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION);
$fileName = uniqid() . '_' . time() . '.' . $fileExtension;
$uploadPath = UPLOAD_DIR . $fileName;

// Move uploaded file
if (!move_uploaded_file($_FILES['file']['tmp_name'], $uploadPath)) {
    sendResponse(500, 'Failed to save uploaded file');
}

// Optional: Save file information to database
try {
    // Example database connection and query
    /*
    $pdo = new PDO("mysql:host=localhost;dbname=your_database", "username", "password");
    $stmt = $pdo->prepare("INSERT INTO uploads (filename, original_name, title, description, category) VALUES (?, ?, ?, ?, ?)");
    $stmt->execute([$fileName, $_FILES['file']['name'], $title, $description, $category]);
    */


    // Return success response
    sendResponse(200, 'File uploaded successfully', [
        'filename' => $fileName,
        'path' => $uploadPath,
        'title' => $title,
        'category' => $category
    ]);

} catch (Exception $e) {
    // If database error occurs, delete uploaded file
    if (file_exists($uploadPath)) {
        unlink($uploadPath);
    }
    sendResponse(500, 'Database error: ' . $e->getMessage());
}
0SHAREFacebookLINE it!