用于日期验证的通用格式


Versatile format for date validations?

我正在寻找一种验证日期的通用方法。

我想要的是实现验证规则的某种方法,例如:

First monday of month

monday or friday

Fourth day of month

有什么可以满足这些要求吗?或者有人对我如何实现这一目标有任何指示吗?

编辑:我很欣赏这些答案,但这是我现在最终使用的:

感谢您的所有答案。我最终实际使用的(至少在我找到完美的解决方案之前(大致是这个函数:

function isDateValid($rule,$date){
    $DATE = (int) $date;
    /* Make it safe for eval */
    preg_match_all('/:'w:|&&|'|'||<|=|>|!|'(|')|'d+/i',$rule,$filteredRule);
    $rule = implode('',$filteredRule[0]);
    //replace rule notations
    $f = function($str){
        return "date('$str[1]','$DATE)";
    };
    //Or if php < 5.3: $f = create_function('$str', 'return "date(''$str[1]'','$DATE)";');
    $rule = preg_replace_callback('/:('w):/i', $f, $rule);
    //Evaluate expression
    return @eval("return $rule;");
}
//Example of usage testing first of month:
var_dump( isDateValid(':d:==1',time()) );

这让我可以处理我的所有需求,以及PHP代码。使用它的人非常有限(<5人(,他们中的大多数人都有一定程度的php经验。现在我可以制定规则,例如:

first monday of month:w:==1 && :d: <= 7

monday or friday:w:==1 || :w:==5

Fourth day of month:d: == 4

我希望有一个更好更灵活的解决方案或关于安全性的反馈(这可以注入恶意的 php 代码吗?

我会定义一组规则,如下所示:

$ordinals = array("First", "Second"...);
$days = array("Monday", "Tuesday"...);
$rules = array(
    array("%1 %2 of month", $ordinals, $days),
    array("%1 or %1", $days),
    etc
)

然后,执行 foreach(规则(并生成所有可能的允许字符串

$alloweds = array();
foreach($rules as $rule){
    $str = $rule[0];
    for($i = 1; $i < sizeof($rule); $i++){
        for($a = 0; $a < sizeof($rule[$i]); $a++){
            $alloweds[] = str_replace($str, "%$i", $rule[$i][$a]);
        }
    }
}

然后做一个foreach(允许的字符串(与我们所拥有的进行比较

foreach($alloweds as $allowed){
    if(preg_match($allowed, $input){
        //its valid
    }
}

您可以将规则设置为非常复杂 - 但是值得注意的是,它们越复杂,花费的时间就越长 - 以目前的形式,它显然是一种指数时间算法,但它是一个起点。

不是最通用的解决方案,但这实际上正是您想要做的:

类:

<?php
class validate {
    private static $month;
    private static $year;
    private static $day;
    private static $day_literal;
    function __construct() {
        self::$year = date("Y");
        self::$month = date("m");
        self::$day = date("d");
        self::$day_literal = date("l");
    }
    public function firstInMonth($required,$day,$month,$year) {
        $firstday;
        for ($i = 1; $i < 31; $i++) {
            if (checkdate($month,$i,$year)) {
                if (trim(strtolower(date("l",mktime(0,0,0,$month,$i,$year)))) == trim(strtolower(trim($required)))) {
                    $firstday = $i;
                    break;
                }
                else {
                    continue;
                }
            }
        }
        if (strtotime(date("Y-m-d",mktime(0,0,0,$month,$i,$year))) == strtotime(date("Y-m-d",mktime(0,0,0,$month,$day,$year)))) {
            return "{$year}/{$month}/{$day} is the first {$required} of the month.";
        }
        else {
            return "Nope.";
        }
    }
    public function checkDayLiteral($literal,$day,$month,$year) {
        if (trim(strtolower(date("l",mktime(0,0,0,$month,$day,$year)))) == trim(strtolower($literal))) {
            return true;
        }
        else {
            return false;
        }
    }
    public function dayPosition($day,$month,$year) {
        return date("jS",mktime(0,0,0,$month,$day,$year));
    }
}
?>

我不知道你检查的目的是什么,所以我还实现了构造方法来编译代码中未使用的"今天"值。如果您需要它们,请随时使用 self::

如何使用:

<?php
$validate = new validate;
echo $validate->firstInMonth("Monday",2,9,2013);
echo "<br />";
echo $validate->checkDayLiteral("Monday",2,9,2013);
echo "<br />";
echo $validate->dayPosition(2,9,2013);
?>

根据您需要获得的内容更改类(我的意思是:编辑我设置的回报(。

在这种情况下,上面的代码返回:

2013/9/2 是每月的第一个星期一。

1

第二

而这:

echo $validate->firstInMonth("Tuesday",2,9,2013);
echo "<br />";
echo $validate->checkDayLiteral("Wednesday",15,9,2013);
echo "<br />";
echo $validate->dayPosition(24,9,2013);

返回以下内容:

不。

24日

当然,这并不像您想要的那样通用,但这有效。

希望这有帮助。

如果它没有完全按照您想要的方式进行,对不起,请将其视为一个想法,我认为很清楚如何从此代码中获取所需的任何信息。