timezoneを設定する

故あって久々に海外サーバを使うことになった。海外サーバは安価で大容量という点がいいのだが、さしあたって2点問題がある。

まず一つ目は速度が期待できないこと。こればかりはどうしようもない。サーバ側でのプログラムの処理速度は問題ないが、距離が遠い分表示に時間がかかる。試してみたら、HTMLのみなら容量もそれほど大きいわけではないのでそれほどでもないが、画像等のバイナリを扱うと遅さがわかってしまう。しかし、こればかりはどうしようもない。画像そのもののサイズを小さくするしかない。

もう一つ。時刻の設定が問題。海外設置のサーバでは、専用サーバやVPSでもない限り現地時刻で設定してあるので、単純に現在日時を表示しようとすると、現地時間で表示されてしまう。かといって時差を考慮して足し算引き算をするのはもっとダメ。サマータイムとか考慮することを考えるととても複雑だし、汎用化するために関数化するのはプログラムの本質から離れてしまうような気がするのでNG。

でも実は簡単だった。プログラム自体は何も考慮せず作り、プログラムの先頭におまじないをつければよい。

putenv(‘TZ=JST-9′);

この1行を書いておくだけで、プログラムは日本時間で処理してくれる。環境変数のことを考慮するようなことってあまりないが、Tipsとして知っておくと便利な機能だ。

環境変数に値をセット

外部から値を渡したいことがある。すぐに思いつくのは以下の方法だ。

  • $_GETや$_POSTで渡す
  • 設定ファイルに記述し、それを呼び出す

前者の場合、その値を引き回したいときには不便だ。毎回リクエストに値を付与してやらなければいけない。後者の場合は、当該ファイルをその都度呼び出さなくてはいけない。例えば特定のディレクトリ内では、常に同じ値を与えたいという場合は、どうすれば簡単に実現できるだろうか。

SetEnv ENV_NAME env_value

これが一番簡単。.htaccessファイルに上記のように記述すると、PHPから$_ENVを参照すれば、設定した値を取得できる。これ便利。

メールヘッダを自前でエンコードするときに

PHPからメールを送信するのはよくあることだけど、いろんな方法がある。mail関数、mb_send_mail関数、PEAR_Mail、fsockopen・・・。普段はmb_send_mail関数で十分だけど、いろいろな状況下でメールを送信することがあるわけで、複数のやり方を知っておくと非常に役に立つ。日本語でメールを送信するときは、いろいろ問題はあるにせよmb_send_mail関数で十分。実際に送信する前に以下の指定さえしておけば問題ない。

mb_language(‘ja’);
mb_internal_encoding(‘utf-8′);

正しい言語指定と正しい文字コード指定をしておけばよい。ただし、この関数を知っているだけでは、例えば添付ファイル付きのメールを送信することはできない。実現するためには、関数の使い方以前にメールのお作法を知っておく必要がある。今回はいろいろあって、mail関数を使い、自前でヘッダや本文をエンコードして送信するプログラムを作ったので、それについてメモしておくことにする。

  • mb_encode_mimeheader関数
    メールのヘッダを自前で準備する際(特にマルチバイト文字を含む場合)、お世話になるのがこの関数だ。今回自前でヘッダを用意するので、いくつか覚えたことをメモしておくことにする。
    ヘッダに日本語で記述したい内容といえば送信者名(from)とタイトル(subject)だ。from句は以下のように記述するのが一般的。
    From: 送信者名<メールアドレス>
    ここで送信者名は上記関数を使ってエンコードする必要があるのだが、一工夫しておく必要がある。mb_encode_mimeheader関数の第一引数はエンコードしたい文字列だが、第二引数には文字コードを指定する(オプション)。マニュアルにはmb_internal_encodingと同じエンコードにしなければいけないと書いてある。これはちょっと気にくわない。だったら最初からこんな引数いらないじゃない。
    ここで問題がでる。基本的に文字コードUTF-8で記述しているのだからmb_internal_encoding(‘utf-8′)で処理しているはずだ。でもマルチバイトのメール送信ってISO-2022-JPじゃなかったっけ。っていろいろ考えていたら訳がわからなくなってくる。だからこう記述した。

    $fromName=mb_convert_encoding($fromName,’ISO-2022-JP’,’UTF-8′);
    mb_internal_encoding(‘ISO-2022-JP’);
    $fromName=mb_encode_mimeheader($fromName,’ISO-2022-JP’);

    文字列は変数に格納されているわけで、それらをいったんISO-2022-JPに変換しておく(メール関連の情報は全て変換すればよい)。その後mb_internal_encodingでISO-2022-JPを指定し、それにしたがってmb_encode_mimeheaderするという手順だ。これでいちおうお作法通りのヘッダを作成することが出来ている(と思う)。

しかし、わからないことがある。mb_encode_mimeheaderの第2引数の指定だ。そもそもmb_internal_encodingと同じ指定をすることが前提なら、そんな引数は必要ないだろうと思う。内部エンコードの指定はあってもいいかもしれないけれど、変換後の文字コード指定があったほうが親切だ。絶対その方がいいに決まっている。

でもなぜ今のような状況なのか。きっとなにか理由があるはずだ。そのうち理解出来るだろうか・・・。あえて探ろうとはしないけどね。

mb_send_mailの第5引数のことで

mail関数でもmb_send_mail関数でも同じだが、第5引数があれば、それはMTAにコマンドラインパラメータとして渡される。これにより受信するメールヘッダにReturn-Pathがセットされ正しくエラーメールが届くようになったり、スパムと判断されにくくなったりする。書式はメールアドレスの前に「-f」とつけるだけ。

ただ、第5引数を与えても、Return-Pathが環境によって付加されないことがわかった。おそらくメール転送に起因するようだ。

現在メインのメールアカウントとしてgmailを使用している。会社ドメインやその他独自ドメインは種々のレンタルサーバで運用しており、メールアドレスはレンタルサーバ内でアカウントを作成しておいて、すべてgmailに転送するよう設定している。

例えばサーバAにメールアカウントを設定してgmailに転送し、以下のスクリプトを流すと、受信したメールには適切にReturn-Pathに値が設定されている。

mb_send_mail(‘Aサーバ上のメールアドレス’,’タイトル’,’本文’,’From: 適当なメールアドレス’,’-f適当なメールアドレス’);

ここで「Aサーバ上のメールアドレス」を「Bサーバ上のメールアドレス」に変更する。A同様Bでもgmailに転送するよう設定している。こちらの場合はReturn-Pathに値が未設定の状態でメールが届いた。以下のような感じ。

Return-Path: <>

mb_send_mail(‘kitao@komamono.com’,’試験’,’テスト’,’From: info@fishup.net’,’-finfo@fishup.net’);

どうやら、レンタルサーバの各種設定(おそらくはMTAの設定)によって、挙動が変わるようだ。これは多分転送設定した場合に現れるようで、転送なしの場合はどのサーバでも問題なく動作するようだ(上記のサーバでも直接gmailのメールアドレスを指定した場合は両方とも問題なかった)。レンタルサーバも、特にココ、というわけではなく複数のレンタルサーバで同様の問題が出ることを確認した。

でも、これ。レンタルサーバのMTAの問題だからどうにもならなさそう。

jQueryによるAjax処理でxmlを受け取るときに

最近はjQueryに夢中。毛嫌いしてきたJavaScriptだったが、jQueryに出会ってからは一転。できることならPHPをやめてしまって、jQueryでご飯を食べたいくらいだ(でもそれは無理)。

Ajaxアプリを記述するときに、サーバサイドPHP、フロントエンドjQueryが今のお決まりのスタイル。基本的にはPHPからの応答はjsonを使うのだが、今回とある理由でxmlでデータを返すことにした。ここではまった。

jQuery側では以下のような記述で受け取りたかったのだが、どうしてもデータを処理できない。

$.ajax({
type:’GET’,
url:’index.php’,
dataType:’xml’,
success:function(data){
//JavaScriptによる処理
}
});

dataTypeでxmlを指定すると、動作しないのだ。なぜだ。

なにぶん、JavaScriptはまだまだ初心者なので、さんざんJavaScriptのプログラムを疑った。でも実はPHP側に問題があったなんて・・・。

PHPからは単純にXMLを吐き出していただけなんだが、それがまずかった。通常特別なことをしない限り、PHPによる応答のContent-typeの指定はtext/htmlなはずだが、これがいけない。jQueryはこのHTTPヘッダを読み取り、Ajaxで帰ってくるデータがhtmlであることを期待しているのに、xmlが返ってきてしまったわけで、それで動作しなかったようだ。

PHP側の処理で、以下の一行を加えることで解決できた。

header(‘Content-Type: text/xml; charset=UTF-8′);

PHPでXMLを返すのではなく、単にdata.xmlのように、拡張子xmlのファイルを呼び出すのであれば問題なかったのにね。


守谷市(まちの情報ポータル) 無料アンケートレンタルjpForm.net