LoginSignup
7

More than 5 years have passed since last update.

Codeigniter3.0のバリデーション一覧(途中)

Last updated at Posted at 2015-12-24

Codeigniter3.0.3のバリデーションルールまとめ

遅れて申し訳ありません。
申し訳ついでに、面白くないテーマですが、バリデーションルールについてまとめました。

基本ルール

「/system/libraries/Form_validation.php」
内にある、
「required」以下のメソッドに内容についてソース読みましょう、読みましょう。

調査対象

  • Codeigniter3.0.3

基礎知識

バリデーションルールって、こんな感じで記述すると思います。

exsample.php
    // 例1:一番単純な書き方    
    // $_POST['first_name'] = 'tomcat';
    $this->form_validation->set_rules('first_name', 'lang:first_name', 'max_length[100]');

バリデーションルール名がそのままメソッド名となります。
フォームに入力された値が第一引数として渡ります。
[]に囲まれた部分(例1での100)が、バリデーションルールの第二引数として渡ります。

Form_validation.php
    // 例1に対応したバリデーションルール
    // ここには $str = 'tomcat'; $val = '100'; が来ます。
    public function max_length($str, $val)
    {
        if ( ! is_numeric($val))
        {
            return FALSE;
        }

        return ($val >= mb_strlen($str));
    }

本編

required

Form_validation.php
    public function required($str)
    {
        return is_array($str) ? (bool) count($str) : (trim($str) !== '');
    }
  • 要素があるかどうかをチェック
  • 配列対応

regex_match

Form_validation.php
    public function regex_match($str, $regex)
    {
        return (bool) preg_match($regex, $str);
    }

正規表現を使用した、文字チェック
詳しくはPHPマニュアル参照のこと
http://php.net/manual/ja/function.preg-match.php

matches

Form_validation.php
    public function matches($str, $field)
    {
        return isset($this->_field_data[$field], $this->_field_data[$field]['postdata'])
            ? ($str === $this->_field_data[$field]['postdata'])
            : FALSE;
    }

他のカラムと一致するかの確認
パスワードの確認、メールアドレスの確認なのでよく使う

differs

Form_validation.php
    public function differs($str, $field)
    {
        return ! (isset($this->_field_data[$field]) && $this->_field_data[$field]['postdata'] === $str);
    }

他のカラムと一致しない
パスワードの再設定とか?
matchesの反対

is_unique

Form_validation.php
    public function is_unique($str, $field)
    {
        sscanf($field, '%[^.].%[^.]', $table, $field);
        return isset($this->CI->db)
            ? ($this->CI->db->limit(1)->get_where($table, array($field => $str))->num_rows() === 0)
            : FALSE;
    }

特定のテーブルの特定のカラムで、ユニークかどうか調べる
自分自身のレコードを除外できない、削除済レコードの除外等の小賢しい処理を挟めないので、実用性は・・・

min_length

Form_validation.php
    public function min_length($str, $val)
    {
        if ( ! is_numeric($val))
        {
            return FALSE;
        }

        return ($val <= mb_strlen($str));
    }

最低文字数
パスワードの設定などに

max_length

Form_validation.php
    public function max_length($str, $val)
    {
        if ( ! is_numeric($val))
        {
            return FALSE;
        }

        return ($val >= mb_strlen($str));
    }

最大文字数
input系ではほぼ必須?

exact_length

Form_validation.php

    public function exact_length($str, $val)
    {
        if ( ! is_numeric($val))
        {
            return FALSE;
        }

        return (mb_strlen($str) === (int) $val);
    }

指定文字数かどうか
郵便番号とか?長さが決まっているもの

valid_url

Form_validation.php

    public function valid_url($str)
    {
        if (empty($str))
        {
            return FALSE;
        }
        elseif (preg_match('/^(?:([^:]*)\:)?\/\/(.+)$/', $str, $matches))
        {
            if (empty($matches[2]))
            {
                return FALSE;
            }
            elseif ( ! in_array($matches[1], array('http', 'https'), TRUE))
            {
                return FALSE;
            }

            $str = $matches[2];
        }

        $str = 'http://'.$str;

        // There's a bug affecting PHP 5.2.13, 5.3.2 that considers the
        // underscore to be a valid hostname character instead of a dash.
        // Reference: https://bugs.php.net/bug.php?id=51192
        if (version_compare(PHP_VERSION, '5.2.13', '==') OR version_compare(PHP_VERSION, '5.3.2', '=='))
        {
            sscanf($str, 'http://%[^/]', $host);
            $str = substr_replace($str, strtr($host, array('_' => '-', '-' => '_')), 7, strlen($host));
        }

        return (filter_var($str, FILTER_VALIDATE_URL) !== FALSE);
    }

URLとして正しいかどうかチェックする
ここに来て、ちょっと面白いルールが出てきました。
まず、今回この記事を書くにあたって、注目した部分が以下の一文です。
preg_match('/^(?:([^:]*)\:)?\/\/(.+)$/', $str, $matches)
勉強不足で初めて知ったのですが、ここの正規表現の「(?:〜〜)」の部分はキャプチャしない
という意味らしいです。(キャプチャとはここでいう$matchesに入れないと考えていただければ差し支えありません。)
この場合ですと、外側の丸カッコは必要ないだけではなく、丸カッコがネストしています。
そこでキャプチャしないという指定をしてあげることで、$matchesの中にどういう順番で文字列が格納されるのかとてもわかりやすくなります。
さて、その後の記述ですが、PHPのバージョンについてコメント付きの条件式が出てきますが、3.0ではPHP5.4以上なのでそのうち外されるんでしょうか?
何にせよ、歴史を感じる記述です。(2.0の頃、ここに関する面白いやりとりが公式リポジトリのissueでありましたが、今ログが見つかりませんでした・・・残念)

valid_email

Form_validation.php


    public function valid_email($str)
    {
        if (function_exists('idn_to_ascii') && $atpos = strpos($str, '@'))
        {
            $str = substr($str, 0, ++$atpos).idn_to_ascii(substr($str, $atpos));
        }

        return (bool) filter_var($str, FILTER_VALIDATE_EMAIL);
    }

メールアドレスとして正しいかチェックする
もうひとつ面白いルールです。
idn_to_asciiとは、誤解を恐れず言うとマルチバイト対応です。
つまり、日本語ドメインなどのメールアドレスをちゃんと扱えるということになります。
日本語ドメインメールアドレスはGoogleが対応すると告知した以上、今後ある程度は普及すると考えられます。
https://googleblog.blogspot.jp/2014/08/a-first-step-toward-more-global-email.html

valid_emails

Form_validation.php

    public function valid_emails($str)
    {
        if (strpos($str, ',') === FALSE)
        {
            return $this->valid_email(trim($str));
        }

        foreach (explode(',', $str) as $email)
        {
            if (trim($email) !== '' && $this->valid_email(trim($email)) === FALSE)
            {
                return FALSE;
            }
        }

        return TRUE;
    }

カンマ区切りの複数のメールアドレスが正しいか、チェックする
カンマでぶった切って、valid_emailに投げてくれます。

valid_ip

Form_validation.php

    public function valid_ip($ip, $which = '')
    {
        return $this->CI->input->valid_ip($ip, $which);
    }

IPアドレスとして正しいかチェックする
処理の本体は/system/libraries/Input.phpにあります。

Input.php
    public function valid_ip($ip, $which = '')
    {
        $which = strtolower($which);

        // First check if filter_var is available
        if (is_callable('filter_var'))
        {
            switch ($which) {
                case 'ipv4':
                    $flag = FILTER_FLAG_IPV4;
                    break;
                case 'ipv6':
                    $flag = FILTER_FLAG_IPV6;
                    break;
                default:
                    $flag = '';
                    break;
            }

            return (bool) filter_var($ip, FILTER_VALIDATE_IP, $flag);
        }

        if ($which !== 'ipv6' && $which !== 'ipv4')
        {
            if (strpos($ip, ':') !== FALSE)
            {
                $which = 'ipv6';
            }
            elseif (strpos($ip, '.') !== FALSE)
            {
                $which = 'ipv4';
            }
            else
            {
                return FALSE;
            }
        }

        $func = '_valid_'.$which;
        return $this->$func($ip);
    }

    // --------------------------------------------------------------------

    /**
    * Validate IPv4 Address
    *
    * Updated version suggested by Geert De Deckere
    *
    * @access   protected
    * @param    string
    * @return   bool
    */
    protected function _valid_ipv4($ip)
    {
        $ip_segments = explode('.', $ip);

        // Always 4 segments needed
        if (count($ip_segments) !== 4)
        {
            return FALSE;
        }
        // IP can not start with 0
        if ($ip_segments[0][0] == '0')
        {
            return FALSE;
        }

        // Check each segment
        foreach ($ip_segments as $segment)
        {
            // IP segments must be digits and can not be
            // longer than 3 digits or greater then 255
            if ($segment == '' OR preg_match("/[^0-9]/", $segment) OR $segment > 255 OR strlen($segment) > 3)
            {
                return FALSE;
            }
        }

        return TRUE;
    }

    // --------------------------------------------------------------------

    /**
    * Validate IPv6 Address
    *
    * @access   protected
    * @param    string
    * @return   bool
    */
    protected function _valid_ipv6($str)
    {
        // 8 groups, separated by :
        // 0-ffff per group
        // one set of consecutive 0 groups can be collapsed to ::

        $groups = 8;
        $collapsed = FALSE;

        $chunks = array_filter(
            preg_split('/(:{1,2})/', $str, NULL, PREG_SPLIT_DELIM_CAPTURE)
        );

        // Rule out easy nonsense
        if (current($chunks) == ':' OR end($chunks) == ':')
        {
            return FALSE;
        }

        // PHP supports IPv4-mapped IPv6 addresses, so we'll expect those as well
        if (strpos(end($chunks), '.') !== FALSE)
        {
            $ipv4 = array_pop($chunks);

            if ( ! $this->_valid_ipv4($ipv4))
            {
                return FALSE;
            }

            $groups--;
        }

        while ($seg = array_pop($chunks))
        {
            if ($seg[0] == ':')
            {
                if (--$groups == 0)
                {
                    return FALSE;   // too many groups
                }

                if (strlen($seg) > 2)
                {
                    return FALSE;   // long separator
                }

                if ($seg == '::')
                {
                    if ($collapsed)
                    {
                        return FALSE;   // multiple collapsed
                    }

                    $collapsed = TRUE;
                }
            }
            elseif (preg_match("/[^0-9a-f]/i", $seg) OR strlen($seg) > 4)
            {
                return FALSE; // invalid segment
            }
        }

        return $collapsed OR $groups == 1;
    }

filter_varはここでも大活躍ですね。

alpha

Form_validation.php
    public function alpha($str)
    {
        return ctype_alpha($str);
    }

PHPのデフォルト関数に渡しているだけです。
シンプルでいいですね。
参考文献: http://php.net/manual/ja/function.ctype-alpha.php

alpha_numeric

Form_validation.php
    public function alpha_numeric($str)
    {
        return ctype_alnum((string) $str);
    }

こちらもPHPのデフォルト関数に渡しているだけです。
シンプルでいいですね。
参考文献: http://php.net/manual/ja/function.ctype-alnum.php

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7