多种格式的日期验证?

时间:2013-09-26 08:59:34

标签: php date

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

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

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代码注入吗?)

2 个答案:

答案 0 :(得分:0)

我会定义一组规则,如:

$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
    }
}

你可以把你的规则设置得相当复杂 - 但值得注意的是,它们越复杂就会越长 - 它的当前形式显然是一个指数时间算法,但它是一个起点。

答案 1 :(得分:0)

不是最通用的解决方案,但这实际上确实完全符合您的要求:

类别:

<?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日

当然,这并不像你想要的那样多才多艺,但这很有效。

希望这有帮助。

如果它不能完全按照您的意愿行事,我很抱歉,只需将其作为一个想法,我认为很清楚如何从这段代码中获得您想要的任何信息。

相关问题