Подтвердить что ты не робот

Ежедневный журнал Laravel, созданный с неправильными разрешениями

У меня есть script, который я запускаю с помощью php-artisan (с root), и иногда он заставляет ежедневный файл журнала создаваться до apache www-data user does - что означает, что когда реальный пользователь использует мое веб-приложение, я получаю ошибку разрешения папки:

Не удалось открыть поток: Permission denied

Я каждый раз меняю разрешения на www-data​​strong > , но я хочу решить это, всегда создавая файл журнала с правильными разрешениями.

Я подумал о создании задания cron, которое создает файл или касается его, чтобы каждый день иметь правильное разрешение, но я ищу лучшее решение, которое не зависит от другого script.

Мы также рассмотрели возможность переноса php-artisan в другой script, чтобы убедиться, что он всегда запускается с учетными данными www-data​​strong > , но что-то, что мы хотим сделать, на самом деле root, которые нельзя разрешить apache.

Другие предложения?

4b9b3361

Ответ 1

Начнем с того, что является постоянным.

У вас есть команда 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:

Измените журнал, используемый вашей командой artisan, в вашем php script.

В вашей функции 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 лучше, учитывая, что он определяет ваши журналы пользователем, и, следовательно, ошибок не будет.

EDIT: Как отметил Джейсон, get_current_user() возвращает имя владельца script. Следовательно, для решения № 1, chown ваши файлы класса Artisan, чтобы указать имя пользователя.

Ответ 2

Для Laravel 5.1 я использую следующее в нижней части bootstrap/app.php (как указано в документах):

/**
 * 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);
});

Есть много других обработчиков, которые вы можете использовать, конечно.

Ответ 3

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.

Ответ 4

Для таких целей вы должны использовать расширенный ACL для ваших файлов и каталогов. setfacl будет вашим ответом здесь. Если вы хотите дать пользователю www-data права на запись в файлы root в определенном каталоге, вы можете сделать это следующим образом:

setfacl -d -m default:www-data:you-chosen-group:rwx /my/folder

После этого вы устанавливаете права доступа к rwx для пользователя www-data для всех файлов в /my/folder/ независимо от того, кто их создал. Пожалуйста, посмотрите этот и этот вопрос для справки. Кроме того, вы можете проверить документы для setfacl.

Позвольте мне знать, если это помогает.

Ответ 5

Для меня эта проблема была намного больше, чем права доступа к журналу... У меня были проблемы со всем, что связано с папками начальной загрузки/кэша и хранилища, когда один пользователь создавал файл/папку, а другой не мог редактировать/удалять из-за стандартного 644 и 755 разрешений.

Типичные сценарии:

  • Файл bootstrap/cache/compiled.php, созданный пользователем apache, но недоступный для редактирования пользователем composer при выполнении команды установки composer

  • Пользователь 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: temporary disable any daemons that may read/write files/folders
## For example Apache and 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

Чисто для целей отладки я обнаружил, что разделение журналов на пользователей cli/web + было выгодно, поэтому я слегка изменил ответ Сэма Уилсона. Мой пример использования: очередь запускалась под собственным пользователем, поэтому он помогал различать пользователя-композитора, использующего 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

У меня это работало очень простым способом:

Я столкнулся с той же проблемой на Laravel 5.6

В config/logging.php я только что обновил значение ежедневного пути к каналу с помощью php_sapi_name().

Это создает отдельную директорию для разных php_sapi_name и помещает файл журнала с отметкой времени в их директорию perticular.

'daily' => [
            'driver' => 'daily',
            'path' => storage_path('logs/' . php_sapi_name() . '/laravel.log'),
            'level' => 'debug',
            'days' => 7,
        ]

Так что для меня,

  • Файлы журналов fpm-fcgi каталоге 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',
        ],
    ],
];

Ответ 7

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);
});

Ответ 8

Добавьте в начало своего файла 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

Laravel 5.5

Добавьте этот код в 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 которые более читабельны.
  • Новые строки сохраняются (по умолчанию в Laravel)
  • Работает с Laravel Log Viewer

Ларавел 5.6

Вы должны создать класс для вашего регистратора:

<?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 которые более читабельны.
  • Новые строки сохраняются (по умолчанию в Laravel)
  • Работает с Laravel Log Viewer

Ответ 10

Laravel 5.4

\Log::getMonolog()->popHandler(); \Log::useDailyFiles(storage_path('/logs/laravel-').get_current_user().'.log');

добавить в boot функцию в AppServiceProvider

Ответ 12

(Laravel 5.6) Недавно я столкнулся с той же проблемой, и я просто установил запланированную команду для запуска в /app/Console/Kernel.php.

$schedule->exec('chown -R www-data:www-data/var/www/**********/storage/logs')->everyMinute();

Я знаю, что это немного излишне, но это работает как шарм, и с тех пор не было никаких проблем.

Ответ 13

Ларавел 5.8

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 зависимости от вашей точки доступа.

Ответ 14

Вы можете просто изменить разрешение файла журнала в вашей команде ремесленника:

$path = storage_path('log/daily.log');
chown($path, get_current_user());

где get_current_user() вернет пользователя текущего скрипта.

Другими словами, daily.log всегда будет иметь www-data качестве своего владельца, даже если вы инициализируете скрипт как root пользователь.

Ответ 15

Лучший способ найти, что fideloper предлагает http://fideloper.com/laravel-log-file-name, вы можете настроить конфигурацию журнала laravel без касания класса Log. У меня есть разные имена для консольных программ и программ Http, я думаю, это лучшее решение.