2008-01-24

PHP の設定って PHP で書いた方がよくない?

PHP の各種設定を行える場所

基本的に3つあると思う。

  1. php.ini
  2. .htaccess
  3. 設定用関数を利用

で、普通 PHP の入門記事とかで触れられるのは 1 か 2 のはず。でも、実はこれ間違ってたんじゃないかって思い始めた。

まぁ確かにすべての項目を 3 の方法で設定できるわけじゃないんだけど、ほとんど困らないような気がする。

今までの方法は全部ダメ

php.ini は忘れた方がいいというか単なるデフォルト

まず php.ini , これは virtual host で複数サイトを展開する際、すべて設定が同じになってしまう。今からまっさらの状態で新しく始めるならこの設定にしておくべきというのがまずだいだい決まっているので、それに従って設定してしまうというのは確かにアリ。

でもちょっとでも歴史があった場合これだけじゃ絶対うまくいかない。sjis のサイト、euc-jp のサイト、utf-8 のサイトが入り乱れていること請け合い。あるいはオープンソース開発者でいろんなコード触ってるとかいう場合なんかも一つの php.ini でまかなえるはずがない。

だからもうこの際「インストールして php.ini を編集する」っていう流れは忘れちゃっていいと思うんだ。

.htaccess はサイトごとの設定を保持できるけどそれだけじゃダメ

..htaccess じゃなくて apache の conf の方がいいとかそんなことを言うつもりなし。

問題は CLI でスクリプトを起こしたときに .htaccess は役に立たないってこと。だからいちばんいいのは、

..htaccess などに

php_value auto_prepend_file CONFIG_FILE

と書いておいて設定は PHP で書く方法なんじゃないか、というのがこの記事の趣旨。

だいたい、.htaccess で設定を書くと PHP 独自定義の bool値も定数も存在しないので読みにくくなってしまう。

php_value error_reporting 2047

とか書かれててもすぐに意味が分からないし、php_flag なのか php_value なのかも気にしなきゃいけない。面倒くさいし、この部分、マニュアルもそんなに丁寧に書かれていない。

やってみよう

php.ini だと

mbstring.language          = Japanese
mbstring.internal_encoding = utf-8
mbstring.http_input        = pass
mbstring.http_output       = utf-8
mbstring.detect_order      = auto

これを .htaccess で書くと

php_value mbstring.language Japanese
php_value mbstring.internal_encoding utf-8
php_value mbstring.http_input pass
php_value mbstring.http_output utf-8
php_value mbstring.detect_order auto

これを PHP で書くと

<?php
// mb_http_input(); // 違う機能です

mb_language( 'Japanese' ); // ※ mbstring.language と同じ意味ではありません!
mb_internal_encoding( 'utf-8' ); // 自動変換の機能に対しては有効ではありません
mb_http_output( 'utf-8' );
mb_detect_order( 'auto' );

ただし上に書いたように注意事項もある。

  1. PHP の中ですべての設定を書けるわけではない
  2. PHP の中で行った設定が期待通りに働かない場合もある

特に 2 の方は一見うまく動いているように見えるので注意が必要。例えば

mbstring.internal_encoding()

を PHP の中で設定するときは

mbstring.encoding_translation off

とセットでないといけない。encoding_translation は PHP のコードを読み込む前に動く(でないと透過的な変換として機能しない)ので、php.ini あるいは .htaccess の段階で internal_encoding が決まっていないと正しく動作しない。逆に、この機能を使いたい場合は

mbstring.encoding_translation
mbstring.internal_encoding

は PHP の外でセットしておかないとダメ。最近では UTF-8 をそのまま使うことが多くなっているはずで、その際は自動変換の機能はなくても問題ないけど、そうでない場合は注意が必要。

PHP で設定を書かなくてもいいのは実はメリットじゃなかったのかも

今回なんでこんなことを思ったかっていうと、さっきも書いたけど

CLI で起動したとき .htaccess は生きてこない

ということに今さら気づいたから。しかし上の auto_prepend_file なら CLI でも以下の方法で設定を読み込むことができる。

php -d auto_prepend_file=CONFIG_FILE

CLI を活かせると、例えば大量の PHP のファイルの動作チェックの自動化とかできちゃう。もっとも、イマドキのアプリなら普通はフレームワーク使ってるし、フレームワークのテストに従ってるかもしれないし、ユニットテストがバッチリ動いててチェックも楽ちんなので全然関係ないかもしれない。

でもそうじゃない環境もある。絶対にある。そのとき、せめてこの方法が使えれば人の目と手でチェックするだけよりも確実に効率は上がる。上がるんだよ。

上の方法で

error_reporting( E_ALL );
ini_set( 'log_errors', true );
ini_set( 'error_log', '/path/to/error.log' );

とかしておいて

for i in `find /path/to/app -name '*.php'`;
do
  cd dirname $i;
  php -d auto_prepend_file=CONFIG_FILE $i;
done

とか回すとドバーっとエラーがログに吐かれる。いちいちブラウザで開いて回らなくてもよい。

まぁ CLI の場合は当然 HTTP 周りのパラメータがセットされないわけだけど、それも CLI での検証時だけ適当に補完するように CONFIG_FILE を書いてやればとりあえず騙せるのではなかろうか。

PHP スクリプトで変更できない設定を CLI 環境下で反映する

PHP のマニュアルで変更の可否が PHP_INI_SYSTEM と PHP_INI_PERDIR になっているものは php のスクリプトからは変更できない。ini_set() とか使ってもダメ。.htaccess を使えない CLI の場合はこうなると php.ini をいじるしかないけど、システム全体に影響する php.ini をいじりたくない場合は

php -c PATH

でそのときだけの php.ini を指定することができる。

というわけで

また一つ PHP ならではの機能がメリットでなくなったことを感じたのでした。(代わりに auto_prepend_file という PHP ならではの機能を使ってるんだけど。)

というかやっぱさ。今さらだけど php.ini や .htaccess でしかいじれない設定があるのってすっげーおかしくね? CLI だと

php -c PATH

で ini ファイルを都度指定できるけど、mod_php とかだと ini を切り替える方法ないよね? なんでこんな変な方針なんだろう。譲って言語の外で設定できることはよしとしよう。それが便利な場合もあるさ、というか実際便利だと思っていたこともある。でも言語の中で変更できないっておかしいよなぁ。

About

例によって個人のなんちゃらです

Recent Posts

Categories

Tool 日々 Web Biz Net Apple MS ことば News Unix howto Food PHP Movie Edu Community Book Security Text TV Perl Ruby Music Pdoc 生き方 RDoc ViewCVS CVS Rsync Disk Mail FreeBSD Cygwin PDF Photo Zebedee Debian OSX Comic Cron Sysadmin Font Analog iCal Sunbird DNS Linux Wiki Emacs Thunderbird Sitecopy Terminal Drawing tDiary AppleScript Life Money Omni PukiWiki Xen XREA Zsh Screen CASL Firefox Fink zsh haXe Ecmascript PATH_INFO SQLite PEAR Lighttpd FastCGI Subversion au prototype.js jsUnit Apache Trac Template Java Rhino Mochikit Feed Bloglines CSS del.icio.us SBS qwikWeb gettext Ajax JSDoc Rails HTML CHM EPWING NDTP EB IE CLI ck ThinkPad Toy WSH RFC readline rlwrap ImageMagick epeg Frenzy sysprep Ubuntu MeCab DTP ERD DBMS eclipse Eclipse Awk RD Diigo XAMPP RubyGems PHPDoc iCab DOM YAML Camino Geekmonkey w3m Scheme Gauche Lisp JSAN Google VMware DSL SLAX Safari Markdown Textile IRC Jabber Fastladder MacPorts LLSpirit CPAN Mozilla Twitter OpenFL Rswatch ITS NTP GUI Pragger Yapra XML Mobile Git Study JSON VirtualBox Samba Pear Growl Mercurial Rack Capistrano Rake Win RSS Mechanize Sitemaps Android JavaScript Python RTM OOo iPod Yahoo Unicode Github iTunes God SBM friendfeed Friendfeed HokuUn Sinatra TDD Test Project Evernote iPad Geohash Location Map Search Simplenote Image WebKit RSpec Phone CSV WiMAX USB Chrome RubyKaigi RubyKaigi2011 Space CoffeeScript Nokogiri Hpricot Rubygems jQuery Node GTD CI UX Design VCS Kanazawa.rb Kindle Amazon Agile Vagrant Chef Windows Composer Dotenv PaaS Itamae SaaS Docker Swagger Grape WebAPI Microservices OmniAuth HTTP 分析基盤 CDN Terraform IaaS HCL Webpack Vue.js BigQuery Middleman CMS AWS PNG Laravel Selenium OAuth OpenAPI GitHub UML GCP TypeScript SQL Hanami Document SVG AsciiDoc Pandoc DocBook Develop Jekyll macOS Node.js Vite Heroku Transformer AI Data Cloud Wasm