Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement date validation function #4246

Draft
wants to merge 9 commits into
base: feature
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 1 addition & 19 deletions admin/modules/user/users.php
Original file line number Diff line number Diff line change
Expand Up @@ -482,20 +482,7 @@
{
$mybb->input['away_year'] = my_date('Y', $awaydate);
}

$return_month = (int)substr($mybb->input['away_month'], 0, 2);
$return_day = (int)substr($mybb->input['away_day'], 0, 2);
$return_year = min($mybb->get_input('away_year', MyBB::INPUT_INT), 9999);

// Check if return date is after the away date.
$returntimestamp = gmmktime(0, 0, 0, $return_month, $return_day, $return_year);
$awaytimestamp = gmmktime(0, 0, 0, my_date('n', $awaydate), my_date('j', $awaydate), my_date('Y', $awaydate));
if($return_year < my_date('Y', $awaydate) || ($returntimestamp < $awaytimestamp && $return_year == my_date('Y', $awaydate)))
{
$away_in_past = true;
}

$returndate = "{$return_day}-{$return_month}-{$return_year}";
$returndate = implode('-', array($mybb->get_input('away_day', MyBB::INPUT_INT), $mybb->get_input('away_month', MyBB::INPUT_INT), $mybb->get_input('away_year', MyBB::INPUT_INT)));
}

// Set up user handler.
Expand Down Expand Up @@ -819,11 +806,6 @@
$errors[] = $lang->suspendmoderate_error;
}

if(isset($away_in_past))
{
$errors[] = $lang->error_acp_return_date_past;
}

if(!$errors)
{
$user_info = $userhandler->update_user();
Expand Down
66 changes: 9 additions & 57 deletions inc/datahandlers/user.php
Original file line number Diff line number Diff line change
Expand Up @@ -352,43 +352,10 @@ function verify_birthday()
return true;
}

// Sanitize any input we have
$birthday['day'] = (int)$birthday['day'];
$birthday['month'] = (int)$birthday['month'];
$birthday['year'] = (int)$birthday['year'];

// Error if a day and month exists, and the birthday day and range is not in range
if($birthday['day'] != 0 || $birthday['month'] != 0)
$validate_birthday = validate_date(array_values($birthday), array(0, TIME_NOW), true);
if($validate_birthday !== true)
{
if($birthday['day'] < 1 || $birthday['day'] > 31 || $birthday['month'] < 1 || $birthday['month'] > 12 || ($birthday['month'] == 2 && $birthday['day'] > 29))
{
$this->set_error("invalid_birthday");
return false;
}
}

// Check if the day actually exists.
$months = get_bdays($birthday['year']);
if($birthday['month'] != 0 && $birthday['day'] > $months[$birthday['month']-1])
{
$this->set_error("invalid_birthday");
return false;
}

// Error if a year exists and the year is out of range
if($birthday['year'] != 0 && ($birthday['year'] < (date("Y")-100)) || $birthday['year'] > date("Y"))
{
$this->set_error("invalid_birthday");
return false;
}
elseif($birthday['year'] == date("Y"))
{
// Error if birth date is in future
if($birthday['month'] > date("m") || ($birthday['month'] == date("m") && $birthday['day'] > date("d")))
{
$this->set_error("invalid_birthday");
return false;
}
$this->set_error("invalid_birthday" . $validate_birthday);
}

// Error if COPPA is on, and the user hasn't verified their age / under 13
Expand All @@ -404,21 +371,8 @@ function verify_birthday()
}

// Make the user's birthday field
if($birthday['year'] != 0)
{
// If the year is specified, put together a d-m-y string
$user['bday'] = $birthday['day']."-".$birthday['month']."-".$birthday['year'];
}
elseif($birthday['day'] && $birthday['month'])
{
// If only a day and month are specified, put together a d-m string
$user['bday'] = $birthday['day']."-".$birthday['month']."-";
}
else
{
// No field is specified, so return an empty string for an unknown birthday
$user['bday'] = '';
}
$user['bday'] = implode('-', array_filter(array_values($birthday)));

return true;
}

Expand Down Expand Up @@ -851,15 +805,13 @@ function verify_away()
return false;
}

list($returnday, $returnmonth, $returnyear) = explode('-', $user['away']['returndate']);
if(!$returnday || !$returnmonth || !$returnyear)
// Validate the return date
$validate_awaydate = validate_date($user['away']['returndate'], array(TIME_NOW));
if($validate_awaydate !== true)
{
$this->set_error("missing_returndate");
$this->set_error("invalid_returndate" . $validate_awaydate);
return false;
}

// Validate the return date lengths
$user['away']['returndate'] = substr($returnday, 0, 2).'-'.substr($returnmonth, 0, 2).'-'.substr($returnyear, 0, 4);
}
return true;
}
Expand Down
67 changes: 67 additions & 0 deletions inc/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -5581,9 +5581,76 @@ function my_wordwrap($message)
return $message;
}

/**
* Checks the validity of a given date
*
* @param mixed $date the date to validate, may be a string or an array of date parts with d:m:Y sequence (supported delimiters are -, /, .)
* @param array $range the range of 2 timestamps the date has to be in. If single stamp is passed, will be considered only not before, to set only not after: pass 0 as first value
* @param bool $skipyear whether year is allowed to be skipped. If year is actually skipped range comparison will not take place
* @return mixed bool or error type string for range comparison. Confirm a validation comparing return value as true only.
*/
function validate_date($date, $range = array(), $skipyear = false)
{
if(is_string($date))
{
$date = preg_split('/[-\/\.]/', $date);
}

if((!isset($date[2]) || empty($date[2])) && $skipyear)
{
$date[2] = '2000'; // If the year is skipped append a leap year to validate
}
else
{
$skipyear = false; // Year provided, reset
}

if (count($date) !== 3 || !is_numeric($date[0]) || !is_numeric($date[1]) || !is_numeric($date[2]))
{
return false;
}

$date[0] = str_pad($date[0], 2, '0', STR_PAD_LEFT);
$date[1] = str_pad($date[1], 2, '0', STR_PAD_LEFT);

if(array(2,2,4) !== array_map('my_strlen', $date)) // Check length of date input
{
return false;
}

// Time to validate the actual date now, let's use PHP's Gregorian date validation : m-d-Y
if(!checkdate($date[1], $date[0], $date[2]))
{
return false;
}

// If we have a range and year is not skipped, validate
if(!empty($range) && !$skipyear)
{
$stamp = strtotime(implode('-', $date)); // Year of 4 digit & - as separator forces the format to be d-m-Y
if(isset($range[0]) && !empty($range[0]) && is_numeric($range[0]) && (int)$range[0] == $range[0])
{
if((int)$range[0] > $stamp)
{
return 'before';
}
}
if(isset($range[1]) && !empty($range[1]) && is_numeric($range[1]) && (int)$range[1] == $range[1])
{
if((int)$range[1] < $stamp)
{
return 'after';
}
}
}

return true;
}

/**
* Workaround for date limitation in PHP to establish the day of a birthday (Provided by meme)
*
* @deprecated
* @param int $month The month of the birthday
* @param int $day The day of the birthday
* @param int $year The year of the bithday
Expand Down
6 changes: 4 additions & 2 deletions inc/languages/english/datahandler_user.lang.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,17 @@
$l['userdata_invalid_website'] = 'The website address you entered is invalid. Please enter a valid website address or leave the field empty.';
$l['userdata_invalid_icq_number'] = 'The ICQ number you entered is invalid. Please enter a valid ICQ number or leave the field empty.';
$l['userdata_invalid_birthday'] = 'The birthday you entered is invalid. Please enter a valid birthday or leave the field empty.';
$l['userdata_invalid_birthdayafter'] = 'Birthday can not be in future. Please enter a valid birthday or leave the field empty.';
$l['userdata_invalid_birthday_coppa'] = 'To verify your age, please enter the year you were born. You may hide your Age and Date of Birth in your profile options.';
$l['userdata_invalid_birthday_coppa2'] = 'You must be at least 13 years of age to be a member of this message board. Please contact an Administrator.';
$l['userdata_invalid_birthday_privacy'] = 'Please choose a valid birthday privacy option.';
$l['userdata_conflicted_birthday_privacy'] = 'You must specify your birth year if you choose to display age only as your birthday privacy.';
$l['userdata_invalid_referrer'] = 'The referrer you entered does not exist. Please enter an existing referrer or leave the field empty.';
$l['userdata_invalid_language'] = 'The language you selected does not exist. Please select an existing language.';
$l['userdata_invalid_style'] = 'The style you selected is invalid. Please select a valid style.';
$l['userdata_away_too_long'] = 'The Away Reason you specified is too long. A maximum of 200 characters is allowed for this field. Please remove {1} character(s) from this field.';
$l['userdata_missing_returndate'] = 'The Return Date you specified is missing one or more fields. Please make sure you have filled in the day, month, and year fields.';
$l['userdata_away_too_long'] = 'The specified away reason is too long. A maximum of 200 characters is allowed for this field. Please remove {1} character(s) from this field.';
$l['userdata_invalid_returndate'] = 'The specified return date is invalid or incomplete. Please enter a valid return date or leave the field empty.';
$l['userdata_invalid_returndatebefore'] = 'The return date can not be in past. Please enter a return date of future or leave the field empty.';
$l['userdata_missing_required_profile_field'] = 'You did not enter an option for the "{1}" field. Please fill in or select a value for this field.';
$l['userdata_bad_profile_field_value'] = 'You did not enter a valid value for the "{1}" field. Please enter a valid value before continuing.';
$l['userdata_bad_profile_field_values'] = 'You did not select a valid option for the "{1}" field. Please select a value from the presented choices.';
Expand Down
1 change: 0 additions & 1 deletion inc/languages/english/usercp.lang.php
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,6 @@
$l['error_noavatar'] = "You did not choose an avatar. Please go back and do so now. If you don't want an avatar, select the \"No avatar\" option.";
$l['error_avatartype'] = "Invalid file type. An uploaded avatar must be in GIF, JPEG, BMP or PNG format.";
$l['error_alreadyingroup'] = "The user specified is already a part of the user group.";
$l['error_usercp_return_date_past'] = "You cannot return in the past!";
$l['error_avatarresizefailed'] = "Your avatar was unable to be resized so that it is within the required dimensions.";
$l['error_avataruserresize'] = "You can also try checking the 'attempt to resize my avatar' check box and uploading the same image again.";
$l['avatar_auto_resize_note'] = "If your avatar is too large, it will automatically be resized.";
Expand Down
36 changes: 15 additions & 21 deletions modcp.php
Original file line number Diff line number Diff line change
Expand Up @@ -2541,20 +2541,7 @@
{
$mybb->input['awayyear'] = my_date('Y', $awaydate);
}

$return_month = (int)substr($mybb->get_input('awaymonth'), 0, 2);
$return_day = (int)substr($mybb->get_input('awayday'), 0, 2);
$return_year = min((int)$mybb->get_input('awayyear'), 9999);

// Check if return date is after the away date.
$returntimestamp = gmmktime(0, 0, 0, $return_month, $return_day, $return_year);
$awaytimestamp = gmmktime(0, 0, 0, my_date('n', $awaydate), my_date('j', $awaydate), my_date('Y', $awaydate));
if($return_year < my_date('Y', $awaydate) || ($returntimestamp < $awaytimestamp && $return_year == my_date('Y', $awaydate)))
{
error($lang->error_modcp_return_date_past);
}

$returndate = "{$return_day}-{$return_month}-{$return_year}";
$returndate = implode('-', array($mybb->get_input('awayday', MyBB::INPUT_INT), $mybb->get_input('awaymonth', MyBB::INPUT_INT), $mybb->get_input('awayyear', MyBB::INPUT_INT)));
}
else
{
Expand Down Expand Up @@ -2880,19 +2867,18 @@
$awaycheck = array('', '');
if($errors)
{
if($user['away'] == 1)
if($mybb->get_input('away', MyBB::INPUT_INT) == 1)
{
$awaycheck[1] = "checked=\"checked\"";
$returndate = array($mybb->get_input('awayday', MyBB::INPUT_INT), $mybb->get_input('awaymonth', MyBB::INPUT_INT), $mybb->get_input('awayyear', MyBB::INPUT_INT));
$user['awayreason'] = htmlspecialchars_uni($mybb->get_input('awayreason'));
}
else
{
$awaycheck[0] = "checked=\"checked\"";
$returndate = array(0, 0, "");
$user['awayreason'] = '';
}
$returndate = array();
$returndate[0] = $mybb->get_input('awayday');
$returndate[1] = $mybb->get_input('awaymonth');
$returndate[2] = $mybb->get_input('awayyear', MyBB::INPUT_INT);
$user['awayreason'] = htmlspecialchars_uni($mybb->get_input('awayreason'));
}
else
{
Expand All @@ -2909,6 +2895,14 @@
$awaycheck[0] = "checked=\"checked\"";
}
$returndate = explode("-", $user['returndate']);
if(!isset($returndate[1]))
{
$returndate[1] = 0;
}
if(!isset($returndate[2]))
{
$returndate[2] = '';
}
}
$returndatesel = $selected = '';
for($day = 1; $day <= 31; ++$day)
Expand All @@ -2921,7 +2915,7 @@
{
$selected = '';
}

eval("\$returndatesel .= \"".$templates->get("usercp_profile_day")."\";");
}

Expand Down
32 changes: 9 additions & 23 deletions usercp.php
Original file line number Diff line number Diff line change
Expand Up @@ -167,20 +167,7 @@
{
$mybb->input['awayyear'] = my_date('Y', $awaydate);
}

$return_month = (int)substr($mybb->get_input('awaymonth'), 0, 2);
$return_day = (int)substr($mybb->get_input('awayday'), 0, 2);
$return_year = min((int)$mybb->get_input('awayyear'), 9999);

// Check if return date is after the away date.
$returntimestamp = gmmktime(0, 0, 0, $return_month, $return_day, $return_year);
$awaytimestamp = gmmktime(0, 0, 0, my_date('n', $awaydate), my_date('j', $awaydate), my_date('Y', $awaydate));
if($return_year < my_date('Y', $awaydate) || ($returntimestamp < $awaytimestamp && $return_year == my_date('Y', $awaydate)))
{
error($lang->error_usercp_return_date_past);
}

$returndate = "{$return_day}-{$return_month}-{$return_year}";
$returndate = implode('-', array($mybb->get_input('awayday', MyBB::INPUT_INT), $mybb->get_input('awaymonth', MyBB::INPUT_INT), $mybb->get_input('awayyear', MyBB::INPUT_INT)));
}
else
{
Expand Down Expand Up @@ -325,7 +312,7 @@

$plugins->run_hooks("usercp_profile_start");

$bdaydaysel = '';
$bdaydaysel = $selected = '';
for($day = 1; $day <= 31; ++$day)
{
if($bday[0] == $day)
Expand Down Expand Up @@ -423,19 +410,18 @@
$awaycheck = array('', '');
if($errors)
{
if($user['away'] == 1)
if($mybb->get_input('away', MyBB::INPUT_INT) == 1)
{
$awaycheck[1] = "checked=\"checked\"";
$returndate = array($mybb->get_input('awayday', MyBB::INPUT_INT), $mybb->get_input('awaymonth', MyBB::INPUT_INT), $mybb->get_input('awayyear', MyBB::INPUT_INT));
$user['awayreason'] = htmlspecialchars_uni($mybb->get_input('awayreason'));
}
else
{
$awaycheck[0] = "checked=\"checked\"";
$returndate = array(0, 0, "");
$user['awayreason'] = '';
}
$returndate = array();
$returndate[0] = $mybb->get_input('awayday', MyBB::INPUT_INT);
$returndate[1] = $mybb->get_input('awaymonth', MyBB::INPUT_INT);
$returndate[2] = $mybb->get_input('awayyear', MyBB::INPUT_INT);
$user['awayreason'] = htmlspecialchars_uni($mybb->get_input('awayreason'));
}
else
{
Expand All @@ -462,7 +448,7 @@
}
}

$returndatesel = '';
$returndatesel = $selected = '';
for($day = 1; $day <= 31; ++$day)
{
if($returndate[0] == $day)
Expand All @@ -473,7 +459,7 @@
{
$selected = '';
}

eval("\$returndatesel .= \"".$templates->get("usercp_profile_day")."\";");
}

Expand Down