PHP File Upload Example

This example shows the HTML and PHP to upload a file.

Browsers handle the MAX_FILE_SIZE input and accept attribute differently. Some will filter the files offered through the dialog box to only list those identified by the accept attribute. Some will allow you to select a file that is too large, and submit it to the server, without any content. In this case, the tmp_name is empty, error is 2, and size is 0.

In all cases you must validate the file on the server side.

HTML to upload a file:


<?php define('FILE_UPLOAD_MAX',min(str_replace('M','000000',ini_get('upload_max_filesize')),str_replace('M','000000',ini_get('post_max_size'))));
 ?>
<!doctype html>
<html lang="en">
	<head>
		<meta charset="utf-8">
		<title>upload demo</title>
		<link href="upload.css" rel="stylesheet">
	</head>
	<body>
		<h1>upload demo</h1>
		<form method="post" enctype="multipart/form-data" action="upload-file.php">
			<input type="hidden" name="MAX_FILE_SIZE" value="<?= FILE_UPLOAD_MAX ?> " >
			<div class="block">
				<label for="file">File</label>
				<input type="file" name="file" id="file" value="" accept="image/*">
			</div>
			<button type="submit">Go</button>
		</form>
	</body>
</html>

PHP to accept it:


<?php
header('Content-Type: text/plain');
define('MAX_FILE_SIZE',min(
        str_replace('M','000000',ini_get('upload_max_filesize')),
        str_replace('M','000000',ini_get('post_max_size'))));

function is_accepted($sAccept,$sFiletype) {
        $aAccept=explode(',',$sAccept);
        return in_array($sFiletype,$aAccept,TRUE);
}

function size_ok($iMaxSize,$iSize) {
        return $iSize <= $iMaxSize;
}

function upload(&$files,$sAccept='*/*',$iMaxSize=MAX_FILE_SIZE) {
        foreach ($_FILES as $k => $v) {
                if ($v['tmp_name']==='') {
                        continue;
                }
                // More robust type checking: https://www.php.net/manual/en/features.file-upload.php#114004
                if (!is_accepted($sAccept,$v['type'])) {
                        throw new Exception($v['type'].' files cannot be sent');
                }
                if (!size_ok($iMaxSize,$v['size'])) {
                        throw new Exception('File cannot be larger than '.$iMaxSize);
                }

               // do antivirus scan here
               $vname = $v['tmp_name'];
               system('clamscan '.escapeshellarg($vname),$result);
               echo $result;
               if ($result !== 0) {
                  die;
              }
              echo 'Scanned okay';
                // Thanks to: https://www.php.net/manual/en/features.file-upload.php#114004
                // strip out anything other than letters, digits, underscores, periods and dashes
                $name = preg_replace('/[^\w.-]/','',$v['name']);
                if ($name === '') {
                        throw new Exception('Invalid filename');
                }
                if (!move_uploaded_file($v['tmp_name'], $name)) {
                        throw new Exception('Upload failed');
                }
                $element = [
                        'filename' => $name,
                        'file' => $v['tmp_name'],
                        'content_type' => $v['type'] ];
                $files[] = $element;
        }
        return true;
}

$uploadFiles = [];
try {
        if (upload($uploadFiles, 'image/png,image/jpg,image/jpeg,image/gif', MAX_FILE_SIZE)) {
                var_dump($uploadFiles);
        } else {
                echo 'Upload failed';
        }
} catch (Exception $e) {
        echo $e->getMessage().PHP_EOL;
        error_log('File upload failed '.$e->getMessage());
}