【问题标题】:Versatile format for date validations?日期验证的通用格式?
【发布时间】:2013-09-26 08:59:33
【问题描述】:

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

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

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 代码。使用它的人非常有限(

first monday of month:w:==1 &amp;&amp; :d: &lt;= 7

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

Fourth day of month : :d: == 4

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

【问题讨论】:

标签: php date


【解决方案1】:

我会定义一组规则,例如:

$ordinals = array("First", "Second"...);
$days = array("Monday", "Tuesday"...);

$rules = array(
    array("%1 %2 of month", $ordinals, $days),
    array("%1 or %1", $days),
    etc
)

然后,执行一个 foreach(rule) 并生成所有可能的允许字符串

$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(allowed string) 与我们所拥有的比较

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

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

【讨论】:

    【解决方案2】:

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

    类:

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

    当然,这并不像你想要的那样多才多艺,但这是可行的。

    希望这会有所帮助。

    如果它不完全符合您的要求,对不起,请将此作为一个想法,我认为您很清楚如何从该代码中获取您想要的任何信息。

    【讨论】:

      猜你喜欢
      • 2017-04-04
      • 1970-01-01
      • 2016-03-27
      • 1970-01-01
      • 1970-01-01
      • 2018-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多