Journal de bord quotidien de Laravel créé avec de mauvaises permissions
j'ai un script que j'exécute en utilisant php artisan( avec root utilisateur), et parfois il provoque le fichier journal quotidien à être créé avant l'apache www-data utilisateur fait - ce qui signifie que quand un utilisateur réel utilise mon application web, Je reçois le dossier erreur de permission:
N'a pas ouvert le flux: Permission refusée
je modifier les autorisations www-data à chaque fois mais je veux résoudre cela en ayant le fichier log toujours créé avec les permissions correctes.
j'ai envisagé de créer un travail cron qui crée le fichier ou le touche pour s'assurer qu'il a la bonne permission tous les jours, mais je suis à la recherche d'une meilleure solution qui ne repose pas sur un autre script.
nous avons également considéré envelopper php artisan dans un autre script pour s'assurer qu'il est toujours exécuté avec le www-data , mais quelque chose que nous voulons faire sont en fait des procédures root qu'apache ne devrait pas être autorisé à faire.
d'autres suggestions?
13 réponses
commençons par ce qui est constant.
vous avez une commande php artisan
, exécutée par root
.
on peut supposer que cette commande est exécutée quotidiennement.
Solution N ° 1:
étant Donné que l'utilisateur qui crée les fichiers est celui qui a la permission d'écrire par défaut, nous pouvons séparer les logs par l'utilisateur en tant que tel:
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');
si votre www-data utilisateur devait créer un journal des erreurs, il en résulterait: storage/logs/laravel-www-data-2015-4-27.log
.
si votre root utilisateur devait créer un journal des erreurs, il en résulterait: storage/logs/laravel-root-2015-4-27.log
.
Solution N ° 2:
changez le log utilisé par votre commande artisan, dans votre script php.
dans votre fonction run()
, Ajoutez cette ligne au début:
Log::useFiles(storage_path().'/logs/laravel-'.__CLASS__.'-'.Carbon::now()->format('Y-m-d').'.log');
si le nom de votre classe est ArtisanRunner
, alors votre fichier journal sera:
storage/logs/laravel-ArtisanRunner-2015-4-27.log
.
Conclusion: la Solution numéro 1 est meilleure, étant donné qu'elle délimite vos journaux par utilisateur, et donc aucune erreur ne se produira.
EDIT: comme l'a souligné jason, get_current_user()
renvoie le script nom de propriétaire. Par conséquent, pour la solution no.1 pour appliquer, chown
vos fichiers de classe artisan au nom d'utilisateur requis.
pour Laravel 5.1 j'utilise ce qui suit vers le bas de bootstrap/app.php
(comme indiqué dans 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);
});
il y a beaucoup d'autres Handlers que vous pouvez utiliser à la place, bien sûr.
à ces fins, vous devez utiliser advanced ACL sur vos fichiers et répertoires. setfacl
serait votre réponse ici. Si vous voulez donner www-data permissions de l'utilisateur pour écrire sur root fichiers dans le répertoire spécifique, vous pouvez le faire comme ceci:
setfacl -d -m default:www-data:you-chosen-group:rwx /my/folder
après avoir émis ceci vous définissez les permissions à rwx
pour www-data utilisateur sur tous les fichiers dans /my/folder/
peu importe qui créé ceux-ci. Voir cette et cette question pour référence. Aussi, vous pouvez cocher docs pour setfacl
.
dites-moi si ça peut aider.
pour moi ce problème était bien plus que des permissions log...J'ai eu des problèmes avec tout ce qui concerne le bootstrap/cache et les dossiers de stockage où un utilisateur créerait un fichier/dossier et l'autre serait incapable de modifier/supprimer en raison des permissions standard 644 et 755.
les scénarios typiques sont:
-
Le bootstrap/cache/compilé.fichier php créé par l'utilisateur apache mais non éditable par l'utilisateur composer lors de l'exécution de la commande composer install
-
l'utilisateur apache créant un cache qui ne peut pas être effacé en utilisant l'utilisateur composer
- Le redoutable journal de la race des conditions décrites ci-dessus.
le rêve est que peu importe quel utilisateur crée le fichier/dossier, les autres utilisateurs qui ont besoin d'accéder ont exactement les mêmes permissions que l'auteur original.
TL; DR?
voilà comment on fait.
nous avons besoin de créer un groupe d'utilisateurs partagé appelé laravel, le groupe se compose de tous les utilisateurs qui ont besoin d'accéder au stockage et aux répertoires bootstrap/cache. Ensuite, nous devons nous assurer que les fichiers et dossiers nouvellement créés ont les permissions laravel group et 664 et 775 respectivement.
il est facile de faire cela pour les fichiers/répertoires existants, mais un peu de magie est nécessaire pour modifier les règles de création de fichier/dossier par défaut...
## 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
purement à des fins de débogage, j'ai trouvé utile de séparer les logs en cli/web + utilisateurs, donc j'ai légèrement modifié la réponse de Sam Wilson. Mon cas d'utilisation était la file d'attente a couru sous son propre utilisateur de sorte qu'il a aidé à faire la distinction entre l'utilisateur compositeur en utilisant le cli (par exemple des tests unitaires) et le démon de file d'attente.
$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);
});
Laravel 5.1
dans notre cas, nous voulions créer des fichiers journaux pour que tous les processus et les utilisateurs du groupe deploy
aient les permissions de lecture/écriture - nous avions donc besoin de nouveaux fichiers créés avec la permission 0664. Par défaut pour les nouveaux fichiers journaux est 0644. Donc c'était notre solution.
nous avons aussi ajouté un formatteur pour ajouter des nouvelles lignes et un log plus lisible
$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);
});
il est également possible de combiner cela avec la réponse acceptée
$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);
});
Laravel version 5.6.10 et ultérieure a le support pour un permission
élément dans la configuration pour le single
et le daily
pilote:
'daily' => [
'driver' => 'daily',
'path' => storage_path('logs/laravel.log'),
'level' => 'debug',
'days' => 7,
'permission' => 0664,
],
Pas besoin de jongler avec Monolog dans le script bootstrap.
plus précisément, le soutien a été ajouté dans https://github.com/laravel/framework/commit/4d31633dca9594c9121afbbaa0190210de28fed8 .
j'ai rencontré le même problème sur Laravel 5.6
Dans config/logging.php
je viens de mettre à jour quotidienne du canal du chemin d'accès de la valeur avec php_sapi_name()
.
cela crée un répertoire séparé pour différents php_sapi_name et met le fichier journal avec l'horodatage dans leur répertoire particulier.
'daily' => [
'driver' => 'daily',
'path' => storage_path('logs/' . php_sapi_name() . '/laravel.log'),
'level' => 'debug',
'days' => 7,
]
Donc, pour moi,
- les fichiers journaux sont créés sous
fpm-fcgi
répertoire: Logs du site web,owner: www-data
Les fichiers journaux - sont créés dans le répertoire
cli
: à partir de la commande artisan(cronjob).owner: root
plus d'informations sur Laravel 5.6 logging: https://laravel.com/docs/5.6/logging
Voici mon fichier 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',
],
],
];
ajoutez quelque chose comme ceci au début de votre fichier app/start/artisan.php
(C'est avec 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);
}
ajustez le chemin si le fichier journal que vous mentionnez n'est pas le fichier journal Laravel standard. Vous pouvez aussi ne pas vouloir changer le groupe ou définir les permissions comme je le fais ici. Ce qui précède définit le groupe à www-data
et définit les permissions d'écriture du groupe. J'ai ensuite ajouté mon Utilisateur régulier au groupe www-data
de sorte que l'exécution des commandes artisan comme mon utilisateur peut toujours écrire dans le journal.
un tweak lié est de mettre ce qui suit Au début de votre app/start/global.php
fichier:
umask(0002);
si vous faites cela, la ligne chmod
ci-dessus devient sans objet. Avec l'umask défini à ceci, tout nouveau fichier PHP (et donc Laravel) makes aura ses permissions masquées uniquement pour que les "autres" utilisateurs n'aient pas de permissions d'écriture. Cela signifie que les répertoires commenceront par rwxrwxr-x
et les fichiers par rw-rw-r--
. Donc si www-data
exécute PHP, tous les fichiers de cache et de log qu'il crée seront accessibles en écriture par défaut par n'importe qui dans le groupe principal de cet utilisateur, qui est www-data
.
Laravel 5.5
ajouter ce code à 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);
});
- il va stocker des fichiers comme ceci:
laravel-2018-01-27-cli-raph.log
etlaravel-2018-01-27-fpm-cgi-raph.log
qui est plus lisible. - les Nouvelles lignes sont conservées (par défaut Laravel comportement)
- Il travaille avec Laravel Visionneuse du Journal
Laravel 5.6
You doit créer une classe pour votre logger:
<?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;
}
}
ensuite, vous devez l'enregistrer dans config/logging.php
:
'channels' => [
'custom' => [
'driver' => 'custom',
'via' => App\Logging\CreateCustomLogger::class,
],
],
même comportement que pour 5.5:
- il va stocker des fichiers comme ceci:
laravel-2018-01-27-cli-raph.log
etlaravel-2018-01-27-fpm-cgi-raph.log
qui est plus lisible. - les Nouvelles lignes sont conservées (par défaut Laravel comportement)
- il fonctionne avec Laravel Visionneuse Du Journal
Laravel 5.4
\Log::getMonolog()->popHandler();
\Log::useDailyFiles(storage_path('/logs/laravel-').get_current_user().'.log');
ajouter à boot
fonction dans AppServiceProvider
une façon non-Laravel de faire ce travail est de simplement exécuter votre cronjob en tant que www-data.
eg 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
(Laravel 5.6) j'ai récemment rencontré le même problème et j'ai simplement mis une commande programmée à exécuter dans /app/Console/Kernel.php
.
$schedule->exec('chown -R www-data:www-data /var/www/**********/storage/logs')->everyMinute();
je sais que c'est un peu exagéré, mais il fonctionne comme un charme et n'ai pas eu de problèmes depuis.
le meilleur moyen que j'ai trouvé est que fideloper suggère, http://fideloper.com/laravel-log-file-name , vous pouvez configurer laravel log sans toucher à la classe Log. Ont des noms différents pour les programmes de Console et les programmes Http, je pense, est la meilleure solution.