読者です 読者をやめる 読者になる 読者になる

年齢0x1Aは有効な値か?

PHP

会員登録などのフォームで、「年齢」等、整数を要求するテキストフィールドあるとします。ここに"0x1A"と入力した場合、検証エラーとして処理を止めるべきでしょうか。それとも自動的に10進数に変換して処理を続行するべきでしょうか。
いくつかのフレームワークで動作を確認してみます。

  • Ethnaの場合、VAR_TYPE_INTと定義しておけば、この値は検証を通りません。
  • Mapleの場合、この値は有効な数値として評価されます。Minvalue, Maxvalue検証を行っている場合は、26として評価されます。Actionにインジェクトされる値は文字列"0x1A"です。
  • Pieceの場合、Range検証では、26として評価されます。Piece_Right_Resultsが保持する検証済みの値は文字列"0x1A"です。


個人的意見としては、

  • 検証エラーにし、フレームワーク利用者にこの値を利用すべきでないことを通知する。
  • 検証を通し、フレームワーク利用者には、型変換を強制した整数型26を渡す。


のどちらかが、正しい振る舞いだと考えます。どちらを選択するかは、フレームワーク作成者のセンスの問題です。
Ethnaは前者の条件に合致しますが、MapleとPieceはどちらの条件にも合致しません。


なぜ型変換を強制していない数値文字列がよくないかというと、実装に依存して動作が変わり、結果としてビジネスルールに反するデータが生成されてしまう可能性があるからです。
PHPの型変換の結果には、ざっと考えてこれだけあります。$valueは"0x1A"とします。

intval($value) int(0)
(int)$value int(0)
settype($value, 'int') int(0)
$value + 0 int(26)
$value + 0.0 float(26)
$value . '' string(4) "0x1A"


PHPの暗黙の型変換は大抵の場合うまくいきますが、使用しているライブラリ・フレームワーク、あるいはアプリケーションのドメインロジックの実装コードによっては、問題が生じます。
一例として、データベース・アクセスにおいて、使用しているデーターベース製品によっては問題が生じる可能性があります。


例えば、Mapleで次のようなActionを記述した場合、年齢"0x1A"を許してしまうと、データベースのエラーが発生するか、最悪の場合、制約に反したデータが挿入できてしまいます。

<?php
class Some_Maple_Action
{
  var $name;
  var $age;
  var $mail;

  /**
   * DIコンテナによって生成されるドメインロジック・クラス。
   * データベースに顧客を登録する。
   */
  var $logic;

  function execute()
  {
    $this->logic->registerCustomer($this->name, $this->age, $this->mail);
  }
}
?>

Oracleの場合、エラーで挿入は実行できませんでしたが、MySQLでは年齢0として登録できてしまいます。例えば「顧客の年齢は18歳以上」などの制約がある場合には、これは後々問題となるでしょう。(もちろん、良心的な、と言うより、まっとうなDBAがいる開発現場では、CHECK制約やTriggerを使って、不注意な開発者からデータベースを保護しているでしょう。)


このエントリでは、データベース・アクセスのケースを想定しましたが、XML-RPCに数値文字列を渡した場合どうなるのか、PEAR::Services_*に登録されているWebサービス・ライブラリの場合どうなるか、など考え始めるときりがありません。
前述のMapleとPieceの数値文字列に対する振る舞いに関しては、バグとしてフレームワーク側が対処するべきでしょうが、この問題に対して何らかの手段で対処されるまで、フレームワーク利用者側で型変換を強制するようなコードを記述する必要があるでしょう。


【追記】
やっぱりこれは、バグではなくて、Actionクラスのなかで明示的に変換する、MapleやPieceの提供するFilter機能を使う等の手段で、フレームワーク利用者側が対処するべきことのような気がしてきました。