<commit_before><?php
// vim: foldmethod=marker
/**
 *  ActionForm.php
 *
 *  @author     <NAME> <<EMAIL>>
 *  @license    http://www.opensource.org/licenses/bsd-license.php The BSD License
 *  @package    Ethna
 *  @version    $Id$
 */
use Symfony\Component\HttpFoundation\Request;

// {{{ Ethna_ActionForm
/**
 *  アクションフォームクラス
 *
 *  @author     <NAME> <<EMAIL>>
 *  @access     public
 *  @package    Ethna
 */
class Ethna_ActionForm
{
    /**#@+
     *  @access protected
     */

    /** @var    array   フォーム値定義(デフォルト) */
    public $form_template = array();

    /** @var    array   フォーム値定義 */
    public $form = array();

    /** @FIXME @protected    array   フォーム値 */
    public $form_vars = array();

    /** @protected    array   アプリケーション設定値 */
    public $app_vars = array();

    /** @protected    array   アプリケーション設定値(自動エスケープなし) */
    public $app_ne_vars = array();

    /** @protected    object  Ethna_ActionError   アクションエラーオブジェクト */
    public $action_error;

    /** @protected    object  Ethna_ActionError   アクションエラーオブジェクト(省略形) */
    public $ae;

    /** @protected    object  Ethna_I18N  i18nオブジェクト */
    public $i18n;

    /** @protected    object  Ethna_Logger    ログオブジェクト */
    public $logger;

    /** @protected    object  Ethna_Plugin    プラグインオブジェクト */
    public $plugin;

    /** @protected    array   フォーム定義要素 */
    public $def = array('name', 'required', 'max', 'min', 'regexp',
                     'custom', 'filter', 'form_type', 'type');

    /** @protected    array   フォーム定義のうち非プラグイン要素とみなすprefix */
    public $def_noplugin = array('type', 'form', 'name', 'plugin', 'filter',
                              'option', 'default');

    /** @protected    bool    追加検証強制フラグ */
    public $force_validate_plus = false;

    /** @protected    array   アプリケーションオブジェクト(helper)で利用しないフォーム名 */
    public $helper_skip_form = array();

    /** @protected    int   フォーム配列で使用可能な深さの上限 */
    public $max_form_deps = 10;

    /**#@-*/
    protected $controller;

    /**
     *  Ethna_ActionFormクラスのコンストラクタ
     *
     *  @access public
     *  @param  object  Ethna_Kernel    $controller    controllerオブジェクト
     */
    public function __construct($controller)
    {
        $this->controller = $controller;
        $this->action_error = $controller->getActionError();
        $this->ae = $this->action_error;
        $this->i18n = $controller->getI18N();
        $this->logger = $controller->getLogger();
        $this->plugin = $controller->getPlugin();

        if (isset($_SERVER['REQUEST_METHOD']) == false) {
            return;
        }

        // フォーム値テンプレートの更新
        $this->form_template = $this->_setFormTemplate($this->form_template);

        // フォーム値定義の設定
        $this->_setFormDef();

        // 省略値補正
        foreach ($this->form as $name => $value) {
            foreach ($this->def as $k) {
                if (isset($value[$k]) == false) {
                    $this->form[$name][$k] = null;
                }
            }
        }
    }

    /**
     *  フォーム値のアクセサ(R)
     *
     *  @access public
     *  @param  string  $name   フォーム値の名称
     *  @return mixed   フォーム値
     */
    public function get($name)
    {
        return $this->_get($this->form_vars, $name);
    }

    function _get(&$target, $name)
    {
        if (isset($target[$name])) {
            return $target[$name];
        }
        return null;
    }

    /**
     *  フォーム値定義を取得する
     *
     *  @access public
     *  @param  string  $name   取得するフォーム名(nullなら全ての定義を取得)
     *  @return array   フォーム値定義
     */
    public function getDef($name = null)
    {
        if (is_null($name)) {
            return $this->form;
        }

        if (array_key_exists($name, $this->form) == false) {
            return null;
        } else {
            return $this->form[$name];
        }
    }

    /**
     *  フォーム項目表示名を取得する
     *
     *  @access public
     *  @param  string  $name   フォーム値の名称
     *  @return mixed   フォーム値の表示名
     */
    public function getName($name)
    {
        if (isset($this->form[$name]) == false) {
            return null;
        }
        if (isset($this->form[$name]['name'])
            && $this->form[$name]['name'] != null) {
            return $this->form[$name]['name'];
        }

        // try message catalog
        return $this->i18n->get($name);
    }
    
    /**
     *  ユーザから送信されたフォーム値をフォーム値定義に従ってインポートする
     *
     */
    public function setFormVars(Request $reqeust)
    {
        $http_vars = (new Ethna_RequestWrapper($reqeust))->getHttpVars();
        $_files = $reqeust->files->all();
        foreach ($this->form as $name => $def) {
            $type = is_array($def['type']) ? $def['type'][0] : $def['type'];
            if ($type == VAR_TYPE_FILE) {
                // ファイルの場合

                // 値の有無の検査
                if (isset($_files[$name]) == false || is_null($_files[$name])) {
                    $this->form_vars[$name] = null;
                    continue;
                }

                // 配列構造の検査
                if (is_array($def['type'])) {
                    if (is_array($_files[$name]['tmp_name']) == false) {
                        $this->handleError($name, E_FORM_WRONGTYPE_ARRAY);
                        $this->form_vars[$name] = null;
                        continue;
                    }
                } else {
                    if (is_array($_files[$name]['tmp_name'])) {
                        $this->handleError($name, E_FORM_WRONGTYPE_SCALAR);
                        $this->form_vars[$name] = null;
                        continue;
                    }
                }

                $files = null;
                if (is_array($def['type'])) {
                    $files = array();
                    // ファイルデータを再構成
                    foreach (array_keys($_files[$name]['name']) as $key) {
                        $files[$key] = array();
                        $files[$key]['name'] = $_files[$name]['name'][$key];
                        $files[$key]['type'] = $_files[$name]['type'][$key];
                        $files[$key]['size'] = $_files[$name]['size'][$key];
                        $files[$key]['tmp_name'] = $_files[$name]['tmp_name'][$key];
                        if (isset($_files[$name]['error']) == false) {
                            // PHP 4.2.0 以前
                            $files[$key]['error'] = 0;
                        } else {
                            $files[$key]['error'] = $_files[$name]['error'][$key];
                        }
                    }
                } else {
                    $files = $_files[$name];
                    if (isset($files['error']) == false) {
                        $files['error'] = 0;
                    }
                }

                // 値のインポート
                $this->form_vars[$name] = $files;

            } else {
                // ファイル以外の場合

                // 値の有無の検査
                if (isset($http_vars[$name]) == false
                    || is_null($http_vars[$name])) {
                    $this->form_vars[$name] = null;
                    if (isset($http_vars["{$name}_x"])
                        && isset($http_vars["{$name}_y"])) {
                        // 以前の仕様に合わせる
                        $this->form_vars[$name] = $http_vars["{$name}_x"];
                    }
                    continue;
                }

                // 配列構造の検査
                if (is_array($def['type'])) {
                    if (is_array($http_vars[$name]) == false) {
                        // 厳密には、この配列の各要素はスカラーであるべき
                        $this->handleError($name, E_FORM_WRONGTYPE_ARRAY);
                        $this->form_vars[$name] = null;
                        continue;
                    }
                } else {
                    if (is_array($http_vars[$name])) {
                        $this->handleError($name, E_FORM_WRONGTYPE_SCALAR);
                        $this->form_vars[$name] = null;
                        continue;
                    }
                }

                // 値のインポート
                $this->form_vars[$name] = $http_vars[$name];
            }
        }
    }

    /**
     *  ユーザから送信されたフォーム値をクリアする
     *
     *  @access public
     */
    public function clearFormVars()
    {
        $this->form_vars = array();
    }

    /**
     *  フォーム値へのアクセサ(W)
     *
     *  @access public
     *  @param  string  $name   フォーム値の名称
     *  @param  string  $value  設定する値
     */
    public function set($name, $value)
    {
        $this->form_vars[$name] = $value;
    }

    /**
     *  フォーム値定義を設定する
     *
     *  @access public
     *  @param  string  $name   設定するフォーム名(nullなら全ての定義を設定)
     *  @param  array   $value  設定するフォーム値定義
     *  @return array   フォーム値定義
     */
    public function setDef($name, $value)
    {
        if (is_null($name)) {
            $this->form = $value;
        }

        $this->form[$name] = $value;
    }

    /**
     *  フォーム値を配列にして返す
     *
     *  @access public
     *  @param  bool    $escape HTMLエスケープフラグ(true:エスケープする)
     *  @return array   フォーム値を格納した配列
     */
    public function getArray($escape = true)
    {
        $retval = array();

        $this->_getArray($this->form_vars, $retval, $escape);

        return $retval;
    }

    /**
     *  アプリケーション設定値のアクセサ(R)
     *
     *  @access public
     *  @param  string  $name   キー
     *  @return mixed   アプリケーション設定値
     */
    public function getApp($name)
    {
        if (isset($this->app_vars[$name]) == false) {
            return null;
        }
        return $this->app_vars[$name];
    }

    /**
     *  アプリケーション設定値のアクセサ(W)
     *
     *  @access public
     *  @param  string  $name   キー
     *  @param  mixed   $value  値
     */
    public function setApp($name, $value)
    {
        $this->app_vars[$name] = $value;
    }

    /**
     *  アプリケーション設定値を配列にして返す
     *
     *  @access public
     *  @param  boolean $escape HTMLエスケープフラグ(true:エスケープする)
     *  @return array   フォーム値を格納した配列
     */
    public function getAppArray($escape = true)
    {
        $retval = array();

        $this->_getArray($this->app_vars, $retval, $escape);

        return $retval;
    }

    /**
     *  アプリケーション設定値(自動エスケープなし)のアクセサ(R)
     *
     *  @access public
     *  @param  string  $name   キー
     *  @return mixed   アプリケーション設定値
     */
    public function getAppNE($name)
    {
        if (isset($this->app_ne_vars[$name]) == false) {
            return null;
        }
        return $this->app_ne_vars[$name];
    }

    /**
     *  アプリケーション設定値(自動エスケープなし)のアクセサ(W)
     *
     *  @access public
     *  @param  string  $name   キー
     *  @param  mixed   $value  値
     */
    public function setAppNE($name, $value)
    {
        $this->app_ne_vars[$name] = $value;
    }

    /**
     *  アプリケーション設定値(自動エスケープなし)を配列にして返す
     *
     *  @access public
     *  @param  boolean $escape HTMLエスケープフラグ(true:エスケープする)
     *  @return array   フォーム値を格納した配列
     */
    public function getAppNEArray($escape = false)
    {
        $retval = array();

        $this->_getArray($this->app_ne_vars, $retval, $escape);

        return $retval;
    }

    /**
     *  フォームを配列にして返す(内部処理)
     *
     *  @access private
     *  @param  array   &$vars      フォーム(等)の配列
     *  @param  array   &$retval    配列への変換結果
     *  @param  bool    $escape     HTMLエスケープフラグ(true:エスケープする)
     */
    public function _getArray(&$vars, &$retval, $escape)
    {
        foreach (array_keys($vars) as $name) {
            if (is_array($vars[$name])) {
                $retval[$name] = array();
                $this->_getArray($vars[$name], $retval[$name], $escape);
            } else if (is_null($vars[$name])) {
                $retval[$name] = null;
            } else {
                $retval[$name] = $escape
                    ? htmlspecialchars($vars[$name], ENT_QUOTES, mb_internal_encoding()) : $vars[$name];
            }
        }
    }

    /**
     *  追加検証強制フラグを取得する
     *  (通常検証でエラーが発生した場合でも_validatePlus()が呼び出される)
     *  @access public
     *  @return bool    true:追加検証強制 false:追加検証非強制
     */
    public function isForceValidatePlus()
    {
        return $this->force_validate_plus;
    }

    /**
     *  追加検証強制フラグを設定する
     *
     *  @access public
     *  @param  $force_validate_plus    追加検証強制フラグ
     */
    public function setForceValidatePlus($force_validate_plus)
    {
        $this->force_validate_plus = $force_validate_plus;
    }

    /**
     *  フォーム値検証メソッド
     *
     *  @access public
     *  @return int     発生したエラーの数
     */
    public function validate()
    {
        $this->logger->log(LOG_INFO, "validation start.");
        foreach ($this->form as $name => $def) {
            $this->_validateWithPlugin($name);
        }

        if ($this->ae->count() == 0 || $this->isForceValidatePlus()) {
            // 追加検証メソッド
            $this->_validatePlus();
        }

        $errorCount = $this->ae->count();
        if ($errorCount > 0) {
            $this->logger->log(LOG_INFO, "validation failed. error count [%d]", $errorCount);
        } else {
            $this->logger->log(LOG_INFO, "validation success.");
        }

        return $errorCount;
    }

    /**
     *  プラグインを使ったフォーム値検証メソッド
     *
     *  @access private
     *  @param  string  $form_name  フォームの名前
     *  @todo   ae 側に $key を与えられるようにする
     */
    function _validateWithPlugin($form_name)
    {
        $this->logger->log(LOG_DEBUG, "validating form [%s]", $form_name);

        // (pre) filter
        if ($this->form[$form_name]['type'] != VAR_TYPE_FILE) {
            if (is_array($this->form[$form_name]['type']) == false) {
                $this->form_vars[$form_name]
                    = $this->_filter($this->form_vars[$form_name],
                                     $this->form[$form_name]['filter']);
            } else if ($this->form_vars[$form_name] != null) {
                foreach (array_keys($this->form_vars[$form_name]) as $key) {
                    $this->form_vars[$form_name][$key]
                        = $this->_filter($this->form_vars[$form_name][$key],
                                         $this->form[$form_name]['filter']);
                }
            } else {  //  配列で値が空の場合
                $this->form_vars[$form_name]
                    = $this->_filter($this->form_vars[$form_name],
                                     $this->form[$form_name]['filter']);
            }
        }

        $form_vars = $this->get($form_name);
        $plugin = $this->_getPluginDef($form_name);

        // type のチェックを処理の最初に追加
        $plugin = array_merge(array('type' => array()), $plugin);
        if (is_array($this->form[$form_name]['type'])) {
            $plugin['type']['type'] = $this->form[$form_name]['type'][0];
        } else {
            $plugin['type']['type'] = $this->form[$form_name]['type'];
        }
        if (isset($this->form[$form_name]['type_error'])) {
            $plugin['type']['error'] = $this->form[$form_name]['type_error'];
        }

        // スカラーの場合
        if (is_array($this->form[$form_name]['type']) == false) {
            foreach (array_keys($plugin) as $name) {
                // break: 明示されていなければ，エラーが起きたらvalidateを継続しない
                $break = isset($plugin[$name]['break']) == false
                               || $plugin[$name]['break'];

                // プラグイン取得
                unset($v);
                $v = $this->plugin->getPlugin('Validator',
                                               ucfirst(strtolower($name)));
                $this->logger->log(LOG_DEBUG, "validating form [%s] by validator plugin [%s]", $form_name, $name);
                if (Ethna::isError($v)) {
                    $this->logger->log(LOG_NOTICE, "cannot get validator plugin [%s]", $name);
                    continue;
                }

                // バリデーション実行
                unset($r);
                $r = $v->validate($form_name, $form_vars, $plugin[$name]);

                // エラー処理
                if ($r !== true) {
                    if (Ethna::isError($r)) {
                        $this->ae->addObject($form_name, $r);
                    }
                    if ($break) {
                        break;
                    }
                }
            }
            return;
        }

        // 配列の場合

        // break 指示用の key list
        $valid_keys = is_array($form_vars) ? array_keys($form_vars) : array();

        foreach (array_keys($plugin) as $name) {
            // break: 明示されていなければ，エラーが起きたらvalidateを継続しない
            $break = isset($plugin[$name]['break']) == false
                           || $plugin[$name]['break'];

            // プラグイン取得
            unset($v);
            $v = $this->plugin->getPlugin('Validator', ucfirst(strtolower($name)));
            if (Ethna::isError($v)) {
                continue;
            }

            // 配列全体を受け取るプラグインの場合
            if (isset($v->accept_array) && $v->accept_array == true) {
                // バリデーション実行
                unset($r);
                $r = $v->validate($form_name, $form_vars, $plugin[$name]);

                // エラー処理
                if (Ethna::isError($r)) {
                    $this->ae->addObject($form_name, $r);
                    if ($break) {
                        break;
                    }
                }
                continue;
            }

            // 配列の各要素に対して実行
            foreach ($valid_keys as $key) {
                // バリデーション実行
                unset($r);
                $r = $v->validate($form_name, $form_vars[$key], $plugin[$name]);

                // エラー処理
                if (Ethna::isError($r)) {
                    $this->ae->addObject($form_name, $r);
                    if ($break) {
                        unset($valid_keys[$key]);
                    }
                }
            }
        }
    }

    /**
     *  チェックメソッド(基底クラス)
     *
     *  @access public
     *  @param  string  $name   フォーム項目名
     *  @return array   チェック対象のフォーム値(エラーが無い場合はnull)
     */
    public function check($name)
    {
        if (is_null($this->get($name)) || $this->get($name) === "") {
            return null;
        }

        // Ethna_Backendの設定
        $c = Ethna_Kernel::getInstance();
        $this->backend = $c->getBackend();

        return to_array($this->get($name));
    }

    /**
     *  チェックメソッド: 機種依存文字
     *
     *  @access public
     *  @param  string  $name   フォーム項目名
     *  @return object  Ethna_Error エラーオブジェクト(エラーが無い場合はnull)
     */
    public function checkVendorChar($name)
    {
        $null = null;
        $string = $this->get($name);

        for ($i = 0; $i < strlen($string); $i++) {
            /* JIS13区のみチェック */
            $c = ord($string{$i});
            if ($c < 0x80) {
                /* ASCII */<commit_msg>eliminate backend<commit_after><?php
// vim: foldmethod=marker
/**
 *  ActionForm.php
 *
 *  @author     <NAME> <<EMAIL>>
 *  @license    http://www.opensource.org/licenses/bsd-license.php The BSD License
 *  @package    Ethna
 *  @version    $Id$
 */
use Symfony\Component\HttpFoundation\Request;

// {{{ Ethna_ActionForm
/**
 *  アクションフォームクラス
 *
 *  @author     <NAME> <<EMAIL>>
 *  @access     public
 *  @package    Ethna
 */
class Ethna_ActionForm
{
    /**#@+
     *  @access protected
     */

    /** @var    array   フォーム値定義(デフォルト) */
    public $form_template = array();

    /** @var    array   フォーム値定義 */
    public $form = array();

    /** @FIXME @protected    array   フォーム値 */
    public $form_vars = array();

    /** @protected    array   アプリケーション設定値 */
    public $app_vars = array();

    /** @protected    array   アプリケーション設定値(自動エスケープなし) */
    public $app_ne_vars = array();

    /** @protected    object  Ethna_ActionError   アクションエラーオブジェクト */
    public $action_error;

    /** @protected    object  Ethna_ActionError   アクションエラーオブジェクト(省略形) */
    public $ae;

    /** @protected    object  Ethna_I18N  i18nオブジェクト */
    public $i18n;

    /** @protected    object  Ethna_Logger    ログオブジェクト */
    public $logger;

    /** @protected    object  Ethna_Plugin    プラグインオブジェクト */
    public $plugin;

    /** @protected    array   フォーム定義要素 */
    public $def = array('name', 'required', 'max', 'min', 'regexp',
                     'custom', 'filter', 'form_type', 'type');

    /** @protected    array   フォーム定義のうち非プラグイン要素とみなすprefix */
    public $def_noplugin = array('type', 'form', 'name', 'plugin', 'filter',
                              'option', 'default');

    /** @protected    bool    追加検証強制フラグ */
    public $force_validate_plus = false;

    /** @protected    array   アプリケーションオブジェクト(helper)で利用しないフォーム名 */
    public $helper_skip_form = array();

    /** @protected    int   フォーム配列で使用可能な深さの上限 */
    public $max_form_deps = 10;

    /**#@-*/
    protected $controller;

    /**
     *  Ethna_ActionFormクラスのコンストラクタ
     *
     *  @access public
     *  @param  object  Ethna_Kernel    $controller    controllerオブジェクト
     */
    public function __construct($controller)
    {
        $this->controller = $controller;
        $this->action_error = $controller->getActionError();
        $this->ae = $this->action_error;
        $this->i18n = $controller->getI18N();
        $this->logger = $controller->getLogger();
        $this->plugin = $controller->getPlugin();

        if (isset($_SERVER['REQUEST_METHOD']) == false) {
            return;
        }

        // フォーム値テンプレートの更新
        $this->form_template = $this->_setFormTemplate($this->form_template);

        // フォーム値定義の設定
        $this->_setFormDef();

        // 省略値補正
        foreach ($this->form as $name => $value) {
            foreach ($this->def as $k) {
                if (isset($value[$k]) == false) {
                    $this->form[$name][$k] = null;
                }
            }
        }
    }

    /**
     *  フォーム値のアクセサ(R)
     *
     *  @access public
     *  @param  string  $name   フォーム値の名称
     *  @return mixed   フォーム値
     */
    public function get($name)
    {
        return $this->_get($this->form_vars, $name);
    }

    function _get(&$target, $name)
    {
        if (isset($target[$name])) {
            return $target[$name];
        }
        return null;
    }

    /**
     *  フォーム値定義を取得する
     *
     *  @access public
     *  @param  string  $name   取得するフォーム名(nullなら全ての定義を取得)
     *  @return array   フォーム値定義
     */
    public function getDef($name = null)
    {
        if (is_null($name)) {
            return $this->form;
        }

        if (array_key_exists($name, $this->form) == false) {
            return null;
        } else {
            return $this->form[$name];
        }
    }

    /**
     *  フォーム項目表示名を取得する
     *
     *  @access public
     *  @param  string  $name   フォーム値の名称
     *  @return mixed   フォーム値の表示名
     */
    public function getName($name)
    {
        if (isset($this->form[$name]) == false) {
            return null;
        }
        if (isset($this->form[$name]['name'])
            && $this->form[$name]['name'] != null) {
            return $this->form[$name]['name'];
        }

        // try message catalog
        return $this->i18n->get($name);
    }
    
    /**
     *  ユーザから送信されたフォーム値をフォーム値定義に従ってインポートする
     *
     */
    public function setFormVars(Request $reqeust)
    {
        $http_vars = (new Ethna_RequestWrapper($reqeust))->getHttpVars();
        $_files = $reqeust->files->all();
        foreach ($this->form as $name => $def) {
            $type = is_array($def['type']) ? $def['type'][0] : $def['type'];
            if ($type == VAR_TYPE_FILE) {
                // ファイルの場合

                // 値の有無の検査
                if (isset($_files[$name]) == false || is_null($_files[$name])) {
                    $this->form_vars[$name] = null;
                    continue;
                }

                // 配列構造の検査
                if (is_array($def['type'])) {
                    if (is_array($_files[$name]['tmp_name']) == false) {
                        $this->handleError($name, E_FORM_WRONGTYPE_ARRAY);
                        $this->form_vars[$name] = null;
                        continue;
                    }
                } else {
                    if (is_array($_files[$name]['tmp_name'])) {
                        $this->handleError($name, E_FORM_WRONGTYPE_SCALAR);
                        $this->form_vars[$name] = null;
                        continue;
                    }
                }

                $files = null;
                if (is_array($def['type'])) {
                    $files = array();
                    // ファイルデータを再構成
                    foreach (array_keys($_files[$name]['name']) as $key) {
                        $files[$key] = array();
                        $files[$key]['name'] = $_files[$name]['name'][$key];
                        $files[$key]['type'] = $_files[$name]['type'][$key];
                        $files[$key]['size'] = $_files[$name]['size'][$key];
                        $files[$key]['tmp_name'] = $_files[$name]['tmp_name'][$key];
                        if (isset($_files[$name]['error']) == false) {
                            // PHP 4.2.0 以前
                            $files[$key]['error'] = 0;
                        } else {
                            $files[$key]['error'] = $_files[$name]['error'][$key];
                        }
                    }
                } else {
                    $files = $_files[$name];
                    if (isset($files['error']) == false) {
                        $files['error'] = 0;
                    }
                }

                // 値のインポート
                $this->form_vars[$name] = $files;

            } else {
                // ファイル以外の場合

                // 値の有無の検査
                if (isset($http_vars[$name]) == false
                    || is_null($http_vars[$name])) {
                    $this->form_vars[$name] = null;
                    if (isset($http_vars["{$name}_x"])
                        && isset($http_vars["{$name}_y"])) {
                        // 以前の仕様に合わせる
                        $this->form_vars[$name] = $http_vars["{$name}_x"];
                    }
                    continue;
                }

                // 配列構造の検査
                if (is_array($def['type'])) {
                    if (is_array($http_vars[$name]) == false) {
                        // 厳密には、この配列の各要素はスカラーであるべき
                        $this->handleError($name, E_FORM_WRONGTYPE_ARRAY);
                        $this->form_vars[$name] = null;
                        continue;
                    }
                } else {
                    if (is_array($http_vars[$name])) {
                        $this->handleError($name, E_FORM_WRONGTYPE_SCALAR);
                        $this->form_vars[$name] = null;
                        continue;
                    }
                }

                // 値のインポート
                $this->form_vars[$name] = $http_vars[$name];
            }
        }
    }

    /**
     *  ユーザから送信されたフォーム値をクリアする
     *
     *  @access public
     */
    public function clearFormVars()
    {
        $this->form_vars = array();
    }

    /**
     *  フォーム値へのアクセサ(W)
     *
     *  @access public
     *  @param  string  $name   フォーム値の名称
     *  @param  string  $value  設定する値
     */
    public function set($name, $value)
    {
        $this->form_vars[$name] = $value;
    }

    /**
     *  フォーム値定義を設定する
     *
     *  @access public
     *  @param  string  $name   設定するフォーム名(nullなら全ての定義を設定)
     *  @param  array   $value  設定するフォーム値定義
     *  @return array   フォーム値定義
     */
    public function setDef($name, $value)
    {
        if (is_null($name)) {
            $this->form = $value;
        }

        $this->form[$name] = $value;
    }

    /**
     *  フォーム値を配列にして返す
     *
     *  @access public
     *  @param  bool    $escape HTMLエスケープフラグ(true:エスケープする)
     *  @return array   フォーム値を格納した配列
     */
    public function getArray($escape = true)
    {
        $retval = array();

        $this->_getArray($this->form_vars, $retval, $escape);

        return $retval;
    }

    /**
     *  アプリケーション設定値のアクセサ(R)
     *
     *  @access public
     *  @param  string  $name   キー
     *  @return mixed   アプリケーション設定値
     */
    public function getApp($name)
    {
        if (isset($this->app_vars[$name]) == false) {
            return null;
        }
        return $this->app_vars[$name];
    }

    /**
     *  アプリケーション設定値のアクセサ(W)
     *
     *  @access public
     *  @param  string  $name   キー
     *  @param  mixed   $value  値
     */
    public function setApp($name, $value)
    {
        $this->app_vars[$name] = $value;
    }

    /**
     *  アプリケーション設定値を配列にして返す
     *
     *  @access public
     *  @param  boolean $escape HTMLエスケープフラグ(true:エスケープする)
     *  @return array   フォーム値を格納した配列
     */
    public function getAppArray($escape = true)
    {
        $retval = array();

        $this->_getArray($this->app_vars, $retval, $escape);

        return $retval;
    }

    /**
     *  アプリケーション設定値(自動エスケープなし)のアクセサ(R)
     *
     *  @access public
     *  @param  string  $name   キー
     *  @return mixed   アプリケーション設定値
     */
    public function getAppNE($name)
    {
        if (isset($this->app_ne_vars[$name]) == false) {
            return null;
        }
        return $this->app_ne_vars[$name];
    }

    /**
     *  アプリケーション設定値(自動エスケープなし)のアクセサ(W)
     *
     *  @access public
     *  @param  string  $name   キー
     *  @param  mixed   $value  値
     */
    public function setAppNE($name, $value)
    {
        $this->app_ne_vars[$name] = $value;
    }

    /**
     *  アプリケーション設定値(自動エスケープなし)を配列にして返す
     *
     *  @access public
     *  @param  boolean $escape HTMLエスケープフラグ(true:エスケープする)
     *  @return array   フォーム値を格納した配列
     */
    public function getAppNEArray($escape = false)
    {
        $retval = array();

        $this->_getArray($this->app_ne_vars, $retval, $escape);

        return $retval;
    }

    /**
     *  フォームを配列にして返す(内部処理)
     *
     *  @access private
     *  @param  array   &$vars      フォーム(等)の配列
     *  @param  array   &$retval    配列への変換結果
     *  @param  bool    $escape     HTMLエスケープフラグ(true:エスケープする)
     */
    public function _getArray(&$vars, &$retval, $escape)
    {
        foreach (array_keys($vars) as $name) {
            if (is_array($vars[$name])) {
                $retval[$name] = array();
                $this->_getArray($vars[$name], $retval[$name], $escape);
            } else if (is_null($vars[$name])) {
                $retval[$name] = null;
            } else {
                $retval[$name] = $escape
                    ? htmlspecialchars($vars[$name], ENT_QUOTES, mb_internal_encoding()) : $vars[$name];
            }
        }
    }

    /**
     *  追加検証強制フラグを取得する
     *  (通常検証でエラーが発生した場合でも_validatePlus()が呼び出される)
     *  @access public
     *  @return bool    true:追加検証強制 false:追加検証非強制
     */
    public function isForceValidatePlus()
    {
        return $this->force_validate_plus;
    }

    /**
     *  追加検証強制フラグを設定する
     *
     *  @access public
     *  @param  $force_validate_plus    追加検証強制フラグ
     */
    public function setForceValidatePlus($force_validate_plus)
    {
        $this->force_validate_plus = $force_validate_plus;
    }

    /**
     *  フォーム値検証メソッド
     *
     *  @access public
     *  @return int     発生したエラーの数
     */
    public function validate()
    {
        $this->logger->log(LOG_INFO, "validation start.");
        foreach ($this->form as $name => $def) {
            $this->_validateWithPlugin($name);
        }

        if ($this->ae->count() == 0 || $this->isForceValidatePlus()) {
            // 追加検証メソッド
            $this->_validatePlus();
        }

        $errorCount = $this->ae->count();
        if ($errorCount > 0) {
            $this->logger->log(LOG_INFO, "validation failed. error count [%d]", $errorCount);
        } else {
            $this->logger->log(LOG_INFO, "validation success.");
        }

        return $errorCount;
    }

    /**
     *  プラグインを使ったフォーム値検証メソッド
     *
     *  @access private
     *  @param  string  $form_name  フォームの名前
     *  @todo   ae 側に $key を与えられるようにする
     */
    function _validateWithPlugin($form_name)
    {
        $this->logger->log(LOG_DEBUG, "validating form [%s]", $form_name);

        // (pre) filter
        if ($this->form[$form_name]['type'] != VAR_TYPE_FILE) {
            if (is_array($this->form[$form_name]['type']) == false) {
                $this->form_vars[$form_name]
                    = $this->_filter($this->form_vars[$form_name],
                                     $this->form[$form_name]['filter']);
            } else if ($this->form_vars[$form_name] != null) {
                foreach (array_keys($this->form_vars[$form_name]) as $key) {
                    $this->form_vars[$form_name][$key]
                        = $this->_filter($this->form_vars[$form_name][$key],
                                         $this->form[$form_name]['filter']);
                }
            } else {  //  配列で値が空の場合
                $this->form_vars[$form_name]
                    = $this->_filter($this->form_vars[$form_name],
                                     $this->form[$form_name]['filter']);
            }
        }

        $form_vars = $this->get($form_name);
        $plugin = $this->_getPluginDef($form_name);

        // type のチェックを処理の最初に追加
        $plugin = array_merge(array('type' => array()), $plugin);
        if (is_array($this->form[$form_name]['type'])) {
            $plugin['type']['type'] = $this->form[$form_name]['type'][0];
        } else {
            $plugin['type']['type'] = $this->form[$form_name]['type'];
        }
        if (isset($this->form[$form_name]['type_error'])) {
            $plugin['type']['error'] = $this->form[$form_name]['type_error'];
        }

        // スカラーの場合
        if (is_array($this->form[$form_name]['type']) == false) {
            foreach (array_keys($plugin) as $name) {
                // break: 明示されていなければ，エラーが起きたらvalidateを継続しない
                $break = isset($plugin[$name]['break']) == false
                               || $plugin[$name]['break'];

                // プラグイン取得
                unset($v);
                $v = $this->plugin->getPlugin('Validator',
                                               ucfirst(strtolower($name)));
                $this->logger->log(LOG_DEBUG, "validating form [%s] by validator plugin [%s]", $form_name, $name);
                if (Ethna::isError($v)) {
                    $this->logger->log(LOG_NOTICE, "cannot get validator plugin [%s]", $name);
                    continue;
                }

                // バリデーション実行
                unset($r);
                $r = $v->validate($form_name, $form_vars, $plugin[$name]);

                // エラー処理
                if ($r !== true) {
                    if (Ethna::isError($r)) {
                        $this->ae->addObject($form_name, $r);
                    }
                    if ($break) {
                        break;
                    }
                }
            }
            return;
        }

        // 配列の場合

        // break 指示用の key list
        $valid_keys = is_array($form_vars) ? array_keys($form_vars) : array();

        foreach (array_keys($plugin) as $name) {
            // break: 明示されていなければ，エラーが起きたらvalidateを継続しない
            $break = isset($plugin[$name]['break']) == false
                           || $plugin[$name]['break'];

            // プラグイン取得
            unset($v);
            $v = $this->plugin->getPlugin('Validator', ucfirst(strtolower($name)));
            if (Ethna::isError($v)) {
                continue;
            }

            // 配列全体を受け取るプラグインの場合
            if (isset($v->accept_array) && $v->accept_array == true) {
                // バリデーション実行
                unset($r);
                $r = $v->validate($form_name, $form_vars, $plugin[$name]);

                // エラー処理
                if (Ethna::isError($r)) {
                    $this->ae->addObject($form_name, $r);
                    if ($break) {
                        break;
                    }
                }
                continue;
            }

            // 配列の各要素に対して実行
            foreach ($valid_keys as $key) {
                // バリデーション実行
                unset($r);
                $r = $v->validate($form_name, $form_vars[$key], $plugin[$name]);

                // エラー処理
                if (Ethna::isError($r)) {
                    $this->ae->addObject($form_name, $r);
                    if ($break) {
                        unset($valid_keys[$key]);
                    }
                }
            }
        }
    }

    /**
     *  チェックメソッド(基底クラス)
     *
     *  @access public
     *  @param  string  $name   フォーム項目名
     *  @return array   チェック対象のフォーム値(エラーが無い場合はnull)
     */
    public function check($name)
    {
        if (is_null($this->get($name)) || $this->get($name) === "") {
            return null;
        }

        // Ethna_Backendの設定
        $c = Ethna_Kernel::getInstance();
        $this->controller = $c;

        return to_array($this->get($name));
    }

    /**
     *  チェックメソッド: 機種依存文字
     *
     *  @access public
     *  @param  string  $name   フォーム項目名
     *  @return object  Ethna_Error エラーオブジェクト(エラーが無い場合はnull)
     */
    public function checkVendorChar($name)
    {
        $null = null;
        $string = $this->get($name);

        for ($i = 0; $i < strlen($string); $i++) {
            /* JIS13区のみチェック */
            $c = ord($string{$i});
            if ($c < 0x80) {
                /* ASCII */
{'fraction_non_alphanumeric': 0.14892991690490823, 'fraction_numerical': 0.0015496833836535122, 'mean_word_length': 1.4461146330305208, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 284, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4779863', 'n_tokens_mistral': 13165, 'n_tokens_neox': 12923, 'n_words': 1883}