- Fix: PHP upload form not working.
- Upload debug script.
- enctype
- Use POST, as GET doesn’t support uploads.
- Check your PHP’s file_uploads configuration.
- Check your post_max_size and upload_max_filesize settings.
- Temporary directory not writable?
- Is the $_FILES array empty?
- Enable PHP errors.
- Разъяснение сообщений об ошибках
- Exception Handling in PHP
- PHP nested try-catch
- Catching all PHP exceptions
- Catching specific PHP exceptions
- The exception handler
- PHP framework exception handling
- Track, Analyze and Manage PHP Errors With Rollbar
Fix: PHP upload form not working.
This troubleshooting guide should help you figure out why your PHP upload form isn’t working. In some cases, you may find that the $_FILES array is completely empty, despite the fact that a file has been selected and uploaded.
Upload debug script.
If you are looking for a quick and easy answer, try placing the following code at the top of your upload script:
/** * Check to see if POST was used and that its content length is less than the value in post_max_size */ $requestType = $_SERVER['REQUEST_METHOD']; if($requestType != 'POST')< echo 'Request type was ' . $requestType . ' - File uploads will only work with POST. Are you using method="post" in your form element?
'; exit; > else< if(isset($_SERVER['CONTENT_TYPE']))< $contentType = strtolower($_SERVER['CONTENT_TYPE']); if(!stristr($contentType, 'multipart/form-data'))< echo 'Could not find multipart/form-data in Content-Type. Did you use enctype="multipart/form-data" in your form element?
'; > > if(isset($_SERVER['CONTENT_LENGTH']))< $postSize = $_SERVER['CONTENT_LENGTH']; $maxPostSize = ini_get('post_max_size'); if($maxPostSize == 0)< echo 'post_max_size is set to 0 - unlimited.
'; > else < if(strlen($maxPostSize) >1) < $lastChar = substr($maxPostSize, -1); $maxPostSize = substr($maxPostSize, 0, -1); if($lastChar == 'G')< $maxPostSize = $maxPostSize * 1024 * 1024 * 1024; >if($lastChar == 'M') < $maxPostSize = $maxPostSize * 1024 * 1024; >if($lastChar == 'K') < $maxPostSize = $maxPostSize * 1024; >if($postSize > $maxPostSize)< echo 'The size of the POST request (' . $postSize . ' bytes) exceeded the limit of post_max_size (' . $maxPostSize . ' bytes) in your php.ini file
'; exit; > > else < if($postSize >$maxPostSize)< echo 'The size of the POST request (' . $postSize . ' bytes) exceeded the limit of post_max_size (' . $maxPostSize . ' bytes) in your php.ini file
'; exit; > > > > else< echo 'CONTENT_LENGTH not found. Make sure that your POST request is smaller than the ' . ini_get('post_max_size') . ' post_max_size in php.ini
'; > > $tempFolder = ini_get('upload_tmp_dir'); if(strlen(trim($tempFolder)) == 0)< echo 'upload_tmp_dir was blank. No temporary upload directory has been set in php.ini
'; exit; > else< echo 'upload_tmp_dir is set to: ' . $tempFolder . '
'; > if(!is_dir($tempFolder))< echo 'The temp upload directory specified in upload_tmp_dir does not exist: ' . $tempFolder . '
'; exit; > else< echo $tempFolder . ' is a valid directory
'; > if(!is_writable($tempFolder))< echo 'The temp upload directory specified in upload_tmp_dir is not writeable: ' . $tempFolder . '
'; echo 'Does PHP have permission to write to this directory?
'; exit; > else< echo $tempFolder . ' is writeable
'; > $write = file_put_contents($tempFolder . '/' . uniqid(). '.tmp', 'test'); if($write === false)< echo 'PHP could not create a file in ' . $tempFolder . '
'; exit; > else< echo 'PHP successfully created a test file in: ' . $tempFolder . '
'; > if(ini_get('file_uploads') == 1)< echo 'The file_uploads directive in php.ini is set to 1, which means that your PHP configuration allows file uploads
'; > else< echo 'The file_uploads directive in php.ini has been set to 0 - Uploads are disabled on this PHP configuration.
'; exit; > if(empty($_FILES)) < echo 'The $_FILES array is empty. Is your form using method="post" and enctype="multipart/form-data"? Did the size of the file exceed the post_max_size in PHP.ini?'; exit; >else< foreach($_FILES as $file)< if($file['error'] !== 0)< echo 'There was an error uploading ' . $file['name'] . '
'; switch($file['error'])< case 1: echo 'Size exceeds the upload_max_filesize directive in php.ini
'; break; case 2: echo 'Size exceeds the MAX_FILE_SIZE field in your HTML form
'; break; case 3: echo 'File was only partially uploaded
'; break; case 4: echo 'No file was selected by the user
'; break; case 6: echo 'PHP could not find the temporary upload folder
'; break; case 7: echo 'PHP failed to write to disk. Possible permissions issue?
'; break; case 8: echo 'A PHP extension prevented the file from being uploaded.
'; break; default: echo 'An unknown error occured: ' . $file['error'] . '
'; break; > > else< echo $file['name'] . ' was successfully uploaded to ' . $file['tmp_name'] . '
'; > > >
The PHP above will attempt to detect some of the most common issues that people have with upload forms. Hopefully, it will point you in the right direction!
enctype
The first thing you should do is make sure that you’ve set the correct enctype attribute on your form element. This attribute basically tells the server how the incoming form data should be encoded. If you forgot to add enctype to your form, no file will be uploaded and the $_FILES array will remain empty:
In this particular case, we’ve set enctype to “multipart/form-data” instead of the default “application/x-www-form-urlencoded”. Setting enctype to “multipart/form-data” prevents data from being encoded.
Use POST, as GET doesn’t support uploads.
You will need to make sure that your HTML form has set the method attribute to “POST”, as file uploads are supported in GET requests (see the above code for an example of “POST” being set as the form method). If the method attribute in your form is not set, then the form will send a GET request by default.
Check your PHP’s file_uploads configuration.
In your php.ini configuration file, you will find a directive called file_uploads. This directive specifies whether PHP should allow HTTP uploads or not. In default PHP installations, this is given the value “1”, which is BOOLEAN for TRUE – meaning file uploads are allowed by default. However, if your web host has disabled file uploads, then you may find that this directive has been set to “0”. To check the value of this directive, you can simply check your PHP.ini file. If you do not have access to the PHP.ini file, then you can use the following code:
Check your post_max_size and upload_max_filesize settings.
These are two PHP.ini directives that could potentially stop your upload form from working.
- upload_max_filesize: The upload_max_filesize directive specifies the maximum size of a file that can be uploaded to the server. By default, this is set to “2M” – meaning 2MB. If a file is larger than the value of this directive, it will not be uploaded. In the past, I have seen this causing 500 Internal Server Errors!
- post_max_size: This directive sets the maximum size of post data that can be submitted to the server. By default, it is set to “8M”. This means that all POST data must be 8MB in size or less. If the file that you are uploading is 9MB in size, then it will be discarded by the server.
Note that the post_max_size directive should always be larger than upload_max_filesize, as it specifies the max size of both regular form POST data AND the uploaded file data.
When you are setting the values for these directives, make sure that you use a single “M” – not “MB”. i.e. If you want your upload_max_filesize to be 80MB, then you will need to use “80M”, not “80MB”. If you omit the “M” character and use an integer, then PHP will interpret the value as bytes.
Temporary directory not writable?
If you’ve reached this part of the troubleshooting guide, then it is fair to say that something funny is going on. The next port of call is to check if your server’s temporary folder is writable (i.e. it exists and that web server has permission to save files to it). When a file is uploaded to the server, it is automatically saved to the temporary folder until you choose to move it. This folder is set in the PHP.ini file under the directive upload_tmp_dir.
Have a look at the following piece of PHP code, which attempts to check if the upload_tmp_dir directory is available:
//Check to see if the temporary folder //is writable. $tempFolder = ini_get('upload_tmp_dir'); echo 'Your upload_tmp_dir directive has been set to: "' . $tempFolder . '"
'; //Firstly, lets make sure that the upload_tmp_dir //actually exists. if(!is_dir($tempFolder)) < throw new Exception($tempFolder . ' does not exist!'); >else< echo 'The directory "' . $tempFolder . '" does exist.
'; > if(!is_writable($tempFolder)) < throw new Exception($tempFolder . ' is not writable!'); >else< echo 'The directory "' . $tempFolder . '" is writable. All is good.
'; >
If you run the code above and no exceptions are thrown, then it is fair to say that the issue isn’t with your upload_tmp_dir directory.
Is the $_FILES array empty?
In the script that handles your uploaded files, do a var_dump on the $_FILES array like so:
Is the $_FILES array empty? If it isn’t – then the files are being uploaded to the temporary directory on your server. If the $_FILES array is empty, then you’ve probably messed up on one of the pitfalls that were listed above.
Enable PHP errors.
At this stage, I think it’s a good idea to enable PHP’s error reporting so that we can see what is actually happening. Maybe you’re getting a blank page or maybe the server is responding with an unhelpful 500 Internal Server Error page.
If the files are being uploaded but they are not being moved to the relevant directory, then it is probably because the file path doesn’t exist (typos) or the correct permissions have not been set. To see what’s actually going wrong, try placing the following piece of code at the top of your upload script:
Hopefully, this troubleshooting guide helped you to fix your PHP upload form – or at the very least, it pointed you in the right direction.
Разъяснение сообщений об ошибках
PHP возвращает код ошибки наряду с другими атрибутами принятого файла. Он расположен в массиве, создаваемом PHP при загрузке файла, и может быть получен при обращении по ключу error. Говоря другими словами, код ошибки можно найти в переменной $_FILES[‘userfile’][‘error’] .
UPLOAD_ERR_OK
Значение: 0; Ошибок не возникло, файл был успешно загружен на сервер.
UPLOAD_ERR_INI_SIZE
Значение: 1; Размер принятого файла превысил максимально допустимый размер, который задан директивой upload_max_filesize конфигурационного файла php.ini .
UPLOAD_ERR_FORM_SIZE
Значение: 2; Размер загружаемого файла превысил значение MAX_FILE_SIZE, указанное в HTML-форме.
UPLOAD_ERR_PARTIAL
Значение: 3; Загружаемый файл был получен только частично.
UPLOAD_ERR_NO_FILE
Значение: 4; Файл не был загружен.
UPLOAD_ERR_NO_TMP_DIR
Значение: 6; Отсутствует временная папка. Добавлено в PHP 5.0.3.
UPLOAD_ERR_CANT_WRITE
Значение: 7; Не удалось записать файл на диск. Добавлено в PHP 5.1.0.
UPLOAD_ERR_EXTENSION
Значение: 8; PHP-расширение остановило загрузку файла. PHP не предоставляет способа определить какое расширение остановило загрузку файла; в этом может помочь просмотр списка загруженных расширений из phpinfo() . Добавлено в PHP 5.2.0.
Exception Handling in PHP
The primary method of handling exceptions in PHP is the try-catch. In a nutshell, the try-catch is a code block that can be used to deal with thrown exceptions without interrupting program execution. In other words, you can «try» to execute a block of code, and «catch» any PHP exceptions that are thrown.
PHP nested try-catch
Try-catch blocks in PHP can be nested up to any desired levels and are handled in reverse order of appearance i.e. innermost exceptions are handled first.
Nested blocks can be useful in case a block of code causes an exception, which can be handled within that block and program execution can continue in the outer block.
They can also be useful in case the handling of an exception causes another exception.
Here is an example of a nested try-catch block:
try < try< if(file_exists("myfile.json"))< //upload file >else < throw new Exception( 'File not found'); >> catch (Exception $e) < throw new Exception( 'Unable to upload file',0,$e); >//continue outer try block code > catch (Exception $e)< echo $e->getMessage() . "
"; while($e = $e->getPrevious()) < echo 'Previous exception: '.$e->getMessage() . "
"; > >
In this example, a file is uploaded and it is checked whether the file exists or not prior to the upload operation. If it does not exist, an exception is thrown.
This code that checks whether the file exists or not is placed within a try-catch block, which is nested within another try-catch block.
In case the file is not found, the inner block throws an ‘Unable to upload file’ exception, which is caught and handled by the outer block, leading to the following output:
Unable to upload file Previous exception: File not found
Catching all PHP exceptions
The simplest way to catch exceptions is through the use of a generic try-catch block. Because exceptions are objects, they all extend a built-in Exception class (see Throwing Exceptions in PHP), which means that catching every PHP exception thrown is as simple as type-hinting the global exception object, which is indicated by adding a backslash in front:
Catching specific PHP exceptions
While catching every exception thrown is great for simplistic implementations—such as generalizing API error responses—best practice is to catch for specific PHP exceptions. By using the same type-hinting method shown above in reference to specific exception objects instead of a global exception object, you can react more effectively to individual problems that your application may encounter on the way.
try < // . >catch ( \Custom\Exception $e ) < // . >
Catching just one type of PHP exception isn’t very valuable though, is it? What happens if your application throws a different exception? Much like an if-elseif-else chain, a try-catch block can have multiple catches—which, when combined with a check for the built-in PHP exception class, allows you to logically adapt to any and all issues that may arise:
try < // . >catch ( \Custom\Exception $e ) < // . >catch ( \Other\Exception $e ) < // . >catch ( \Exception $e ) < // . >
The exception handler
While wrapping dangerous code in try-catch blocks is a great way to harden an application against unexpected PHP errors, you can’t always catch everything. Sometimes an exception falls through the cracks, which is where the global PHP exception handler comes into play. This method, dubbed set_exception_handler, provides a fallback for any uncaught exceptions.
set_exception_handler(function($exception) < // . >);
Although you can utilize this method in a number of different ways, it is generally best used for logging and display formatting, as every PHP exception thrown will be caught—not just built-in exceptions—which can result in unpredictable behavior if not used properly.
PHP framework exception handling
While the global exception handler can be used regardless of framework, it is important to know that frameworks like Symfony and Laravel have their own ways of handling PHP exceptions. Laravel, for example, handles all exceptions using a class that defines how exceptions should be reported and rendered. Symfony, on the other hand, uses an event listener to catch exceptions. Both valid ways to handle PHP exceptions, but designed to fit within their own ecosystems.
Check out our blog to see a working example of Laravel error reporting.
Track, Analyze and Manage PHP Errors With Rollbar
Managing errors and PHP exceptions in your code is challenging. It can make deploying production code an unnerving experience. Being able to track, analyze, and manage errors in real-time can help you to proceed with more confidence. Rollbar automates error monitoring and triaging, making fixing PHP errors easier than ever. Learn more about Rollbar’s features for PHP and then sign up for a free trial.