建立ODBC连接后PHP is_readable返回false问题求助
运行环境:Windows Server 2012 + IIS + PHP 5.4.45
两段仅调整odbc_connect与is_readable调用顺序的代码出现完全相反的执行结果:
代码1(先检测文件再连ODBC)
<?php echo get_current_user(); $file_path = "templates\index.tpl"; $test = getcwd() . "\\" . $file_path; echo $test."\r\n"; if(is_readable($test)) { echo ("Readable!\r\n"); } else { echo ("Not readable!\r\n"); } odbc_connect("kontaktdb", null, null); ?>
执行结果:返回Readable!
代码2(先连ODBC再检测文件)
<?php echo get_current_user(); $file_path = "templates\index.tpl"; $test = getcwd() . "\\" . $file_path; echo $test."\r\n"; odbc_connect("kontaktdb", null, null); if(is_readable($test)) { echo ("Readable!\r\n"); } else { echo ("Not readable!\r\n"); } ?>
执行结果:返回Not readable!
原因分析
在Windows IIS环境下,PHP默认以应用池身份运行。当调用odbc_connect使用Windows集成身份验证连接数据源时,会触发身份模拟切换——PHP进程的权限上下文会切换到ODBC数据源对应的身份(比如SQL Server服务账户或域账户),导致后续文件访问的权限与之前不一致,原本能读取的文件因新身份无权限而返回false。
解决方案
提前缓存文件可读状态
在建立ODBC连接前先执行is_readable并缓存结果,后续直接使用缓存值:<?php echo get_current_user(); $file_path = "templates\index.tpl"; $test = getcwd() . "\\" . $file_path; echo $test."\r\n"; // 提前检测并存储结果 $fileIsReadable = is_readable($test); odbc_connect("kontaktdb", null, null); if($fileIsReadable) { echo ("Readable!\r\n"); } else { echo ("Not readable!\r\n"); } ?>修改ODBC数据源的身份验证方式
将kontaktdb数据源的身份验证从Windows集成身份改为SQL Server身份验证(指定独立的用户名和密码),避免连接时触发身份切换,保持PHP进程的原权限上下文。给切换后的身份添加文件读取权限
找到ODBC连接切换到的目标身份(可通过get_current_user()在连接后输出确认),给templates目录及tpl文件添加该身份的读取权限,确保切换后仍能访问文件。调整PHP ODBC配置
检查php.ini中的odbc.allow_persistent、odbc.default_user等配置项,或在odbc_connect调用时显式指定身份参数,强制保持原运行身份,避免自动模拟切换。
内容的提问来源于stack exchange,提问作者H3GE

