J'ai un script que je lance en utilisant php artisan (avec root utilisateur), et parfois, le fichier journal quotidien est créé avant l'utilisateur Apache www-data - ce qui signifie que lorsqu'un vrai utilisateur utilise mon application Web, l'erreur d'erreur de permission du dossier est générée:
Échec d'ouverture du flux: autorisation refusée
Je modifie les autorisations en www-data à chaque fois, mais je veux résoudre ce problème en laissant le fichier journal toujours créé avec les autorisations appropriées.
J'ai envisagé de créer un travail cron qui crée le fichier ou le touche pour s'assurer qu'il dispose de la permission appropriée chaque jour, mais je recherche une solution meilleure qui ne repose pas sur un autre script.
Nous avons également envisagé d'encapsuler php artisan dans un autre script pour nous assurer qu'il est toujours exécuté avec les informations d'identification www-data, mais nous souhaitons faire quelque chose: root procédures qu’Apache ne devrait pas être autorisé à faire.
Des suggestions supplémentaires?
Commençons par ce qui est constant.
Vous avez une commande php artisan
, Exécutée par root
.
Il est prudent de supposer que cette commande est exécutée quotidiennement.
Solution No 1:
Etant donné que l'utilisateur qui crée les fichiers est celui qui a le droit d'écrire par défaut, nous pouvons séparer les journaux par utilisateur en tant que tels:
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 utilisateur www-data devait créer un journal des erreurs, le résultat serait: storage/logs/laravel-www-data-2015-4-27.log
.
Si votre utilisateur root devait créer un journal des erreurs, le résultat serait: storage/logs/laravel-root-2015-4-27.log
.
Solution No 2:
Changer le journal 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
, votre fichier journal sera:
storage/logs/laravel-ArtisanRunner-2015-4-27.log
.
Conclusion: La solution numéro 1 est préférable, car elle délimite vos journaux par utilisateur. Par conséquent, aucune erreur ne se produit.
EDIT: Comme l'a souligné jason, get_current_user()
renvoie le nom du propriétaire du script. Par conséquent, pour que la solution n ° 1 s’applique, chown
vos fichiers de classe artisanaux au nom d’utilisateur requis.
Pour Laravel 5.1 J'utilise ce qui suit vers le bas de bootstrap/app.php
_ (comme mentionné dans la documentation ):
/**
* 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 gestionnaires que vous pouvez utiliser à la place, bien sûr.
Laravel version 5.6.10 et ultérieure prend en charge un élément permission
dans la configuration (config/logging.php
) pour le pilote single
et le pilote daily
:
'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, un support a été ajouté dans https://github.com/laravel/framework/commit/4d31633dca9594c9121afbbaa0190210de28fed8 .
Pour ce faire, vous devez utiliser ACL avancé sur vos fichiers et répertoires. setfacl
serait votre réponse ici. Si vous voulez donner à www-data le droit d'utilisateur pour écrire sur la racine fichiers dans un 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 cette information, vous définissez les autorisations sur rwx
pour l'utilisateur www-data sur tous les fichiers de /my/folder/
peu importe qui a créé ceux-ci. S'il vous plaît, voir this et cette question pour référence. En outre, vous pouvez vérifier docs pour setfacl
.
Faites-moi savoir si cela aide.
Pour moi, ce problème était bien plus que les autorisations de journalisation ... J'avais des problèmes avec tout ce qui concernait les dossiers d'amorçage/cache et de stockage dans lesquels un utilisateur créerait un fichier/dossier et l'autre ne pourrait pas éditer/supprimer en raison de la norme Autorisations 644 et 755.
Les scénarios typiques sont:
Le fichier bootstrap/cache/compiled.php créé par l'utilisateur Apache mais non modifiable par composer utilisateur lors de l'exécution de la commande composer install
L’utilisateur Apache créant un cache qui ne peut pas être effacé à l’aide de composer utilisateur
Le rêve est que, quel que soit l'utilisateur qui crée le fichier/dossier, les autres utilisateurs qui ont besoin d'accéder ont exactement les mêmes autorisations que l'auteur d'origine.
TL; DR?
Voici comment c'est fait.
Nous devons créer un groupe d'utilisateurs partagé appelé laravel, composé de tous les utilisateurs ayant besoin d'accéder aux répertoires de stockage et bootstrap/cache. Ensuite, nous devons nous assurer que les fichiers et les dossiers nouvellement créés disposent des autorisations laravel du groupe et 664 et 775 respectivement).
C'est facile à faire pour les fichiers/répertoires existants, mais un peu de magie est nécessaire pour modifier le fichier/dossier par défaut créant des règles ...
## 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
À des fins purement de débogage, j'ai trouvé qu'il était avantageux de scinder les journaux en deux utilisateurs cli/web +, c'est pourquoi j'ai légèrement modifié la réponse de Sam Wilson. Mon cas d'utilisation étant la file d'attente exécutée sous son propre utilisateur, il a donc permis de faire la distinction entre l'utilisateur composer) utilisant le cli (par exemple, les 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);
});
J'ai rencontré le même problème sur Laravel 5.6
Dans config/logging.php
, Je viens de mettre à jour la valeur de chemin du canal quotidien avec php_sapi_name()
.
Cela crée un répertoire distinct pour différents noms php_sapi et place le fichier journal avec l’horodatage dans leur répertoire respectif.
'daily' => [
'driver' => 'daily',
'path' => storage_path('logs/' . php_sapi_name() . '/laravel.log'),
'level' => 'debug',
'days' => 7,
]
Donc pour moi
fpm-fcgi
: Journaux du site Web, owner: www-data
cli
: à partir de la commande artisan (cronjob). owner: root
Plus d'informations sur Laravel 5.6 journalisation: 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',
],
],
];
Laravel 5.1
Dans notre cas, nous voulions créer tous les fichiers journaux de manière à ce que tout le groupe deploy
dispose des autorisations de lecture/écriture. Par conséquent, nous devions créer tous les nouveaux fichiers avec 0664
autorisations, opposées à la 0644
défaut.
Nous avons également ajouté un formateur pour ajouter des nouvelles lignes pour une meilleure lisibilité:
$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);
});
En outre, il est 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);
});
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);
});
laravel-2018-01-27-cli-raph.log
et laravel-2018-01-27-fpm-cgi-raph.log
qui est plus lisible.Vous devez 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:
laravel-2018-01-27-cli-raph.log
et laravel-2018-01-27-fpm-cgi-raph.log
qui est plus lisible.Ajoutez quelque chose comme ceci au début de votre fichier app/start/artisan.php
(Il s’agit de 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 quotidien que vous mentionnez n’est pas le fichier journal standard Laravel. Vous pouvez également ne pas vouloir modifier le groupe ni définir les autorisations comme je le fais ici. group à www-data
et définit les autorisations d'écriture du groupe.J'ai ensuite ajouté mon utilisateur habituel au groupe www-data
pour que l'exécution de commandes artisan en tant qu'utilisateur régulier puisse toujours écrire dans le journal.
Un Tweak associé est de mettre ce qui suit au début de votre fichier app/start/global.php
:
umask(0002);
Si vous faites cela, la ligne chmod
ci-dessus devient sans objet. Lorsque umask est défini sur ceci, tous les nouveaux fichiers PHP (et donc Laravel) créeront leurs autorisations masquées uniquement, de sorte que les "autres" utilisateurs ne disposeront pas d'autorisations en écriture. Cela signifie que les répertoires commenceront comme rwxrwxr-x
et les fichiers comme rw-rw-r--
. Ainsi, si www-data
exécute PHP, tous les fichiers de cache et de journal qu'il permet seront en écriture pour tout membre du groupe principal de cet utilisateur, qui est www-data
.
Une façon non-Laravel de faire ce travail est d’exécuter simplement votre travail cron en tant que www-data.
par exemple 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.4
\Log::getMonolog()->popHandler(); \Log::useDailyFiles(storage_path('/logs/laravel-').get_current_user().'.log');
ajouter à boot
fonction dans AppServiceProvider
(Laravel 5.6) J'ai récemment rencontré le même problème et j'ai simplement défini une commande planifiée pour qu'elle s'exécute 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 excessif, mais cela fonctionne comme un charme et n'a pas eu de problèmes depuis.
Vous pouvez simplement changer l’autorisation du fichier journal dans votre commande artisan:
$path = storage_path('log/daily.log');
chown($path, get_current_user());
où get_current_user () renvoie l'utilisateur du script actuel.
En d'autres termes, daily.log
aura toujours www-data
en tant que propriétaire, même si vous initialisez le script en tant que root
utilisateur.
Laravel 5.8 vous permet de définir le nom du journal dans config/logging.php
.
Donc, en utilisant les réponses et les commentaires précédents, si vous voulez nommer votre journal en utilisant à la fois le nom d’utilisateur posix ET la valeur php_sapi_name()
, il vous suffit de modifier le nom du journal. L'utilisation du pilote quotidien permet une rotation du journal qui s'exécute par combinaison utilisateur/API, ce qui garantit que le journal est toujours pivoté par un compte capable de modifier les journaux.
J'ai également ajouté une vérification des fonctions posix qui n'existent peut-être pas dans votre environnement local. Dans ce cas, le nom du journal est simplement la valeur par défaut.
En supposant que vous utilisez le canal de journalisation par défaut "quotidiennement", vous pouvez modifier votre clé de "canaux" comme suit:
# 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,
],
...
Cela donnera un nom de journal qui devrait être unique pour chaque combinaison, tel que laravel-cli-sfscs-2019-05-15.log
Ou laravel-Apache2handler-Apache-2019-05-15.log
En fonction de votre point d'accès.