ここの情報は古いです。ご理解頂いた上でお取り扱いください。

source: OpenPNE/trunk/webapp/lib/OpenPNE/Validator.php

Last change on this file was 13623, checked in by tajima, 9 years ago

#4433: fixed bug on PHP 5.3

File size: 12.4 KB
Line 
1<?php
2/**
3 * @copyright 2005-2008 OpenPNE Project
4 * @license   http://www.php.net/license/3_01.txt PHP License 3.01
5 */
6
7/**
8 * ユーザー入力値バリデータクラス
9 */
10class OpenPNE_Validator
11{
12    /**
13     * @var array 検証ルール
14     * @access private
15     */
16    var $rules = array();
17
18    /**
19     * @var array 検証済みリクエストパラメタ
20     * @access private
21     */
22    var $params = array();
23
24    /**
25     * @var array エラー
26     * @access private
27     */
28    var $errors = array();
29
30    /**
31     * @var array 検証対象リクエストパラメタ
32     * @access private
33     */
34    var $requests = array();
35
36    /**
37     * @var string デフォルトフィルター
38     */
39    var $default_filter = 'ntrim,rtrim,mysqltext';
40
41    /**
42     * バリデータの初期化
43     *
44     * @param array $rules
45     * @param array $requests
46     */
47    function OpenPNE_Validator($rules = array(), $requests = array())
48    {
49        $this->rules = $rules;
50        if ($requests) {
51            $this->requests = $requests;
52        } else {
53            $this->requests = $_REQUEST;
54        }
55    }
56
57    /**
58     * ルールの追加
59     *
60     * @access public
61     * @param array $rules
62     */
63    function addRules($rules)
64    {
65        $this->rules = array_merge($this->rules, (array)$rules);
66    }
67
68    /**
69     * ルールをiniファイルから追加
70     *
71     * @access public
72     * @param string $ini_path
73     */
74    function addIniSetting($ini_path)
75    {
76        if(version_compare(PHP_VERSION, '5.3.0', '>=')){
77            if (!is_readable($ini_path) ||
78                !$rules = parse_ini_file($ini_path, true, INI_SCANNER_RAW)) {
79                return false;
80            }
81        } else {
82            if (!is_readable($ini_path) ||
83                !$rules = parse_ini_file($ini_path, true)) {
84                return false;
85            }
86        }
87
88        $this->addRules($rules);
89        return true;
90    }
91
92    /**
93     * (検証済み)リクエストパラメータを取得
94     *
95     * @access public
96     * @return array
97     */
98    function getParams()
99    {
100        return $this->params;
101    }
102
103    /**
104     * エラー情報を取得
105     *
106     * @access public
107     * @return array
108     */
109    function getErrors()
110    {
111        return $this->errors;
112    }
113
114    /**
115     * (検証前の)リクエストパラメータを追加
116     *
117     * @access public
118     * @param array $requests
119     */
120    function addRequests($requests)
121    {
122        $this->requests = array_merge($this->requests, (array)$requests);
123    }
124
125    /**
126     * パラメータに検証済みの値をセット
127     *
128     * @access private
129     * @param string $key
130     * @param string $value
131     */
132    function _setParam($key, $value)
133    {
134        $this->params[$key] = $value;
135    }
136
137    /**
138     * エラー情報を設定
139     *
140     * @access private
141     * @param string $key
142     * @param string $msg エラーメッセージ
143     */
144    function _setError($key, $msg)
145    {
146        // エラーメッセージに名称変更を適用
147        $msg = preg_replace_callback('/WORD_[A-Z_]+/', create_function('$m', 'return defined($m[0]) ? constant($m[0]) : $m[0];'), $msg);
148
149        $this->errors[$key] = $msg;
150    }
151
152    /**
153     * validate
154     *
155     * @access public
156     * @return boolean エラーが発生しなかったかどうか
157     */
158    function validate()
159    {
160        foreach ($this->rules as $key => $rule) {
161            $rule = $this->_initRule($key, $rule);
162
163            $values = array();
164            if (isset($this->requests[$key])) {
165                if (!is_array($this->requests[$key])) {
166                    $values = array($this->requests[$key]);
167                } else {
168                    $values = $this->requests[$key];
169                }
170            }
171
172            if (empty($rule['is_array'])) {
173                $reqval = array_shift($values);
174                $result = $this->_filter($reqval, $rule['pre_filter']);
175
176                // 必須項目チェック
177                if (is_null($result) || $result === '') {
178                    if (!empty($rule['required'])) {
179                        if (isset($rule['required_error'])) {
180                            $error = $rule['required_error'];
181                        } else {
182                            $error = "{$rule['caption']}を入力してください";
183                        }
184                        $this->_setError($key, $error);
185                    } else {
186                        if (isset($rule['default'])) {
187                            $result = $rule['default'];
188                        } else {
189                            $result = null;
190                        }
191                    }
192                } else {
193                    $this->_validate($key, $result, $rule);
194                }
195            } else {
196                $result = array();
197                $empty = true;
198                foreach ($values as $k => $value) {
199                    $value = $this->_filter($value, $rule['pre_filter']);
200                    if (is_null($value) || $value === '') {
201                        continue;
202                    }
203
204                    $this->_validate($key, $value, $rule);
205                    $result[$k] = $value;
206                    $empty = false;
207                }
208                if ($empty) {
209                    if (!empty($rule['required'])) {
210                        if (isset($rule['required_error'])) {
211                            $error = $rule['required_error'];
212                        } else {
213                            $error = "{$rule['caption']}を入力してください";
214                        }
215                        $this->_setError($key, $error);
216                    } else {
217                        if (isset($rule['default'])) {
218                            $result = array($rule['default']);
219                        } else {
220                            $result = array();
221                        }
222                    }
223                }
224            }
225
226            $this->_setParam($key, $result);
227        }
228
229        return empty($this->errors);
230    }
231
232    /**
233     * 検証ルールの初期化
234     *
235     * @access private
236     * @param string $key
237     * @param array $rule
238     * @return array 初期化済み検証ルール
239     */
240    function _initRule($key, $rule)
241    {
242        if (!isset($rule['caption'])) {
243            $rule['caption'] = $key;
244        }
245
246        if (!isset($rule['pre_filter'])) {
247            $rule['pre_filter'] = $this->default_filter;
248        }
249
250        if (empty($rule['type'])) {
251            $rule['type'] = 'string';
252        }
253
254        if ($rule['type'] == 'int') {
255            $rule['pre_filter'] = $rule['pre_filter'] . ',intval';
256        }
257
258        return $rule;
259    }
260
261    /**
262     * _filter
263     *
264     * @access private
265     * @param string $value
266     * @param string $filter
267     * @return string フィルターを通した値
268     */
269    function _filter($value, $filter)
270    {
271        $filters = explode(',', $filter);
272        foreach ($filters as $filter) {
273            if (!empty($filter)) {
274                switch ($filter) {
275                case 'trim':
276                    if (OPENPNE_TRIM_DOUBLEBYTE_SPACE) {
277                        // 全角スペースに対応
278                        $value = preg_replace('/^[\s ]+/u', '', $value);
279                        $value = preg_replace('/[\s ]+$/u', '', $value);
280                    } else {
281                        $value = trim($value);
282                    }
283                    break;
284                case 'ltrim':
285                    if (OPENPNE_TRIM_DOUBLEBYTE_SPACE) {
286                        // 全角スペースに対応
287                        $value = preg_replace('/^[\s ]+/u', '', $value);
288                    } else {
289                        $value = ltrim($value);
290                    }
291                    break;
292                case 'rtrim':
293                    if (OPENPNE_TRIM_DOUBLEBYTE_SPACE) {
294                        // 全角スペースに対応
295                        $value = preg_replace('/[\s ]+$/u', '', $value);
296                    } else {
297                        $value = rtrim($value);
298                    }
299                    break;
300                case 'ntrim':
301                    // NULL バイト・制御文字(HT,LF,NBSP以外)をすべて削除
302                    $value = preg_replace("/[\x{0}-\x{08}\x{0b}-\x{1f}\x{7f}-\x{9f}\x{ad}]/u", '', $value);
303                    break;
304                case 'mysqltext':
305                    if (is_string($value) && strlen($value) > 65535) {
306                        $value = mb_strcut($value, 0, 65535);
307                    }
308                    break;
309                case 'intval':
310                    if (is_numeric($value)) {
311                        $value = (int)$value;
312                    }
313                    break;
314                }
315            }
316        }
317        return $value;
318    }
319
320    /**
321     * _validate
322     *
323     * @access private
324     * @param string $key
325     * @param string $reqval
326     * @param array $rule
327     * @return boolean
328     */
329    function _validate($key, $reqval, $rule)
330    {
331        // 型チェック
332        switch (strtolower($rule['type'])) {
333        case 'int':
334            if (!is_numeric($reqval)) {
335                if (isset($rule['type_error'])) {
336                    $error = $rule['type_error'];
337                } else {
338                    $error = "{$rule['caption']}は数値で入力してください";
339                }
340                $this->_setError($key, $error);
341                return false;
342            }
343            break;
344        case 'bool':
345            if ($reqval != '0' && $reqval != '1') {
346                if (isset($rule['type_error'])) {
347                    $error = $rule['type_error'];
348                } else {
349                    $error = "{$rule['caption']}の値が不正です";
350                }
351                $this->_setError($key, $error);
352                return false;
353            }
354            break;
355        case 'string':
356            break;
357        case 'regexp':
358            if (isset($rule['regexp']) && !preg_match($rule['regexp'], $reqval)) {
359                if (isset($rule['type_error'])) {
360                    $error = $rule['type_error'];
361                } else {
362                    $error = "{$rule['caption']}を正しく入力してください";
363                }
364                $this->_setError($key, $error);
365                return false;
366            }
367            break;
368        default:
369            $error = "{$rule['type']}は未定義の型です";
370            $this->_setError($key, $error);
371            return false;
372        }
373
374        // min/max チェック
375        switch ($rule['type']) {
376        case 'int':
377            // min
378            if (isset($rule['min']) && $reqval < intval($rule['min'])) {
379                if (isset($rule['min_error'])) {
380                    $error = $rule['min_error'];
381                } else {
382                    $error = "{$rule['caption']}{$rule['min']}以上の数値で入力してください";
383                }
384                $this->_setError($key, $error);
385                return false;
386            }
387            // max
388            if (isset ($rule['max']) && $reqval > $rule['max']) {
389                if (isset($rule['max_error'])) {
390                    $error = $rule['max_error'];
391                } else {
392                    $error = "{$rule['caption']}{$rule['max']}以下の数値で入力してください";
393                }
394                $this->_setError($key, $error);
395                return false;
396            }
397            break;
398        case 'string':
399        case 'regexp':
400            // min
401            if (isset($rule['min']) && (mb_strwidth($reqval, 'UTF-8') < $rule['min'])) {
402                if (isset($rule['min_error'])) {
403                    $error = $rule['min_error'];
404                } else {
405                    $error = "{$rule['caption']}は半角{$rule['min']}文字以上で入力してください";
406                }
407                $this->_setError($key, $error);
408                return false;
409            }
410            // max
411            if (isset($rule['max']) && (mb_strwidth($reqval, 'UTF-8') > $rule['max'])) {
412                if (isset($rule['max_error'])) {
413                    $error = $rule['max_error'];
414                } else {
415                    $error = "{$rule['caption']}は半角{$rule['max']}文字以内で入力してください";
416                }
417                $this->_setError($key, $error);
418                return false;
419            }
420            break;
421        }
422
423        return true;
424    }
425}
426
427?>
Note: See TracBrowser for help on using the repository browser.