Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP won't acknowledge its own uploaded temporary files

I've got a real head-scratcher here.

This is my system configuration:

  • Windows Server 2008 R2
  • PHP 5.3.8 installed as a FastCGI module
  • IIS 7.5

This is my problem:

I have a simple file upload form. As we know, when PHP accepts a file upload, the file is given a temporary name and placed in a temporary directory before it's processed. In my case, PHP places the file in the temporary directory (which happens to be E:\Inetpub_IIS\tmp, next to E:\Inetpub_IIS\wwwroot) but then immediately "forgets" that the file exists until the garbage collector shows up, which deletes the temporary file. More specifically, the temporary file is created in the temporary directory on the server, but when I call sha1_file() on that file, the function returns nothing. file_exists() also fails. This makes me think that PHP can't find the file. The ProcMon log below shows that PHP is looking in the right spot.

Here is my ProcMon log:

2:43:14.9175650 PM  php-cgi.exe 5020    CreateFile  E:\Inetpub_IIS\tmp\php3F86.tmp  SUCCESS Desired Access: Generic Read, Disposition: Create, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: None, AllocationSize: 0, Impersonating: NT AUTHORITY\IUSR, OpenResult: Created
2:43:14.9182596 PM  php-cgi.exe 5020    CloseFile   E:\Inetpub_IIS\tmp\php3F86.tmp  SUCCESS 
2:43:14.9184424 PM  php-cgi.exe 5020    QueryOpen   E:\Inetpub_IIS\tmp\php3F86.tmp  SUCCESS CreationTime: 12/27/2011 2:43:14 PM, LastAccessTime: 12/27/2011 2:43:14 PM, LastWriteTime: 12/27/2011 2:43:14 PM, ChangeTime: 12/27/2011 2:43:14 PM, AllocationSize: 0, EndOfFile: 0, FileAttributes: A
2:43:14.9185907 PM  php-cgi.exe 5020    CreateFile  E:\Inetpub_IIS\tmp\php3F86.tmp  SUCCESS Desired Access: Write Attributes, Synchronize, Disposition: Open, Options: Synchronous IO Non-Alert, Open Reparse Point, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a, Impersonating: NT AUTHORITY\IUSR, OpenResult: Opened
2:43:14.9187896 PM  php-cgi.exe 5020    SetBasicInformationFile E:\Inetpub_IIS\tmp\php3F86.tmp  SUCCESS CreationTime: 0, LastAccessTime: 0, LastWriteTime: 0, ChangeTime: 0, FileAttributes: AN
2:43:14.9188368 PM  php-cgi.exe 5020    CloseFile   E:\Inetpub_IIS\tmp\php3F86.tmp  SUCCESS 
2:43:14.9190234 PM  php-cgi.exe 5020    CreateFile  E:\Inetpub_IIS\tmp\php3F86.tmp  SUCCESS Desired Access: Generic Read/Write, Disposition: OverwriteIf, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: Read, Write, AllocationSize: 0, Impersonating: NT AUTHORITY\IUSR, OpenResult: Overwritten
2:43:14.9193771 PM  php-cgi.exe 5020    WriteFile   E:\Inetpub_IIS\tmp\php3F86.tmp  SUCCESS Offset: 0, Length: 5,119, Priority: Normal
2:43:14.9489663 PM  php-cgi.exe 5020    WriteFile   E:\Inetpub_IIS\tmp\php3F86.tmp  SUCCESS Offset: 5,119, Length: 5,119, Priority: Normal
2:43:14.9730524 PM  php-cgi.exe 5020    WriteFile   E:\Inetpub_IIS\tmp\php3F86.tmp  SUCCESS Offset: 10,238, Length: 5,119
2:43:15.0054693 PM  php-cgi.exe 5020    WriteFile   E:\Inetpub_IIS\tmp\php3F86.tmp  SUCCESS Offset: 15,357, Length: 5,119, Priority: Normal
2:43:15.0309328 PM  php-cgi.exe 5020    WriteFile   E:\Inetpub_IIS\tmp\php3F86.tmp  SUCCESS Offset: 20,476, Length: 5,119
2:43:15.0633978 PM  php-cgi.exe 5020    WriteFile   E:\Inetpub_IIS\tmp\php3F86.tmp  SUCCESS Offset: 25,595, Length: 5,119
2:43:15.0879028 PM  php-cgi.exe 5020    WriteFile   E:\Inetpub_IIS\tmp\php3F86.tmp  SUCCESS Offset: 30,714, Length: 5,119, Priority: Normal
...
2:43:17.1849721 PM  php-cgi.exe 5020    WriteFile   E:\Inetpub_IIS\tmp\php3F86.tmp  SUCCESS Offset: 383,925, Length: 5,119
2:43:17.1851664 PM  php-cgi.exe 5020    WriteFile   E:\Inetpub_IIS\tmp\php3F86.tmp  SUCCESS Offset: 389,044, Length: 2,343
2:43:17.1852283 PM  php-cgi.exe 5020    CloseFile   E:\Inetpub_IIS\tmp\php3F86.tmp  SUCCESS 
2:43:17.5070914 PM  php-cgi.exe 5020    QueryDirectory  E:\Inetpub_IIS\tmp\php3F86.tmp  SUCCESS Filter: php3F86.tmp, 1: php3F86.tmp
2:43:17.5083973 PM  php-cgi.exe 5020    QueryDirectory  E:\Inetpub_IIS\tmp\php3F86.tmp  SUCCESS Filter: php3F86.tmp, 1: php3F86.tmp
2:43:17.5112593 PM  php-cgi.exe 5020    QueryDirectory  E:\Inetpub_IIS\tmp\php3F86.tmp  SUCCESS Filter: php3F86.tmp, 1: php3F86.tmp
2:43:17.5120519 PM  php-cgi.exe 5020    QueryDirectory  E:\Inetpub_IIS\tmp\php3F86.tmp  SUCCESS Filter: php3F86.tmp, 1: php3F86.tmp
2:43:27.5512956 PM  php-cgi.exe 5020    CreateFile  E:\Inetpub_IIS\tmp\php3F86.tmp  SUCCESS Desired Access: Read Attributes, Delete, Disposition: Open, Options: Non-Directory File, Open Reparse Point, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a, OpenResult: Opened
2:43:27.5515084 PM  php-cgi.exe 5020    QueryAttributeTagFile   E:\Inetpub_IIS\tmp\php3F86.tmp  SUCCESS Attributes: A, ReparseTag: 0x0
2:43:27.5515406 PM  php-cgi.exe 5020    SetDispositionInformationFile   E:\Inetpub_IIS\tmp\php3F86.tmp  SUCCESS Delete: True
2:43:27.5515879 PM  php-cgi.exe 5020    CloseFile   E:\Inetpub_IIS\tmp\php3F86.tmp  SUCCESS 

As you can see, ProcMon clearly shows the temporary file being created, written and then closed. Near the end you can see the "QueryDirectory" calls, which coincide with my script calls, which attempt to get the SHA1 hash of the file amongst other things.

This is my script:

The file upload form has a Flash object and some DIVs for the Flash object to build the form, nothing more. The temporary upload file is being created on the server in its entirety so I doubt very seriously that my form is the problem.

<?php
// *******************************************************************
// exhibit-upload.php
// 
// *******************************************************************

// Reset same session ID because Adobe Flash is a flaming pile
session_id($_POST['sessionid']);

ob_start("ob_gzhandler");
require_once('inc-common.php');

$logFile = "logfile.txt";
$logHandle = fopen($logFile, 'w');

fwrite($logHandle, '$_FILES error: ' . $_FILES['error'] . "\n");

if(!empty($_FILES))
{
    // Get temp file
    $sFileTemp = $_FILES['Filedata']['tmp_name'];
    $sFileName = $objMySQL->sanitize($_FILES['Filedata']['name']);

    fwrite($logHandle, "Permanent Filename: " . $sFileName . "\n");

    $aFileBits = explode('.', $_FILES['Filedata']['name']);
    $sFileExt = $aFileBits[count($aFileBits) - 1];

    // Get SHA1 hash
    $sFileHash = sha1_file($sFileTemp);

    fwrite($logHandle, "Temp File Exists: " . file_exists($sFileTemp) . "\n");
    fwrite($logHandle, "Temp File Name: " . $sFileTemp . "\n");
    fwrite($logHandle, "File Hash: " . $sFileHash . "\n");
    sleep(10);
    exit();
}
?>

The contents of "logfile.txt":

$_FILES error: 
Permanent Filename: picture.jpg
Temp File Exists: 
Temp File Name: E:\Inetpub_IIS\tmp\php3F86.tmp
File Hash: 

The "sleep" call exists to give me time to check the temporary directory for the file before it disappears.

Dozens of Google searches have led me to things concerning permissions, or to solutions that involve broken upload forms that fail to upload anything at all. The files are being created on the server so obviously the form works. Also, I have tried giving IUSR, IIS_ISURS and DefaultAppPool full access to the temporary directory and all of E:\Inetpub_IIS to see if this had something to do with the associated permissions but that did not change anything. Can anyone offer some advice on what is going on here?

EDIT: I figured it out.

DaveRandom and I both thought that it was a permissions problem of some type, which was true. However we were both thinking of Windows permissions, when the problem was actually a PHP permission / configuration issue. Dave's "work backwards" phrasing got me thinking of moving backwards through the directory tree and testing permissions which eventually produced the following solution.

What I did:

I wrote a very short script:

<?php
    //phpinfo();
    echo "Readable: " . is_readable('E:\Inetpub_IIS\tmp');
?>

This returned FALSE. Apparently the directory wasn't readable, as Dave suggested.

I tried the E:\Inetpub_IIS\wwwroot directory, which returned TRUE. Hmm. I then realized I'd neglected to check the php_error.log all day. Here is what I found:

[27-Dec-2011 16:51:43] PHP Warning:  is_readable(): open_basedir restriction in effect. File(E:\Inetpub_IIS\tmp) is not within the allowed path(s): (E:\Inetpub_IIS\wwwroot) in E:\Inetpub_IIS\wwwroot\ipl\info.php on line 3

I Googled "open_basedir restriction in effect" and had my answer. In the php.ini file, open_basedir was set to:

open_basedir = E:\Inetpub_IIS\wwwroot

I changed this to:

open_basedir = "E:\Inetpub_IIS\wwwroot;E:\Inetpub_IIS\tmp"

After restarting the server the app began working as intended.

Hopefully that is enough documentation for someone else who might be having the same problem.

Moral(s) of the story:

  • Check your open_basedir setting.
  • Enable, set and remember to check your php error log.
  • Don't stare at the same problem for 7 hours straight without a break. I think I almost had a stroke.
like image 489
TPC Avatar asked Dec 27 '11 21:12

TPC


1 Answers

As promised, here is my answer. This was copy/pasted from the OP edit.

I figured it out.

DaveRandom and I both thought that it was a permissions problem of some type, which was true. However we were both thinking of Windows permissions, when the problem was actually a PHP permission / configuration issue. Dave's "work backwards" phrasing got me thinking of moving backwards through the directory tree and testing permissions which eventually produced the following solution.

What I did:

I wrote a very short script:

<?php
    //phpinfo();
    echo "Readable: " . is_readable('E:\Inetpub_IIS\tmp');
?>

This returned FALSE. Apparently the directory wasn't readable, as Dave suggested.

I tried the E:\Inetpub_IIS\wwwroot directory, which returned TRUE. Hmm. I then realized I'd neglected to check the php_error.log all day. Here is what I found:

[27-Dec-2011 16:51:43] PHP Warning:  is_readable(): open_basedir restriction in effect. File(E:\Inetpub_IIS\tmp) is not within the allowed path(s): (E:\Inetpub_IIS\wwwroot) in E:\Inetpub_IIS\wwwroot\ipl\info.php on line 3

I Googled "open_basedir restriction in effect" and had my answer. In the php.ini file, open_basedir was set to:

open_basedir = E:\Inetpub_IIS\wwwroot

I changed this to:

open_basedir = "E:\Inetpub_IIS\wwwroot;E:\Inetpub_IIS\tmp"

After restarting the server the app began working as intended.

Hopefully that is enough documentation for someone else who might be having the same problem.

Moral(s) of the story:

  • Check your open_basedir setting.
  • Enable, set and remember to check your php error log.
  • Don't stare at the same problem for 7 hours straight. I think I almost had a stroke.
like image 118
TPC Avatar answered Nov 11 '22 23:11

TPC