昨日作った
M.C.P.C.: ケータイ3キャリア別URLに振り分けるPerlのCGI
ですが、よくかんがえると今月末(2012年3月31日)でdocomoのムーバ(PDC)が停波になるのです。そうすると、別にCHTMLで作る必要はなくね? XHTMLで作ればよくね? となります。厳密にいえば、900i以前のモデル(東芝とかの4ケタ型番のやつとか)はXHTMLはだめらしいのですけれども、実質試験機みたいなものだったので(すこぶるでかい)、コンテンツが見れなくてもしゃーなしだと思います。
というわけで、3キャリア対応でXHTMLで表示URLを振り分けるPerl CGIを作りました。ポイントは、docomoのXHTMLの古い仕様で、外部CSSファイルは使えないという制約があるのですが、PerlのHTML::MobileJpCSSでdocomo端末の時だけインラインCSSに展開してしまう、ていうところです。これにより3社対応ページが共通のHTMLとCSSで作ることができるようになりました。
Filename: index.cgi
#!/usr/bin/perl use strict; use warnings; use utf8; use CGI; use Encode; use Encode::JP::Mobile qw(:props); use File::Spec; use FindBin::Real; use HTML::Template; use HTTP::MobileAgent; use HTTP::MobileAgent::Plugin::Charset; use HTML::MobileJpCSS; my $basedir = FindBin::Real::Bin(); my $q = CGI->new(); my $agent = HTTP::MobileAgent->new; my $inliner = HTML::MobileJpCSS->new( base_dir => "$basedir"); my $emoticons = { 'E63E' => 'sun', 'E63F' => 'cloud', 'E640' => 'rain', 'E641' => 'snow', 'E642' => 'thunder', 'E643' => 'typhoon', 'E644' => 'mist', 'E645' => 'sprinkle', 'E646' => 'aries', 'E647' => 'taurus', 'E648' => 'gemini', 'E649' => 'cancer', 'E64A' => 'leo', 'E64B' => 'virgo', 'E64C' => 'libra', 'E64D' => 'scorpius', 'E64E' => 'sagittarius', 'E64F' => 'capricornus', 'E650' => 'aquarius', 'E651' => 'pisces', 'E652' => 'sports', 'E653' => 'baseball', 'E654' => 'golf', 'E655' => 'tennis', 'E656' => 'soccer', 'E657' => 'ski', 'E658' => 'basketball', 'E659' => 'motorsports', 'E65A' => 'pocketbell', 'E65B' => 'train', 'E65C' => 'subway', 'E65D' => 'bullettrain', 'E65E' => 'car', 'E65F' => 'rvcar', 'E660' => 'bus', 'E661' => 'ship', 'E662' => 'airplane', 'E663' => 'house', 'E664' => 'building', 'E665' => 'postoffice', 'E666' => 'hospital', 'E667' => 'bank', 'E668' => 'atm', 'E669' => 'hotel', 'E66A' => '24hours', 'E66B' => 'gasstation', 'E66C' => 'parking', 'E66D' => 'signaler', 'E66E' => 'toilet', 'E66F' => 'restaurant', 'E670' => 'cafe', 'E671' => 'bar', 'E672' => 'beer', 'E673' => 'fastfood', 'E674' => 'boutique', 'E675' => 'hairsalon', 'E676' => 'karaoke', 'E677' => 'movie', 'E678' => 'upwardright', 'E679' => 'carouselpony', 'E67A' => 'music', 'E67B' => 'art', 'E67C' => 'drama', 'E67D' => 'event', 'E67E' => 'ticket', 'E67F' => 'smoking', 'E680' => 'nosmoking', 'E681' => 'camera', 'E682' => 'bag', 'E683' => 'book', 'E684' => 'ribbon', 'E685' => 'present', 'E686' => 'birthday', 'E687' => 'telephone', 'E688' => 'mobilephone', 'E689' => 'memo', 'E68A' => 'tv', 'E68B' => 'game', 'E68C' => 'cd', 'E68D' => 'heart', 'E68E' => 'spade', 'E68F' => 'diamond', 'E690' => 'club', 'E691' => 'eye', 'E692' => 'ear', 'E693' => 'rock', 'E694' => 'scissors', 'E695' => 'paper', 'E696' => 'downwardright', 'E697' => 'upwardleft', 'E698' => 'foot', 'E699' => 'shoe', 'E69A' => 'eyeglass', 'E69B' => 'wheelchair', 'E69C' => 'newmoon', 'E69D' => 'moon1', 'E69E' => 'moon2', 'E69F' => 'moon3', 'E6A0' => 'fullmoon', 'E6A1' => 'dog', 'E6A2' => 'cat', 'E6A3' => 'yacht', 'E6A4' => 'xmas', 'E6A5' => 'downwardleft', 'E6AC' => 'slate', 'E6AD' => 'pouch', 'E6AE' => 'pen', 'E6B1' => 'shadow', 'E6B2' => 'chair', 'E6B3' => 'night', 'E6B7' => 'soon', 'E6B8' => 'on', 'E6B9' => 'end', 'E6BA' => 'clock', 'E6CE' => 'phoneto', 'E6CF' => 'mailto', 'E6D0' => 'faxto', 'E6D1' => 'info01', 'E6D2' => 'info02', 'E6D3' => 'mail', 'E6D4' => 'by-d', 'E6D5' => 'd-point', 'E6D6' => 'yen', 'E6D7' => 'free', 'E6D8' => 'id', 'E6D9' => 'key', 'E6DA' => 'enter', 'E6DB' => 'clear', 'E6DC' => 'search', 'E6DD' => 'new', 'E6DE' => 'flag', 'E6DF' => 'freedial', 'E6E0' => 'sharp', 'E6E1' => 'mobaq', 'E6E2' => 'one', 'E6E3' => 'two', 'E6E4' => 'three', 'E6E5' => 'four', 'E6E6' => 'five', 'E6E7' => 'six', 'E6E8' => 'seven', 'E6E9' => 'eight', 'E6EA' => 'nine', 'E6EB' => 'zero', 'E6EC' => 'heart01', 'E6ED' => 'heart02', 'E6EE' => 'heart03', 'E6EF' => 'heart04', 'E6F0' => 'happy01', 'E6F1' => 'angry', 'E6F2' => 'despair', 'E6F3' => 'sad', 'E6F4' => 'wobbly', 'E6F5' => 'up', 'E6F6' => 'note', 'E6F7' => 'spa', 'E6F8' => 'cute', 'E6F9' => 'kissmark', 'E6FA' => 'shine', 'E6FB' => 'flair', 'E6FC' => 'annoy', 'E6FD' => 'punch', 'E6FE' => 'bomb', 'E6FF' => 'notes', 'E700' => 'down', 'E701' => 'sleepy', 'E702' => 'sign01', 'E703' => 'sign02', 'E704' => 'sign03', 'E705' => 'impact', 'E706' => 'sweat01', 'E707' => 'sweat02', 'E708' => 'dash', 'E709' => 'sign04', 'E70A' => 'sign05', 'E70B' => 'ok', 'E70C' => 'appli01', 'E70D' => 'appli02', 'E70E' => 't-shirt', 'E70F' => 'moneybag', 'E710' => 'rouge', 'E711' => 'denim', 'E712' => 'snowboard', 'E713' => 'bell', 'E714' => 'door', 'E715' => 'dollar', 'E716' => 'pc', 'E717' => 'loveletter', 'E718' => 'wrench', 'E719' => 'pencil', 'E71A' => 'crown', 'E71B' => 'ring', 'E71C' => 'sandclock', 'E71D' => 'bicycle', 'E71E' => 'japanesetea', 'E71F' => 'watch', 'E720' => 'think', 'E721' => 'confident', 'E722' => 'coldsweats01', 'E723' => 'coldsweats02', 'E724' => 'pout', 'E725' => 'gawk', 'E726' => 'lovely', 'E727' => 'good', 'E728' => 'bleah', 'E729' => 'wink', 'E72A' => 'happy02', 'E72B' => 'bearing', 'E72C' => 'catface', 'E72D' => 'crying', 'E72E' => 'weep', 'E72F' => 'ng', 'E730' => 'clip', 'E731' => 'copyright', 'E732' => 'tm', 'E733' => 'run', 'E734' => 'secret', 'E735' => 'recycle', 'E736' => 'r-mark', 'E737' => 'danger', 'E738' => 'ban', 'E739' => 'empty', 'E73A' => 'pass', 'E73B' => 'full', 'E73C' => 'leftright', 'E73D' => 'updown', 'E73E' => 'school', 'E73F' => 'wave', 'E740' => 'fuji', 'E741' => 'clover', 'E742' => 'cherry', 'E743' => 'tulip', 'E744' => 'banana', 'E745' => 'apple', 'E746' => 'bud', 'E747' => 'maple', 'E748' => 'cherryblossom', 'E749' => 'riceball', 'E74A' => 'cake', 'E74B' => 'bottle', 'E74C' => 'noodle', 'E74D' => 'bread', 'E74E' => 'snail', 'E74F' => 'chick', 'E750' => 'penguin', 'E751' => 'fish', 'E752' => 'delicious', 'E753' => 'smile', 'E754' => 'horse', 'E755' => 'pig', 'E756' => 'wine', 'E757' => 'shock', }; # テンプレートファイル読み込み my $template = sub { open my $fh, '<', shift or die $!; local $/ = undef; my $s = <$fh>; close $fh; return $s; }->('index.tmpl'); $template = decode_utf8( $template ); $template =~s|\\x{(.+?)}|chr(hex($1))|eg; # 絵文字記述をUnicode文字列に # キャリア別処理 my $params; # TemplateにUserAgent(キャリア名)をまとめて渡す my $carrier; # Templateに渡すキャリア名 if ( $agent->is_docomo ) { $carrier = 'docomo'; } elsif ( $agent->is_ezweb ) { $carrier = 'AU'; } elsif ( $agent->is_vodafone ) { $carrier = 'SoftBank'; } else { $carrier = 'パソコン/スマートフォン'; $params->{pc} = $carrier; $template =~ s{(\p{InMobileJPPictograms})}{ my $char = Encode::JP::Mobile::Character->from_unicode(ord $1); sprintf '<img src="/emoticons/%s.gif" />', $emoticons->{$char->unicode_hex}; }ge; } my $encoding = $agent->encoding; # Encode用のキャリアごとのエンコーディング my $charset = $encoding =~ /sjis/ ? 'Shift_JIS' : 'UTF-8'; # HTML用のcharset my $content = $encoding =~ /x-utf8-docomo/ ? 'application/xhtml+xml' : 'text/html'; $params->{ carrier} = $carrier; # <tmpl_var name="carrier">でdocomoとか表示できる $params->{$carrier} = $carrier; # <tmpl_if name="docomo">でdocomo用処理振り分けできる $params->{ charset} = $charset; # <meta~charset=<tmpl_var name="charset">" /> $params->{ content} = $content; # <meta~content="<tmpl_var name="content">" /> # テンプレート処理 my $t = HTML::Template->new( scalarref => \$template, die_on_bad_params => 0 ); $t->param( $params ); my $html = $t->output; $html = $inliner->apply( $html ); # CSSをキャリアごとに適用するよう書き換え # 出力 print $q->header( -type => $content, -charset => $charset ); print encode( $encoding, $html ); exit; __END__
Filename: index.tmpl
<?xml version="1.0" encoding="<tmpl_var name="charset">"?> <!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" "http://www.wapforum.org/DTD/xhtml-mobile10.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja"> <head> <meta http-equiv="Content-Type" content="<tmpl_var name="content" >; charset=<tmpl_var name="charset">" /> <title>エロいリンク</title> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes," /> <link rel="stylesheet" href="styles.css" /> </head> <body> <div id="hd"> <h1>エロいページ</h1> <h2>ケータイ版リンク集</h2> </div> <hr /> <div> <dl> <dt> <span style="color: #0077ff;">\x{e6e2}</span ><a accesskey="1" href="<tmpl_if name="pc" >http://www.example.com/<tmpl_else><tmpl_if name="docomo" >http://www.example.com/i/</tmpl_if><tmpl_if name="au" >http://www.example.com/e/</tmpl_if><tmpl_if name="softbank" >http://www.example.com/j/</tmpl_if></tmpl_if >">お世話になったVHS</a>\x{E6DD}</dt> <dd> ツメオリのVHS情報がご覧になれます。 </dd> </dl> </div> <hr /> <div id="ft"> <span>©DTPWiki 2012</span> </div> </body> </html>
Filename: styles.css
#ft { text-align: right; font-size: x-small; color: red; }
どうでもいいけれども、ムーバ端末がネットから切り離されると、CHTMLを正確に展開できるのはiモードHTMLシミュレータだけになりそうですが、インターネット上にiモードHTMLブラウザでしか読めない新天地ができたりとか、iモードが絶滅した後の世界で刊行された小説に、「iモードブラウザで隠されたメッセージを探し出す」とかいうのがあったりすると胸アツなので、今のうちにiモードHTMLシミュレータをダウンロードしておくのはどうでしょうか。