php の 755ファイルが面倒
php って便利なんだけど、至る所に、apacheユーザでファイルを作りまくられては困る。 755のパーミッションで、apacheユーザのファイルがあるのは/var/ww以下なら良いんだけど 自分のpublic_html内部にapacheユーザーの権限ファイルがあるとあれこれ面倒が多いよね。
phpがはき出したファイルを触るのにsetid・・つまり 、adduser takuya _www; chmod -R g+w path/to/web; chmod a+s path/to/web; umask 0002 とかしておく必要があるのがいやだし・・・
だから、cgiモードでtakuyaユーザーのファイルを作ってほしい。
先に状況を確認
takuya@rena:~/Sites/upload$ cat /etc/apache2/httpd.conf | grep cgi-bin 340: ScriptAliasMatch ^/cgi-bin/((?!(?i:webobjects)).*$) "/Library/WebServer/CGI-Executables/$1"
OS X mavericks の phpは 5.4でした
takuya@rena:~/Sites/upload$ /usr/bin/php -v PHP 5.4.24 (cli) (built: Jan 19 2014 21:32:15) Copyright (c) 1997-2013 The PHP Group Zend Engine v2.4.0, Copyright (c) 1998-2013 Zend Technologies
OS X mavericks には php-cgiはありません
takuya@rena:~/Sites/upload$ /usr/bin/php-cgi -bash: /usr/bin/php-cgi: No such file or directory takuya@rena:~/Sites/upload$ /usr/bin/php -i | grep cgi 6:Configure Command => 中略 '--disable-cgi' 以下略
php-cgiが無いなーと思ったら、disabledされてました。乙
cgiモードを使うには、インストールが必要です
ここから分かる通り、osx の標準添付のphp ではcgi は動かない。なのでインストールが必要と分かります。
OS X に php5.5をインストール
brew の標準では*1 tap に入っているのでtap*2を作ってphp5.5を流し込みます。
brew tap homebrew/php
brew install php55
phpインストールを確認
takuya@rena:~/Sites/upload$ which /usr/local/bin/php /usr/local/bin/php takuya@rena:~/Sites/upload$ /usr/local/bin/php -v PHP 5.5.11 (cli) (built: Apr 13 2014 02:20:35) Copyright (c) 1997-2014 The PHP Group Zend Engine v2.5.0, Copyright (c) 1998-2014 Zend Technologies
php-cgi をcgi-binにコピーします。
http://127.0.0.1/cgi-bin/php-cgi
sudo cp $(which php-cgi) /Library/WebServer/CGI-Executables/
cgi が動くようにapache を設定
httpd.conf で
LoadModule cgi_module libexec/apache2/mod_cgi.so LoadModule actions_module libexec/apache2/mod_actions.so
をコメントアウトを削除して、Action と cgi が動くように設定してリスタート
sudo /usr/sbin/apachectl restart
cgiでphpが動くように 設定します。
takuyaユーザーに全権を許可しました。
/etc/apache2/users/takuya.conf
この辺は適宜やっちゃえば良いんですけど。user.confで設定してから、全権を許可して.htaccessで制御しました
<Directory "/Users/takuya/Sites/"> #Options Indexes MultiViews FollowSymLinks # commented out Options All AllowOverride All AllowOverride all Order allow,deny Allow from all </Directory> <IfModule mod_rewrite.c> RewriteEngine on </IfModule>
これで、.htaccessから全部制御します。
/Users/takuya/Sites/path/to/myApp/.htaccess
DirectoryIndex index.php index.cgi index.fcgi Action php-script /cgi-bin/php-cgi AddHandler php-script .cgi .php php_flag display_errors on php_flag display_startup_errors on php_value date.timezone Asia/Tokyo
timezoneは書いておかないと、warnningが出るのと、display_errors は、何が起きてるか分かるようにするために、必要。本番では外す。
動作チェック
cd /Users/takuya/Sites/path/to/myApp/ echo "<?php phpinfo();" > index.php
これで動いてることが確認できる。
Server API CGI/FastCGI
になっていれば、php が apache 2 handler のmod_phpから CGI/FastCGIに制御が変わったことがわかる。
次に、ユーザ権限で動くようにする。
起動した状態で、~/takuya/index.phpはどのユーザーで動いているか確認してみる。
(2015-05-25確認
動作してるユーザーを確認してみる
echo '<?php echo "<pre>"; var_dump(posix_getpwuid(posix_getuid()));' > index.php
動作結果は以下のようになった。
array(7) { ["name"]=> string(4) "_www" ["passwd"]=> string(1) "*" ["uid"]=> int(70) ["gid"]=> int(70) ["gecos"]=> string(21) "World Wide Web Server" ["dir"]=> string(18) "/Library/WebServer" ["shell"]=> string(14) "/usr/bin/false" }
え、っと、、、apacheユーザーで動いてます。ふーむ。正しいと言えば正しいんだけど。apacheユーザーでファイルを作りまくられては困る。 これでは、目的を達せない。
cgiを動かすと言えばsuexec。
suexec をインストール
cgi をユーザーのパーミッションで動かすためにsuexecを出来るようにします。
brew install mod_suexec
/etc/apache2/httpd.conf
apacheに suexecをロードさせます。
LoadModule suexec_module /usr/local/Cellar/mod_suexec/2.2.22/libexec/mod_suexec.so
Apache再起動
sudo apachectl restart
suexecのインストールの確認はrubyやperlでcgiを作ればOK
suexecの動作確認
php-cgiがsuexecでなんかおかしかったので、ruby+sinatraをrack cgiでsuexecを確認。
~/Site/ruby.cgi
#!/usr/bin/ruby require 'pp' require 'etc' require 'bundler' Bundler.require get "/" do uid= Process.uid Etc.getpwuid( uid ) end set :run => false Rack::Handler::CGI.run Sinatra::Application
これで、実行時ユーザーが自分になればOK
でもって、suexecのログを確認
tail -n 1 /var/log/apache2/suexec.log [2014-04-xxx 12xxxxx]: uid: (50xxx/takuya) gid: (20/staff) cmd: ruby.cgi
よしsuexec動いた
php-cgiをsuexecで動かす。
index.cgiを作って。。。
#!/usr/local/bin/php-cgi <?php echo "<pre>"; var_dump(posix_getpwuid(posix_getuid()));
実行するとinternal server errorになる。えっと。なんでエラーなんですか
error_logは次のようになっていて。
[Sun Apr 13 04:29:08 2014] [error] [client ::1] suexec failure: could not open log file [Sun Apr 13 04:29:08 2014] [error] [client ::1] fopen: Permission denied [Sun Apr 13 04:29:08 2014] [error] [client ::1] Premature end of script headers: index.cgi
suexecには実行ログが出ている
[2014-04-13 04:30:08]: uid: (501/takuya) gid: (20/staff) cmd: index.cgi [2014-04-13 04:30:10]: uid: (501/takuya) gid: (20/staff) cmd: index.cgi
suexecで実行ログがあるのに500 internal server erro だとか、security 警告が出る。
解決策
いろいろ試したところ、ユーザ権限でphp-cgiを動かすとしたら
このいずれかが必要と分かった。
phpのマニュアル通りに以下をhttpd.confまたは.htaccessに記述すると shebang なしでもphpが実行されるが
Action php-script /cgi-bin/php-cgi AddHandler php-script .cgi
この場合は実行ユーザーはapacheになってしまう。
このままで動くんだけどApacheユーザーのファイルは要らないんだ。
いや、たぶんユーザーごとにcgi-binを作れば良いんだろうけど。。。それってsuexecの意味が・・・ もしかしてphpでは、suexecが想定されてない??
解決策1 ユーザーごとのcgi-binを作ってみた
mkdir -p ~/Sites/cgi-bin cp $(which php-cgi) ~/Sites/cgi-bin echo "\ Options ExecCGI SetHandler cgi-script " > ~/Sites/cgi-bin/.htaccess
~/Sites/path/to/app/.htaccess
Action php-script /~takuya/cgi-bin/php-cgi AddHandler php-script .cgi
これで動いた。とりあえずsuexecも動いてる。。 suexec_log
[2014-04-13 04:51:42]: uid: (501/takuya) gid: (20/staff) cmd: php-cgi
でもさ、これってsuexecの意味ない・・・よね。。。
takuyaユーザーがownerのphp-cgiを作ってActionを設定するのが正しいと言えばそうなんだけどさ。
解決策2cgi.force_redirect=0 にした
結局cgi-bin にphp-cgiをいくつも作るのは面倒だし。.htaccessファイルが共通にならないので、php.iniのforce_redirect=0で動かすことに
- .htaccessに cgi-script有効にするためAddHandler cgi-script .cgiを書く
- php.iniで cgi.force_redirect=0にして
- index.cgiに shebang で #!/usr/local/bin/php-cgiを書く
AddHandler cgi-script .cgi
php.ini
cgi.force_redirect=0
権限チェックするphp
#!/usr/local/bin/php-cgi <?php echo "<pre>"; var_dump(posix_getpwuid(posix_getuid()));
suexec_log
[2014-04-13 04:56:54]: uid: (501/takuya) gid: (20/staff) cmd: index.cgi
これで、takuyaユーザーでphp-cgiが実行されていることが確認できた
念のためアクセスできないことを確認。
http://127.0.0.1/cgi-bin/php-cgi/etc/passwd
にアクセスしておいた。
ふーむ。エラーになった。
結論
addhandler cgi-scriptとsuexec+shebang行では、force_redicrect=1に引っかかる。
apacheのphp-scriptと/cgi-binの組み合わせは必ずapacheユーザーで実行される
こういう当たり前のことを当たり前にキッチリ強制されてる感じでした。
面倒。。。なんか、きもい。きもいよphp。 いや、僕がsuexecを理解してない??そうかも。。。
Apache権限でファイルを作りまくる、それが一番怖いんだけど。
共用サーバーでapacheのファイルがいっぱいあって、それが全部wordpressだとしたらやばくねーかね。。。。。ファイル構造や場所やパーミッション丸見えじゃないかね。
2014-04-13 追記
そういえば、suexecにユーザーIDを指定するモードがあったことを忘れていた
解決策3
SuexecUserGroup takuya staff
これですね。ただし、SuexecUserGroupは VirtualHost単位でしか得使えないので注意が必要
参考資料
http://d.hatena.ne.jp/msakamoto-sf/20080802/1217662203