Laravel 4 使用错误权限创建的Laravel每日日志

Laravel 4 使用错误权限创建的Laravel每日日志,laravel-4,file-permissions,Laravel 4,File Permissions,我有一个使用php artisan(使用root用户)运行的脚本,有时它会导致在apachewww data用户创建日志文件之前创建日志文件,这意味着当真实用户使用我的web应用程序时,我会收到文件夹权限错误: 无法打开流:权限被拒绝 每次我都会将权限更改回www data,但我希望通过始终使用正确的权限创建日志文件来解决此问题 我考虑过创建一个cron作业来创建文件或触摸它,以确保它每天都有正确的权限,但我正在寻找一个不依赖其他脚本的更好的解决方案 我们还考虑将php artisan封装在另一

我有一个使用php artisan(使用root用户)运行的脚本,有时它会导致在apachewww data用户创建日志文件之前创建日志文件,这意味着当真实用户使用我的web应用程序时,我会收到文件夹权限错误:

无法打开流:权限被拒绝

每次我都会将权限更改回www data,但我希望通过始终使用正确的权限创建日志文件来解决此问题

我考虑过创建一个cron作业来创建文件或触摸它,以确保它每天都有正确的权限,但我正在寻找一个不依赖其他脚本的更好的解决方案

我们还考虑将php artisan封装在另一个脚本中,以确保它始终使用www data凭据运行,但我们要做的一些事情实际上是root过程,apache不应该允许这样做


还有什么建议吗?

app/start/artisan.php
文件的开头添加如下内容(这是Laravel 4):

如果您提到的每日日志文件不是标准的Laravel日志文件,请调整路径。您也可能不想像我在这里所做的那样更改组或设置权限。上面将组设置为
www-data
,并设置组写入权限。然后,我将常规用户添加到
www-data
组中,这样,作为常规用户运行artisan命令仍然可以写入日志

一个相关的调整是将以下内容放在
app/start/global.php
文件的开头:

umask(0002);
<?php

return [
    /*
    |--------------------------------------------------------------------------
    | Default Log Channel
    |--------------------------------------------------------------------------
    |
    | This option defines the default log channel that gets used when writing
    | messages to the logs. The name specified in this option should match
    | one of the channels defined in the "channels" configuration array.
    |
    */
    'default' => env('LOG_CHANNEL', 'stack'),
    /*
    |--------------------------------------------------------------------------
    | Log Channels
    |--------------------------------------------------------------------------
    |
    | Here you may configure the log channels for your application. Out of
    | the box, Laravel uses the Monolog PHP logging library. This gives
    | you a variety of powerful log handlers / formatters to utilize.
    |
    | Available Drivers: "single", "daily", "slack", "syslog",
    |                    "errorlog", "custom", "stack"
    |
    */
    'channels' => [
        'stack' => [
            'driver' => 'stack',
            'channels' => ['daily'],
        ],
        'single' => [
            'driver' => 'single',
            'path' => storage_path('logs/laravel.log'),
            'level' => 'debug',
        ],
        'daily' => [
            'driver' => 'daily',
            'path' => storage_path('logs/' . php_sapi_name() . '/laravel.log'),
            'level' => 'debug',
            'days' => 7,
        ],
        'slack' => [
            'driver' => 'slack',
            'url' => env('LOG_SLACK_WEBHOOK_URL'),
            'username' => 'Laravel Log',
            'level' => 'critical',
        ],
        'syslog' => [
            'driver' => 'syslog',
            'level' => 'debug',
        ],
        'errorlog' => [
            'driver' => 'errorlog',
            'level' => 'debug',
        ],
    ],
];

如果您这样做,上面的
chmod
行将变得没有意义。将umask设置为该值时,PHP(以及Laravel)生成的任何新文件都将被屏蔽权限,这样“其他”用户就不会有写权限。这意味着目录将以
rwxrwxr-x
开头,文件以
rw-rw-r--
开头。因此,如果
www-data
正在运行PHP,它生成的任何缓存和日志文件默认情况下都可以由该用户的主组(即
www-data

中的任何人写入。为此,您应该在文件和目录上使用高级ACL
setfacl
将是您的答案。如果您想授予www data用户权限,以便在特定目录下的root的文件上进行写入,您可以这样做:

setfacl -d -m default:www-data:you-chosen-group:rwx /my/folder
发出此命令后,您将为www data用户对
/my/folder/
中所有文件的
rwx
设置权限,无论这些文件是谁创建的。请参阅和以供参考。还有,你可以查一下


让我知道这是否有用。

让我们从常量开始

您有一个
php artisan
命令,由
root
运行

可以安全地假设该命令每天都执行

解决方案1:

假设创建文件的用户在默认情况下具有写入权限,我们可以按用户将日志分开:

App/start/global.php

/*
|--------------------------------------------------------------------------
| Application Error Logger
|--------------------------------------------------------------------------
|
| Here we will configure the error logger setup for the application which
| is built on top of the wonderful Monolog library. By default we will
| build a basic log file setup which creates a single file for logs.
|
*/

Log::useDailyFiles(storage_path().'/logs/laravel-'.get_current_user().'.log');
如果您的www数据用户创建错误日志,则会导致:
storage/logs/laravel-www-data-2015-4-27.log

如果root用户要创建错误日志,则会导致:
storage/logs/laravel-root-2015-4-27.log

解决方案2:

在php脚本中更改artisan命令使用的日志

run()
函数中,在开头添加此行:

Log::useFiles(storage_path().'/logs/laravel-'.__CLASS__.'-'.Carbon::now()->format('Y-m-d').'.log');
如果类的名称为
ArtisRunner
,则日志文件将为:

存储/logs/laravel-ArtisanRunner-2015-4-27.log

结论:解决方案1更好,因为它按用户描述日志,因此不会发生错误


编辑:正如jason指出的,
get\u current\u user()
返回脚本的所有者名称。因此,要应用解决方案1,
chown
将artisan类文件设置为所需的用户名。

对于Laravel 5.1,我在
bootstrap/app.php
的底部使用以下内容(如中所述):


当然,还有很多其他的处理程序可以使用。

Laravel 5.1

在本例中,我们希望创建所有日志文件,以便
deploy
组中的所有内容都具有读/写权限。因此,我们需要创建具有
0664
权限的所有新文件,而不是
0644
默认权限

我们还添加了一个格式化程序来添加换行符以提高可读性:

$app->configureMonologUsing(function(Monolog\Logger $monolog) {
    $filename = storage_path('/logs/laravel.log');
    $handler = new Monolog\Handler\RotatingFileHandler($filename, 0, \Monolog\Logger::DEBUG, true, 0664);
    $handler->setFormatter(new \Monolog\Formatter\LineFormatter(null, null, true, true));
    $monolog->pushHandler($handler);
});
也可以将此与公认的答案结合起来

$app->configureMonologUsing(function(Monolog\Logger $monolog) {
    $filename = storage_path('/logs/laravel-' . php_sapi_name() . '.log');
    $handler = new Monolog\Handler\RotatingFileHandler($filename, 0, \Monolog\Logger::DEBUG, true, 0664);
    $handler->setFormatter(new \Monolog\Formatter\LineFormatter(null, null, true, true));
    $monolog->pushHandler($handler);
});

对我来说,这个问题不仅仅是日志权限……我遇到了与引导/缓存和存储文件夹相关的任何问题,其中一个用户将创建一个文件/文件夹,而另一个用户由于标准644和755权限而无法编辑/删除

典型情况如下:

  • 由apache用户创建的bootstrap/cache/compiled.php文件,但在执行composer安装命令时,composer用户不可编辑该文件

  • apache用户正在创建无法使用composer用户清除的缓存

  • 上述可怕的日志竞争条件
我们的梦想是,无论哪个用户创建文件/文件夹,需要访问的其他用户都拥有与原始作者完全相同的权限

TL;DR?

这是怎么做到的

我们需要创建一个名为laravel的共享用户组,该组由需要访问存储和引导/缓存目录的所有用户组成。 接下来,我们需要确保新创建的文件和文件夹分别具有laravel组和664和775权限

对现有文件/目录执行此操作很容易,但需要一点魔力
$app->configureMonologUsing(function(Monolog\Logger $monolog) {
    $filename = storage_path('/logs/laravel-' . php_sapi_name() . '.log');
    $handler = new Monolog\Handler\RotatingFileHandler($filename, 0, \Monolog\Logger::DEBUG, true, 0664);
    $handler->setFormatter(new \Monolog\Formatter\LineFormatter(null, null, true, true));
    $monolog->pushHandler($handler);
});
## create user group
sudo groupadd laravel

## add composer user to group
sudo gpasswd -a composer-user laravel

## add web server to group
sudo gpasswd -a apache laravel

## jump to laravel path
sudo cd /path/to/your/beautiful/laravel-application

## optional: temporary disable any daemons that may read/write files/folders
## For example Apache & Queues

## optional: if you've been playing around with permissions
## consider resetting all files and directories to the default
sudo find ./ -type d -exec chmod 755 {} \;
sudo find ./ -type f -exec chmod 644 {} \;

## give users part of the laravel group the standard RW and RWX
## permissions for the existing files and folders respectively
sudo chown -R :laravel ./storage
sudo chown -R :laravel ./bootstrap/cache
sudo find ./storage -type d -exec chmod 775 {} \;
sudo find ./bootstrap/cache -type d -exec chmod 775 {} \;
sudo find ./storage -type f -exec chmod 664 {} \;
sudo find ./bootstrap/cache -type f -exec chmod 664 {} \;


## give the newly created files/directories the group of the parent directory 
## e.g. the laravel group
sudo find ./bootstrap/cache -type d -exec chmod g+s {} \;
sudo find ./storage -type d -exec chmod g+s {} \;

## let newly created files/directories inherit the default owner 
## permissions up to maximum permission of rwx e.g. new files get 664, 
## folders get 775
sudo setfacl -R -d -m g::rwx ./storage
sudo setfacl -R -d -m g::rwx ./bootstrap/cache

## Reboot so group file permissions refresh (required on Debian and Centos)
sudo shutdown now -r

## optional: enable any daemons we disabled like Apache & Queues
$app->configureMonologUsing(function(MonologLogger $monolog) {
     $processUser = posix_getpwuid(posix_geteuid());
     $processName= $processUser['name'];

     $filename = storage_path('logs/laravel-'.php_sapi_name().'-'.$processName.'.log');
     $handler = new MonologHandlerRotatingFileHandler($filename);
     $monolog->pushHandler($handler);
}); 
$app->configureMonologUsing(function (Monolog\Logger $monolog) {
    $filename = storage_path('logs/' . php_sapi_name() . '-' . posix_getpwuid(posix_geteuid())['name'] . '.log');
    $monolog->pushHandler($handler = new Monolog\Handler\RotatingFileHandler($filename, 30));
    $handler->setFilenameFormat('laravel-{date}-{filename}', 'Y-m-d');
    $formatter = new \Monolog\Formatter\LineFormatter(null, null, true, true);
    $formatter->includeStacktraces();
    $handler->setFormatter($formatter);
});
<?php

namespace App;

use Monolog\Logger as MonologLogger;

class Logger {
    public function __invoke(array $config)
    {
        $monolog = new MonologLogger('my-logger');
        $filename = storage_path('logs/' . php_sapi_name() . '-' . posix_getpwuid(posix_geteuid())['name'] . '.log');
        $monolog->pushHandler($handler = new \Monolog\Handler\RotatingFileHandler($filename, 30));
        $handler->setFilenameFormat('laravel-{date}-{filename}', 'Y-m-d');
        $formatter = new \Monolog\Formatter\LineFormatter(null, null, true, true);
        $formatter->includeStacktraces();
        $handler->setFormatter($formatter);
        return $monolog;
    }
}
'channels' => [
    'custom' => [
        'driver' => 'custom',
        'via' => App\Logging\CreateCustomLogger::class,
    ],
],
'daily' => [
            'driver' => 'daily',
            'path' => storage_path('logs/' . php_sapi_name() . '/laravel.log'),
            'level' => 'debug',
            'days' => 7,
        ]
<?php

return [
    /*
    |--------------------------------------------------------------------------
    | Default Log Channel
    |--------------------------------------------------------------------------
    |
    | This option defines the default log channel that gets used when writing
    | messages to the logs. The name specified in this option should match
    | one of the channels defined in the "channels" configuration array.
    |
    */
    'default' => env('LOG_CHANNEL', 'stack'),
    /*
    |--------------------------------------------------------------------------
    | Log Channels
    |--------------------------------------------------------------------------
    |
    | Here you may configure the log channels for your application. Out of
    | the box, Laravel uses the Monolog PHP logging library. This gives
    | you a variety of powerful log handlers / formatters to utilize.
    |
    | Available Drivers: "single", "daily", "slack", "syslog",
    |                    "errorlog", "custom", "stack"
    |
    */
    'channels' => [
        'stack' => [
            'driver' => 'stack',
            'channels' => ['daily'],
        ],
        'single' => [
            'driver' => 'single',
            'path' => storage_path('logs/laravel.log'),
            'level' => 'debug',
        ],
        'daily' => [
            'driver' => 'daily',
            'path' => storage_path('logs/' . php_sapi_name() . '/laravel.log'),
            'level' => 'debug',
            'days' => 7,
        ],
        'slack' => [
            'driver' => 'slack',
            'url' => env('LOG_SLACK_WEBHOOK_URL'),
            'username' => 'Laravel Log',
            'level' => 'critical',
        ],
        'syslog' => [
            'driver' => 'syslog',
            'level' => 'debug',
        ],
        'errorlog' => [
            'driver' => 'errorlog',
            'level' => 'debug',
        ],
    ],
];
    'daily' => [
        'driver' => 'daily',
        'path' => storage_path('logs/laravel.log'),
        'level' => 'debug',
        'days' => 7,
        'permission' => 0664,
    ],
# config/logging.php
'channels' => [
    ...
    'daily' => [
        'driver' => 'daily',
        'path'   => storage_path(
            function_exists('posix_getpwuid') 
            && function_exists('posix_geteuid')
                ? 'logs/laravel'
                    . '-' . php_sapi_name()
                    . '-' . posix_getpwuid(posix_geteuid())['name'] 
                    . '.log'
                : 'logs/laravel.log'),
        'level'  => 'debug',
        'days'   => 15,
    ],
    ...
$path = storage_path('log/daily.log');
chown($path, get_current_user());
find /path/to/your/root/dir/ -type f -exec chmod 644 {} \;
find /path/to/your/root/dir/ -type d -exec chmod 755 {} \;

chown -R www-data:www-data /path/to/your/root/dir/

chgrp -R www-data storage bootstrap/cache
chmod -R ug+rwx storage bootstrap/cache
   php artisan key:generate
   php artisan cache:clear
   php artisan config:clear
   composer dump-autoload
   php artisan migrate //only if not already migrated
#!/bin/bash

DIRS="storage current/bootstrap/cache"
MASTER_PATH={{MASTER_PATH}}

if [ -d $MASTER_PATH ]; then 
    cd $MASTER_PATH
    for p in `ls $MASTER_PATH`; do 
        if [ -d $MASTER_PATH/$p ]; then     
        cd $MASTER_PATH/$p
            echo "Project: $p -> $MASTER_PATH/$p"
            for i in $DIRS; do 
                echo "- directory: $i" 
                if [ -d $i ]; then 
                    echo "-- checking ACL..."
                    HAS_ACL=`getfacl -p $i | grep "^user:{{WEB_SERVER_USER}}:.*w" | wc -l`
                    if [  $HAS_ACL -eq 0 ]; then 
                        echo "--- applying $i"
                        setfacl -L -R -m u:{{WEB_SERVER_USER}}:rwX -m u:{{DEPLOYMENT_USER}}:rwX $i
                        setfacl -dL -R -m u:{{WEB_SERVER_USER}}:rwX -m u:{{DEPLOYMENT_USER}}:rwX $i
                    else
                        echo "--- skipping $i"
                    fi
                fi
            done
        echo "--------------"
        fi
    done
else
    echo "No $MASTER_PATH - skipping overall"
fi
PROJECT_DIRS="storage"
RELEASE_DIRS="bootstrap/cache"
 
cd {{ project }}
 
for i in $PROJECT_DIRS; do
  if [ -d $i ]; then
    HAS_ACL=`getfacl -p $i | grep "^user:{{WEB_SERVER_USER}}:.*w" | wc -l`
    if [  $HAS_ACL -eq 0 ]; then
      echo "ACL set for directory {{project}}/$i"
      setfacl -L -R -m u:{{WEB_SERVER_USER}}:rwX -m u:{{DEPLOYMENT_USER}}:rwX $i
      setfacl -dL -R -m u:{{WEB_SERVER_USER}}:rwX -m u:{{DEPLOYMENT_USER}}:rwX $i
    fi
  fi
done
 
cd {{ release }}
 
for i in $RELEASE_DIRS; do
  if [ -d $i ]; then
    HAS_ACL=`getfacl -p $i | grep "^user:{{WEB_SERVER_USER}}:.*w" | wc -l`
    if [  $HAS_ACL -eq 0 ]; then
      echo "ACL set for directory {{project}}/$i"
      setfacl -L -R -m u:{{WEB_SERVER_USER}}:rwX -m u:{{DEPLOYMENT_USER}}:rwX $i
      setfacl -dL -R -m u:{{WEB_SERVER_USER}}:rwX -m u:{{DEPLOYMENT_USER}}:rwX $i
    fi
  fi
done
cd /path/to/project
chown -R www-data:root .
chmod -R g+s .