views:

178

answers:

6

How do I make the expression which checks the birthday input to match a format like this dd/mm/yyyy? Below is what I came out so far, but it takes this too if I put 99/99/9999!

if (!preg_match("/[0-9]{2}\/[0-9]{2}\/[0-9]{4}/", $cnt_birthday))
  {
   $error = true;
   echo '<error elementid="cnt_birthday" message="BIRTHDAY - Only this birthday format - dd/mm/yyyy - is accepted."/>';
  }

How can I make sure that its only 01 to 31 for dd and 01 to 12 for mm? but I am sure how to restrict yyyy... I think theoritical 9999 should be acceptable... let me know if you have a better idea!

thanks, Lau

+6  A: 

I would suggest using checkdate() for this instead:

if (preg_match("/([0-9]{2})\/([0-9]{2})\/([0-9]{4})/", $cnt_birthday, $matches)) {
    if (!checkdate($matches[2], $matches[1], $matches[3])) {
        $error = true;
        echo '<error elementid="cnt_birthday" message="BIRTHDAY - Please enter a valid date in the format - dd/mm/yyyy"/>';
    }
} else {
    $error = true;
    echo '<error elementid="cnt_birthday" message="BIRTHDAY - Only this birthday format - dd/mm/yyyy - is accepted."/>';
}

So regexp validates the format, checkdate validates the actual date.

Tim Fountain
Preg_match are not used for that, a 20lines pattern could do the job, but it would be complex as it would require to "hard code" the number of days of each month, and check if there is a February 29th, checkdate do exactly what you want, you should use it.
Dominique
thanks so much for this!
lauthiamkok
+4  A: 

Based on Tim's checkdate based solution:

The extraction of day, month and year can easily be done using explode as:

list($dd,$mm,$yyyy) = explode('/',$cnt_birthday);
if (!checkdate($mm,$dd,$yyyy)) {
        $error = true;
codaddict
$yyy should be $yyyy in list($dd,$mm,$yyy). (and the if block is missing a closing bracket.)
catgofire
thank u very much for this!
lauthiamkok
A: 

To be really anal-retentive it might be easier to use your current regex, parse the numbers, then verify they're in range with checkdate(), but for kicks, here's the regex that ensures dates = 01-31 (and 1-9), and month = 01-12 (and 1-9).

preg_match("/([012]?[1-9]|[12]0|3[01])\/(0?[1-9]|1[012])\/([0-9]{4})/", $date_string)

Couple things of note

  • I've used grouping on all, required for the ORing (|) within, but also useful to extract those values if you want to do specific things with them
  • 0000 doesn't make much sense as a date, but I've left the explosion of that regex as an excersise to the reader. If you really want this to verify birthdates (and you're expecting currently or relatively recently deceased people) restrict that to say 1900+ or 1800+, or whatever is an acceptable range for you. If you might be parsing historical figures' birthdays... your call.
  • This still doesn't check that the date range is correct for the month in question! so for that use checkdate()
Chadwick
A fine example why not to use a regex. For even leap year (sort of) awareness: http://regexadvice.com/blogs/mash/archive/2004/04/02/300.aspx
Wrikken
thank u very much!
lauthiamkok
A: 

Only accepting a strictly formatted string is probably a bad practice. Assuming you're getting input from a webpage, it would be better to have separate fields for month, day, and year. They could just be text boxes, but it might be preferable to have drop-down menus, which would solve your limits problem (i.e. the only choices for month are 1,2,...,12). Requiring that users enter 01/01/2001 and not accepting 1/1/2001 is lazy programming. And only accepting "/" as a separator is awkward.

But, to touch on your original question even if you decide to stick with formatted strings — since it's a birthdate field, you should probably restrict the yyyy to:

if($yyyy > date('Y')) {
  echo '<error elementid="cnt_birthday" message="BIRTHDAY - Year must be less than or equal to the current year."/>';
}

Otherwise people could have negative ages :)

catgofire
+1  A: 

Consider using strtotime() and reformat it with date(). It will provide more flexibility for users while entering a date and let's you use whatever formats you need in different places.

Personally, I am pretty lazy when it comes to accurate date calculation and abuse it like strtotime("-10 day",$timestamp). This has the benefit of lower possibility of getting sued by an annoyed parent becuse you calculated their little daughters age to be just above 18, not accounting for leap years correctly, and let her to your adult themed site, however ridiculous it may sound.

artificialidiot
+1 for flexible input. Users are notoriously lazy, if not also less intelligent. Making them have to stop to think can be hazardous to your health.
Kevin
A: 
$ok  = DateTime::createFromFormat('d/m/Y',$datestring)->format('d/m/Y') == $datestring;

PHP >= 5.3

Wrikken