2年経ってた

mixi日記に回帰してしまい、このブログに2年の空白をもたらしてしまいました。
オープンなブログ≒利用価値の高い情報」なんて自分で敷居を高めてしまうとなかなか厳しいですね。

それなりに紆余曲折はあるものなんだと思いますが、
前回、前々回の記事の内容が2年前とは思えない...。成長していないのかしら。おれ。

現在オープンソース的(あくまでも”的”な)ものを考案および開発中なので、
復帰がてらにここで公にしていこうと考えています。

AS3.0は相変わらず勉強・実績ともに不足していますが、暗号化・復号化の続きはいい加減アーカイブとして残しておかないないといけませんね。
コメントいただいたのに(スパムじゃないのは本当にひさしぶり)。猛省。

ごめんなさい(次回予告)

ブログが頓挫する理由の常套句かもしれませんが、本業の締め切りラッシュを邁進中です。
復号化の記事とソースコードをいち早くご紹介できるよう、合間をみてちょこちょこと記事を書き溜めていますので、
今しばらくお時間いただければ幸いです。(仕事のメールみたいになってしまいました...)

それにしても、ブログからコメントいただいたのは何年ぶりでしょうか。
テンションあがりますね。頑張ります。

※次回は今週中に公開予定です!

ActionScript 3.0で暗号化・復号化のメモ(2) ハッシュ関数(MD5,SHA)

暗号化・復号化の予備知識メモ

前回(ActionScript 3.0で暗号化・復号化のメモ(1) データフォーマットについての予備知識(バイナリ、Hex、Base64...))、暗号化・復号化の予備知識として、取り扱うデータ形式についてメモしました。
今回は、ActionScript 3.0のライブラリas3crypto(Google Code)を利用して、MD5,SHAによるハッシュ値の生成方法をご紹介します。

ハッシュ関数

与えられた原文から固定長の疑似乱数を生成する演算手法。生成した値は「ハッシュ値」と呼ばれる。(中略)経路の両端でデータのハッシュ値を求めて両者を比較すれば、データが通信途中で改ざんされていないか調べることができる。不可逆な一方向関数を含むため、ハッシュ値から原文を再現することはできず、また同じハッシュ値を持つ異なるデータを作成することは極めて困難である。

ハッシュ関数とは 【hash function】 - 意味・解説 : IT用語辞典

プログラマーさんの会話の中から「ハッシュ」「MD5」というキーワードを耳にすることも少なくないのではないでしょうか?
暗号化・データの照合・復号化という仕組みは、プログラマーさんの領域内で構築されることがほとんどでしょう。デザイナーさんは「このページに暗号化された文字列がアサインされ〜このページにPOSTする」的な受渡しデータの一つでしかないことも多いかもしれませんね。
でも、デザイナーさんも 取り扱うデータがどういう経緯、意図を持って加工されているのか?ということを知っていたりすると、インターフェースデザインの思わぬヒントになったりするかもしれません。

ActionScript 3.0のサンプルコード

サンプルデータ(sample-2-hash.fla)のダウンロード

http://www.ideamans.com/_dat/sample-2-hash.fla(約300KB)

(1) はじめに、ハッシュ関数を利用するためのクラスをimportします

(as3cryptoのダウンロードはこちら→Google Code)

import com.hurlant.crypto.Crypto;
import com.hurlant.crypto.symmetric.*;
import com.hurlant.crypto.hash.*;
import com.hurlant.util.Base64;
import com.hurlant.util.Hex;

5つのクラスの中の、〜.Base64;と〜.Hex;は、Hex文字列、Base64文字列への変換を行うためのものです。
(前回ご紹介しましたので、?の方はご一読ください→ActionScript 3.0で暗号化・復号化のメモ(1) データフォーマットについての予備知識(バイナリ、Hex、Base64...)

(2) ハッシュ関数はバイナリデータを利用しますので、プレーンテキストをバイナリ変換します
/*/////////////////////////////////////////////
元データをバイナリ化
//////////////////////////////////////////////*/
//ハッシュ値生成にはバイナリデータを利用するので、
//プレーンテキストをバイナリ化します

//プレーンテキスト
var strA:String;		
strA = '本日は晴天なり';

	/*/////////////////////////////////////////////
	バイナリ変換の方法
	(1)プレーンテキスト→バイナリデータ
	(as3cryptoを利用しない)
	//////////////////////////////////////////////*/
	var baA:ByteArray = new ByteArray();
	baA.writeMultiByte( strA , "utf-8");
	
	
	/*/////////////////////////////////////////////
	バイナリ変換の方法
	(2)プレーンテキスト→Hex文字列→バイナリデータ
	(as3cryptoを利用する)
	//////////////////////////////////////////////*/
	//プレーンテキストをHex文字列に変換
	var hexA:String;
	hexA = Hex.fromString(strA);
	//Hex文字列をバイナリデータに変換
	var baB:ByteArray = new ByteArray();
	baB = Hex.toArray(hexA);
	
	
	//結果、baAとbaBが同じ値になっているはず(当然ですけども)
	//2進数の文字列に変換して確認してみましょう
	var i:int;
	//(1)の結果
	var strA2:String = '';
	for ( i = 0; i <baA.length; i++ ){
		strA2 += baA[i].toString(2);
	}
	//(2)の結果
	var strB2:String = '';
	for ( i = 0; i <baB.length; i++ ){
		strB2 += baB[i].toString(2);
	}
	
	trace('(1)プレーンテキスト→バイナリ:\n' + strA2 + '\n');
	trace('(2)プレーンテキスト→Hex文字列→バイナリ:\n' + strB2 + '\n');

出力結果)

(1)プレーンテキスト→バイナリ:
111001101001110010101100111001101001011110100101111000111000000110101111111001101001100110110100111001011010010010101001111000111000000110101010111000111000001010001010

(2)プレーンテキスト→Hex文字列→バイナリ:
111001101001110010101100111001101001011110100101111000111000000110101111111001101001100110110100111001011010010010101001111000111000000110101010111000111000001010001010
(3) MD5(Message Digest 5)を利用してハッシュ値を生成してみます
/*/////////////////////////////////////////////
(3) MD5を利用する

	MD5のほかにMD2も利用可能です
		Crypto.getHash()の引数:
		"md5" →MD5
		"md2" →MD2

//////////////////////////////////////////////*/
//ハッシュ値生成のアルゴリズム
var hashA:IHash;
hashA = Crypto.getHash("md5");

//バイナリデータ(baA)を元にハッシュ値(hashA)を生成
//ハッシュ値(バイナリ)
var hashBa:ByteArray;
hashBa = hashA.hash( baA );

//生成されたハッシュ値はバイナリデータなので、プレーンテキストに変換
var strC:String;
strC = Hex.fromArray( hashBa );

trace('(3) ハッシュ値(MD5):\n' + strC + '\n');

出力結果)

(3) ハッシュ値(MD5):
c67beed7a2249dc572eb17ad0c1e5c03

(4) SHA(シャー、Secure Hash Algorithm)を利用してハッシュ値を生成してみます
/*/////////////////////////////////////////////
(4) SHAを利用する

	SHAは下記の4種類を選択可能です
	(生成するハッシュ値のビット長を選ぶことが出来ます)
		Crypto.getHash()の引数:
		"sha" 		→SHA-1(160ビット)
		"sha1" 	→SHA-1(160ビット)
		"sha224" →SHA-224(224ビット)
		"sha256" →SHA-256(256ビット)
		
//////////////////////////////////////////////*/
//ハッシュ値生成のアルゴリズム
var hashB:IHash;
hashB = Crypto.getHash("sha");

//バイナリデータ(baA)を元にハッシュ値(hashB)を生成
//ハッシュ値(バイナリ)
var hashBa2:ByteArray;
hashBa2 = hashB.hash( baA );

//生成されたハッシュ値はバイナリデータなので、プレーンテキストに変換
var strD:String;
strD = Hex.fromArray( hashBa2 );

出力結果)

(4) ハッシュ値(SHA-1):
6b4016472030307a38f6ca23f76572ae0bed338f
(5) PHPでの生成結果と答え合わせをしてみましょう

サンプルコード)

<?php 
//プレーンテキスト
$strA = '本日は晴天なり';

//MD5でのハッシュ値
$strC = md5( $strA );

//SHA-1でのハッシュ値
$strD = sha1( $strA );

print 'プレーンテキスト:<br>' . $strA . '<br/>';
print '(3)MD5でのハッシュ値:<br>' . $strC . '<br/>';
print '(4)SHA-1でのハッシュ値:<br>' . $strD;

?>

出力結果)

プレーンテキスト:
本日は晴天なり
(3)MD5でのハッシュ値:
c67beed7a2249dc572eb17ad0c1e5c03
(4)SHA-1でのハッシュ値:
6b4016472030307a38f6ca23f76572ae0bed338f 

大丈夫そうですね...

次回予告

長くなってしまったので、共通鍵暗号化・復号化については、次回書こうかと思います。
(どうやったら、すっきりとご紹介できるのだろうか...)

ActionScript 3.0で暗号化・復号化のメモ(1) データフォーマットについての予備知識(バイナリ、Hex、Base64...)

取り急ぎ、本業でActionScript 3.0でのスクリプティングが必要な案件にあたりました。
僕は、オブジェクト指向プログラミング、型指定、イベント...などといったキーワードから避けて通ってきてしまったように思います。
いやむしろ、「ActionScript 3.0はウチの開発者さんのための言語だろう」までに思っていたのですが、なにしろ取り急ぎだったので、慌てて書店に向かい2冊ほど開きながら書きましたよ。ふう。

参考になったサイト

ActionScript関連

as3crypto - Google Code
参考になった。というか、このライブラリで暗号化・復号化が実現できます。必須です。
また、下記のデモサイトで各種の暗号化・復号化が行えます。ActionScript 3.0の動作確認に重宝しました

as3cryptoのデモ確認ページ

ActionScript3.0を極める | AS3で暗号化
as3cryptoライブラリの利用例を一通り紹介してくれています。大変感謝感激でした。が、復号化については記載されていませんでした。

ウノウラボ Unoh Labs: PHPで暗号化して、Flashで復号してみたときのメモ
結局たどり着いたのが、ウノウラボKeitaさんの記事です。Flex2ですが壁を乗り越えることが出来ました。
感激のあまり、ブログコメントをしようまいかドギマギしたくらいです。ありがとうございます。

encrypton - ActionScript.org Forums
上記でもas3cryptoライブラリの記述例があります。PHPで照合確認するためのコードとPHPライブラリも配布されています。
ただし、64bitの復号用Keyに対応していないようで、結局今回は利用しませんでした。


as3cryptoライブラリを利用する(下準備)

(1) as3crypto - Google Code から Crypto.zip をダウンロード後、適宜解凍してください
例)解凍したファイル一式を(I:)ドライブの「/Crypto/」という名前のフォルダに置きました

(設置箇所)
I:\Crypto
(設置内容)
/certs/
/com/
BenchmarkTab.mxml
build-swc.xml
CryptoDemo.mxml
HashTab.mxml
HmacTab.mxml
LICENSE.txt
MonkeyTab.mxml
PublicTab.mxml
RELEASENOTES.txt
SecretTab.mxml
TLSDemo.mxml
UnitTestTab.mxml

(2) 上記のライブラリを利用するには
ActionScript 3.0でのメインタイムラインのフレームアクションに、次のように記述します(例として)

import com.hurlant.crypto.symmetric.*;
import com.hurlant.crypto.prng.Random;
import com.hurlant.crypto.Crypto;
import com.hurlant.crypto.hash.*;

(3) また、コンパイル時に上記(2)のクラスを読み込むためのパス指定を行います。
[ファイル > パブリッシュ設定 > "Flash"タブ] を選択し、 [ActionScriptのバージョン:]の右にある[設定ボタン]をクリックします。
[ActionScript 3.0設定]ウィンドウの[クラスパス:]欄に下記/Crypto/ライブラリのパスを追加します。

I:\Crypto

暗号化・復号化でやり取りするデータの種類について(プレーンテキスト,バイナリ,Hex,Base64)

暗号化についての基礎知識が皆無だった僕には、まずデータフォーマットについての予備知識が必要でした。
as3cryptoライブラリでは、プレーンテキストとHex文字列やbase64文字列とを簡単に変換することができるクラスが用意されています。
暗号化・復号化には、3種の文字列(プレーンテキスト、Hex、base64)とバイナリとの変換が必要ですので、as3cryptoライブラリを利用して各種変換する方法をご参考ください。

※また、暗号化・復号化の際に必ず出てくる用語についてのメモ書きをページ下部に列記しましたので、「バイナリ?聞いたことあるけど...」という僕くらいの方は目を通しておいてくださいね。


サンプルコード

下記.flaファイルをダウンロードください(flashCS3)。

.flaファイル

http://www.ideamans.com/_dat/sample-1.fla (約65KB)

上記の内容
import com.hurlant.util.Hex;
import com.hurlant.util.Base64;

/*■プレーンテキスト*/

	//半角文字の場合
	var strA:String;
	strA = 'abcdef';
	trace('プレーンテキスト(半角文字):\n' + strA + '\n');

	//全角文字(マルチバイトの場合)
	var strB:String;
	strB = 'あいうえお';
	trace('プレーンテキスト(全角文字):\n' + strB + '\n');
	

/*■バイナリ変換*/
	
	//半角文字の場合
	var baA:ByteArray = new ByteArray();
	baA.writeUTFBytes( strA);
	
	//全角文字(マルチバイトの場合)
	var baB:ByteArray = new ByteArray();
	baB.writeMultiByte( strB , "utf-8");


/*■2進数に変換して0と1の文字列で表す(確認のため)*/

	var i:int;
	//半角文字の場合
	var strA2:String = '';
	for ( i = 0; i <baA.length; i++ ){
		strA2 += baA[i].toString(2);
	}
	trace('バイナリを2進数の文字列に(半角文字):\n' + strA2 + '\n');
	
	//全角文字(マルチバイトの場合)
	var strB2:String = '';
	for ( i = 0; i <baB.length; i++ ){
		strB2 += baB[i].toString(2);
	}
	trace('バイナリを2進数の文字列に(全角文字):\n' + strB2 + '\n');


/*■Hex文字列変換*/
	//import com.hurlant.util.Hex を利用します
	
	//(1) プレーンテキストをHex文字列に変換
	var strHexA:String;
	strHexA = Hex.fromString(strA);
	trace('(1) プレーンテキストをHex文字列に変換:\n' + strHexA + '\n');
	
	//(2) バイナリをHex文字列に変換
	var strHexB:String;
	strHexB = Hex.fromArray(baA);
	trace('(2) バイナリをHex文字列に変換:\n' + strHexB + '\n');	
	
	//(1)と(2)が同じになりますね
	
	//(3) Hex文字列をプレーンテキストに変換
	var hexStr:String;
	hexStr = Hex.toString( strHexA );
	trace('(3) Hex文字列をプレーンテキストに変換:\n' + hexStr + '\n');		

	//(4) Hex文字列をバイナリに変換
	var hexBa:ByteArray;
	hexBa = Hex.toArray( strHexA );
	
	//2進数に変換して0と1の文字列で表す(確認のため)
	var hexBaStr:String = '';
	for ( i = 0; i <hexBa.length; i++ ){
		hexBaStr += hexBa[i].toString(2);
	}	
	trace('(4) Hex文字列をバイナリに変換し、確認の為2進数に変換して0と1の文字列で表す:\n' + hexBaStr + '\n');			


/*■base64文字列変換*/
	//import com.hurlant.util.Base64 を利用します

	//(5) プレーンテキストをBase64文字列に変換
	var strB64:String;
	strB64 = Base64.encode(strA);
	trace('(5) プレーンテキストをBase64文字列に変換:\n' + strB64 + '\n');
	
	//(6) バイナリをBase64文字列に変換
	var baB64:String;
	baB64 = Base64.encodeByteArray(baA);
	trace('(6) バイナリをBase64文字列に変換:\n' + baB64 + '\n');
	
	//(5)と(6)が同じになりますね
	
	//(7) Base64文字列をプレーンテキストに変換
	var b64Str:String;
	b64Str = Base64.decode( strB64 );
	trace('(7) Base64文字列をプレーンテキストに変換:\n' + b64Str + '\n');
	
	//(8) Base64文字列をバイナリに変換
	var b64Ba:ByteArray;
	b64Ba = Base64.decodeToByteArray( strB64 );
	
	//2進数に変換して0と1の文字列で表す(確認のため)
	var b64BaStr:String = '';
	for ( i = 0; i <b64Ba.length; i++ ){
		b64BaStr += b64Ba[i].toString(2);
	}	
	trace('(8) Base64文字列をバイナリに変換し、確認の為2進数に変換して0と1の文字列で表す:\n' + b64BaStr + '\n');
出力結果
プレーンテキスト(半角文字):
abcdef

プレーンテキスト(全角文字):
あいうえお

バイナリを2進数の文字列に(半角文字):
110000111000101100011110010011001011100110

バイナリを2進数の文字列に(全角文字):
111000111000000110000010111000111000000110000100111000111000000110000110111000111000000110001000111000111000000110001010

(1) プレーンテキストをHex文字列に変換:
616263646566

(2) バイナリをHex文字列に変換:
616263646566

(3) Hex文字列をプレーンテキストに変換:
abcdef

(4) Hex文字列をバイナリに変換し、確認の為2進数に変換して0と1の文字列で表す:
110000111000101100011110010011001011100110

(5) プレーンテキストをBase64文字列に変換:
YWJjZGVm

(6) バイナリをBase64文字列に変換:
YWJjZGVm

(7) Base64文字列をプレーンテキストに変換:
abcdef

(8) Base64文字列をバイナリに変換し、確認の為2進数に変換して0と1の文字列で表す:
110000111000101100011110010011001011100110

用語予備知識メモ

プレーンテキスト

「平文」とも。通常判読可能な文字列です。この文章もプレーンテキストとして変換表示されている。ということになります。

(プレーンテキスト)
本日は晴天なり
Binary(バイナリ)

プレーンテキスト形式(文字データ)以外のデータ形式全般のこと。

コンピュータが解釈する情報は「0」と「1」の2進法の数で構成される。0あるいは1の情報単位はビットと呼ばれる。1ビットが8つ並んで8ビットを形成すると、256種類のアルファベット、数字、カナなどの文字に対応させることができる。日本語の漢字を表現するには2バイトが必要である。2バイトあると4096文字までに対応させることができる。

バイト (byte)とは: - IT用語辞典バイナリ

僕らが普段PCで読んでいる文(文字)は、0か1かの数字の組み合わせで形成されています。
暗号化・復号化には、この「0110101011…」といったデータの並び(バイナリデータ)を利用します。

(プレーンテキスト)
本日は晴天なり

↓↓上記を2進数で表記↓↓↓

(バイナリ)
1001011001111011100100111111101010000010110011011001000010110000100100110101011010000010110010001000001011101000

(解説)
全角日本語1文字は2バイト(16ビット)で構成されるのでプレーンテキストの「本」は「1001011001111011」、

10010110 01111011 → 本
10010011 11111010 → 日
10000010 11001101 → は
10010000 10110000 → 晴
10010011 01010110 → 天
10000010 11001000 → な
10000010 11101000 → り

文字コードShift_jisを想定しています

Hex

Hex(Hexadecimal number)とは、

「基数を16とした数値の表現方法」で0〜9までの数字とA〜Fまでの文字を用いた文字列のことをいいます。

16進数とは 【hexadecimal number】 - 意味・解説 : IT用語辞典

16進数は,2進数の代用としてよく使われます。16進数と2進数は相互に変換が容易です。16進数の1桁が2進数の4桁にピッタリ一致するからです。その理由が分かりますか?2進数の4桁は2倍を4回分ですから,2進数の4桁=2倍×2倍×2倍×2倍=16倍=16進数の1桁になるからです。

【5分で覚えるIT基礎の基礎】ゼロから学ぶ2進数 第5回:ITpro

(プレーンテキスト)
本日は晴天なり

↓↓上記を2進数で表記↓↓↓

(バイナリ)
1001 0110 0111 1011 → 本
1001 0011 1111 1010 → 日
1000 0010 1100 1101 → は
1001 0000 1011 0000 → 晴
1001 0011 0101 0110 → 天
1000 0010 1100 1000 → な
1000 0010 1110 1000 → り

↓↓上記を16進数で表記↓↓↓

9 6 7 B → 本
9 3 F A → 日
8 2 C D → は
9 0 B 0 → 晴
9 3 5 6 → 天
8 2 C 8 → な
8 2 E 8 → り

↓↓
(Hex文字列)
967B93FA82CD90B0935682C882E8
Base64

2進数のバイナリデータを0123456789ABCDEFの16文字に置き換えるHexのほかに、下記の62つの文字、2つの記号と余白で置き換えた文字列のことをいいます。
後述するPadding(パディング)の存在をここで知りました。

Wikiの説明が分かりやすいですね。

A–Z, a–z, 0–9 までの62文字と、記号2つ (+ , /) 、さらにパディング(余った部分を詰める)のための記号として = が用いられる。この変換によって、データ量は4/3になる。

(Base64 - Wikipedia)

Wikiより引用)
変換例
元データ 
文字列: "ABCDEFG" 
16進数: 41, 42, 43, 44, 45, 46, 47 
2進数: 0100 0001, 0100 0010, 0100 0011, 0100 0100, 0100 0101, 0100 0110, 0100 0111 
6bitずつに分割 
010000 010100 001001 000011 010001 000100 010101 000110 010001 11 
2bit余るので、4bit分0を追加して6bitにする 
010000 010100 001001 000011 010001 000100 010101 000110 010001 110000 
変換表により、4文字ずつ変換 
"QUJD","REVG","Rw" 
2文字余るので、2文字分 = 記号を追加して4文字にする 
"QUJD","REVG","Rw==" 
Base64文字列 
"QUJDREVGRw==" 

次回予告

ActionScript3.0で暗号化・復号化のメモ(2) MD5,SHA,AES,DES,3DES,BlowFish
  • 暗号化・復号化の予備知識メモ
  • ハッシュ関数
    • MD5を利用する
    • SHAを利用する
  • 共通鍵暗号化・復号化
    • AESを利用する
    • DES,3DESを利用する
    • BlowFishを利用する

DreamweaverでSmartyを扱うための設定メモ[改訂版]

かなり前に、弊社のブログ(現在休止中)でエントリーした内容ですが、今読み返して見ると文字化けを起こしていたり、ソースコードが読みにくかったり、リンク切れを起こしていたり…となかなか厄介な状態だったので、ここに改訂版を掲載しようかと思います。

大げさなタイトルですが、Dreamweaverでの編集画面でSmartyインクルード{include file="〜"}を表示させるための各設定方法です。

また、MVCモデルで開発・制作を進める際に、ビュー用のテンプレート(例:/templates/)と画像やCSS(例:/htdocs/images/〜など)が、Dreamweaverでの編集画面でデッドリンクを起こす場合の対処法も載せていました。(Windowsディレクトリにエイリアス貼るだけですけど)
この件は、先日のSmartyを利用したもっともシンプルなWeb制作の環境づくりの環境では必要がないので割愛しています。(ご興味のある方は、旧版の方をご覧ください。読みにくくて申し訳ないです)

それでは以下、転載いたします。

はじめに

弊社のフレームワークに欠かせないDreamweaverSmartyの連携。
ですが、いくらCS3とはいえデフォルトの仕様ではちと厳しいオーサリング状況。

大きな問題点は、Smartyほかテンプレートの最大メリットである「テンプレート同士のインクルード{include}」がDWで再現されないこと。
ヘッダー・フッターは共有化部分の筆頭なので編集画面で確認できないのは痛いですね。

このままではリアルタイムにデザインビューを確認しながらオーサリングというDWの強みを生かすことができません。
早速、Smartyの{include}をDreamweaverで再現する方法を2点ばかり見つけました。

Smartyの{include}をDreamweaverで再現する方法

Use Smarty in Dreamweaver

上記ページの説明

下記の箇所に設定用ファイル(任意.htm)を設置します。
※HDD(C)にDreamWeaver8をインストールしている場合

C:\Program Files\Macromedia\Dreamweaver 8\Configuration\Translators

設定用ファイルの内容は下記とします。

<html>
<head>
<title>Smarty Include Tag Translator</title>
<meta http-equiv="Content-Type" content="text/html; charset=">
<script language="JavaScript">

/**
 * This translator will only work on this format:
 * {include file="foo.tpl"}
 * filename must surrounded by double or single quotes
 * if 'assign' or '[var]' attribute exists, it will not tranlated
 * the include tag must be in one line
 * extra spaces are allowed, e.g. { include file = " foo.tpl " }
 * all templates file suppose to stay in the same top 'templates' folder
 * you can include subfolder in the include tag
 * all other formats will be displayed as a simple 'inc' icon
 */

/**
 * define smarty delimiters
*/

var LDELIM = "{";
var RDELIM = "}";


function getTranslatorInfo()
{
	var transArray = new Array(6);
	transArray[0] = "SMARTY_INCLUDE";
	transArray[1] = "Smarty Include Translator";
	transArray[2] = "0";
	transArray[3] = "1";
	transArray[4] = LDELIM + "[ \t]*include";
	transArray[5] = "byExpression";
	return transArray; 
}

function translateMarkup( docNameStr, siteRootStr, inStr )
{
	var pos = 0;
	var patternFound = false;
	var outStr = '';
	var depPath = '';
	var remainInStr = inStr;
	smartyRegExp = new RegExp("(" + LDELIM + "[ \t]*include[ \t]+file[ \t]*=[ \t]*[\"|'][ \t]*([^\"^']*)[ \t]*[\"|'][ \t]*[^"+RDELIM+"]*" + RDELIM + ")", "im");
	while ((pos = remainInStr.search(smartyRegExp)) >= 0)
	{
		var matchStr = RegExp.$1;
		var templateFileName = RegExp.$2;
		var templateFullName = templateFileName;
		var smartyFile;
		outStr += remainInStr.substr(0, pos);
		smartyFile = new File(templateFullName, docNameStr);
		if (smartyFile.exists())
		{
			smartyContent = smartyFile.getContents();
			if (smartyContent.length <= 0)
			{
				// this is an empty file
				smartyContent = "&nbsp;";
			}
			depPath = smartyFile.getAbsolutePath();
		}
		else
		{
			// file doesn't exist
			smartyContent = "File Error!";
		}
		
		// Do translation
		outStr += '<MM:BeginLock translatorClass="' + getTranslatorInfo()[0] + '" type="smartyInclude" orig="' + escape(matchStr) + '"';
		if (depPath.length > 0)
			outStr += ' depFiles="' + depPath + '"';
		outStr += '>' + smartyContent + '<MM:EndLock>';
		
		// Re-search text following match
		remainInStr = remainInStr.substring(pos + matchStr.length);
		// Remember that at least one translation was performed
		patternFound = true;
	}
	outStr += remainInStr;
	return patternFound ? outStr : "";
}
</script>
</head>
<body>
</body>
</html>

うまくいかない場合は、下記の行を書き換えてください。

smartyRegExp = new RegExp("(" + LDELIM + "[ \t]*include[ \t]+file[ \t]*=[ \t]*[\"|'][ \t]*([^\"^']*)[ \t]*[\"|'][ \t]*" + RDELIM + ")", "im");

上記を次に書き換えます。

smartyRegExp = new RegExp("(" + LDELIM + "[ \t]*include[ \t]+file[ \t]*=[ \t]*[\"|'][ \t]*([^\"^']*)[ \t]*[\"|']+([^}]*)" + RDELIM + ")", "im");


以上で、Smartyの{include}がDreamweaverでも表示されるようになります。

他にDreamweaverSmarty拡張機能を見つけたのでご紹介します。

Smartyタグをアイコンで表示する方法

{include}以外でも{if]〜{/if}や{foreach}〜{/foreach}などのSmartyタグを記述した場合、Dreamweaverでの編集画面が崩れてしまう場合があります。
下記はレイアウトの再現性を高めるために有用かと思います。


Smarty Tags for DreamWeaver

上記サイトより「dreamweaver_smartytags.zip」をダウンロード後、下記に解凍したファイル群を全て設置してください(フォルダではなく複数ファイルを置いてください)

C:\Program Files\Macromedia\Dreamweaver 8\Configuration\ThirdPartyTags\

下図の様にSmartyタグ部分がアイコンで表示されます。すっきりしますね。


こんな感じが…

こんなにすっきりと…

Smartyを利用したもっともシンプルなWeb制作の環境づくり

発端 -Smartyはデザイナーにもありがたい-

中・大規模の開発案件で、ビュー(UI・デザイン)を担当することもあって、僕にとって、Smartyを利用したコーディングは馴染み深いものになりました。
Smartyに慣れてしまうと機能系・開発系の案件だけでなく、静的なWebサイト制作にも利用したくなってしまうような便利な機能が満載です。

そこで、デザイナーさん視点からSmartyを利用したもっともシンプルでスマート(スマーティ?)な制作環境を用意できれば、共感してくれる方も中には居るんじゃないかな。
などと思い立ち、はてなダイアリーデビューをしてしまった次第です。

サンプルファイル一式のダウンロード

下記にサンプルファイル一式をUPいたしました。
ディレクトリやファイル構造などの説明ばかりなので、予めDLいただいたほうが分かりやすいかもしれません。

Smarty Dev ver0.1(zip形式 約98KB)

http://www.ideamans.com/_dat/SmartyDev010.zip
Smartyのライセンス上、Smarty一式を2次配布してしまってよいものかどうか、こちらも取り急ぎ確認しています。でも、EC-CUBESmarty込みで一式DLできちゃうよね...

ファイル構造の説明

/Smarty/  …… Smarty一式(特に変更なしにザクっとUPしてください)
/_cache/  …… Smartyのキャッシュ格納用ディレクトリ(特に変更なしにザクっとUPしてください。パーミッションは777(とか707とか)書込権限が必要です)
/_common/  …… デザイナーさんがご自由に設置するimage,js,css,swfなどのファイル格納用ディレクトリ(_commonていうのは僕(弊社)の癖)
/test/   …… デザイナーさんがご自由に設置するディレクトリ(何個でも、何階層でもご自由にどうぞ)
 index.html…… デザイナーさんがご自由に作成する静的ページ(なんだけども、実はSmartyテンプレート)
index.html …… 同上
.htaccess  …… Smartyテンプレートファイルを静的ファイルであるかの様に扱う為の設定(基本は変更なしです。サーバー環境によっては変更が必要かも)

上記をみると、
Smarty,_cacheディレクトリ」と「.htaccess」以外は、普段のWeb制作の構造と全く同じになっています。たぶん。
index.htmlやhogehoge.htmlは自由に何処にでも設置可能で、URLもその通りに表示されます。つまり...

/FOO/HOGE/test.htmlに設置したファイルは、

http://hogehoge.com/FOO/HOGE/test.html

として表示されます。
がしかし、test.htmlにはSmarty構文を記述することができるんです。

Smartyってすばらしい -でも開発者さんの反応はいたって普通の件(※註)-

いままで、requre_once(php)やSSI、JavaScript果てはFlashにしちまうか。といった苦心も、

{include file="外部のテンプレート" foo="変数渡せる"}

が使えますし、

何度も何度も繰り返し記述しなきゃいけない(でもシステム開発するほどではない)場合、

{assign var="FOO" value="HOGEHOGE"}
で変数をセットして、
{$FOO}何度でも
{$FOO}何度でも

使えますし、コーディング補助機能として有用のように感じます。

※註)
開発者さん「そりゃオメーがSmartyに慣れてるからだろ。新しい記述を学ぶ手間考えたら、PHPでいいんじゃん?」
僕(デザイナー)「そうじゃないって。DreamWeaverの奇怪なテンプレート機能つかって苦心してる人だっているんだぞ〜?それにくりゃべりゃアンタ、Smartyなんて、シンプルなほうだよ!」

CSSSmarty使えるようにしました

本当は、これがやりたかったんです。
サイトの統一感を出すために、サイトを構築していくとカラー設定は次第に絞られていきます。
シーズン毎のリニューアルなどに対応するため、外部CSSで一括設定する。なんて構成で設計される方もおられるかと。

colorやbockground-color,marginやブラウザハックの記述など、繰り返し記述することが多い場合は
{assign}で最初に一括設定してしまいましょう。

/_common/css/common.cssの記述例
{assign var="clr_green" value="#006600"}
{assign var="clr_black" value="#000000"}

{if $smarty.get.flg=='A'}
 body {{
  background-color:{$clr_green};
 }}
{/if}

{if $smarty.get.flg=='B'}
 body {{
  background-color:{$clr_black};
 color:#FFFFFF;
 }}
{/if}

ここで、CSSの記述に用いる”{}”に独自のルールを適用しました。(Smartyの{}とバッティングしてしまうため)
CSSでの"{"は"{{"に。
"}"は"}}"と記述しなければなりませんのでご了承ください。

あるいは、下記のように記述しても同じ結果となります。

{assign var="clr_green" value="#006600"}
{assign var="clr_black" value="#000000"}

{if $smarty.get.flg=='A'}
 body {rdelim}
  background-color:{$clr_green};
 {ldelim}
{/if}

{if $smarty.get.flg=='B'}
 body {rdelim}
  background-color:{$clr_black};
 color:#FFFFFF;
 {ldelim}
{/if}

※上記のように記述するのがめんどうなので{{〜}}という略式表示にしてみました。

構造の説明(は特に無く)

そもそも、Smartyの構造(しくみ)を理解される開発者さん達にとっては、このような環境設定は「とるに足らぬ事」と思います。むしろ劣化版と思われるかもしれない。
おそらく開発者さんは配布ファイル一式を斜め読みしただけで、「ふふぅん、mod_rewriteとここの●●に××を集約してるだけかい」ということがご理解いただけるかと思います。

まぁでも、今回の目標はそこじゃなくって、デザイナーさんが如何にPHPとかMVCとかいう領域を意識せずに、
自然にSmartyを利用するかにフォーカスしてますんで、細かい説明は特に必要ないかなと思ってます。


動作環境

ロリポップCORESERVERなど、低価格な共有レンタルサーバーでは「配布ファイル一式をごっそりUPして即稼動」OKなところが多かったです。
現在テスト確認中ですが...

(そのままUPで利用可能だったサーバー)

.htaccessの変更が必要そうなサーバー)

  • heteml

(未確認)

  • ラピッドサイト(共有系)
  • アイル(共有系)
  • @YMC(共有系)
  • 等など

サーバー環境は、

PHPがインストールされていて、
mod_rewriteが利用可能であれば大丈夫かと思います。
phpのバージョンは4系、5系どちらでもOKでしょう。


締め

一通り思いつくことは書いたつもりですが、果たしてどれだけ伝わるんだろう...
僕の説明下手、調査と知識の不足は日々アップデートしていきます。

一人でもいいんです。共感してくれる方がいたら、僕は泣きます。

ではまた。