I've got a real head-scratcher here.
This is my system configuration:
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:
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:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With