[index] [bottom] [prev] [next]

水際で取り押さえろ

入力チェックに関する考察

アプリケーションでユーザが入力するデータを、どこでチェックするかという問題は、GUIを使う以上、必ずつきまといます。

よく、コンポーネントからのフォーカス移動時に、チェックを行うというものがありますが、チェックでエラーだった場合に、元のコンポーネントにフォーカスを戻したり、フォーカスの異動先がボタンで、何か処理が実行されてしまったら、これをキャンセルする方法など、考えなければならない事が多すぎて、あまりお勧めできません(経験談です(笑))。

幸い、HTMLの入力コンポーネントには、入力をチェックすることのできるイベントハンドラが用意されています。これを使って、不正入国(入力!)を水際で防いでみましょう。

まずは、JavaScriptでイベントを使う上での、おまじないを紹介します。MozillaとIEのイベントに関する実装の違いを、吸収するためのものです。いろいろなところで、良く紹介されている例なので、ご存じの方も多いかもしれません。

イベントのおまじない
/*
 * イベントハンドラ
 */
function textInput(evnt) {
  evnt = (evnt) ? evnt : ((window.event) ? event : null);
  if (evnt) {
    ・
    ・
  }
  else {
    // エラー処理
  }
}

mozillaの場合は、textInputの引数としてevntが渡されますが、IEの場合はなにも渡されません。その代わりにwindowオブジェクトのeventプロパティに、イベントの内容がセットされます。3項演算子の連続で、わかりにくい部分もあるかと思いますが(3項演算子は、コーディング基準上禁止のプロジェクトもある!)おまじないなどはこんなものと言うことで。

実際には、渡されるイベントそのものも、mozillaとIEでは全くと言っていいほど違うため、独自のイベントオブジェクトを作成し、これを返すようにしないと、至る所にWebブラウザの判定処理が入り、すっきりとしません。

以下が、これから使う最低限の機能を実装した、独自イベントオブジェクトです。

独自イベントオブジェクト
/*
 * 独自のイベントオブジェクト コンストラクタ
 * 原則として、DOM Level3のTextEventと、同じインターフェイスを踏襲する。
 * 最低限の実装なので、どの環境でも使用できるわけではない。
 */
function MyEvent(evnt) {
  if (evnt) {
    this.data = evnt.charCode;
    this.target = evnt.target;
  }
  else if (window.event) {
    evnt = event;
    this.data = evnt.keyCode;
    this.target = evnt.srcElement;
  }
  else {
    // throw new MyException();
  }
  this.evnt = evnt;
}

/*
 * イベントファクトリ
 */
MyEvent.createEvent = function (evnt) {
  if (evnt && evnt.data) {
    // W3CのDOMイベントの場合は、そのまま返す。
    // 但し、現時点(2004/10)では、あり得ない。
    return evnt;
  }
  return new MyEvent(evnt);
}

/*
 * 最低限必要なメソッドを実装
 */
MyEvent.prototype.preventDefault = function () {
  if (this.evnt.preventDefault) {
    this.evnt.preventDefault();
  }
  else {
    this.evnt.cancelBubble = true;
  }
}
MyEvent.prototype.stopPropagation = function () {
  if (this.evnt.stopPropagation) {
    this.evnt.stopPropagation();
  }
  else {
    this.evnt.returnValue = false;
  }
}

上記イベントを使用したイベントハンドラによる、入力チェック(入力制限)の簡単な例です。数字の入力(16進で、0x30〜0x39の間)だけを受け付けます。0x20より小さい値を受け付けているのは、制御文字を許可するためです。制御文字を許可しないと、BackSpace等で入力値を削除できなくなってしまいます。

入力制限の例
/*
 * テキストフィールドへの、入力制限
 */
function restriction(evnt)
  evnt = new MyEvent(evnt);
  if (evnt) {
    if ((evnt.data >= 0x20 && evnt.data < 0x30) || evnt.data > 0x39) {
      evnt.preventDefault();
      evnt.stopPropagation();
      return;
    }
  }
  else {
    // throw new MyException();
  }
}

上記メソッドの使用例です。至って簡単ですね。

使用例
document.getElementById('textInput').onkeypress = restriction;

入力された文字のコードは、onkeypressイベントで取得できますが、Webブラウザやプラットフォームによって、取得できるコードが異なるので、実際に使用する場合は、サポートが必要なプラットフォームやWebブラウザ上での、詳細なテストが必要です。

多様性のサポート

当然、アプリケーションで入力制限を行いたいデータの種類は、数字だけではありません。

マイナスが入力できる必要があるかもしれませんし、小数点以下の入力もあり得ます。半角英字だけかもしれません。えとせとらえとせとら!

別ファイルに設定を行うと、スクリプトのチェックルーチンを、自動的に生成してくれるツールなども見かけます。しかし、Webアプリケーションが、画面の生成にHTMLを使っていることを考えれば(DOMを使うには、xhtmlの方が、問題が少ないことを考えれば)、情報はできるだけ画面のHTML(xhtml)ファイルの中に埋め込んでしまった方が、何かと都合がいいはずです。

入力制限の、情報HTMLファイル埋めバージョン

情報HTMLファイル埋めバージョン
/*
 * テキストフィールドへの、入力制限
 */
function restriction(evnt) {
  evnt = MyEvent.createEvent(evnt);
  var isRestriction = false;
  if (evnt) {
    var targetClassValue = evnt.target.className;
    if (evnt.data < 0x20) {
      return;
    }
    if (targetClassValue.search(/restriction_Number/) != -1) {
      if (evnt.data >= 0x30 && evnt.data <= 0x39) {
        return;
      }
      else {
        isRestriction = true;
      }
    }
    if (targetClassValue.search(/restriction_Sign/) != -1) {
      if (evnt.data == 0x2D) {
        return;
      }
      else {
        isRestriction = true;
      }
    }
    if (targetClassValue.search(/restriction_UpperCase/) != -1) {
      if (evnt.data >= 0x41 && evnt.data <= 0x5A) {
        return;
      }
      else {
        isRestriction = true;
      }
    }
  }
  else {
  }
  if (isRestriction) {
    evnt.preventDefault();
    evnt.stopPropagation();
  }
}
HTMLの内容
<p>数値のみ<input class="restriction_Number"/></p>
<p>英大文字のみ<input class="restriction_UpperCase"/></p>
<p>数値とサイン<input class="restriction_Number
                             restriction_Sign"/></p>
HTMLの内容

数値のみ

英大文字のみ

数値とサイン

HTMLでは、class属性はWebブラウザやアプリケーションが、自由に使う属性として定義されているので、これを使って入力制限の内容を、変更します。

操作をしてみると分かると思いますが、これらの入力制限は、単純なキーボード入力に対する制限でしかありません。マウスを使ったコピー&ペーストや、IMを使った入力をガードすることはできません。

また、当然の事ながら、WebブラウザのJavaScriptサポートを解除すれば、入力制限はかかりません。これらの入力制限は、ユーザに対する利便性の向上は提供しますが、システム上必要とされるような、強固な入力制限は提供しません。

Webアプリケーションに於いて、クライアント側の入力チェックは、全く信用するに値しません。サーバ側は、なにが来ても大丈夫という作りをする必要があります。

この点においても、上記のように入力制限の定義を、画面のファイル内に持つことは、意義があります。HTMLファイルは当然サーバにあるので、サーバ側アプリケーションは、このファイルをリソースとして読み込み、項目毎の制限内容を取得することができます。その内容を元にチェック処理を走らせれば、クライアントとサーバのチェック内容が、必ず同じになりますし、いちいち全項目のチェックを、サーバクライアントで確認する必要もなくなります。

当然正しいHTML(xhtml)を使っていれば、属性値も含めたフォームの内容の一覧表示や、属性の内容の設定などが比較的簡単にできるので、ドキュメントの作成も楽になります(ドキュメントイコールソースにもなります)。

[index] [top] [prev] [next]