我正在寻找一种验证日期的通用方法。
我想要的是实现验证规则的某种方法,例如:
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日
当然,这并不像您想要的那样通用,但这有效。
希望这有帮助。
如果它没有完全按照您想要的方式进行,对不起,请将其视为一个想法,我认为很清楚如何从此代码中获取所需的任何信息。