我有一个脚本,我使用php artisan(使用 root 用户)运行,有时它会导致在apache www-data 之前创建每日日志文件用户做 - 这意味着当真实用户使用我的Web应用程序时,我收到文件夹权限错误:
无法打开流:权限被拒绝
我每次都会将权限更改回 www-data ,但我想通过始终使用正确的权限创建日志文件来解决此问题。
我考虑创建一个创建文件或触摸它的cron作业,以确保它每天都有正确的权限,但我正在寻找一个不依赖于其他脚本的更好的解决方案。
我们还考虑将php artisan包装在另一个脚本中,以确保它始终使用 www-data 凭据运行,但我们想要做的事情实际上是 root < / strong>不允许apache执行的程序。
还有其他建议吗?
答案 0 :(得分:61)
对于Laravel 5.1,我在bootstrap/app.php
的底部使用以下内容(如the docs中所述):
/**
* Configure Monolog.
*/
$app->configureMonologUsing(function(Monolog\Logger $monolog) {
$filename = storage_path('logs/laravel-'.php_sapi_name().'.log');
$handler = new Monolog\Handler\RotatingFileHandler($filename);
$monolog->pushHandler($handler);
});
当然,您可以使用许多其他处理程序。
答案 1 :(得分:55)
让我们从常量开始。
您有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-data 用户要创建错误日志,则会产生: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');
如果您的班级名称为ArtisanRunner
,那么您的日志文件将为:
storage/logs/laravel-ArtisanRunner-2015-4-27.log
。
结论:解决方案编号1更好,因为它按用户描述了您的日志,因此不会发生错误。
编辑:正如杰森指出的,get_current_user()
返回脚本的所有者名称。因此,要解决方案1,请将您的工匠类文件chown
应用到所需的用户名。
答案 2 :(得分:41)
Laravel 5.6.10及更高版本支持permission
和config/logging.php
驱动程序的配置(single
)中的daily
元素:
'daily' => [
'driver' => 'daily',
'path' => storage_path('logs/laravel.log'),
'level' => 'debug',
'days' => 7,
'permission' => 0664,
],
无需在引导程序脚本中使用Monolog。
具体而言,在https://github.com/laravel/framework/commit/4d31633dca9594c9121afbbaa0190210de28fed8中添加了支持。
答案 3 :(得分:19)
出于此目的,您应该在文件和目录上使用高级ACL。 setfacl
将是您的答案。如果您想授予 www-data 用户权限以在特定目录中的 root 文件上书写,您可以这样做:
setfacl -d -m default:www-data:you-chosen-group:rwx /my/folder
发布此内容后,您无需为rwx
中的所有文件设置/my/folder/
对 www-data 用户的权限,无论是谁创建了这些文件。请参阅this和this question以获取参考。另外,您可以查看docs for setfacl
。
如果有帮助,请告诉我。
答案 4 :(得分:9)
我在 Laravel 5.6
上遇到了同样的问题在config/logging.php
我刚刚更新了每日频道的路径值,其中包含php_sapi_name()
。
这会为不同的php_sapi_name创建单独的durectory,并将带有时间戳的日志文件放入其特定目录中。
'daily' => [
'driver' => 'daily',
'path' => storage_path('logs/' . php_sapi_name() . '/laravel.log'),
'level' => 'debug',
'days' => 7,
]
所以对我来说,
fpm-fcgi
目录下创建:来自网站的日志owner: www-data
cli
目录下创建:来自artisan命令(cronjob)。 owner: root
有关Laravel 5.6日志记录的更多信息:https://laravel.com/docs/5.6/logging
这是我的config/logging.php
文件:
<?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',
],
],
];
答案 5 :(得分:9)
对我来说,这个问题不仅仅是日志权限......我遇到了与引导程序/缓存和存储文件夹相关的任何问题,其中一个用户将创建文件/文件夹而另一个用户将无法编辑/删除标准644和755权限。
典型情况是:
bootstrap / cache / compiled.php文件由apache用户创建,但在执行composer install命令时由编写者用户无法编辑
创建缓存的apache用户无法使用composer用户清除
梦想是无论哪个用户创建文件/文件夹,其他需要访问的用户都拥有与原始作者完全相同的权限。
<强> TL; DR 强>
以下是它的完成方式。
我们需要创建一个名为laravel的共享用户组,该组由需要访问存储和引导/缓存目录的所有用户组成。 接下来,我们需要确保新创建的文件和文件夹分别具有laravel组和664和775权限。
现有的文件/目录很容易做到这一点,但需要一点魔法来调整默认的文件/文件夹创建规则......
## 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: 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
纯粹出于调试目的,我发现将日志分成两个cli / web +用户是有益的,所以我稍微修改了Sam Wilson的答案。我的用例是队列在它自己的用户下运行,因此它帮助区分使用cli的作曲家用户(例如单元测试)和队列守护进程。
$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);
});
答案 6 :(得分:6)
Laravel 5.1
在我们的案例中,我们想创建日志文件,以便map
组中的所有进程和用户都具有读/写权限 - 因此我们需要具有权限0664的新创建文件。新日志文件的默认值为0644那么这就是我们的解决方案。
我们还添加了一个格式化程序来添加换行符和更易读的日志
deploy
此外,还可以将其与接受的答案结合起来
$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);
});
答案 7 :(得分:4)
将此代码添加到bootstrap/app.php
:
$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);
});
laravel-2018-01-27-cli-raph.log
和laravel-2018-01-27-fpm-cgi-raph.log
,更具可读性。您为记录器have to create a class:
<?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;
}
}
然后,您必须在config/logging.php
:
'channels' => [
'custom' => [
'driver' => 'custom',
'via' => App\Logging\CreateCustomLogger::class,
],
],
与5.5相同的行为:
laravel-2018-01-27-cli-raph.log
和laravel-2018-01-27-fpm-cgi-raph.log
,更具可读性。答案 8 :(得分:4)
将以下内容添加到app/start/artisan.php
文件的开头(这是Laravel 4):
// If effectively root, touch the log file and make sure it belongs to www-data
if (posix_geteuid() === 0) {
$file = storage_path() . '/logs/laravel.log';
touch($file);
chown($file, 'www-data');
chgrp($file, 'www-data');
chmod($file, 0664);
}
如果您提到的每日日志文件不是标准的Laravel日志文件,请调整路径。您也可能不想像我在这里那样更改组或设置权限。以上将组设置为www-data
并设置组写权限。然后我将常规用户添加到www-data
组,以便以常规用户身份运行artisan命令仍然可以写入日志。
相关调整是将以下内容放在app/start/global.php
文件的开头:
umask(0002);
如果你这样做,上面的chmod
行变得毫无意义。将umask设置为此,PHP(以及Laravel)生成的任何新文件都将仅屏蔽其权限,以便“其他”用户不具有写入权限。这意味着目录将以rwxrwxr-x
开头,文件将以rw-rw-r--
开头。因此,如果www-data
正在运行PHP,则默认情况下,该用户的主要组中的任何人www-data
都可写入其创建的任何缓存和日志文件。
答案 9 :(得分:3)
一种非Laravel方法可以简单地将您的cronjob作为www-data执行。
例如https://askubuntu.com/questions/189189/how-to-run-crontab-as-userwww-data
/etc/crontab
*/5 * * * * www-data php /var/www/public/voto_m/artisan top >/dev/null 2>&1
&#13;
答案 10 :(得分:2)
Laravel 5.4
\Log::getMonolog()->popHandler();
\Log::useDailyFiles(storage_path('/logs/laravel-').get_current_user().'.log');
在boot
AppServiceProvider
功能
答案 11 :(得分:2)
(Laravel 5.6)我最近遇到了同样的问题,我只是设置了计划的命令以在/app/Console/Kernel.php
中运行。
$schedule->exec('chown -R www-data:www-data /var/www/**********/storage/logs')->everyMinute();
我知道这有点矫kill过正,但是它就像一种魅力,从那以后没有任何问题。
答案 12 :(得分:0)
Laravel 5.8允许您在config/logging.php
中设置日志名称。
因此,使用以前的答案和注释,如果要使用实际的posix用户名和php_sapi_name()
值来命名日志,则只需更改设置的日志名。使用每日驱动程序可以按用户/ API组合运行日志轮换,这将确保始终由可以修改日志的帐户轮换日志。
我还添加了对本地环境中可能不存在的posix函数的检查,在这种情况下,日志名称仅默认为标准。
假设您正在使用默认的日志通道“每日”,则可以按如下方式修改“通道”键:
# 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,
],
...
这将导致日志名称对于每种组合(例如laravel-cli-sfscs-2019-05-15.log
或laravel-apache2handler-apache-2019-05-15.log
)都是唯一的,具体取决于您的访问点。
答案 13 :(得分:0)
您可以在artisan命令中简单地更改日志文件的权限:
$path = storage_path('log/daily.log');
chown($path, get_current_user());
其中get_current_user()将返回当前脚本的用户。
换句话说,即使您将脚本初始化为daily.log
用户,www-data
也将始终以root
作为其所有者。
答案 14 :(得分:0)
此错误的原因:
.env
文件修复:
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
touch .env
创建一个文件并粘贴您的环境变量,然后运行 php artisan key:generate
php artisan cache:clear
php artisan config:clear
composer dump-autoload
php artisan migrate //only if not already migrated
答案 15 :(得分:0)
如果您使用的是Laravel Envoyer,则可以在Linux中使用ACL进行以下修复:
root
权限运行以下脚本:在两个脚本中,您都需要按照以下说明替换变量:
- {{MASTER_PATH}} :虚拟主机目录的路径(例如,包含应用程序的文件夹>)。
- {{WEB_SERVER_USER}} :您的网络服务器使用的用户。
- {{DEPLOYMENT_USER}} :运行您的部署脚本的用户。
#!/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
现在重新部署您的应用程序,它将继续向前发展。
注意: 1。中定义的脚本应在每次将新项目添加到计算机时运行。
答案 16 :(得分:0)
cd /path/to/project
chown -R www-data:root .
chmod -R g+s .
答案 17 :(得分:-1)
我发现最好的方法是fideloper建议,http://fideloper.com/laravel-log-file-name,您可以设置laravel日志配置而无需触摸Log类。 我认为,控制台程序和Http程序的不同名称是最佳解决方案。