11

Users would select their date from 3 dropdowns (day, month, year). I will combine them on server-side to make a string like '2008-12-30'. How can I then validate to make sure this date was in the right format/numeric only, etc?

2
  • Can you reword this slightly; it's not entirely clear what you're after. Do you want to validate the date coming from the query, or do you want to validate the individual components before you insert them into the database? Commented Feb 28, 2009 at 3:41
  • I want to combine the components of the date and validate the combined date against the database. Commented Feb 28, 2009 at 3:48

6 Answers 6

22

I personally found this to be the correct and elegant way to determine if the date is both according to format and valid:

  • treats dates like 20111-03-21 as invalid - unlike checkdate()
  • no possible PHP warnings (if any one parameter is provided, naturally) - unlike most explode() solutions
  • takes leap years into account unlike regex-only solutions
  • fully compatible with the mysql DATE format (10.03.21 is the same as 2010-03-21)

Here's the method you can use:

function isValidMysqlDate( string $date ): bool
{
    return preg_match( '#^(?P<year>\d{2}|\d{4})([- /.])(?P<month>\d{1,2})\2(?P<day>\d{1,2})$#', $date, $matches )
           && checkdate($matches['month'],$matches['day'], $matches['year']);
}
Sign up to request clarification or add additional context in comments.

2 Comments

Technically correct but it does allow "01/02/03". Who knows what the user intended, but it's considered valid still.
@acoder that's 2001-02-03, what's the issue here?
6

I am using this function:

<?php 
function validateMysqlDate( $date ){ 
    if (preg_match("/^(\d{4})-(\d{2})-(\d{2}) ([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$/", $date, $matches)) { 
        if (checkdate($matches[2], $matches[3], $matches[1])) { 
            return true; 
        } 
    } 
    return false; 
} 

// check it: 
  $a = validateMysqlDate('2012-12-09 09:04:00');
  $b = validateMysqlDate('20122-12-09 09:04:00');
  $c = validateMysqlDate('2012-12_09 09:04:00');
  $d = validateMysqlDate('');
  var_dump( $a );
  var_dump( $b );
  var_dump( $c );
  var_dump( $d ); 
?>

$a is true, the others are false - and that is correct

The function from Raveren (above) will not cover valid dates with timestamps !!! $a returns false there! And btw: checkdate() would return true for $b although it is not a valid mysql datetime

1 Comment

This will incorrectly invalidate 10.03.21 00:00:00 and will not validate date strings without time at all - which the OP asked for.
5

If they are 3 separate drop-downs, you will need to validate them as three separate values.

Ie,

  • Validate that the year column is numeric and between whatever years are valid in your app
  • Validate that the month column is numeric
  • Validate that the day column is numeric
  • Validate that they are all valid values using checkdate()

Or, you could just cast them all to integer, combine them together into a date, and see if the resulting date is valid. Ie,

$time = mktime(0, 0, 0, (int)$_POST['month'], (int)$_POST['day'], (int)$_POST['year']);

// in this example, valid values are between jan 1 2000 (server time) and now
// modify as required
if ($time < mktime(0, 0, 0, 1, 1, 2000) || $time > time())
  return 'Invalid!';

$mysqltime = date('Y-m-d', $time);

// now insert $mysqltime into database

The downside to this method is that it'll only work with dates within the Unix timestamp range ie 1970 to 2038 or so.

2 Comments

You probably want to check if it is an integer, not if it is numeric. is_numeric is true for floats as well as integers, but is_int only checks for integers.
is_int() cannot work on user-submitted variables, ie variables in $_POST, because these are always of type string. You could, however, cast them to integer using (int)$_POST['var'] and then loosely compare that to the original string value (using ==).
2

You can check that the date is valid using checkdate. If you want to make sure that the values are numeric and the correct length, you could do something as simple as an is_int ctype_digit and a strlen combination before you build the date.

// untested
if( !ctype_digit)( $month ) || strlen( $month ) != 2 ) {
    // handle error
}
// repeat for $day and $year
if ( checkdate( $month, $day, $year ) {
    // do your work
}

1 Comment

I changed my answer from is_int to ctype_digit based on thomasrutter's comment that is_int won't handle POST variables correctly.
1

Just had the same issue. I wrote a short function that checks if the format is correct, and also if the date is real:

function valid_mysql_date($str){
    $date_parts = explode('-',$str);
    if (count($date_parts) != 3) return false;
    if ((strlen($date_parts[0]) != 4) || (!is_numeric($date_parts[0]))) return false;
    if ((strlen($date_parts[1]) != 2) || (!is_numeric($date_parts[1]))) return false;
    if ((strlen($date_parts[2]) != 2) || (!is_numeric($date_parts[2]))) return false;
    if (!checkdate( $date_parts[1], $date_parts[2] , $date_parts[0] )) return false;
    return true;
}

hope it helps.

3 Comments

funny, now I'm trying to understand what's wrong with me... :)
ok now I see what i meant, cuz I just ran into the same problem today. checkdate() ask for three parameters. so if you got a string of date, it doesn't helps you. my function gets a string and the formats it and check with checkdate()
Yeah, I had the same problem. I had a string, so checkdate() was of no use to me. This solution works perfectly for me though. Thanks.
-1

If you have three dropdowns then the values coming from the dropdowns should always be numbers since you control the values associated with the month (shown below). This would then lead to the conclusion that the combined result is valid.

<option value="01">January</option>

If you provide provide assistance entries in the drop downs such as "Select a Month" then you can make that value 0 and ensure that the values coming from each drop box is greater than zero.

There is the possibility that someone will alter the HTML form to provide other values. If this is a concern then you can use the PHP function ctype_digit() to check that each value provided is actually a numerical digit.

If your concern is that the date is actually valid the use the checkdate() function.

2 Comments

Its possible to make posts to a script without the use of forms. I can write a bot that makes a post to your form and posts whatever value i put in for each field without the use of forms.
That's true which is why the suggestion of using ctype_digit() and checkdate() make sense. I was basing my answer on the statement that you had a form. Even if you use a script, there aren't many cases in this instance in which it wouldn't use the values in the forms.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.