我正在寻找一种验证日期的通用方法。
我想要的是实现验证规则的一些方法,例如:
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代码注入吗?)
答案 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日
当然,这并不像你想要的那样多才多艺,但这很有效。
希望这有帮助。
如果它不能完全按照您的意愿行事,我很抱歉,只需将其作为一个想法,我认为很清楚如何从这段代码中获得您想要的任何信息。