php pdo 无内置查询日志,推荐应用层拦截记录sql(含绑定参数);开发可用调试模式拼接日志,生产应慢查/错误查+参数脱敏+异步写入;亦可临时启用mysql general_log。

PHP PDO 本身不直接提供查询日志功能,但可通过启用 PDO::ATTR_EMULATE_PREPARES 配合调试模式、SQL 日志中间层或数据库服务端日志来实现。最实用且可控的方式是**在应用层拦截并记录所有执行的 SQL(含绑定参数)**,兼顾可读性与生产安全性。
启用 PDO 调试模式 + 手动拼接日志
适用于开发/测试环境快速定位问题,不推荐直接用于生产(因性能开销和敏感数据风险):
- 设置
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION确保异常可捕获 - 对每个
$stmt->execute($params)前,用str_replace或正则将占位符替换成实际值(注意转义与类型判断) - 示例逻辑:不要直接拼接字符串防注入,仅用于日志;真实执行仍走预处理
封装 PDO 类统一记录 SQL 日志
推荐方案:继承或包装 PDO,重写 prepare() 和 execute(),在执行前后记录完整语句与耗时:
- 在
prepare()中保存原始 SQL - 在
execute()中获取绑定参数,调用自定义方法格式化为可读 SQL(如WHERE id = ?→WHERE id = 123) - 使用
microtime(true)计算执行耗时,写入文件或 PSR-3 兼容日志器(如 Monolog)
利用 MySQL 的 general_log(仅限开发/临时排查)
数据库服务端级记录,无需改 PHP 代码,但影响性能且包含所有连接请求(含系统账号操作):
立即学习“PHP免费学习笔记(深入)”;
- 动态开启:
SET GLOBAL general_log = 'ON'; SET GLOBAL general_log_file = '/tmp/mysql-general.log'; - 日志内容含时间、连接 ID、SQL 语句,但不展开参数,? 占位符原样保留
- 需确保 MySQL 用户有
SUPER权限,且磁盘空间充足
生产环境安全日志建议
避免记录密码、token、身份证等敏感字段,同时降低性能损耗:
- 只记录慢查询(如 >100ms)或错误查询,通过
microtime判断阈值 - 对参数值做脱敏:字符串截断(如
substr($val, 0, 32))、正则替换(如手机号 →138****1234) - 异步写日志:用
file_put_contents(..., FILE_APPEND | LOCK_EX)或消息队列暂存,避免阻塞主流程











