au と Softbank の input要素や textarea要素内にタグが入っていた場合の表示の違い

2007年12月20日 06:58 au と Softbank の input要素や textarea要素内にタグが入っていた場合の表示の違い

昨日仕事で、携帯からサイトの更新ができる、ちょっとしたCMSツールみたいなのを作っていたんですが、新たな発見があったのでメモ。

作っていたツールというのは「普段PCで更新しているPC向けサイトを、緊急時なんかに外出先でも更新できるようにする」という目的のものです。

ケータイのブラウザでツールにログインして、更新するページの項目を選択。その後表示されるフォームで、コンテンツを携帯から書き換える。というような処理をしています。

で、サイトのコンテンツを更新するツールなので、フォームの input要素や textarea要素には、現在のコンテンツが入った状態で出力されます。
当然、HTMLタグも入っているわけです。下記のような感じ。

<input type="text" name="header" value="<strong>新着情報</strong>" />

<textarea name="content">クリスマス中止のお知らせ!<br />今年のクリスマスは中止!</textarea>

動作確認をしてみると、ソフトバンクのケータイでは input要素や textarea要素内にHTMLタグが入っていても、普通にフォームが表示されました。
auのケータイではアウト。 input要素の value属性内や、textarea要素内の、HTMLタグがある部分で入力欄の内容が終わっちゃいます。

まあ双方一機種ずつしか確認してないので、ソフトバンクでも駄目なケータイがあるかもしれないし、au でも OKなケータイがあるかもしれません。
au とソフトバンクの違いというか、搭載しているブラウザの違いと言うべきでしょうか。
ちなみに、PCで表示した場合、IEだと普通に見れます。
DoCoMo のケータイは持ってないので確かめてません。

どっちにしろ、これは横着した結果こうなったというだけで、ほんとは全部「<」は「&lt;」、「>」は「&gt;」と出力するべきです。

というわけで、そのフォームを出力する前に、

$content =~ s/</&lt;/g;
$content =~ s/>/&gt;/g;

みたいにしてから、

print qq|<input type="text" name="header" value="$content" />\n|;

とか、

print qq|<textarea name="content">$content</textarea>\n|;

とやれば、au でもちゃんと表示できました。

ブックマークに追加する
関連するブログ記事
スポンサード リンク
カテゴリー
perl/CGI | モバイル(携帯電話・ケータイ)Web
タグ
au | input要素 | perl | textarea要素 | xhtml | ソフトバンク | モバイル | 実体参照 | 正規表現

コメント(2) | トラックバック(0)

 

PostgreSQLで複数のテーブルを結合して処理する方法

今日は久々に旧ブログから記事を引っ張ってきました。

以下は二年以上前に書いたブログ記事の転載です。


新鮮なネタがないので、ストックの中からPostgreSQLネタでも。
というわけで、PostgreSQLで複数のテーブルを結合して処理する方法のメモです。

「複数のテーブルを結合して集計する」というのがどういう意味かと言うと、例えばまず会員制のショッピングサイトなどでユーザーの情報を管理するDBがあると仮定します。
で、一つ目のテーブル「TABLE1」には下記のように、ユーザーID・ユーザーの氏名・ユーザーのメールアドレス等の基本情報が格納されているとします。

TABLE1
UserID UserName MailAddress
Amethyst 鬼瓦 権三郎 amethyst@amethyst-web.org
Alexandrite 俵田山 兼松 alexandrite@amethyst-web.org
Sapphire 平等院 鳳凰堂 sapphire@amethyst-web.org

次に、二つ目のテーブル「TABLE2」には、各ユーザーの購入商品の情報が格納されているとします。
例えば、注文ID・注文者のユーザーID・商品名・商品価格etc。

TABLE2
OrderID UserID ItemName ItemPrice
1 Amethyst 扇風機 2980
2 Amethyst エアコン 99800
3 Sapphire コーヒーメーカー 2800
4 Amethyst 電気コタツ 5800
5 Alexandrite 上戸彩写真集 4800
6 Sapphire マグカップ 1200
7 Alexandrite エロマンガ 980

さて、上記の注文商品の情報が格納されたTABLE2のデータを元に、注文したユーザー宛に一括で受注確認のメールを送信するプログラムを作りたい時、どうすれば良いでしょうか。

単純に処理しようと思えば、まずTABLE2のデータを一行ずつ取得し、その情報の中からユーザーIDを取得し、次にそのユーザーIDをキーにしてTABLE1からメールアドレスを取得、という流れになります。
perlで書くと、下記のような感じ

#-- TABLE2のデータを取得
$SQLstat1 = $DB->prepare("select OrderID, UserID, ItemName, ItemPrice from TABLE2");
#-- 一行ずつ処理する
while(@DATA = $SQLstat1->execute){
    #-- 取得したデータを変数にセット
    ($OrderID,$UserID,$ItemName,$ItemPrice) = @DATA;
    #-- $UserIDをキーにしてTABLE1のデータを取得
    $SQLstat2 = $DB->prepare("select UserName, MailAddress from TABLE1 where UserID = '$UserID'");
    #-- 取得したデータを変数にセット
    ($UserName,$MailAddress) = $SQLstat->execute;
    #-- 以下にメール送信の処理が入る
    &SendMail;
}

※上記の処理の場合は、実際にはプレースホルダを使った方が良いと思いますが、ここでは処理の流れをわかりやすくするために敢えてこういう記述にしました。

さて、上記のスクリプトの場合は一つ目のselect文の中で何度も別のselect文を発行していることになります。
が、select文にinner joinという句を使うと、一度のSQL文で上記の処理を済ますことができます。
↓こんな感じ。

#-- TABLE2のデータを元にTABLE1からUserIDをキーにしてデータを取得
$SQLstat = $DB->prepare("select TABLE2.OrderID, TABLE2.UserID, TABLE2.ItemName,
 TABLE2.ItemPrice, TABLE1.UserName, TABLE1.MailAddrss
 from TABLE2 inner join TABLE1 on TABLE2.UserID = TABLE1.UserID");
#-- 一行ずつ処理する
while(@DATA = $SQLstat->execute){
    #-- 取得したデータを変数にセット
    ($OrderID,$UserID,$ItemName,$ItemPrice,$UserName,$MailAddress) = @DATA;
    #-- 以下にメール送信の処理が入る
    &SendMail;
}

上記スクリプトの
from TABLE2 inner join TABLE1 on TABLE2.UserID = TABLE1.UserID
の部分がポイントです。
これは「TABLE2とTABLE1を結合するよ。条件として"TABLE2のUserIDとTABLE1のUserIDが同じ"データを結合してね」
ということです。
ちなみに、上記select文で出てくる TABLE2.OrderID とか TABLE1.UserID とかはそれぞれ「TABLE2内のOrderID」「TABLE1内のUserID」を表します。

このinner join句は、select文だけではなくupdate文にも使えますので何かと便利です。
delete文には使った記憶がないのでよくわかりません。多分使えるんじゃないですかね?

ブックマークに追加する
関連するブログ記事
カテゴリー
PostgreSQL | perl/CGI
タグ
inner join | perl | PostgreSQL | RDBMS | SQL | コマンドライン | シェル

コメント(0) | トラックバック(0)

 

perl の CGI や PHP でファイルをアップロードする方法

フォームからファイルをアップロードして、そのファイル自体をサーバーに保存したり、あるいはファイルの内容をデータベースに反映したりするようなスクリプトも、作る機会がかなり多いので、手順をメモしておきます。

フォームの html

ファイルをアップロードさせるフォームの場合、通常の form 要素とは違って、enctype 属性をつける必要があります。

<form method="POST" action="upload.cgi" enctype="multipart/form-data">
  <!-- ここにフォームの内容が入る -->
  <input type="file" name="uploadfile" value="" size="20" />
  <input type="submit" value="アップロード" />
</form>

enctype 属性の他に注意する点としては、必ず POST メソッドを指定することが挙げられます。
GET メソッドではファイルのアップロードはできません。

アップされたファイルの受け取り方 (perl の場合)

僕自身は昔、まだ CGI.pm が perl の標準モジュールじゃなかった頃に作ったコードで、アップされたファイルの内容を受け取る処理をすることが多いですが、今は CGI.pm が標準モジュールとして最初から入っているので、これを使うのが手っ取り早いでしょう。

下記サイトが参考になります。

アップされたファイルの受け取り方 (PHP の場合)

PHP の場合は、非常に簡単です。
定義済変数 $_FILES に、アップロードされたファイルの情報が自動的に入ります。

例えば、

<form method="POST" action="upload.cgi" enctype="multipart/form-data">
  <input type="file" name="uploadfile" value="" size="20" />
</form>

のように、アップロードするファイルの入力欄の名前を uploadfile とした場合、変数 $_FILES は以下のように参照できます。

$_FILES['uploadfile']['name']
元のファイル名
$_FILES['uploadfile']['type']
ファイルの MIME-Type
$_FILES['uploadfile']['size']
ファイルのサイズ (バイト単位)
$_FILES['uploadfile']['tmp_name']
アップロードされたファイルのテンポラリ(一時)ファイルの名前(パス)

後は、サーバー上でファイルを保存するなら、 $_FILES['uploadfile']['tmp_name'] をどこかにコピーすれば良いし、ファイルが CSV 等で、その中身を見て何らかの処理をするなら、$_FILES['uploadfile']['tmp_name'] を開いて中身を読めば良いわけです。

ブックマークに追加する
関連するブログ記事
カテゴリー
PHP | perl/CGI
タグ
CGI | CGI.pm | enctype属性 | form要素 | input要素 | MIME | perl | PHP | xhtml | アップロード

コメント(0) | トラックバック(0)

 

SEO対策として使われる、perl の CGI や PHP に GET で渡す値を「/」(スラッシュ)で区切る方法

よく「CGI や PHP は SEO に不利だ!」なんてことが言われますが、これは技術的なことをよく理解していない人に向けて、難しいことを極端に省略した説明なので、大きな誤解を孕んでいます。

正確には、

http://www.abe-tatsuya.com/aaa.cgi?v1=bbb&v2=ccc

のようなURIの、CGI や PHP に値を GET メソッドで渡す「?v1=bbb&v2=ccc」といった部分が問題なわけです。
こういった値を渡さない、シンプルな URI であれば、拡張子が何であろうが関係はないはずです。

なので、逆に CGI や PHP でなく、拡張子が .html であっても、

http://www.abe-tatsuya.com/aaa.html?v1=bbb&v2=ccc

のような URI なら、同様に検索エンジン側から「これは動的なURIだ」と判断されて、低く評価されるはずです。
(アクセス解析目的とか、ページ側で JavaScript 等で何かの処理をする際に、こういう手法を取ることはあり得ますよね)

で、そういった CGI や PHP 等に、GET メソッドで値を渡した結果によって表示する内容を変えるようなコンテンツの場合、検索エンジンから低く評価されることを避けるために、下記のような URI で処理することが多いです。

http://www.abe-tatsuya.com/aaa/bbb/ccc

最初の例との違いは、以下の通りです。

  1. 「aaa.cgi」の拡張子「.cgi」がない
  2. 「ここからが GET メソッドで渡す値ですよ」という意味の記号「?」がなく、代わりに「/」で区切っている
  3. GET メソッドで渡す値の名前(「v1=」「v2=」)がない
  4. GET メソッドで渡す値の区切りの記号「&」がなく、代わりに「/」で区切っている

これで、一見して動的な URI ではなく、単なるディレクトリ内にあるファイルの URI のように見せることができるわけです。

これを実現するためにやらないといけないことは、

  1. 「aaa」という拡張子のないファイルが、CGI または PHP のスクリプトであることをサーバーに教えてあげる
  2. 「aaa」のスクリプト内で、「/」区切りで渡される値を受け付ける処理を書く

大きく分けて、この二点です。

拡張子のないファイルを CGI や PHP として動作させる方法

「aaa」のような拡張子のないファイルを、CGI または PHP として動作させるには、.htaccess を使います。

特定のファイルに対するアクセス制限や、.htaccess で特定のファイルのみにBasic認証を設定する方法の応用で、

<Files aaa>
ForceType cgi-script
</Files>

と書けば、「aaa」というファイルが CGI として実行されます。

PHP として実行したい場合は、

<Files aaa>
ForceType application/x-httpd-php
</Files>

と書けば、「aaa」というファイルが PHP として実行されます。

perl の CGI や PHP で、「/」(スラッシュ)で区切られた値を受け取る方法

とりあえず「aaa」のようなファイル名のスクリプトが動くようになりました。
次は「/bbb/ccc」のような、一見ただのディレクトリへのリクエストのように見える URI を、スクリプトに渡される値として処理するための方法です。

これには、環境変数 PATH_INFO を参照します。

例えば、perl の CGI である「http://www.abe-tatsuya.com/aaa」に対して、「/bbb/ccc」という値を渡す、つまり、「http://www.abe-tatsuya.com/aaa/bbb/ccc」という URI にアクセスさせる場合、「aaa」というスクリプトの中で、$ENV{'PATH_INFO'}を参照すると、その内容は「/bbb/ccc」となります。

なので例えば、「aaa」という CGI スクリプトの最初のほうに、

#-- PATH_INFO を「/」で分けて配列に格納
@params = split(/\//,$ENV{'PATH_INFO'});
shift(@params);

等とすれば、$params[0],$params[1]... の順番に、「/」区切りで渡された値が入ります。

PHP の場合は、$_SERVER['PATH_INFO']を参照すれば、同様に処理できます。

// PATH_INFO を「/」で分けて配列に格納
$params = split("/",$_SERVER['PATH_INFO']);
array_shift($params);

これで、perl と同様に、$params[0],$params[1]...の順番に、「/」区切りで渡された値が入ります。

後は、渡された値に応じて、出力内容を変えるように色々とスクリプトを書けば OK です。

ブックマークに追加する
関連するブログ記事
カテゴリー
.htaccess | PHP | SEO(検索エンジン最適化) | perl/CGI
タグ
.htaccess | CGI | ForceType | GETメソッド | PATH_INFO | perl | PHP | SEO | 環境変数

コメント(0) | トラックバック(1)

 

ケータイの端末識別情報を取得する方法

「IDとパスワードを使ってログインする」というステップを省略するために、PC用のWeb上のサービスやシステムでは Cookie を使うことがよくあります。

ところがPCと違ってケータイは、Cookieに対応していない端末が多数を占めます。
そのため、ケータイ向けのWeb上のサービスやシステムを作る際、ログインを簡略化するために、「サブスクライバID」とか「端末シリアル番号」とか「固体識別情報」とか呼ばれるものを使うことが、よくあります。

これは、それぞれの携帯電話個別に、電話番号とは別に割り振られた固有のIDのようなもので、多分 mixi の「かんたんログイン」とかも、これを取得して認証しているはず。

DoCoMo と Softbank は未確認ですが、少なくとも au の場合は、機種変更をしても、この番号は引き継がれるので、ケータイ所有者個人を識別するためにはかなり有効です。

ただし、どこのキャリアかは知りませんが、「解約して使われなくなった端末識別情報が、別の誰かに割り振られることがある」なんてことを聞いたことがあるので、この端末識別情報に頼りすぎたログイン認証システムは、安全ではないかもしれないことも付記しておきます。

DoCoMo の iモード端末の固体識別情報

html の a要素や form要素に utn属性 をつけることによって、そのリンクや送信ボタンをクリックした際に、サーバーに固体識別情報が送信されます。
なお、送信される前に端末側には「固体識別情報を送信しますか?」みたいな確認ダイアログが表示され、同意した場合のみ送信されます。

<!-- a要素の場合 -->
<p><a href="http://www.abe-tatsuya.com/login.cgi" utn>ログイン</a></p>

<!-- form要素の場合 -->
<form method="POST"
action="http://www.abe-tatsuya.com/login.cgi" utn>
  <input type="submit" value="ログイン" />
</form>

本当は valid な xhtml にするために、utn="utn" としたいところなんですが、ケータイというのは機種ごとに仕様が異なっていたりして、「utn="utn"」という書き方だと正常に動作してくれない機種なんかもありそうで怖いので、DoCoMo の utn属性の説明ページの通りに書いています。
全機種の動作確認ができる機会も、まずないですし……。

このエントリーのコメントでご指摘頂いた通り、i-mode HTML/XHTML 比較表を見ると、「utn="utn"」という書き方で大丈夫なようです。
コメント頂いたyurikoさん、ありがとうございました。

で、サーバー側に送られてくる固体識別情報はどこに含まれているかというと、User-Agent ヘッダに含まれています。

非FOMA端末の場合、固体識別情報を含んだ User-Agent は以下のようになります。

DoCoMo/1.0/X503i/c10/ser***********

「ser***********」の「***********」の部分には、11桁の英数字が入り、これが固体識別情報に当たります。

perl でこれを取得しようとすると、以下のような感じでしょうか(普段自分が使ってるソースは、他のサブルーチンから渡される変数を色々使ってて、ブログに掲載しても可読性が低いと思われるので新たに書きました。以下のソースは動作確認を全くしてません)。

if($ENV{'HTTP_USER_AGENT'} =~ /^DoCoMo\/1\.0\/.*\/(ser\w{11})$/){
	#-- 固体識別情報を変数に代入
	$mobile_id = $1;
}

FOMA端末の場合は「携帯電話の製造番号」と「FOMAカードの製造番号」の二種類の固体識別情報が取得できます。
「携帯電話の製造番号」の方は、機種変更をしたら変わってしまうと思うんですが、「FOMAカードの製造番号」の方は、多分機種変更をしても、FOMAカードが同一であれば変わらないはず。

FOMA端末の、固体識別情報を含んだ User-Agent は以下の通り。

DoCoMo/2.0 YYYY(c10;serXXXXXXXXXXXXXXX; iccxxxxxxxxxxxxxxxxxxxx)

「serXXXXXXXXXXXXXXX」の部分が携帯電話の製造番号で、「XXXXXXXXXXXXXXX」には15桁の英数字が入ります。
「iccxxxxxxxxxxxxxxxxxxxx」の部分がFOMAカードの製造番号で、「xxxxxxxxxxxxxxxxxxxx」には20桁の英数字が入ります。

用途にもよりますが、基本的には FOMAカードの製造番号を取得した方が便利ですかね。
FOMAカードの製造番号を取得する perl のスクリプトは以下(上の同じく、以下のソースは動作確認を全くしてません)。

if($ENV{'HTTP_USER_AGENT'} =~ /^DoCoMo\/2\.0 .*; (icc\w{20})\)$/){
	#-- 固体識別情報を変数に代入
	$mobile_id = $1;
}

au の EZweb 端末のサブスクライバID

au の場合は、自動的にサブスクライバIDと呼ばれる X_UP_SUBNO ヘッダを、サーバーに送信しています。

ただし、ユーザー側がこのヘッダを「通知しない」という設定にしている場合は、送信しません。
通知設定に関しては、au 公式サイトのお知らせにあります。

サーバーに送信される X_UP_SUBNO ヘッダは、以下のようなフォーマットになっています。

xxxxxxxxxxxxxx_**.ezweb.ne.jp

最初の「xxxxxxxxxxxxxx」の部分が14桁の数字で、端末固有の番号にあたるようです。
※参考: モバイルCGI研究(EZweb編)環境変数リファレンス [CGIぽん]

サブスクライバIDを取得する perl スクリプトは以下の通り(同様に以下のソースは動作確認を全くしてません)。

if($ENV{'HTTP_X_UP_SUBNO'} =~ /^(\d{14})_\w{2}\.ezweb\.ne\.jp$/){
	#-- サブスクライバIDを変数に代入
	$mobile_id = $1;
}

Softbank 端末の端末シリアル番号

Softbank の端末の場合、ユーザーが「ユーザーID通知」または「製造番号通知」の設定を on にしていれば、端末シリアル番号というものが User-Agent に含まれます。

端末の世代によって、フォーマットが異なってややこしいですが、ソフトバンクの公式サイトのユーザーエージェントについての説明によると、以下のようなパターンがあるらしいです。

#-- SoftBank 6-5 Series
J-PHONE/4.0/J-SH51/SN************ SH/0001a Profile/MIDP-1.0 Configuration/CLDC-1.0
Ext-Profile/JSCL-1.1.0

#-- SoftBank 3G Series (Vodafone時代の端末)
Vodafone/1.0/V904SH/SHJ001/SN************ Browser/VF-NetFront/3.3 Profile/MIDP-2.0 
Configuration/CLDC-1.1
#-- SoftBank 3G Series (Softbank時代の端末)
SoftBank/1.0/910T/TJ001/SN************ Browser/NetFront/3.3 Profile/MIDP-2.0 
Configuration/CLDC-1.1

「SN************」の部分が端末シリアル番号で「************」には11~15桁の英数字が入るようです。

端末シリアル番号を取得する perl スクリプトは、ちょっといいかげんですが以下のような感じ(同様に以下のソースは動作確認を全くしてません)。

if($ENV{'HTTP_USER_AGENT'} =~ /^(J\-PHONE|Vodafone|Softbank)\/.*\/(SN\w{11,15}) .*/){
	#-- 端末シリアル番号を変数に代入
	$mobile_id = $2;
}

端末識別情報に頼りすぎないこと

ログイン認証を端末識別情報に依存しすぎたせいで、「機種変更したらログインできない」なんていう事態に陥ったサービスを知っています。

また、たまたま携帯事業者側の都合で、全く同じ番号の端末識別情報が複数の端末に割り振られた、なんてケースも聞いたことがあります。

ケータイは文字入力が不便なインターフェイスなので、ログインの簡略化のために端末識別情報を使うのは、ユーザーの利便性向上のためにも、良いことだとは思うのですが、認証をこれだけに頼るのは、ちょっと危険かもしれません。

ブックマークに追加する
関連するブログ記事
カテゴリー
perl/CGI | モバイル(携帯電話・ケータイ)Web
タグ
au | a要素 | Cookie | DoCoMo | form要素 | HTTPヘッダ | perl | User-Agent | utn属性 | xhtml | X_UP_SUBNO | アクセス制限 | サブスクライバID | ソフトバンク | モバイル | 固体識別情報 | 正規表現 | 環境変数 | 端末シリアル番号

コメント(2) | トラックバック(0)

 

メール受信時に perl スクリプトを起動して自動処理させる方法

メールが届くと同時に何らかのアクションを起こすプログラムというのは、かなり作る機会の多い部類に入るかと思います。

ここ数年で特に多いものだと、ケータイ向けサイトの案件で、空メールを受信したら自動でユーザー登録用のフォームのアドレスを書いたメールを、空メール送信者に送る、みたいなものとか、ブログやSNSの日記なんかを、ケータイメールで投稿できるようにする処理とかですね。
そして王道の自動返信メールとか。

後、途中で飽きちゃったんですが、昔、送られてくるメールの内容を自分で学習して言葉を覚えて、文章を生成して返信する bot (人工無脳)を趣味で作ってたことがあります。

で、実際こういう「メールを受け取ったら何らかの処理を自動で行なう」という機能を実現するには、どうすれば良いかというと、

  1. 特定のメールアカウントにメールが届いた際に、何らかのプログラムが起動するように設定する
  2. そのプログラムを書く

という二つのステップが必要になります。

まずは、この1ステップ目の「特定のメールアカウントにメールが届いた際に、何らかのプログラムが起動するように設定する」方法について、簡単にまとめてみます。

aliases を使う場合

aliases の設定と使い方についてのメモにも書きましたが、下記のようにすることで、特定のアカウントに届いたメールを、パイプを使って直接何らかのプログラムに渡して実行することができます。

entry: "|/home/tatsuya/entry.pl"

上記の例では、「entry」というメールアカウントにメールが届いた際に、自動的に「/home/tatsuya/entry.pl」という perl スクリプトが起動するように設定しています。

~/.forward を使う場合

サーバーの各ユーザーアカウント毎に、個別に設定が可能な ~/.forward を使う場合は(レンタルサーバーを使う場合はこちらの方が利用する機会が多いかもですね)、~/.forward に以下のように書けばOKです。

"|exec /home/tatsuya/entry.pl"

procmail を使う場合

届いたメールに対して、自動でマッチング処理等を行なって、結果によって行なう処理を振り分けてくれる便利な存在である procmail を使う場合は、~/.procmailrc に以下のように書きます。

:0 :
* ^To: entry
| /home/tatsuya/entry.pl

^To: entry」の部分は正規表現が使えるので、メールのヘッダ(FromやSubject等)に対して細かい条件を設定して振り分けることで、一つのメールアカウントで様々な処理を行なうことができるのも良いですね。

メールを処理する perl スクリプトの書き方

さて、続いて第2ステップ「そのプログラムを書く」の部分です。

aliases、~/.forward、procmail の三種類の設定方法を紹介しましたが、どの方法を用いても、「指定したプログラムの標準入力に、受け取ったメールの内容を渡す」というのは同じです。

つまり、受け取る側の perl スクリプトでは、標準入力の内容を読めば良いだけです。

while(<STDIN>){
	#-- 「$_」にメールの内容(ヘッダも本文も添付ファイルも全て)が
	#-- 一行ずつ代入されていくので、正規表現とかを使って色々処理する
}

これだけです。

後は、「メール送信者のアドレスをデータベースに登録しておいて、ユーザー登録用のURIを生成してメールを返信する処理を書く」とか、「メール送信者のアドレスからユーザーIDを引っ張ってきて、メール本文の内容をそのユーザーIDの日記に投稿させる」とか、「本文を形態素解析して、内容を bot (人工無脳)に覚えさせる」とか、色々とやれば良いわけです。

ブックマークに追加する
関連するブログ記事
カテゴリー
Linux/UNIX | perl/CGI
タグ
.forward | aliases | perl | procmail | sendmail | SMTP | UNIX | ケータイメール | コマンドライン | メール | モバイル | レンタルサーバー | 人工無脳

コメント(0) | トラックバック(1)

 

perl の CGI や PHP でよく出力する Content-type ヘッダ一覧 (MIME-type)

ここ数日、perlやPHPでファイルのダウンロード確認ダイアログを表示させる方法へのアクセスが、すば抜けて多いです。

こういうスクリプトを書こうとしている人って多いんでしょうか。

なので、件のエントリーの補完ということで、今回は perl の CGI や PHP で個人的によく出力する or 今後出力する機会がありそうな Content-type ヘッダをまとめておきます。
まとめとけば自分が後で一番楽だし。

テキスト・文書・MSオフィス関連

ファイルの種類 拡張子 MIME-Type
テキスト文書 .txt text/plain
CSVファイル .csv text/csv
TSVファイル .tsv text/tab-separated-values
ワード文書 .doc application/msword
エクセルシート .xls application/vnd.ms-excel
パワーポイント .ppt application/vnd.ms-powerpoint
PDF文書 .pdf application/pdf
Docuworks .xdw application/vnd.fujixerox.docuworks
HTML文書 .html .htm text/html
スタイルシート .css text/css
JavaScriptファイル .js text/javascript
HDML文書 .hdml text/x-hdml

画像関連

ファイルの種類 拡張子 MIME-Type
JPEG .jpg .jpeg image/jpeg
PNG .png image/png
GIF .gif image/gif
ビットマップ .bmp image/bmp
イラストレーター .ai application/postscript

音声関連

ファイルの種類 拡張子 MIME-Type
MP3 .mp3 audio/mpeg
MP4 .m4a audio/mp4
WAV .wav audio/x-wav
MIDI .mid .midi audio/midi
SMAF .mmf application/x-smaf

動画関連

ファイルの種類 拡張子 MIME-Type
MPEG .mpg .mpeg video/mpeg
WMV .wmv video/x-ms-wmv
Flash (Shockwave) .swf application/x-shockwave-flash
3GPP2 .3g2 video/3gpp2

圧縮ファイル関連

ファイルの種類 拡張子 MIME-Type
ZIP形式 .zip application/zip
LZH形式 .lha .lzh application/x-lzh
tar / tar+gzip形式 .tar .tgz application/x-tar

その他

ファイルの種類 拡張子 MIME-Type
実行ファイル .exe application/octet-stream

perl なら出力の一番最初に、

print qq|Content-type: MIME-Type\n|;

PHPなら出力の一番最初に、

header("Content-type: MIME-Type");

とやれば良いわけです。

ブックマークに追加する
関連するブログ記事
カテゴリー
PHP | perl/CGI
タグ
CGI | Content-type | HTTPヘッダ | MIME | perl | PHP | RFC | ダウンロード

コメント(0) | トラックバック(2)

 

Yahoo!モバイルのjigブラウザ機能の問題点と、perlとPHPでのjigブラウザのUser-Agent振り分け方法

「ケータイでPCのサイトが閲覧できる!」という謳い文句の割に、所謂「フルブラウザ」と比較しても機能的に中途半端で(特にJavaScript非対応はイタい)、個人的にはあんまり使い物にならないと思っている jigブラウザ。

同一URLで、User-Agentを元にして、ケータイとPCを自動で振り分ける際に、jigブラウザをPCサイト側に振り分けると、サイトの構成によっては、あまりいただけないことになってしまいます。

特に問題なのが、ケータイ版のYahoo!検索「Yahoo!モバイル」で検索した際に「PCサイトとの一致」でヒットしたサイトは、自動的にjigブラウザで表示されてしまうこと。

Yahoo!モバイルのインデックスが微妙なせいで、ケータイサイトとPCサイトを同一URLで公開していると、「携帯サイトとの一致」ではヒットしないけど「PCサイトとの一致」ではヒットする、みたいなことも起こりうるんですよね。

「PCサイトとの一致」でヒットしたサイトを、自動でjigブラウザで表示するのは基本的には便利な機能なんですが……。
こっちはちゃんとケータイに合わせた仕様でのサイトを提供しているんだから、わざわざ中途半端な機能しかないjigブラウザでPCサイト見るくらいなら、普通にケータイ用のブラウザでケータイ向けサイトを見てもらった方が、まともにサイト内のコンテンツを利用することができるわけです。

そういうわけで、jigブラウザからのアクセスの場合は、それを判別して、サイト内に注意書きを自動で入れるとか、そもそもjigブラウザでもケータイ向けサイトを表示するようにするとか、そんな対処が必要になります。

「Yahoo!モバイル」等で提供されている「jigブラウザ WEB」のデフォルトのUser-Agentは、

Mozilla/4.0 (jig browser web; version; 機種名

という感じです。
version」はjigブラウザのバージョン。「1.0.4」みたいな数字が入る。
機種名」は利用している携帯の機種名。「F904i」「812SH」みたいなのが入る。

なのでとりあえず、User-Agent内に「jig browser web」が含まれている場合はjigブラウザだと判断して、何らかの処理をするのが手っ取り早いかと思います。

perlなら、

if($ENV{'HTTP_USER_AGENT'} =~ /jig browser web/){
	#-- ここにjigブラウザの場合の処理
}

PHPなら、

if(preg_match("/jig browser web/",$_SERVER['HTTP_USER_AGENT'])){
	// ここにjigブラウザの場合の処理
}

こんな感じで。

ちなみに、GoogleもPCサイトの検索結果に出たサイトを携帯で見る場合、独自のブラウザを介して表示しますが、こっちは未調査です。
そのうち調べます。

ブックマークに追加する
関連するブログ記事
カテゴリー
PHP | perl/CGI | モバイル(携帯電話・ケータイ)Web
タグ
jigブラウザ | perl | PHP | User-Agent | Yahoo!モバイル | YST | モバイル | 環境変数

コメント(0) | トラックバック(0)

 

perlやPHPでファイルのダウンロード確認ダイアログを表示させる方法

perlやPHPを使って、ユーザーにWebブラウザから何らかのファイルをダウンロードしてもらうスクリプトというのは、作る機会も結構多いかと思います。

しかし、ダウンロードしてもらうファイルがjpegやpng、gif等の画像ファイルだったり、PDFやワード・エクセル等のファイルだったり、音声や動画ファイルだったり等、ブラウザでそのまま閲覧できるファイルだった場合、ローカルにダウンロードするダイアログが出ずに、そのままブラウザに表示されてしまうことがよくあります。

そういう場合、「『右クリック⇒対象をファイルに保存』でローカルに保存できます」なんて注意書きをつけて、そのCGIやPHPスクリプトにリンクを張ることも多いかもしれませんね。

この現象は、CGIやPHPからブラウザに送信するHTTPヘッダを少し変えることで、避けることが可能です。
(ただし、ブラウザによっては駄目かも……)

具体的には、以下のようなHTTPヘッダを送信します。

Content-Disposition: attachment; filename="sample.jpg"

sample.jpg」の部分には、ファイルのダウンロードダイアログにデフォルトで表示される、保存先ファイル名を指定します。

これを踏まえて、perlである特定のjpeg画像を、ダウンロード確認ダイアログを表示させてダウンロードさせる場合は、以下のようになります。

#-- ダウンロードさせる元ファイル
$source = '/home/tatsuya/data/img/00001.jpg';
#-- 保存時のファイル名(デフォルト)
$filename = 'uetoaya.jpg';

#-- HTTPヘッダ送信
print qq|Content-type: image/jpeg\n|;
print qq|Content-Disposition: attachment; filename="$filename"\n|;
print qq|\n|;
#-- ファイルを読み込んで出力
open(FILE,"$source");
while(<FILE>){print;}
close(FILE);

PHPの場合は、以下のような感じ。

// ダウンロードさせる元ファイル
$source = '/home/tatsuya/data/img/00002.jpg';
// 保存時のファイル名(デフォルト)
$filename = 'aibusaki.jpg';

// HTTPヘッダ送信
header("Content-type: image/jpeg");
header("Content-Disposition: attachment; filename=\"{$filename}\"");
// ファイルを読み込んで出力
readfile($source);

何らかのWebアプリケーションのバックアップデータなんかをダウンロードする場合とかは、保存時のファイル名を「ダウンロード時の日付.txt」みたいな感じにするようにしとくと便利かもですね。

ブックマークに追加する
関連するブログ記事
カテゴリー
PHP | perl/CGI
タグ
CGI | Content-Disposition | Content-type | HTTPヘッダ | perl | PHP | ダウンロード

コメント(0) | トラックバック(0)

 

perlのCGIでよく利用する環境変数一覧

タイトル通り、perlの、特にCGIでよく使う環境変数の一覧です。

ちなみに、perlの環境変数は連想配列 %ENV に格納されていて、 $ENV{'REMOTE_ADDR'} 等として参照できます。

REMOTE_ADDR
スクリプトを実行したクライアントのリモートアドレス(IPアドレス)。
REMOTE_HOST
スクリプトを実行したクライアントのリモートホスト。
HTTP_USER_AGENT
スクリプトを実行したクライアントのユーザーエージェント
HTTP_COOKIE
スクリプトを実行したクライアントのCOOKIEの値
HTTP_HOST
リクエストされたURIのホスト名。
REQUEST_METHOD
スクリプトを実行したメソッド。GET、POST、HEAD等。
CONTENT_LENGTH
POSTメソッドで渡されたデータの長さ。
QUERY_STRING
GETメソッドで渡されたクエリの内容。所謂「●●.cgi?■■■」の■■■の部分。
PATH_INFO
リクエストされたURIのパス。最近流行の、SEOを意識してGETメソッドではなく「/」区切りでデータをCGIに渡す手法を使う際には、これを参照することが多い。
SCRIPT_NAME
実行されたスクリプトのURI上の「/」からのパス。
SCRIPT_FILENAME
実行されたスクリプトのルートからのパス。
SERVER_PORT
通信に利用したサーバーのポート。SSLと非SSLでのアクセスの判断等に使ったりする。