How to check date format on input

Hi guys, I have a form that allows the user to enter a date:

<div id="addmovie_date">
<label for="date"><strong>Release Date (YYYY-MM-DD):</strong</Label><br/>
<input type="text" name="date"/><br/>

I am wondering how to check that the user has input the correct DATE format and (YYYY-MM-DD) and nothing else

closest thing I’ve used ot this is:

if(strlen($moviename) > 80) {
			header("Location: /movies/addmovie.php?user=' . $username . ");
			include 'error.php';
			$error = 'movie name must not exceed 80 characters.';
			exit();
}

my little error include thing there messes my page up, but anyway! hehe

I’m sure there’s something similar for me to use for the date?

There are many ways to check the date format, here’s a simple example using [fphp]checkdate[/fphp].


<?php
$date = '2011-12-25';

list($y, $m, $d) = explode('-', $date);

if(checkdate($m, $d, $y)){
  /*
   is valid
  */
}

1 Like

If I presume this date field is part of a filtering / search process to identify a short-list of films, and it is designed for use by the general public…

Then I would guess that the majority of searches will be typically “show me all films since 2005” which would require the user to a) read and follow your GUI (onscreen) instructions to enter exactly 2005-01-01 (and not 2005/1/1 etc).

If that is the case I would recommend you reduce the chance of error by having 2 or 3 input boxes. Year / Month and possibly Day (the need for Day might be debatable).

If your film years start in say: 1970 then generate a pick-list of years so:


$years = range(date('Y'), '1970');

var_dump($years);

// 2011
// to 
// 1970

That will get you the years you want and in the manner of good e-commerce sites when you come to enter the expiry date of you card you are not allowed to enter the wrong year or enter an out of range year, you have to pick a year.

Optionally - add a third argument to the range,(say 5) and you will have every 5 years instead of 40 items in your picklist.

Repeat with months (ask if you need help)

Repeat with days if you wish. (ditto idem)

Filter and then add the 2 or 3 fields back together on your server, and run it through checkdate() as Anthony has described.

Accepting free text for dates is fraught with problems - depending on just how much you value your users and their input.

If you are sure free text input for dates IS the way to go, for example power-users on an internal CMS or similar, then yes, there are other ways of going about the intelligent filtering/checking of text as dates.

What do you think of the general idea of making users pick dates instead of entering them though?

Thanks guys. The users on this forum are just beyond amazing. There is nowhere else like it.

The date is for the users Movie Wishlist.

The user page displays the users collection, with a wishlist section at the top. The date is simply to show the release date of the movie that they desire.

So far I just did the following

$date = html($_POST['date']);
list($y, $m, $d) = explode('-', $date);
if(!checkdate($m, $d, $y)) {
		header("Location: /moviesite/error.php");
		exit();
}

It works great. oh and edit: ‘html’ is my htmlspecialchars function.

I’m really not very good at this so I appreciate the help, just trying to slowly learn little things here and there. Anthony’s example actually made me understand a bit more what ‘explode’ does, so that’s good! :slight_smile:

I really like the idea of having 3 input boxes (year, month, day) for the date though, Cups… I will play with that and try to figure out how to implement it… I think I can work that out.

extra question, are you able to limit the amount someone can type into a particular text box with just html? so that the can type 2000 but not 20000 in the YEAR field for example

1 Like

You could use a for loop to make month, day and year drop downs so they can only select what is listed.

1 Like

Seeing as you said such nice things … and you may not got what I was getting at…



<h3>Pick a release year/month</h3>
<select name='year'>
<option value =''>Pick one</option>
<?php
$years = range( date('Y'), '1990');
foreach( $years as $y ){
echo"'<option value='$y'>$y</option>" . PHP_EOL ;
}
?>
</select>

<select name='month'>
<option value =''>Pick one</option>
<?php
$months = array('01'=>'Jan','02'=>'Feb','03'=>'Mar',// etc);
foreach( $months as $k=>$v ){
echo"'<option value='$k'>$v</option>" . PHP_EOL ;
}
?>
</select>

Then on the back end you can detect if month was selected (is month really necessary at all?) if it is not your sql can be


// say you filtered incoming value and assigned it to
// $year = 2005 ;

SELECT id, title 
FROM films 
WHERE YEAR(release_date) = $year ;

Otherwise if month is set you can simply do


// say you filtered incoming value and assigned it to
// $year = 2005 ;
// $month = '02' ; // NB this must remain a string!
$tgt = $year . '-' . $month ; // add together to make your target

SELECT id, title 
FROM films 
WHERE release_date LIKE '$tgt%'
// NB quote the LIKE string

1 Like
Off Topic:

Hi Cups.

I noticed you were having to predefine the $months array, can you think of a better way of building that array at runtime than my example below?


<?php
function months($format = 'M'){
	$months = array();
	foreach(range(1, 12) as $num){
		$months[sprintf('%02s', $num)] = date($format, mktime(0, 0, 0, $num));
	}
	return $months;
}

print_r(
	months()
);

/*
	Array
	(
			[01] => Jan
			[02] => Feb
			[03] => Mar
			[04] => Apr
			[05] => May
			[06] => Jun
			[07] => Jul
			[08] => Aug
			[09] => Sep
			[10] => Oct
			[11] => Nov
			[12] => Dec
	)
*/

Code clarity, speed, etc… ?

Anthony, I was merely pitching a solution aimed initially at the level of the OP (with the greatest respect to the OP) - but maybe you are right, give out top class solutions when you can.

To answer you question though, I think I have used something like your solution previously, probably using the DateTime class though - I think it may have been on here somewhere, but cannot find it atm.

Although sometimes you just have to shake your head and just make an array in a function or a method - is creating an array of months worth using any processing power?

Well I suppose “it depends…”, we could probably reuse your code to make a multi-language version …

flip, flop, flip, flop as ever eh?

Sorry if this have muddied the waters portem, it wasn’t my intention. :blush:

Off Topic:

Oh I know, I meant no disrespect.

I think I probably have a little bit too much spare time this Sunday morning, and seen a mini-challenge. :slight_smile:

As you say, I would just create something static for this normally as the data structure doesn’t change (exactly what you have done).

For what it’s worth, I personally consider your solutions/advice (including this one) top class anyway.

I don’t think it has muddied the waters at all, its merely another example of how many ways there are for portem to skin this particular cat - and its all good because you are raising fundamental issues of portability, re-usability and deal with basic principles such as DRY and so on.

They may not be fundamental to portem today, but we know that if he/she sticks with web development they will eventually be big issues.

Ideally portem (or anyone else reading this thread) will spot that the months of the year is something rather static, and if it can be used in several places throughout his web site, and maybe other websites he/she maintains then it is worth keeping it in a central place and including it on demand.

Then the argument of this particular data structure could open out into “but hang on, what if I don’t want the output to be array(“01” => “January”, etc) but array(“1” => “Jan”, etc) in another form I am making?”.

You can try using the simple html maxlength attribute:

<input type=“text” name=“year” maxlength=“4”>

Or you could use JS or jQuery’s mask to enforce it on the client.

But essentially, despite these usability tricks, you have to be aware that some users can bypass these and it remains incumbent upon you to check back on the server that what you get back is filtered and checked against what you expect to get, that is 4 digits only, with a min of say 1900 and a max of 2011.


if( (int)$_POST['year'] < 1900 || (int)$_POST['year'] > date('Y') ){
// this user has sent you duff info, either by accident
// or on purpose, so abort this operation?
}

To eliminate the possibility of the user submitting a bad year by accident you give them a pick-list of years, see**?

Some users may confuse the digit 0 with the letter O when they submit 2OOO - which may be acceptable to you or not.

Some users may just submit 99 expecting that your application will be smart enough to deduce that they meant 1999 - and again this may be acceptable to you or not - and you actually can “recover and forgive” from both of these errors if you wanted to.

**Watch out: Even with a pick-list of years, bad users can still send you duff or malicious info - so you STILL have to do some kind of backend check to protect yourself - and the same goes for everything coming from your form.

Wow thanks for the help… amazing… I will try to learn all of this over the next week or two… gonna take some re-reading/trying things out. :slight_smile:

so far I have decided to go with the simple 3 text input box method and just limit with maxlength, just to get started. I am definitely going to implement the other examples you guys gave me, will just take me some learning. I truly appreciate this!

I have this:

$year = html($link, $_POST['year']);
$month = html($link, $_POST['month']);
$day = html($link, $_POST['day']);
$date = $year . '-' . $month . '-' . $day ;

but then $date always gets put in the DB as 0000-00-00 for some reason.

I did this:

$date = html($_POST['year'] . '-' . $_POST['month'] . '-' . $_POST['day']);

and it works, but is that code ‘right’? ‘html’ is my htmlspecialchars function and I’m not sure you can use it like that.

if that’s cool, now I need to re-work checkdate to work.