🔥

CodeIgniter4 バリデーションルール valid_date は年月の検証に使用できるのか

2022/11/15に公開2

はじめに

Validation — CodeIgniter 4.2.10 documentation

Rule: valid_date
Description: Fails if field does not contain a valid date. Accepts an optional parameter to matches a date format.
Example: valid_date[d/m/Y]

valid_date[Y/m] のように指定した場合に期待する結果が得られなかった為、実装を確認した。

実行環境

  • CodeIgniter 4.2.10

動作確認

system\Validation\FormatRules.php
<?php

//...

class FormatRules
{
    //...

    public function valid_date(?string $str = null, ?string $format = null): bool
    {
        if ($str === null) {
            return false;
        }

        if (empty($format)) {
            return strtotime($str) !== false;
        }

        $date   = DateTime::createFromFormat($format, $str);
        $errors = DateTime::getLastErrors();

        if ($date === false) {
            return false;
        }

        // PHP 8.2 or later.
        if ($errors === false) {
            return true;
        }

        return $errors['warning_count'] === 0 && $errors['error_count'] === 0;
    }
}

DateTime::createFromFormat のパース結果で判定されていることがわかる。

正常系

var_dump(DateTime::createFromFormat('Y/m', '2022/11'));
object(DateTime)#1 (3) {
  ["date"]=>
  string(26) "2022-11-15 12:30:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(10) "Asia/Tokyo"
}

異常系

var_dump(DateTime::createFromFormat('Y/m', '2022'));
bool(false)

存在しない月

var_dump(DateTime::createFromFormat('Y/m', '2022/18'));
object(DateTime)#1 (3) {
  ["date"]=>
  string(26) "2023-06-15 12:30:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(10) "Asia/Tokyo"
}

オブジェクトが返却される為、valid_date は正常と判断する。

代案

年月の妥当性をチェックする適当なカスタムバリデーションを実装する。

app\Config\Validation.php
    public $ruleSets = [
        Rules::class,
        FormatRules::class,
        FileRules::class,
        CreditCardRules::class,
+       CustomRules::class,
    ];
app\Config\CustomRules.php
<?php

namespace Config;

class CustomRules
{
    public function valid_ym(?string $str = null): bool
    {
        return (bool)preg_match('/^(19|20)\d{2}\/(0[1-9]|1[0-2])$/', $str);
    }
}
app\Language\ja\Validation.php
<?php

return [
    'valid_ym' => '{field} には、有効な年月を入力してください。',
];

参考

Discussion