🙅

PHP でファイル入出力しようとしたらパーミッションエラーが出た

2017/03/13に公開

情報

  • CentOS 7.3.1611
  • PHP 5.6.30
  • 入出力したいディレクトリ /var/www/logs
  • ディレクトリの所有者: apache
  • ディレクトリのグループ: apache
  • ディレクトリのパーミッション: 777
  • 使用した関数: file_put_contents, touch

出力されたエラー

Warning: touch(): Unable to create file /var/www/logs/test20170303.log because Permission denied in /var/www/html/log_test.php on line 2

touch(): 実行した関数(ファイルがあればタイムスタンプを更新、なければ作成)
/var/www/logs/test20170303.log: 操作しようとしたファイル
/var/www/html/log_test.php: 実行した関数が書いてあるファイル
line 2: Warning が発生したファイルでの該当行番号

Permission denied ?

先頭に書いた通り、ディレクトリの所有者や権限は満たしているはず。

SELinux

何かうまく動作しなかった場合、とりあえず疑ってみるのがこいつ。
getenforce -> Enforcing
稼働しているので、とりあえずこいつを停止させて ( setenforce 0 ) から同じファイルを実行してみると、ファイルが作成された。
こやつじゃ。

されど停止させるわけにもいかず

VirtualBox 上とかのマシンならまだしも、通常利用するサーバで SELinux の停止を即断するのはリスクがあるし、検討や対応している暇もないので他の道を探すことにする。

ディレクトリの context を変更しちゃおう

semanage fcontext -a -t httpd_sys_rw_content_t /var/www/logs
このコマンドを発行することで、 Apache からディレクトリのファイルの読み書きができるようになる。
このコマンドは完了するまで時間がかかる場合があるので、返ってくるまでちょっと待つ。

次に以下のコマンドを発行し、適応する。
restorecon /var/www/logs

SELinux を再度動かす。
setenforce 1

この状態で先ほどのファイルを実行してファイルが書き出されていれば完了 ( touch で検証する場合は、直前のテストで作成されたファイルを削除しておくとわかりやすい )。

可能ならば念のためサーバを再起動してからファイル出力できるか確認しておくと良いかも。

蛇足

semanage コマンドが見つかりません

semanage 発行時にこういうエラーが出た人もいると思う(むしろ自分が出た)。
そういう時は以下のコマンドでインストールする。
yum install policycoreutils-python

SELinux を disabled にしちゃダメなの?

SELinux は基本的なセキュリティなどを提供してくれる一方で、今回のようにいろいろな不具合の原因になったりする( PHP で他によくあるのがメール送信ができない、 DB アクセスできない、など )。
検索すると disabled を推奨するページがぼちぼち出てくるけど、個人的にはあまりしたくない。
disabled にするならば、ちゃんとリスクを検討し、対処(保持も含む)しておくべきだ。
もちろん SELinux を有効にしていてもリスクの検討は必要だけど。

Discussion