ThinkPHP6 记录日志 Permission denied 的解决方法

最近用ThinkPHP6.0写了一个项目,提交到线上测试时发现后台登录后又被中间件重定向到了登录页面,导致后台无法正常使用,绑定了异常处理接管,打开数据库查看异常日志,发现两处异常:

'file' => 'vendor/topthink/think-log/src/log/driver/File.php',
'line' => 123,
'message' => 'error_log(/201907/09.log): failed to open stream: Permission denied'

'file' => 'vendor/topthink/framework/src/think/Cookie.php',
'line' => 203,
'message' => 'Uncaught think\\exception\\ErrorException: Cannot modify header information - headers already sent by (output started at .......'

查看源码

// vendor/topthink/think-log/src/log/driver/File.php
protected function write(array $message, string $destination): bool
{
  // 检测日志文件大小,超过配置大小则备份日志文件重新生成
  $this->checkLogSize($destination);

  $info = [];

  foreach ($message as $type => $msg) {
  $info[$type] = is_array($msg) ? implode(PHP_EOL, $msg) : $msg;
  }

  $message = implode(PHP_EOL, $info) . PHP_EOL;

  return error_log($message, 3, $destination); // 123
}

//  vendor/topthink/framework/src/think/Cookie.php 
protected function saveCookie(string $name, string $value, int $expire, string $path, string $domain, bool $secure, bool $httponly): void
{
  setcookie($name, $value, $expire, $path, $domain, $secure, $httponly);  // 203
}

应该是error_log没有权限,抛出了异常,导致setcookie失败,果断chomd -R 777 runtime/,刷新重试,依然出现一样的错误。runtime已经777了还报Permission denied,难道日志目录不在runtime,查看日志配置文件

<?php

// +----------------------------------------------------------------------
// | 日志设置
// +----------------------------------------------------------------------
return [
    // 默认日志记录通道
    'default' => 'file',
    // 日志记录级别
    'level' => [],
    // 日志类型记录的通道 ['error'=>'email',...]
    'type_channel' => [],
    // 是否关闭日志写入
    'close' => false,

    // 日志通道列表
    'channels' => [
        'file' => [
            // 日志记录方式
            'type' => 'File',
            // 日志保存目录
            'path' => '',
            // 单文件日志写入
            'single' => false,
            // 独立日志级别
            'apart_level' => [],
            // 最大日志文件数量
            'max_files' => 0,
        ],
        // 其它日志通道配置
    ],
];

path为空,框架应该有默认值啊,然后就一路找到vendor\topthink\think-log\src\log\driver\File.php getMasterLogFile方法

protected function getMasterLogFile(): string
{
    if (substr($this->config['path'], -1) != DIRECTORY_SEPARATOR) {
        $this->config['path'] .= DIRECTORY_SEPARATOR;
    }
    .
    .
    .

卧槽!!! 默认日志保存路径/,然后修改配置文件'path' => app()->getRuntimePath() . '/log',再次刷新重试,运行正常,查看runtime目录,日志已记录进去,然后想到本地windows环境不存在权限问题,打开D盘,果然
ThinkPHP6 写入日志权限报错

文档里日志处理也没有对path参数特别说明,感觉是个坑!

讨论数量: 3
cnguu
  • 从源码去排错, 好评
  • 严格来说,这不算坑,从错误提示就可以大概猜到哪里错了
1个月前 评论

tp的日志处理驱动其实有坑,最大的问题是一旦出现permisson denied 时直接抛出异常,导致所有程序都被终止了,问题出现在生产环境就是致命的

1个月前 评论
lmaster

@Zccc 这个问题应该给 tp 官方说下

1个月前 评论

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!