試験問題 回答コード

PHP
末尾 5 行のパラメータを書き換えれば動きます。HTML_QuickForm, HTML_Template_Flexy 必須。
掲載用に行数を詰めているので可読性は低下気味。要求項目はそのまま解決箇所のコメントに写しているので、コードを読もうという酔狂な人は手がかりにどうぞ。output メソッドが処理概要の中心です。
ん〜、あまりよいコードではないかも。

_setupForm();
	}
	
	function _setupForm() {
		$qf = new HTML_QuickForm();
		// 入力ページでは郵便番号(7桁)の入力欄と送信ボタンを表示 
		// 確認ページで戻るボタンが押された場合は「郵便番号欄の値を保持したまま」入力ページを再表示 
		$qf->addElement('text', 'zipcode', '郵便番号(7桁):', array('size'=>10));
		// 入力ページで送信ボタンを押した際、郵便番号欄の値を半角に変換してハイフンを除去 
		$qf->applyFilter('zipcode', 'formFilterZipcode');
		// 郵便番号欄の値が「空文字列」または「7文字の半角数字以外」の場合は「郵便番号欄の値を保持」したまま入力ページを再表示 
		// 入力ページを再表示する再、郵便番号欄の下に入力値に応じて「入力されていません」または「入力内容が正しくありません」と表示 
		$qf->addRule('zipcode', '入力されていません', 'required', null, 'client'); 
		$qf->addRule('zipcode', '入力内容が正しくありません', 'numeric', null, 'client');
		$this->qf = $qf;
	}
	
	/** フォーム遷移: 初回アクセス */
	function _setFormStatusDefault() {
		$this->qf->addElement('submit', 'confirm', '確認');
	}
	
	/** フォーム遷移: 内容確認 */
	function _setFormStatusConfirm() {
		$qf =& $this->qf;
		// 確認ページでは郵便番号、戻るボタン、次へボタンを表示 
		$qf->freeze();
		$qf->addElement('submit', 'submit', '次へ');
		$qf->addElement('submit', 'edit', '戻る'); 
	}
	
	/** フォーム遷移: 修正 */
	function _setFormStatusEdit() {
		return $this->_setFormStatusDefault();
	}
	
	/** ページ遷移: 送信受け付け */
	function _setPageStatusSubmitted() {
		// 確認ページで次へボタンが押された場合は結果表示ページに「入力された郵便番号はxxx-xxxxです」と表示 
		$zipcode = $this->qf->exportValue('zipcode');
		$result_msg = sprintf('入力された郵便番号は%d-%dです', substr($zipcode, 0, 3), substr($zipcode, 3, 4));
		$this->result_msg = $result_msg;
	}
	
	/** QF をテンプレート出力用にフリーズする */
	function _buildForm(&$page) {
		$renderer =& new HTML_QuickForm_Renderer_ObjectFlexy(&$page); 
		$this->qf->accept($renderer); 
		$this->form = $renderer->toObject(); 
	}
	
	/** 画面出力 */
	function output() {
		$qf =& $this->qf;		
		// 入力ページ、確認ページ、結果表示ページから成る
		if ( (!$qf->validate()) || !empty($_REQUEST['edit']) ) {
			// 入力ページ or [戻る] 押し下げ or バリデート失敗
			$this->_setFormStatusDefault();
		}
		elseif(empty($_REQUEST['submit'])) {
			// 確認ページ
			$this->_setFormStatusConfirm();
		}
		else {
			// 結果表示ページ
			$this->_setPageStatusSubmitted();
		}
		
		// 出力処理
		$master = new HTML_Template_Flexy(
			array('templateDir' => $this->templateDir, 'compileDir' => $this->compileDir)
		);
		$this->_buildForm($master);
		$master->compile($this->masterTemplate);
		$master->outputObject($this); 
	}
	
}

/** フォームエレメント zipcode 用フィルタ */	
function formFilterZipcode($var) 
{
	// 全角->半角に置換
	// $var = mb_convert_kana($var, 'a')
	// ハイフンを除去
	return str_replace('-', '', $var);
}

$page = new zipEntry();
$page->compileDir = dirname(__FILE__) .'/tmp';
$page->templateDir = dirname(__FILE__) .'/tmp';
// ページデザインは後で差し替えるのでスクリプトとは別ファイルにしておく 
$page->masterTemplate = 'zip.tpl.html';
$page->output();
?>

HTML テンプレート
一部省略。

<head>
{form.javascript:h}
</head>
<body>
	{if:result_msg}
		{result_msg}
	{else:}
		{form.outputHeader():h}
		{form.hidden:h}
		<div> 
			{form.zipcode.label} {form.zipcode.html:h} 
			<div flexy:if="form.errors.zipcode" style="color:red;">{form.errors.zipcode}</div>
		</div>
		<div> {form.submit.label} {form.submit.html:h} </div>
		<div> {form.confirm.label} {form.confirm.html:h} </div>
		<div> {form.edit.label} {form.edit.html:h} </div>
		</form>
	{end:}
</body>