特点
在线手册:中文 英文
PHP手册

文件上传处理

Table of Contents


特点
在线手册:中文 英文
PHP手册
PHP手册 - N: 文件上传处理

用户评论:

xmontero at dsitelecom dot com (07-Feb-2012 06:23)

If "large files" (ie: 50 or 100 MB) fail, check this:

It may happen that your outgoing connection to the server is slow, and it may timeout not the "execution time" but the "input time", which for example in our system defaulted to 60s. In our case a large upload could take 1 or 2 hours.

Additionally we had "session settings" that should be preserved after upload.

1) You might want review those ini entries:

* session.gc_maxlifetime
* max_input_time
* max_execution_time
* upload_max_filesize
* post_max_size

2) Still fails? Caution, not all are changeable from the script itself. ini_set() might fail to override.

More info here:
http://www.php.net/manual/es/ini.list.php

You can see that the "upload_max_filesize", among others, is PHP_INI_PERDIR and not PHP_INI_ALL. This invalidates to use ini_set():
http://www.php.net/manual/en/configuration.changes.modes.php

Use .htaccess instead.

3) Still fails?. Just make sure you enabled ".htaccess" to overwrite your php settings. This is made in the apache file. You need at least AllowOverride Options.

See this here:
http://www.php.net/manual/en/configuration.changes.php

You will necessarily allow this manually in the case your master files come with AllowOverride None.

Conclussion:

Depending on the system, to allow "large file uploads" you must go up and up and up and touch your config necessarily up to the apache config.

Sample files:

These work for me, for 100MB uploads, lasting 2 hours:

In apache-virtual-host:
-----------------------------------------------------------
<Directory /var/www/MyProgram>
    AllowOverride Options
</Directory>
-----------------------------------------------------------

In .htaccess:
-----------------------------------------------------------
php_value session.gc_maxlifetime 10800
php_value max_input_time         10800
php_value max_execution_time     10800
php_value upload_max_filesize    110M
php_value post_max_size          120M
-----------------------------------------------------------

In the example,
- As I last 1 to 2 hours, I allow 3 hours (3600x3)
- As I need 100MB, I allow air above for the file (110M) and a bit more for the whole post (120M).

joehopf at gmail dot com (19-Dec-2010 03:02)

Please be aware that if you do a comparision like ($error == UPLOAD_ERR_OK) you are NOT on the safe side!

The official example is fine, because I executes a loop for all $_FILES entries. But if you only expect one file and you check $_FILE['something']['error']  == UPLOAD_ERR_OK directly, it will true even if no file was uploaed, because the constant is zero!

So please do $_FILE['something']['error']  === UPLOAD_ERR_OK!

Marcus (19-Nov-2010 05:00)

This is the code I use, it works very well and is super simple

*NOTE*
This isn't upload for users.  This is an admin page, so monitoring file types isn't an issue
but would be easy to do merging one of the examples in previous comments with this one

//////////////////////////////////////////////////////////////////////
//THE FORM ON THE HTML PAGE
//////////////////////////////////////////////////////////////////////

<form action="upload.php" method="post" enctype="multipart/form-data">
<input type="file"  name="ufile" />
<input type="submit" value="Upload" />
</form>

//////////////////////////////////////////////////////////////////////
//THE PHP CODE IN upload.php
//////////////////////////////////////////////////////////////////////

<?php

//The files have a link on a page for downloading
//and filenames are also put in the progress bar so
//the file can be viewed in the browser (ie. PDF files)
//so replace a few characters.  Since the file links are
//loaded onto another page via php and filenames
//are displayed, I wanted to use this method instead
//of url_encode() [just looks funny when displayed]

$SafeFile = $HTTP_POST_FILES['ufile']['name'];
$SafeFile = str_replace("#", "No.", $SafeFile);
$SafeFile = str_replace("$", "Dollar", $SafeFile);
$SafeFile = str_replace("%", "Percent", $SafeFile);
$SafeFile = str_replace("^", "", $SafeFile);
$SafeFile = str_replace("&", "and", $SafeFile);
$SafeFile = str_replace("*", "", $SafeFile);
$SafeFile = str_replace("?", "", $SafeFile);

$uploaddir = "uploads/";
$path = $uploaddir.$SafeFile;

if(
$ufile != none){ //AS LONG AS A FILE WAS SELECTED...

   
if(copy($HTTP_POST_FILES['ufile']['tmp_name'], $path)){ //IF IT HAS BEEN COPIED...

        //GET FILE NAME
       
$theFileName = $HTTP_POST_FILES['ufile']['name'];

       
//GET FILE SIZE
       
$theFileSize = $HTTP_POST_FILES['ufile']['size'];

        if (
$theFileSize>999999){ //IF GREATER THAN 999KB, DISPLAY AS MB
           
$theDiv = $theFileSize / 1000000;
           
$theFileSize = round($theDiv, 1)." MB"; //round($WhatToRound, $DecimalPlaces)
       
} else { //OTHERWISE DISPLAY AS KB
           
$theDiv = $theFileSize / 1000;
           
$theFileSize = round($theDiv, 1)." KB"; //round($WhatToRound, $DecimalPlaces)
       
}

echo <<<UPLS
<table cellpadding="5" width="300">
<tr>
    <td align="Center" colspan="2"><font color="#009900"><b>Upload Successful</b></font></td>
</tr>
<tr>
    <td align="right"><b>File Name: </b></td>
    <td align="left">
$theFileName</td>
</tr>
<tr>
    <td align="right"><b>File Size: </b></td>
    <td align="left">
$theFileSize</td>
</tr>
<tr>
    <td align="right"><b>Directory: </b></td>
    <td align="left">
$uploaddir</td>
</tr>
</table>

UPLS;

    } else {

//PRINT AN ERROR IF THE FILE COULD NOT BE COPIED
echo <<<UPLF
<table cellpadding="5" width="80%">
<tr>
<td align="Center" colspan="2"><font color=\"#C80000\"><b>File could not be uploaded</b></font></td>
</tr>

</table>

UPLF;
    }
}

?>

ling (03-Nov-2010 08:35)

Sometimes you may get empty $_FILES and empty $_POST.
If this happens, this is probably because the posted file size exceed the post_max_size php ini directive value.

You could use something like this to handle it in your form, here it is :

<?php
// The form isn't misbehavin then…
if (empty($_FILES) && empty($_POST) && isset($_SERVER['REQUEST_METHOD']) && strtolower($_SERVER['REQUEST_METHOD']) == 'post') {   
   
$poidsMax = ini_get('post_max_size');
   
$oElement->addError("fileoverload", "Your feet is too big, maximum allowed size here is $poidsMax.");
}
?>

Phil Ciebiera (17-Sep-2009 09:54)

On a Microsoft platform utilizing IIS, you may run into a situation where, upon moving the uploaded file, anonymous web users can't access the content without being prompted to authenticate first...

The reason for this is, the uploaded file will inherit the permissions of the directory specified in the directive upload_tmp_dir of php.ini.  If this directive isn't set, the default of C:\Windows\Temp is used.

You can work around this by granting the IUSR_[server name] user read access to your temporary upload directory, so that after you move_uploaded_file the permissions will already be set properly.

It's also a good idea to set the Execute Permissions of the upload directory to NOT include Executables, for security reasons. 
To accomplish this:
-Open the IIS Manager
-Browse to the relevant sites directory where the uploads will be placed
-Right Click the folder and select Properties
-In the Directory tab of the resulting dialog, set the Execute permissions to be None

This took me a while to figure out, so I hope this helps save some other peoples time.

dbennettNOSPAM at bensoft dot com (06-Aug-2009 06:15)

I needed to quickly patch a server with a lot of bad file upload
code (multiple sites).  Here's what I came up with.  Paste this
in every PHP file on the server that contains $_FILE before the
first reference of $_FILE:

<?php
  
// begin Dave B's Q&D file upload security code
 
$allowedExtensions = array("txt","csv","htm","html","xml",
   
"css","doc","xls","rtf","ppt","pdf","swf","flv","avi",
   
"wmv","mov","jpg","jpeg","gif","png");
  foreach (
$_FILES as $file) {
    if (
$file['tmp_name'] > '') {
      if (!
in_array(end(explode(".",
           
strtolower($file['name']))),
           
$allowedExtensions)) {
       die(
$file['name'].' is an invalid file type!<br/>'.
       
'<a href="javascript:history.go(-1);">'.
       
'&lt;&lt Go Back</a>');
      }
    }
  }
 
// end Dave B's Q&D file upload security code
?>

alex from france (15-Feb-2009 05:37)

<?php
/***
    this is a simple and complete function and
    the easyest way i have found to allow you
    to add an image to a form that the user can
    verify before submiting

    if the user do not want this image and change
    his mind he can reupload a new image and we
    will delete the last

    i have added the debug if !move_uploaded_file
    so you can verify the result with your
    directory and you can use this function to
    destroy the last upload without uploading
    again if you want too, just add a value...
***/

function upload_back() { global $globals;

/***
    1rst set the images dir and declare a files
    array we will have to loop the images
    directory to write a new name for our picture
***/

 
$uploaddir = 'images_dir/'; $dir = opendir($uploaddir);
 
$files = array();

/***
    if we are on a form who allow to reedit the
    posted vars we can save the image previously
    uploaded if the previous upload was successfull.
    so declare that value into a global var, we
    will rewrite that value in a hidden input later
    to post it again if we do not need to rewrite
    the image after the new upload and just... save
    the value...
***/

 
if(!empty($_POST['attachement_loos'])) { $globals['attachement'] = $_POST['attachement_loos']; }

/***
    now verify if the file exists, just verify
    if the 1rst array is not empty. else you
    can do what you want, that form allows to
    use a multipart form, for exemple for a
    topic on a forum, and then to post an
    attachement with all our other values
***/

 
if(isset($_FILES['attachement']) && !empty($_FILES['attachement']['name'])) {

/***
    now verify the mime, i did not find
    something more easy than verify the
    'image/' ty^pe. if wrong tell it!
***/

   
if(!eregi('image/', $_FILES['attachement']['type'])) {

      echo
'The uploaded file is not an image please upload a valide file!';

    } else {

/***
    else we must loop our upload folder to find
    the last entry the count will tell us and will
    be used to declare the new name of the new
    image. we do not want to rewrite a previously
    uploaded image
***/

       
while($file = readdir($dir)) { array_push($files,"$file"); echo $file; } closedir($dir);

/***
    now just rewrite the name of our uploaded file
    with the count and the extension, strrchr will
    return us the needle for the extension
***/

       
$_FILES['attachement']['name'] = ceil(count($files)+'1').''.strrchr($_FILES['attachement']['name'], '.');
       
$uploadfile = $uploaddir . basename($_FILES['attachement']['name']);

/***
    do same for the last uploaded file, just build
    it if we have a previously uploaded file
***/

       
$previousToDestroy = empty($globals['attachement']) && !empty($_FILES['attachement']['name']) ? '' : $uploaddir . $files[ceil(count($files)-'1')];

// now verify if file was successfully uploaded

     
if(!move_uploaded_file($_FILES['attachement']['tmp_name'], $uploadfile)) {

echo
'<pre>
Your file was not uploaded please try again
here are your debug informations:
'
.print_r($_FILES) .'
</pre>'
;

      } else {

          echo
'image succesfully uploaded!';

      }

/***
    and reset the globals vars if we maybe want to
    reedit the form: first the new image, second
    delete the previous....
***/

       
$globals['attachement'] = $_FILES['attachement']['name'];
        if(!empty(
$previousToDestroy)) { unlink($previousToDestroy); }

    }

  }
}

upload_back();

/***
    now the form if you need it (with the global...):

    just add the hidden input when you write your
    preview script and... in the original form but!
    if you have send a value to advert your script
    than we are remaking the form. for exemple with a
    hidden input with "reedit" as value  or with a
    $_GET method who can verify that condition
***/

echo '<form action="" method="post" enctype="multipart/form-data">

  <input type="file" name="attachement" name="attachement"></input>
  <input type="hidden" name="attachement_loos" name="attachement_loos" value="'
, $globals['attachement'] ,'"></input>

  <input type="submit" value="submit"></input>

</form>'
;
?>

info at levaravel dot com (30-Jan-2009 03:39)

A little codesnippet which returns a filesize in a more legible format.

<?php

function display_filesize($filesize){
   
    if(
is_numeric($filesize)){
   
$decr = 1024; $step = 0;
   
$prefix = array('Byte','KB','MB','GB','TB','PB');
       
    while((
$filesize / $decr) > 0.9){
       
$filesize = $filesize / $decr;
       
$step++;
    }
    return
round($filesize,2).' '.$prefix[$step];
    } else {

    return
'NaN';
    }
   
}

?>

damien from valex (05-Jan-2009 01:53)

This is simpler method of checking for too much POST data (alternative to that by v3 from sonic-world.ru).

<?php
   
if ($_SERVER['REQUEST_METHOD'] == 'POST' && empty($_POST) && $_SERVER['CONTENT_LENGTH'] > 0) {
        throw new
Exception(sprintf('The server was unable to handle that much POST data (%s bytes) due to its current configuration', $_SERVER['CONTENT_LENGTH']));
    }
?>

Robert W. (12-Dec-2008 03:05)

Here's a really fast way to get a files' extension:

<?php

$file
= $_FILES['userfile'];

$allowedExtensions = array("txt", "rtf", "doc");

function
isAllowedExtension($fileName) {
  global
$allowedExtensions;

  return
in_array(end(explode(".", $fileName)), $allowedExtensions);
}

if(
$file['error'] == UPLOAD_ERR_OK) {
  if(
isAllowedExtension($file['name'])) {
   
# Do uploading here
 
} else {
    echo
"Invalid file type";
  }
} else die(
"Cannot upload");

?>

This works in PHP v5+ -- haven't tested in PHP v4

rnagavel at yahoo dot com dot au (25-Nov-2008 09:10)

If $_FILES is always empty, check the method of your form.
It should be POST. Default method of a form is GET.

<form action="myaction.php">
 <input type="file" name"userfile">
</form>
File will not be uploaded as default method of the form is GET.

<form action="myaction.php" method="POST">
 <input type="file" name"userfile">
</form>
Files will be uploaded and $_FILES will be populated.

romke at romke dot nl (28-Aug-2008 12:26)

IIS7
has a upload limit of 30000000 (about 30mb)

You can change this with the command (for 250mb):

c:\windows\system32\inetsrv\appcmd set config -section:requestFiltering -requestLimits.maxAllowedContentLength:262144000

Or manual define it in:
%windir%\system32\inetsrv\config\applicationhost.config

Add this rule before the </requestFiltering> tag:
<requestLimits maxAllowedContentLength ="262144000" />

RK (21-Aug-2008 09:48)

If you're so inclined to get access to the http request body via php://input when the content-type is multipart/form-data, and you're running apache, this hack may be helpful:

.htaccess
SetEnvIf content-type (multipart/form-data)(.*) NEW_CONTENT_TYPE=multipart/form-data-alternate$2 OLD_CONTENT_TYPE=$1$2
RequestHeader set content-type %{NEW_CONTENT_TYPE}e env=NEW_CONTENT_TYPE

Obviously, this will bypass all of PHP's file handling, as if you had set file_uploads=0, except that the request body wont be discarded. I can't comment on the consequences/pitfalls, since I'm just messing around.

sedativchunk at gmail dot com (06-Jun-2008 06:19)

If you are using PHP 5, make sure you are using $_FILES to collect your post files. I spent an entire day trying to figure out why my files were not uploading when using $HTTP_POST_FILES. Previous to upgrading to PHP 5, $HTTP_POST_FILES was compatible with PHP 4, but you should always use the new method of something in your code!

jahajee (30-Apr-2008 12:27)

hi , i was having difficulty with the upload_max_filesize , if u set the max file size lesser than the php setting then ur script to report error will only work till this difference between ur max set file size and the php set max size .Hence if the uploaded file exceeds the php max file size then php end abruptly without a trace of error that is it behaves like no file is uploaded and hence no error reported .Sure if uploading a file is optional for a form then a user who uploads larger file will get no error and still the form will be processed only without the file.
The method of using GET can't be used for optional uploads. Can't find help even in the bugs .Be careful with optional uploads.
jahajee

Rob (24-Apr-2008 09:07)

You should not have any directories within your website root that has the permissions required for file upload.  If you are going to do a file upload, I recommend you use the PHP FTP Functions in conjunction with your file field, that way the files are transferred to a remote FTP location separate from your server.

dev at arthurk dot com (02-Apr-2008 06:44)

Here is a quick and easy way to get the base name and the extension of a file.

I noticed that many examples here use explode(...), however this doesn't handle filenames like foo-1.0.1.tar gracefully. This code does. (foo-1.0.1 is the base, and .tar is the extension).

<?php
      $file_basename
= substr($filename, 0, strripos($filename, '.')); // strip extention
     
$file_ext      = substr($filename, strripos($filename, '.'));
?>

Notice the use of "strripos()" instead of "stripos()".

If you need to detect .tar.gz, etc. as the ext (starting at the first dot), substitute "stripos" for "strripos".

ajs at earthshod dot co dot uk (24-Jan-2008 02:17)

Note that on Windows, EVERY file has execute permission.  This means whenever you upload a file from a Windows host, it will have its execute bit set.

If you are moving uploaded files to a directory where they will be accessible via HTTP  (necessary if e.g. you want to allow uploads of avatars),  you *must* use chmod() to make them non-executable after moving them to their intended location.  Otherwise, you run the risk that they could be treated by the web server as CGI scripts.

If you don't need uploaded files to be accessible directly via http, then use a .htaccess file containing the line "Deny from all" in the directory where you placed them; or, if your web server is set up with public_html directories, place uploaded files in a location *outside* public_html.

Note also that the uploaded files won't belong to you, but to the user in whose name httpd is running.  And on most systems, only root can chown() files  (even if they were your files to begin with).  This will mean you can't do file management via FTP / SSH unless you make the files world-writable .....  and you probably don't really want that.  (Workaround: put in a password protected script to chmod() files as required, and if for some reason you don't trust Apache's password protection, use your FTP client to make it non-world-readable when it is not needed.)

Tomas (07-Jan-2008 07:51)

An upploaded file ( $_FILES['userfile']['tmp_name'] ) has permission 600 and MySQL LOAD_FILE() function will not work!
Use chmod() to change permission.

ragtime at alice-dsl dot com (24-Sep-2007 04:55)

I don't believe the myth that 'memory_size' should be the size of the uploaded file. The files are definitely not kept in memory... instead uploaded chunks of 1MB each are stored under /var/tmp and later on rebuild under /tmp before moving to the web/user space.

I'm running a linux-box with only 64MB RAM, setting the memory_limit to 16MB and uploading files of sizes about 100MB is no problem at all! Nevertheless, some users reported a problem at a few 100MB, but that's not confirmed... ;-)

The other sizes in php.ini are set to 1GB and the times to 300... maybe the execution_time limits before, since the CPU is just a 233MHz one... :-)

====

OK,... I got it... finally!

If some of you have also problems uploading large files but the usual sizes/times in php.ini are ok, please check

    session.gc_maxlifetime

when you are using session management with your upload script!

The default value is 1440 which is just 24min... so with only 600kbit/s upload rate the session will be closed automatically after uploading
about 100MB. Actually you are able to upload more, but the file won't be copied from the temporary to the destination folder... ;-)

You can set the value also directly inside the php-script via
<?php ini_set("session.gc_maxlifetime","10800"); ?>

HNS (12-Sep-2007 09:30)

I rather check the imagetype with getimagesize. <4 and != 0 equals jpg, gif, png. Also it already gives you a chance to store other interesting data about the images.
php.ini vars that deal with size that need to be checked are
-max upload filesize
-max post data size
-memory limit (for script to use)
My suggestion is to keep the two latter greater then the upload file size limit to be able to give back some user errors.
When POST data size get exceeded it just doesn't run the script that is set to run at application of a form. So

v dot galyanin at gmail dot com (21-Jul-2007 11:37)

I try to set up file uploading under IIS 7 and PHP 5.

First problem was to set 2 variables in php.ini

 file_uploads = On

 upload_tmp_dir = "C:\Inetpub\wwwroot\uploads"

 For some reasons such directory name works,
 but "upload_tmp" won't work.

The second problem was to set correct user rigths for upload folders where you try to save your file. I set my upload folder rights for the "WORKGROUP/users" for the full access. You may experiment by yourselves if you not need execute access, for example.

sogdiev at gmail dot com (10-Jul-2007 09:19)

Hi there.
As far as I understand IE has his own MIME types based on the values stored in a registry. To locate this "feature" I spent a lot of time and was granted with a perfect headache. :)
In my case I tried to upload a CSV file on a server and abort a script in case if the corresponding file isn't of a desired type.
And it work fine with Opera and stuck with IE.
So the workaround is that you should add this values in your windows registry (I have windows xp box and it works fine for me)
[HKEY_CLASSES_ROOT\.csv]
"Content Type"="application/vnd.ms-excel"
@="Excel.CSV"
[HKEY_CLASSES_ROOT\.csv\Excel.CSV]
[HKEY_CLASSES_ROOT\.csv\Excel.CSV\ShellNew]

NB:
add the value "application/vnd.ms-excel" if you plan to open it with excel.

Richard Davey rich at corephp dot co dot uk (22-Jun-2007 01:05)

Beware the mime-types! Given the GIF security issue that has been doing the rounds recently you may be inclined to validate an update based on its reported mime-type from the $_FILES array. However be careful with this - it is set by the *browser*, not by PHP or the web server, and browsers are not consistent (what's new?!)

For example IE6/7 will upload a progressive JPEG as image/pjpeg, while Firefox and Opera will upload it as image/jpeg. More importantly IE will try and determine the mime type of the file by actually inspecting its contents. For example if you rename a perfectly valid PNG file to end with .zip instead, IE will still send a mime type of image/x-png, where-as Firefox and Opera will send application/x-zip-compressed and application/zip respectively, even though the file is a valid PNG.

In short if you are going to validate an upload on the mime-type, be sure to do some careful research and testing first!

svenr at selfhtml dot org (23-Apr-2007 11:13)

Clarification on the MAX_FILE_SIZE hidden form field:

PHP has the somewhat strange feature of checking multiple "maximum file sizes".

The two widely known limits are the php.ini settings "post_max_size" and "upload_max_size", which in combination impose a hard limit on the maximum amount of data that can be received.

In addition to this PHP somehow got implemented a soft limit feature. It checks the existance of a form field names "max_file_size" (upper case is also OK), which should contain an integer with the maximum number of bytes allowed. If the uploaded file is bigger than the integer in this field, PHP disallows this upload and presents an error code in the $_FILES-Array.

The PHP documentation also makes (or made - see bug #40387 - http://bugs.php.net/bug.php?id=40387) vague references to "allows browsers to check the file size before uploading". This, however, is not true and has never been. Up til today there has never been a RFC proposing the usage of such named form field, nor has there been a browser actually checking its existance or content, or preventing anything. The PHP documentation implies that a browser may alert the user that his upload is too big - this is simply wrong.

Please note that using this PHP feature is not a good idea. A form field can easily be changed by the client. If you have to check the size of a file, do it conventionally within your script, using a script-defined integer, not an arbitrary number you got from the HTTP client (which always must be mistrusted from a security standpoint).

v3 (&) sonic-world.ru (09-Mar-2007 10:29)

As said before if POST size exceeds server limit then $_POST and $_FILES arrays become empty. You can track this using $_SERVER['CONTENT_LENGTH'].
For example:

<?php
$POST_MAX_SIZE
= ini_get('post_max_size');
$mul = substr($POST_MAX_SIZE, -1);
$mul = ($mul == 'M' ? 1048576 : ($mul == 'K' ? 1024 : ($mul == 'G' ? 1073741824 : 1)));
if (
$_SERVER['CONTENT_LENGTH'] > $mul*(int)$POST_MAX_SIZE && $POST_MAX_SIZE) $error = true;
?>

jazfresh at hotmail.com (06-Dec-2006 07:45)

Now that PHP 5.2 supports a hook that can be used to handle upload progress, you can use a PECL extension (uploadprogress) to display an upload progress meter. Since documentation for this PECL extension is a bit thin on the ground, here are the basics:

1) Run "pecl install uploadprogress", and add "extension=uploadprogress.so" in your php.ini file.
2) Tell the extension where to temporarily store information about each upload. By default, this is in "/tmp/upt_%s.txt" (where %s is replaced with the UPLOAD_IDENTIFIER, see below). You can change it with the following config line:
uploadprogress.file.filename_template = /path/to/some_name_%s.txt
It must have a single '%s' in it, or it will fail!
3) Add a hidden element at the very beginning (this is important) of your upload form, called UPLOAD_IDENTIFIER. The value of this should be match the expression "^[A-Za-z0-9_.-=]{1,64}$" and be unique for every upload.
4) When the form is submitted, pop open a window to display the progress information and continue submitting the form. This window should refresh itself every few seconds, calling a PHP script that will retrieve the progress information and generate a display meter.

This script calls the function uploadprogress_get_info($id), where $id is the UPLOAD_IDENTIFIER value. This will return false if there is no progress information, or an array of values about that upload. The array contains:

time_start - The time that the upload began (same format as time()).
time_last - The time that the progress info was last updated.
speed_average - Average speed. (bytes / second)
speed_last - Last measured speed. (bytes / second)
bytes_uploaded - Number of bytes uploaded so far.
bytes_total - The value of the Content-Length header sent by the browser.
files_uploaded - Number of files uploaded so far.
est_sec - Estimated number of seconds remaining.

The speed_average is measured based on the number of bytes uploaded since the upload began, whereas the speed_last is based on the number of bytes uploaded since the progress information was last updated. The progress information is updated whenever PHP reads in some more data from the client, so speed_last may not be very accurate.

Note 1) The bytes_total figure is NOT a reflection of the file size, but of the POST's size, so don't expect them to match.

Note 2) This module really only detects how much data the POST form has sent, and keeps a running count of how many POST variables of type 'file' that it encounters along the way.  It has no way of knowing how many files are in the POST, so it is not possible to have a progress bar for each file, just one for all files (and the ability to display how many files have been uploaded so far).

frustrated dot user at fake dot com (29-Nov-2006 05:11)

Before you even bother doing anything, verify the filesystem your permanent upload directory will reside on. Use NTFS before you even start! (Assuming you're on Windows.)

Unfortunately, because I've been preparing to switch to Linux on this machine, I thought it would be a *great* idea to use FAT32 so I could access my websites from both Windows and Linux (this is not a production box, but where I am creating a CMS).

This was a *bad* idea...since the filesystem is not NTFS, now the only permissions I can set are *share* permissions.

I *guess* that *share* permissions are not used through the webserver, because even though the user Apache runs as is one of the users given permissions "Read" and "Modify" share permissions, the file cannot be permanently saved via neither move_uploaded_file() nor copy().

I verified this by using conditionals with !is_readable() and !is_writable() to echo specific messages.

So, now I have to back up everything I've done, reformat that partition as NTFS, copy everything over again, and set all the permissions, including on databases that I am using with other pages. *(sigh)*

jedi_aka at yahoo dot com (18-Oct-2006 08:12)

For those of you trying to make the upload work with IIS on windows XP/2000/XP Media and alike here is a quick todo.

1) Once you have created subdirectories "uploads/"  in the same directory wher you code is running use the code from oportocala above and to make absolutely sure sure that the file you are trying to right is written under that folder. ( I recomend printing it using echo $uploadfile; )

2) In windows explorer browse to the upload directory created above and share it. To do that execute the following substeps.
     a) Right click the folder click "sharing and security..."
     b) Check 'Share this folder on the network'
     c) Check 'Allow network users to change my files' ( THIS STEP IS VERY IMPORTANT )
     d) click 'ok' or 'apply'

3) you can then go in the IIS to set read and write permissions for it. To do that execute the followin substeps.
     a) Open IIS (Start/Controp Panel (classic View)/ Admistrative tools/Internet Information Service
     b) Browse to your folder (the one we created above)
     c) right click and select properties.
     d) in the Directory tab, make sure, READ, WRITE, AND DIRECTORY BROWSING are checked.
     e) For the security freaks out there, You should also make sure that 'execute permissions:' are set to Script only or lower (DO NOT SET IT TO 'script and executable)'( that is because someone could upload a script to your directory and run it. And, boy, you do not want that to happen).

there U go.

Send me feed back it if worked for you or not so that I can update the todo.

jedi_aka@yahoo.com

PS: BIG thanks to oportocala

tom dot blom at helsinki dot fi (04-Sep-2006 02:02)

I have been upgrading a web server. The current configuration is IIS 6.0 + PHP 5.2 build 3790 with SSL support.

File uploads failed with a blank screen if the file size exceeded ca. 49 Kb. I tried modifying different timeout parameters (PHP and IIS) and the POST_MAX_SIZE and UPLOAD_MAX_FILESIZE directives. Modifications had no effect.

After turning off SSL in IIS uploads were successful. Some experimenting showed  that the "Accept client certificates" -setting was causing the problem. Now I am running IIS with SSL and "Ignore client certificates" -setting. Even large files can now be uploaded.

I didn't found anything about this feature on the web.

david at cygnet dot be (12-May-2006 01:14)

If you are experiencing problems posting files from Internet Explorer to a PHP script over an SSL connection, for instance "Page can not be displayed" or empty $_FILES and $_POST arrays (described by jason 10-Jan-2006 02:08), then check out this microsoft knowledgebase article:

http://support.microsoft.com/?kbid=889334

This knowledgebase article explains how since service pack 2 there may be problems posting from IE over SSL. It is worth checking whether your problem is IE specific since this is definitely not a PHP problem!

geert dot php at myrosoft dot com (23-Dec-2005 08:16)

When file names do contain single quote parts of the filename are being lost.
eg.: uploading a filename
      startName 'middlepart' endName.txt
will be uploaded (and hence stored in the _Files ['userfile'] variable as
      endName.txt
skipping everything before the second single quote.

djot at hotmail dot com (27-Nov-2005 10:02)

-
Be carefull with setting max_file_size via
<?php ini_get('upload_max_filesize'); ?>

ini_get might return values like "2M" which will result in non working uploads.

This was the "no no" in my case:

<?php
$form
= '<input type="hidden" name="MAX_FILE_SIZE" value=".ini_get('upload_max_filesize')." />';
?>

Files were uploaded to the server, but than there was not any upload information, not even an error message. $_FILES was completly empty.

djot
-

ded at in dot ua (04-Oct-2005 10:03)

Generally, if you use
CharsetDisable on
or
CharsetSourceEnc off
in (russian) apache config file, and if your script which receives upload still have some html, use <meta http-equiv ...> tags so browser can correctly display the pages.

NO_lewis_SPAM at NOSPAM dot delta-hf dot co dot uk (03-Sep-2005 05:27)

I have been having issues with putting data in to an MSSQL database from an uploaded file. Trying to INSERT a file in excess of 25MB caused "Insufficient memory" errors from the SQL server

I decided to chunk the data into the database rather than trying to spurt it all in at once. The memory management is much better and from Submit to in the DB takes about 1 second per MB. The machine has dual Pentium 3 933MHz and 2GB RAM.

First things first I had to write a stored procedure. I saw no point in attempting to return a TEXTPTR(), which is required for the UPDATETEXT function to work, back to PHP so I didn't even bother. This is my very first stored procedure since this is really the first time I've developed solely for MSSQL. The important thing is that it's functional.

Here's the code I used for my stored procedure. After writing this I need to execute it in a loop to get all the data in, in the correct order. I leave that bit to PHP of course. Please don't tell me I could have just written it all in the stored procedure using another language, this is PHP and MSSQL we're talking about. :)

The zipfile column data type is TEXT, I tried IMAGE but it was problematic dealing with HEX data.

///////////// SP//////////////////////
CREATE PROCEDURE dbo.dds_writeBlob @dataChunk AS TEXT, @refCode AS VARCHAR(50), @offSet AS INT

AS

DECLARE    @dataPtr AS BINARY(16)

SELECT    @dataPtr=TEXTPTR(zipfile)
FROM    [dbo].[file] (UPDLOCK)
WHERE    [dbo].[file].ref = @refCode

UPDATETEXT    [dbo].[file].zipfile @dataPtr @offSet 0 @dataChunk
GO
//////////////////END SP/////////////////

Then of course comes the PHP code to do the chunking. Firstly I have to convert the binary data to a type that can be accepted by TEXT data type. base64_encode() comes in handy for this purpose but of course I need it in chunks so I used chunk_split() and split it in to chunks of 256000 bytes by declaring the optional [chunklen]. I then explode() it in to a numerically indexed array using the newlines ("\r\n") that are inserted every [chunklen] by chunk_split. I can then loop through with a for(), passing the data chunks, in order, one at a time to the stored procedure. Here's the code:

<?php
$data
= chunk_split(base64_encode(fread(fopen($file, "rb"), filesize($file))), 256000);
$arrData = explode("\r\n", $data);
unset(
$data); // Clear memory space
$num = count($arrData);
$offset = 0;

for (
$i=0;$i<$num;$i++) {
   
$buffer = $arrData[$i];
   
$query = "EXEC [dds_writeBlob] '".$buffer."', '$reference', $offset";
    @
mssql_query($query) or die(mssql_get_last_message());
   
$offset = ($offset + strlen($buffer));
}
?>

Of course we then need to extract the data from the database. This, thankfully, is a lot easier! Simply base64_decode() the data before outputting to a browser.
<?php
$query
= "SELECT zipfile, job_code FROM [file] WHERE ref = '$ref'";
@
$result = mssql_query($query) or die('File Download: Failed to get file from the database.');
$file = mssql_fetch_assoc($result);
header('Content-type: application/zip');
header('Content-Disposition: attachment; filename="job-'.trim($file['job_code']).'.zip"');
echo
base64_decode($file['zipfile']);
?>

The benefit of storing in base64_encoded format is the simplicity with which you can now send mime emails with the data attached as an alternative to having people download it. A simple chunk_split() on the SELECTed data will have it in the right format for mime mails.

The draw back is the extra size required! Expect the base64_encoded data to be 1.33 times the size of the original data!

mariodivece at bytedive dot com (24-Aug-2005 07:33)

Just wanted to point out a detail that might be of interest to some:

when using base64_encode to store binary data in a database, you are increasing the size of the data by 1.33 times. There is a nicer way of storing the data directly. Try the following:

<?php $data = mysql_real_escape_string($data); ?>

This will leave the data untouched and formatted in the correct way and ready to be inserted right into a MySQL statement without wasting space.

By the way, I'd like to thank therebechips for his excellent advice on data chunks.

warwickbarnes at yahoo dot co dot uk (19-Aug-2005 12:58)

You may come across the following problem using PHP on Microsoft IIS: getting permission denied errors from the move_uploaded_file function even when all the folder permissions seem correct. I had to set the following to get it to work:

1. Write permissions on the the folder through the IIS management console.
2. Write permissions to IUSR_'server' in the folder's security settings.
3. Write permissions to "Domain Users" in the folder's security settings.

The third setting was required because my application itself lives in a secure folder - using authentication (either Basic or Windows Integrated) to identify the users. When the uploads happen IIS seems to be checking that these users have write access to the folder, not just whether the web server (IUSR_'server') has access.

Also, remember to set "Execute Permissions" to "None" in the IIS management console, so that people can't upload a script file and then run it. (Other checks of the uploaded file are recommended as well but 'Execute None' is a good start.)

myko AT blue needle DOT com (16-Aug-2005 05:13)

Just a quick note that there's an issue with Apache, the MAX_FILE_SIZE hidden form field, and zlib.output_compression = On.  Seems that the browser continues to post up the entire file, even though PHP throws the MAX_FILE_SIZE error properly.  Turning zlib compression to OFF seems to solve the issue.  Don't have time to dig in and see who's at fault, but wanted to save others the hassle of banging their head on this one.

sgarner(a)expio.co.nz (21-Jun-2005 05:52)

Internet Explorer has problems with submitting forms with enctype="multipart/form-data" (e.g. uploading files) when combined with text fields containing non-standard ASCII characters (e.g. smart quotes or em-dashes) and a non-Windows-1255 character encoding.

Many Apache 2.0 default configs (e.g. Fedora 3) ship with "AddDefaultCharset UTF-8" in the httpd.conf. Commenting out this line will resolve the problem (assuming no charset is defined using <meta> tags in the page as well).

The problem manifests when submitting the form; the input field containing characters like , , , (common in text copied from MS Word) will appear blank to the receiving page.

keith at phpdiary dot org (24-May-2005 12:14)

Caution: *DO NOT* trust $_FILES['userfile']['type'] to verify the uploaded filetype; if you do so your server could be compromised.  I'll show you why below:

The manual (if you scroll above) states: $_FILES['userfile']['type'] -  The mime type of the file, if the browser provided this information. An example would be "image/gif".

Be reminded that this mime type can easily be faked as PHP doesn't go very far in verifying whether it really is what the end user reported!

So, someone could upload a nasty .php script as an "image/gif" and execute the url to the "image".

My best bet would be for you to check the extension of the file and using exif_imagetype() to check for valid images.  Many people have suggested the use of getimagesize() which returns an array if the file is indeed an image and false otherwise, but exif_imagetype() is much faster. (the manual says it so)

ceo at l-i-e dot com (20-May-2005 04:25)

Using /var/www/uploads in the example code is just criminal, imnsho.

One should *NOT* upload untrusted files into your web tree, on any server.

Nor should any directory within your web tree have permissions sufficient for an upload to succeed, on a shared server. Any other user on that shared server could write a PHP script to dump anything they want in there!

The $_FILES['userfile']['type'] is essentially USELESS.
A. Browsers aren't consistent in their mime-types, so you'll never catch all the possible combinations of types for any given file format.
B. It can be forged, so it's crappy security anyway.

One's code should INSPECT the actual file to see if it looks kosher.

For example, images can quickly and easily be run through imagegetsize and you at least know the first N bytes LOOK like an image.  That doesn't guarantee it's a valid image, but it makes it much less likely to be a workable security breaching file.

For Un*x based servers, one could use exec and 'file' command to see if the Operating System thinks the internal contents seem consistent with the data type you expect.

I've had trouble in the past with reading the '/tmp' file in a file upload.  It would be nice if PHP let me read that file BEFORE I tried to move_uploaded_file on it, but PHP won't, presumably under the assumption that I'd be doing something dangerous to read an untrusted file.  Fine.   One should move the uploaded file to some staging directory.  Then you check out its contents as thoroughly as you can.  THEN, if it seems kosher, move it into a directory outside your web tree.  Any access to that file should be through a PHP script which reads the file.  Putting it into your web tree, even with all the checks you can think of, is just too dangerous, imnsho.

There are more than a few 用户评论 here with naive (bad) advice.  Be wary.

Steven (29-Apr-2005 12:30)

Need to get around your PHP.ini file upload limit?
Use a bit of clever JavaScript to get the value of your <input type="file"> (the location of the file on the client's machine), copy it to a hidden text box then try and upload traditionally, if you get a PHP error UPLOAD_ERR_INI_SIZE, then use the value of your hidden text box to initiate a PHP-FTP connection and upload to your heart's content. 
No more limits :)

dmsuperman at comcast dot net (26-Apr-2005 07:00)

I needed a file uploader for a client a little while ago, then the client didn't want it, so I'll share with all of you. I know I hated coding it, it was confusing (for me anyway), but I made it fairly simple to use:

<?php
function uploader($num_of_uploads=1, $file_types_array=array("txt"), $max_file_size=1048576, $upload_dir=""){
  if(!
is_numeric($max_file_size)){
   
$max_file_size = 1048576;
  }
  if(!isset(
$_POST["submitted"])){
   
$form = "<form action='".$PHP_SELF."' method='post' enctype='multipart/form-data'>Upload files:<br /><input type='hidden' name='submitted' value='TRUE' id='".time()."'><input type='hidden' name='MAX_FILE_SIZE' value='".$max_file_size."'>";
    for(
$x=0;$x<$num_of_uploads;$x++){
     
$form .= "<input type='file' name='file[]'><font color='red'>*</font><br />";
    }
   
$form .= "<input type='submit' value='Upload'><br /><font color='red'>*</font>Maximum file length (minus extension) is 15 characters. Anything over that will be cut to only 15 characters. Valid file type(s): ";
    for(
$x=0;$x<count($file_types_array);$x++){
      if(
$x<count($file_types_array)-1){
       
$form .= $file_types_array[$x].", ";
      }else{
       
$form .= $file_types_array[$x].".";
      }
    }
   
$form .= "</form>";
    echo(
$form);
  }else{
    foreach(
$_FILES["file"]["error"] as $key => $value){
      if(
$_FILES["file"]["name"][$key]!=""){
        if(
$value==UPLOAD_ERR_OK){
         
$origfilename = $_FILES["file"]["name"][$key];
         
$filename = explode(".", $_FILES["file"]["name"][$key]);
         
$filenameext = $filename[count($filename)-1];
          unset(
$filename[count($filename)-1]);
         
$filename = implode(".", $filename);
         
$filename = substr($filename, 0, 15).".".$filenameext;
         
$file_ext_allow = FALSE;
          for(
$x=0;$x<count($file_types_array);$x++){
            if(
$filenameext==$file_types_array[$x]){
             
$file_ext_allow = TRUE;
            }
          }
          if(
$file_ext_allow){
            if(
$_FILES["file"]["size"][$key]<$max_file_size){
              if(
move_uploaded_file($_FILES["file"]["tmp_name"][$key], $upload_dir.$filename)){
                echo(
"File uploaded successfully. - <a href='".$upload_dir.$filename."' target='_blank'>".$filename."</a><br />");
              }else{
                echo(
$origfilename." was not successfully uploaded<br />");
              }
            }else{
              echo(
$origfilename." was too big, not uploaded<br />");
            }
          }else{
            echo(
$origfilename." had an invalid file extension, not uploaded<br />");
          }
        }else{
          echo(
$origfilename." was not successfully uploaded<br />");
        }
      }
    }
  }
}
?>

uploader([int num_uploads [, arr file_types [, int file_size [, str upload_dir ]]]]);

num_uploads = Number of uploads to handle at once.

file_types = An array of all the file types you wish to use. The default is txt only.

file_size = The maximum file size of EACH file. A non-number will results in using the default 1mb filesize.

upload_dir = The directory to upload to, make sure this ends with a /

This functions echo()'s the whole uploader, and submits to itself, you need not do a thing but put uploader(); to have a simple 1 file upload with all defaults.

oportocala at DON'T GET SPAM dot yahoo dot comerce (22-Apr-2005 02:59)

I had some problems with uploading files because of the path .So to save you some problems. if you get an error like "failed to open stream: No such file or directory in ..." it's likely because your not specifing the full path of the directory you want to upload.In other words you need to specify the full path and not the relative path in the second parameter.
Here is a small function to upload stuff. The files get their new name via last index from a database.
<?php
 
  $name_tmp
= $HTTP_POST_FILES['file']['tmp_name'];
//read temporay filename
 
$name = $HTTP_POST_FILES['file']['name'];
//read initial filename
 
if(is_uploaded_file($name_tmp)){
   
$ext =explode('.', $name);
   
$ext = $ext[count($ext)-1];
   
//get extension of uploaded file
       
$index=getLastIndex();//costum function
   
$path_parts = pathinfo(__file__);//get path info of curent php script
   
$dir = $path_parts['dirname']."\\uploads"; //full path of upload directory
   
$new = $dir."\\".$index.".".$ext;
      if(
move_uploaded_file($name_tmp,$new))
        echo
"File transfer succesfull.";
    }

?>

robpet at tds dot net (03-Apr-2005 06:35)

People have remarked that incorrect permissions on the upload directory may prevent photos or other files from uploading.  Setting the Apache owner of the directory incorrectly will also prevent files from uploading -- I use a PHP script that creates a directory (if it doesn't exist already) before placing an uploaded file into it.  When the script creates the directory and then copies the uploaded file into the directory there is no problem because the owner of the file is whatever Apache is running as, typically "nobody". However, lets say that I've moved the site to a new server and have copied over existing file directories using FTP.  In this case the owner will have a different name from the Apache owner and files will not upload. The solution is to TelNet into the site and reset the owner to "nobody" or whatever Apache is running as using the CHOWN command.

javasri at yahoo dot com (30-Mar-2005 10:34)

On windows XP, SP2, Explorer at times fails to upload files without extensions.

$_FILES array is null in that case. Microsoft says its a security feature(!)

The only solution we could comeup is to enforce uploaded file  to have an extention.

thisisroot at gmail dot com (14-Mar-2005 03:33)

If you're having problems uploading large files but small files go through fine, here are some things to try:

- In the HTML form, make sure you've set MAX_FILE_SIZE to an acceptable value.
- In php.ini, be sure you've set the the upload_max_filesize and post_max_size to be large enough to handle your upload.
- In your httpd.conf (if you're using apache), check that the LimitRequestBody directive isn't set too low (it's optional, so it may not be there at all).

If those settings don't work, you can check your firewall configuration. When uploading large files, packets have to be split into fragments of varying size depending on your systems MTU (maximum transmission unit), which is typically 1500 bytes.

Because some systems send the packets with the headers last (or the header packet may be received after some of the data packets), firewalls can't filter this traffic based on destination port and address. Many firewalls (including iptables) have to be configured to allow fragments separately from standard traffic. Unfortunately, it's an all-or-nothing thing in these cases, and exploits based on packet fragmentation have been a problem in the past (teardrop, boink, etc.). Note that ICMP may be used to notify the host (your server) of oncoming fragmentation, so you may need to allow ICMP traffic as well.

The iptables rules for this are as follows:
# allow all fragments
-A INPUT -f -j ACCEPT
# allow icmp traffic
-A INPUT -p icmp -j ACCEPT

On the bright side, this will also fix some issues with ssh and NFS =)

(27-Feb-2005 06:06)

Just to remind everyone, if you are wanting to upload larger files, you will need to change the value of both upload_max_filesize and post_max_size to the largest filesize you would like to allow.  Then restart apache and everything should work.

Leevi at izilla dot com dot au (09-Feb-2005 06:52)

This may help a newbie to file uploads.. it took advice from a friend to fix it..

If you are using
-windows xp
-iis 5
-php 5

If you keep getting permission errors on file uploads... and you have sworn you set the permissions to write to the directory in iis...

double check that
a) in windows explorer under tools > folder options
click the view tab
scroll down all the way to "use simple file sharing (recommended)"
uncheck this box

b) find the folder you wish to upload to on your server
c) click properties and then the security tab
d) make sure the appropriate write settings are checked.

you may want to test by setting "everyone" to have full permission....

BEWARE doing this will open up big security holes on your server....

hope this helps

Leevi Graham

phpnoob at adam dot net dot nz (09-Feb-2005 01:57)

Just thought I'd add this since I had to search forever to find an answer. 

When I used the enctype attribute on a form to process a file upload I had a problem redirecting back to an anchor point on the original page my code looked like this on the upload page:

header("Location: original_page.php#image_gal");

and the resulting url looked like this:

http://www.example.com/original_page.php

note the missing anchor reference.  So my work around was to pass the anchor point as a variable and then redirect again when I got to the original page.  A little bit chunky but it worked.  Hope this helps someone.

Tyfud (07-Jan-2005 04:44)

It's important to note that when using the move_uploaded_file() command, that some configurations (Especially IIS) will fail if you prefix the destination path with a leading "/". Try the following:

<?php move_uploaded_file($tmpFileName,'uploads/'.$fileName); ?>

Setting up permissions is also a must. Make sure all accounts have write access to your upload directory, and read access if you wish to view these files later. You might have to chmod() the directory or file afterwards as well if you're still getting access errors.

lobo235 at gmail dot com (04-Jan-2005 10:48)

Be sure to be careful with the $_FILES['userfile']['name'] array element. If the client uploads a file that has an apostrophe in the filename it WILL NOT get set to the full name of the file from the client's machine.

For example, if the client uploads a file named george's car.jpg the $_FILES['userfile']['name'] element will be set to s car.jpg because PHP appears to cut off everything before the apostrophe as well as the apostrophe itself.

This did not happen in some of the previous versions of PHP but I know that it happens in version 4.3.10 so watch out for this.

I thought this was a bug so I submitted it but it turns out that it is a "security measure"

ryan dot baclit at gmail dot com (15-Dec-2004 07:15)

Hello everyone. I want to share to you that uploading will never work out of the box if you didn't set the upload_tmp_dir directive in your php.ini file in the first place. If you just compiled the source files as is and tried to upload, you're in for a big mess. I don't know the flags to pass to the configure script to tell php about the default temporary directory to place the uploaded files.

In case your php upload code won't do as expected, open up the php.ini file and set the upload_tmp_dir. Then restart the Apache server and you're set.

By the way, I'm using Linux Mandrake 10.1 Official and PHP 4.3.9 on Apache 2.0.49.

therhinoman at hotmail dot com (27-Aug-2004 09:20)

If your upload script is meant only for uploading images, you can use the image function getimagesize() (does not require the GD image library) to make sure you're really getting an image and also filter image types.

<?php getimagesize($file); ?>

...will return false if the file is not an image or is not accessable, otherwise it will return an array...

<?php
$file
= 'somefile.jpg';

# assuming you've already taken some other
# preventive measures such as checking file
# extensions...

$result_array = getimagesize($file);

if (
$result_array !== false) {
   
$mime_type = $result_array['mime'];
    switch(
$mime_type) {
        case
"image/jpeg":
            echo
"file is jpeg type";
            break;
        case
"image/gif":
            echo
"file is gif type";
            break;
        default:
            echo
"file is an image, but not of gif or jpeg type";
    }
} else {
    echo
"file is not a valid image file";
}
?>

using this function along with others mentioned on this page, image ploading can be made pretty much fool-proof.

See http://php.net/manual/en/function.getimagesize.php for supported image types and more info.

olijon, iceland (19-Jun-2004 04:24)

When uploading large images, I got a "Document contains no data" error when using Netscape and an error page when using Explorer. My server setup is RH Linux 9, Apache 2 and PHP 4.3.

I found out that the following entry in the httpd.conf file was missing:

<Files *.php>
  SetOutputFilter PHP
  SetInputFilter PHP
  LimitRequestBody 524288 (max size in bytes)
</Files>

When this had been added, everything worked smoothly.

- Oli Jon, Iceland

brion at pobox dot com (11-May-2004 02:08)

Note that with magic_quotes_gpc on, the uploaded filename has backslashes added *but the tmp_name does not*. On Windows where the tmp_name path includes backslashes, you *must not* run stripslashes() on the tmp_name, so keep that in mind when de-magic_quotes-izing your input.

steve dot criddle at crd-sector dot com (16-Apr-2004 07:43)

IE on the Mac is a bit troublesome.  If you are uploading a file with an unknown file suffix, IE uploads the file with a mime type of "application/x-macbinary".  The resulting file includes the resource fork wrapped around the file.  Not terribly useful.

The following code assumes that the mime type is in $type, and that you have loaded the file's contents into $content.  If the file is in MacBinary format, it delves into the resource fork header, gets the length of the data fork (bytes 83-86) and uses that to get rid of the resource fork.

(There is probably a better way to do it, but this solved my problem):

<?php
if ($type == 'application/x-macbinary') {
    if (
strlen($content) < 128) die('File too small');
   
$length = 0;
    for (
$i=83; $i<=86; $i++) {
       
$length = ($length * 256) + ord(substr($content,$i,1));
          }
   
$content = substr($content,128,$length);
}
?>

~caetin~ ( at ) ~hotpop~ ( dot ) ~com~ (11-Feb-2004 04:37)

From the manual:

     If no file is selected for upload in your form, PHP will return $_FILES['userfile']['size'] as 0, and $_FILES['userfile']['tmp_name'] as none.

As of PHP 4.2.0, the "none" is no longer a reliable determinant of no file uploaded. It's documented if you click on the "error codes" link, but you need to look at the $_FILES['your_file']['error']. If it's 4, then no file was selected.

maya_gomez ~ at ~ mail ~ dot ~ ru (06-Feb-2004 01:20)

when you upload the file, $_FILES['file']['name'] contains its original name converted into server's default charset.
if a name contain characters that aren't present in default charset, the conversion fails and the $_FILES['file']['name'] remains in original charset.

i've got this behavior when uploading from a windows-1251 environment into koi8-r. if a filename has the number sign "" (0xb9), it DOES NOT GET CONVERTED as soon as there is no such character in koi8-r.

Workaround i use:

<?php
if (strstr ($_FILES['file']['name'], chr(0xb9)) != "")
{
   
$_FILES['file']['name'] = iconv (
       
"windows-1251",
       
"koi8-r",
       
str_replace (chr(0xb9), "N.", $_FILES['file']['name']));
};
?>

e4c5 at raditha dot com (12-Aug-2003 10:22)

Progress bar support has been a recurring theme in many a PHP mailing list over the years. You can find a free progress monitor component for PHP file uploads at http://sourceforge.net/projects/megaupload/

The advantage of this system is that you do not have to apply any patches to PHP to make use of it.

diegoful at yahoo dot com (25-Mar-2003 08:22)

SECURITY CONSIDERATION: If you are saving all uploaded files to a directory accesible with an URL, remember to filter files not only by mime-type (e.g. image/gif), but also by extension. The mime-type is reported by the client, if you trust him, he can upload a php file as an image and then request it, executing malicious code.
I hope I am not giving hackers a good idea anymore than I am giving it to good-intended developers. Cheers.

garyds at miraclemedia dot ca (16-Mar-2003 02:12)

As it has been mentioned, Windows-based servers have trouble with the path to move the uploaded file to when using move_uploaded_file()... this may also be the reason copy() works and not move_uploaded_file(), but of course move_uploaded_file() is a much better method to use. The solution in the aforementioned note said you must use "\\" in the path, but I found "/" works as well. So to get a working path, I used something to the effect of:

"g:/rootdir/default/www/".$_FILES['userfile']['name']

...which worked like a charm.

I am using PHP 4.3.0 on a win2k server.

Hope this helps!

ov at xs4all dot nl (09-Mar-2003 03:08)

This took me a few days to find out: when uploading large files with a slow connection to my WIN2K/IIS5/PHP4 server the POST form kept timing out at exactly 5 minutes. All PHP.INI settings were large enough to accomodate huge file uploads. Searched like hell with keywords like "file upload php timeout script" until I realised that I installed PHP as CGI and added that as a keyword. This was the solution:

To set the timeout value:
1. In the Internet Information Services snap-in, select the computer icon and open its property sheets.
2. Under Master Properties, select WWW Service, and then click the Edit button
3. Click the Home Directory tab.
4. Click the Configuration button.
5. Click the Process Options tab, and then type the timeout period in the CGI Script Timeout box.

travis dot lewis at amd dot com (04-Dec-2002 08:58)

If you we dumb like me you installed Redhat 8.0 and kept the default install of packages for Apache 2.0 and PHP4.2.2.  I could not upload any files larger than 512kB and all the php directorives were set to 32MB or higher.
memory_limit = 128M
post_max_size = 64M
upload_max_filesize = 32M

And my upload web page was set to 32MB as well:
<Form ID="frmAttach" Name="frmAttach" enctype="multipart/form-data" action="attachments.php" method="POST">
<input type="hidden" name="MAX_FILE_SIZE" value="33554432" />

However, the insiduous php.conf (/etc/httpd/conf.d/php.conf) file used by default RPM install of Redhat httpd has a LimitRequestBody set to 512kB ("524288" ).  Adjusting this to 32MB ("33554432") got things going for the larger files.  Here is my php.conf file in its entirety.  Hope this helps someone.  L8er.

#
# PHP is an HTML-embedded scripting language which attempts to make it
# easy for developers to write dynamically generated webpages.
#

LoadModule php4_module modules/libphp4.so

#
# Cause the PHP interpreter handle files with a .php extension.
#
<Files *.php>
    SetOutputFilter PHP
    SetInputFilter PHP
    LimitRequestBody 33554432
</Files>

#
# Add index.php to the list of files that will be served as directory
# indexes.
#

solja at gci dot net (04-May-2002 02:11)

Just another way I found to keep an uploaded file from overwriting an already exisiting one - I prefix each uploaded file with time() timestamp. Something like:
$unique_id = time();

Then when I give the new name to move the file to, I use something like:
$unique_id."-".$filename

So I get a fairly unique filename each time a file is uploaded. Obviously, if two files are uploaded at once, both will have the same timestamp, but I don't worry too much about that. Hope this might help someone.

am at netactor dot NO_SPAN dot com (15-Mar-2002 06:20)

Your binary files may be uploaded incorrectly if you use modules what recode characters. For example, for Russian Apache, you should use
<Files ScriptThatReceivesUploads.php>
CharsetDisable On
</Files>