69

Okay I'm totally new in this field and going through some tutorials and I found that while uploading files in PHP it stores them in a temporary location.

$file_temp=$_FILES['file']['tmp_name'];
$file_loc="Upload".$file_name;
move_uploaded_files($file_temp,$file_loc);

Now why doesn't PHP allow uploading files directly to the desired location? Why they are stored in a temporary location with a .tmp extension and what benefit do we get from this strategy?

psmears
  • 26,070
  • 4
  • 40
  • 48
Jai Shree Ganesh
  • 511
  • 4
  • 15
  • Related: https://stackoverflow.com/questions/13972714/uploading-processing-storing-and-delivering-user-provided-files-and-images – Machavity Feb 16 '18 at 13:33
  • Wouldn't this allow clients to upload files arbitrarily, even if the script wasn't intended for uploading? – Barmar Feb 16 '18 at 23:01
  • How would it know where the desired location is? – Barmar Feb 16 '18 at 23:02
  • 1
    See the upload-tmp-dir directive in php.ini: http://php.net/manual/en/ini.core.php#ini.upload-tmp-dir. It allows setting the location of the temporary folder. One benefit of using tmp folder is that the uploaded file is kept in a folder outside the document root. If the tmp folder was inside the document root, users would be able to download each other's files – Nadir Latif Feb 17 '18 at 04:56

3 Answers3

83

Good question. The short answer is that PHP must process the entire HTTP request - filling out $_POST with data, and $_FILES as needed - before giving control to your script. Since your script doesn't gain control until after the processing, there's no way to tell PHP where to put that file data.

But why does PHP do it this way? Well, let's look at an HTTP POST with file data:

POST /upload?upload_progress_id=12344 HTTP/1.1
Host: localhost:3000
Content-Length: 1325
Origin: http://localhost:3000
... other headers ...
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryePkpFF7tjBAqx29L

------WebKitFormBoundaryePkpFF7tjBAqx29L
Content-Disposition: form-data; name="MAX_FILE_SIZE"

100000
------WebKitFormBoundaryePkpFF7tjBAqx29L
Content-Disposition: form-data; name="uploadedfile"; filename="hello.o"
Content-Type: application/x-object

... contents of file goes here ...
------WebKitFormBoundaryePkpFF7tjBAqx29L--

Notice that the contents of the request are a multi-part encoded document, with form fields interspersed among file data. In this particular example, the form field occurs before the file data. However, it's possible - indeed likely - that form data occurs after file data.

So, in order to guarantee that PHP can give you all the $_POST data, PHP must process the entire request. So it might as well complete the $_FILES super-global while it's there.

Now, PHP could keep this file data in memory, but this might really be a bad idea. Think about what would happen if PHP needed to store a 100 MiB file a user uploaded. Suddenly, you've got a 100 MiB increase in the RSS of your Apache process, which is really not too good - Apache might be ulimited to not have that much space, or Apache might get swapped: to your users anguish. So, PHP does the next best thing: put this received file in a temporary file.

You might ask why PHP can't be told what file to put the incoming file data first, so you didn't have to move it. Well, that's a bootstrapping problem: PHP hasn't handed control over to the script yet, so the script can't tell PHP where to put the file. Thus, PHP does the best it can: put the file data into a temporary file.

Now, you can keep this file data in a RAM disk, for speed if you want. This is a good approach if you don't mind the infrastructure cost (eg, maintaining the RAM disk setup). But note this isn't like PHP holding it in RAM itself: in that scenario, the PHP container process (usually Apache or some other web server) must have the heap to hold the file (which it might not). In this scenario, the RAM disk is managed by the kernel.

bishop
  • 37,830
  • 11
  • 104
  • 139
  • 2
    Can I change the temporary location? Or it is a fixed location? – Jai Shree Ganesh Feb 16 '18 at 03:56
  • 18
    Yes: change the [`upload_tmp_dir`](http://php.net/manual/en/ini.core.php#ini.upload-tmp-dir) setting to the desired path. – bishop Feb 16 '18 at 03:58
  • 2
    Thank you so much very much appreciate your effort – Jai Shree Ganesh Feb 16 '18 at 03:59
  • 3
    The way other frameworks usually solve this is to avoid the whole problem by providing the application with a lazy enumerable of http parts. A more flexible solution, but it also puts more responsibility on the application developer which PHP usually tries to avoid. – Voo Feb 16 '18 at 11:08
  • 8
    @JaiShreeGanesh if you're trying to change the `upload_tmp_dir` variable to desired, publicly accessible directory... **don't**. Somone can simply POST a malicious file to your PHP script and it will end up in that directory **without any sanity checking**. – Salman A Feb 16 '18 at 13:20
  • 1
    Good question, nice brief answer and i learnt something today. I never thought of this so far. Thanks for jai sree Ganesh and bishop and all others who have posted your points, really useful. – Abilash Arjunan Feb 21 '18 at 06:49
22

From What is the benefit of writing to a temp location, And then copying it to the intended destination?:

  • On most platforms, file moves are atomic, but file writes are not (especially if you can't write all the data in one go). So if you have the typical producer/consumer pattern (one process produces files, the other watches a directory and picks up everything it finds), writing to a temp folder first and only then moving to the real location means the consumer can never see an unfinished file.
  • If the process that writes the file dies halfway through, you have a broken file on your disk. If it's in a real location, you have to take care of cleaning it up yourself, but if it's in a temp location, the OS will take care of it. If the file happens to be created while a backup job is running, the job may pick up an incomplete file; temp directories are generally excluded from backups, so the file will only be included once moved to the final destination.
  • The temp directory may be on a fast-but-volatile filesystem (e.g. a ramdisk), which can be beneficial for things like downloading several chunks of the same file in parallel, or doing in-place processing on the file with lots of seeks. Also, temp directories tend to cause more fragmentation than directories with less frequent reads, writes, and deletes, and keeping the temp directory on a separate partition can help keep fragmentation of the other partitions down.
Jomoos
  • 12,823
  • 10
  • 55
  • 92
  • 4
    Please tell what is it mean "file moves are atomic" ? Very much appreciate your effort – Jai Shree Ganesh Feb 16 '18 at 03:32
  • 1
    @JaiShreeGanesh Atomic move means it won't fail halfway through. – Shafiq al-Shaar Feb 16 '18 at 03:36
  • 3
    @JaiShreeGanesh atomic operation, is an operation, which can be done without interruption (think of interruptions, process scheduling etc.,). They either fails or succeed. Metadata changes are atomic. File rename is such a case. – Jomoos Feb 16 '18 at 03:36
  • 3
    Atomic means it's all or nothing. – Robert Feb 16 '18 at 03:46
  • 2
    @JaiShreeGanesh: "atomic" is an important concept in computer science. See e.g. the Wikipedia article on [linearizability](https://en.wikipedia.org/wiki/Linearizability) for an overview. – sleske Feb 16 '18 at 10:34
  • 1
    But cross-filesystem moves aren't atomic, so if the temporary storage is indeed on a separate partition or on a tmpfs... – Daniel Schepler Feb 16 '18 at 20:03
7

Two additional reasons:

  1. If you decide not to accept the file for some reason, it's stored in a temporary location and presumably will be automatically deleted at some point.

  2. Security. Let's say PHP was set to upload to a web-accessible directory like /images. Someone could upload some sort of hacking file and then execute it. By putting files in a temporary directory first (which will usually not be web-accessible), PHP lets you examine the file first. For instance, by processing images to remove any comments that could contain PHP code.

24Ahead
  • 71
  • 1