IIS10.0+PHP7.1 FastCGI导致ThinkPHP出错路径问题

第一次尝试部署IIS+PHP,使用FastCGI,结果服务器上正常,但是开发环境下部署时却出现了问题,报错如下:

1
2
3
4
5
6
7
8
9
PHP Fatal error:  Uncaught think\exception\ErrorException: mkdir(): Invalid argument in F:\Richex\Develop\ileoleo\thinkphp\library\think\log\driver\File.php:61
Stack trace:
#0 [internal function]: think\Error::appError(2, 'mkdir(): Invali...', 'F:\\Richex\\Devel...', 61, Array)
#1 F:\Richex\Develop\ileoleo\thinkphp\library\think\log\driver\File.php(61): mkdir('\\\\runtime\\log\\2...', 493, true)
#2 F:\Richex\Develop\ileoleo\thinkphp\library\think\Log.php(222): think\log\driver\File->save(Array, true)
#3 F:\Richex\Develop\ileoleo\thinkphp\library\think\Error.php(94): think\Log->save()
#4 [internal function]: think\Error::appShutdown()
#5 {main}
thrown in F:\Richex\Develop\ileoleo\thinkphp\library\think\log\driver\File.php on line 61

先附上配置环境,下面是开发环境:

1
2
3
4
Windows 10 专业版 1803
IIS 10.0.17134.1
php-7.1.23-Win32-VC14-x64 ts
ThinkPHP 5.1.28 LTS

服务器环境(别问我为啥不用 Windows Server ~):

1
2
3
Windows 7 旗舰版
IIS 7.5
php和ThinkPHP框架同开发环境

折腾过程不细说了,一开始并不是这个问题,而是网站一直出现500,说FastCGI内部出现异常,从PHP配置到IIS配置全部仔细查了个遍没有结果。最终找到问题是目录权限问题,因为内网不考虑什么安全性,所以一股脑把所有权限全部给 IUSR 和 IIS_IUSRS 两个用户组加上去。

服务器没问题了,接着又是生产环境,报了文章开头所述的错误,这次服务器环境和PHP都没有问题了,而是ThinkPHP框架里面出现了问题。又是一顿排查,最后跟踪到 /thinkphp/library/think/Loader.phpgetRootPath 方法,获取根目录出现了问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 获取应用根目录
public static function getRootPath()
{
if ('cli' == PHP_SAPI) {
$scriptName = realpath($_SERVER['argv'][0]);
} else {
$scriptName = $_SERVER['SCRIPT_FILENAME'];
}

$path = realpath(dirname($scriptName));

if (!is_file($path . DIRECTORY_SEPARATOR . 'think')) {
$path = dirname($path);
}

return $path . DIRECTORY_SEPARATOR;
}

dirname 没有问题,但是经过 realpath 之后,结果变成了 false,也就是说目录不存在?

所以问题基本确定是IIS环境的问题,可能是因为虚拟环境之类的情况,程序运行的上下文路径并不是项目路径?

经过google一顿查找,最终似乎尝试了如下所述的方式:

1
2
3
4
5
After much gnashing of teeth the solution has been found.

The problem described does not occur if the account the website is running under has Read permission for the parent folder. If you have your sites setup under inetpub then this is already in place.

I'm using DotNetPanel and it uses a different folder structure which does not have this permission, however it can easily be added through the DNP file manager, or of course it can be done via console.

地址: https://forums.iis.net/t/1153823.aspx?PHP+realpath+problem

大意是说要将项目所在目录的父级目录页添加对应的权限,似乎就得到了解决。

因为设置权限需要遍历所有子目录和文件,所以在等待期间我找了一下IIS配置当中是不是有相关上下文虚拟环境之类的配置,通过描述看来似乎也很符合导致这个问题的原因,所以改成了 False 。

也就是说父级目录全局和这个配置都进行了改动,之后问题就解决了,所以到底是哪个方法解决了最上面所说的问题就不得而知了。不过刚才我尝试改回了IIS当中的这个模拟用户为 True 之后,网站仍然没有出现这个问题,所以基本上能确定解决方案是前者。