PHP  
downloads | documentation | faq | getting help | mailing lists | | php.net sites | links 
search for in the  
previousCookiesCommon Pitfallsnext
Last updated: Tue, 03 Sep 2002
view the printer friendly version or the printer friendly version with notes or change language to English | Brazilian Portuguese | Chinese | Czech | Dutch | Finnish | French | German | Hungarian | Japanese | Korean | Polish | Romanian | Russian | Spanish | Swedish | Turkish

Capitolo 20. Caricare file

Metodo POST per caricamento di file

PHP � in grado di ricevere file caricati da qualsiasi browser compatibile con le specifiche RFC-1867 (che comprende Netscape Navigator 3 o successivo, Microsoft Internet Explorer 3 con una modifica di Microsoft, o versioni successive senza modifica). Questa caratteristica permette di caricare sia file di testo che binari. Utilizzando le funzioni di PHP per l'autenticazione e manipolazione dei file, � possibile avere pieno controllo su chi ha i permessi per caricare un file e su ci� che deve essere fatto una volta che il file � stato caricato.

Si noti che PHP permette l'upload di file con metodo PUT come utilizzato dai programmi Netscape Composer e W3C Amaya. Si veda Supporto per metodo PUT per maggiori dettagli.

La schermata di caricamento di un file pu� essere costruita con una form particolare, di questo tipo:

Esempio 20-1. Form di caricamento file

<form enctype="multipart/form-data" action="_URL_" method="post">
<input type="hidden" name="MAX_FILE_SIZE" value="1000">
Invia questo file: <input name="userfile" type="file">
<input type="submit" value="Invia File">
</form>
Il valore della action _URL_ dovrebbe puntare a un file PHP. Il campo nascosto MAX_FILE_SIZE deve precedere il campo di immisione del file e il suo valore � la dimensione massima accettata del file. Il valore � in byte.

Attenzione

Il valore MAX_FILE_SIZE � consigliato al browser. E' facile aggirare questo valore, quindi non fate affidamento sul fatto che il navigatore si comporti come desiderato! L'impostazione PHP lato server per la dimensione massima non pu� comunque essere aggirata.

In PHP, le seguenti variabili sono definite all'interno dello script di destinazione a seguito di un upload terminato con successo, nell'ipotesi che l'impostazione register_globals sia attiva nel file php.ini. Se l'impostazione track_vars � attiva, le variabili saranno attive in PHP nell'array globale $HTTP_POST_VARS. Notate che i nomi delle variabili seguenti si basano sull'ipotesi che abbiate chiamato il file di cui fare l'upload 'userfile' come nell'esempio precedente:

  • $userfile - Il file temporaneo in cui il file caricato � salvato sul server.

  • $userfile_name - Il nome originale o percorso del file sulla macchina dell'utente.

  • $userfile_size - La dimensione del file caricato in bytes.

  • $userfile_type - Il mime-type del file, se il browser fornisce questa informazione. Un esempio pu� essere "image/gif".

Si noti che la parte "$userfile" della variabile precedente � specificata nel campo INPUT TYPE=file nella form di upload. Nell'esempio precedente dell'upload, � stata chiamata "userfile"

In PHP 4 il comportamento � leggermente differente, perch� � disponibile il nuovo array globale $HTTP_POST_FILES che contiene le informazioni sul file caricato. Questo � disponibile solo se la variabile track_vars � attiva, ma track_vars � sempre attiva dalle versioni successive alla PHP 4.0.2.

Il contentuto dell'array $HTTP_POST_FILES � riportato di seguito. Si noti che che questo ipotizza l'uso del nome del file caricato 'userfile', come nell'esempio precedente:

$HTTP_POST_FILES['userfile']['name']

Il nome originale del file sulla macchina dell'utente.

$HTTP_POST_FILES['userfile']['type']

Il mime-type del file, se il browser fornisce questa informazione. Un esempio potrebbe essere "image/gif".

$HTTP_POST_FILES['userfile']['size']

La dimensione, in bytes, del file caricato.

$HTTP_POST_FILES['userfile']['tmp_name']

Il nome del file temporaneo in cui il file caricato � salvato sul server.

I file sono, di default, salvati in una directory temporanea sul server, a meno che un diverso percorso sia specificato nella direttiva upload_tmp_dir nel file php.ini. La directory del server predefinita pu� essere cambiata impostando la variabile di ambiente TMPDIR in cui � in esecuzione PHP. Non � possibile impostare questa variabile utilizzando la funzione putenv() da uno script PHP. Questa variabile di ambiente pu� anche essere usata per assicurarsi che anche altre operazioni stiano lavorando sui file caricati.

Esempio 20-2. Verifica dell'upload di file

Gli esempi seguenti valgono per versioni di PHP 3 maggiori di 3.0.16, e versioni di PHP 4 maggiorni di 4.0.2. Si vedano le definizioni delle funzioni is_uploaded_file() e move_uploaded_file().

<?php 
if (is_uploaded_file($userfile)) {
    copy($userfile, "/place/to/put/uploaded/file");
} else {
    echo "Possibile attacco nell'upload del file: filename '$userfile'.";
}
/* ...or... */
move_uploaded_file($userfile, "/posto/dove/mettere/file/caricato");
?>

Per le versioni precedenti di PHP � necessario fare come descritto in seguito.

Nota: Questo non funziona con le versioni di PHP 4 successive alla 4.0.2. Dipende da funzionalit� interne del PHP cambiate dopo quella versione.

<?php
/* Userland test for uploaded file. */ 
function is_uploaded_file($filename) {
    if (!$tmp_file = get_cfg_var('upload_tmp_dir')) {
        $tmp_file = dirname(tempnam('', ''));
    }
    $tmp_file .= '/' . basename($filename);
    /* User might have trailing slash in php.ini... */
    return (ereg_replace('/+', '/', $tmp_file) == $filename);
}

if (is_uploaded_file($userfile)) {
    copy($userfile, "/posto/dove/mettere/file/caricato");
} else {
    echo "Possibile attacco nell'upload del file: filename '$userfile'.";
}
?>

Lo script PHP che riceve il file caricato dovrebbe implementare la logica necessaria per determinare cosa deve essere fatto con il file caricato. E' possibile, per esempio, utilizzare la variabile $file_size per eliminare file che siano troppo grandi o troppo piccoli. E' possibile utillizzare la variabile $file_type per eliminare tutti i file che nono sodisfano certi criteri. Quale che sia la logica, bisognerebbe comunque sempre cancellare il file dalla directory temporanea e spostarlo da qualche altra parte.

Il file sar� eliminato dalla directory temporanea al termine della richiesta se non � stato mosso e rinominato.

User Contributed Notes
Caricare file
add a note about notes
[email protected]
05-Jan-2001 03:36

$HTTP_RAW_POST_DATA --

You'll usually access variables from forms sent via POST method by just accessing the associated PHP global variable.

However, if your POST data is not URI encoded (i.e., custom application that's not form-based) PHP won't parse the data into nice variables for you. You will need to use $HTTP_RAW_POST_DATA to access the raw data directly. (This should return a copy of the data given to the PHP process on STDIN; note that you wan't be able to open STDIN and read it yourself because PHP already did so itself.)

[email protected]
26-Aug-2001 07:20

File uploading with 'safe mode' turned on is a real problem. (As is 'safe mode' in its present incarnation, generally.) The temporary file is rarely owned by the same userid who created the page. But PHP, having just created this file, ought to know that and ought to handle it more sensibly.

It seems to me that 'safe mode' could be more well-defined, e.g. with a set of user-IDs that are allowed to create pages, any one of whose IDs should be accepted.

Certainly 'safe mode' should be aware of uploads. In its present form, uploading essentially rules-out the use of safe mode completely. :-/

16-Jan-2002 08:09
This example is was a bit confusing for me... didn't get a file to upload till I looked here.

[email protected]
30-Jan-2002 02:33

Some restrictive firewalls may not let file uploads happen via a form with enctype="multipart/form-data".

We were having problems with an upload script hanging (not returning content) when a file was uploaded through a remote office firewall. Removing the enctype parameter of the form allowed the form submit to happen but then broke the file upload capability. Everything but the file came through. Using a dial-in or other Internet connection (bypassing the bad firewall) allowed everything to function correctly.

So if your upload script does not respond when uploading a file, it may be a firewall issue.

[email protected]
02-Feb-2002 01:02

There is one thing open.

I am using PHP 4.1.1 on Apache / Linux. The upload procedure _requires_ that you have a line that sets the maximum file size in your form:

<input type="hidden" name="MAX_FILE_SIZE" value="100000">

(value in bytes)

[email protected]
12-Feb-2002 11:55

Well so far none of the suggestions mentioned here has worked for me. I am currently using the following pieced together from all the different comments and continue to get an "attack" error. The file I am unloading is 4Bytes and I have the MAX-SIZE set to 100000. Here is the code:

<?
print "$userfile = userfile
";
print "$userfile_name = userfile_name
";
print "$userfile_type = userfile_type
";
print "$userfile_size = userfile_size
";
print "$tmp_name = tmp_name
";

// In PHP 4.1.0 or later, $_FILES should be used instead of $HTTP_POST_FILES.
if (is_uploaded_file($HTTP_POST_FILES['userfile']['tmp_name'])) {
copy($HTTP_POST_FILES['userfile']['tmp_name'], "f:\\place\\to\\file\\");
} else {
echo "Possible file upload attack: filename '".$HTTP_POST_FILES['userfile']['name'].".";
}
/* ...or... */
move_uploaded_file($HTTP_POST_FILES['userfile']['tmp_name'], "f:\\place\\to\\file\\");
?>

Here is the result:
= userfile
test.txt = userfile_name
text/plain = userfile_type
= userfile_size
= tmp_name
Possible file upload attack: filename 'test.txt.

[email protected]
13-Feb-2002 06:11

i had many problems trying to do a multiple upload and insert into mysql, i eventually cracked it

$ary=array($pic_name[$key],$name[$key]);
while(list($key) = each($ary)) {
$query="insert into images (pics,name) values ('$pics_name[$key]', '$name[$key]')";
$result = $db->query($query);
print "".$query."
";

unset($pics_name[$key],$name[$key]);
}

using pic[] and name[] in the form

[email protected]
15-Feb-2002 03:52

There's a strange issue with file uploading and mime types, it seems it depends of the browser..

With a file upload system, the above code will show differents results :

echo "type : ".$HTTP_POST_FILES["image"]["type"]." name : ".$HTTP_POST_FILES["image_thb"]["name"]." tmpname : ".$HTTP_POST_FILES["image"]["tmp_name"]." size : ".$HTTP_POST_FILES["image"]["size"] ;

where 'image' is an input (type='file') field.

On IE, it gives :
type : image/pjpeg name : apercuclip.jpg tmpname : /tmp/phpwYQzWO size : 5182

Ok, normal, let's try another

On Netscape6 it gives :
type : image/jpeg name : apercuclip.jpg tmpname : /tmp/php6jgmQR size : 5182

note that the mime type is now image/jpeg and not image/pjpeg

On Opera6 :
type : image/jpeg; name=\"apercuclip.jpg\" name : apercuclip.jpg tmpname : /tmp/php655KLf size : 5182

Still image/jpeg, but there's also a "name" value ! weird result..

So be careful with that while uploading file..

[email protected]
18-Feb-2002 06:55

The

enctype="multipart/form-data"

part in the <form ...> field is very important, if you forget it you won't get the $userfile, $userfile_name, $userfile_size, $userfile_type veriables set (correctly). So if you're adding a File Input Field in a form, don't forget to add the above part (I did it and wondered why the vars were not set correctly).

[email protected]
27-Feb-2002 03:13

Some browsers label the type differently. I found this out while trying to restrict the file types that could be uploaded. I created a simple script that will let the user upload a file, and then print_r() the $_FILES variables. In Microsoft Internet Explorer 6.0.26 on Windows XP, I got this result:

Array
(
[file] => Array
(
[name] => command.com
[type] => application/octet-stream
[tmp_name] => C:\WINDOWS\TEMP\phpBE.tmp
[size] => 50620
)

)

Uploading the same file with the same script in Opera 6.01 (again on Windows XP), I got this result:

Array
(
[file] => Array
(
[name] => command.com
[type] => application/octet-stream; name="command.com"
[tmp_name] => C:\WINDOWS\TEMP\phpBF.tmp
[size] => 50620
)

)

The tmp_name is obviously supposed to be different, but notice how the name of the file was appened to type. My solution is either (a) split() at the semicolon and use the first element of that array, or (b), search the type for the allowed filetypes (via strstr()).

[email protected]
04-Mar-2002 09:05

When uploading very large files (greater than the default 8M) I found that I had alter not only the "max_file_size" input and the php.ini max_file_size limit, but ALSO the "post_max_size" variable in the php.ini file.

Because I was submitting the file via a POST request, it would hit this limit and deny the upload.

[email protected]
12-Mar-2002 06:50

I don't know if anybody else besides me will find this useful, but I just wrote this bit to handle files that were uploaded to my server, but to not allow them to overwrite an existing file with the same name. This will append the number 1 to the end of the file name and if THAT file exists, it will increment the number until it finds an unused one.

One thing this wouldn't handle, is if you have periods in your directory name for some reason. Replace "images/profile" with your directory path.

$glued_filename = "images/profile/" . $_FILES['userfile']['name'];
$i = 1;
while (file_exists($glued_filename)) {
$separated_filename = explode(".",$glued_filename);
if (substr($separated_filename[0],-1) == $i) {
$separated_filename[0] = substr($separated_filename[0], 0, (strlen($separated_filename[0])-1));
$i++;
}

$separated_filename[0] = $separated_filename[0] . "$i";
$glued_filename = implode(".",$separated_filename);
}

copy($_FILES['userfile']['tmp_name'], $glued_filename);

[email protected]_SPAN.com
15-Mar-2002 05: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>

[email protected]
24-Mar-2002 09:14

If no file was uploaded, you would probably expect the $userfile variable (or whatever its name is) to be empty. But it isn't. It contains the string "none" instead.

I don't know if this is true for all systems and configurations, but the fact that it *might* be the case is reason enough *not* to use things like that in order to check whether a file was uploaded:

// This is bad:
if($userfile == "")
echo "You did not upload any file!";

Instead, you might want to check $userfile_size. But note that this method makes no difference between NO and an EMPTY file:

// This is better:
if(!$userfile_size)
echo "Either you did not upload any file, or you uploaded an empty file!";

[email protected]
16-Apr-2002 11:50

Don't forget to allow file uploads by other users for the directory you use as file-upload destination. Same thing for the temporary-file directory.

Just CHMOD the directories to 777 and it should work, granted the PHP code itself is working okay.

[email protected]
24-Apr-2002 12:27

in reply to:
[email protected]
19-Apr-2002 07:46

open_dir restriction is when the folders on your server are read only for the current user (public).

You must edit the properties of that folder in some FTP program. Setting the properties to 777 should remove this problem.
Also typing
error_reporting(7);
in your code will hide the error from the users.

[email protected]
25-Apr-2002 01:01

Just another way to handle multiple uploads:

<?
function upload($FVARS) {
for($i=0;$i<count($FVARS[file][tmp_name]);$i++) {
$size=$FVARS[file][size][$i]; // filesize
$type=$FVARS[file][type][$i]; // mime type
$name=$FVARS[file][name][$i]; // original name
$temp=$FVARS[file][tmp_name][$i]; // temporary name
if($size) {
//whatever to do with uploaded files
echo "original name: $name<br />";
echo "temporary name: $temp<br />";
echo "mime type: $type<br />";
echo "size: $size<hr />";
}
}
}

upload($HTTP_POST_FILES); // or $_FILES or whatever
?>

Using this function every <input type="file" name="file[]"> will be handled.

[email protected]
02-May-2002 11:53

To check to see if a file was actually uploaded, it is safer to check the value of ($_FILES["name"]["size"] > 0) than to check (!empty($_FILES["name"]["tmp_name"])) beacuse some versions of PHP will store 'none' in $_FILES["name"]["tmp_name"] while others will leave it empty in the case od a missing file.
[email protected]
04-May-2002 01: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.

CBWhiz@[email protected]
09-May-2002 12:06

Here is a fully functional File Upload Handler function. You simply pass it the name that you typed on the form, the upload dir (and others if your advanced,) and viola!

call like so:
$OkExt = Array('php', 'htm', 'html')
DoFileUpload('Userfile', 1024, './upload', '', $OkExt , '', '')

$ForceFilename is if you want to use this name instead of whats in the $_FILES var.

$Overwriteok - set to anything but '' for yes

$ErrorFunction - set to the name of a function you defined, or '' to use default.

Need help? ask again.
Not that you may have to fix word wrap...

----------------------------
function DoFileUpload($InputFile, $MaxSize, $Path, $ErrorFunction, $ExtsOk, $ForceFilename, $OverwriteOk) {
//Copyright CBWhiz
$ErrNo = -1;
$TempFile = $_FILES[$InputFile]['tmp_name'];
$FileSize = $_FILES[$InputFile]['size'];
$FileName = $_FILES[$InputFile]['name'];
$FileType = $_FILES[$InputFile]['type'];
if (strlen($ForceFilename)) { $FileName = $ForceFilename; }

if (!function_exists($ErrorFunction)) {
if (!function_exists('DoFileUploadDefErrorHandle')) {
function DoFileUploadDefErrorHandle($ErrorNumber, $ErrorText) {
echo "<center><font color=red><b>Error $ErrorNumber: $ErrorText</b></font></center>";
}
}
$ErrorFunction = 'DoFileUploadDefErrorHandle';
}

echo <<<HTML
<hr>

<center>Uploading $InputFile:<hr width=35%>
<table>
<tr><td>Filename:</td><td>$FileName</td></tr>
<tr><td>File Size:</td><td>$FileSize</td></tr>
<tr><td>Temporary File:</td><td>$TempFile</td></tr>
<tr><td>File MIME Type:</td><td>$FileType</td></tr>
</table>
<hr width=35%>
</center>
HTML;
if($TempFile == 'none' || $TempFile == '') {
$ErrorTxt = "This File was unspecified.";
$ErrNo = 1;
$ErrorFunction($ErrNo, $ErrorTxt);
return $ErrNo;
}

if(!is_uploaded_file($TempFile)) {
$ErrorTxt = "File Upload Attack, Filename: \"$FileName\"";
$ErrNo = 2;
$ErrorFunction($ErrNo, $ErrorTxt);
return $ErrNo;
} //if(!is_uploaded_file($TempFile))

if($FileSize == 0) {
$ErrorTxt = 'The file you attempted to upload is zero length!';
$ErrNo = 3;
$ErrorFunction($ErrNo, $ErrorTxt);
return $ErrNo;
} //$FileSize == 0

$TheExt = GetExt($FileName);

foreach ($ExtsOk as $CurNum => $CurText) {
if ($TheExt == $CurText) { $FileExtOk = 1; }
}

if($FileExtOk != 1) {
$ErrorTxt = 'You attempted to upload a file with a disallowed extention!';
$ErrNo = 4;
$ErrorFunction($ErrNo, $ErrorTxt);
return $ErrNo;
}

if($FileSize > $MaxSize) {
$ErrorTxt = 'The file you attempted to upload exceeded the maximum file size of' . ($MaxSize / 1024) . 'kb.';
$ErrNo = 5;
$ErrorFunction($ErrNo, $ErrorTxt);
return $ErrNo;
} //if($FileSize > $MaxSize)

if(file_exists($Path.$FileName) && !strlen($OverwriteOk)) {
$ErrorTxt = 'The file you attempted to upload already exists. Please specify a new filename.';
$ErrNo = 6;
$ErrorFunction($ErrNo, $ErrorTxt);
return $ErrNo;
}

//-----------------------------------
//-------Actual Uploading Here

move_uploaded_file ($TempFile, $Path.$FileName);

chmod ($Path.$FileName, 0644); //Remove if your webserver hates you :D

echo '<center>File Upload Sucess!</center>
';
return $ErrNo;
} //function DoFileUpload($InputFile, $MaxSize, $Path, $ErrorFunction, $ExtsOk, $ForceFilename, $OverwriteOk)

function GetExt($Filename) {
$RetVal = explode ( '.', $Filename);
return $RetVal[count($RetVal)-1];
}

[email protected]
12-May-2002 06:04

Guys here,I think u should take a look here:
Array ( [attach] => Array ( [name] => An01_019.gif [type] => image/gif [tmp_name] => [error] => 2 [size] => 0 ) )
I use a file upload with max_file_size,I found here is a error,what does it mean.

And I also found this:
If u file size is larger than the max_file_size error would be 2,and if there is no file upload ,error would be 4, if the file uploaded correctly,error is 0.
But my Question is when it would be 3?

[email protected]
28-May-2002 08:41

Somebody asked for the error codes for the $_FILES error variable. I just found them in the code...

#define UPLOAD_ERROR_A 1 /* Uploaded file exceeded upload_max_filesize */
#define UPLOAD_ERROR_B 2 /* Uploaded file exceeded MAX_FILE_SIZE */
#define UPLOAD_ERROR_C 3 /* Only partiallly uploaded */
#define UPLOAD_ERROR_D 4 /* No file uploaded */
#define UPLOAD_ERROR_E 5 /* Uploaded file size 0 bytes */

[email protected]
07-Jun-2002 02:39

Hi,

To get the max upload filesize i use this

<?php

echo get_max_upload();

function get_max_upload() {
if (!ini_get("file_uploads")) {
return FALSE;
}
$upload_max_filesize = get_real_size(ini_get("upload_max_filesize"));
$post_max_size = get_real_size(ini_get("post_max_size")); // User Contributed Notes - [email protected]
$memory_limit = round(get_real_size(ini_get("memory_limit")) / 2); // User Contributed Notes - [email protected]
if ($upload_max_filesize>$post_max_size) {
$max = $post_max_size;
} else {
$max = $upload_max_filesize;
}
if (($memory_limit!="")&&($memory_limit<$max)) { // i had problems to get the "memory_limit" from the php.ini (this is testing on winXP with apache)
$max = $memory_limit;
}
return $max;
}

function get_real_size($size) {
if ($size=="") { return 0; }
$scan['MB'] = 1048576;
$scan['M'] = 1048576;
$scan['KB'] = 1024;
$scan['K'] = 1024;
while (list($key) = each($scan)) {
if ((strlen($size)>strlen($key))&&(substr($size, strlen($size) - strlen($key))==$key)) {
$size = substr($size, 0, strlen($size) - strlen($key)) * $scan[$key];
break;
}
}
return $size;
}

?>

[email protected]
07-Jun-2002 08:39

It should be noted that there is a control for file uploads in PHP.INI which must be on for any of this to work. In fact, my experience is that if file uplods are turned off in php.ini, NONE of the fields in a multipart/form-data form will be passed to PHP. This will be truw whether or not a file is being uploaded.
[email protected]
08-Jun-2002 01:25

I was having problems with the returned upload array. The name, and type were returned, but tmp_name was empty and size was set as 0.

I removed the maxfilesize input type, and it worked perfectly again, all of the elements of the array were present. Odd but true. Hope this helps someone out.

12-Jun-2002 09:21
this is really wierd, wanted to let y'all know that I tried many upload scripts could not make any work until I set "register_globals = on ". I was trying to avoid turning it on b/c of all the security warnings but it was unavoidable.
Im running win2k, apache 2.0.36 and php 4.2.1. I used the recommended php.ini which already had "file_uploads = on" and I set an"upload_tmp_dir". Now ...I could not install php as a module (dont ask me why Im happy its working) I had to use the CGI binary,php.exe. could this be a problem?

Bottom line I got my stuff working but if there is a better way Im all ears.

[email protected]
14-Jun-2002 06:29

Dave has a good upload class working with 4.2.1
[email protected]
18-Jun-2002 06:32

I had a strange Problem on a Debian System with PHP 4.2.1-3.

$filename is $filename_name not the tempname on the Server.

--- CUT ---

if ($filename==$filename_name):
$filename=$_FILES['filename']['tmp_name'];
endif;

--- CUT END ---

This bit of code helps to get the right tempfile as u expect.

prof_

18-Jun-2002 10:40
Si trabajas en XP, es necesario colocar los slashes de esta forma:

"e:/inetpub/wwwroot/vfc/fotosup\\".$userfile_name

[email protected]
21-Jun-2002 06:30

One important point to note is that there is a upload parameter in the php configuration file (i.e. php.ini). There is a section called "File Uploads".

If large files would be uploaded to the server, upload_max_filesize should be set to a large size. e.g. 10M

[email protected]
24-Jun-2002 08:24

I've pieced this together out of bits I've found elsewhere, but the info belongs here.

If you're on a shared host that won't allow you to modify the php.ini file and your max_upload_size is set low, you can create an .htaccess file in the upload handler script directory that contains:

php_value upload_max_filesize 8000000

(example set for 8 megs)

As a nice side benefit, it will keep big uploads from being erroneously listed as an upload attack via many of the scripts found here ;)

[email protected]
29-Jun-2002 06:54

Always use move_uploaded_file() to have your uploaded file in a suitable location, not copy() .

move_uploaded_file() is easier and more secure.

And it will work in safe_mode and with an open_basedir.

It your customers complain about errors like :

Warning: open_basedir restriction in effect. File is in wrong directory in
/users/sexydoo/www.bitchy-sex.com/html/inscription.php on line 40

with scripts managing uploaded files, tell them to replace copy() calls with move_uploaded_file() .

[email protected]
14-Jul-2002 06:53

Well, it could look so obvious, but I spent some hour asking to myself why the hell the whole thing didn't work: when I sent POST with ENCTYPE="multipart/form-data", I did find the file uploaded into /tmp, but the post data were completely BLANK!! The matter was that the php.ini file actually has a file_uploads directive, and in my Red Hat 7.3 distro it is Off by default.
[email protected]
19-Jul-2002 05:57

--HANDLING LARGE FILE UPLOADS and entering into a MySQL blob field--

Hope this helps someone as it was a bitch to fig out. MySQL default buffer and packets are set small. here is a method to get aroudn it.

$filehandle = fopen($addfile, "r");
$filesize = filesize($addfile);

//now this is bullshit, but have to read the file piece by piece and insert because the mysql server is set up to only handle 1meg inserts (small buffer and packet).

$buffer = addslashes(fread($filehandle, 906240));
$query = "Insert into files (file, filename, size, userid ) values ('$filedata','$addfile_name', '$filesize')";
$this->query($query);
$id = mysql_insert_id($this->link_id());

while (!feof ($filehandle)) {
$buffer = addslashes(fread($filehandle, 906240));
$query = "UPDATE files SET file = concat('$buffer') where id='$id'";
$this->query($query);
}
fclose ($filehandle);

[email protected]
26-Jul-2002 06:27

If you have a script like this:

<?
if ($_REQUEST["answered"] == "ok") {
echo "<pre>";
echo $_SERVER["SERVER_SOFTWARE"] . "\n\n";
if (is_uploaded_file($_FILES["userfile"]["tmp_name"]))
echo "It really is an Uploaded File!\n";
else
echo "It is NOT\n";
echo "These are the contents of the \$_FILES array :: \n";
print_r($_FILES);
echo "</pre>";

} else {
?>

<form name="forma" action="file_problem.php" method="post" ENCTYPE="multipart/form-data">
<input type="file" name="userfile">
<input type="hidden" name="answered" value="ok">
<input type="submit">
</form>

<?}?>

**** This is the result when we run it in PHP 4.1.2 browsing a real file from our disk:

Apache/1.3.24 (Unix) PHP/4.1.2

It really is an Uploaded File!
These are the contents of the $_FILES array ::
Array
(
[userfile] => Array
(
[name] => wtrs.audit
[type] => text/plain
[tmp_name] => /var/tmp/phpTMaO4e
[size] => 30313
)

)

**** And this is the result in PHP 4.2.2 :

Apache/1.3.26 (Unix) PHP/4.2.2

It really is an Uploaded File!
These are the contents of the $_FILES array ::
Array
(
[userfile] => Array
(
[name] => wtrs.audit
[type] => text/plain
[tmp_name] => /var/tmp/phpU6a4fK
[error] => 0
[size] => 30313
)

)

Everything seems to work fine, In fact in 4.2.2 we have a nice variable "error" in the array to be sure that there was no error during the upload.

BUT!

If we select a 0 byte file from our disk or if we simply write a bogus name in the userfile field before submiting the form we have these VERY different results:

**** In PHP 4.1.2:

Apache/1.3.24 (Unix) PHP/4.1.2

It is NOT
These are the contents of the $_FILES array ::
Array
(
[userfile] => Array
(
[name] => sdfsdf
[type] => application/octet-stream
[tmp_name] => none
[size] => 0
)

)

... very nice, we can use the "none" in the tmp_name to determine that this is not a correct file and that we don't have to move it to our directory maybe damaging an already stored file with that name.

*** In PHP 4.2.2 :

Apache/1.3.26 (Unix) PHP/4.2.2

It really is an Uploaded File!
These are the contents of the $_FILES array ::
Array
(
[userfile] => Array
(
[name] => sdfsdf
[type] => application/octet-stream
[tmp_name] => /var/tmp/phpNaaagK
[error] => 0
[size] => 0
)

)

... this is bad because PHP assumes a file was uploaded and creates a tmp_file in the server, also it doesn't report an error in the "error" variable of the array, and of course is_uploaded_file returns true.

Now we have no way to determine if the uploaded file was really a file and we will finish coding something like "IF FILESIZE IS 0 THEN DISCARD THE UPLOAD", but then we won't be able to upload 0 byte files (as we could in earlier version of PHP).

Is this a bug? any ideas of working this arround?

Constructions like these won't work any more:

if (!empty($userfile_name) && is_uploaded_file($userfile))
move_uploaded_file($userfile, "$ruta2".$userfile_name);

...assuming that register_globals is on; or:

$userfile = $_FILE["userfile"]["tmp_name"];
$userfile_name = $_FILE["userfile"]["name"];
if ( $userfile != 'none' && is_uploaded_file($userfile))
move_uploaded_file($userfile, "$ruta2".$userfile_name);

... if register_globals are off.

[email protected]
30-Jul-2002 12:11

In my opinion PHP 4.2.2 behaves correctly. It may be not as nice as before, but cleaner. If the user sends an empty file you get an empty file. If the user types a bogus file name it is the responsibility of the browser to tell the user that the file cannot be found.
I would not consider the PHP 4.2.2 behaviour a bug, but the change in behaviour could be considered a bug.

[email protected]
30-Jul-2002 05:15

after many attempts, i found this script from a previous posting above. worked the first time without a hitch. good luck!

<?php

// Complete working file upload example, Win2KPro, Apache 1.3x, PHP 4.x

// Set this line in php.ini
// upload_tmp_dir = /Library/WebServer/yourURL.com/upload_directory/

function handleupload() {
if (is_uploaded_file($_FILES['userfile']['tmp_name'])) {

$realname = $_FILES['userfile']['name'];
print "<b>$realname</b> was uploaded successfuly to the upload directory";

print "";

copy($_FILES['userfile']['tmp_name'],
"/Library/WebServer/yourURL.com/upload_directory/".$realname);
} else {
echo "Possible file upload attack: filename
".$_FILES['userfile']['name'].".";
}
}

?>

<html><body>

<?php

if ($act == "upload") {
handleupload();
}

?>

<form ENCTYPE="multipart/form-data" method="POST" action="ultest.php?act=upload">
File:<INPUT TYPE="FILE" NAME="userfile" SIZE="35">
<input type="hidden" name="MAX_FILE_SIZE" value="1000000">
<input type="submit" value="Upload" name="B1">
Please click only <b>once</b> and wait for confirmation
</form>
<a href=ultest.php>clear form</a>
</body></html>

[email protected]
07-Aug-2002 06:13

PHP 4.2.2 in CGI mode ; Xitami Web Server 2.4d9 ; Opera 6.04.
When i upload a Binary file, i always have something like this :
Name="1234.xls"
type=""
tmp_name="" (<-- strange here )
error=2
size=0

if and only if i have the MAX_FILE_SIZE value in the form.

If i remove the MAX_FILE_SIZE hidden html object of the form, everything works fine.

[email protected]
04-Sep-2002 09:44

Make sure that you set METHOD="POST" on the form you are using to submit the file.
If you don't, $userfile will simply be the directory on your local machine, and none of the other php variables will work ($userfile_name, $userfile_type, or any of the $_FILES vars)

add a note about notes
previousCookiesCommon Pitfallsnext
Last updated: Tue, 03 Sep 2002
show source | credits | stats | mirror sites
Copyright © 2001, 2002 The PHP Group
All rights reserved.
This mirror generously provided by:
Last updated: Thu Sep 5 20:07:53 2002 CEST