印刷用表示へ切り替え 通常表示へ切り替え 更新履歴を表示 更新履歴を隠す
Linux 拡張子 html で PHP を動作させているときの文字化け問題が解決

文字化けを直すと PHP が動作せず,PHP を動作させると文字化けになってしまう問題が解決した。

■ ■ ■

問題発生

このサイトの文字コードは基本的に EUC-JP で,一部に UTF-8 のページがある。UTF-8 のページでは PHP が動作している(nlog(n): Picasa の Web エクスポートに PukiWiki 風のコメント欄をつける)。PHP は,拡張子が .html の場合でも動作するように設定している(nlog(n): 拡張子を変更せずに MT を PHP 化)。当初はうまく動作していたのだが,いつの間にか UTF-8 のページが文字化けするようになってしまった(nlog(n): 文字化けを直すとPHPが動作しなくなる)。Apache のバージョンを疑ったが,原因は違うところにあった。

このサイトの構成で関係のある点は次の通り。

  • 基本は EUC-JP のページだが,一部 UTF-8 のページがある
  • 拡張子 .html で PHP を動作させている

環境は Vine Linux 3.2 kernel-2.4.33-0vl0.9,apache-1.3.33-0vl2.3, php5-apache-5.2.0-0vl2 である。

問題解決

拡張子 .html を PHP に処理させる指定は httpd.conf ではなく .htaccess で行う

これは,異なる文字コードのページが混在している場合に有効な設定である。

このサイトでは,拡張子が .php のファイルだけでなく,.html のファイルも PHP で動作するように設定している。基本は .htaccess に AddType ディレクティブを追加することで行う(nlog(n): 拡張子を変更せずに MT を PHP 化)。

PHP 化した際に,.htaccess の代わりに httpd.conf で設定してみたが,動作しなかったためそのまま放置していた。その後しばらくして UTF-8 のページに文字化けが発生した(nlog(n): 文字化けを直すとPHPが動作しなくなる)。当初は反映されなかった httpd.conf での AddType 設定が,何らかのタイミングで有効になり,それと同時に文字化けが始まったのではないかと推測される。

なぜなら,httpd.conf で .html を PHP に処理させるように設定すると,.htaccess 内で AddType で文字コード設定をしていても,PHP で設定されている Content-Type が強制的にヘッダについてしまうからである。つまり,Apache の文字コード設定よりも PHP の設定の方が優先されるのだ。

PHP のディレクティブで Content-Type の charset 設定を行う

上述の理由により,nlog(n): Picasa の Web エクスポートに PukiWiki 風のコメント欄をつける を正しく動作させるには,.htaccess に次のように書いておけばよいことになる。特にこれは EUC-JP と UTF-8 のページが混在している場合だが,混在せず UTF-8 のページだけの場合でも有効である。

<IfModule mod_php5.c>
  AddType "application/x-httpd-php" .html
  php_value default_charset utf-8
  php_value mbstring.internal_encoding UTF-8
</IfModule>

ポイントは,default_charset の設定である。default_charset で設定した文字列は,HTML レスポンスヘッダ内の「Content-Type: text/html; charset=」の後ろにそのまま表示される(PHP: コア php.ini ディレクティブに関する説明 - Manual)。この文字列は,最終的には Web ブラウザで利用されるため,大文字でも小文字でもよい。W3C の書式に習い,ここでは小文字にしている(W3C I18n article: Character encodings)。mbstring.internal_encoding は PHP が扱うものなので,マニュアルにある通り大文字とした(PHP: マルチバイト文字列関数 (mbstring) - Manual)。.htaccess で設定できる PHP ディレクティブは,PHP: php.ini ディレクティブ - Manual のうち,変更の可否が PHP_INI_ALL または PHP_INI_PERDIR となっているものである。

文字コード設定の優先順位

まず,Web ブラウザが文字コードを判定する基準についてみてみる。@IT:Javaの文字化け対策FAQ には次の解説がある。

HTML 4.01仕様では、Webブラウザが以下の優先順位で文字コードを決定することを規定している。

  1. HTTPにおけるContent-Typeヘッダのcharsetパラメータ
  2. HTML文書内のMETA宣言およびhttp-equiv属性で設定された、Content-Typeヘッダのcharsetパラメータ
  3. HTML文書内の各要素のcharset属性

ここで,数字が若いほど優先順位が高い。すなわち,Content-Type ヘッダの charset パラメータが最も優先される。

次に,サーバ側で Content-Type ヘッダをどのように設定しているかについて見てみたい。しかし,探し出せなかった。恐らく次のような動作をすると思われる。順序は上から下なので,下に行くほど優先度が高くなる。

  1. httpd.conf 内の AddType 設定を調べる
    1. AddType application/x-httpd-php .html なら,php.ini 内の default_charset 設定を調べる (設定がなければコンパイル時オプションの値を設定)
  2. .htaccess 内の AddType 設定を調べる
    1. AddType application/x-httpd-php .html なら,default_charset 設定を調べる
      1. php.ini 内の default_charset 設定 (設定がなければコンパイル時オプションの値を設定)
      2. .htaccess 内の default_charset 設定

ここまで書き終わったところで,タイムリーにはてブコメントをいただいた(はてなブックマーク - 徒栞 / 2007年01月16日)。すんごくタイムリー。そして的確である。

1つの拡張子に違うAddTypeを同時に適用はできないので、(1)AddType application/x-httpd-php htmlするならPHP側でContent-Typeヘッダを出力。(2)AddType "text/html; charset=.." htmlするならAddHandler application/x-httpd-php html とかでは。

2015年1月14日追記:
OS をアップグレードしたところ,またもやこの問題が発生し,そして解決しました (nlog(n): 拡張子 html で PHP を動作させているときの文字化け問題が復活)。

Posted by n at 2007-01-16 23:55 | Edit | Comments (0) | Trackback(0)
Trackbacks

  • 「手違いで複数トラックバックを送ってしまった!」という場合でも気にしないでください (重複分はこちらで勝手に削除させていただきます)
  • タイムアウトエラーは,こちらのサーバの処理能力不足が原因です (詳細は トラックバック送信時のエラー をご覧ください)
  • トラックバックする記事には,この記事へのリンクを含めてください(詳細は 迷惑トラックバック対策 をご覧ください)
Comments
Post a comment
  • 電子メールアドレスは必須ですが,表示されません (気になる場合は「メールアドレスのような」文字列でもOKです)
  • URL を入力した場合はリンクが張られます
  • コメント欄内ではタグは使えません
  • コメント欄内に URL を記入した場合は自動的にリンクに変換されます
  • コメント欄内の改行はそのまま改行となります
  • 「Confirmation Code」に表示されている数字を入力してください (迷惑コメント対策です)


(必須, 表示されます)


(必須, 表示されません)


(任意, リンクされます)


Confirmation Code (必須)


Remember info (R)?