Filesystem 函数
在线手册:中文 英文
PHP手册

move_uploaded_file

(PHP 4 >= 4.0.3, PHP 5)

move_uploaded_file将上传的文件移动到新位置

说明

bool move_uploaded_file ( string $filename , string $destination )

本函数检查并确保由 filename 指定的文件是合法的上传文件(即通过 PHP 的 HTTP POST 上传机制所上传的)。如果文件合法,则将其移动为由 destination 指定的文件。

如果 filename 不是合法的上传文件,不会出现任何操作,move_uploaded_file() 将返回 FALSE

如果 filename 是合法的上传文件,但出于某些原因无法移动,不会出现任何操作,move_uploaded_file() 将返回 FALSE。此外还会发出一条警告。

这种检查显得格外重要,如果上传的文件有可能会造成对用户或本系统的其他用户显示其内容的话。

Note:

move_uploaded_file()安全模式open_basedir 都是敏感的。不过,限制只针对 destination 路径,因为允许移动上传的文件名 filename 可能会与这些限制产生冲突。move_uploaded_file() 仅作用于通过 PHP 上传的文件以确保这个操作的安全性。

Warning

如果目标文件已经存在,将会被覆盖。

参见 is_uploaded_file(),以及文件上传处理一章中的简单使用例子。

参数

filename

The filename of the uploaded file.

destination

The destination of the moved file.

返回值

Returns TRUE on success.

If filename is not a valid upload file, then no action will occur, and move_uploaded_file() will return FALSE.

If filename is a valid upload file, but cannot be moved for some reason, no action will occur, and move_uploaded_file() will return FALSE. Additionally, a warning will be issued.

范例

Example #1 Uploading multiple files

<?php
$uploads_dir 
'/uploads';
foreach (
$_FILES["pictures"]["error"] as $key => $error) {
    if (
$error == UPLOAD_ERR_OK) {
        
$tmp_name $_FILES["pictures"]["tmp_name"][$key];
        
$name $_FILES["pictures"]["name"][$key];
        
move_uploaded_file($tmp_name"$uploads_dir/$name");
    }
}
?>

注释

Note:

move_uploaded_file() is both 安全模式 and open_basedir aware. However, restrictions are placed only on the destination path as to allow the moving of uploaded files in which filename may conflict with such restrictions. move_uploaded_file() ensures the safety of this operation by allowing only those files uploaded through PHP to be moved.

Warning

If the destination file already exists, it will be overwritten.

参见


Filesystem 函数
在线手册:中文 英文
PHP手册
PHP手册 - N: 将上传的文件移动到新位置

用户评论:

marcelwoo (31-Mar-2012 12:41)

One more thing I want to mention about the post_max_size setting in php.ini that nobody else has mentioned.
If you try to upload a file larger than the post_max_size value (or multi files), the page will only refresh itself and no errors are thrown. It took me a while to figure the reason out.

matthias dot dailey at gmail dot com (22-Jul-2011 09:26)

The destination directory must exist; move_uploaded_file() will not automatically create it for you.

labsy at seznam dot org (04-May-2011 12:07)

A note for PHP on Windows IIS platform:
PHP does obviously not like directory traversing among partitions, so if you set upload_tmp_dir to be on different partition as php-cgi.exe or php.exe is, upload_tmp_dir will NOT be accessible for file uploads! You will get ERROR 6 on any attempt to upload file, and file size will be 0.
Resolution is to have upload_tmp_dir set to a path under PHP install folder.
...and make sure this folder (and also session_save_path folder) has at least read/write permissions granted to AppPool owner (usually NETWORK SERVICE) and IIS web user (by default IUSR_).

wilcobeekhuizen at gmail dot com (30-Mar-2011 08:55)

When uploading a file with a very long filename, for example 255 characters, move_uploaded_file fails. The longest file I've succesfully uploaded has a 247 character filename. So, although you can create a 250 character filename locally the server may not be able to move it.

alex at alx dot bz (17-Mar-2011 07:03)

I've run into this problem of move_uploaded_file not functioning several times, and always troubleshoot for a good 30 minutes until I find the SAME problem (because I never learn).

Always specify the proper enctype in the HTML form:

enctype='multipart/form-data'

I'm running Apache, on Linux, so take that into consideration, but I always assume (wrongly) that it is a permissions issue first.

jsimon at redventures dot com (02-Jan-2011 05:41)

Because of the way in which move_uploaded_file works, it can be difficult to debug without the proper error settings. If you are noticing that move_uploaded_file is not doing what you're expecting, and you are only getting a return value of false, try setting the error reporting at the top of your script.

error_reporting(E_ALL);
ini_set("display_errors", 1);

This will ensure you are receiving any notices or warnings that you were missing before.

Ray.Paseur sometimes uses Gmail (18-Aug-2010 04:42)

You can only move the uploaded file once.  You can use copy() if you need the file in more than one place.
<?php // RAY_temp_upload_example.php
error_reporting(E_ALL);
echo
"<pre>" . PHP_EOL;

// IF A FILE HAS BEEN UPLOADED
if (!empty($_FILES))
{
   
// SHOW THE UPLOADED FILES
   
print_r($_FILES);

   
// TRY TO MOVE THE FILE TWICE - SECOND MOVE RETURNS FALSE
   
if (!move_uploaded_file($_FILES["userfile"]["tmp_name"], $_FILES["userfile"]["name"])) echo "CANNOT MOVE {$_FILES["userfile"]["name"]}" . PHP_EOL;
    if (!
move_uploaded_file($_FILES["userfile"]["tmp_name"], $_FILES["userfile"]["name"])) echo "CANNOT MOVE {$_FILES["userfile"]["name"]}" . PHP_EOL;

   
// SHOW THE UPLOADED FILES AFTER THE MOVE - NO VISIBLE CHANGE
   
print_r($_FILES);
}

// END OF PHP, PUT UP THE HTML FORM TO GET THE FILE
?>
<!-- The data encoding type, enctype, MUST be specified as below -->
<form enctype="multipart/form-data" method="POST">
    <!-- MAX_FILE_SIZE must precede the file input field -->
    <input type="hidden" name="MAX_FILE_SIZE" value="300000" />
    <!-- Name of input element determines name in $_FILES array -->
    Send this file: <input name="userfile" type="file" />
    <input type="submit" value="Send File" />
</form>

brentwientjes at NOSPAM dot comcast dot net (15-Feb-2010 07:34)

I have for a couple of years been stymed to understand how to effectively load images (of more than 2MB) and then create thumbnails.  My note below on general file uploading was an early hint of some of the system default limitations and I have recently discovered the final limit  I offer this as an example of the various missing pieces of information to successfully load images of more than 2MB and then create thumbnails.  This particular example assumes a picture of a user is being uploaded and because of browser caching needs a unique number at the end to make the browser load a new picture for review at the time of upload.  The overall calling program I am using is a Flex based application which calls this php file to upload user thumbnails.

The secret sauce is:

1.  adjust server memory size, file upload size, and post size
2.  convert image to standard formate (in this case jpg) and scale

The server may be adjusted with the .htaccess file or inline code.  This example has an .htaccess file with file upload size and post size and then inline code for dynamic system memory.

htaccess file:
php_value post_max_size 16M
php_value upload_max_filesize 6M

<?php
//  $img_base = base directory structure for thumbnail images
//  $w_dst = maximum width of thumbnail
//  $h_dst = maximum height of thumbnail
//  $n_img = new thumbnail name
//  $o_img = old thumbnail name
function convertPic($img_base, $w_dst, $h_dst, $n_img, $o_img)
  {
ini_set('memory_limit', '100M');   //  handle large images
  
unlink($img_base.$n_img);         //  remove old images if present
  
unlink($img_base.$o_img);
  
$new_img = $img_base.$n_img;
    
  
$file_src = $img_base."img.jpg"//  temporary safe image storage
  
unlink($file_src);
  
move_uploaded_file($_FILES['Filedata']['tmp_name'], $file_src);
             
   list(
$w_src, $h_src, $type) = getimagesize($file_src);     // create new dimensions, keeping aspect ratio
  
$ratio = $w_src/$h_src;
   if (
$w_dst/$h_dst > $ratio) {$w_dst = floor($h_dst*$ratio);} else {$h_dst = floor($w_dst/$ratio);}

   switch (
$type)
     {case
1:   //   gif -> jpg
       
$img_src = imagecreatefromgif($file_src);
        break;
      case
2:   //   jpeg -> jpg
       
$img_src = imagecreatefromjpeg($file_src);
        break;
      case
3//   png -> jpg
       
$img_src = imagecreatefrompng($file_src);
        break;
     }
  
$img_dst = imagecreatetruecolor($w_dst, $h_dst);  //  resample
  
  
imagecopyresampled($img_dst, $img_src, 0, 0, 0, 0, $w_dst, $h_dst, $w_src, $h_src);
  
imagejpeg($img_dst, $new_img);    //  save new image

  
unlink($file_src);  //  clean up image storage
  
imagedestroy($img_src);       
  
imagedestroy($img_dst);
  }

$p_id = (Integer) $_POST[uid];
$ver = (Integer) $_POST[ver];
$delver = (Integer) $_POST[delver];
convertPic("your/file/structure/", 150, 150, "u".$p_id."v".$ver.".jpg", "u".$p_id."v".$delver.".jpg");

?>

wyverald at gmail dot com (12-Dec-2009 05:27)

Another note concerning the following 2 warnings:

-
Warning: move_uploaded_file(/dest/inat/ion.ext) [function.move-uploaded-file]: failed to open stream: No such file or directory in /upload/handler.php on line X

Warning: move_uploaded_file() [function.move-uploaded-file]: Unable to move '/temp/file/name' to '/dest/inat/ion.ext' in /upload/handler.php on line X
-

You would think that something is wrong about '/temp/file/name'... while actually, the real cause could be that the directory '/dest/inat' does not exist. Create this directory and the problem will likely get fixed.

Hope this helps.

gotrunko at hotmail dot com (13-Nov-2009 12:50)

This function can upload many files whitout parameters in the declaration.
If one of them can not be uploaded, the function returns false and deletes all files that have been sent

<?php
function uploadFiles() {
   
$num_args = func_num_args();
   
$arg_list = func_get_args();
   
   
$valReturn = false;
   
$i = 0;
   
$unlinkElement = array();
    foreach(
$arg_list as $key=>$value) {
        if(
is_array($value) AND is_array($value[0])) {
            if(
$value[0]['error'] == 0 AND isset($value[1])) {
                if(
$value[0]['size'] > 0 AND $value[0]['size'] < 500000) {
                   
$typeAccepted = array("image/jpeg", "image/gif", "image/png");
                    if(
in_array($value[0]['type'],$typeAccepted)) {   
                       
$destination = $value[1];
                        if(isset(
$value[2])) {
                           
$extension = substr($value[0]['name'] , strrpos($value[0]['name'] , '.') +1);
                           
$destination .= (str_replace(" ","-",$value[2])).".".$extension;
                        } else {
                           
$destination .= $value[0]['name'];
                        }
                       
                        if(
move_uploaded_file($value[0]['tmp_name'],$destination)) {
                           
$i++;
                           
$unlinkElement[] = $destination;
                        }
                    }
                }
            }
        }
    }
    if(
$i == $num_args) {
       
$valReturn = true;
    } else {
        foreach(
$unlinkElement as $value) {
           
unlink($value);
        }
    }
    return
$valReturn;
}
?>

To use this function you must specify an array with min two parameters like that.
NAME is an optional parameter !
uploadFiles(array("FILES","DESTINATION","NAME"));

<?php

$file_one
= array($_FILES['file_one'],$destination,$name_one);
$file_two = array($_FILES['file_two'],$destination); //The name will be the same that $_FILES[]['name']

if(uploadFiles($file_one,$file_two)) {
    echo
"true";
} else {
    echo
"false";
}
?>

chatchaw at tot dot co dot th (19-Oct-2009 08:03)

When you use move_uploaded_file function to upload a file with utf-8  filename to linux system, you probably check your result by browsing to see the file in the target directory so please make sure that your terminal emulator or your samba configuration is set the character encoding to utf-8 otherwise  your file will be shown as ?????? (unreadable character).

brentwientjes at NOSPAM dot comast dot net (18-Oct-2009 08:21)

I have looked at a lot of the file upload code listed below and other php documentation and have developed hopefully a robust single file upload routine.  I will later update with a multi file upload.  I have modestly tested the code.

<?php
//  5MB maximum file size
$MAXIMUM_FILESIZE = 5 * 1024 * 1024;
//  Valid file extensions (images, word, excel, powerpoint)
$rEFileTypes =
 
"/^\.(jpg|jpeg|gif|png|doc|docx|txt|rtf|pdf|xls|xlsx|
        ppt|pptx){1}$/i"
;
$dir_base = "/your/file/location/";

$isFile = is_uploaded_file($_FILES['Filedata']['tmp_name']);
if (
$isFile)    //  do we have a file?
  
{//  sanatize file name
    //     - remove extra spaces/convert to _,
    //     - remove non 0-9a-Z._- characters,
    //     - remove leading/trailing spaces
    //  check if under 5MB,
    //  check file extension for legal file types
   
$safe_filename = preg_replace(
                     array(
"/\s+/", "/[^-\.\w]+/"),
                     array(
"_", ""),
                    
trim($_FILES['Filedata']['name']));
    if (
$_FILES['Filedata']['size'] <= $MAXIMUM_FILESIZE &&
       
preg_match($rEFileTypes, strrchr($safe_filename, '.')))
      {
$isMove = move_uploaded_file (
                
$_FILES['Filedata']['tmp_name'],
                
$dir_base.$safe_filename);}
      }
   }
?>

I use $isFile and $isMove later in the code for error recording.

Make sure your system has the appropriate file loading limits. This caused a lot of headeaches trying to figure out why some files loaded and some did not.   In my case I have an .htaccess file in the root of the web site with:

php_value post_max_size 16M
php_value upload_max_filesize 6M

You may also need to extend the execution time depending upon the amount of data being transferred.

(sorry if spacing of code is a little off.  it was hard to make the note editor like the code style.)

dt at NOSPAM dot windsor-county dot com (25-Aug-2009 03:10)

Easiest way to find the extension of an uploaded file is to use:

<?php
$extension
= end(explode(".", $file['name']));
?>

Anonymous (21-Jul-2009 07:33)

$file_extension = pathinfo($path, PATHINFO_EXTENSION);

omgmain at gmail dot com (31-Jan-2009 04:23)

This function should run perfectly, but just in case there are errors, this should help.
1 : Check that the syntax is correct. Remember, lines end with ;
2 : Make sure that the file you're moving exists, and that the place you're writing to is...well, writable. Sometimes, for instance with mac, they make the file so that it can only be accessed by the system, and you. You need to make it available for everyone.
3 : Make sure that the file size of the file you're uploading is under the max upload size. You can change the allowed file size on the php.ini file. The default value is 2M (M as in Megabytes). Also make sure that uploading is allowed
---
If you don't have any errors, then give yourself a pat on the back. BUT, to make your script more secure, put in your file:
str_replace('.', '', $_FILES['file name']['name']);
str_replace('/', '', $_FILES['file name']['name']);
Replace file name with the file name, and you're good to go!

nuabaranda at web dot de (14-Jan-2009 09:21)

When using PHP on Windows and trying to use move_uploaded_file() on a file with special non-ascii characters like german umlauts they get converted bytewise thus destroying them resulting in a wrong CP1251 Windows filename.

Johan GENNESSON (php at genjo dot fr) (08-Jan-2009 02:08)

sedativchunk post a method to find the extension of the file uploaded; but if the extension is more than 3 characters it won't work :

<?php
    $file_type
= 'hello.world.JPEG';
   
$file_type_length = strlen($file_type) - 3;
    echo
substr($file_type, $file_type_length);    //Will return PEG
?>

Instead you can use :

<?php
   
echo strrchr('hello.world.JPEG', '.');    //Will return .JPEG
?>

Best regards
Johan

sedativchunk at gmail dot com (21-Dec-2008 10:13)

I've been having alot of problems validating files on upload. The main problem I was having was matching up the type of file uploaded with the allowed file types, as when you use $_FILES['userfile']['type'], the variable contains the MIME type, which can change consistently from browser to browser.

A better method for simply finding the file type is to get the extension of the file by the file name. Here is an example of getting a file type and matching it to an allowed file type (then uploading it and doing some other validation):
<?php
   
// Declare variables
    // Get the basic file information
   
$userfile = $_FILES['userfile']['name'];
   
$file_size = $_FILES['userfile']['size'];
   
$file_temp = $_FILES['userfile']['tmp_name'];
   
$file_err = $_FILES['userfile']['error'];
   
$path = 'images/';

   
// Create a new file name
    // This is so if other files on the server have the same name, it will be renamed
   
$randomizer = rand(0000, 9999);
   
$file_name = $randomizer.$userfile;

// Get the file type
    // Using $_FILES to get the file type is sometimes inaccurate, so we are going
    // to get the extension ourselves from the name of the file
    // This also eliminates having to worry about the MIME type
   
$file_type = $userfile;
   
$file_type_length = strlen($file_type) - 3;
   
$file_type = substr($file_type, $file_type_length);

    if(!empty(
$userfile)) {
        echo
'<div style="font-weight: bold; padding: 6px;">File Uploaded  Information</div>
        <ul>
        <li>Original File Name: '
.$userfile. '</li>
        <li>New File Name: '
.$file_name. '</li>
        <li>File Type: '
.$file_type.'</li>
        <li>File Size: '
.$file_size. '</li>
        <li>File Temporary Name: '
.$file_temp. '</li>
        <li>Fille Error: '
. $file_err. '</li>
        </ul>'
;

       
// limit the size of the file to 200KB
       
if($file_size > 25600) {
            echo
'FILE SIZE TO LARGE<BR />';
            exit();
        }

       
// Set allowed file types
        // Set case of all letters to lower case
       
$file_type = strtolower($file_type);
       
$files = array();
       
$files[] = 'jpeg';
       
$files[] = 'jpg';
       
$files[] = 'gif';
       
$files[] = 'png';
       
// Search the array for the allowed file type
       
$key = array_search($file_type, $files);
        if(
$key) {
            echo
'<b>File allowed!</b><br />';
        } else {
            echo
'<b>ILLEGAL FILE TYPE</b><br />';
            exit();
        }

// Check for errors and upload the file
$error_count = count($file_error);
if(
$error_count > 0) {
        for(
$i = 0; $i <= $error_count; ++$i) {
            echo
$_FILES['userfile']['error'][$i];
        }
} else {
        if(
move_uploaded_file($file_temp, 'images/' .$file_name.'')) {
            echo
'<h3>Upload Successful!</h3>';
        } else {
            echo
'<h3>ERROR</h3>';
        }
}

    } else {
        echo
'<h3>No file has been selected.</h3>';
    }
?>

In this script, I am looking for image types JPG, PNG, and GIF. You could easily add other types of files ex.
$files[] = "docx";
$files[] = "txt";

I am running into some trouble getting PNG's to upload properly, but this is the best method for validating the file type I believe.

Antoine (24-Nov-2008 08:44)

I had exactly than" tnp at shaman dot co dot uk" : move_uploaded_file() is either asynchronous or uses some kind of virtual filesystem. But you may encounter big problems when trying to access a file just uploaded, especially is you tried to change the name.
If you have problems where the uploaded file seems unaccessible, try to use copy() instead.

Dan Delaney (13-Oct-2008 09:41)

For those using PHP on Windows and IIS, you SHOULD set the "upload_tmp_dir" value in php.ini to some directory around where your websites directory is, create that directory, and then set the same permissions on it that you have set for your websites directory. Otherwise, when you upload a file and it goes into C:\WINDOWS\Temp, then you move it to your website directory, its permissions will NOT be set correctly. This will cause you problems if you then want to manipulate that file with something like ImageMagick's convert utility.

Mark Kazemier (27-Aug-2008 05:36)

I have the same problem as the person two comments below me. When I use the move_uploaded_file function the permissions for the file are set to 0600. No matter what configurations you set.

I searched the internet and I found more people with the same problems, but no solutions. I set the umask of apache to 013 and still the files were set to 0600.

The copy function solves the problem. Another way to solve this problem is using the chmod function after uploading.

agan0052 at hotmail dot com (23-Aug-2008 08:22)

<?php

if(isset($_FILES['uploaded'])){
$target = "galleries/".basename($_FILES['uploaded']['name']) ;
print_r($_FILES);

if(
move_uploaded_file($_FILES['uploaded']['tmp_name'],$target)) echo "OK!";//$chmod o+rw galleries

}
else{
 echo
"<form enctype='multipart/form-data' action='CodeTool.php' method='POST'>";
 echo
"File:<input name='uploaded' type='file'/><input type='submit' value='Upload'/>";
 echo
"</form>";
}

?>

Florian S. in H. an der E. [.de] (17-Aug-2008 10:02)

move_uploaded_file (on my setup) always makes files 0600 ("rw- --- ---") and owned by the user running the webserver (owner AND group).
Even though the directory has a sticky bit set to the group permissions!
I couldn't find any settings to change this via php.ini or even using "umask()".

I want my regular user on the server to be able to "tar cjf" the directory .. which would fail on files totally owned by the webserver-process-user;
the "copy(from, to)" function obeys the sticky-bit though!

milan dot matejcek at seznam dot cz (05-Aug-2008 12:59)

<?php
/**
     * function for upload file
     * @version 5.8.2008
     * @author Milan Matejcek
     * @param $GLOBALS        $files        -$_FILES[], array with keys error, size, type etc.
     * @param string        $dir_out    -dir, where save file without filename
     * @param string        $up_file    -regular string for MIME type
     * @param int            $max_size    -maximum size [B]
     * @param bool|string    $f_name        -true    =new automatic filename
     *                     -false    =original filename
     *                     -string    =forexample picture.jpg, you will write only 'picture'
     * @return string        -filename
     */
   
   
function upload_file($files, $dir_out, $up_file='/', $max_size=null, $f_name=true){

        if(
$files['error'] == 0){
               
            if(
preg_match("~$up_file~", $files['type'])){

                if(
$max_size === null){
                   
$max_size    =$files['size'];
                }

                if(
$files['size'] > 0 && $files['size'] <= $max_size){
                   
                   
$name        =array_reverse(explode('.', $files['name']));
                   
$koncovka    ='.'.strtolower($name[0]);
                   
                    if(
$f_name === true){
                       
$files['name']    =substr(md5(microtime()),0,6).$koncovka;
                    }elseif (
is_string($f_name)){
                       
$files['name']    =$f_name.$koncovka;
                    }
/*
                      * }else{
                      * $files['name'] =$files['name'];
                      * }
                      */

                   
$filename    =$files['name'];

                   
$m    =@move_uploaded_file($files['tmp_name'], $dir_out.$files['name']);
                       
                    if(
$m === false){
                       
//soubor se nepodarilo nahrat
                       
return array(
                           
'num'    =>    4,
                           
'text'    =>    'selhala move_uploaded_file'
                           
);
                    }
                       
                }else{
                   
//file is big
                   
return array(
                       
'num'    =>    5,
                       
'text'    =>    'soubor je moc velky'
                       
);
                }

            }else{
               
//false MIME type
               
return array(
                   
'num'    =>    6,
                   
'text'    =>    'neodpovidajici typ souboru, kontrola na '.$up_file.' vysledek '.$files['type']
                );
            }
               
        }else{
           
//$_File['error'] return 1
           
return array(
               
'num'    =>    7,
               
'text'    =>    'selhalo nahrani souboru na server'
               
);
        }

        return
$filename;

    }
?>

jphansen at uga dot edu (26-Mar-2008 03:41)

I was getting error code 1 (http://www.php.net/manual/en/features.file-upload.errors.php), indicating that the file exceeded upload_max_filesize. To fix this, run <?php ini_set("upload_max_filesize", "100M"); ?> (then restart apache) changing the second argument to your limit.

rasponline at gmail dot com (14-Jan-2008 03:43)

Basic difference between Copy() and move_uploaded_file() function i have noted is that, Copy function upload the file from any source to any destination on the server!!!!
While move_uploaded_file() can moved the uploaded file from temp server location to any destination on the server!!!

iim dot vxk at gmail dot com (07-Sep-2007 10:38)

when you get this 2 Warnings - paths are a real sample - ::

-
move_uploaded_file(/uploads/images/sample.png) [function.move-uploaded-file]: failed to open stream: No such file or directory in /scripts/php/system/upload-file.php on line X
-

and

-
move_uploaded_file() [function.move-uploaded-file]: Unable to move '/tmp/somefilename' to '/uploads/images/sample.png' in /scripts/php/system/upload-file.php on line X
-

probably the path '/uploads/images/sample.png' is incomplete, in my case the complet path is "/home/x-user/public_html/uploads/images/sample.png"

you can use getcwd() to know the current working directory.

:)

tnp at shaman dot co dot uk (04-Sep-2007 09:20)

I may well also report this as a bug, but in the meantime I'll document what I have seen so far.

What I wanted to do, was take the uploaded temporary filename and pass it to MySql as part of a load_file  injection into a BLOB to store the file contents.
My first attempt was of an indexed array..

$filename=$_FILES[$index]["name"];
$filesize= $_FILES[$index]["size"];
$tmpname=$_FILES[$index]["tmp_name"];

followed by:-

$query=sprintf("insert into project_files set project_id='%s',current='yes',date='%s' ,user='%d', size='%d', description='%s', name='%s', content=LOAD_FILE('%s')",
                $project_id,
                date('Y-m-d'),
                $employee_id,
                $filesize,
                $filedescription,
                $filename,
                $tmpname);
mysql_query($query);

This gave me an empty content field. Zero bytes.

I took the echo $query string and applied it to MtySql interpreter. With a suitable filename it worked..well after fixing a few database perms..but no joy from PHP still.

I found this page and tried adding:-

move_uploaded_file($tmpname)"/tmp/foo");
$tmpname-"/tmp/foo";

before setting up the query.

That was worse. The browser just hung on me.

Then I tried
copy($tmpname,"/tmp/foo");
$tmpname="/tmp/foo";

That worked!?*&^

My CONJECTURE is that PHP has a meta file-system running, and the environment the program sees is NOT reflected into the OS (Debian etch, in this case) until it closes and flushes its buffers.

Copy() does in fact seem to result in a real disk write, but move_uploaded_file() does not, so when the name was passed to Mysqld, it didn't exist, or had zero content or maybe with a large file truncated content.

I can see the point of this: faster response for web browsers who get the program HTTP output over with before it settles down to its housekeeping, but in this case it's a bit of a disaster.

What is needed is a way to force the buffers to flush if that is what is going on...

bdeguire at yahoo dot com (20-Jul-2007 02:16)

For Windows users: Note that your file attributes from the temporary upload folder ("upload_tmp_dir" in php.ini) are copied to the destination folder (because the file is *moved*, not copied).

I ran into a problem when using Microsoft Indexing Server. For it to work, you must activate the attribute "For fast searching,  allow Indexing Server to index this folder". However, you must not only activate this attribute on the *final* destination folder, but ALSO on the temporary upload folder. So when the file is move from the temp location to the final location, the attributes are kept.

nlgordon at iastate dot edu (16-Jul-2007 07:29)

Just a helpful comment.  If you have open_basedir set then you must set upload_tmp_dir to somewhere within the open_basedir.  Otherwise the file upload will be denied.  move_uploaded_file might be open_basedir aware, but the rest of the upload process isn't.

bogusred (10-Jun-2007 09:58)

If you have a directory in a *nix environment where you store all of your file uploads and your php script only seems to work when permissions for that directory are set to 777, here's how to fix it so that you can have the security benefits of 755 while still allowing your php scripts to work, including the move_uploaded_file().

through shell access, navigate to the directory that contains your uploads folder and run the following 2 commands:
chown -R nobody uploaddir
chmod -R 755 uploaddir

Replace 'uploaddir' with the name of your uploads directory. The first command changes the owner of the directory and files to 'nobody' which is what php operates under. The second changes the folder and files to only allow user access to writing. This is much more secure.

Hopefully this will help someone out there who had the same problem as me.

masahigo at gmail dot com (30-May-2007 04:49)

I found a great resource concerning uploads with PHP:

http://www.radinks.com/upload/config.php

They explain and tell how to optimize PHP installation to handle large file uploads. Helped me a lot!

info at arpadh dot hu (04-May-2007 07:02)

Values upload_max_filesize and post_max_size (ie. php.ini values) cannot be modified in runtime with ini_set() function.
If you are using Apache web server, use .htaccess files with an IfModule replacing values corresponding to your file size and PHP version:

<IfModule mod_php4.c>
php_value upload_max_filesize 50M
php_value post_max_size 50M
</IfModule>

- means 50MB upload limit.

booc0mtaco at gmail dot com (19-Apr-2007 04:45)

Also, make sure that the setting for the post_max_size allows for a proper file size range.

post_max_size = 128M ; Expands the size of POST data for file uploads

guy at neonxero dot net (22-Mar-2007 03:47)

I could be wrong, but I usualy use

$uploadext = strtolower(strrchr($imagename,"."));

to find the file extension when uploading, as opposed to explode().

(13-Mar-2007 10:55)

To allow bigger upload file size, edit in php.ini and change:

upload_max_filesize =350M ; Maximum allowed size for uploaded files.
post_max_size =360M ; Maximum size of POST data that PHP will accept.

max_execution_time =5000 ; Maximum execution time of each script, in seconds

In adition, you must change the server configuration as well.
For apache server, edit httpd.conf.

Harmor (07-Mar-2007 05:38)

the dot only dot storm at gmail dot com wrote:
>
> In addition to the file extension checking. A simply way
> of getting the extension (regardless of size):
>
> $efilename = explode('.', $filename);
> $ext = $efilename[count($efilename) - 1];
>

How about:

$ext = end(explode('.',$filename));

dev at rising9 dot com (06-Mar-2007 01:07)

Can you explain more, how i can change the max memory size varible for the large file can work with move_uploaded_file()?
Thanks a lot!

(03-Feb-2007 03:32)

If you find that large files do not upload in PHP even though you've changed the max_upload_size , this is because you need to change the max memory size varible too. The entire file is loaded into memory before it is saved to disk.

Nibinaear (01-Nov-2006 10:49)

If you want to change the filename used by the user then use this code (static name). This example uploads a pdf magazine to a website and always overwrites the file that is there. Use if you are dealing with a small number of files or people who know what they're doing!

<?php
 
if(!empty($_FILES["magfile"]))
  {
   
$uploaddir = $_SERVER['DOCUMENT_ROOT']."/dainsider/magazines/";
   
$uploaddir.="magazine.pdf";
   
   
//Copy the file to some permanent location
   
if(move_uploaded_file($_FILES["magfile"]["tmp_name"], $uploaddir))
    {
      echo
"Magazine Updated!";
    }
    else
    {
      echo
"There was a problem when uploding the new file, please contact ".$admin_email." about this.";
     
print_r($_FILES);
    }
  }
?>

shacker at birdhouse dot org (10-Sep-2006 08:28)

If you're dealing with files uploaded through some external FTP source and need to move them to a final destination, searching php.net for "mv" or "move" won't get you what you want. You want the rename() function.

http://www.php.net/manual/en/function.rename.php

(move_uploaded_file() won't work, since the POST vars won't be present.)

Rob Szarka (23-Aug-2006 02:18)

Apparently the warning above might better be written "If the destination file already exists, it will be overwritten ... regardless of the destination file's permissions."

In other words, move_uploaded_file() executes as if it's root, not the user under which the web server is operating or the owner of the script that's executing.

sergeygrinev at mail dot ru (20-Apr-2006 10:04)

small typo:

$fulldest = $dest.$newfilename;

show be

$fulldest = $dest.$filename;

or you would have infinite loop.

Zarel (14-Apr-2006 02:12)

nouncad at mayetlite dot com posted a function that uploaded a file, and would rename it if it already existed, to filename[n].ext

It only worked for files with extensions exactly three letters long, so I fixed that (and made a few other improvements while I was at it).

<?php
// Usage: uploadfile($_FILE['file']['name'],'temp/',$_FILE['file']['tmp_name'])
function uploadfile($origin, $dest, $tmp_name)
{
 
$origin = strtolower(basename($origin));
 
$fulldest = $dest.$origin;
 
$filename = $origin;
  for (
$i=1; file_exists($fulldest); $i++)
  {
   
$fileext = (strpos($origin,'.')===false?'':'.'.substr(strrchr($origin, "."), 1));
   
$filename = substr($origin, 0, strlen($origin)-strlen($fileext)).'['.$i.']'.$fileext;
   
$fulldest = $dest.$newfilename;
  }
 
  if (
move_uploaded_file($tmp_name, $fulldest))
    return
$filename;
  return
false;
}
?>

jessy dot diamondman at gmail dot com (05-Apr-2006 05:29)

I am pretty new, and am having upload problems myself, but I think I can help out ffproberen2 at dodgeit dot com with his premission denied errors. I had these two, and I had to change the upload directory, not the tmp_upload_dir or what ever it is called. The move_uploaded_file meathod takes an upload location as the last parameter. I am running a bundled package of Apache, Php, mySQL and so on, and on mine, specifing a directory of '' will upload it into C:\Program Files\xampp\apache (my PC is my experimental server, I will get linux, but got to obtain it and internet cuts off after 196mb so can't download it) even though php file is in C:\Program Files\xampp\htdocs\xampp\jessyexum\upload_client.php.

This is a code that I found and then modified, hope it can help. It dosn't always upload every file type giving me an error #2.

<?php
$uploaddir
= '';
$uploadfile = $uploaddir . basename($_FILES['upfile']['name']);
echo
'<pre>';
if (
move_uploaded_file($_FILES['upfile']['tmp_name'], $uploadfile)) {
   echo
"File is valid, and was successfully uploaded.\n";
} else {
   echo
"Possible file upload attack!\n";
}
echo
'Here is some more debugging info:';
print_r($_FILES);
print
"</pre>";
?>

ffproberen2 at dodgeit dot com (05-Apr-2006 11:02)

On windows I made the directory writable, by changing the Apache httpd.conf file.

The problem I had, was with the upload directory. The move_uploaded_file produced an error like: failed to open stream: Permission denied.

I changed my php.ini to specify an upload directory:
  upload_tmp_dir = "d:/temp/php/uploads/"

and I added the following in the Apache hpptd.conf file:

  <Directory "D:/temp/php/uploads">
    Options None
    AllowOverride None
    Order allow,deny
    Allow from all
  </Directory>

restarted Apache, and the upload succeeded.

j dot m dot thomas at NOSPAM dot blueyonder dot co dot uk (16-Feb-2006 08:26)

To retrieve the file extension, and various other information about the path, it is easiest to use the pathinfo function.

<?php
$path_parts
= pathinfo('/www/htdocs/index.html');

echo
$path_parts['dirname'], "\n";
echo
$path_parts['basename'], "\n";
echo
$path_parts['extension'], "\n";
?>

Would produce:

/www/htdocs
index.html
html

http://uk.php.net/manual/en/function.pathinfo.php

adam at darkhousemedia dot com (03-Feb-2006 06:35)

To retrieve the file extension, I think this example makes more sense than the one below. 

$ext = explode(".", $file);
$ext = array_pop($ext);

It doesn't have to count() the array and then subtract 1 to point to the proper array element, it simply isolates the last element of the array, and discards everything else.

calamitoso at gmail dot com (31-Jan-2006 07:10)

to separate (for example) images from other file types among the uploaded files you can check the MIME type also (thus making the file extension check unnecessary)

$temp = strpos($_FILES["pic"]["type"], "image");
if ($rep===FALSE){
   //the strpos function will return a boolean "false" ONLY if the needle string is not found within the haystack
   echo "is not an image";
}else{
   echo "is an image";
}

mancow at macfilez dot net (10-Jan-2006 05:31)

To nouncad at mayetlite dot com,

That function will work fine for files with a 3-character file extension.  However, it is worth noting that there are valid, registered file extensions that are longer than 3 characters.  For example, a JPEG file can be denoted by *.jpg (and others), but it can also have *.jpeg as a valid extension.  Check out http://www.filext.com/ for a good reference of file extensions.

The best bet to me would be parsing the uploaded file's name ($_FILES['uploadedfile']['name']) based on the presence of dots.  Another wrench in the gears:  a file can have dots in the filename.  That's easy enough to handle -- just explode() the file name and hope that the last element in the array it gives you is the file extension (you can always validate it if you're so inclined).  Then just piece it together in a string accordingly by stepping through the array (don't forget to add those dots back to where they were!), appending a guaranteed unique string of characters (or enumerate it like you were doing, keeping track via a loop), and finally tacking on the file extension.

You may have other mechanisms for verifying a file's extension, such as a preg_match on the whole name, using something like "/\\.(gif|jpg|jpeg|png|bmp)$/i" (more can, of course, be added if you so desire) for the most common types of images found on the web.

For blindly guaranteeing an uploaded file will be uniquely named, this seems like a fantastic way to go.  Enjoy!

AT-HE (at_he AT hotm4il DOT com) (16-Dec-2005 06:28)

---------
Note that post_max_size also needs to be considered, by default it is 8M. I raised my upload_max_filesize to 20M and was wondering why 10M uploads weren't working...

r: It could be because of your max execution time.
----------

try changing the value of both post_max_size and upload_max_filesize

nouncad at mayetlite dot com (14-Dec-2005 01:30)

Great!! my first note here...

This function upload a file.
If file exist, create a copy as "filename[n].ext"

<?php
function subirFichero($origen, $destinoDir, $ftemporal) {   
   
$origen = strtolower(basename($origen));

   
$destinoFull = $destinoDir.$origen;
   
$frand = $origen;
   
$i = 1;
   
    while (
file_exists( $destinoFull )) {
       
$file_name         = substr($origen, 0, strlen($origen)-4);
       
$file_extension  = substr($origen, strlen($origen)-4, strlen($origen));
       
$frand = $file_name."[$i]".$file_extension;
       
$destinoFull = $destinoDir.$frand;
       
$i++;
    }
   
    if (
move_uploaded_file($ftemporal, $destinoFull))    return $frand;
    else                                                 return
"0";
}
?>

ineedmynetwork.com (07-Nov-2005 09:27)

Microsoft returns image/pjpeg not image/jpg when using $_FILES['imageName']['type'];

albert (07-Nov-2005 08:44)

move_uploaded_file()'s return codes are not allways obious !

Unable to move '/var/tmp/phpuuAVJv' to '/home/me/website.com/upload/images/hello.png'

will apear if your disk is full, or the webserver (www user) exeeded it's disk qouta. (probably some others)

i dont know if its a bug (just not iplemented) or a feature (to hide from 3rd parties details about the system or about the specific error) ?

it happend to me that after several months of successful operation, the disk filled up and qouta exeeded.

it took me long time, finding out why all the sudden my scripts didnt work properly anymore.

(04-Nov-2005 11:56)

[quote]
Note that post_max_size also needs to be considered, by default it is 8M. I raised my upload_max_filesize to 20M and was wondering why 10M uploads weren't working...
[/quote]

It could be because of your max execution time.

(29-Oct-2005 04:44)

Note that post_max_size also needs to be considered, by default it is 8M. I raised my upload_max_filesize to 20M and was wondering why 10M uploads weren't working...

jest3r at mtonic dot net (20-Oct-2005 05:10)

It seems that move_uploaded_file use the GROUP permissions of the parent directory of the tmp file location, whereas a simple "copy" uses the group of the apache process. This could create a security nighmare if your tmp file location is owned by root:wheel

mikelone (06-Sep-2005 04:46)

If the user try to upload a too bigger file then the upload procedure will fail even if u have established an error message.
How to avoid this problem? there's my solution:

(max_file_size = 2,50 MB)

$fsize = $_FILES["userfile"]["size"];

if($fsize == 0 || $fsize > 2621000) exit("keep the filesize under 2,50MB!!");

When the size is bigger than the MAX_FILE_SIZE field, the value of $fsize is equal to 0 (zero) ......

espiao at gmail dot com (27-Jul-2005 03:25)

/**
 * This function moves the archives and directoryes of a directory of
 * origin for a directory destination being able replace them or not.
 **/

function mvdir($oldDir, $newDir, $replaceFiles = true) {

    if ($oldDir == $newDir) {
        trigger_error("Destination directory is equal of origin.");
        return false;
    }
       
    if (!($tmpDir = opendir($oldDir))) {
        trigger_error("It was not possible to open origin directory.");
        return false;
    }

    if (!is_dir($newDir)) {
        trigger_error("It was not possible to open destination directory.");
        return false;       
    }

    while (($file = readdir($tmpDir)) !== false) {

        if (($file != ".") && ($file !== "..")) {
           
            $oldFileWithDir = $oldDir . $file;
            $newFileWithDir = $newDir . $file;
           
            if (is_dir($oldFileWithDir)) {
               
                @mkdir($newFileWithDir."/", 0777);
                @mvdir($oldFileWithDir."/", $newFileWithDir."/", $replaceFiles);
                @rmdir($oldFileWithDir);

            }
            else {
                if (file_exists($newFileWithDir)) {
                    if (!$replaceFiles) {
                       
                        @unlink($oldFileWithDir);
                        continue;
                       
                    }
                }
               
                @unlink($newFileWithDir);
                @copy($oldFileWithDir, $newFileWithDir);
                @chmod($newFileWithDir, 0777);
                @unlink($oldFileWithDir);
               
            }
        }
    }
   
    return true;
   
}

/**
 * This is an example of move with replace files on destination folder if
 * exists files with the same names on destionatio folder
 **/
mvdir("/var/www/example/", "/var/www/other_folder/");

/**
 * This is an example of move without replace files on destination
 * folder if  exists files with the same names on destionatio folder
 **/
mvdir("/var/www/example/", "/var/www/other_folder/", false);

Darrell (18-May-2005 10:51)

move_uploaded_file apparently uses the root of the Apache installation (e.g. "Apache Group\Apache2" under Windows) as the upload location if relative pathnames are used.

For example,
$ftmp = $_FILES['userfile']['tmp_name'];
$fname = $_FILES['userfile']['name'];
move_uploaded_file($ftmp, $fname);
                          
moves the file to
"Apache Group\Apache2\$fname";

In contrast, other file/directory related functions use the current directory of the php script as the offset for relative pathnames.  So, for example, if the command

mkdir('tmp');

is called from 'Apache Group\Apache2\htdocs\testpages\upload.php', the result is to create
'Apache Group\Apache2\htdocs\testpages\tmp'

On the other hand, if 'mkdir' is called just before 'move_uploaded_file', the behavior changes.  The commands,

mkdir('tmp');
move_uploaded_file($ftmp, $fname);

used together result in

"Apache Group\Apache2\htdocs\testpages\tmp\$fname"

being created.  Wonder if this is a bug or a feature.

Darrell

andrew@euperia,com (04-Apr-2005 10:29)

Instead of using chdir or chmod 0777 a safer alternative to move_uploaded_files is to use PHP's ftp functions to move the file into a web dir.

1. Make ftp connection to 127.0.0.1 with the correct username and password.
2. ftp_chdir to the required directory.
3. ftp_put ($_FILES['myfile']['tmp_name'], $finalfilename);
4. ftp quit.

richardNO at SPAMbesite dot nl (11-Mar-2005 12:32)

Creating the dir with mkdir from php is a security risk too. Everyone who can run a php script on the server can write a script to mess with the dir.

user at php dot net (01-Mar-2005 10:54)

Giving the directory 777 permission is not a good idea for security reasons, it would be better to create the directory using "mkdir()".

That will make php user (usually "nobody") the owner of the directory, and permissions will not be a problem.

Michel S (16-Feb-2005 05:41)

I once had a problem with this function. File was uploaded correctly, but I still had to chmod the file afterwards. It could not be used otherwise.

Michel S

allan666 at NOSPAM dot gmail dot com (17-Dec-2004 06:35)

On the Fedora Core 3 Linux distribution, you may get a "failed to open stream: Permission denied in ..." message. I fact changing the permission of the directory will not work (even if you set to 0777). It is because of the new SELinux kernel that allow apache user to write only in /tmp dir (I think). In order to solve the problem you must to disable the SELinux (at least for apache service) to allow the server to write in other directories. To do that, run the system-config-securitylevel app and disable the SE to apache service. Reboot your system and continue your work. Hope it helps!

php at f00n dot com (04-Jul-2004 09:17)

If you are building an intranet framework and use NAT/Routing heed the following advice.

If you want to move uploaded files to an FTP server you cannot use the ftp wrapper (ie. 'ftp://user:pass@ftpserver/') as part of your move_uploaded_file() action.  This is due to the wrapper only using passive mode with ftp.

The only workaround is using the ftp functions (may not be compiled by default with *nix but is by default with windows).

froid_nordik at sympatico dot ca (04-Jun-2004 05:26)

Make sure the directory you are moving the file to exists before using this command.

sauron at nospam on morannon dot org (08-Mar-2004 01:20)

An extension only does not really tell you what type of file it really is. I can easily rename a .jpg file to a .zip file and make the server think it is a ZIP file with webmaster kobrasrealm's code.

A better way is to use the Linux utility "file" to determine the file type. Although I'm aware that some users might use Windows on their webservers, I thought it's worth  mentioning the utility here. Using the backtick operators and preg_matches on the output, you can easily determine the file type safely, and fix the extension when necessary.

mail at johan dot it (28-Feb-2004 10:14)

Warning: If you save a md5_file hash in a database to keep record of uploaded files, which is usefull to prevent users from uploading the same file twice, be aware that after using move_uploaded_file the md5_file hash changes! And you are unable to find the corresponding hash and delete it in the database, when a file is deleted.

mina86 at tlen dot pl (07-Dec-2003 11:03)

Hey! Why not using strrchr() to get file  extension:
<?php $ext = strrchr($_FILES['file']['name'], '.'); ?>
or to get it without '.' at the begining:
<?php $ext = substr(strrchr($_FILES['file']['name'], '.'), 1); ?>

If you want to update file without any strang characters you can use:
<?php
move_uploaded_file
(
 
$_FILES["file"]["tmp_name"],
 
$dir . preg_replace('/[^a-z0-9_\-\.]/i', '_', $_FILES["file"]["name"])
);
?>

wolke74 at web dot de (18-Nov-2003 05:02)

French and English filenames --- as it is not forbidden -- often have an apostrophy, for instance "That's advertisement paper.doc" or "Les aventures d'Alice dans le pays du miracle.doc". However, uploading such files can run into trouble.

So you can write, if the posted file had been marked by myfile .

if(!move_uploaded_file($_FILES["myfile"]["tmp_name"],
rawurlencode($mydir.$_FILES["myfile"]["name"]))
{
     echo "Something is wrong with the file";
      exit;
}

(09-Nov-2003 03:54)

The example to find file extension bellow is quite confusing and its using to much code for a much simpler solution. Which is in example:

$file_parts = pathinfo('dir/' . $_FILES['file']['name']);
$file_extension = strtolower($file_parts['extension']);

The 'dir/' part is only to get a valid path.