PHP

Validating dates

Dates of birth, expiry dates, order dates, and other dates are commonly entered by users. Most dates require checks to see if the date is valid and also if it's in a required range. In the customer <form>, the user is required to provide a date of birth. We validate this date of birth to check it has been entered, and to check its format, its validity, and whether it's within a range; the range of valid dates in the example begins with the user being alive-we assume alive users are born after 1890-and ends with the user being at least 18 years of age.

Date-of-birth checking is implemented with the following code fragment:

// Validate Date of Birth
if (empty($formVars["dob"]))
      // the user's date of birth cannot be a null string
      $errorString .= "You must supply a date of birth.";
  elseif (!ereg("^([0-9]{2})/([0-9]{2})/([0-9]{4})$",
          $formVars["dob"], $parts))
      // Check the format
      $errorString .=
        "The date of birth is not a valid date in the " .
        "format DD/MM/YYYY";
elseif (!checkdate($parts[2],$parts[1],$parts[3]))
      $errorString .= "The date of birth is invalid. " .
    "Please check that the month is between 1 and 12, " .
    "and the day is valid for that month.";
  elseif (intval($parts[3]) < 1890)
      // Make sure that the user has a reasonable birth year
      $errorString .=
         "You must be alive to use this service.";
  // Check whether the user is 18 years old.
  // If all the following are NOT true,
  // then report an error.
elseif
         // Were they born more than 19 years ago?
       (!((intval($parts[3]) < (intval(date("Y") - 19))) ||
         // No, so were they born exactly 18 years ago, and
         // has the month they were born in passed?
       (intval($parts[3]) == (intval(date("Y")) - 18) &&
       (intval($parts[2]) < intval(date("m")))) ||
         // No, so were they born exactly 18 years ago
         // in this month, and was the day today or earlier
         // in the month?
       (intval($parts[3]) == (intval(date("Y")) - 18) &&
       (intval($parts[2]) ==  intval(date("m"))) &&
       (intval($parts[1]) <= intval(date("d"))))))
       $errorString .=
        "You must be 18+ years of age to use this service.";

If any date test fails, an error string is appended to the $errorString, and no further checks of the date are made. A valid date passes all the tests.

The first check tests if a date has been entered. The second check uses a regular expression to check whether the date consists of numbers and if it matches the template DD/MM/YYYY:

(!ereg("^([0-9]{2})/([0-9]{2})/([0-9]{4})$",
$formVars["dob"], $parts))

Whatever the result of this check, the expression also explodes the date into the array $parts so that the component that matches the first grouped expression ([0-9{2}) is found in $parts[1], the second grouped expression in $parts[2], and the third grouped expression in $parts[3]. The ereg( ) function stores the string matching the complete expression in $parts[0]. The overall result of processing a date that matches the template is that the day of the month is accessible as $parts[1], the month as $parts[2], and the year as $parts[3].

The third check uses the exploded data stored in the array $parts and the function checkdate( ) to test if the date is a valid calendar date. For example, the date 31/02/1970 would fail this test.

The fourth check tests if the year is greater than 1890. The function intval( ) converts a string to an integer. A test such as if ($parts[3] < 1890) may not work as desired, because $parts[3] is a string-which can be unreliably converted to an integer, as discussed in Chapter 2-and 1890 is an integer. Both the PHP functions intval( )-to convert strings to integers for comparisons-and strval( )-to convert integers to strings-are useful tools in range-checking <form> fields.

The fifth and final check tests if the user is 18 years of age or older. There are many ways to do this, with perhaps the most obvious being finding the difference between the date of birth and the current date using library functions, and checking that this difference is more than 18 years. The strtotime( ) function converts a date string in the format MM/DD/YYYY to a large numeric Unix timestamp value that represents the number of seconds since January 1, 1970. This can be cast to a float to ensure reliable comparison as discussed in Chapter 2.

However, our approach here to validating if a user is over 18 years of age uses only logic, and the intval( ) and date( ) functions:

// Check whether the user is 18 years old.
// If all the following are NOT true,
  // then report an error.
  elseif
         // Were they born more than 19 years ago?
       (!((intval($parts[3]) < (intval(date("Y") - 19))) ||
         // No, so were they born exactly 18 years ago, and
         // has the month they were born in passed?
       (intval($parts[3]) == (intval(date("Y")) - 18) &&
       (intval($parts[2]) < intval(date("m")))) ||
         // No, so were they born exactly 18 years ago
         // in this month, and was the day today or earlier
         // in the month?
       (intval($parts[3]) == (intval(date("Y")) - 18) &&
       (intval($parts[2]) ==  intval(date("m"))) &&
       (intval($parts[1]) <= intval(date("d"))))))
       $errorString .=
        "You must be 18+ years of age to use this service.";

First, we check if the user's date of birth is 19 or more years ago; if this is the case, there is no error. Second, we check if the user was born exactly 18 years ago in a month earlier than the current month; if this is the case, again there is no error. Last, we check if the user was born exactly 18 years ago, in the current month, and on a day less than or equal to the current day; yet again, if this is true, there is no error. The parameters to the function date( ) are discussed in Chapter 2.

There are other approaches to checking differences between dates. For example, one approach is to use the MySQL functions described in Chapter 3 through an SQL query. The query need not use a database; that is, SQL can be used as a simple calculator. This approach is perhaps less desirable than the approach we have described, because there is no database activity involved in our example, and database activity adds unnecessary overhead. However, if one or more dates are extracted in the script from a database, MySQL date and time functions are a useful alternative.

by BrainBellupdated
Advertisement: