PHPではエラーが発生した場合わりとわかりやすく教えてくれますが、テキスト表示なので素っ気ないです。
ビジュアル的に表示してくれるツールとしてXDebugというものがあります。
エラーが発生した周辺のトレースなんかも行ってくれ、デバッグがちょっとだけやりやすくなります。
導入はxgebug.orgからダウンロードしてきてインストールするのが正道ですが、例によってXAMPPには最初から入っていたりします。
php.iniにも予めXdebugの定義が書かれており、コメントを外すだけで使用できます。
デフォルトで使用されている[Zend]セクションを全てコメントアウトし、[XDebug]セクションのコメントを外します。
丁寧にも「Only Zend OR (!) XDebug」なんて注意書きまでしてくれているのでおとなしく従いましょう。
php.ini
[XDebug] ;; Only Zend OR (!) XDebug zend_extension_ts="C:\xampp\php\ext\php_xdebug.dll" xdebug.remote_enable=true xdebug.remote_host=127.0.0.1 xdebug.remote_port=9000 xdebug.remote_handler=dbgp xdebug.profiler_enable=1 xdebug.profiler_output_dir="C:\xampp\tmp" |
適当にエラーが出るコードを書いて実行すると、↓のようにテーブル表記でエラー部分をわかりやすく表示してくれます。
[Zend] Warning: Wrong parameter count for substr() in C:\xampp\htdocs\index.php on line 3
[XDebug]
( ! ) Warning: Wrong parameter count for substr() in C:\xampp\htdocs\index.php on line 3
Call Stack
#
Time
Memory
Function
Location
1
0.0008
57224
{main}( )
..\index.php:0
2
0.0008
57336
substr ( )
..\index.php:3
あと、副作用でvar_dump()の表示も色つきに変化します。
まあ、慣れれば通常の表示でも十分ではあるのですが、やっぱ見た目が明るいとなんとなく違うというか。
ただ問題点として、変数の中身が長すぎると途中で端折られてしまいます。
出力の時点で消えているため、どうやっても確認することができないので物凄い迷惑。
端折られるサイズの制限は、php.iniに
xdebug.var_display_max_data //表示する最大データサイズ、デフォルト512
xdebug.var_display_max_depth //配列やオブジェクトを表示する深さ、デフォルト3
を追加すると変更することができます。
var_display_max_data=65535、var_display_max_depth=20くらいに変えてしまいましょう。
Smartyインスタンスをvar_dump()するとわかりますが、Smarty::assignした変数はSmarty::_tpl_varsに入っています。
で、Smarty::_tpl_varsはPHP4互換のためvarで宣言されているので外部から書き換えが可能です。
さて、これで何が便利かというとテンプレート内から配列にアサインしたい場合です。
テンプレート内で変数をアサインすることができます。
{assign var='title' value='hoge'}
{$title}
とすると$titleで'hoge'を表示することができます。
ところがこの{assign}、実は配列をアサインすることができません。
そんな場合に{assign}が覗いている先を直接書き換えてしまいます。
{php}
$this->_tpl_vars['aaaa'] = array('aa'=>'hoge','bb'=>'fuga');
{/php}
これで{$aaaa.aa}で'hoge'を表示することができるようになりました。
まあ、そもそもテンプレート内で配列をアサインするような設計になっている時点でどこかがおかしいんですがね。
ここで出てくる{php}ですが、これは{php}{/php}で挟まれた部分をPHPとして解釈するという極めて危険な関数です。
これを使用した時点でSmartyの役目が台無しです。
というわけで、$smarty->security=true;とすると使用を禁止することができます。
これで安全といえば安全なのですが、同時にPHP関数の修正子も使用できなくなってしまいます。
使用できるのはpluginsフォルダに入っている、カスタム修正子を含めた修正子だけとなります。
{$text|substr:5:10}とかも使えなくなってしまうのが少々困りもの。
{php}だけ禁止して他はおっけーとかの設定はできんものかのう。
前{html_select_date}、{html_select_time}を紹介しましたが、それ以外のフォームもSmartyから簡単に作成できます。
html_input.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
//Smarty
require_once('./../smarty/libs/Smarty.php');
//チェックボックス
$form_checkbox=array(
'1'=>'チェックボックス1'
,'2'=>'チェックボックス2'
,'3'=>'チェックボックス3'
,'4'=>'チェックボックス4'
);
$form_checkbox_selected=array(2,4);
//ラジオボタン
$form_radiobutton=array(
'1'=>'ラジオボタン1'
,'2'=>'ラジオボタン2'
,'3'=>'ラジオボタン3'
,'4'=>'ラジオボタン4'
);
$form_radiobutton_selected=3;
//ドロップダウンリスト
$form_option=array(
'1'=>'リスト1'
,'2'=>'リスト2'
,'3'=>'リスト3'
,'4'=>'リスト4'
);
$form_option_selected=3;
//変数アサイン
$smarty->assign('form_checkbox',$form_checkbox);
$smarty->assign('form_checkbox_selected',$form_checkbox_selected);
$smarty->assign('form_radiobutton',$form_radiobutton);
$smarty->assign('form_radiobutton_selected',$form_radiobutton_selected);
$smarty->assign('form_option',$form_option);
$smarty->assign('form_option_selected',$form_option_selected);
//表示
$smarty->display('html_form.html');
|
html_form.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<html><body>
{html_checkboxes name='form_checkbox' options=$form_checkbox
selected=$form_checkbox_selected separator='<br />'}
{html_radios name='form_radio' options=$form_radiobutton
selected=$form_radiobutton_selected separator='<br />'}
{html_options name='form_option' options=$form_option
selected=$form_option_selected}
{* checkboxを自力で表示する *}
{foreach from=$form_checkbox key=form_key item=form_item}
<input type="checkbox" name="form_checkbox[]" value="{$form_key|escape}"
{if $form_key|in_array:$form_checkbox_selected}checked="checked" {/if}>
{$form_item|escape}
</input><br />
{/foreach}
</body></html>
|
チェックボックス、ラジオボタン、ドロップダウンリストが簡単にできました。
その下に書いてある自力での表示と比べるとその威力は一目瞭然です。
内容が予め決まっているようなフォームであればテンプレートに書いてしまっても問題無いでしょうが、データベースに一覧を入れておいてそこから選択させるようなフォームを作りたい場合などに役に立つことでしょう。
前したらば削除スクリプトを公開しましたが、2009/08初頭に行われた管理画面改修のせいで動かなくなっていました。
というわけで新管理画面に対応した版を作成しました。
もし万一使っていた人がいたら差し替えてください。
ダウンロード(zip)
したらば管理画面について所感。
前の管理画面はどこかに移動するたびにパスワードをhiddenで持ち回すという有り得ない作りだったのですが、新管理画面になってようやくログインとセッション機構が導入されました。
まあログインのセッションを無期限にしているとかこれまたちょっとどうなのよという感じなのですが、それでも前のよりはよっぽどマシです。
ただ、よくわかんないのが各管理画面の遷移。
何故か知らんが何かを送信するたびに一旦302でリダイレクトするんだよね。
おかげで標準関数での実装に手間取り、Zend_Httpを使用することになりました。
ZendFrameworkが入ってないという人は、ここらへんかを参考に入れてください。
まあ、インストールせずとも、たぶんZend/Httpフォルダ丸ごとアップロードで動かなくもない気もしないでもないです。
前回の続き。
テンプレを作成してバリデータと合わせました。
index.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
|
//=========================================================================
//準備
//根本のフォルダ
$base_dir=dirname(__FILE__).DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR ;
define('BASE_DIR',$base_dir);
//必要なファイルをインクルード
require_once('../../smarty/libs/Smarty.class.php');
//=========================================================================
//クラス
class HtmlForm{
//-------------------------------------------------------------------------
//インスタンス変数等
//Smartyテンプレ、キャッシュ置き場
private $smarty_template_dir='../templates/';
private $smarty_compile_dir='../templates_c/';
//エラーメッセージ入れ
protected $error_message_array=array(
'error_name_null'=>'氏名が入力されていません'
,'error_age_null'=>'年齢が入力されていません'
,'error_age_int'=>'年齢が正しくありません'
);
//-------------------------------------------------------------------------
//コンストラクタ
public function __construct(){
//Smarty
$this->smarty=new Smarty();
$this->smarty->template_dir = $this->smarty_template_dir;
$this->smarty->compile_dir = $this->smarty_compile_dir;
//実行メソッドを呼ぶ
$this->init();
exit();
}
//-------------------------------------------------------------------------
//実行
public function init(){
//実行するメソッド選択
if(isset($_REQUEST['form_input'])){
$this->FormInput();
}elseif(isset($_REQUEST['form_complete'])){
$this->FormComplete();
}else{
$this->FormIndex();
}
}
//-------------------------------------------------------------------------
//表示
public function view($template_file='index.html'){
//変数アサイン
//$this->dataに突っ込めば$dataで表示できる
$this->smarty->assign('data',$this->data);
//$_REQUESTは常時参照可能
$this->smarty->assign('request',$_REQUEST);
//表示
$this->smarty->display($template_file);
exit();
}
//-------------------------------------------------------------------------
//投稿内容一覧画面
public function FormIndex(){
//表示内容取得
$data_array=array();
$tmp_array=file('data.txt',
FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES );
foreach($tmp_array as $data){
$data_array[]=explode("\t",$data);
}
$this->data['data_array']=$data_array;
//表示
$this->view('form_index.html');
}
//-------------------------------------------------------------------------
//フォーム入力画面
public function FormInput(){
//表示
$this->view('form_input.html');
}
//-------------------------------------------------------------------------
//フォーム入力完了画面
public function FormComplete(){
//入力値のバリデート
$ret=$this->_FormValidate($_REQUEST);
if(!$ret){
$this->FormInput();
}elseif($ret['error']){
$this->data['error_message']=
$this->_FormSetErrorCode($ret['error']);
$this->FormInput();
}
//保存
$data=implode("\t",$_REQUEST)."\r\n";
file_put_contents('data.txt',$data,FILE_APPEND);
//表示
$this->view('form_complete.html');
}
//=========================================================================
//-------------------------------------------------------------------------
//サブルーチン//入力値チェック
public function _FormValidate($request_array){
//引数
if(!$request_array){return false;}
$ret=array();
//バリデート
if(!$request_array['name']){
$ret['error'][]='error_name_null';
}
if(!$request_array['age']){
$ret['error'][]='error_age_null';
}elseif(!is_numeric($request_array['age'])){
$ret['error'][]='error_age_int';
}
//返却
if($ret['error']){
return $ret;
}else{
return true;
}
}
//-------------------------------------------------------------------------
//サブルーチン//エラーメッセージを入れておく
public function _FormSetErrorCode($error_code_array=array()){
//引数
if(!is_array($error_code_array)){return false;}
//返り値
$ret=array();
//各エラーコードに対してエラーメッセージを対応させる
foreach($error_code_array as $error_code_val){
$ret[]=$this->error_message_array[$error_code_val];
}
//返却
return $ret;
}//クラスのおわり
}
|
templates/form_index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>投稿フォーム</title>
</head>
<body>
<a href="./?form_input=1">発言する</a><br />
{if $data.data_array}
<table border=1>
<tr>
<th>投稿日</th><th>氏名</th><th>年齢</th><th>発言</th>
</tr>
{foreach from=$data.data_array item=data_item }
<tr style="background:{cycle values='lightcyan,peachpuff'};">
<td>
{$data_item.0|date_format:"%Y-%m-%d %H:%M:%S"}
</td>
<td>
{$data_item.1|escape}
</td>
<td>
{$data_item.2|escape}
</td>
<td>
{$data_item.3|escape}
</td>
</tr>
{/foreach}
</table>
{/if}
</body>
</html>
|
templates/form_input.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>投稿フォーム</title>
</head>
<body>
{if $data.error_message}
<div style="color:red;">
{foreach from=$data.error_message item=error_message_val}
{$error_message_val|escape}<br />
{/foreach}
</div>
{/if}
<form method="POST" action="./?form_complete=1">
氏名:
<input type="text" name="name" size="20"
maxlength="20" value="{$request.name|escape}" /><br />
年齢:
<input type="text" name="age" size="10"
maxlength="4" value="{$request.age|escape}" /><br />
発言:
<input type="text" name="val" size="10"
maxlength="4" value="{$request.age|escape}" /><br />
<input type="submit" value="投稿する">
</form>
</body>
</html>
|
templates/form_complete.html
1
2
3
4
5
6
7
8
9
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>投稿フォーム</title>
</head>
<body>
投稿されました
</body>
</html>
|
保存読み込み部分がアバウトすぎて、改行やタブを送信されたら死ぬというどうにもならないフォームです。
まあそこらへんどうにかしようとすればどうにでもなるのですが、面倒なので今回はパス。
DBに突っ込めば面倒なことを考える必要もないので、特に理由のない限り余計なことはせずにDBにしてしまいましょう。
それに保存用の関数などは直接書かず、それ用のクラスを作ってそちらに投げた方が色々と便利です。
バリデータの部分はもうちょっとerror_name_nullみたいなのを直接書かずにHtmlForm::error_message_arrayあたりをうまく利用して定義するべきなんですが、これもまあ面倒なのでいいや。
やりすぎてZend_Formみたいな意味不明状態になってもなんですし。
本当は投稿完了画面なんて要らなくて、インデックスに投稿完了した旨表示するだけでかまわないと思うのですが、何故か皆付けたがるので作っています。
まあそこらへんの遷移は好きなようにしてください。
こんなかんじで昔のよりちょっとだけソースが綺麗なような気がしないでもないフォームが完成しました。
見た目を変えたい場合は各HTMLファイルだけを触ればいいのでPHPの知識は不要となり、ロジックを触る場合はphpファイルを触ればいいのでデザインを壊す心配をする必要もありません。
いいことづくめですね。
まあ、といいつつプログラマがデザインの修正もさせられるのが世の常なんですが…
前回形は作ってしまったので、後はこりこり書いていくだけです。
投稿内容は後でどうとでも修正できるのでとりあえず氏名、年齢、発言という簡単なフォームで、テンプレ以外はまあこんな感じでしょう、ということで途中まで作ったの図。
/form/lib/index.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
//=========================================================================
//準備
//根本のフォルダ
$base_dir=dirname(__FILE__).DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR ;
define('BASE_DIR',$base_dir);
//必要なファイルをインクルード
require_once('../../smarty/libs/Smarty.class.php');
//=========================================================================
//クラスclass HtmlForm{
//-------------------------------------------------------------------------
//インスタンス変数等
//Smartyテンプレ、キャッシュ置き場
private $smarty_template_dir='../templates/';
private $smarty_compile_dir='../templates_c/';
//エラーメッセージ入れ
protected $error_message_array=array(
'error_name_null'=>'氏名が入力されていません'
,'error_age_null'=>'年齢が入力されていません'
,'error_age_int'=>'年齢が正しくありません'
);
//-------------------------------------------------------------------------
//コンストラクタ
public function __construct(){
//Smarty
$this->smarty=new Smarty();
$this->smarty->template_dir = $this->smarty_template_dir;
$this->smarty->compile_dir = $this->smarty_compile_dir;
//実行メソッドを呼ぶ
$this->init();
exit();
}
//-------------------------------------------------------------------------
//実行
public function init(){
//引数によって実行するメソッドを分岐
if(isset($_REQUEST['form_input'])){
$this->FormInput();
}elseif(isset($_REQUEST['form_complete'])){
$this->FormComplete();
}else{
$this->FormIndex();
}
}
//-------------------------------------------------------------------------
//表示
public function view($template_file='index.html'){
//変数アサイン
//$this->dataに突っ込めば$dataで表示できるようにします
$this->smarty->assign('data',$this->data);
//$_REQUESTは常時参照可能
$this->smarty->assign('request',$_REQUEST);
//表示
$this->smarty->display($template_file);
exit();
}
//-------------------------------------------------------------------------
//投稿内容一覧画面
public function FormIndex(){
//表示内容取得
$this->data['applied_form']=file('data.txt',FILE_IGNORE_NEW_LINES);
//表示
$this->view('form_index.html');
}
//-------------------------------------------------------------------------
//フォーム入力画面
public function FormInput(){
//表示
$this->view('form_input.html');
}
//-------------------------------------------------------------------------
//フォーム入力完了画面
public function FormComplete(){
//入力値のバリデート
$ret=$this->_FormValidate($_REQUEST);
if(!$ret){
$this->FormInput();
}elseif($ret['error']){
$this->data['error_message']=
$this->_FormSetErrorCode($ret['error']);
$this->FormInput();
}
//保存
file_put_contents('data.txt',$ret['data'],FILE_APPEND);
//表示
$this->view('form_complete.html');
}
//=========================================================================
//-------------------------------------------------------------------------
//サブルーチン//入力値チェック
public function _FormValidate($request_array){
//引数
if(!$request_array){return false;}
//バリデート
//返却
return $ret;
}
//-------------------------------------------------------------------------
//サブルーチン//エラーメッセージを入れておく
public function _FormSetErrorCode($error_code_array=array()){
//引数
if(!is_array($error_code_array)){return false;}
//返り値
$ret=array();
//各エラーコードに対してエラーメッセージを対応させる
foreach($error_code_array as $error_code_val){
$ret[]=$this->error_message_array[$error_code_val];
}
//返却
return $ret;
}
//クラスのおわり
}
|
フォームデータを保存する部分は非常にやる気がないので超適当です。
まともに作るときはDBに入れた方が面倒もないでしょう。
$error_message_arrayと_FormSetErrorCode()あたりはもうちょっとどうにかならなかったのだろうか、という気がひしひしとしますが気にしない。
というわけで、あとはテンプレを書いて_FormValidate()と合わせれば完成といったところです。
ところで、私はだいたいいつも今回のようにテンプレを後回しにして作成するのですが、どのような順番で作成するのがいいんでしょうかね?
昔ずいぶん適当な投稿フォームを作りましたが、昨今流行りのクラスを使ってたらりんと書き換えていきましょう。
フォルダ構成はこんなかんじ
/Smarty/(Smarty構成ファイル)
/form/htdocs/index.php
/lib/index.php
/templates/(テンプレ)
/templates_c/(テンプレのキャッシュ置き場)
/form/htdocs/index.php
1
2
3
4
5
6
7
|
//必要なファイルをインクルード
require_once('../lib/index.php');
//実行
$form=new HtmlForm();
|
htdocs/index.phpはDocumentRoot外に出ている唯一のファイルで、万一サーバの設定ミスとかでPHPが処理できない場合でもソースの流出を最小限に抑えます。
あとclassの上にnewを書くとうまく動かないことがあったりなかったりするので、分かれている方が安心。
というわけでlib/index.phpに実際の中身を書いていきます。
/form/lib/index.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
//=========================================================================
//準備
//根本のフォルダ
$base_dir=dirname(__FILE__).DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR ;
define('BASE_DIR',$base_dir);
//必要なファイルをインクルード
require_once('../../smarty/libs/Smarty.class.php');
//=========================================================================
//クラスclass HtmlForm{
//-------------------------------------------------------------------------
//インスタンス変数等
//Smartyテンプレ、キャッシュ置き場
private $smarty_template_dir='../templates/';
private $smarty_compile_dir='../templates_c/';
//-------------------------------------------------------------------------
//コンストラクタ
public function __construct(){
//Smarty
$this->smarty=new Smarty();
$this->smarty->template_dir = $this->smarty_template_dir;
$this->smarty->compile_dir = $this->smarty_compile_dir;
//実行メソッドを呼ぶ
$this->init();
exit();
}
//-------------------------------------------------------------------------
//実行
public function init(){
}
//-------------------------------------------------------------------------
//表示
public function view($template_file='index.html'){
//変数アサイン
//$this->dataに突っ込めば$dataで表示できるようにします
$this->smarty->assign('data',$this->data);
//$_REQUESTは常時参照可能
$this->smarty->assign('request',$_REQUEST);
//表示
$this->smarty->display($template_file);
exit();
}
//-------------------------------------------------------------------------
//投稿内容一覧画面
public function FormIndex(){
}
//-------------------------------------------------------------------------
//フォーム入力画面
public function FormInput(){
}
//-------------------------------------------------------------------------
//フォーム入力完了画面
public function FormComplete(){
}
//=========================================================================
//-------------------------------------------------------------------------
//サブルーチン//入力値チェック
public function _FormValidate(){
}
//-------------------------------------------------------------------------
//サブルーチン//エラーコードを入れておく
public function _FormSetErrorCode(){
}
//クラスのおわり
}
|
別にクラスの利用法とか勉強したわけじゃなく概ね自己流なので本職から見たらこんなのクラスじゃねえとかいわれるのかもしれませんが、さくっと大まかな形だけを整えた状態です。
__construct()やview()、BASE_DIRの定義なんかは基底クラス、定義ファイルとしてどっかに置いておき、実装でそれをrequire_onceなりextendsなりして作成した方が使い回しも効いて便利なんですが、今回はまあいいや。
実際__construct()内の$this->init()なんてこの使い方では全く意味がありません。
スーパークラスにabstract function init()とか書いておいてオーバーライドするのが定石です。
具体的な実装は何も書いていませんが、とりあえずこれでもエラーは出ません。
後は個々のメソッドを埋めていけばそのうち動くようになります。
このようにアバウトな作り方で進められるのもOOPの利点の一つだと思います。
はっ、これがもしかして伝説のエクストリームプログラミング?(多分違う)
ZendFrameworkはCakePHPやEthna等と同じくフレームワークの一種ですが、特徴として各コンポーネントの独立性が高く、一部のモジュールだけを単体で使うことができます。
つうか本気で使用するにはmod_rewriteとかMVCの準備とかいろいろ必要でどうすりゃいいのかよくわからん。
まあモジュールをちょっと使ってみるだけならPear並に簡単です。
まず公式からダウンロードしてきたら適当な場所に解凍します。
で、その中のlibraryフォルダにインクルードパスを通せば後は好きなモジュールを使用することができます。
それどころかpearコマンドでもインストールでき、そうすると本気でPearと同等です。
# cd C:\xampp\php
# pear channel-discover zend.googlecode.com/svn
# pear install zend/zend
こんなかんじで実行するとC:\xampp\php\PEAR\Zendあたりに堂々とインストールされ、後はPearライブラリ呼ぶときと全く同じ使い方ができます。
まあ適当に、試しに簡単そうなZend_Dateを使ってみます。
zend_date1.php
1
2
3
4
5
6
7
8
9
10
11
12
13
|
//Zend_Dateを使用するための初期設定
date_default_timezone_set('Asia/Tokyo');
//Zend_Date
require_once('Zend/Date.php');
$date = new Zend_Date();
//適当に使ってみる
print $date->get();
$date->set('13:00:00',Zend_Date::TIMES);
print $date->get();
|
Fatal error: Uncaught exception 'Zend_Date_Exception' with message 'Missing locale file 'C:\xampp\php\PEAR\Zend\Locale/Data/ja.xml' for 'ja' locale.' in C:\xampp\php\PEAR\Zend\Date.php:2136 Stack trace: #0 C:\xampp\php\PEAR\Zend\Date.php(989): Zend_Date->_calculate('set', '13:00:00', 'WW', NULL) #1 C:\xampp\htdocs\index.php(12): Zend_Date->set('13:00:00', 'WW') #2 {main} thrown in C:\xampp\php\PEAR\Zend\Date.php on line 2136
あれ?
C:\xampp\php\PEAR\Zend\Locale/Data/を見てみると、本来入っているべきja.xmlやja_JP.xmlなんかが一切存在しませんでした。
なぜだらう?
仕方ないのでこのフォルダだけ手動でコピペした。
zend_date2.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
//Zend_Dateを使用するための初期設定
date_default_timezone_set('Asia/Tokyo');
//Zend_Date
require_once('Zend/Date.php');
$date = new Zend_Date();
//適当に使ってみる
print($date->get());
$date->set('11092210232008','mmMMHHddssyyyy');
print($date->get('yyyy年MM月dd日(E曜日) HH時mm分ss秒'));
$date->add('22:00:00',Zend_Date::TIMES);
print($date->get(Zend_Date::RFC_2822));
|
何が便利って入力値のフォーマットを指定できる!!
DBから取得した日時をstrtotime()に突っ込んだつもりが何故かVARCHAR型に変なフォーマットで入ってて理解できねーと言われた、とかいうような腐った設計でもこれで安心。
例にある'11092210232008'のような意味不明な文字列ですら、'2008年09月10日(水曜日) 22時11分23秒'と引数通りの解釈を行ってくれます。
また日付の足し引きや比較といった計算もadd()やsub()、isLater()等で自由に行うことができます。
http://framework.zend.com/manual/ja/zend.date.overview.html#id.date.basic.operations
計算の場合も第二引数で入力値の形式を指定することができるので、日時形式をいちいち分解してmktime()に突っ込んだり、使い方が微妙に不自由なDateTime::addを使用したりせずに済みます。
日時形式を設定、取得するために多数の定数が用意されており、決まった形式なら定数を使えます。
http://framework.zend.com/manual/ja/zend.date.constants.html#zend.date.constants.list
まあ、Zend_Date::DAYって書くより'dd'って書く方が早いような気もしないでもないですが。
いやあ、しかしZend_Date便利だね。
これが普及してくれれば現行の日付関数全部要らなくなるんだが。
注意点としては、西暦-99年~-01年の値を'yyyy'で取得しようとすると00-1とかいう形になってしまいます。
Zend_Date::YEARだときちんと-1になるんですがね。
古めの記事だと999年以前やZend_Date::YEARでもおかしかったみたいだけど、そこらへんは直ったみたい。
前カスタム修正子を作成しましたが、同じフォルダにfunction.html_select_date.phpといったファイルがあるのに気付いた人もいるかもしれません。
言うまでもなく{html_select_date}です。
というわけでカスタム関数も簡単に作成することができます。
今回は試しに{now}を作ってみます。
Smartyは{$smarty.now}でタイムスタンプを返してくれるのですが、マニュアルにあるとおり実行した時点でのタイムスタンプが返ってきます。
{$smarty.now}{1|sleep}{$smarty.now}
とすると1ずれた時間になってしまいます。
一度参照すれば以降は同じタイムスタンプが返ってきた方が便利でしょう。
プラグインフォルダにfunction.now.phpを作成してsmarty_function_nowという名前の関数を作成すれば、Smartyから{now}で呼び出すことができます。
smarty/libs/plugins/function.now.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
function smarty_function_now($params, &$smarty){
//初期値に関数とかは使えない
static $timestamp=false;
//まだ定義されてない時だけ定義
if(!$timestamp){
$timestamp=time();
}
//返却
if($params['format']){
return strftime($params['format'],$timestamp);
}else{
return $timestamp;
}
}
|
{now}{1|sleep}{now}
無事に同じタイムスタンプが取得できました。めでたし。
ついでに引数を指定することでフォーマットも指定できるようになっています。
{now format='%Y-%m-%d %H:%M:%S'}
というふうに使えます。
複数箇所で同じ時刻を参照したい場合に便利かもしれません。
Smartyには、変数を格納して表示する以外に、テンプレートを作成する上で便利な機能がいくつも存在します。
試しに{html_select_date}と書いてみると、いきなり生年月日選択フォームができあがります。
後は適当にオプションを突っ込めば面倒な日付選択フォームがあっさり完成します。
html_select_date.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
//Smarty
require_once('./../smarty/libs/Smarty.php');
//取得した日時
$request_datetime=mktime(
$_REQUEST['Time_Hour']
,$_REQUEST['Time_Minute']
,$_REQUEST['Time_Second']
,$_REQUEST['Date_Month']
,$_REQUEST['Date_Day']
,$_REQUEST['Date_Year']
);
$smarty->assign('request_datetime',$request_datetime);
//表示
$smarty->display('html_select_date.html');
|
html_select_date.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<html><body>
<form method="POST" action="html_select_date.php">
{html_select_date field_order='Y'
start_year='-10' end_year='+10' time=$request_date}年
{html_select_date field_order='M'
month_format='%m' time=$request_date}月
{html_select_date field_order='D'
time=$request_date}日
{html_select_time display_hours=true
display_minutes=false display_seconds=false time=$request_date}時
{html_select_time display_hours=false
display_minutes=true display_seconds=false time=$request_date}分
{html_select_time display_hours=false
display_minutes=false display_seconds=true time=$request_date}秒
<input type="submit" value="送信">
</form>
</body></html>
|
実行するとこのようなフォームが現れます。
年 月 日 時 分 秒
問題点としては、フィールドの区切りに任意の値を設定できないので、YYYY年MM月DD日みたいなフォーマットを作るには、上記のように<select>単位で区切らなければなりません。
しかし、うんざりするほど長大な<select><option>を書くことや(ここのソースを見てみましょう)、{foreach}なんかでややこしいループを書くことに比べれば、圧倒的に楽です。
しかし{html_select_date}と{html_select_time}のオプションが何故か違うとか、month_formatとday_formatはあるのにyaer_formatは無いとか、なんか微妙に気持ち悪い仕様なのはどうにかならないんでしょうか。