PHP不承认自己上传的临时文件


PHP won't acknowledge its own uploaded temporary files

我有一个真正的头痛。

我的系统配置:

  • Windows Server 2008 R2
  • PHP 5.3.8作为FastCGI模块安装
  • IIS 7.5

这是我的问题:

我有一个简单的文件上传表单。正如我们所知,当PHP接受文件上传时,该文件被赋予一个临时名称,并在处理之前放置在一个临时目录中。在我的例子中,PHP将文件放在临时目录中(恰好是E:'Inetpub_IIS'tmp,在E:'Inetpub_IIS'wwwroot旁边),但随后立即"忘记"该文件存在,直到垃圾收集器出现,它删除临时文件。更具体地说,临时文件是在服务器上的临时目录中创建的,但是当我对该文件调用sha1_file()时,该函数什么也不返回。File_exists()也失败。这让我认为PHP找不到文件。下面的ProcMon日志显示PHP正在寻找正确的位置。

这是我的ProcMon日志:

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 

可以看到,ProcMon清楚地显示正在创建、写入和关闭的临时文件。在接近结尾时,您可以看到"QueryDirectory"调用,它与我的脚本调用一致,它试图获得文件的SHA1哈希值以及其他内容。

这是我的脚本:

文件上传表单有一个Flash对象和一些div用于Flash对象构建表单,仅此而已。临时上传文件是在服务器上创建的,所以我非常怀疑我的表单有问题。

<?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();
}
?>

"logfile.txt"的内容:

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

"sleep"调用的存在是为了让我有时间在文件消失之前检查临时目录。

几十个谷歌搜索导致我的东西有关权限,或解决方案,涉及损坏的上传表单,无法上传任何东西。这些文件是在服务器上创建的,所以显然表单可以工作。此外,我还尝试让IUSR, IIS_ISURS和DefaultAppPool完全访问临时目录和所有E:'Inetpub_IIS,看看这是否与相关权限有关,但这并没有改变任何东西。有谁能就这里发生的事情提供一些建议吗?

编辑:I figure out.

DaveRandom和我都认为这是某种类型的权限问题,这是真的。然而,当问题实际上是PHP权限/配置问题时,我们都在考虑Windows权限。Dave的"向后工作"这句话让我想到向后遍历目录树并测试权限,最终产生了以下解决方案:

我做了什么:

我写了一个很短的脚本:

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

返回FALSE。很显然,这个目录是不可读的,就像Dave建议的那样。

我尝试了E:'Inetpub_IIS'wwwroot目录,它返回TRUE。嗯。然后我意识到我一整天都忽略了检查php_error.log。以下是我的发现:

[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

我搜索了"open_basedir限制生效",并得到了我的答案。在php.ini文件中,open_basedir设置为:

open_basedir = E:'Inetpub_IIS'wwwroot

我把它改成:

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

重新启动服务器后,应用程序开始正常工作。

希望这些文档对其他可能遇到同样问题的人来说足够了。

故事寓意:

    检查open_basedir设置
  • 启用,设置并记得检查php错误日志。
  • 不要连续7个小时盯着同一个问题不休息。我想我差点中风了。

如我所承诺的,以下是我的答案。这是从OP编辑中复制/粘贴的。

我明白了。

DaveRandom和我都认为这是某种类型的权限问题,这是真的。然而,当问题实际上是PHP权限/配置问题时,我们都在考虑Windows权限。Dave的"向后工作"这句话让我想到向后遍历目录树并测试权限,最终产生了以下解决方案:

我做了什么:

我写了一个很短的脚本:

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

返回FALSE。很显然,这个目录是不可读的,就像Dave建议的那样。

我尝试了E:'Inetpub_IIS'wwwroot目录,它返回TRUE。嗯。然后我意识到我一整天都忽略了检查php_error.log。以下是我的发现:

[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

我搜索了"open_basedir限制生效",并得到了我的答案。在php.ini文件中,open_basedir设置为:

open_basedir = E:'Inetpub_IIS'wwwroot

我把它改成:

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

重新启动服务器后,应用程序开始正常工作。

希望这些文档对其他可能遇到同样问题的人来说足够了。

故事寓意:

    检查open_basedir设置
  • 启用,设置并记得检查php错误日志。
  • 不要连续7个小时盯着同一个问题看。我想我差点中风了。