strtotime date validation passes on invalid date - php

I am in the middle of setting up a basic CMS that allows the client to add articles to their mobile app. The CMS is coded in PHP and will use JSON to deliver the content to the mobile app.
Now my problem is there is an option to publish the article at a certain date, so I want to validate the date to check it is valid.
So to test possibilites I made a small script. I am using strtotime() to check the date is valid, my script is:
<?php
$date[] = '2011-31-01';
$date[] = '2011-02-31';
foreach($date as $str) {
if(strtotime($str) == false) {
$result[] = '<p>[' . $str . '] Resulted in an <span style="color: red;">Error.</span></p>';
} else {
$result[] = '<p>[' . $str . '] Resulted in <span style="color: green;">Success.</span></p>';
}
}
foreach($result as $return) {
echo $return;
}
?>
Now my problem is the date 2011-02-31 which is 31st February 2011 is returning as valid, when obviously it isn't. So my question is why does it do this? and is there a better method to check that the date is valid and exists?
Thanks in advance.

checkdate(); Validates a Gregorian date. Returns TRUE if the date given is valid; otherwise returns FALSE.
if(checkdate(2, 31, 2011)){
echo "Yeah";
} else {echo "nah";}
It returns false!
That's the way to go.

Unless you have one (or a small set) fixed format for your date string it will be hard to get an acceptable result. In case you know the format, you can either parse the string directly yourself (and test it afterwards with checkdate), or you use strptime to try parsing against known formats until you get a valid result.
If you don’t know the format, and you have to use strtotime, then you are required to accept that strtotime will try parsing the date string in the best possible way. This may lead to different dates than it was expected to be.

Related

Unable to get date/time from XML - Strange value in source

I'm just starting with php, but this is a thing I can't figure out.
I browsed the internet / stack / other forums, but for now I don't have any clue.
The date format is something I can't understand / recognize at all:
<datum>1491976626</datum>
<datum>1491894573</datum>
<datum>1491734853</datum>
<datum>1491680837</datum>
<datum>1491671357</datum>
Here's the link to the XML: Link
When you check the 'datum' node, you'll see it.
As an example (compared to the output on this site)
Value: 1491734853
= Date: 09-04-2017
Value: 1491671357
= Date: 08-04-2017
Value: 1491463926
= Date: 06-04-2017
Anyone of you guys / guru's have an idea how to get this working? Is there a default (sort of) algoritm for this or something I don't know of?
Thank you very much for thinking with me :)
I think this should do the job, but I'm unable to get it to show..
This is the PHP code I have so far:
<?php
foreach ($xml->beoordelingen->beoordeling as $beoordelingenoverzicht) {
echo "<div class='containerbeoordeling'><div class='hoofd'>";
foreach($beoordelingenoverzicht->voornaam as $label => $voornaam) {
echo "<div class='naam'><span id='label'>Naam</span><span id='voornaam'>{$voornaam}</span>"; }
foreach($beoordelingenoverzicht->achternaam as $label => $achternaam) {
echo "<span id='achternaam'> {$achternaam}</span></div>";
}
foreach($beoordelingenoverzicht->datum as $label => $datum) {
$datumnew = date('Y-m-d h:i:s',$datum);
echo "<div class='datum'><span id='label'>{$label}</span><span id='datum'>{$datumnew}</span></div></div>";
}
foreach($beoordelingenoverzicht->beschrijving as $label => $beschrijving) {
echo "<div class='beschrijving'>{$beschrijving}</div>";
}
echo "</div>";
}
?>
I wouldn't be surprised if I implemented it totally wrong :D
It suppose it's just a Unix timestamp, one of the most ubiquitous date formats in computer science. Many PHP date functions support it natively, e.g. date():
var_dump(date('r', 1491734853));
// string(31) "Sun, 09 Apr 2017 12:47:33 +0200"
The optional timestamp parameter is an integer Unix timestamp that
defaults to the current local time if a timestamp is not given. In
other words, it defaults to the value of time().

Compare date to today does not work

I want to display a text if the date in the database matches today's date.
$userdate = date("m/d/Y", strtotime($rr['last_login']));
$today = date("m/d/Y");
if ($userdate==$today){
echo "<test>";
}
Even if it is today's date, the records never echo out the string.
Interestingly, if I change it to
if ($userdate!=$today){
it also does not display the <test>.
My bad! I was not trying to echo out any html thing. The < brackets were just random characters. I changed it to "test" and now it works. Sorry for the < > characters causing confusion!
Since this is PHP, one would assume you're looking at the result in a browser, which will interpret the "<test>" as an HTML tag, and thus it will ignore it. Try changing the "echo" to simply echo "test<br>";
Also, if you are always dealing with a database, you could also use this:
if (substr($rr['last_login'], 0, 10) == date('Y-m-d'))
echo "test<br />\n";

Replacing characters only a set amount of time

I've been googling a bit, but I can't figure out what keywords to use.
I'm saving the users date of birth, and I want to make sure the format is YYYY-MM-DD.
I'm thinking something like:
if(!ctype_digit(str_replace("-", "", $dob)) || strlen(str_replace("-", "", $dob)) != 8)
{
echo "Incorrect format: date of birth";
}
For this, I need to use strlen() to only replace three - chars. If it's more or less than 3, then echo incorrect format. How do I achieve this? Or is there a better way?
How about using regex?
if ( !preg_match( "/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/", $dob) )
{
echo "Invalid date.";
}
To find many examples, search for "validating dates" or, in your case, to find php examples, try "php validate date format" -- you'll see most examples are solved with regular expressions, which is your ticket this this sort of thing. Reg Expressions can help you validate dates, email address formats, inputs for passwords that meet minimal requirements (e.g. at least 8 characters, at least one numeric and one capital letter, etc.)
Here's one such example:
if(preg_match('/\d{4}-\d{2}-\d{2}/',$date)){
// good date
}else{
// bad date
}
You should also check that the date is an actual date; not just that it looks like an actual date.
if (!preg_match("/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/D", $dob))
{
echo 'Invalid date';
}
else
{
list($year, $month, $day) = explode('-', $dob);
if (!checkdate((int) $month, (int) $day, (int) $year))
{
echo 'Invalid date';
}
}
You don't want to accept 1988-06-31 after all.

PHP verify correct time format in $value

I have an online form that has a few fields with time data. I store this data into the MySQL data base into a time field, which needs a format hh:mm:ss. If the user inputs the time in this format correctly, then i want to accept the data. I also want to allow users to input the time in standard US time, like 9:30 am or 11:25 pm or 10:27 am etc.
Basically I want to test if the time is in the proper database format first (hh:mm:ss), then if it is not, test if it is in the second accepted format (hh:mm am/pm), and if it is, then I will use the PHP function strtotime() to convert it into the database time format. If it is in neither of these formats, then we display an error message and die.
Does anyone know how to test if the value of a variable matches one of these time formats?
Pseudo PHP code of what I want to do:
<?php
$value = //some time;
if (is_database_time($value)){
// good no problem
}else if (is_usa_time($value)){
$value = strtotime($value);
}else{
die("error incorrect time format, try again.");
}
?>
** EDIT **
Thanks everyone for the help. I used some of the info here to make a function that works perfectly:
<?php
function filter_time($key,$value){
// this section handles the storage of time data
if (preg_match('/^(0?\d|1\d|2[0-3]):[0-5]\d:[0-5]\d$/', $value)){
//do nothing
}else if (preg_match('/^(0?\d|1[0-2]):[0-5]\d\s(am|pm)$/i', $value)){
$value = date( 'H:i:s', strtotime($value));
}else{
display_error('incorrect time format in '.$key.' field.');
}
return $value;
}
?>
function verify_time_format()
function verify_time_format ($value) {
$pattern1 = '/^(0?\d|1\d|2[0-3]):[0-5]\d:[0-5]\d$/';
$pattern2 = '/^(0?\d|1[0-2]):[0-5]\d\s(am|pm)$/i';
return preg_match ($pattern1, $value) || preg_match ($pattern2, $value);
}
Returns TRUE for following values:
2:03:32
02:03:32
23:59:59
15:23 AM
15:23 am
09:41 pm
9:41 PM
etc...
Update:
function filter_time ($key, $value) {
$p1 = '/^(0?\d|1\d|2[0-3]):[0-5]\d:[0-5]\d$/';
$p2 = '/^(0?\d|1[0-2]):[0-5]\d\s(am|pm)$/i';
if (preg_match ($p1, $value) || preg_match ($p2, $value))
$res = date ('H:i:s', strtotime ($value));
else
display_error ("incorrect time format in {$key} field.");
return $res;
}
You're already using the strtotime from PHP, and for the values you specified there really is no need to force a specific format.
What you would likely want to test for and ensure, is that the field validates with only digits, the colon, and am or pm as in Wh1T3h4Ck5 answer.
With that in place, your code would likely be similar to the following
<?php
function valid_time($value) {//Wh1T3h4Ck5's function
return preg_match('/^(0?\d|1[0-2]):[0-5]\d\s(am|pm)$/i', $value);
}
$value = //some time;
if (vald_time($value)){
$time_value = strtotime($value);
echo $time_value;
}else{
die("Error incorrect time format, try again.");
}
?>
Though a more elegant solution would to look into using Jquery/Javascript PRIOR to the form being submitted. You can test and warn the user of improper format before submitting to the PHP script. Leave the validation in the PHP script though as well, with other safeguards if needed.
You can use a regular expression to solve the problem pretty easily. For example:
<?php
$databaseTimePattern = '/^(0[0-9])|(1[0-2]):[0-5][0-9]:[0-5][0-9]$/'; //Matches times in the form hh:mm:ss
$usaTimePattern = '/^([1-9]|(1[0-2])):[0-5][0-9] [a|p]m$/'; //Matches times in the form hh:mm am/pm
$value = //some time;
if (preg_match($databaseTimePattern, $value)){
// good no problem
}else if (preg_match($usaTimePattern, $value)){
$value = strtotime($value);
}else{
die("error incorrect time format, try again.");
}
?>

preg_match for mysql date format

im trying to validate a date to see if it matchs the mysql format
this is the code
$match = "/^\d{4}-\d{2}-\d{2} [0-2][0-3]:[0-5][0-9]:[0-5][0-9]$/";
$s = $this->input->post("report_start"). " " . $this->input->post("report_start_time").":00";
$e = $this->input->post("report_end"). " " . $this->input->post("report_end_time").":59";
if($this->input->post("action") != "")
{
echo trim($s). " => " . preg_match($match, trim($s));
echo "<br>";
echo trim($e). " => " . preg_match($match, trim($e));
}
the date format goes into $s and $e are
$s = 2011-03-01 00:00:00
$e = 2011-03-01 23:59:59
and they both return false (0).
i tested the pattern on http://www.spaweditor.com/scripts/regex/index.php and it returns true (1)
http://pastebin.com/pFZSKYpj
however if i manual inter the date strings into preg_match like
preg_match($match, "2011-03-01 00:00:00")
it works.
i have no idea what im doing wrong
======================
now that i think about it, i only need to validate the houre:min part of the datetime string.
im manually adding the seconds and the date is forced by a datepicker and users cant edit it
You're making your work harder that it needs to be. In php there are many date handling functions that mean you don't have to treat dates like strings. So, rather than test that your input dates are in the correct format, just insist on the correct format:
$adate= date_create('January 6, 1983 1:30pm'); //date format that you don't want
$mysqldate= $adate->format("Y-m-d h:i:s");//date format that you do want
There are also functions to check that a date is a real date, like checkdate.
ok heres wat i did.
since im forcing the date format and the ending seconds of the time part
i just validated the hour:mini part using "/^2[0-3]|[01][0-9]:[0-5][0-9]$";
and if that returns true i put everything together end reconstructed the final datetime string
$match = "/^2[0-3]|[01][0-9]:[0-5][0-9]$/";
$s_d = $this->input->post("report_start");
$s_t = $this->input->post("report_start_time");
$e_d = $this->input->post("report_end");
$e_t = $this->input->post("report_end_time");
if($this->input->post("action") != "")
{
if(
( preg_match($match , trim($s_d." ".$s_t.":00")) )
&& ( preg_match($match , trim($e_d." ".$e_t.":59")) )
)
{
$r = $this->model_report->client_hours_logged(array($s,$e));
$data['report'] = $r;
var_dump($r);
//$this->load->view("report/client_hours_per_client",$data);
}
}
Watch out:
[0-2][0-3] is not a good regex for hour values - it will match 01, 12, 23 and others, but it will fail 04 through 09 and 14 through 19.
Better use (2[0-3]|[01][0-9]) instead.
I use this to validate a 'Y-m-d H:i:s' format date string:
match = '/^[12][0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[01]) ([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$/';
You could use strtotime and date to parse and format the date properly.
Why not just simply force the date into the format you want:
$e = '2011-03-01 00:00:00';
$mysqlFormat = date('Y-m-d H:i:s', strtotime($e));
Also, there is a bit of an error in your regex [0-2][0-3]:[0-5][0-9]:[0-5][0-9] will only match the hours of 00,01,02,03,10,11,12,13,20,21,22,23 so it will never match 4am, or 3pm among others. That aside I looked over your RegEx and I don't see any problems with it matching the test cases you've offered. I would check to make sure there is not extra whitespace on either side of date string with trim().
I concur with Tim : MySQL behaves in quirks mode and always tries to go easy on DATE and DATE_TIME column types. You can omit certain parts of your input and it still will try to compensate and achieve that goal successfully to some degree... That's why, most numbers your Reg-ex considers as invalid, MySQL will accept as valid.

Categories