PHP Yii2远程MySQL SSL连接失败:控制台正常Web服务报1045错误
针对你遇到的两种运行环境下的连接差异,以及PDO常量识别的问题,我整理了几个排查和解决方向:
一、先排查控制台与Web服务的核心差异
虽然你说phpInfo()配置一致,但以下细节很容易被忽略:
1. 运行用户与文件权限差异
控制台脚本是以当前登录用户身份执行的,而php yii serve启动的内置Web服务,默认是以PHP进程的运行用户(比如Linux下的www-data、Windows下的系统用户)来执行的。如果你的SSL证书文件(如ca.pem)权限设置为仅当前登录用户可读,Web服务用户就无法读取证书,进而导致SSL连接失败——MySQL有时会把SSL握手失败的错误伪装成"Access denied",这很容易误导排查方向。
解决方法:
- 调整SSL证书文件的权限,让Web服务用户拥有读取权限:
chmod o+r /path/to/your/ca.pem # 或者更安全的方式,将文件所属组改为Web服务用户组 chgrp www-data /path/to/your/ca.pem chmod g+r /path/to/your/ca.pem
2. Yii配置文件的环境差异
Yii2的控制台和Web服务默认加载不同的配置文件:控制台用config/console.php,Web服务用config/web.php。你需要确认两个配置文件中,远程MySQL的连接参数(尤其是SSL相关配置)是否完全一致。
比如控制台配置里可能有:
'components' => [ 'remoteDb' => [ 'class' => 'yii\db\Connection', 'dsn' => 'mysql:host=remote-mysql;dbname=your_db', 'username' => 'userName', 'password' => 'your_pass', 'attributes' => [ // SSL相关配置 PDO::MYSQL_ATTR_SSL_CA => '/path/to/ca.pem', ], ], ],
要确保web.php里的remoteDb配置完全相同,没有遗漏SSL参数。
3. 出口IP差异
如果你的服务器有多个网络接口,控制台和Web服务的出口IP可能不同。远程MySQL的用户权限可能只允许控制台的IP访问,而Web服务的IP不在授权列表里,就会触发"Access denied"错误。
解决方法:
- 查看Web服务的出口IP:在Web脚本中执行
echo $_SERVER['SERVER_ADDR'];或者用curl ifconfig.me获取公网IP。 - 登录远程MySQL,检查用户权限:
如果Web服务的IP不在列表中,添加授权:SELECT host, user FROM mysql.user WHERE user='userName';GRANT ALL ON your_db.* TO 'userName'@'web-service-ip' IDENTIFIED BY 'your_pass' REQUIRE SSL; FLUSH PRIVILEGES;
二、解决PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT常量不存在的问题
你在CLI中能识别该常量,但Web环境中无法识别,大概率是PDO MySQL扩展版本差异或者命名空间干扰导致的。
1. 直接使用常量值替代
既然你已经通过php -r 'var_dump(PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT);'确认常量值为1014,可以直接在配置中用数值代替常量:
'attributes' => [ 1014 => false, // 替代PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT PDO::MYSQL_ATTR_SSL_CA => '/path/to/ca.pem', // 其他SSL参数 ],
2. 验证Web环境的PDO扩展
在Web脚本中添加以下代码,确认PDO MySQL扩展的状态:
var_dump(extension_loaded('pdo_mysql')); var_dump(phpversion('pdo_mysql'));
对比CLI下的输出,如果版本不一致,说明Web环境和CLI使用的是不同的PHP配置,需要调整Web服务器的PHP配置,确保加载的PDO MySQL扩展支持SSL常量。
三、额外调试步骤
如果以上方法都无效,可以用原生PHP代码在Web环境中直接测试连接,排除Yii框架的干扰:
// 用mysqli测试SSL连接 $conn = mysqli_init(); mysqli_ssl_set($conn, NULL, NULL, '/path/to/ca.pem', NULL, NULL); if (!mysqli_real_connect($conn, 'remote-host', 'userName', 'password', 'dbname', 3306, NULL, MYSQLI_CLIENT_SSL)) { die('连接错误: ' . mysqli_connect_error()); } echo '连接成功'; mysqli_close($conn);
如果这段代码在Web环境中也失败,说明问题出在PHP Web环境的SSL配置上,而非Yii框架。
内容的提问来源于stack exchange,提问作者viks1010

