標準出力のバッファリングを有効化するPHP関数ob_start

PHPは、WEBブラウザという手近な実行環境を持つプログラミング言語です。そして、WEBブラウザ以外にも実行環境を持つプログラミング言語です。WEB制作の目的でPHPを習得しており、かつPHPが初めてのプログラミング言語である場合などには気付かないかもしれませんが、コマンドライン上でPHPを動かすことも可能なわけです。
したがって、echo命令等が出力する先は、常にWEBブラウザのウィンドウというわけではありません(そもそもWEBブラウザで動いていないPHPがどこのウィンドウに出力するというのでしょう)。echo命令のマニュアルに書いてあるように、出力先はあくまで”標準出力”となっています。

標準出力をバッファリングする

さて、WEBブラウザ上でPHPを実行する場合、この”標準出力”として、WEBブラウザ上のウィンドウが指定してあります。そのおかげあってecho命令はいつもブラウザ上に文字列を吐き出すわけですが、echo命令が吐き出す内容を一時的に変数に入れたい場合や、ファイルに保存したい場合などは、プログラム中でタイミングを指定して、標準出力のバッファリングを行うことが可能です。
標準出力バッファリングのための関数には、output bufferingの略、ob_という接頭辞がついています。プログラム中のバッファリングを開始したいポイントでob_start関数をコールし、バッファリングを停止したいポイントでob_end_clean関数ないしob_end_flush関数を呼びます。

<?php
echo "a";
ob_start();
echo "b";
echo "c";
ob_end_clean();
echo "d";
?>

このプログラムをWEBブラウザで走らせると、ブラウザのウィンドウには”ad”と出力されます。ob_startとob_end_clean関数に挟まれている部分で出力されるべき”bc”は、その間標準出力がジャックされているので表示されません。
一方、終了時の関数をob_end_cleanではなくob_end_flushにした場合、バッファリングの終了時に貯めていた出力内容を標準出力に開放します。そこで、ブラウザの出力は”abcd”となります。

バッファリングした内容を変数に格納する

バッファリングした内容を、そのまま破棄あるいは標準出力に出力してしまうのも面白くありません。ob_get_contentsという関数を使い、変数に格納して取り出してみましょう。

<?php
echo "a";
ob_start();
echo "b";
$buffer = ob_get_contents();
echo "c";
ob_end_clean();
echo "d";
echo $buffer;
?>

このプログラムの出力結果は”adb”となります。ob_get_contents関数が呼ばれた時点でのバッファを変数に格納し、echo “d”;の後に吐き出した結果ですね。

応用:他ファイルでのPHPスクリプト実行結果を読み込む

このようなバッファリングが役に立つケースとして、他ファイルでのPHPスクリプトの、”実行結果”を読み込み、変数に格納しておきたい場合が挙げられます。
たとえばWEBページのコンテンツ部分のHTMLを、PHPスクリプトを使って動的に生成する場合について考えます。仮に、contents.phpというファイルを作成していた場合、呼び出し側の記述は以下のようになります。

<!DOCTYPE html>
<html lang="ja">
<head>
.
.
</head>
<body>
.
.
<div id="contents">
<?php include("contents.php"); ?>
</div>
.
.
</body>
</html>

この例の場合、includeは1回で済んでいますが、contents.phpの生成内容を同じページ内で何度も繰り返す必要がある場合、都度includeするのではなく、変数に格納しておいた方がよいということになります。

<?php
ob_start();
include("contents.php");
$contents = ob_get_contents();
ob_end_clean();
?>
<!DOCTYPE html>
<html lang="ja">
<head>
.
.
</head>
<body>
.
.
<div id="contents1">
<?php echo $contents; ?>
</div>
<div id="contents2">
<?php echo $contents; ?>
</div>
.
.
</body>
</html>

また、ページによってどのファイルを呼び出すか、分岐の可能性がある場合などには、この書き方ではincludeの周辺が分岐ロジックの記述などで膨れ上がってしまい、呼び出し側のHTMLの視認性を損ないます。それを避けるため、コンテンツを呼び出す部分では変数の出力にとどめ、変数に入れる値をPHPのロジック部分にてあらかじめ求めておくといった形にする方がベターです。その場合にも、出力バッファ関数が役に立ちます。

<?php
ob_start();
if("条件式"){
include("contents1.php");
} else {
include("contents2.php");
}
$contents = ob_get_contents();
ob_end_clean();
?>
<!DOCTYPE html>
<html lang="ja">
<head>
.
.
</head>
<body>
.
.
<div id="contents">
<?php echo $contents; ?>
</div>
.
.
</body>
</html>

その他、色々とアクロバティックなコードを書くときに使えたりします。もちろん推奨はしませんが(笑)。


Webフォントにそろそろ手を出すの事

WordPressでは、ヴァージョン3.6とTwenty Thirteenのペアから本格的採用が始まったWebフォント(WebFonts)。WordPressでの新技術採用は見切り発車というか地固めというか、1年くらいして各社ブラウザがWordPressに合わせてくるのを待って、次第に導入するのが都合が良い。HTML5然り、レスポンシブデザイン然り。それで、Twenty Thirteenの登場からは1年というタイミング、そろそろ趣味のサイト以外でも採用して良い頃合いなのではないかなと思ったので、なるべく安牌的な導入方法を調べてみることにした。

Webフォントの概要

Webフォントというのは、従来のようにユーザのローカル環境にあるフォントを引っ張ってきてWEBコンテンツを表示させるのではなく、WEB制作者側があらかじめ指定したフォントをユーザ側にダウンロードさせて、ある程度制作者側が想定した通りの表示内容で表示させる仕組み。この仕組みがあれば、font-family : sans-serif;のように指定した結果がWindows環境とMac環境で全く異なって表示されてしまうという、デザイン上の困り事も軽減される。

採用のデメリットは、Webページが重くなること。何しろフォントセットを丸々ダウンロードさせるわけで、特にモバイル環境のユーザに対してはストレスを与える結果になる事が多い。また、サイトの表示が重くなると、SEO的観点からもあまりよろしくない。この辺りは膨大な文字数が必要な日本語フォントでは、とりわけ顕著である問題。

Webフォントの仕組みはCSS3の正式規格で、これ自体をサポートしていないブラウザは切り捨てる方向で話を進める。こういう話のときに取り残されるブラウザは大抵IEなのだが、実は元々WebフォントはIEの拡張規格から来ているので、案外IE4などでも使えたりする。ただ、IE8以前の場合はフォントの規格自体がEOTという独自路線のみ対応なので、場合によっては切り捨ててしまった方が面倒でないだろう。

Webフォントとして使用できる形式

そう、どのタイプのフォントがWebフォントとして使用できるかは、ブラウザ側の対応状況に依存する。TrueTypeフォントやOpenTypeフォントはPC環境に付属する一般的なフォントだが、Firefox、Chrome、Safariともにかなり以前のヴァージョンから対応している。また、Mobile SafariではiOSの4.2から対応している。日本発売のiOSデバイスならば、上限までアップデートすれば全デバイスで表示が可能ということだ。
TrueTypeやOpenTypeを表示できないのが、IE。先程も書いた通り、一貫してEOT形式を採用してきた。そのため、表示したいフォントがTrueTypeやOpenTypeであった場合、EOTに変換した上で、同じフォントをIE用に指定して読み込ませるという方針が考えられる。
TrueTypeフォントのEOTへの変換は、WEBサービスやローカルアプリケーションなどが検索すれば出てくる。代表的なところとしてはココ

.ttf/.otfとEOTの組み合わせ指定の場合

TrueTypeならびにOpenTypeフォントと、EOTに変換後のフォントが揃ったと仮定する。IE以外で未変換のフォント、IEでEOTフォントを表示させるように指定するには、スタイルシートに以下のように書く。

/*mplus-1c-thin.ttfというファイルを元にする場合*/
/*EOTはmplus-1c-thin.eotというファイル名で作成したと仮定*/
 
/*今回使用するフォントにtestfontという名称をふる*/
@font-face{
	font-family: "testfont";
	src: url("mplus-1c-thin.eot");
}
@font-face{
	font-family: "testfont";
	src: url("mplus-1c-thin.ttf") format("truetype");
}
 
/*h1見出しのフォントを全てtestfontにする場合*/
h1{
font-family: "testfont";
}

あらかじめ@font-faceでfont-familyの名前空間を確保しておき、srcでパスを指定する。その後、実際に使う箇所ではfont-familyで呼び出す。何も難しいところは無い。ただ、IE用のEOT指定の場合はformatをつけてはいけないというところは注意だ。
このように.ttf/.otfと.eotの組み合わせ指定をすれば、4以上のIEを含めた大抵のブラウザで表示が出来る。カバー率は高いだろう。

WOFFを使用する場合

ただ、TrueTypeやOpenTypeをそのまま指定する方法には、閲覧者がフォントをそのままダウンロードできてしまうという短所がある。WEB制作者的にそれで困るところはあまりないが、フォントメーカーなどはそれでは困るので、Webフォント用の新規格としてWOFFというのが策定された。最新ブラウザなどは一様に対応しているし、これから主流になっていくであろうフォーマットだ。
WOFFのメリットとして、著作権情報が盛り込めたり、データを圧縮できたりというものがある。特に後者の恩恵は大きい。

/*mplus-1c-thin.woffというファイルを元にする場合*/
 
/*今回使用するフォントにtestfontという名称をふる*/
@font-face{
	font-family: "testfont";
	src: url("mplus-1c-thin.woff") format("woff");
}
 
/*h1見出しのフォントを全てtestfontにする場合*/
h1{
font-family: "testfont";
}

WOFFに対応するブラウザは、IEは9以降、Chrome、Firefoxは割と前のヴァージョンからに対応しているので意識しないで良いだろう。Safariでは、Mac版、iOS版とも対応は5.1からと遅めで、これはOSX10.6 Snow LeopardとiOS5以降となる。iOS5以降ということで、日本発売のiOSデバイスではiPhone3Gが非対応になるし、iPhone3GSでもiOS5にアップグレードしないユーザは切り捨てだ。WOFFだけ指定するのは、MacやiOSにおいてもIE8以前バッサリ切り捨てと同じくらいの決断となる。
WOFFへの対応ヴァージョンの確認はこちらのページが便利だろう。

Webフォントのサブセット化

何とかWebフォントの容量を軽くしたいという場合には、サイト上で使う文字だけを組み込んだサブセットを作成する方法がある。武蔵システムのサブセットフォントメーカーというソフトを落として使うのが早い。サブセット化&WOFF変換をすれば、日本語フォントでも常識的なサイズに落ちてくれる。

とは言え、日本語Webフォント導入の動機は薄いかも

各社ブラウザの対応によって、確かにWebフォント導入への障壁は低くなっている。ただ、そのわりにWebフォントを使ったサイトというのがイマイチ流行っていないのは、やはり日本語の文字数が膨大で、ページ本文のフォントとして使用するのがあまりにナンセンスだからだろう。例に挙げたmplus-1p-thin.ttfというフォントで1.6MB。フォントによっては20MBくらいになるものもあるので、気に入ったデザインのフォントをよく考えないで採用すると泣きを見る。あくまでせいぜいアルファベット程度の文字セットをダウンロードさせようという目論見から来ている規格なのだろう。


PHP、JavaScriptにおける三項演算子(条件演算子)

ライブラリなどの出来合いコードを読解するようになると、割と目にすることも多い三項演算子(条件演算子とも)。条件分岐のifクローズをただの式に変えてしまうということで、その使用には抵抗がある向きも多いと思う(実際私もあまり好きではない)。ただ、三項演算子イコール単純なifクローズの省略記法というわけではなく、少々のメリットも存在する。その辺りを含めて、PHPとJavaScriptにおける三項演算子の使い方をまとめてみることにした。

三項演算子の基本的使用法

三項演算子については、PHP、JavaScriptともにC言語と同じ”?”や”:”といった演算子を使う。とりあえずPHPの場合で説明すると、

//ifクローズを使った場合
if($age >= 20){
$alcohol = "OK";
} else {
$alcohol = "NG";
}
 
//三項演算子を使った場合
//(式1) ? (式2) : (式3);
//(式1)が真であるとき(式2)、偽であるなら(式3)
$alcohol = $age >= 20 ? "OK" : "NG";

という具合になる。JavaScriptの場合は変数に$がつかない程度の違い。

三項演算子に慣れて親しんでいないと、直感的に理解できず少し混乱してしまう部分もあるかもしれない。上の例で見ると、変数$bへの代入で使われる”=”と、(式1)であるところの”$a <= 100"のような条件式で使われる"<="等の記号が字面上ややこしく見える。 三項演算子は算術演算子のように式を評価した結果を返すと考えなければならない。つまり、

$b = $a * 100;

こういった代入式と同じで、右辺を評価したが代入されているのだ。三項演算子は代入演算子より優先度が高い。

三項演算子に値ではなく式を入れる

ところで、三項演算子を用いた例として、以下のようなものもあり得る。PHPでの例。

//例1
$age >= 20 ? $alcohol = "OK" : $alcohol = "NG";
 
//例2
$age >= 20 ? print "OK" : print "NG";

これは、前回PHPの言語構造を説明した際に出てきた式とは何かというところで、式とは値をもつものという定義により、文法的にパスすると書いた例だ。もちろんJavaScriptの式の定義も同じであり、たとえば

//例1
age >= 20 ? alcohol = "OK" : alcohol = "NG";
 
//例2
age >= 20 ? alert("OK") : alert("NG");

このような式の代入が可能だ。

エルビス演算子(PHP5.3以降のみ)

PHPの場合、三項の真ん中の(式2)を省略して、(式1)がTRUEである場合値も(式1)になる書き方が出来る。この場合、”?:”という演算子を使う。時計回り90度回転したときに誰かさんの顔に見えるので、エルビス演算子と呼ばれる。

//(式1) ?: (式3);
//(式1)が真であるとき(式1)、偽であるなら(式3)
$tobaccoOkFlag = $alcohol == "OK" ?: 0;
 
//つまり、こう書いているのと同じ
$tobaccoOkFlag = $alcohol == "OK" ? 1 : 0;

ただし、PHP5.3以降でないと使えない。

三項演算子の右結合と左結合

三項演算子を多重に用いる場合、評価する順序が問題となってくる。標準的な順序は右結合と呼ばれる、右から評価していく方法。JavaScriptは右結合なので、JavaScriptの例を書く。

//右結合の場合
tobaccoOkFlag = pregnantFlag ? 0 : alcoholOkFlag ? 1 : 0;
 
//評価順序を分かりやすく書くと
tobaccoOkFlag = pregnantFlag ? 0 : ( alcoholOkFlag ? 1 : 0 );

この場合、多重に用いられた三項演算子のうち、右側のものが優先して評価される。alcoholOkFlagが0の場合は、pregnantFlag、つまり妊婦かどうかに関係なくtobaccoOkFlagは0になる。
一方、PHPはこれとは逆の左結合になるのだが、PHPの場合で解釈してみよう。

//左結合の場合
$tobaccoOkFlag = $pregnantFlag ? 0 : $alcoholOkFlag ? 1 : 0;
 
//評価順序を分かりやすく書くと
$tobaccoOkFlag = ( $pregnantFlag ? 0 : $alcoholOkFlag ) ? 1 : 0;

$pregnantFlagつまり妊婦であるかどうかを評価して、妊婦なら0、そうでないなら$alcoholOkFlagの値によって$tobaccoOkFlagが決まる。例があまり直感的なものに出来なかったので、申し訳ない気持ちでいっぱい。

左結合になる言語はほぼPHPのみ。というのも、PHPが左結合になってしまっているのは言語仕様を決めた際の間違いをひきずっているらしい。今更変えられないので、今後もPHPの短所として残り続けるだろう。

右結合の場合のif-elseの書き方

三項演算子が右結合だとif-elseがスッキリ書けるというメリットがある。右結合のJavaScriptの例。

//if-elseを使う場合
if(age >= 65){
message = "高齢者料金になります。";
} else if(age >= 20){
message = "大人料金になります。";
} else if(age >= 6){
message = "小人料金になります。";
} else {
message = "幼児料金になります。";
}
alert(message);
 
//三項演算子を使う場合
message = age >= 65 ? "高齢者料金になります。"
: age >= 20 ? "大人料金になります。"
: age >= 6 ? "小人料金になります。"
: "幼児料金になります。";
alert(message);

さらに、ifクローズが制御構造であるのに対して、三項演算子は式であるため、関数の直接の引数にすることも出来る。

//三項演算子を引数に
alert(age >= 65 ? "高齢者料金になります。"
: age >= 20 ? "大人料金になります。"
: age >= 6 ? "小人料金になります。"
: "幼児料金になります。");

ここまでスッキリするのなら、三項演算子を導入することも検討してよいのではないだろうか。
逆にPHPでは、三項演算子を多重に使用する事は避けた方が良いのかもしれない。


PHPのechoとprintは言語構造だというけど、言語構造とは何か

細かいことが気になり出すと、調べ尽くして解答を出すまで次の事に移れないタイプで。
PHPを覚えたての頃、標準出力にテキストや変数などを書き出す際に使う命令、echoとprintがあるということを学んだ。そして、解説書に書いてある通り、これらの命令はそれほど違わないので好きな方を使えば良いと理解した。

たまたまPHPにおける三項演算子を調べていたとき、echoとprintで挙動が異なるという例に当たった。三項演算子については、まとめ直した投稿をそのうち上げる予定だけれど、”?”や”:”といった演算子で挟まれる部分は、式でなければならないらしい。そして、echoなどは式という条件を満たさない言語構造であるから、入れるとエラーが出ますよ。ちなみにprintも言語構造ですよ。でも、関数のように振る舞うからエラーが出ませんよ。といったよく分からない説明があった。

//エラーにならない(理由:式だから)
$alcohol = $age >= 20 ? "OK" : "NG";
echo $alcohol;
 
//エラーにならない(理由:式だから)
$age >= 20 ? $alcohol = "OK" : $alcohol = "NG";
echo $alcohol;
 
//エラーにならない(理由:式だから)
$alcohol = $age >= 20 ? htmlentities("OK") : htmlentities("NG");
echo $alcohol;
 
//エラーになる(理由:言語構造だから)
$age >= 20 ? echo "OK" : echo "NG";
 
//エラーにならない(理由:言語構造だけど関数のように振る舞うから)
$age >= 20 ? print "OK" : print "NG";

PHPの式とはなんだろう?

上の3つの例でエラーにならないのは、三項演算子の書式(式1)?(式2):(式3);これに即しているため。ではそもそもPHPにおける式の定義とは何だろうか。マニュアルを見るとちゃんと一項目があって式とは値があるものだそうです。
一番上の例、”OK”や”NG”というのは、値である。これはとても直感的にわかる。
上から2番目は代入式だ。ここで結構ショッキングな事実になるけれども、実は代入式では、左辺の$alcoholに右辺の値”OK”が代入されるのみならず、式自体も右辺と同じ値を持つということらしい。
したがって、代入式は値を持っているのでエラーにならない。
上から3番目。関数を呼んで実行するのも式だ。htmlentities関数はstring型を返り値として返す。また、特に値を返す設定をしていない関数(たとえば、ユーザ定義関数でreturnを行わないタイプ)でも、自動的にNULLを返す設定となっている。つまり値を返すから式だ。

言語構造とは

では、関数ではない言語構造と呼ばれるものは一体なんなのだろう。言語構造(Language Constructs)とは、英語で見れば何のこともない。言語を構成する要素である。ifとかwhileとかといったものと同じ。制御構造を作るためのifやwhileとともに、言語に最初から存在するものとしてハードコードされているため、関数のように決まった形でないと呼び出せないというような制約はない。echoはecho “文字列”;のようにもecho(“文字列”);と関数のようにも呼び出せるが、これは便宜のためたまたまどちらの書き方でも呼び出せるようにハードコードされているからで、echoの属する言語構造というカテゴリがこうした文法的制約を持っているわけではない。
関数ではないということで、当然のことながらcall_user_func(“echo”,”文字列”);こういった呼び出し方も出来ない。

echoとprintの違いとは

では、echoとprintが両方とも言語構造でありながら、異なるというところはどこだろうか。実は先程echoが便宜のため関数のように括弧を付けても呼び出せると書いたが、printはさらに返り値として常に1を返してくる。つまり、printの方が関数への擬態がうまい。そしてその分処理が重い。
そして、何らかの値を返すということは、printは式になるのである。そのため、三項演算子の中の式としても使えていたのである。

なるほどよく分かった。ちなみに違いとしてもう一つ、echoはecho”値1″,”値2″;のように使う事も出来るというものがあり、大抵の解説書にはechoとprintの違いとしてこちらが説明されているのではないかと思う。そっちの方が重要かもしれないね。

関数っぽいけど言語構造のもの一覧

最後に、一見関数のように見えて実は言語構造という例をいくつか挙げておこう。

返り値の型 名前 機能
なし echo 文字列を出力
int print 文字列を出力
array array 配列を生成
array list 配列の形式で、変数に値を代入
mixed eval 文字列をPHPコードとして評価
なし unset 変数を破棄する
bool isset 変数がセットされているか調べる
bool empty 変数が空かどうか調べる
なし exit スクリプトの実行を終了
なし die exitと同等
mixed include ファイルを読み込む
mixed require ファイルを読み込む(読み込めないと停止)

同列に扱っているけど、既に説明したとおり共通した呼び出し方の制約はない。フリーダムなやつらなので注意が必要。


Conceptual:EXIFviewerに撮影地の地図表示機能を追加

予告通り、ローカル領域にあるjpegファイルのEXIF情報を表示するWEBサービス、EXIFviewerの機能を追加してみた。今回追加した機能は、jpegファイルのEXIFの中に撮影地情報が格納されていた場合、Google Mapsで表示するというもの。EXIFファイルの中のGPS情報をテーブルに表示するまでは前のヴァージョンでも実現していたため、今回の説明はGoogle Maps APIと連携する際の注意点が中心となる。

連携の前段階、既存プログラムの手直し

前のヴァージョンのEXIFviewerの作成手順では、表の成形部分で特にid指定などもしないセルを吐き出していた。今回、緯度経度情報をGoogle Maps APIに渡すには、JavaScript(jQuery)を使ったクライアントサイドでの値取得が必要となる。そのため、値の入ったセルにidで一意の名前をつけるようにする。また、前回手を付けられなかった値のサニタイジングもついでに行う。

if(!empty($_POST["path"])){
if($exif = exif_read_data($_POST["path"],NULL,true)){
echo "<h2>EXIF情報</h2>";
echo "<table class='exiftable table table-striped'><thead><tr><th>キー名</th><th>値</th></tr></thead><tbody>";
foreach ($exif as $key => $section) {
    foreach ($section as $name => $val) {
	if(is_array($val)){
	foreach ($val as $valname => $vval) {
	echo "<tr><td>" . htmlentities($key,ENT_QUOTES,"UTF-8") . ' ' . htmlentities($name,ENT_QUOTES,"UTF-8") . ' ' .  htmlentities($valname,ENT_QUOTES,"UTF-8") . "</td><td id=" . '"' . htmlentities($name . $valname,ENT_QUOTES,"UTF-8") . '">' . "$vval</td></tr>";
	}
	} else {
	echo "<tr><td>" . htmlentities($key,ENT_QUOTES,"UTF-8") . ' ' . htmlentities($name,ENT_QUOTES,"UTF-8") . "</td><td id=" . '"' . htmlentities($name,ENT_QUOTES,"UTF-8") . '">' . htmlentities($val,ENT_QUOTES,"UTF-8") . "</td></tr>";
	}
    }
}
echo "</tbody></table>";
} else {
echo "画像のEXIFデータが見つかりませんでした。";
}
} else {
echo "画像をセットして下さい。";
}

これがPHP部分。画像のEXIFにGPSの情報が不足なく入っていた場合に初めて処理を行うようにするので、このPHP部分で情報の不足をチェックし、地図表示の実行フラグとして非表示のセルにでも入れれば、JavaScript側の記述がスマートに済む筈。今回それをしなかったのは、不特定多数が利用する可能性があるため、出来るだけサーバ側の負担を軽く、クライアントサイドで処理を担保してもらうように設計したため。

Google Maps APIの使用方法

Google Maps APIを使いたい場合、htmlのヘッダ部で読み込む事になる。

<head>
.
.
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false"></script>
</head>

こういった具合。クエリストリングのsensor=falseという部分は、利用者の位置情報を求めるかどうかということで、falseに設定しておけば鬱陶しい確認ダイアログが出ないだろう。
今回は、id=”googlemapdiv”というdiv要素の中にマップを表示する場合で説明する。jQueryのreadyの中に、以下のように記述した。

$(function(){
.
.
var option = {
zoom: 17,//地図の縮尺初期設定(0〜19)
center: new google.maps.LatLng(imagelat,imagelong),
//地図の中心の座標 LatLng(緯度,経度)
//とりあえず今回はimagelat,imagelngというユーザ定義変数を使った
//もちろんこれより前に宣言されてないといけない
mapTypeId: google.maps.MapTypeId.ROADMAP,//地図の種別初期設定
zoomControl: true,//ズームGUIの表示非表示
streetViewControl: true,//ストリートビュー表示可能にするか
scaleControl: true,//ズームスライダーGUIの表示非表示
mapTypeControl: true//地図の種別切り替えGUIの表示非表示
};
var map = new google.maps.Map($("#googlemapdiv")[0],option);
var marker = new google.maps.Marker({
				position : option.center,
				map : map
			});
});

コントロールの指定については必須ではない。google.maps.Mapメソッドに引数として地図の設置場所(DOMオブジェクトで指定)と、各種オプションを代入する。

Google Maps API用に緯度経度を10進法に変換する

さて、お膳立ても出来たので、単純にPHP側で成形した表のGPS情報の部分を取得し、Google Maps APIに渡せば良い、、とはいかない。
iPhone等で記録されるEXIFのGPSデータは、60進法で記録されているが、Google Maps APIが受け付けるのは10進法の数字なのだ。そこで、画像から取得した緯度経度を60→10進法に変換する処理を用意しないといけない。
60→10進法変換の方法だが、たとえば60進法で12.3という数字があった場合、10の位の1は10進法の60*1を表し、1の位の2は1*2、小数点第一位の3は60分の1*3を表している…といった数学の知識を、思い出してほしい。iPhoneなどが採用している60進法の表示方式では、”北緯36度46.5分0秒,東経137度54.52分0秒”といったように書くが、これは成形された表ではこのように表示されている。

EXIFでの緯度経度

EXIFでの緯度経度

GPSLatitudeRefやGPSLongitudeRefが東西南北(EWSN)を表している事は分かり易い。GPSLatitude 0が表すのは、緯度の”度”の部分。”36/1″という数字は、分母が1で分子が36ということ、つまり分数だ。同様に、GPSLatitude 1は100分の4650、つまり46.5分を表すといったように、面倒臭い書き方をしている。しかもこの値が60進法なのだ。
変換手順は、分数の文字列をなんとか少数に直して、それから10進法への変換を行うという形になる。
そして最後に10進法に直した後の値に、西経、南緯の場合マイナスをつけるという手順も必要だ。

 
//緯度を求める
var imagelat = parseFloat($("#GPSLatitude0").text().split("/")[0])/parseFloat($("#GPSLatitude0").text().split("/")[1]) + parseFloat($("#GPSLatitude1").text().split("/")[0])/(parseFloat($("#GPSLatitude1").text().split("/")[1])*60) + parseFloat($("#GPSLatitude2").text().split("/")[0])/(parseFloat($("#GPSLatitude2").text().split("/")[1])*3600);
if($("#GPSLatitudeRef").text() == "S"){
imagelat = "-" + imagelat;
}
 
//経度を求める
var imagelong = parseFloat($("#GPSLongitude0").text().split("/")[0])/parseFloat($("#GPSLongitude0").text().split("/")[1]) + parseFloat($("#GPSLongitude1").text().split("/")[0])/(parseFloat($("#GPSLongitude1").text().split("/")[1])*60) + parseFloat($("#GPSLongitude2").text().split("/")[0])/(parseFloat($("#GPSLongitude2").text().split("/")[1])*3600);
if($("#GPSLongitudeRef").text() == "W"){
imagelong = "-" + imagelong;
}

このようにして出てきた結果を、google.maps.LatLngメソッドの引数として与えてやれば良い。

ということで、EXIFViewerでの地図表示が可能になった。労力のわりに、いまや出来て当たり前の機能のように見えるからどうにも報われないのです。


BootstrapとGoogle Maps API同時使用時の表示崩れを修正する

Twitter社の提供するCSSフレームワーク、Bootstrap。これを使うと、面倒臭いWEBのGUIデザインを、要素へのクラス指定一発で解決することが出来る。以前紹介を行ったとおりCDNでの利用も可能なので、WEBサイトを作成する前にとりあえず(jQueryと一緒に)呪文のように読み込んでおくと、ページ制作中痒いところにも咄嗟に手が届き易い。

もう一つ、企業サイトであれば”会社概要”ページのアクセスマップなどで使われるであろう、Google Maps API。こちらも頻繁に利用されるものに違いないのだが、BootstrapとGoogle Maps APIを同時に利用して地図の表示を行うと、以下のスクリーンショットのように表示崩れが発生する。

Google Maps表示不具合

Google Maps表示不具合

まず由々しきこととして、左端の縮尺スライダーが表示されない。このような状態だと、スクリーンショットを貼っておいた方がまだ良かったのではないかという疑問も湧くだろう。また、右上の地図と衛星写真の切り替えメニューで、カーソルをホバーした時のドロップダウンメニューが少し見苦しい。具体的には、チェックボックスとラベルの間に改行が入ってしまうのである。

Google Maps表示不具合の原因

これらの不具合の原因は、Bootstrap側で読み込むCSSで、img属性やlabel属性など比較的影響の大きいところでスタイル指定を行っているからである。具体的には、

img{
max-width:100%;
width:auto\9;
height:auto;
vertical-align:middle;
border:0;
-ms-interpolation-mode:bicubic;
}
 
label{
display:block;
margin-bottom:5px;
}

といったような記載のある箇所である。問題となっているのは、img属性のmax-width:100%指定と、label属性のdisplay:inline-block指定である。

特に対応せずにGoogle Mapsが表示できているケース

img属性の指定によってマップのスライダーが表示されない不具合については、Bootstrap側としても対応策をとっている(どのヴァージョンからかは、生憎把握していないが)。

#map_canvas img,.google-maps img{
max-width:none;
}

このようなCSSを追加して、Google Mapsのデフォルトで包括要素として使われるdivのid=”map_canvas”以下のimg属性に特別にスタイル指定している。そのため、素直にマップを表示する領域のidを#map_canvasにしている場合、不具合は起こらないはずだ。問題は、別のid名やクラス名をしている場合。Bootstrap側の付け焼き刃的対策では問題が解決しない。

解決策

解決策は、Bootstrapの付け焼き刃解決策と同じように、包括要素以下のimg属性・label属性にスタイルを指定してやれば良い。たとえば包括要素がid=”googlemapdiv”だった場合、スタイルシートに以下のように記述する。

#googlemapdiv img{
max-width : none;
}
 
#googlemapdiv label{ 
width : auto;
display : inline; 
}

また、マップのコントロール部分の上位要素であるclass=”gm-style”以下の各属性に指定する形でも良いだろう。

.gm-style img{
max-width : none;
}
 
.gm-style label{ 
width : auto;
display : inline; 
}

これで正常に表示されるはず。

GoogleMaps正常表示

GoogleMaps正常表示

BootstrapやGoogle Mapsなどの複数WEBサービスを組み合わせて利用する場合、どこかは絶対ぶつかるものだと最初から割り切っていた方が良いのだろう。ちなみに今回の問題はEXIFviewerに機能を追加する過程で確認したもの。そろそろ新ヴァージョンを公開できるはず。


WordPress 3.8と新デフォルトテーマTwenty Fourteen

最近、妙に生き急いでいる感まであるWordPress。WordPressでブログを運営していると、本体のアップデートがリリースになったので更新しろとの注意が頻繁に表示される。そのうちに週刊WordPress状態に移行してしまうのではないかという危惧もあるのだが、とりあえずはへいへいと言いなりになって更新ボタンを押している。

今回12月12日にリリースされたヴァージョンは、3.8。WordPress3.7のリリースが10月で、当ブログでも言及した3.6のリリースが8月。3.5が去年の12月であるため、サイトによっては2013年中に3度のアップデートを経験することになるかもしれない。

リデザインされた管理画面

今回のアップデートの主な変更点は、まず管理画面のリデザイン。3.6でも、投稿画面にリビジョン表示・アイキャッチ表示が追加されたり、3.7では投稿フォーマットの指定欄追加など、機能の継ぎ足し継ぎ足しが行われ(その都度新しく覚え直し…)てきたわけだが、今回の変更はそれらとは異なる、リデザインになる。まあ、WordPress.comでは先行実装されていた管理画面なので、見覚えがある方も多いかもしれない。MP6プラグインとしてレビューされていたものだ。
管理画面自体がフラットなデザインになり、スマートフォンなどのデバイスとの相性が良くなった。これは人によっては、これまでのデザインの方が良かったと感じるかもしれない。テーマの選択画面は、Thx38プラグインとしてレビューされていたものを採用し、こちらもこれまでの選択画面に慣れているとやや戸惑うだろう。
期待されていた、コンテンツの串刺し検索であるGlobal Admin Searchはまだ標準実装には至っていない。プラグインとしては同名で配布されているので、WordPress3.5以上のヴァージョンのユーザは先んじて試してみるのも良いかもしれない。

新デフォルトテーマTwenty Fourteen

WordPress3.6のデフォルトテーマ、Twenty Thirteenでは、それまでのデザインを覆すフラットデザインと、レスポンシブの徹底化、WEBフォントの採用など大きな変更があった。そして、ユーザがTwenty Thirteenに慣れる間もなく、3.8では新デフォルトテーマのTwenty Fourteenが登場することとなった。

Twenty Fourteen

Twenty Fourteen

これまでのデフォルトテーマでは、トップにヘッダ画像があり、その下のブロック要素に水平メニュー・サイドバーを含むカラム要素を詰め込むというデザイン。それに対して、Twenty Fourteenでは水平メニューが上部固定でスクロールの影響を受けないように、記事部分はヘッダ画像の幅に左右されず広々と幅をとり、幅1007px以下のウィンドウサイズで早々とサイトバーが下部に落ちてしまうようになった。
感覚的には、wrapperを取り払ったイメージというべきか。近頃のOSXなどが推しているフルスクリーン表示を行っても、間抜けにならないデザインとして考えられているのかもしれない。是非テーマのデモサイトでググっとウィンドウサイズの変更を試されたし。

今回のアップデートで、混乱するライトユーザも相当数出そうだというのが率直な感想。惰性でWordPressを使っている層がどう動くだろうか、多少の波乱に期待してみたり。

(2013.12.18追記)
WordPress3.8日本語版をインストールしたのだが、管理画面のアイコンのうちいくつかが文字化けしてしまうという現象が発生した。

WordPress3.8 文字化け

WordPress3.8 文字化け

公式では、WordPress3.8管理画面の文字化けはプラグインWP Multibyte Patch1.9のインストールで解決するとアナウンスしているのだけど…
WP Multibyte Patchの最新版インストールでは解決せず。WEBフォントの使用に疎いのだが、環境依存の壁を取り払うことを目的としたWEBフォントが化けてしまうということはあり得るのだろうか?

(さらに追記)
ブラウザ再起動で解決。WEBフォントが化ける可能性について、原因を調べてみようと思います。