月別アーカイブ: 2014年3月

PHPテンプレートエンジンを使おう 素のPHP編

このブログの作成当初、「作成するサイトにはテンプレートエンジンとしてSmartyを採用します!」とか言ってしまっているのだけれど、現在のところ結局Twigに落ち着いてしまっている。いや、色々と理由があったのだけれども、それらをすっ飛ばして、当初の宣言を無かった事にしてTwigの紹介を始めても、というところがあるので、本当にさらっとテンプレートエンジンとは何かと、諸事情で通過してしまったSmartyについて書こうと思う。

テンプレートの考え方

というわけで、まずテンプレートとは何か。テンプレートというのは、Dreamweaverを始めとして数々のPCアプリケーションではそのままの単語が使用されている、作成する書類の「ひな形」の事だ。つまりもう文書構造まではでき上がっているファイルに、タイトルだの本文だのオリジナルな情報を加えて保存すると、立派な当たり障りの無いファイルが出来る。また、オリジナル情報の部分を書き換える事で、似たような文書を量産する事が出来る、そういった仕組みだ。

WEBサイトを構成するhtmlファイルについても、サイトの全ページを集めて見比べてみると、共通部分が多い事に気付くだろう。たとえばヘッダ部分とかフッタ部分とか。ブログなどでは記事横のサイドバーなども共通するし、広告を表示する設定にしているならば、その部分も共通している。ちょっと例を挙げてみよう。

 
<!-- トップページ -->
<!DOCTYPE html>
<html lang="ja">
<head>
.
.
<title>サンプル株式会社 トップページ</title>
</head>
<body>
<header>
<h1>サンプル株式会社</h1>
</header>
<div id="wrapper">
<div id="main">
<article>
<h1>ごあいさつ</h1>
<p>ようこそサンプル株式会社ホームページへ!</p>
.
.
</article>
</div>
<div id="sidebar">
<aside>
.
.
</aside>
</div>
</div>
<footer>
.
.
</footer>
</body>
</html>
 
<!-- 各商品紹介ページ -->
<!DOCTYPE html>
<html lang="ja">
<head>
.
.
<title>サンプル株式会社 商品A</title>
</head>
<body>
<header>
<h1>サンプル株式会社</h1>
</header>
<div id="wrapper">
<div id="main">
<article>
<h1>商品Aの概要</h1>
<p>説明説明説明</p>
.
.
</article>
</div>
<div id="sidebar">
<aside>
.
.
</aside>
</div>
</div>
<footer>
.
.
</footer>
</body>
</html>

この2つのページは、ほぼ共通部分によって構成されている。違いと言えば、ページタイトルとid=”main”の中のarticleだけだ。
テンプレートを使わない方法では、たとえばテキストファイルでページタイトルとarticle以外の部分を空白にした文書を作っておき、新しくページを加える際にはそのファイルを元にして新ページのファイルを書くといった手順になるだろう。
けれども、この方法だと全ページのサイドバーに項目を増やしたいなどとなったとき、テキストファイルを開いてコピー、開いてコピーと忙しい。非現実的である。

Dreamweaverにおけるテンプレート

そこで、Dreamweaverなんかではテンプレートファイル.dwtを作成して、テンプレート全体に渡る変更はこの.dwtファイルを弄れば良いというような仕組みでやっている。

 
<!-- テンプレートファイル.dwt -->
<!DOCTYPE html>
<html lang="ja">
<head>
.
.
<!-- TemplateBeginEditable name="doctitle" -->
<!-- TemplateEndEditable -->
</head>
<body>
<header>
<h1>サンプル株式会社</h1>
</header>
<div id="wrapper">
<div id="main">
<!-- TemplateBeginEditable name="mainarea" -->
<!-- TemplateEndEditable -->
</div>
<div id="sidebar">
<aside>
.
.
</aside>
</div>
</div>
<footer>
.
.
</footer>
</body>
</html>

このような.dwtファイルを作成しておき、新しくページを作成する際はこのテンプレートを元にTemplateBeginEditable…というhtmlコメントアウトとTemplateEndEditable…に挟まれた部分にページオリジナルのコンテンツを入れる。もしテンプレート自体に変更が起きた場合は、そのテンプレートを元に作成された全てのページへの同様の変更が有効になるといった具合だ。

PHPでテンプレート方式を利用する

でも、Dreamweaverはお高い。現在ではCreative Cloudなんかで継続的にコストがかかるし、契約を止めてしまえば作成した.dwtファイルなんて無用の長物になってしまう。そこで、テンプレート機能のためだけにDreamweaverを導入するくらいならば、プログラムで何とかしてしてしまおうという考え方もあるだろう。
幸いPHPにはテンプレート方式を利用するのに具合の良い仕組みがある。一番大きいのは、html文書の途中にインラインで出力命令を埋め込めること。そこで、実際ページ毎に出力が異なる部分にあらかじめecho命令を書いておいたものをテンプレートファイルとして保存し、各ページのアドレスに対応するファイルから変数に出力する値を設定して呼び出せば良いのだ。

 
//テンプレートファイル template.php
<!DOCTYPE html>
<html lang="ja">
<head>
.
.
<title><?php echo $title; ?></title>
</head>
<body>
<header>
<h1>サンプル株式会社</h1>
</header>
<div id="wrapper">
<div id="main">
<?php echo $honbun; ?>
</div>
<div id="sidebar">
<aside>
.
.
</aside>
</div>
</div>
<footer>
.
.
</footer>
</body>
</html>
 
//トップページ index.php
<?php
$title = "サンプル株式会社 トップページ";
$honbun = "<article>
<h1>ごあいさつ</h1>
<p>ようこそサンプル株式会社ホームページへ!</p>
.
.
</article>";
include("template.php");
?>
 
//各商品紹介ページ itemA.php
<?php
$title = "サンプル株式会社 商品A";
$honbun = "<article>
<h1>商品Aの概要</h1>
<p>説明説明説明</p>
.
.
</article>";
include("template.php");
?>

ショートタグを使えばプレースホルダに近く

呼び出し側のファイルでは、変数を参照する箇所で毎度毎度インラインのPHPを呼び出し、echo命令を打っている。このままでも別に構わないのだろうが、よりテンプレートっぽくするために、プレースホルダに近い省略表現にしてみよう。
プレースホルダというのは、テンプレートエンジンで使われる用語の一つで、後から何か別のものを置く場所に仮置きしておくものである。Dreamweaverではイメージプレースホルダーという名前の、仮置き用のイメージをおける機能があるが、これはとりあえず関係ない。先の例でechoを使っていた部分を、そこに吐き出す変数名とプレースホルダであることを示すちょっとした目印表現の組み合わせ程度に簡略化すれば、仮置きらしくなる。
PHPは本当にテンプレートに向いている言語というべきか、echo命令の同義語として以下のような変換が出来る。

//これが
<?php echo $title; ?>
 
//これと同義語に
<?= $title ?>

幾分短くなった。この書き換えは、PHP5.4以降のヴァージョンなら標準で、5.3以前のヴァージョンなら、php.iniを書き換えてshort_open_tagをOnにすればできる(残念ながらini_setでは不可能)。
テンプレート使用のメリットの一つとして、デザイナーとプログラマーの作業の分担というものがある。PHPは全く分からないというデザイナー・htmlコーダにテンプレートファイルを渡して、”<?=”と”?>”に囲まれている部分には絶対に手を付けるなと言っておけば、デザイン作業が進みつつ、プログラマも並行してプログラムを書くことが出来る。ということで、テンプレート導入は、WEB制作の大きなパラダイムとなったわけだ。


標準出力のバッファリングを有効化する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くらいになるものもあるので、気に入ったデザインのフォントをよく考えないで採用すると泣きを見る。あくまでせいぜいアルファベット程度の文字セットをダウンロードさせようという目論見から来ている規格なのだろう。