Last updated: February 5, 2025

<span aria-hidden="true" id="handling-file-uploads-in-php-increasing-size-and-validating-uploads"></span>

# Handling file uploads in PHP: increasing size and validating uploads

![Kevin van Zonneveld](/assets/images/teammates/avatar-kvz-4.jpg?dpl=dpl_EgVneLSpgfLPyuLUzfbHZX9Uye4a)

**Kevin van Zonneveld**

Co-founder · Amsterdam, The Netherlands · Show bio

[](https://x.com/kvz)[](https://github.com/kvz)

Handling file uploads is a common requirement in web applications, but it presents its own challenges. This guide explores how to handle file uploads in PHP 8.3, including checking and increasing the maximum upload size, modifying PHP configurations, restricting file types, and validating uploads to enhance the security and efficiency of your applications.

<span aria-hidden="true" id="php-version-and-configuration-defaults"></span>

## PHP version and configuration defaults

This guide has been tested with PHP 8.3—the latest stable version as of 2024. In PHP 8.3, the default file upload settings typically include:

* `upload_max_filesize` set to 2M.
* `post_max_size` usually around 8M (the value may vary based on your configuration).
* `max_file_uploads` set to 20.

Review your current settings as needed before making changes.

<span aria-hidden="true" id="how-to-check-max-file-upload-size-in-php"></span>

## How to check max file upload size in PHP

In PHP 8.3, the default upload\_max\_filesize is 2MB and max\_file\_uploads is 20. Before making any changes, it's essential to know your current upload limits. PHP controls file upload sizes with two configuration directives: `upload_max_filesize` and `post_max_size`. You can check these values by creating a simple PHP script:

```php
<?php
try {
    echo 'upload_max_filesize: ' . ini_get('upload_max_filesize') . '<br>';
    echo 'post_max_size: ' . ini_get('post_max_size') . '<br>';
    echo 'max_file_uploads: ' . ini_get('max_file_uploads') . '<br>';
    echo 'memory_limit: ' . ini_get('memory_limit') . '<br>';
} catch (Exception $e) {
    error_log('Error checking PHP configuration: ' . $e->getMessage());
    echo 'Error checking configuration settings.';
}
?>

```

Save this script as `check_upload_size.php` and run it on your server. It will display the current maximum file upload size and the maximum post size allowed.

Alternatively, you can use the `phpinfo()` function to get a full overview of your PHP configuration:

```php
<?php
phpinfo();
?>

```

Accessing this script in your browser will provide detailed information about your PHP configuration.

<span aria-hidden="true" id="how-to-increase-file-upload-size-in-php"></span>

## How to increase file upload size in PHP

If you need to allow larger file uploads, you will have to adjust the `upload_max_filesize` and`post_max_size` directives in your PHP configuration. Here is how you can do it:

<span aria-hidden="true" id="using-htaccess-for-apache-24"></span>

### Using `.htaccess` (for apache 2.4+)

Add the following lines to your `.htaccess` file:

```apache
<IfModule mod_php.c>
    php_value upload_max_filesize 20M
    php_value post_max_size 25M
    php_value memory_limit 256M
    php_value max_execution_time 300
</IfModule>

```

This sets the maximum upload file size to 20 megabytes and the maximum post size to 25 megabytes. Adjust the values according to your needs.

<span aria-hidden="true" id="using-php-fpm-configuration"></span>

### Using php-fpm configuration

If you're using PHP-FPM, add these settings to your pool configuration file (usually in`/etc/php/8.3/fpm/pool.d/www.conf`):

```ini
php_admin_value[upload_max_filesize] = 20M
php_admin_value[post_max_size] = 25M
php_admin_value[memory_limit] = 256M

```

<span aria-hidden="true" id="how-to-change-max-file-upload-size-in-phpini-on-ubuntu"></span>

## How to change max file upload size in `php.ini` on Ubuntu

If you have access to your server's `php.ini` file, you can make the changes there. Here is how to do it on an Ubuntu system:

1. Locate your `php.ini` file. For PHP 8.3, it's usually at `/etc/php/8.3/apache2/php.ini` or`/etc/php/8.3/fpm/php.ini`.
2. Open the file in a text editor with root privileges:

```bash
sudo nano /etc/php/8.3/apache2/php.ini  
```

3. Find and modify these directives:

```ini
upload_max_filesize = 20M  
post_max_size = 25M  
memory_limit = 256M  
max_execution_time = 300  
max_file_uploads = 50  
```

4. Save the file and exit the editor.
5. Restart your web server and PHP-FPM (if applicable):

```bash
sudo systemctl restart apache2  
sudo systemctl restart php8.3-fpm  
```

<span aria-hidden="true" id="implementing-file-upload-functionality-in-php"></span>

## Implementing file upload functionality in PHP

With the configuration set, you can now implement file upload functionality in your application.

<span aria-hidden="true" id="html-form"></span>

### HTML form

First, create an HTML form that allows users to upload files:

```html
<form action="upload.php" method="post" enctype="multipart/form-data">
  <label for="file">Choose file to upload:</label>
  <input type="file" name="file" id="file" required />
  <input type="submit" value="Upload" />
</form>

```

Make sure to set `enctype="multipart/form-data"` in the form tag to handle file uploads.

<span aria-hidden="true" id="php-upload-script"></span>

### PHP upload script

Here's a modern, secure implementation of `upload.php` using PHP 8.3 features:

```php
<?php
declare(strict_types=1);

class FileUploadHandler {
    private string $uploadDirectory;
    private array $allowedTypes;
    private array $allowedExtensions;
    private int $maxFileSize;
    private array $uploadedFiles = [];

    public function __construct(
        string $uploadDirectory = 'uploads/',
        array $allowedTypes = ['image/jpeg', 'image/png', 'application/pdf'],
        array $allowedExtensions = ['jpg', 'jpeg', 'png', 'pdf'],
        int $maxFileSize = 5242880 // 5MB
    ) {
        $this->uploadDirectory = $uploadDirectory;
        $this->allowedTypes = $allowedTypes;
        $this->allowedExtensions = $allowedExtensions;
        $this->maxFileSize = $maxFileSize;

        $this->initializeUploadDirectory();
    }

    private function initializeUploadDirectory(): void {
        if (!is_dir($this->uploadDirectory)) {
            if (!mkdir($this->uploadDirectory, 0755, true)) {
                throw new RuntimeException('Failed to create upload directory');
            }
        }

        $htaccess = $this->uploadDirectory . '.htaccess';
        if (!file_exists($htaccess)) {
            file_put_contents($htaccess, "php_flag engine off\nOptions -Indexes\n");
        }
    }

    public function handleUpload(): array {
        try {
            if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
                throw new RuntimeException('Invalid request method');
            }

            if (!isset($_FILES['file'])) {
                throw new RuntimeException('No file uploaded');
            }

            $file = $_FILES['file'];
            $this->validateUpload($file);

            $fileInfo = $this->processUpload($file);
            $this->uploadedFiles[] = $fileInfo;

            return [
                'success' => true,
                'message' => 'File uploaded successfully',
                'file' => $fileInfo
            ];

        } catch (Exception $e) {
            error_log('Upload error: ' . $e->getMessage());
            return [
                'success' => false,
                'message' => $e->getMessage()
            ];
        }
    }

    private function validateUpload(array $file): void {
        if ($file['error'] !== UPLOAD_ERR_OK) {
            throw new RuntimeException($this->getUploadErrorMessage($file['error']));
        }

        if ($file['size'] > $this->maxFileSize) {
            throw new RuntimeException('File is too large');
        }

        $fileType = mime_content_type($file['tmp_name']);
        if (!in_array($fileType, $this->allowedTypes, true)) {
            throw new RuntimeException('Invalid file type');
        }

        $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
        if (!in_array($extension, $this->allowedExtensions, true)) {
            throw new RuntimeException('Invalid file extension');
        }

        if (!is_uploaded_file($file['tmp_name'])) {
            throw new RuntimeException('Invalid upload attempt');
        }
    }

    private function processUpload(array $file): array {
        $hash = hash_file('sha256', $file['tmp_name']);
        $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
        $newFilename = sprintf('%s_%s.%s', uniqid('', true), $hash, $extension);
        $destination = $this->uploadDirectory . $newFilename;

        if (!move_uploaded_file($file['tmp_name'], $destination)) {
            throw new RuntimeException('Failed to move uploaded file');
        }

        chmod($destination, 0644);

        return [
            'name' => $file['name'],
            'type' => mime_content_type($destination),
            'size' => filesize($destination),
            'hash' => $hash,
            'path' => $destination
        ];
    }

    private function getUploadErrorMessage(int $error): string {
        return match($error) {
            UPLOAD_ERR_INI_SIZE => 'File exceeds upload_max_filesize',
            UPLOAD_ERR_FORM_SIZE => 'File exceeds MAX_FILE_SIZE',
            UPLOAD_ERR_PARTIAL => 'File was only partially uploaded',
            UPLOAD_ERR_NO_FILE => 'No file was uploaded',
            UPLOAD_ERR_NO_TMP_DIR => 'Missing temporary folder',
            UPLOAD_ERR_CANT_WRITE => 'Failed to write file to disk',
            UPLOAD_ERR_EXTENSION => 'File upload stopped by extension',
            default => 'Unknown upload error'
        };
    }
}

// Usage
header('Content-Type: application/json');

$handler = new FileUploadHandler();
$result = $handler->handleUpload();

echo json_encode($result, JSON_THROW_ON_ERROR);

```

This implementation includes:

* Strict type checking
* Comprehensive error handling with try-catch
* File hash verification for integrity checks
* Secure file type validation using the Fileinfo extension
* Proper directory permissions and .htaccess protection
* Protection against common upload vulnerabilities

<span aria-hidden="true" id="best-practices-for-secure-file-uploads"></span>

## Best practices for secure file uploads

<span aria-hidden="true" id="directory-security"></span>

### Directory security

1. Set proper permissions:

```bash
chmod 755 uploads/  
chmod 644 uploads/*  
```

2. Use open\_basedir restriction in php.ini:

```ini
open_basedir = /var/www/uploads/:/tmp/  
```

3. Organize uploads into randomized subdirectories to isolate files and reduce exposure to directory traversal attacks.
4. Implement rate limiting:

```php
<?php  
session_start();  
if (!isset($_SESSION['upload_count'])) {  
    $_SESSION['upload_count'] = 0;  
    $_SESSION['upload_time'] = time();  
}  
if (time() - $_SESSION['upload_time'] > 3600) {  
    $_SESSION['upload_count'] = 0;  
    $_SESSION['upload_time'] = time();  
}  
if ($_SESSION['upload_count'] >= 10) {  
    throw new RuntimeException('Upload limit exceeded');  
}  
$_SESSION['upload_count']++;  
```

<span aria-hidden="true" id="virus-scanning"></span>

### Virus scanning

Implement ClamAV scanning for uploaded files:

```php
<?php
function scanFile(string $filepath): bool {
    $socket = socket_create(AF_UNIX, SOCK_STREAM, 0);
    socket_connect($socket, '/var/run/clamav/clamd.ctl');
    socket_send($socket, "SCAN $filepath\n", strlen("SCAN $filepath\n"), 0);
    $result = socket_read($socket, 4096);
    socket_close($socket);
    return strpos($result, 'OK') !== false;
}
?>

```

<span aria-hidden="true" id="modern-framework-integration"></span>

### Modern framework integration

For more robust handling, consider using modern PHP frameworks. For example, a Laravel implementation might look like this:

```php
<?php
// Laravel example
use Illuminate\Http\Request;

public function upload(Request $request)
{
    $request->validate([
        'file' => 'required|file|mimes:pdf,jpg,png|max:5120'
    ]);

    $path = $request->file('file')->store('uploads');
    return response()->json(['success' => true, 'path' => $path]);
}

```

<span aria-hidden="true" id="advanced-upload-techniques"></span>

## Advanced upload techniques

Beyond the basics, you can further improve the upload experience and handle more demanding scenarios:

* **Handling AJAX Uploads:** Use XMLHttpRequest or the Fetch API to upload files asynchronously. This approach allows you to track upload progress and provide real-time feedback to users. For example:

```html
<script>  
  const fileInput = document.getElementById('file')  
  fileInput.addEventListener('change', function () {  
    const file = fileInput.files[0]  
    const xhr = new XMLHttpRequest()  
    xhr.upload.addEventListener('progress', function (e) {  
      if (e.lengthComputable) {  
        const percent = (e.loaded / e.total) * 100  
        console.log('Upload progress: ' + percent.toFixed(2) + '%')  
      }  
    })  
    xhr.open('POST', 'upload.php')  
    const formData = new FormData()  
    formData.append('file', file)  
    xhr.send(formData)  
  })  
</script>  
```

* **Chunked Uploads for Large Files:** For very large files, consider breaking the file into smaller chunks and uploading them sequentially. This method can improve reliability and support resumable uploads.
* **Supporting Additional File Formats:** Extend your validation logic to support other formats such as WebP images or ZIP archives. Always perform strict validation to ensure the file's content matches its extension.

<span aria-hidden="true" id="conclusion"></span>

## Conclusion

By following these techniques, you can securely and efficiently handle file uploads in PHP. From increasing upload size limits and robust validation to implementing advanced methods like AJAX uploads and chunked transfers, these practices help improve both security and user experience. For an integrated solution using modern file uploading tools, consider exploring Transloadit's[handling uploads service](/index.md).

\#php#file-upload#validation#upload-size#handling-uploads-service

### 👩‍💻 Join 20k+ developers

Sign up for our [monthly newsletter](/newsletters.md) to receive direct links to 3 exclusive tech — and 2 product updates. No less, no more.

Your email:

Get access

## File uploading and encoding. Made simple.

Transloadit streamlines file handling for developers, trusted by brands like Coursera and The New York Times. We’re known for a reliable API, top-notch support, and a strong commitment to open source, with projects like [Uppy⁠](https://uppy.io) and [Tus⁠](https://tus.io) setting standards in file processing.

[Sign up](/c/)[Book a Demo](https://survey.typeform.com/to/kRg47Xi5)

No credit card needed

Cancel anytime
