Javascript+PHP5で禁則処理をする(その2)

Javascriptでの禁則処理をエンハンスしたついでに、以前作成したPHPの方のプログラムにも同等の機能を実装しておく。
実装する機能は、

  • 禁止する文字を■に置換するのは格好悪いので、化けそうも無い文字(列)に置換する。

というもの。禁止する文字と、その代替として用いる文字は、Javascriptの時と同等にして、


を以下に置換する。

1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20
1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,(株),(有),cm,kg,-


以下に、このモジュールをテストした際のスナップショットを載せる。入力のテキストエリアに文字列を入力し、フォーカスを外したら(onBlurイベントが発生したら)、入力された文字列をXHRでサーバーに送り、禁則処理(置換処理)をして、結果を「出力」の箇所に出力する。


まず、コンバートを行うMyConverter.class.phpのソースを以下に示す。このクラスをnewし、convertToRegalChar($_str)とすれば、禁止文字を代替する文字で置換した結果が戻る(引数$_strは、置換をも施したい文字列)。
作った印象としては、PHPJavascriptよりも、この手の処理を記述しにくい。特に、preg_match_all()で禁止文字の出現を調べる際、禁止文字列が2つ以上並んでいた場合にそれらをまとめてピックアップしてしまう、という不都合がある。この対応が面倒だった。以下k、$_illegalCharsRegと$_illegalCharsが化けてしまっているが、ここは、上の禁止文字の羅列がはいる。

<?php
/**
 * MyConverter.class.php
 * 
 * (C) 2009, tetsuya.odaka(EzoGP).
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* 
 * データコンバート用Class
	 * 
 * author;		t.odaka
 * date;		2009/4/23
 * 
 * modified		2009/5/25	t.odaka	化けそうな文字を追加
 * 			2009/5/26	t.odaka	convertToRegalChar()を追加
 * 
*/

class MyConverter {

	/* 
	 * プロパティー
	 *  適当に書き換えてください。
	*/
	var $_illegalCharsReg = '/[&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;鄯鄱鄴鄽酈酛醃醞醬醱&#65533;&#65533;&#65533;&#65533;〜]+/u';
    var $_replaceChars = '??';
	
    var $_illegalChars ='&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;鄯鄱鄴鄽酈酛醃醞醬醱&#65533;&#65533;&#65533;&#65533;〜';
    
    var $_legalChars = array(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,
		   		1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,
    			'(株)','(有)','cm','kg','-');
	
        /* 
	 * デフォルトのコンストラクタ 
	 */
	function __construct() {
	}

        /* 
	 * 禁則文字の置換メソッド(UTF-8のみ)
	 *   パラメータ
	 * 	 $_str		:   禁則文字があるかもしれない文字列
	 *   戻り値		:   置換後の文字列
	 */
	function convertIllegal($_str){
		
		// debug用
		require("../Myznala/debugLog.php");
		// 置換
		mb_regex_encoding('UTF-8');
		$_ret = preg_replace($this->_illegalCharsReg, 
						$this->_replaceChars, $_str);
						
		return $_ret;
	}

         /* 
	 * 禁則文字の置換メソッド(UTF-8のみ)
	 *   パラメータ
	 * 	 $_str		:   禁則文字があるかもしれない文字列
	 *   戻り値		:   置換後の文字列
	 */
	function convertToRegalChar($_str){
	
		// debug用
		require("../Myznala/debugLog.php");
		
		// 置換
		mb_regex_encoding('UTF-8');
		$_ret = preg_match_all($this->_illegalCharsReg, 
						$_str, $_matches);
		
		if($_ret>0){
			$m_log->debug($_matches[0]);
		
			$_lArr = array(); //長さ2以上の禁止文字列を入れる。

			// 禁止文字が並んでないとき処理。
			foreach($_matches[0] as $key => $val){
				if(mb_strlen($val,'UTF-8') == 1){
				// 1文字だけとれた場合
					$_idx = mb_strpos($this->_illegalChars, $val, 0, 'UTF-8');
					$_reg = '/['.$val.']+/u';
					$_str = preg_replace($_reg, 
								$this->_legalChars[$_idx], $_str);
				}else{
				// 2文字以上とれた場合
					array_push($_lArr, $val);
				}
			}
		}

		// 2文字以上禁止文字が並んでいたときの処理。
		if(count($_lArr)>0){
			// 1文字ずつに分割して、$_sArrに入れる。
			$_sArr = array();
			foreach($_lArr as $key => $val){
				$val = mb_convert_encoding($val,'UTF-8','auto');
				$_len = mb_strlen($val,'UTF-8');
				for($i=0; $i < $_len; $i++){
					$_wk = mb_substr($val, $i, 1,'UTF-8');
					array_push($_sArr, $_wk);
				}
			}
			
			// $_sArrから禁止文字を一文字ずつ取り出し、置換する。
			foreach($_sArr as $key => $val){
					$_idx = mb_strpos($this->_illegalChars, $val, 0, 'UTF-8');
					$_reg = '/['.$val.']+/u';
					$_str = preg_replace($_reg, 
								$this->_legalChars[$_idx], $_str);
			}
		}
		
		$_ret = $_str;
						
		return $_ret;
	}	
	
}
?>


以下は、上記のサンプルのためのプログラム。最初は、クライアント側の処理。YUI2.7.0を用いている。

<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<META http-equiv="Content-Style-Type" content="text/css">
<TITLE>MyConverter</TITLE>

<style type="text/css">

input.ez_initguide {
	/* grey */
    color:#808080;
}

</style>
<!-- 読み込むjs --> 
<script type="text/javascript" src="../scripts/lib/yui/build/yahoo/yahoo-min.js">
</script>
<script type="text/javascript" src="../scripts/lib/yui/build/yahoo-dom-event/yahoo-dom-event.js">
</script>
<script type="text/javascript" src="../scripts/lib/yui/build/connection/connection-min.js" >
</script>

<script type="text/javascript">
/*
 * コンバート検証
 *  (モジュールパターンで実装)
 */
convert = function() {
	var	Dom 	= YAHOO.util.Dom;	
	var	Event 	= YAHOO.util.Event;

	/**
	* Inputからフォーカスが外れたときのハンドラー
	*/
	var onBlurHdlr = function(_evt,_obj){
		
		_e = YAHOO.util.Event.getTarget(_evt)
		var _id = _e.id;
		var _resId = _id + '_res';
		
		// 検証対象を取得.
		var _str  = Dom.get(_id).value;

		var _url = "test_convert2.php"
		
		var _parm = 'val='+_str;
		var _arg ={
				'id': _id,
				'resId': _resId
			};
		// 戻ってきたときのために、エレメントのidをセットする。
		ajaxCallback.argument = _arg;

		//alert('call ajax val: '+_str);
		
		// ajaxでコンバート
		YAHOO.util.Connect.asyncRequest('POST',_url,
					ajaxCallback, _parm);
	};
		
	/*
	 * Ajaxハンドラー
	 *  
	 */
	var ajaxHandlers = {
		
		// 受信成功時の処理
		responseSuccess: function(_oj){
			var _id 	= _oj.argument.id;
			var _resId 	= _oj.argument.resId;
			alert(_resId);
			// データの取得
			var _ret 	= _oj.responseText;
			alert(_ret);
			Dom.get(_resId).innerHTML = _ret;
		},

		// 受信失敗時の処理
		responseFailure: function(_oj){
			var _id 	= _oj.argument.id;
			var _resId 	= _oj.argument.resId;

			var _ret = 'ステータス: ' + _oj.status + 'ステータステキスト: ' +
							_oj.statusText + '読み込みに失敗しました。';
			// エラーのハンドル(皆さん適当に)
			// 入力フィールドの色をピンクにする。
			Dom.setStyle(_id, 'background-color', 'pink');
			Dom.get(_resId).innerHTML = _ret;
		}
	};

	/*
	 * コールバック成功/失敗時の振り分け
	 *  
	 */
	var ajaxCallback =
	{
		success: ajaxHandlers.responseSuccess,
		failure: ajaxHandlers.responseFailure,
		cache: false,
		scope: ajaxHandlers,
		argument: null
	};
	
	return {
		/**
		* 初期処理
		*/
    	        init: function() {
			Event.addBlurListener('area1', onBlurHdlr, Dom.get('area1'));		    
		} // initの終わり
	};
}();

</script> 

</HEAD>
<BODY onload="convert.init()">
test_convert_svr2.html
<h3>
サーバーサイドでのコンバート確認用
</h3>

<form method="post" action='#'>
<!--// 入力検証項目 -->

入力;<br>
<textarea id="area1" cols=50 rows=8></textarea><br>
<br>
出力;<br>
<div id="area1_res"></div>


</form>

<br>
</body>
</HTML>


以下、これと、MyConverter.class.phpをつなぐPHPプログラム。

<?php
/* MyConverter.class.phpを使ったサンプル
	      
		author	; t.odaka

*/

include("../Myznala/MyConverter.class.php");
require("../Myznala/debugLog.php");

/*
$m_log->debug(var_dump($_POST)); // Debugログ
*/

switch($_SERVER['REQUEST_METHOD']) {
	case 'GET'	: $rMethod = &$_GET; break;
	case 'POST'	: $rMethod = &$_POST; break;
	default:
}

// MyConverterをインスタンス化する。
$cnvObj = new MyConverter();

$val = $rMethod['val'];
$val = mb_convert_encoding($val, "UTF-8", "auto");

// 禁則文字の処理
$ret = $cnvObj->convertToRegalChar($val);

// 結果の返却
header("Content-Type:text/html");
echo $ret;

?>