昨日作った
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シミュレータをダウンロードしておくのはどうでしょうか。