<?php
/**
* This class encapsulates various validation functionality.
*
* PHP developers should always validate data on the server side to prevent
* vulnerabilities and bugs. JavaScript alone is not adequate data validation
* because it can easily be bypassed or turned off altogether.
*
* Feb 20, 2007 - Initial Release
* Feb 28, 2007 - Vitaliy Bogdanets contributed regular expressions
* Mar 12, 2007 - Restructured/renamed class, made static, added functionality
* Mar 27, 2007 - Added GetBooleanValue method
* Jun 19, 2007 - Added functionality and bug fix for getBooleanValue
* Jun 29, 2007 - Changed checkMinimumLength to isTooShort and fixed help
* Aug 18, 2010 - Added getRequestValue, getCurrentPageURL, and getCurrentPageName methods
* Apr 04, 2018 - Added trim and minor code updates
* Apr 22, 2018 - Added various useful formatting and validation functions
* Apr 30, 2018 - Added credit card validation and other string/integer functions
* May 23, 2018 - Added compareValues and containsValues that use arrays
* May 28, 2018 - Added beginsWith, formatTitleCase, truncate, counts, plus fixes
* Feb 17, 2022 - Fixes and generateRandomString uses cryptographically secure random int
*
* @version 4.01
* @author Jeff L. Williams
*/
class Valid {
/**
* Determines if a string begins with another string
*
* @param string $string The subject of the search
* @param string $find The string to look for
* @param boolean $caseSensitive Case sensitive?
* @return boolean TRUE if yes and FALSE if not
*/
public static function beginsWith($string, $find, $caseSensitive = true) {
if (strlen($find) == 0) {
return true;
} else {
$substring = substr($string, 0, strlen($find));
if ($caseSensitive) {
return ($substring === $find);
} else {
return (strtoupper($substring) === strtoupper($find));
}
}
}
/**
* Converts the case of all keys in a multidimensional array to upper or lower
*
* @param array $array The array to modify
* @param integer $case [OPTIONAL] Use either CASE_UPPER or CASE_LOWER (default)
* @return array The array with keys changed
*/
public static function changeArrayKeyCaseRecursive($array, $case = CASE_LOWER) {
return array_map(function ($item) use ($case) {
if (is_array($item)) {
$item = self::changeArrayKeyCaseRecursive($item, $case);
}
return $item;
}, array_change_key_case($array, $case));
}
/**
* Returns a character at a given position
*
* @param string $string The subject of the search
* @param string $position The position of the character
* @return string The character at the specified position
*/
public static function charAt($string, $position) {
if ($position < 0 || strlen($string) <= $position) {
return '';
} else {
return $string[$position];
}
}
/**
* Checks to see if an IP address is in a range using wildcards.
* Use * or % for any value. Use ? for a single digit. Use #/# or #-# for ranges.
*
* @example $in_range = CheckIpRange('123.4.56.78', '1*.1/4.50-60.?8');
*
* @param string $ip The IP address to check
* @param string $range The range using wildcards (can also be a single address)
* @return boolean TRUE if a match, otherwise FALSE
*/
public static function checkIPRange($ip, $range) {
// Split the parts of the IP address into an array
$ip_parts = explode('.', $ip);
$range_parts = explode('.', $range);
// Loop through the 4 parts
for ($i = 0; $i < 4; $i++) {
// Convert each section of the IP into a number
$ip_part = intval($ip_parts[$i]);
// Is this a range using #/# or #-# or #:#?
if (strpos($range_parts[$i], '/') !== false ||
strpos($range_parts[$i], '-') !== false ||
strpos($range_parts[$i], ':') !== false) {
// We only want to deal with /
$range_parts[$i] = str_replace('-', '/',
str_replace(':', '/', $range_parts[$i]));
// Get the left and right side of the range
list($left, $right) = explode('/', $range_parts[$i], 2);
// If the number is out of range...
if ($ip_part < $left || $ip_part > $right) {
return false;
}
// Does this contain a wildcard like * or 1%
} elseif (strpos($range_parts[$i], '*') !== false ||
strpos($range_parts[$i], '%') !== false ||
strpos($range_parts[$i], '?') !== false) {
// Turn this into a regular expression
$regex = '/^' . str_replace(array('*', '%'),
array_fill(0, 2, '.+'), $range_parts[$i]) . '$/';
$regex = str_replace('?', '.', $regex);
if (!preg_match($regex, $ip_part)) {
return false;
}
// Just compare the number
} else {
// If the 2 sides don't match
if ("$ip_part" !== $range_parts[$i]) {
return false;
}
}
}
return true;
}
/**
* Checks the length of a value
*
* @param string $value The value to check
* @param integer $maxLength The maximum allowable length of the value
* @param integer $minLength [OPTIONAL] The minimum allowable length
* @return boolean TRUE if the requirements are met, FALSE if not
*/
public static function checkLength($value, $maxLength, $minLength = 0) {
if (!(strlen($value) > $maxLength) && !(strlen($value) < $minLength)) {
return true;
} else {
return false;
}
}
/**
* Checks to make sure a folder path ends in a slash and add only if needed
*
* @param string $value The value to check
* @return string Returns a path with a trailing slash
*/
public static function checkPathEndingSlash($path) {
$is_unix = (strpos($path, '\\') === 0) ? false : true;
$last_char = substr($path, strlen($path) - 1, 1);
if ($last_char != '/' && $last_char != '\\') {
$path .= ($is_unix) ? '/' : '\\';
}
return $path;
}
/**
* Compares two values for equality
*
* @param string $value1 First value to compare
* @param string $value2 Second value to compare
* @param boolean $caseSensitive [OPTIONAL] TRUE if compare is case sensitive
* @return boolean TRUE if the values are equal and FALSE if not
*/
public static function compare($value1, $value2, $caseSensitive = false) {
if ($caseSensitive) {
return ($value1 == $value2 ? true : false);
} else {
if (strtoupper($value1) == strtoupper($value2)) {
return true;
} else {
return false;
}
}
}
/**
* Determines if a string matches any item in a list of strings
*
* @example $match = compareValues('Blue', true, 'red', 'green', 'blue');
* @example $match = compareValues('blue', false, array('red', 'blue'));
*
* @param string $string The string to match
* @param boolean $ignoreCase TRUE if this is a case insensitive match
* @param array $find Either an array or list of one or more extra parameters
* @return boolean TRUE if found and FALSE if not
*/
public static function compareValues($string, $caseSensitive, $find) {
// If no find array was used then use a list of parameters...
if (!is_array($find)) {
// If there are enough parameters to search with...
if (func_num_args() > 2) {
// Create the new $find_array variable using a list of parameters
$find_array = func_get_args();
// Remove the first two parameters
array_shift($find_array);
array_shift($find_array);
} else { // Not enough parameters either
// Create an empty array
$find_array = array();
}
} else { // An array was specified to search with...
// Set the array to the one passed in
$find_array = $find;
}
if ($caseSensitive) {
// Do a case-sensitive search
return in_array($string, $find_array);
} else {
// Do a case-insensitive search
return in_array(strtolower($string), array_map('strtolower', $find_array));
}
}
/**
* Determines if a string contains another
*
* @param string $string The subject of the search
* @param string $find The string to look for
* @param boolean $caseSensitive Case sensitive?
* @return boolean TRUE if yes and FALSE if not
*/
public static function contains($string, $find, $caseSensitive = true) {
if (strlen($find) == 0) {
return true;
} else {
if ($caseSensitive) {
return (strpos($string, $find) !== false);
} else {
return (strpos(strtoupper($string), strtoupper($find)) !== false);
}
}
}
/**
* Determines if a list of partial matches can be found in a string
*
* @example $match = containsValues('RED', true, 'ed', 'ee', 'ue');
* @example $match = containsValues('blue', false, array('ed', 'ee', 'ue'));
*
* @param string $string The string to search
* @param boolean $ignoreCase TRUE if this is a case insensitive match
* @param array $find Either an array or list of one or more extra parameters
* @return boolean TRUE if found and FALSE if not
*/
public static function containsValues($string, $caseSensitive, $find) {
// If no find array was used then use a list of parameters...
if (!is_array($find)) {
// If there are enough parameters to search with...
if (func_num_args() > 2) {
// Create the new $find_array variable using a list of parameters
$find_array = func_get_args();
// Remove the first two parameters
array_shift($find_array);
array_shift($find_array);
} else { // Not enough parameters either
// Create an empty array
$find_array = array();
}
} else { // An array was specified to search with...
// Set the array to the one passed in
$find_array = $find;
}
// Set the default values
$return = false;
// Loop through the array
foreach ($find_array as $value) {
// Case sensitive search
if ($caseSensitive) {
if (strpos($string, $value) !== false) {
$return = true;
}
} else { // Case insensitive search
if (strpos(strtoupper($string), strtoupper($value)) !== false) {
$return = true;
}
}
}
// Return the outcome
return $return;
}
/**
* Count the number of characters in a string
*
* @param string $string The string to process
* @return integer Returns the count as a number
*/
public static function countCharacters($string) {
return strlen($string);
}
/**
* Count the number of paragraphs (line breaks) in a string
*
* @param string $string The string to process
* @return integer Returns the count as a number
*/
public static function countParagraphs($string) {
return preg_match_all('/([^\r\n]*[^ \r\n]+[^\r\n]*((\r|\n|\r\n)[^\r\n]*[^ \r\n]+[^\r\n]*)*)/m', $string);
}
/**
* Count the number of sentences in a string
*
* @param string $string The string to process
* @return integer Returns the count as a number
*/
public static function countSentences($string) {
return preg_match_all('/[^\s](\.|\!|\?)(?!\w)/', $string);
}
/**
* Count the number of words in a string
*
* @param string $string The string to process
* @return integer Returns the count as a number
*/
public static function countWords($string) {
return str_word_count($string);
}
/**
* HTML Encode a string value or array of values
* to stop any cross-site scripting attacks
* (STATIC method - use Template::encodeHTML)
*
* @param string/array $value The value(s) to encode
* @param string [OPTIONAL] $encoding The type of encoding
* @param string [OPTIONAL] $dateFormat Default date format for date values
* @return string/array HTML encoded value(s)
*/
public static function encodeHTML($value, $encoding = 'UTF-8', $dateFormat = 'm/d/Y') {
if (is_array($value)) {
$return = array();
foreach ($value as $key => $data) {
$return[$key] = self::encodeHTML($data, $encoding, $dateFormat);
}
} else {
if (is_string($value)) {
$return = htmlentities(trim($value),
ENT_QUOTES | ENT_HTML5, $encoding);
} elseif (is_bool($value)) {
$return = ($value) ? 'true' : 'false';
} elseif (is_numeric($value)) {
$return = htmlentities("$value",
ENT_QUOTES | ENT_HTML5, $encoding);
} elseif ($value instanceof DateTime) {
$return = htmlentities($value->format($dateFormat),
ENT_QUOTES | ENT_HTML5, $encoding);
} elseif (empty($value)) {
$return = '';
} else {
$return = $value;
}
}
return $return;
}
/**
* URL Encode a string value or array of values
* (STATIC method - use Template::encodeURL)
*
* @param string/array $value The value(s) to encode
* @param boolean [OPTIONAL] $raw TRUE for RFC 3986; FALSE use + for spaces
* @param string [OPTIONAL] $dateFormat Default date format for date values
* @return string/array HTML encoded value(s)
*/
public static function encodeURL($value, $raw = false, $dateFormat = 'Y-m-d') {
if (is_array($value)) {
$return = array();
foreach ($value as $key => $data) {
$return[$key] = self::encodeURL($data, $encoding, $dateFormat);
}
} else {
if (is_string($value)) {
if ($raw) {
$return = rawurlencode(trim($value));
} else {
$return = urlencode(trim($value));
}
} elseif (is_bool($value)) {
$return = ($value) ? 'yes' : 'no';
} elseif (is_numeric($value)) {
if ($raw) {
$return = rawurlencode($value);
} else {
$return = urlencode($value);
}
} elseif ($value instanceof DateTime) {
if ($raw) {
$return = rawurlencode($value->format($dateFormat));
} else {
$return = urlencode($value->format($dateFormat));
}
} elseif (empty($value)) {
return '';
} else {
$return = $value;
}
}
return $return;
}
/**
* Determines if a string ends with another string
*
* @param string $string The subject of the search
* @param string $find The string to look for
* @param boolean $caseSensitive Case sensitive?
* @return boolean TRUE if yes and FALSE if not
*/
public static function endsWith($string, $find, $caseSensitive = true) {
if (strlen($find) == 0) {
return true;
} else {
if ($caseSensitive) {
return (substr($string, -strlen($find)) === $find);
} else {
return (strtoupper(substr($string, -strlen($find)))
=== strtoupper($find));
}
}
}
/**
* Formats a phone number
*
* @param string $numbers An unformatted value
* @return string Returns the formatted value
*/
public static function formatPhoneNumber($numbers) {
$numbers = self::stripNonNumeric($numbers);
if (!$numbers) {
return $numbers;
} else {
$regex = '/^1?(?:[- .])?(\d{3})(?:[- .])?(\d{3})(?:[- .])?(\d{4})$/';
$format = '($1) $2-$3';
return preg_replace($regex, $format, $numbers);
}
}
/**
* Formats a social security number
*
* @param string $numbers An unformatted value
* @return string Returns the formatted value
*/
public static function formatSSN($numbers) {
$numbers = self::stripNonNumeric($numbers);
$ssn = '';
if (strlen($numbers) > 3) {
$ssn = substr($numbers, 0, 3) . '-' . substr($numbers, 3, 2);
} else {
$ssn = $numbers;
}
if (strlen($numbers) > 5) {
$ssn .= '-' . substr($numbers, 5, 4);
}
return $ssn;
}
/**
* Formats text to be proper title case like news article titles
*
* @param string $title The string to capitalize
* @return string The formatted string
*/
public static function formatTitleCase($title) {
// Our array of 'small words' which shouldn't be capitalized if
// they aren't the first word
$smallwordsarray = array(
'a','an','and','as','at','but','by','en','for','if','in','nor','of','on','or','per','the','to');
// Split the string into separate words
$words = explode(' ', $title);
foreach ($words as $key => $word) {
// If this word is the first and not one of our small words, capitalize it
if ($key == 0 or !in_array($word, $smallwordsarray)) {
$words[$key] = ucwords($word);
}
}
// Join the words back into a string
return implode(' ', $words);
}
/**
* Formats a zip code
*
* @param string $numbers An unformatted value
* @return string Returns the formatted value
*/
public static function formatZipCode($numbers) {
$numbers = self::stripNonNumeric($numbers);
if (strlen($numbers) > 5) {
return substr($numbers, 0, 5) . '-' . substr($numbers, 5, 4);
} else {
return $numbers;
}
}
/**
* Combine first, middle, and last names without extra spaces in-between
*
* @param string $first First name
* @param string $middle Middle name or initial
* @param string $last Last Name
* @return string The full name
*/
public static function fullName($first, $middle, $last) {
If (strlen(trim($middle)) == 1) {
$middle = trim($middle) . '.';
}
$full = trim($first . ' ' . $middle . ' ' . $last);
return self::stripExcessWhitespace($full);
}
/**
* Generate a random string of specified length from a set of specified characters
*
* @param integer $size Default size is 30 characters.
* @param string $chars The characters to use for randomization.
* @return string Returns the random generated string
*/
public static function generateRandomString($size = 30,
$characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') {
$randomString = '';
for ($i = 0; $i < $size; $i++) {
$index = random_int(0, strlen($characters) - 1);
$randomString .= $characters[$index];
}
return $randomString;
}
/**
* Safely returns an array element with a specified data type
* without generating any warning if an element doesn't exist
*
* @param array $array The array to use
* @param string $key The array key to use
* @param string $datatype [OPTIONAL] The datatype to return
* @return mixed The return value
*/
public static function getArrayElementValue($array, $key, $datatype = '') {
$return = null;
if (isset($array[$key])) {
$return = convertDataType($array[$key], $datatype, false);
}
return $return;
}
/**
* Converts any value of any datatype into boolean (true or false)
*
* @param any $value Value to analyze for TRUE or FALSE
* @param any $includeTrueValue [OPTIONAL] return TRUE if the value equals this
* @param any $includeFalseValue [OPTIONAL] return FALSE if the value equals this
* @return boolean Returns TRUE or FALSE
*/
public static function getBooleanValue($value, $includeTrueValue = null, $includeFalseValue = null) {
if (!(is_null($includeTrueValue)) && $value == $includeTrueValue) {
return true;
} elseif (!(is_null($includeFalseValue)) && $value == $includeFalseValue) {
return false;
} else {
if (is_array($value)) {
return empty($value);
} elseif (gettype($value) == 'boolean') {
if ($value == true) {
return true;
} else {
return false;
}
} elseif (is_numeric($value)) {
if ($value > 0) {
return true;
} else {
return false;
}
} else {
$cleaned = strtoupper(self::trim($value));
if ($cleaned == 'ON') {
return true;
} elseif ($cleaned == 'SELECTED' || $cleaned == 'CHECKED') {
return true;
} elseif ($cleaned == 'YES' || $cleaned == 'Y') {
return true;
} elseif ($cleaned == 'TRUE' || $cleaned == 'T') {
return true;
} else {
return false;
}
}
}
}
/**
* Get the IP address of the current client (must be used on a server).
* $_SERVER['REMOTE_ADDR'] sometimes does not returns the correct ip address
* of the visitor. This can be occur due to reasons like the user is behind a
* proxy, your apache server is behind a reverse proxy (e.g. varnish), etc.
*
* @return string Returns the IP address of the visitor
*/
public static function getClientIPAddress() {
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
$ipaddress = $_SERVER['HTTP_CLIENT_IP'];
} else if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ipaddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else if (!empty($_SERVER['HTTP_X_FORWARDED'])) {
$ipaddress = $_SERVER['HTTP_X_FORWARDED'];
} else if (!empty($_SERVER['HTTP_FORWARDED_FOR'])) {
$ipaddress = $_SERVER['HTTP_FORWARDED_FOR'];
} else if (!empty($_SERVER['HTTP_FORWARDED'])) {
$ipaddress = $_SERVER['HTTP_FORWARDED'];
} else if (!empty($_SERVER['REMOTE_ADDR'])) {
$ipaddress = $_SERVER['REMOTE_ADDR'];
} else {
$ipaddress = 'UNKNOWN';
}
return $ipaddress;
}
/**
* Get the value for a cookie by the cookie name
*
* @param string $name The name of the cookie
* @param string $default [OPTIONAL] A default if the value is empty
* @return string The cookie value
*/
public static function getCookieValue($name, $default = '') {
if (isset($_COOKIE[$name])) {
return self::trim($_COOKIE[$name]);
} else {
return $default;
}
}
/**
* Validates a credit card and returns what type of card it is
*
* @param string $cardnumber The credit card number with or without dashes/spaces
* @return string/boolean Returns the card type if valid, otherwise FALSE
*/
public static function getCreditCardType($cardnumber) {
// Strip all non-numeric input
$number = preg_replace('/[^0-9]/i', '', $cardnumber);
// Set our regex for each card type
$cardtypes = array(
'visa' => '/^4[0-9]{12}(?:[0-9]{3})?$/',
'mastercard' => '/^(?:5[1-5][0-9]{2}|222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}$/',
'amex' => '/^3[47][0-9]{13}$/',
'discover' => '/^6(?:011|5[0-9]{2})[0-9]{12}$/',
'jcb' => '/^(?:2131|1800|35\d{3})\d{11}$/',
'maestro' => '/^(?:5[0678]\d\d|6304|6390|67\d\d)\d{8,15}$/',
'solo' => '/^((?:6334|6767)\d{12}(?:\d\d)?\d?)$/',
'switch' => '/^(?:(?:(?:4903|4905|4911|4936|6333|6759)\d{12})|(?:(?:564182|633110)\d{10})(\d\d)?\d?)$/',
'dinersclub' => '/^3(?:0[0-5]|[68][0-9])[0-9]{11}$/'
);
// Set the default type if none found
$type = false;
// Loop through the card types
foreach ($cardtypes as $cardtype => $regex) {
// If a match is found...
if (preg_match($regex, $number)) {
// Save the type of card
$type = $cardtype;
// No need to keep processing regex
break;
}
}
// Return the result
return $type;
}
/**
* Returns the name of the current page (i.e. sample.php)
*
* @return string The page name
*/
public static function getCurrentPageName($lowercase = false, $extension = true) {
if ($extension) {
$return = pathinfo($_SERVER['PHP_SELF'], PATHINFO_BASENAME);
} else {
$return = pathinfo($_SERVER['PHP_SELF'], PATHINFO_FILENAME);
}
return ($lowercase ? strtolower($return) : $return);
}
/**
* Returns the name of the current URL (i.e. https://example.com/dir/sample.php)
*
* @return string The URL path
*/
public static function getCurrentPageURL($lowercase = false) {
$pageURL = self::getCurrentSite() . $_SERVER['REQUEST_URI'];
return ($lowercase ? strtolower($pageURL) : $pageURL);
}
/**
* Returns the name of the current URL (i.e. https://example.com
*
* @return string The URL path
*/
public static function getCurrentSite($lowercase = false) {
$url = 'http';
if (isset($_SERVER['HTTPS'])) {
if ($_SERVER['HTTPS'] == 'on') {
$url .= 's';
}
}
$url .= '://';
if ($_SERVER['SERVER_PORT'] != '80' && $_SERVER['SERVER_PORT'] != '443') {
$url .= $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT'];
} else {
$url .= $_SERVER['SERVER_NAME'];
}
return ($lowercase ? strtolower($url) : $url);
}
/**
* Returns the value if one exists, otherwise returns a default value
* (This also works on NULL values)
*
* @param string $name The value to check
* @param string $default A default if the value is empty
* @return string Returns the original value unless this value is
* empty - in which the default is returned
*/
public static function getDefaultOnEmpty($value, $default) {
if (self::hasValue($value)) {
return $value;
} else {
return $default;
}
}
/**
* Returns a value that is safe to use for a file or folder name
* (Warning: this will strip extensions like .ext)
*
* @param string $name The value to convert
* @param boolean $lowercase Determines if the return value will be lowercase
* @param integer $maxlength Determines if max length of the return value
* @param string $delimiter The character used to separate words
* @return string Returns a string that is safe for a file system
*/
public static function getFileSystemSafeString($string, $lowercase = true, $maxlength = 100, $delimiter = '_') {
// Strip any HTML or PHP tags
$string = trim(strip_tags($string));
// Remove apostrophes
$string = preg_replace("/[?']/", '', $string);
// We only want letters and numbers
$string = preg_replace('/[^a-zA-Z0-9]+/', $delimiter, $string);
// Strip out any non-words
$string = preg_replace('#\W+#', $delimiter, $string);
// Get rid of duplicate delimiters
$string = preg_replace('/[' . $delimiter . ']+/', $delimiter, $string);
// Convert to lowercase if necessary
if ($lowercase) $string = strtolower($string);
// Return the maximum allowed characters and do not begin/end with delimiters
return trim(substr($string, 0, $maxlength), $delimiter);
}
/**
* Converts a string into a floating point value
*
* example echo getFloatValue('$1,234,567.89');
*
* @param string $string String to modify
* @return string Modified string
*/
public static function getFloatValue($string) {
$value = preg_replace('/[^0-9.]/i', '', $string);
if (is_numeric($value)) {
return floatval($value);
} else {
return 0;
}
}
/**
* Get a GET value by a form element name
*
* @param string $name The name of the GET data
* @param string $default [OPTIONAL] A default if the value is empty
* @return string The value of the form element
*/
public static function getFormGet($name, $default = '') {
return this::getFormValue($name, $default, INPUT_GET);
}
/**
* Get a POST value by a form element name
*
* @param string $name The name of the POST data
* @param string $default [OPTIONAL] A default if the value is empty
* @return string The value of the form element
*/
public static function getFormPost($name, $default = '') {
return this::getFormValue($name, $default, INPUT_POST);
}
/**
* Get a POST or GET value by a form element name
*
* @param string $name The name of the POST or GET data
* @param string $default [OPTIONAL] A default if the value is empty
* @param string $method [OPTIONAL] INPUT_GET, INPUT_POST, or INPUT_REQUEST for both
* @return string The value of the form element
*/
public static function getFormValue($name, $default = '', $method = INPUT_REQUEST) {
if ($method != INPUT_GET && isset($_POST[$name])) {
return self::trim($_POST[$name]);
} else {
if ($method != INPUT_POST && isset($_GET[$name])) {
return self::trim($_GET[$name]);
} else {
return $default;
}
}
}
/**
* Checks an array to see if required keys exist and returns missing keys
*
* @param array $array The array to check
* @param array $required_keys An array holding a list of required keys
* @param boolean [OPTIONAL] $keys_uppercase If CASE_UPPER or CASE_LOWER,
* the $required_keys parameter will be converted to uppercase or lowercase
* @return array An array containing any missing fields
* Empty array() if no keys were found missing
* False if not an array
*/
public static function getMissingArrayKeys($array, $required_keys, $keys_case = false) {
$keys = array();
if (!is_array($array) || !is_array($required_keys)) {
$keys = false;
} else {
foreach ($required_keys as $key) {
if ($keys_case == CASE_UPPER) {
if (!array_key_exists(strtoupper($key), $array)) {
$keys[] = $key;
}
} elseif ($keys_case == CASE_LOWER) {
if (!array_key_exists(strtolower($key), $array)) {
$keys[] = $key;
}
} else {
if (!array_key_exists($key, $array)) {
$keys[] = $key;
}
}
}
}
return $keys;
}
/**
* Get the value for a request
*
* @param string $name The name of the request item
* @param string $default [OPTIONAL] A default if the value is empty
* @return string The request value
*/
public static function getRequestValue($name, $default = '') {
if (isset($_REQUEST[$name])) {
return self::trim($_REQUEST[$name]);
} else {
return $default;
}
}
/**
* Get the value for a session by the session name
*
* @param string $name The name of the session
* @param string $default [OPTIONAL] A default if the value is empty
* @return string The session value
*/
public static function getSessionValue($name, $default = '') {
if (isset($_SESSION[$name])) {
return self::trim($_SESSION[$name]);
} else {
return $default;
}
}
/**
* Get an array of unique characters used in a string.
* (Also works with multibyte characters)
*
* @param string $string String to modify
* @param boolean $returnAsArray True if results should be returned as array
* @return string/array Modified string
*/
public static function getUniqueChars($string, $returnAsArray = true) {
$unique = array_unique(preg_split('/(?<!^)(?!$)/u', $string));
if (!$returnAsArray) {
$unique = implode('', $unique);
}
return $unique;
}
/**
* Get a POST, GET, Cookie, or Session value by name
* (in that order - if one doesn't exist, the next is tried)
*
* @param string $name The name of the POST, GET, Session, or Cookie
* @param string $default [OPTIONAL] A default if the value is empty
* @return string The value from that element
*/
public static function getValue($name, $default = '') {
if (isset($_REQUEST[$name])) {
return self::trim($_REQUEST[$name]);
} else {
if (isset($_SESSION[$name])) {
return self::trim($_SESSION[$name]);
} else {
return $default;
}
}
}
/**
* Checks an array to see if required keys exist
*
* @param array $array The array to check
* @param array $required_keys An array holding a list of required keys
* @param boolean [OPTIONAL] $keys_uppercase If CASE_UPPER or CASE_LOWER,
* the $required_keys parameter will be converted to uppercase or lowercase
* @return boolean TRUE if all keys are found, otherwise FALSE
*/
public static function hasArrayKeys($array, $required_keys, $keys_case = false) {
$valid = true;
if (!is_array($array)) {
$valid = false;
} else {
foreach ($required_keys as $key) {
if ($keys_case == CASE_UPPER) {
if (!array_key_exists(strtoupper($key), $array)) {
$valid = false;
}
} elseif ($keys_case == CASE_LOWER) {
if (!array_key_exists(strtolower($key), $array)) {
$valid = false;
}
} else {
if (!array_key_exists($key, $array)) {
$valid = false;
}
}
}
}
return $valid;
}
/**
* Create a hash checksum for any number of different types of variables
*
* @example echo hashAny('test', true, false, -100, array('a' => 1, 'b' => 'c'));
*
* @param mixed $mixed Any number of parameters (order will change the return value)
* @return string A unique string of 64 characters representing the input parameters
*/
public static function hashAny($mixed) {
// (SHA-256 was chosen over MD5 to reduce the very remote possibility of collisions
// and virtually eliminate the chance of reverse engineering the hash)
return hash('sha256', print_r(func_get_args(), true));
}
/**
* Checks to see if a variable contains a value
*
* @param string $value The value to check
* @return boolean TRUE if a value exists, FALSE if empty
*/
public static function hasValue($value) {
return !(self::isEmpty($value));
}
/**
* Determines if a string is alpha only
*
* @param string $value The value to check for alpha (letters) only
* @param string $allow Any additional allowable characters
* @return boolean
*/
public static function isAlpha($value, $allow = '') {
if (preg_match('/^[a-zA-Z' . $allow . ']+$/', $value)) {
return true;
} else {
return false;
}
}
/**
* Determines if a string is alpha-numeric
*
* @param string $value The value to check
* @return boolean TRUE if there are letters and numbers, FALSE if other
*/
public static function isAlphaNumeric($value) {
if (preg_match('/^[A-Za-z0-9 ]+$/', $value)) {
return true;
} else {
return false;
}
}
/**
* Checks for a valid email address
*
* @param string $email The value to validate as an email address
* @return boolean TRUE if it is a valid email address, FALSE if not
*/
public static function isEmail($email) {
$pattern = '/^([a-zA-Z0-9])+([\.a-zA-Z0-9_-])*@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-]+)+/';
if (preg_match($pattern, $email)) {
return true;
} else {
return false;
}
}
/**
* Checks to see if a variable contains no value (not even a zero)
*
* @param string $value The value to check
* @return boolean TRUE if a value exists, FALSE if empty
*/
public static function isEmpty($value) {
if (!isset($value)) {
return true;
} elseif (is_null($value)) {
return true;
} elseif (is_string($value) && strlen($value) == 0) {
return true;
} elseif (is_array($value) && count($value) == 0) {
return true;
} else {
return false;
}
}
/**
* Checks to see if a variable is a floating point number
*
* @param float $number The value to check
* @return boolean TRUE if the value is a number, FALSE if not
*/
public static function isFloat($number) {
if (is_float($number)) {
return true;
} else {
$pattern = '/^[-+]?(((\\\\d+)\\\\.?(\\\\d+)?)|\\\\.\\\\d+)([eE]?[+-]?\\\\d+)?$/';
return (!is_bool($number) &&
(is_float($number) || preg_match($pattern, trim($number))));
}
}
/**
* Checks for a valid internet URL
*
* @param string $value The value to check
* @return boolean TRUE if the value is a valid URL, FALSE if not
*/
public static function isInternetURL($value) {
if (preg_match('/^http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w- .\/?%&=]*)?$/i', $value)) {
return true;
} else {
return false;
}
}
/**
* Checks for a valid IP Address
*
* @param string $value The value to check
* @return boolean TRUE if the value is an IP address, FALSE if not
*/
public static function isIPAddress($value) {
$pattern = '/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.'
. '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.'
. '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.'
. '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/i';
if (preg_match($pattern, $value)) {
return true;
} else {
return false;
}
}
/**
* Checks to see if a variable is a number
*
* @param integer $number The value to check
* @return boolean TRUE if the value is a number, FALSE if not
*/
public static function isNumber($number) {
if (preg_match('/^\-?\+?[0-9e1-9]+$/', $number)) {
return true;
} else {
return false;
}
}
/**
* Checks for a valid US phone number
*
* @param string $value The value to inspect
* @return boolean TRUE if the value is a phone number or FALSE if not
*/
public static function isPhoneNumber($value) {
if (preg_match(
'/^(?:(?:\+?1\s*(?:[.-]\s*)?)?(?:\(\s*([2-9]1[02-9]|' .
'[2-9][02-8]1|[2-9][02-8][02-9])\s*\)|([2-9]1[02-9]|' .
'[2-9][02-8]1|[2-9][02-8][02-9]))\s*(?:[.-]\s*)?)?' .
'([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\s*(?:[.-]\s*)?' .
'([0-9]{4})(?:\s*(?:#|x\.?|ext\.?|extension)\s*(\d+))?$/i', $value)) {
return true;
} else {
return false;
}
}
/**
* Checks to see if a variable is a social security number
*
* @param integer $ssn The value to check
* @param integer $strict If true, there are additional checks
* @return boolean TRUE if the value is a social security number, FALSE if not
*/
public static function isSSN($ssn, $strict = false) {
if (preg_match('/^\d{3}\-?\d{2}\-?\d{4}$/', $ssn)) {
if ($strict) {
// None of the digit groups can be all zeros.
// Area number 666 is unassigned.
// Numbers from 987-65-4320 to 987-65-4329 are reserved for use in advertisements.
// Many SSNs have been invalidated by use in advertising.
// Numbers above 772 are currently unassigned.
$regex = '/^((000|666)\-?\d{2}\-?\d{4}|\d{3}\-?00\-?\d{4}|\d{3}\-?' .
'\d{2}\-?0000|987\-?65\-?432\d{1}|042\-?10\-?3580|062\-?36\-?' .
'0749|078\-?05\-?1120|095\-?07\-?3645|128\-?03\-?6045|135\-?01\-?' .
'6629|141\-?18\-?6941|165\-?(16|18|20|22|24)\-?7999|189\-?09\-?' .
'2294|212\-?09\-?(7694|9999|219\-?09\-?9999|306\-?30\-?' .
'2348|308\-?12\-?5070|468\-?28\-?8779|549\-?24\-?1889)$/';
if (preg_match($regex, $ssn) || substr($ssn, 0, 3) > 772) {
return false;
} else {
return true;
}
} else {
return true;
}
} else {
return false;
}
}
/**
* Checks for a two character state abbreviation
*
* @param string $value The value to inspect
* @return boolean TRUE if the value is a 2 letter state abbreviation
* FALSE if the value is anything else
*/
public static function isStateAbbreviation($value) {
if (preg_match('/^[A-Z][A-Z]$/i', $value)) {
return true;
} else {
return false;
}
}
/**
* Check to see if a string length is too long
*
* @param string $value The string value to check
* @param integer $maximumLength The maximum allowed length
* @return boolean TRUE if the length is too long
* FALSE if the length is acceptable
*/
public static function isTooLong($value, $maximumLength) {
if (strlen($value) > $maximumLength) {
return true;
} else {
return false;
}
}
/**
* Check to see if a string length is too short
*
* @param string $value The string value to check
* @param integer $maximumLength The minimum allowed length
* @return boolean TRUE if the length is too short
* FALSE if the length is acceptable
*/
public static function isTooShort($value, $minimumLength) {
if (strlen($value) < $minimumLength) {
return true;
} else {
return false;
}
}
/**
* Checks to see if a variable is an unsigned number
*
* @param integer $number The value to inspect
* @return boolean TRUE if the value is a number without a sign
* and FALSE if a sign exists
*/
public static function isUnsignedNumber($number) {
if (preg_match('/^\+?[0-9]+$/', $number)) {
return true;
} else {
return false;
}
}
/**
* Checks a credit card number to see if it is valid using the Luhn checksum
*
* @param string $cardnumber The credit card number with or without dashes/spaces
* @return boolean TRUE if card checksum passes and FALSE if otherwise
*/
public static function isValidCreditCardNumber($cardnumber) {
// Strip all non-numeric input
$number = preg_replace('/[^0-9]/i', '', $cardnumber);
$length = strlen($number);
// Reverse the order of the number
$revNumber = strrev($number);
// Loop through and calculate the Luhn checksum
$sum = '';
for ($i = 0; $i < $length; $i++) {
$sum .= $i & 1 ? $revNumber[$i] * 2 : $revNumber[$i];
}
// Return the result as a boolean
return array_sum(str_split($sum)) % 10 === 0;
}
/**
* Checks to see if a variable is a valid JSON string
*
* @param string $string The value to check
* @return boolean TRUE if the value is JSON, FALSE if not
*/
public static function isValidJSON($string) {
@json_decode($string);
return (json_last_error() == JSON_ERROR_NONE);
}
/**
* Checks to see if a string contains valid XML
*
* @param string $string The value to check
* @return boolean TRUE if the value is XML, FALSE if not
*/
public static function isValidXML($string) {
libxml_use_internal_errors(true);
$doc = false;
$doc = @simplexml_load_string($string);
if ($doc !== false) {
$errors = false;
} else {
// $errors = libxml_get_errors();
$errors = true;
}
libxml_clear_errors();
return (!$errors);
}
/**
* Checks to see if a value contains a 5 or 9 digit zip code
*
* @param string $value The value to inspect
* @return boolean TRUE if zip code, otherwise FALSE
*/
public static function isZipCode($value) {
$numbers = self::stripNonNumeric($value);
if (strlen($numbers) == 5 || strlen($numbers) == 9) {
$formatted = self::formatZipCode($numbers);
if ($value == $numbers || $value == $formatted) {
return true;
} else {
return false;
}
} else {
return false;
}
}
/**
* Returns the left part of a string
*
* @param string $string The string to be divided
* @param int $length The number of characters to return
* @return string The extracted string
*/
public static function left($string, $length) {
return substr($string, 0, $length);
}
/**
* Adds th, st, nd, rd, th to the end of a number
*
* @param integer $number A number
* @return string A string with the modified number
*/
public static function ordinal($number) {
$test_c = abs($number) % 10;
$ext = ((abs($number) % 100 < 21 && abs($number) % 100 > 4) ? 'th'
: (($test_c < 4) ? ($test_c < 3) ? ($test_c < 2) ? ($test_c < 1)
? 'th' : 'st' : 'nd' : 'rd' : 'th'));
return $number . $ext;
}
/**
* Replace the last occurrence of a string.
*
* @param string $search String to search for
* @param string $replace String to replace with
* @param string $subject String to operate on
* @return string Replaces text
*/
public static function replaceLast($search, $replace, $subject) {
$lenOfSearch = strlen($search);
$posOfSearch = strrpos($subject, $search);
return substr_replace($subject, $replace, $posOfSearch, $lenOfSearch);
}
/**
* Returns the right part of a string
*
* @param string $string The string to be divided
* @param int $length The number of characters to return
* @return string The extracted string
*/
public static function right($string, $length) {
if ($length < 1) {
return '';
} else {
return substr($string, -$length);
}
}
/**
* Removes any dangerous javascript, HTML, or CSS code in a string
*
* @param String $input String to be sanitized
* @return String Sanitized string
*/
public static function sanitize($input) {
$search = array(
'@<script[^>]*?>.*?</script>@si', // Strip out javascript
'@<[\/\!]*?[^<>]*?>@si', // Strip out HTML tags
'@<style[^>]*?>.*?</style>@siU', // Strip style tags properly
'@<![\s\S]*?--[ \t\n\r]*>@' // Strip multi-line comments
);
return preg_replace($search, '', $input);
}
/**
* Determines if a string starts with another string
*
* @param string $string The subject of the search
* @param string $find The string to look for
* @param boolean $caseSensitive Case sensitive?
* @return boolean TRUE if yes and FALSE if not
*/
public static function startsWith($string, $find, $caseSensitive = true) {
$length = strlen($find);
if ($caseSensitive) {
return !strncmp($string, $find, $length);
} else {
return !strncmp(strtoupper($string), strtoupper($find), $length);
}
}
/**
* Transform two or more spaces into just one space.
*
* @param string $string String to modify
* @return string Modified string
*/
public static function stripExcessWhitespace($string) {
return preg_replace('/ +/', ' ', $string);
}
/**
* Remove all characters except letters.
*
* @param string $string String to modify
* @return string Modified string
*/
public static function stripNonAlpha($string) {
return preg_replace('/[^a-z]/i', '', $string);
}
/**
* Remove all characters except letters, hyphens, and spaces.
* (Most commonly used for names)
*
* @param string $string String to modify
* @return string Modified string
*/
public static function stripNonAlphaHyphenSpaces($string) {
return preg_replace('/[^a-z\- ]/i', '', $string);
}
/**
* Remove all characters except letters and numbers.
*
* @param string $string String to modify
* @return string Modified string
*/
public static function stripNonAlphaNumeric($string) {
return preg_replace('/[^a-z0-9]/i', '', $string);
}
/**
* Remove all characters except letters, numbers, hyphens, and spaces.
* (Most commonly used for city names)
*
* @param string $string String to modify
* @return string Modified string
*/
public static function stripNonAlphaNumericHyphenSpaces($string) {
return preg_replace('/[^a-z0-9\- ]/i', '', $string);
}
/**
* Remove all characters except letters, numbers, and spaces.
*
* @param string $string String to modify
* @return string Modified string
*/
public static function stripNonAlphaNumericSpaces($string) {
return preg_replace('/[^a-z0-9 ]/i', '', $string);
}
/**
* Remove all characters except numbers.
*
* @param string $string String to modify
* @return string Modified string
*/
public static function stripNonNumeric($string) {
return preg_replace('/[^0-9]/', '', $string);
}
/**
* Trims a value if it is a string
*
* @param unknown_type $value The value to trim
* @param string $mask The characters used for trim
* @return unknown_type The value passed in; if a string, then it is trimmed
*/
public static function trim($value, $mask = ' ') {
if (is_string($value)) {
return trim($value, $mask);
} elseif (is_null($value)) {
return '';
} else {
return $value;
}
}
/**
* Removes the decimal point in a float without rounding up or down
*
* example echo truncate('This is too long', 10, '...');
*
* @param string $string The string to truncate
* @param int $length The number of max character
* @return string The truncated string
*/
public static function truncate($string, $length, $dots = '') {
if (strlen($string) > $length) {
return substr($string, 0, $length - strlen($dots)) . $dots;
} else {
return $string;
}
}
/**
* Removes the decimal point in a float without rounding up or down
*
* example echo truncateDecimal(1234.5678);
*
* @param float $float Floating point decimal number
* @param int $precision [OPTIONAL] The number of decimal points to keep
* @return float The truncated floating point number
*/
public static function truncateDecimal($float, $precision = 0) {
$pow = pow(10, $precision);
$precise = (int) ($float * $pow);
return (float) ($precise / $pow);
}
/**
* Check to see if a password is string and meets basic requirements
*
* @param string $password Password
* @param string $confirm Confirmed password
* @param string $email Username
* @param string $username Email
* @param boolean $forceUpperLower True if password must contain both a
* lower and uppercase character
* @return string Contains an HTML list of problems or FALSE if valid
*/
public static function validatePassword($password, $confirm, $email = '',
$username = '', $forceUpperLower = false, $returnArray = false) {
// Create a variable to contain potential problems
$problem = '';
if ($password != $confirm) {
$problem .= 'Password and confirm password fields did not match.' . "<br>\n";
}
if (strlen($password) < 8) {
$problem .= 'Password must be at least 8 characters long.' . "<br>\n";
}
if ($email) {
if (strpos(strtoupper($password), strtoupper($email)) !== false
|| strpos(strtoupper($password), strtoupper(strrev($email))) !== false) {
$problem .= 'Password cannot contain the email address.' . "<br>\n";
}
}
if ($username) {
if (strpos(strtoupper($password), strtoupper($username)) !== false
|| strpos(strtoupper($password), strtoupper(strrev($username))) !== false) {
$problem .= 'Password cannot contain the username (or reversed username).' . "<br>\n";
}
}
if (!preg_match('#[0-9]+#', $password)) {
$problem .= 'Password must contain at least one number.' . "<br>\n";
}
if ($forceUpperLower) {
if (!preg_match('#[a-z]+#', $password)) {
$problem .= 'Password must contain at least one lowercase letter.' . "<br>\n";
}
if (!preg_match('#[A-Z]+#', $password)) {
$problem .= 'Password must contain at least one uppercase letter.' . "<br>\n";
}
} else {
if (!preg_match('#[a-zA-Z]+#', $password)) {
$problem .= 'Password must contain at least one letter.' . "<br>\n";
}
}
// Fix the return result
if (strlen($problem) == 0) {
$problem = false;
} elseif ($returnArray) {
$problem = explode("<br>\n", trim($problem, "<br>\n"));
} else {
// $problem = trim($problem, "<br>\n");
}
return $problem;
}
}
?>
|