From 80e4b012bbc39c63ad987b5e85993c7b3a0f6723 Mon Sep 17 00:00:00 2001 From: Thomas White Date: Sat, 27 Aug 2011 06:43:44 +0000 Subject: [PATCH] Added JavaScript equivalents of many more PHP functions in ExpressionManager (from phpjs.org). To keep codebase small, only added functions expected to be needed. Added many more test cases, especially of strings that contain special characters Still trying to find right balance of use of addslashes() and htmlspecialchars() in Javascript generation (e.g. surveys run properly, but some unit tests still fail). git-svn-id: file:///Users/Shitiz/Downloads/lssvn/source/limesurvey_ci@10862 b72ed6b6-b9f8-46b5-92b4-906544132732 --- .../helpers/expressions/em_core_helper.php | 314 +-- .../helpers/expressions/em_manager_helper.php | 12 +- scripts/admin/expressions/em_javascript.js | 1768 ++++++++++++++++- 3 files changed, 1971 insertions(+), 123 deletions(-) diff --git a/application/helpers/expressions/em_core_helper.php b/application/helpers/expressions/em_core_helper.php index e20e39e76fe..bdc56e3ede4 100644 --- a/application/helpers/expressions/em_core_helper.php +++ b/application/helpers/expressions/em_core_helper.php @@ -123,140 +123,148 @@ function __construct() $this->amValidFunctions = array( 'abs' =>array('abs','Math.abs','Absolute value',1), 'acos' =>array('acos','Math.acos','Arc cosine',1), - 'acosh' =>array('acosh','NA','Inverse hyperbolic cosine',1), +// 'acosh' =>array('acosh','acosh','Inverse hyperbolic cosine',1), 'asin' =>array('asin','Math.asin','Arc sine',1), - 'asinh' =>array('asinh','NA','Inverse hyperbolic sine',1), +// 'asinh' =>array('asinh','asinh','Inverse hyperbolic sine',1), 'atan2' =>array('atan2','Math.atan2','Arc tangent of two variables',2), 'atan' =>array('atan','Math.atan','Arc tangent',1), - 'atanh' =>array('atanh','NA','Inverse hyperbolic tangent',1), - 'base_convert' =>array('base_convert','NA','Convert a number between arbitrary bases',3), - 'bindec' =>array('bindec','NA','Binary to decimal',1), +// 'atanh' =>array('atanh','atanh','Inverse hyperbolic tangent',1), +// 'base_convert' =>array('base_convert','base_convert','Convert a number between arbitrary bases',3), +// 'bindec' =>array('bindec','bindec','Binary to decimal',1), 'ceil' =>array('ceil','Math.ceil','Round fractions up',1), 'cos' =>array('cos','Math.cos','Cosine',1), - 'cosh' =>array('cosh','NA','Hyperbolic cosine',1), - 'decbin' =>array('decbin','NA','Decimal to binary',1), - 'dechex' =>array('dechex','NA','Decimal to hexadecimal',1), - 'decoct' =>array('decoct','NA','Decimal to octal',1), - 'deg2rad' =>array('deg2rad','NA','Converts the number in degrees to the radian equivalent',1), +// 'cosh' =>array('cosh','cosh','Hyperbolic cosine',1), +// 'decbin' =>array('decbin','decbin','Decimal to binary',1), +// 'dechex' =>array('dechex','dechex','Decimal to hexadecimal',1), +// 'decoct' =>array('decoct','decoct','Decimal to octal',1), +// 'deg2rad' =>array('deg2rad','deg2rad','Converts the number in degrees to the radian equivalent',1), 'exp' =>array('exp','Math.exp','Calculates the exponent of e',1), - 'expm1' =>array('expm1','NA','Returns exp(number) - 1, computed in a way that is accurate even when the value of number is close to zero',1), +// 'expm1' =>array('expm1','expm1','Returns exp(number) - 1, computed in a way that is accurate even when the value of number is close to zero',1), 'floor' =>array('floor','Math.floor','Round fractions down',1), - 'fmod' =>array('fmod','NA','Returns the floating point remainder (modulo) of the division of the arguments',2), - 'getrandmax' =>array('getrandmax','NA','Show largest possible random value',0), - 'hexdec' =>array('hexdec','NA','Hexadecimal to decimal',1), - 'hypot' =>array('hypot','NA','Calculate the length of the hypotenuse of a right-angle triangle',2), - 'is_finite' =>array('is_finite','NA','Finds whether a value is a legal finite number',1), - 'is_infinite' =>array('is_infinite','NA','Finds whether a value is infinite',1), +// 'fmod' =>array('fmod','fmod','Returns the floating point remainder (modulo) of the division of the arguments',2), +// 'getrandmax' =>array('getrandmax','getrandmax','Show largest possible random value',0), +// 'hexdec' =>array('hexdec','hexdec','Hexadecimal to decimal',1), +// 'hypot' =>array('hypot','hypot','Calculate the length of the hypotenuse of a right-angle triangle',2), +// 'is_finite' =>array('is_finite','is_finite','Finds whether a value is a legal finite number',1), +// 'is_infinite' =>array('is_infinite','is_infinite','Finds whether a value is infinite',1), 'is_nan' =>array('is_nan','isNaN','Finds whether a value is not a number',1), - 'lcg_value' =>array('lcg_value','NA','Combined linear congruential generator',0), - 'log10' =>array('log10','NA','Base-10 logarithm',1), - 'log1p' =>array('log1p','NA','Returns log(1 + number), computed in a way that is accurate even when the value of number is close to zero',1), +// 'lcg_value' =>array('lcg_value','NA','Combined linear congruential generator',0), +// 'log10' =>array('log10','log10','Base-10 logarithm',1), +// 'log1p' =>array('log1p','log1p','Returns log(1 + number), computed in a way that is accurate even when the value of number is close to zero',1), 'log' =>array('log','Math.log','Natural logarithm',1,2), 'max' =>array('max','Math.max','Find highest value',-1), 'min' =>array('min','Math.min','Find lowest value',-1), - 'mt_getrandmax' =>array('mt_getrandmax','NA','Show largest possible random value',0), - 'mt_rand' =>array('mt_rand','NA','Generate a better random value',0,2), - 'mt_srand' =>array('mt_srand','NA','Seed the better random number generator',0,1), - 'octdec' =>array('octdec','NA','Octal to decimal',1), +// 'mt_getrandmax' =>array('mt_getrandmax','mt_getrandmax','Show largest possible random value',0), +// 'mt_rand' =>array('mt_rand','mt_rand','Generate a better random value',0,2), +// 'mt_srand' =>array('mt_srand','NA','Seed the better random number generator',0,1), +// 'octdec' =>array('octdec','octdec','Octal to decimal',1), 'pi' =>array('pi','LEMpi','Get value of pi',0), 'pow' =>array('pow','Math.pow','Exponential expression',2), - 'rad2deg' =>array('rad2deg','NA','Converts the radian number to the equivalent number in degrees',1), +// 'rad2deg' =>array('rad2deg','rad2deg','Converts the radian number to the equivalent number in degrees',1), 'rand' =>array('rand','Math.random','Generate a random integer',0,2), 'round' =>array('round','LEMround','Rounds a number to an optional precision',1,2), 'sin' =>array('sin','Math.sin','Sine',1), - 'sinh' =>array('sinh','NA','Hyperbolic sine',1), +// 'sinh' =>array('sinh','sinh','Hyperbolic sine',1), 'sqrt' =>array('sqrt','Math.sqrt','Square root',1), 'srand' =>array('srand','NA','Seed the random number generator',0,1), 'sum' =>array('array_sum','LEMsum','Calculate the sum of values in an array',-1), 'tan' =>array('tan','Math.tan','Tangent',1), - 'tanh' =>array('tanh','NA','Hyperbolic tangent',1), +// 'tanh' =>array('tanh','tanh','Hyperbolic tangent',1), 'intval' =>array('intval','LEMintval','Get the integer value of a variable',1,2), - 'is_bool' =>array('is_bool','NA','Finds out whether a variable is a boolean',1), + 'is_bool' =>array('is_bool','is_bool','Finds out whether a variable is a boolean',1), 'is_float' =>array('is_float','LEMis_float','Finds whether the type of a variable is float',1), 'is_int' =>array('is_int','LEMis_int','Find whether the type of a variable is integer',1), 'is_null' =>array('is_null','LEMis_null','Finds whether a variable is NULL',1), 'is_numeric' =>array('is_numeric','LEMis_numeric','Finds whether a variable is a number or a numeric string',1), - 'is_scalar' =>array('is_scalar','NA','Finds whether a variable is a scalar',1), +// 'is_scalar' =>array('is_scalar','is_scalar','Finds whether a variable is a scalar',1), 'is_string' =>array('is_string','LEMis_string','Find whether the type of a variable is string',1), - 'addcslashes' =>array('addcslashes','NA','Quote string with slashes in a C style',2), - 'addslashes' =>array('addslashes','NA','Quote string with slashes',1), - 'bin2hex' =>array('bin2hex','NA','Convert binary data into hexadecimal representation',1), - 'chr' =>array('chr','NA','Return a specific character',1), - 'chunk_split' =>array('chunk_split','NA','Split a string into smaller chunks',1,2,3), - 'convert_uudecode' =>array('convert_uudecode','NA','Decode a uuencoded string',1), - 'convert_uuencode' =>array('convert_uuencode','NA','Uuencode a string',1), - 'count_chars' =>array('count_chars','NA','Return information about characters used in a string',1,2), - 'crc32' =>array('crc32','NA','Calculates the crc32 polynomial of a string',1), - 'crypt' =>array('crypt','NA','One-way string hashing',1,2), - 'hebrev' =>array('hebrev','NA','Convert logical Hebrew text to visual text',1,2), - 'hebrevc' =>array('hebrevc','NA','Convert logical Hebrew text to visual text with newline conversion',1,2), - 'html_entity_decode' =>array('html_entity_decode','NA','Convert all HTML entities to their applicable characters',1,2,3), - 'htmlentities' =>array('htmlentities','NA','Convert all applicable characters to HTML entities',1,2,3), - 'htmlspecialchars_decode' =>array('htmlspecialchars_decode','NA','Convert special HTML entities back to characters',1,2), - 'htmlspecialchars' =>array('htmlspecialchars','NA','Convert special characters to HTML entities',1,2,3,4), +// 'addcslashes' =>array('addcslashes','addcslashes','Quote string with slashes in a C style',2), + 'addslashes' =>array('addslashes','addslashes','Quote string with slashes',1), +// 'bin2hex' =>array('bin2hex','bin2hex','Convert binary data into hexadecimal representation',1), +// 'chr' =>array('chr','chr','Return a specific character',1), +// 'chunk_split' =>array('chunk_split','chunk_split','Split a string into smaller chunks',1,2,3), +// 'convert_uudecode' =>array('convert_uudecode','NA','Decode a uuencoded string',1), +// 'convert_uuencode' =>array('convert_uuencode','convert_uuencode','Uuencode a string',1), +// 'count_chars' =>array('count_chars','count_chars','Return information about characters used in a string',1,2), +// 'crc32' =>array('crc32','crc32','Calculates the crc32 polynomial of a string',1), +// 'crypt' =>array('crypt','NA','One-way string hashing',1,2), +// 'hebrev' =>array('hebrev','NA','Convert logical Hebrew text to visual text',1,2), +// 'hebrevc' =>array('hebrevc','NA','Convert logical Hebrew text to visual text with newline conversion',1,2), + 'html_entity_decode' =>array('html_entity_decode','html_entity_decode','Convert all HTML entities to their applicable characters',1,2,3), + 'htmlentities' =>array('htmlentities','htmlentities','Convert all applicable characters to HTML entities',1,2,3), + 'htmlspecialchars_decode' =>array('expr_mgr_htmlspecialchars_decode','htmlspecialchars_decode','Convert special HTML entities back to characters',1,2), + 'htmlspecialchars' =>array('expr_mgr_htmlspecialchars','htmlspecialchars','Convert special characters to HTML entities',1,2,3,4), 'implode' =>array('exprmgr_implode','LEMimplode','Join array elements with a string',-1), - 'lcfirst' =>array('lcfirst','NA','Make a string\'s first character lowercase',1), - 'levenshtein' =>array('levenshtein','NA','Calculate Levenshtein distance between two strings',2,5), - 'ltrim' =>array('ltrim','NA','Strip whitespace (or other characters) from the beginning of a string',1,2), - 'md5' =>array('md5','NA','Calculate the md5 hash of a string',1), - 'metaphone' =>array('metaphone','NA','Calculate the metaphone key of a string',1,2), - 'money_format' =>array('money_format','NA','Formats a number as a currency string',1,2), - 'nl2br' =>array('nl2br','NA','Inserts HTML line breaks before all newlines in a string',1,2), - 'number_format' =>array('number_format','NA','Format a number with grouped thousands',1,2,4), - 'ord' =>array('ord','NA','Return ASCII value of character',1), - 'quoted_printable_decode' =>array('quoted_printable_decode','NA','Convert a quoted-printable string to an 8 bit string',1), - 'quoted_printable_encode' =>array('quoted_printable_encode','NA','Convert a 8 bit string to a quoted-printable string',1), - 'quotemeta' =>array('quotemeta','NA','Quote meta characters',1), - 'rtrim' =>array('rtrim','NA','Strip whitespace (or other characters) from the end of a string',1,2), - 'sha1' =>array('sha1','NA','Calculate the sha1 hash of a string',1), - 'similar_text' =>array('similar_text','NA','Calculate the similarity between two strings',1,2), - 'soundex' =>array('soundex','NA','Calculate the soundex key of a string',1), - 'sprintf' =>array('sprintf','NA','Return a formatted string',-1), - 'str_ireplace' =>array('str_ireplace','NA','Case-insensitive version of str_replace',3), - 'str_pad' =>array('str_pad','NA','Pad a string to a certain length with another string',2,3,4), - 'str_repeat' =>array('str_repeat','NA','Repeat a string',2), +// 'lcfirst' =>array('lcfirst','lcfirst','Make a string\'s first character lowercase',1), +// 'levenshtein' =>array('levenshtein','levenshtein','Calculate Levenshtein distance between two strings',2,5), + 'ltrim' =>array('ltrim','ltrim','Strip whitespace (or other characters) from the beginning of a string',1,2), +// 'md5' =>array('md5','md5','Calculate the md5 hash of a string',1), +// 'metaphone' =>array('metaphone','metaphone','Calculate the metaphone key of a string',1,2), +// 'money_format' =>array('money_format','money_format','Formats a number as a currency string',1,2), + 'nl2br' =>array('nl2br','nl2br','Inserts HTML line breaks before all newlines in a string',1,2), + 'number_format' =>array('number_format','number_format','Format a number with grouped thousands',1,2,4), +// 'ord' =>array('ord','ord','Return ASCII value of character',1), + 'quoted_printable_decode' =>array('quoted_printable_decode','quoted_printable_decode','Convert a quoted-printable string to an 8 bit string',1), + 'quoted_printable_encode' =>array('quoted_printable_encode','quoted_printable_encode','Convert a 8 bit string to a quoted-printable string',1), + 'quotemeta' =>array('quotemeta','quotemeta','Quote meta characters',1), + 'rtrim' =>array('rtrim','rtrim','Strip whitespace (or other characters) from the end of a string',1,2), +// 'sha1' =>array('sha1','sha1','Calculate the sha1 hash of a string',1), +// 'similar_text' =>array('similar_text','similar_text','Calculate the similarity between two strings',1,2), +// 'soundex' =>array('soundex','soundex','Calculate the soundex key of a string',1), + 'sprintf' =>array('sprintf','sprintf','Return a formatted string',-1), +// 'str_ireplace' =>array('str_ireplace','str_ireplace','Case-insensitive version of str_replace',3), + 'str_pad' =>array('str_pad','str_pad','Pad a string to a certain length with another string',2,3,4), + 'str_repeat' =>array('str_repeat','str_repeat','Repeat a string',2), 'str_replace' =>array('str_replace','LEMstr_replace','Replace all occurrences of the search string with the replacement string',3), - 'str_rot13' =>array('str_rot13','NA','Perform the rot13 transform on a string',1), - 'str_shuffle' =>array('str_shuffle','NA','Randomly shuffles a string',1), - 'str_word_count' =>array('str_word_count','NA','Return information about words used in a string',1), - 'strcasecmp' =>array('strcasecmp','NA','Binary safe case-insensitive string comparison',2), - 'strcmp' =>array('strcmp','NA','Binary safe string comparison',2), - 'strcoll' =>array('strcoll','NA','Locale based string comparison',2), - 'strcspn' =>array('strcspn','NA','Find length of initial segment not matching mask',2,3,4), - 'strip_tags' =>array('strip_tags','LEMstrip_tags','Strip HTML and PHP tags from a string',1,2), - 'stripcslashes' =>array('stripcslashes','NA','Un-quote string quoted with addcslashes',1), - 'stripos' =>array('stripos','NA','Find position of first occurrence of a case-insensitive string',2,3), - 'stripslashes' =>array('stripslashes','NA','Un-quotes a quoted string',1), - 'stristr' =>array('stristr','NA','Case-insensitive strstr',2,3), +// 'str_rot13' =>array('str_rot13','str_rot13','Perform the rot13 transform on a string',1), +// 'str_shuffle' =>array('str_shuffle','str_shuffle','Randomly shuffles a string',1), +// 'str_word_count' =>array('str_word_count','str_word_count','Return information about words used in a string',1), + 'strcasecmp' =>array('strcasecmp','strcasecmp','Binary safe case-insensitive string comparison',2), + 'strcmp' =>array('strcmp','strcmp','Binary safe string comparison',2), +// 'strcoll' =>array('strcoll','strcoll','Locale based string comparison',2), +// 'strcspn' =>array('strcspn','strcspn','Find length of initial segment not matching mask',2,3,4), + 'strip_tags' =>array('strip_tags','strip_tags','Strip HTML and PHP tags from a string',1,2), +// 'stripcslashes' =>array('stripcslashes','NA','Un-quote string quoted with addcslashes',1), + 'stripos' =>array('stripos','stripos','Find position of first occurrence of a case-insensitive string',2,3), + 'stripslashes' =>array('stripslashes','stripslashes','Un-quotes a quoted string',1), + 'stristr' =>array('stristr','stristr','Case-insensitive strstr',2,3), 'strlen' =>array('strlen','LEMstrlen','Get string length',1), - 'strnatcasecmp' =>array('strnatcasecmp','NA','Case insensitive string comparisons using a "natural order" algorithm',2), - 'strnatcmp' =>array('strnatcmp','NA','String comparisons using a "natural order" algorithm',2), - 'strncasecmp' =>array('strncasecmp','NA','Binary safe case-insensitive string comparison of the first n characters',3), - 'strncmp' =>array('strncmp','NA','Binary safe string comparison of the first n characters',3), - 'strpbrk' =>array('strpbrk','NA','Search a string for any of a set of characters',2), +// 'strnatcasecmp' =>array('strnatcasecmp','strnatcasecmp','Case insensitive string comparisons using a "natural order" algorithm',2), +// 'strnatcmp' =>array('strnatcmp','strnatcmp','String comparisons using a "natural order" algorithm',2), +// 'strncasecmp' =>array('strncasecmp','strncasecmp','Binary safe case-insensitive string comparison of the first n characters',3), +// 'strncmp' =>array('strncmp','strncmp','Binary safe string comparison of the first n characters',3), +// 'strpbrk' =>array('strpbrk','strpbrk','Search a string for any of a set of characters',2), 'strpos' =>array('strpos','LEMstrpos','Find position of first occurrence of a string',2,3), - 'strrchr' =>array('strrchr','NA','Find the last occurrence of a character in a string',2), - 'strrev' =>array('strrev','NA','Reverse a string',1), - 'strripos' =>array('strripos','NA','Find position of last occurrence of a case-insensitive string in a string',2,3), - 'strrpos' =>array('strrpos','NA','Find the position of the last occurrence of a substring in a string',2,3), - 'strspn' =>array('strspn','NA','Finds the length of the initial segment of a string consisting entirely of characters contained within a given mask.',2,3,4), - 'strstr' =>array('strstr','NA','Find first occurrence of a string',2,3), +// 'strrchr' =>array('strrchr','strrchr','Find the last occurrence of a character in a string',2), + 'strrev' =>array('strrev','strrev','Reverse a string',1), +// 'strripos' =>array('strripos','strripos','Find position of last occurrence of a case-insensitive string in a string',2,3), +// 'strrpos' =>array('strrpos','strrpos','Find the position of the last occurrence of a substring in a string',2,3), +// 'strspn' =>array('strspn','strspn','Finds the length of the initial segment of a string consisting entirely of characters contained within a given mask.',2,3,4), + 'strstr' =>array('strstr','strstr','Find first occurrence of a string',2,3), 'strtolower' =>array('strtolower','LEMstrtolower','Make a string lowercase',1), 'strtoupper' =>array('strtoupper','LEMstrtoupper','Make a string uppercase',1), - 'strtr' =>array('strtr','NA','Translate characters or replace substrings',3), - 'substr_compare'=>array('substr_compare','NA','Binary safe comparison of two strings from an offset, up to length characters',3,4,5), - 'substr_count' =>array('substr_count','NA','Count the number of substring occurrences',2,3,4), - 'substr_replace'=>array('substr_replace','NA','Replace text within a portion of a string',3,4), - 'substr' =>array('substr','NA','Return part of a string',2,3), - 'ucfirst' =>array('ucfirst','NA','Make a string\'s first character uppercase',1), - 'ucwords' =>array('ucwords','NA','Uppercase the first character of each word in a string',1), +// 'strtr' =>array('strtr','strtr','Translate characters or replace substrings',3), +// 'substr_compare'=>array('substr_compare','substr_compare','Binary safe comparison of two strings from an offset, up to length characters',3,4,5), +// 'substr_count' =>array('substr_count','substr_count','Count the number of substring occurrences',2,3,4), +// 'substr_replace'=>array('substr_replace','substr_replace','Replace text within a portion of a string',3,4), + 'substr' =>array('substr','substr','Return part of a string',2,3), + 'trim' =>array('trim','trim','Strip whitespace (or other characters) from the beginning and end of a string',1,2), +// 'ucfirst' =>array('ucfirst','ucfirst','Make a string\'s first character uppercase',1), + 'ucwords' =>array('ucwords','ucwords','Uppercase the first character of each word in a string',1), 'if' => array('exprmgr_if','LEMif','Excel-style if(test,result_if_true,result_if_false)',3), 'list' => array('exprmgr_list','LEMlist','Return comma-separated list of values',-1), 'is_empty' => array('exprmgr_empty','LEMempty','Determine whether a variable is considered to be empty',1), 'stddev' => array('exprmgr_stddev','LEMstddev','Calculate the Sample Standard Deviation for the list of numbers',-1), + + 'checkdate' => array('checkdate','checkdate','Returns true(1) if it is a valid date in gregorian calendar',3), + 'date' => array('date','date','Format a local date/time',2), + 'gmdate' => array('gmdate','gmdate','Format a GMT date/time',2), + 'idate' => array('idate','idate','Format a local time/date as integer',2), + 'mktime' => array('mktime','mktime','Get UNIX timestamp for a date',1,2,3,4,5,6), + 'time' => array('time','time','Return current UNIX timestamp',0), ); $this->amVars = array(); @@ -1138,8 +1146,10 @@ public function GetJavaScriptEquivalentOfExpression() switch ($token[2]) { case 'DQ_STRING': + $stringParts[] = '"' . addcslashes($token[0],'"') . '"'; // htmlspecialchars($token[0],ENT_QUOTES,'UTF-8',false) . "'"; + break; case 'SQ_STRING': - $stringParts[] = "'" . htmlspecialchars($token[0],ENT_QUOTES,'UTF-8') . "'"; + $stringParts[] = "'" . addcslashes($token[0],"'") . "'"; // htmlspecialchars($token[0],ENT_QUOTES,'UTF-8',false) . "'"; break; case 'SGQA': case 'WORD': @@ -1193,7 +1203,7 @@ public function GetJavaScriptEquivalentOfExpression() } else { - $stringParts[] = is_numeric($varInfo['codeValue']) ? $varInfo['codeValue'] : ("'" . htmlspecialchars($varInfo['codeValue'],ENT_QUOTES,'UTF-8') . "'"); + $stringParts[] = is_numeric($varInfo['codeValue']) ? $varInfo['codeValue'] : ("'" . addcslashes($varInfo['codeValue'],"'") . "'"); // htmlspecialchars($varInfo['codeValue'],ENT_QUOTES,'UTF-8',false) . "'"); } } break; @@ -1250,7 +1260,7 @@ public function GetJavaScriptEquivalentOfExpression() * JavaScript Test function - simply writes the result of the current JavaScriptEquivalentFunction to the output buffer. * @return */ - public function GetJavascriptTestforExpression($expected) + public function GetJavascriptTestforExpression($expected,$num) { // assumes that the hidden variables have already been declared $expr = $this->GetJavaScriptEquivalentOfExpression(); @@ -1258,12 +1268,10 @@ public function GetJavascriptTestforExpression($expected) $expr = "'NULL'"; } $jsParts = array(); - $jsParts[] = '\n"; + $jsParts[] = "val = " . $expr . ";\n"; + $jsParts[] = "klass = (LEMeq(addslashes(val),'" . addslashes($expected) . "')) ? 'ok' : 'error';\n"; + $jsParts[] = "document.getElementById('test_" . $num . "').innerHTML=val;\n"; + $jsParts[] = "document.getElementById('test_" . $num . "').className=klass;\n"; return implode('',$jsParts); } @@ -1347,13 +1355,13 @@ public function GetPrettyPrintString() case 'DQ_STRING': // $messages[] = 'STRING'; $stringParts[] = "\""; - $stringParts[] = htmlspecialchars($token[0],ENT_QUOTES,'UTF-8'); + $stringParts[] = $token[0]; // htmlspecialchars($token[0],ENT_QUOTES,'UTF-8',false); $stringParts[] = "\""; break; case 'SQ_STRING': // $messages[] = 'STRING'; $stringParts[] = "'"; - $stringParts[] = htmlspecialchars($token[0],ENT_QUOTES,'UTF-8'); + $stringParts[] = $token[0]; // htmlspecialchars($token[0],ENT_QUOTES,'UTF-8',false); $stringParts[] = "'"; break; case 'SGQA': @@ -1381,7 +1389,7 @@ public function GetPrettyPrintString() $messages[] = $varInfo['jsName']; } if (strlen(trim($varInfo['codeValue'])) > 0) { - $messages[] = 'value=' . htmlspecialchars($varInfo['codeValue'],ENT_QUOTES,'UTF-8'); + $messages[] = 'value=' . htmlspecialchars($varInfo['codeValue'],ENT_QUOTES,'UTF-8',false); } $stringParts[] = ""; $stringParts[] = $token[0]; @@ -1393,7 +1401,7 @@ public function GetPrettyPrintString() $messages[] = $varInfo['jsName']; } if (strlen(trim($varInfo['codeValue'])) > 0) { - $messages[] = 'value=' . htmlspecialchars($varInfo['codeValue'],ENT_QUOTES,'UTF-8'); + $messages[] = 'value=' . htmlspecialchars($varInfo['codeValue'],ENT_QUOTES,'UTF-8',false); } $stringParts[] = ""; $stringParts[] = $token[0]; @@ -1674,7 +1682,7 @@ public function sProcessStringContainingExpressions($src, $questionNum=0, $numRe for($i=1;$i<=$numRecursionLevels;++$i) { // TODO - Since want to use for dynamic substitution, what if there are recursive substititons? - $result = $this->sProcessStringContainingExpressionsHelper(htmlspecialchars_decode($result),$questionNum); + $result = $this->sProcessStringContainingExpressionsHelper(htmlspecialchars_decode($result,ENT_QUOTES),$questionNum); if ($i == $whichPrettyPrintIteration) { $prettyPrint = $this->prettyPrintSource; @@ -1724,7 +1732,8 @@ public function sProcessStringContainingExpressionsHelper($src, $questionNum) if (count($jsVarsUsed) > 0) { $idName = "LEMtailor_Q_" . $questionNum . "_" . $this->substitutionNum; - $resolvedParts[] = "" . htmlspecialchars($resolvedPart,ENT_QUOTES,"UTF-8") . ""; +// $resolvedParts[] = "" . htmlspecialchars($resolvedPart,ENT_QUOTES,'UTF-8',false) . ""; // TODO - encode within SPAN? + $resolvedParts[] = "" . $resolvedPart . ""; $this->substitutionVars[$idName] = 1; $this->substitutionInfo[] = array( 'questionNum' => $questionNum, @@ -1871,8 +1880,18 @@ private function RunFunction($funcNameToken,$params) $result = $funcName($params[0], $params[1], $params[2], $params[3]); } break; + case 5: + if (!$this->onlyparse) { + $result = $funcName($params[0], $params[1], $params[2], $params[3], $params[4]); + } + break; + case 6: + if (!$this->onlyparse) { + $result = $funcName($params[0], $params[1], $params[2], $params[3], $params[4], $params[5]); + } + break; default: - $this->AddError("Unsupported number of arguments: " . $argsPassed, $funNameToken); + $this->AddError("Unsupported number of arguments: " . $argsPassed, $funcNameToken); return false; } @@ -2430,6 +2449,40 @@ static function UnitTestEvaluator() 1~if(' ',1,0) 0~!is_empty(a==b) 1~!is_empty(1) +1~is_bool(false) +0~is_bool(1) +"Can strings contain embedded \"quoted passages\" (and parentheses + other characters?)?"~a=htmlspecialchars(ASSESSMENT_HEADING) +"can single quoted strings" . 'contain nested 'quoted sections'?~b=htmlspecialchars(QUESTIONHELP) +Can strings have embedded <tags> like <html>, or even unbalanced "quotes or entities without terminal semicolons like &amp and &lt?~c=htmlspecialchars(QUESTION_HELP) +1~c==htmlspecialchars(htmlspecialchars_decode(c)) +1~b==htmlspecialchars(htmlspecialchars_decode(b)) +1~a==htmlspecialchars(htmlspecialchars_decode(a)) +"Can strings contain embedded \\"quoted passages\\" (and parentheses + other characters?)?"~addslashes(a) +"can single quoted strings" . 'contain nested 'quoted sections'?~addslashes(b) +Can strings have embedded <tags> like <html>, or even unbalanced "quotes or entities without terminal semicolons like &amp and &lt?~addslashes(c) +"Can strings contain embedded \"quoted passages\" (and parentheses + other characters?)?"~html_entity_decode(a) +"can single quoted strings" . 'contain nested 'quoted sections'?~html_entity_decode(b) +Can strings have embedded like , or even unbalanced "quotes or entities without terminal semicolons like & and <?~html_entity_decode(c) +"Can strings contain embedded \"quoted passages\" (and parentheses + other characters?)?"~htmlentities(a) +"can single quoted strings" . 'contain nested 'quoted sections'?~htmlentities(b) +Can strings have embedded <tags> like <html>, or even unbalanced "quotes or entities without terminal semicolons like &amp and &lt?~htmlentities(c) +"Can strings contain embedded \"quoted passages\" (and parentheses + other characters?)?"~htmlspecialchars_decode(a) +"can single quoted strings" . 'contain nested 'quoted sections'?~htmlspecialchars_decode(b) +Can strings have embedded like , or even unbalanced "quotes or entities without terminal semicolons like & and like , or even unbalanced "quotes or entities without terminal semicolons like & and <?~htmlspecialchars(c) +I was trimmed ~ltrim(' I was trimmed ') + I was trimmed~rtrim(' I was trimmed ') +I was trimmed~trim(' I was trimmed ') +1,234,567~number_format(1234567) +Hi There You~ucwords('hi there you') +1~checkdate(1,29,1967) +0~checkdate(2,29,1967) +1144191723~mktime(1,2,3,4,5,6) +April 5, 2006, 1:02 am~date('F j, Y, g:i a',mktime(1,2,3,4,5,6)) +NULL~time() +NULL~date('F j, Y, g:i a',time()) EOD; $em = new ExpressionManager(); @@ -2474,14 +2527,14 @@ static function UnitTestEvaluator() $value = $v['codeValue']; } } - print "" . $value . "\n"; + print "" . $value . "\n"; print "\n"; print "\n"; $LEMalias2varName[] = "'" . substr($jsVarName,5) . "':{'jsName':'" . $jsVarName . "'}"; $LEMalias2varName[] = "'" . $jsVarName . "':{'jsName':'" . $jsVarName . "'}"; $LEMvarNameAttr[] = "'" . $jsVarName . "': {" . "'jsName':'" . $jsVarName - . "','code':'" . htmlspecialchars(preg_replace("/[[:space:]]/",' ',$value),ENT_QUOTES,'UTF-8') + . "','code':'" . htmlspecialchars(preg_replace("/[[:space:]]/",' ',$value),ENT_QUOTES) . "','question':'" . "','qid':'" . $i . "'}"; } @@ -2494,16 +2547,19 @@ static function UnitTestEvaluator() print "//-->\n\n"; print ''; + $i=0; + $javaScript = array(); foreach(explode("\n",$tests)as $test) { + ++$i; $values = explode("~",$test); $expectedResult = array_shift($values); $expr = implode("~",$values); $resultStatus = 'ok'; $status = $em->Evaluate($expr); $result = $em->GetResult(); - $valToShow = htmlspecialchars($result,ENT_QUOTES,'UTF-8'); - $expectedToShow = htmlspecialchars($expectedResult,ENT_QUOTES,'UTF-8'); + $valToShow = $result; // htmlspecialchars($result,ENT_QUOTES,'UTF-8',false); + $expectedToShow = $expectedResult; // htmlspecialchars($expectedResult,ENT_QUOTES,'UTF-8',false); print ""; print "\n"; if (is_null($result)) { @@ -2515,7 +2571,8 @@ static function UnitTestEvaluator() $resultStatus = 'error'; } print "\n"; - print "\n"; + $javaScript[] = $em->GetJavascriptTestforExpression($expectedToShow, $i); + print "\n"; $varsUsed = $em->GetVarsUsed(); if (is_array($varsUsed) and count($varsUsed) > 0) { $varDesc = array(); @@ -2540,6 +2597,11 @@ static function UnitTestEvaluator() print ''; } print '
ExpressionResultExpectedJavaScript TestVarNamesJavaScript Eqn
" . $em->GetPrettyPrintString() . "" . $expectedToShow . "" . $em->GetJavascriptTestforExpression($expectedToShow) . "  
'; + print "\n"; } } @@ -2662,4 +2724,24 @@ function exprmgr_stddev($args) return $stddev; } +/** + * Javascript equivalent does not cope well with ENT_QUOTES and related PHP constants, so set default to ENT_QUOTES + * @param $string + * @return + */ +function expr_mgr_htmlspecialchars($string) +{ + return htmlspecialchars($string,ENT_QUOTES); +} + +/** + * Javascript equivalent does not cope well with ENT_QUOTES and related PHP constants, so set default to ENT_QUOTES + * @param $string + * @return + */ +function expr_mgr_htmlspecialchars_decode($string) +{ + return htmlspecialchars_decode($string,ENT_QUOTES); +} + ?> diff --git a/application/helpers/expressions/em_manager_helper.php b/application/helpers/expressions/em_manager_helper.php index fd66d0b6141..c2d5c2a8b91 100644 --- a/application/helpers/expressions/em_manager_helper.php +++ b/application/helpers/expressions/em_manager_helper.php @@ -300,7 +300,7 @@ public function setVariableAndTokenMappingsForExpressionManager($forceRefresh=fa $varNameAttr[$jsVarName] = "'" . $jsVarName . "':{" . "'jsName':'" . $jsVarName - . "','code':'" . htmlspecialchars(preg_replace('/[[:space:]]/',' ',$codeValue),ENT_QUOTES,'UTF-8') + . "','code':'" . htmlspecialchars(preg_replace('/[[:space:]]/',' ',$codeValue),ENT_QUOTES) // . "','shown':'" . $displayValue // . "','question':'" . $question . "','qid':'" . $questionNum @@ -457,7 +457,7 @@ static function ProcessString($string, $questionNum=NULL, $replacementFields=arr } $em->RegisterVarnamesUsingMerge($replaceArray); // TODO - is it safe to just merge these in each time, or should a refresh be forced? } - $result = $em->sProcessStringContainingExpressions(htmlspecialchars_decode($string),(is_null($questionNum) ? 0 : $questionNum), $numRecursionLevels, $whichPrettyPrintIteration); + $result = $em->sProcessStringContainingExpressions(htmlspecialchars_decode($string,ENT_QUOTES),(is_null($questionNum) ? 0 : $questionNum), $numRecursionLevels, $whichPrettyPrintIteration); if ($lem->debugLEM) { @@ -500,7 +500,7 @@ static function ProcessRelevance($eqn,$questionNum=NULL,$jsResultVar=NULL,$type= return true; } $em = $lem->em; - $result = $em->ProcessBooleanExpression(htmlspecialchars_decode($eqn)); + $result = $em->ProcessBooleanExpression(htmlspecialchars_decode($eqn,ENT_QUOTES)); $jsVars = $em->GetJSVarsUsed(); $relevanceVars = implode('|',$em->GetJSVarsUsed()); $relevanceJS = $lem->em->GetJavaScriptEquivalentOfExpression(); @@ -779,7 +779,7 @@ static function GetRelevanceAndTailoringJavaScript() foreach ($undeclaredJsVars as $jsVar) { // TODO - is different type needed for text? Or process value to striphtml? - $jsParts[] = "\n"; + $jsParts[] = "\n"; } } sort($qidList,SORT_NUMERIC); @@ -910,9 +910,9 @@ static function UnitTestProcessStringContainingExpressions() static function UnitTestRelevance() { // Tests: varName~relevance~inputType~message +//info~1~expr~{info='Can strings have embedded like , or even unbalanced "quotes, \'single quoted strings\', or entities without terminal semicolons like & and <?'} $tests = <<Here is the "junk" you entered: {junk} name~1~text~What is your name? age~1~text~How old are you? @@ -963,7 +963,7 @@ static function UnitTestRelevance() { $testArg = $testArgs[$i]; $var = $testArg[0]; - LimeExpressionManager::ProcessRelevance(htmlspecialchars_decode($testArg[1]),$i,$var); + LimeExpressionManager::ProcessRelevance(htmlspecialchars_decode($testArg[1],ENT_QUOTES),$i,$var); $question = LimeExpressionManager::ProcessString($testArg[3], $i, NULL, true, 1, 1); $jsVarName='java_' . $testArg[0]; diff --git a/scripts/admin/expressions/em_javascript.js b/scripts/admin/expressions/em_javascript.js index 1a9d02a2905..a9f0ec0bdd8 100644 --- a/scripts/admin/expressions/em_javascript.js +++ b/scripts/admin/expressions/em_javascript.js @@ -152,6 +152,20 @@ function LEMbool(v) return false; } +/** + * Match even if different types - especially true vs. 1, and false vs. 0 or blank + */ +function LEMeq(a,b) +{ + if ((a==="true" && b==="1") || (a==="1" && b==="true")) { + return true; + } + if ((a==="false" && (b==="0" || b==="")) || ((a==="0" || a==="") && b ==="false")) { + return true; + } + return a==b; +} + /** * Return the value for data element jsName, treating it as blank if its question is irrelevant on the current page. * Also convert the string 'false' to '' to cope with a JavaScript type casting issue @@ -165,7 +179,8 @@ function LEMval(alias) return ''; } } - value = document.getElementById(attr.jsName).value; + // values should always be stored encoded with htmlspecialchars() + value = htmlspecialchars_decode(document.getElementById(attr.jsName).value); if (isNaN(value)) { if (value==='false') { return ''; // so Boolean operations will treat it as false. In JavaScript, Boolean("false") is true since "false" is not a zero-length string @@ -253,3 +268,1754 @@ function LEManyNA() } return false; } + +/* Functions from phpjs.org */ + +function is_bool (mixed_var) { + // Returns true if variable is a boolean + // + // version: 1107.2516 + // discuss at: http://phpjs.org/functions/is_bool + // + original by: Onno Marsman + // * example 1: is_bool(false); + // * returns 1: true + // * example 2: is_bool(0); + // * returns 2: false + return (typeof mixed_var === 'boolean'); +} + +function addslashes (str) { + // Escapes single quote, double quotes and backslash characters in a string with backslashes + // + // version: 1107.2516 + // discuss at: http://phpjs.org/functions/addslashes + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: Ates Goral (http://magnetiq.com) + // + improved by: marrtins + // + improved by: Nate + // + improved by: Onno Marsman + // + input by: Denny Wardhana + // + improved by: Brett Zamir (http://brett-zamir.me) + // + improved by: Oskar Larsson Högfeldt (http://oskar-lh.name/) + // * example 1: addslashes("kevin's birthday"); + // * returns 1: 'kevin\'s birthday' + return (str + '').replace(/[\\"']/g, '\\$&').replace(/\u0000/g, '\\0'); +} + +function html_entity_decode (string, quote_style) { + // Convert all HTML entities to their applicable characters + // + // version: 1107.2516 + // discuss at: http://phpjs.org/functions/html_entity_decode + // + original by: john (http://www.jd-tech.net) + // + input by: ger + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + bugfixed by: Onno Marsman + // + improved by: marc andreu + // + revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + input by: Ratheous + // + bugfixed by: Brett Zamir (http://brett-zamir.me) + // + input by: Nick Kolosov (http://sammy.ru) + // + bugfixed by: Fox + // - depends on: get_html_translation_table + // * example 1: html_entity_decode('Kevin & van Zonneveld'); + // * returns 1: 'Kevin & van Zonneveld' + // * example 2: html_entity_decode('&lt;'); + // * returns 2: '<' + var hash_map = {}, + symbol = '', + tmp_str = '', + entity = ''; + tmp_str = string.toString(); + + if (false === (hash_map = this.get_html_translation_table('HTML_ENTITIES', quote_style))) { + return false; + } + + // fix & problem + // http://phpjs.org/functions/get_html_translation_table:416#comment_97660 + delete(hash_map['&']); + hash_map['&'] = '&'; + + for (symbol in hash_map) { + entity = hash_map[symbol]; + tmp_str = tmp_str.split(entity).join(symbol); + } + tmp_str = tmp_str.split(''').join("'"); + + return tmp_str; +} + +function htmlentities (string, quote_style, charset, double_encode) { + // Convert all applicable characters to HTML entities + // + // version: 1107.2516 + // discuss at: http://phpjs.org/functions/htmlentities + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: nobbler + // + tweaked by: Jack + // + bugfixed by: Onno Marsman + // + revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + bugfixed by: Brett Zamir (http://brett-zamir.me) + // + input by: Ratheous + // + improved by: Rafał Kukawski (http://blog.kukawski.pl) + // - depends on: get_html_translation_table + // * example 1: htmlentities('Kevin & van Zonneveld'); + // * returns 1: 'Kevin & van Zonneveld' + // * example 2: htmlentities("foo'bar","ENT_QUOTES"); + // * returns 2: 'foo'bar' + var hash_map = {}, + symbol = '', + entity = '', + self = this; + string += ''; + double_encode = !!double_encode || double_encode == null; + + if (false === (hash_map = this.get_html_translation_table('HTML_ENTITIES', quote_style))) { + return false; + } + hash_map["'"] = '''; + + if (double_encode) { + for (symbol in hash_map) { + entity = hash_map[symbol]; + string = string.split(symbol).join(entity); + } + } else { + string = string.replace(/([\s\S]*?)(&(?:#\d+|#x[\da-f]+|[a-z][\da-z]*);|$)/g, function (ignore, text, entity) { + return self.htmlentities(text, quote_style, charset) + entity; + }); + } + + return string; +} + +function get_html_translation_table (table, quote_style) { + // Returns the internal translation table used by htmlspecialchars and htmlentities + // + // version: 1107.2516 + // discuss at: http://phpjs.org/functions/get_html_translation_table + // + original by: Philip Peterson + // + revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + bugfixed by: noname + // + bugfixed by: Alex + // + bugfixed by: Marco + // + bugfixed by: madipta + // + improved by: KELAN + // + improved by: Brett Zamir (http://brett-zamir.me) + // + bugfixed by: Brett Zamir (http://brett-zamir.me) + // + input by: Frank Forte + // + bugfixed by: T.Wild + // + input by: Ratheous + // % note: It has been decided that we're not going to add global + // % note: dependencies to php.js, meaning the constants are not + // % note: real constants, but strings instead. Integers are also supported if someone + // % note: chooses to create the constants themselves. + // * example 1: get_html_translation_table('HTML_SPECIALCHARS'); + // * returns 1: {'"': '"', '&': '&', '<': '<', '>': '>'} + var entities = {}, + hash_map = {}, + decimal = 0, + symbol = ''; + var constMappingTable = {}, + constMappingQuoteStyle = {}; + var useTable = {}, + useQuoteStyle = {}; + + // Translate arguments + constMappingTable[0] = 'HTML_SPECIALCHARS'; + constMappingTable[1] = 'HTML_ENTITIES'; + constMappingQuoteStyle[0] = 'ENT_NOQUOTES'; + constMappingQuoteStyle[2] = 'ENT_COMPAT'; + constMappingQuoteStyle[3] = 'ENT_QUOTES'; + + useTable = !isNaN(table) ? constMappingTable[table] : table ? table.toUpperCase() : 'HTML_SPECIALCHARS'; + useQuoteStyle = !isNaN(quote_style) ? constMappingQuoteStyle[quote_style] : quote_style ? quote_style.toUpperCase() : 'ENT_COMPAT'; + + if (useTable !== 'HTML_SPECIALCHARS' && useTable !== 'HTML_ENTITIES') { + throw new Error("Table: " + useTable + ' not supported'); + // return false; + } + + entities['38'] = '&'; + if (useTable === 'HTML_ENTITIES') { + entities['160'] = ' '; + entities['161'] = '¡'; + entities['162'] = '¢'; + entities['163'] = '£'; + entities['164'] = '¤'; + entities['165'] = '¥'; + entities['166'] = '¦'; + entities['167'] = '§'; + entities['168'] = '¨'; + entities['169'] = '©'; + entities['170'] = 'ª'; + entities['171'] = '«'; + entities['172'] = '¬'; + entities['173'] = '­'; + entities['174'] = '®'; + entities['175'] = '¯'; + entities['176'] = '°'; + entities['177'] = '±'; + entities['178'] = '²'; + entities['179'] = '³'; + entities['180'] = '´'; + entities['181'] = 'µ'; + entities['182'] = '¶'; + entities['183'] = '·'; + entities['184'] = '¸'; + entities['185'] = '¹'; + entities['186'] = 'º'; + entities['187'] = '»'; + entities['188'] = '¼'; + entities['189'] = '½'; + entities['190'] = '¾'; + entities['191'] = '¿'; + entities['192'] = 'À'; + entities['193'] = 'Á'; + entities['194'] = 'Â'; + entities['195'] = 'Ã'; + entities['196'] = 'Ä'; + entities['197'] = 'Å'; + entities['198'] = 'Æ'; + entities['199'] = 'Ç'; + entities['200'] = 'È'; + entities['201'] = 'É'; + entities['202'] = 'Ê'; + entities['203'] = 'Ë'; + entities['204'] = 'Ì'; + entities['205'] = 'Í'; + entities['206'] = 'Î'; + entities['207'] = 'Ï'; + entities['208'] = 'Ð'; + entities['209'] = 'Ñ'; + entities['210'] = 'Ò'; + entities['211'] = 'Ó'; + entities['212'] = 'Ô'; + entities['213'] = 'Õ'; + entities['214'] = 'Ö'; + entities['215'] = '×'; + entities['216'] = 'Ø'; + entities['217'] = 'Ù'; + entities['218'] = 'Ú'; + entities['219'] = 'Û'; + entities['220'] = 'Ü'; + entities['221'] = 'Ý'; + entities['222'] = 'Þ'; + entities['223'] = 'ß'; + entities['224'] = 'à'; + entities['225'] = 'á'; + entities['226'] = 'â'; + entities['227'] = 'ã'; + entities['228'] = 'ä'; + entities['229'] = 'å'; + entities['230'] = 'æ'; + entities['231'] = 'ç'; + entities['232'] = 'è'; + entities['233'] = 'é'; + entities['234'] = 'ê'; + entities['235'] = 'ë'; + entities['236'] = 'ì'; + entities['237'] = 'í'; + entities['238'] = 'î'; + entities['239'] = 'ï'; + entities['240'] = 'ð'; + entities['241'] = 'ñ'; + entities['242'] = 'ò'; + entities['243'] = 'ó'; + entities['244'] = 'ô'; + entities['245'] = 'õ'; + entities['246'] = 'ö'; + entities['247'] = '÷'; + entities['248'] = 'ø'; + entities['249'] = 'ù'; + entities['250'] = 'ú'; + entities['251'] = 'û'; + entities['252'] = 'ü'; + entities['253'] = 'ý'; + entities['254'] = 'þ'; + entities['255'] = 'ÿ'; + } + + if (useQuoteStyle !== 'ENT_NOQUOTES') { + entities['34'] = '"'; + } + if (useQuoteStyle === 'ENT_QUOTES') { + entities['39'] = '''; + } + entities['60'] = '<'; + entities['62'] = '>'; + + + // ascii decimals to real symbols + for (decimal in entities) { + symbol = String.fromCharCode(decimal); + hash_map[symbol] = entities[decimal]; + } + + return hash_map; +} + +function htmlspecialchars (string, quote_style, charset, double_encode) { + // Convert special characters to HTML entities + // + // version: 1107.2516 + // discuss at: http://phpjs.org/functions/htmlspecialchars + // + original by: Mirek Slugen + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + bugfixed by: Nathan + // + bugfixed by: Arno + // + revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + bugfixed by: Brett Zamir (http://brett-zamir.me) + // + input by: Ratheous + // + input by: Mailfaker (http://www.weedem.fr/) + // + reimplemented by: Brett Zamir (http://brett-zamir.me) + // + input by: felix + // + bugfixed by: Brett Zamir (http://brett-zamir.me) + // % note 1: charset argument not supported + // * example 1: htmlspecialchars("Test", 'ENT_QUOTES'); + // * returns 1: '<a href='test'>Test</a>' + // * example 2: htmlspecialchars("ab\"c'd", ['ENT_NOQUOTES', 'ENT_QUOTES']); + // * returns 2: 'ab"c'd' + // * example 3: htmlspecialchars("my "&entity;" is still here", null, null, false); + // * returns 3: 'my "&entity;" is still here' + var optTemp = 0, + i = 0, + noquotes = false; + if (typeof quote_style === 'undefined' || quote_style === null) { + quote_style = 3; // default for PHP is 2 - using 3 as default for LimeSurvey + } + string = string.toString(); + if (double_encode !== false) { // Put this first to avoid double-encoding + string = string.replace(/&/g, '&'); + } + string = string.replace(//g, '>'); + + var OPTS = { + 'ENT_NOQUOTES': 0, + 'ENT_HTML_QUOTE_SINGLE': 1, + 'ENT_HTML_QUOTE_DOUBLE': 2, + 'ENT_COMPAT': 2, + 'ENT_QUOTES': 3, + 'ENT_IGNORE': 4 + }; + if (quote_style === 0) { + noquotes = true; + } + if (typeof quote_style !== 'number') { // Allow for a single string or an array of string flags + quote_style = [].concat(quote_style); + for (i = 0; i < quote_style.length; i++) { + // Resolve string input to bitwise e.g. 'ENT_IGNORE' becomes 4 + if (OPTS[quote_style[i]] === 0) { + noquotes = true; + } + else if (OPTS[quote_style[i]]) { + optTemp = optTemp | OPTS[quote_style[i]]; + } + } + quote_style = optTemp; + } + if (quote_style & OPTS.ENT_HTML_QUOTE_SINGLE) { + string = string.replace(/'/g, '''); + } + if (!noquotes) { + string = string.replace(/"/g, '"'); + } + + return string; +} + +function htmlspecialchars_decode (string, quote_style) { + // Convert special HTML entities back to characters + // + // version: 1107.2516 + // discuss at: http://phpjs.org/functions/htmlspecialchars_decode + // + original by: Mirek Slugen + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + bugfixed by: Mateusz "loonquawl" Zalega + // + input by: ReverseSyntax + // + input by: Slawomir Kaniecki + // + input by: Scott Cariss + // + input by: Francois + // + bugfixed by: Onno Marsman + // + revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + bugfixed by: Brett Zamir (http://brett-zamir.me) + // + input by: Ratheous + // + input by: Mailfaker (http://www.weedem.fr/) + // + reimplemented by: Brett Zamir (http://brett-zamir.me) + // + bugfixed by: Brett Zamir (http://brett-zamir.me) + // * example 1: htmlspecialchars_decode("

this -> "

", 'ENT_NOQUOTES'); + // * returns 1: '

this -> "

' + // * example 2: htmlspecialchars_decode("&quot;"); + // * returns 2: '"' + var optTemp = 0, + i = 0, + noquotes = false; + if (typeof quote_style === 'undefined') { + quote_style = 3; // default for PHP is 2 - using 3 as default for LimeSurvey + } + string = string.toString().replace(/</g, '<').replace(/>/g, '>'); + var OPTS = { + 'ENT_NOQUOTES': 0, + 'ENT_HTML_QUOTE_SINGLE': 1, + 'ENT_HTML_QUOTE_DOUBLE': 2, + 'ENT_COMPAT': 2, + 'ENT_QUOTES': 3, + 'ENT_IGNORE': 4 + }; + if (quote_style === 0) { + noquotes = true; + } + if (typeof quote_style !== 'number') { // Allow for a single string or an array of string flags + quote_style = [].concat(quote_style); + for (i = 0; i < quote_style.length; i++) { + // Resolve string input to bitwise e.g. 'PATHINFO_EXTENSION' becomes 4 + if (OPTS[quote_style[i]] === 0) { + noquotes = true; + } else if (OPTS[quote_style[i]]) { + optTemp = optTemp | OPTS[quote_style[i]]; + } + } + quote_style = optTemp; + } + if (quote_style & OPTS.ENT_HTML_QUOTE_SINGLE) { + string = string.replace(/�*39;/g, "'"); // PHP doesn't currently escape if more than one 0, but it should + // string = string.replace(/'|�*27;/g, "'"); // This would also be useful here, but not a part of PHP + } + if (!noquotes) { + string = string.replace(/"/g, '"'); + } + // Put this in last place to avoid escape being double-decoded + string = string.replace(/&/g, '&'); + + return string; +} + +function ltrim (str, charlist) { + // Strips whitespace from the beginning of a string + // + // version: 1107.2516 + // discuss at: http://phpjs.org/functions/ltrim + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + input by: Erkekjetter + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + bugfixed by: Onno Marsman + // * example 1: ltrim(' Kevin van Zonneveld '); + // * returns 1: 'Kevin van Zonneveld ' + charlist = !charlist ? ' \\s\u00A0' : (charlist + '').replace(/([\[\]\(\)\.\?\/\*\{\}\+\$\^\:])/g, '$1'); + var re = new RegExp('^[' + charlist + ']+', 'g'); + return (str + '').replace(re, ''); +} + +function nl2br (str, is_xhtml) { + // Converts newlines to HTML line breaks + // + // version: 1107.2516 + // discuss at: http://phpjs.org/functions/nl2br + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: Philip Peterson + // + improved by: Onno Marsman + // + improved by: Atli Þór + // + bugfixed by: Onno Marsman + // + input by: Brett Zamir (http://brett-zamir.me) + // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: Brett Zamir (http://brett-zamir.me) + // + improved by: Maximusya + // * example 1: nl2br('Kevin\nvan\nZonneveld'); + // * returns 1: 'Kevin\nvan\nZonneveld' + // * example 2: nl2br("\nOne\nTwo\n\nThree\n", false); + // * returns 2: '
\nOne
\nTwo
\n
\nThree
\n' + // * example 3: nl2br("\nOne\nTwo\n\nThree\n", true); + // * returns 3: '\nOne\nTwo\n\nThree\n' + var breakTag = (is_xhtml || typeof is_xhtml === 'undefined') ? '' : '
'; + + return (str + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + breakTag + '$2'); +} + +function number_format (number, decimals, dec_point, thousands_sep) { + // http://kevin.vanzonneveld.net + // + original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com) + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + bugfix by: Michael White (http://getsprink.com) + // + bugfix by: Benjamin Lupton + // + bugfix by: Allan Jensen (http://www.winternet.no) + // + revised by: Jonas Raoni Soares Silva (http://www.jsfromhell.com) + // + bugfix by: Howard Yeend + // + revised by: Luke Smith (http://lucassmith.name) + // + bugfix by: Diogo Resende + // + bugfix by: Rival + // + input by: Kheang Hok Chin (http://www.distantia.ca/) + // + improved by: davook + // + improved by: Brett Zamir (http://brett-zamir.me) + // + input by: Jay Klehr + // + improved by: Brett Zamir (http://brett-zamir.me) + // + input by: Amir Habibi (http://www.residence-mixte.com/) + // + bugfix by: Brett Zamir (http://brett-zamir.me) + // + improved by: Theriault + // + input by: Amirouche + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // * example 1: number_format(1234.56); + // * returns 1: '1,235' + // * example 2: number_format(1234.56, 2, ',', ' '); + // * returns 2: '1 234,56' + // * example 3: number_format(1234.5678, 2, '.', ''); + // * returns 3: '1234.57' + // * example 4: number_format(67, 2, ',', '.'); + // * returns 4: '67,00' + // * example 5: number_format(1000); + // * returns 5: '1,000' + // * example 6: number_format(67.311, 2); + // * returns 6: '67.31' + // * example 7: number_format(1000.55, 1); + // * returns 7: '1,000.6' + // * example 8: number_format(67000, 5, ',', '.'); + // * returns 8: '67.000,00000' + // * example 9: number_format(0.9, 0); + // * returns 9: '1' + // * example 10: number_format('1.20', 2); + // * returns 10: '1.20' + // * example 11: number_format('1.20', 4); + // * returns 11: '1.2000' + // * example 12: number_format('1.2000', 3); + // * returns 12: '1.200' + // * example 13: number_format('1 000,50', 2, '.', ' '); + // * returns 13: '100 050.00' + // Strip all characters but numerical ones. + number = (number + '').replace(/[^0-9+\-Ee.]/g, ''); + var n = !isFinite(+number) ? 0 : +number, + prec = !isFinite(+decimals) ? 0 : Math.abs(decimals), + sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep, + dec = (typeof dec_point === 'undefined') ? '.' : dec_point, + s = '', + toFixedFix = function (n, prec) { + var k = Math.pow(10, prec); + return '' + Math.round(n * k) / k; + }; + // Fix for IE parseFloat(0.55).toFixed(0) = 0; + s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.'); + if (s[0].length > 3) { + s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep); + } + if ((s[1] || '').length < prec) { + s[1] = s[1] || ''; + s[1] += new Array(prec - s[1].length + 1).join('0'); + } + return s.join(dec); +} + +function quoted_printable_decode (str) { + // Convert a quoted-printable string to an 8 bit string + // + // version: 1107.2516 + // discuss at: http://phpjs.org/functions/quoted_printable_decode + // + original by: Ole Vrijenhoek + // + bugfixed by: Brett Zamir (http://brett-zamir.me) + // + reimplemented by: Theriault + // + improved by: Brett Zamir (http://brett-zamir.me) + // + bugfixed by: Theriault + // * example 1: quoted_printable_decode('a=3Db=3Dc'); + // * returns 1: 'a=b=c' + // * example 2: quoted_printable_decode('abc =20\r\n123 =20\r\n'); + // * returns 2: 'abc \r\n123 \r\n' + // * example 3: quoted_printable_decode('012345678901234567890123456789012345678901234567890123456789012345678901234=\r\n56789'); + // * returns 3: '01234567890123456789012345678901234567890123456789012345678901234567890123456789' + // * example 4: quoted_printable_decode("Lorem ipsum dolor sit amet=23, consectetur adipisicing elit"); + // * returns 4: Lorem ipsum dolor sit amet#, consectetur adipisicing elit + // Removes softline breaks + var RFC2045Decode1 = /=\r\n/gm, + // Decodes all equal signs followed by two hex digits + RFC2045Decode2IN = /=([0-9A-F]{2})/gim, + // the RFC states against decoding lower case encodings, but following apparent PHP behavior + // RFC2045Decode2IN = /=([0-9A-F]{2})/gm, + RFC2045Decode2OUT = function (sMatch, sHex) { + return String.fromCharCode(parseInt(sHex, 16)); + }; + return str.replace(RFC2045Decode1, '').replace(RFC2045Decode2IN, RFC2045Decode2OUT); +} + +function quoted_printable_encode (str) { + // + original by: Theriault + // + improved by: Brett Zamir (http://brett-zamir.me) + // + improved by: Theriault + // * example 1: quoted_printable_encode('a=b=c'); + // * returns 1: 'a=3Db=3Dc' + // * example 2: quoted_printable_encode('abc \r\n123 \r\n'); + // * returns 2: 'abc =20\r\n123 =20\r\n' + // * example 3: quoted_printable_encode('0123456789012345678901234567890123456789012345678901234567890123456789012345'); + // * returns 3: '012345678901234567890123456789012345678901234567890123456789012345678901234=\r\n5' + // RFC 2045: 6.7.2: Octets with decimal values of 33 through 60 (bang to less-than) inclusive, and 62 through 126 (greater-than to tilde), inclusive, MAY be represented as the US-ASCII characters + // PHP does not encode any of the above; as does this function. + // RFC 2045: 6.7.3: Octets with values of 9 and 32 MAY be represented as US-ASCII TAB (HT) and SPACE characters, respectively, but MUST NOT be so represented at the end of an encoded line + // PHP does not encode spaces (octet 32) except before a CRLF sequence as stated above. PHP always encodes tabs (octet 9). This function replicates PHP. + // RFC 2045: 6.7.4: A line break in a text body, represented as a CRLF sequence in the text canonical form, must be represented by a (RFC 822) line break + // PHP does not encode a CRLF sequence, as does this function. + // RFC 2045: 6.7.5: The Quoted-Printable encoding REQUIRES that encoded lines be no more than 76 characters long. If longer lines are to be encoded with the Quoted-Printable encoding, "soft" line breaks must be used. + // PHP breaks lines greater than 76 characters; as does this function. + var hexChars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'], + RFC2045Encode1IN = / \r\n|\r\n|[^!-<>-~ ]/gm, + RFC2045Encode1OUT = function (sMatch) { + // Encode space before CRLF sequence to prevent spaces from being stripped + // Keep hard line breaks intact; CRLF sequences + if (sMatch.length > 1) { + return sMatch.replace(' ', '=20'); + } + // Encode matching character + var chr = sMatch.charCodeAt(0); + return '=' + hexChars[((chr >>> 4) & 15)] + hexChars[(chr & 15)]; + }, + // Split lines to 75 characters; the reason it's 75 and not 76 is because softline breaks are preceeded by an equal sign; which would be the 76th character. + // However, if the last line/string was exactly 76 characters, then a softline would not be needed. PHP currently softbreaks anyway; so this function replicates PHP. + RFC2045Encode2IN = /.{1,72}(?!\r\n)[^=]{0,3}/g, + RFC2045Encode2OUT = function (sMatch) { + if (sMatch.substr(sMatch.length - 2) === '\r\n') { + return sMatch; + } + return sMatch + '=\r\n'; + }; + str = str.replace(RFC2045Encode1IN, RFC2045Encode1OUT).replace(RFC2045Encode2IN, RFC2045Encode2OUT); + // Strip last softline break + return str.substr(0, str.length - 3); +} + +function quotemeta (str) { + // Quotes meta characters + // + // version: 1107.2516 + // discuss at: http://phpjs.org/functions/quotemeta + // + original by: Paulo Freitas + // * example 1: quotemeta(". + * ? ^ ( $ )"); + // * returns 1: '\. \+ \* \? \^ \( \$ \)' + return (str + '').replace(/([\.\\\+\*\?\[\^\]\$\(\)])/g, '\\$1'); +} + +function rtrim (str, charlist) { + // Removes trailing whitespace + // + // version: 1107.2516 + // discuss at: http://phpjs.org/functions/rtrim + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + input by: Erkekjetter + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + bugfixed by: Onno Marsman + // + input by: rem + // + bugfixed by: Brett Zamir (http://brett-zamir.me) + // * example 1: rtrim(' Kevin van Zonneveld '); + // * returns 1: ' Kevin van Zonneveld' + charlist = !charlist ? ' \\s\u00A0' : (charlist + '').replace(/([\[\]\(\)\.\?\/\*\{\}\+\$\^\:])/g, '\\$1'); + var re = new RegExp('[' + charlist + ']+$', 'g'); + return (str + '').replace(re, ''); +} + +function sprintf () { + // Return a formatted string + // + // version: 1107.2516 + // discuss at: http://phpjs.org/functions/sprintf + // + original by: Ash Searle (http://hexmen.com/blog/) + // + namespaced by: Michael White (http://getsprink.com) + // + tweaked by: Jack + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + input by: Paulo Freitas + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + input by: Brett Zamir (http://brett-zamir.me) + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // * example 1: sprintf("%01.2f", 123.1); + // * returns 1: 123.10 + // * example 2: sprintf("[%10s]", 'monkey'); + // * returns 2: '[ monkey]' + // * example 3: sprintf("[%'#10s]", 'monkey'); + // * returns 3: '[####monkey]' + var regex = /%%|%(\d+\$)?([-+\'#0 ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([scboxXuidfegEG])/g; + var a = arguments, + i = 0, + format = a[i++]; + + // pad() + var pad = function (str, len, chr, leftJustify) { + if (!chr) { + chr = ' '; + } + var padding = (str.length >= len) ? '' : Array(1 + len - str.length >>> 0).join(chr); + return leftJustify ? str + padding : padding + str; + }; + + // justify() + var justify = function (value, prefix, leftJustify, minWidth, zeroPad, customPadChar) { + var diff = minWidth - value.length; + if (diff > 0) { + if (leftJustify || !zeroPad) { + value = pad(value, minWidth, customPadChar, leftJustify); + } else { + value = value.slice(0, prefix.length) + pad('', diff, '0', true) + value.slice(prefix.length); + } + } + return value; + }; + + // formatBaseX() + var formatBaseX = function (value, base, prefix, leftJustify, minWidth, precision, zeroPad) { + // Note: casts negative numbers to positive ones + var number = value >>> 0; + prefix = prefix && number && { + '2': '0b', + '8': '0', + '16': '0x' + }[base] || ''; + value = prefix + pad(number.toString(base), precision || 0, '0', false); + return justify(value, prefix, leftJustify, minWidth, zeroPad); + }; + + // formatString() + var formatString = function (value, leftJustify, minWidth, precision, zeroPad, customPadChar) { + if (precision != null) { + value = value.slice(0, precision); + } + return justify(value, '', leftJustify, minWidth, zeroPad, customPadChar); + }; + + // doFormat() + var doFormat = function (substring, valueIndex, flags, minWidth, _, precision, type) { + var number; + var prefix; + var method; + var textTransform; + var value; + + if (substring == '%%') { + return '%'; + } + + // parse flags + var leftJustify = false, + positivePrefix = '', + zeroPad = false, + prefixBaseX = false, + customPadChar = ' '; + var flagsl = flags.length; + for (var j = 0; flags && j < flagsl; j++) { + switch (flags.charAt(j)) { + case ' ': + positivePrefix = ' '; + break; + case '+': + positivePrefix = '+'; + break; + case '-': + leftJustify = true; + break; + case "'": + customPadChar = flags.charAt(j + 1); + break; + case '0': + zeroPad = true; + break; + case '#': + prefixBaseX = true; + break; + } + } + + // parameters may be null, undefined, empty-string or real valued + // we want to ignore null, undefined and empty-string values + if (!minWidth) { + minWidth = 0; + } else if (minWidth == '*') { + minWidth = +a[i++]; + } else if (minWidth.charAt(0) == '*') { + minWidth = +a[minWidth.slice(1, -1)]; + } else { + minWidth = +minWidth; + } + + // Note: undocumented perl feature: + if (minWidth < 0) { + minWidth = -minWidth; + leftJustify = true; + } + + if (!isFinite(minWidth)) { + throw new Error('sprintf: (minimum-)width must be finite'); + } + + if (!precision) { + precision = 'fFeE'.indexOf(type) > -1 ? 6 : (type == 'd') ? 0 : undefined; + } else if (precision == '*') { + precision = +a[i++]; + } else if (precision.charAt(0) == '*') { + precision = +a[precision.slice(1, -1)]; + } else { + precision = +precision; + } + + // grab value using valueIndex if required? + value = valueIndex ? a[valueIndex.slice(0, -1)] : a[i++]; + + switch (type) { + case 's': + return formatString(String(value), leftJustify, minWidth, precision, zeroPad, customPadChar); + case 'c': + return formatString(String.fromCharCode(+value), leftJustify, minWidth, precision, zeroPad); + case 'b': + return formatBaseX(value, 2, prefixBaseX, leftJustify, minWidth, precision, zeroPad); + case 'o': + return formatBaseX(value, 8, prefixBaseX, leftJustify, minWidth, precision, zeroPad); + case 'x': + return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad); + case 'X': + return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad).toUpperCase(); + case 'u': + return formatBaseX(value, 10, prefixBaseX, leftJustify, minWidth, precision, zeroPad); + case 'i': + case 'd': + number = (+value) | 0; + prefix = number < 0 ? '-' : positivePrefix; + value = prefix + pad(String(Math.abs(number)), precision, '0', false); + return justify(value, prefix, leftJustify, minWidth, zeroPad); + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': + number = +value; + prefix = number < 0 ? '-' : positivePrefix; + method = ['toExponential', 'toFixed', 'toPrecision']['efg'.indexOf(type.toLowerCase())]; + textTransform = ['toString', 'toUpperCase']['eEfFgG'.indexOf(type) % 2]; + value = prefix + Math.abs(number)[method](precision); + return justify(value, prefix, leftJustify, minWidth, zeroPad)[textTransform](); + default: + return substring; + } + }; + + return format.replace(regex, doFormat); +} + +function str_pad (input, pad_length, pad_string, pad_type) { + // Returns input string padded on the left or right to specified length with pad_string + // + // version: 1107.2516 + // discuss at: http://phpjs.org/functions/str_pad + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + namespaced by: Michael White (http://getsprink.com) + // + input by: Marco van Oort + // + bugfixed by: Brett Zamir (http://brett-zamir.me) + // * example 1: str_pad('Kevin van Zonneveld', 30, '-=', 'STR_PAD_LEFT'); + // * returns 1: '-=-=-=-=-=-Kevin van Zonneveld' + // * example 2: str_pad('Kevin van Zonneveld', 30, '-', 'STR_PAD_BOTH'); + // * returns 2: '------Kevin van Zonneveld-----' + var half = '', + pad_to_go; + + var str_pad_repeater = function (s, len) { + var collect = '', + i; + + while (collect.length < len) { + collect += s; + } + collect = collect.substr(0, len); + + return collect; + }; + + input += ''; + pad_string = pad_string !== undefined ? pad_string : ' '; + + if (pad_type != 'STR_PAD_LEFT' && pad_type != 'STR_PAD_RIGHT' && pad_type != 'STR_PAD_BOTH') { + pad_type = 'STR_PAD_RIGHT'; + } + if ((pad_to_go = pad_length - input.length) > 0) { + if (pad_type == 'STR_PAD_LEFT') { + input = str_pad_repeater(pad_string, pad_to_go) + input; + } else if (pad_type == 'STR_PAD_RIGHT') { + input = input + str_pad_repeater(pad_string, pad_to_go); + } else if (pad_type == 'STR_PAD_BOTH') { + half = str_pad_repeater(pad_string, Math.ceil(pad_to_go / 2)); + input = half + input + half; + input = input.substr(0, pad_length); + } + } + + return input; +} + +function str_repeat (input, multiplier) { + // Returns the input string repeat mult times + // + // version: 1107.2516 + // discuss at: http://phpjs.org/functions/str_repeat + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: Jonas Raoni Soares Silva (http://www.jsfromhell.com) + // * example 1: str_repeat('-=', 10); + // * returns 1: '-=-=-=-=-=-=-=-=-=-=' + return new Array(multiplier + 1).join(input); +} + +function strcasecmp (f_string1, f_string2) { + // Binary safe case-insensitive string comparison + // + // version: 1107.2516 + // discuss at: http://phpjs.org/functions/strcasecmp + // + original by: Martijn Wieringa + // + bugfixed by: Onno Marsman + // * example 1: strcasecmp('Hello', 'hello'); + // * returns 1: 0 + var string1 = (f_string1 + '').toLowerCase(); + var string2 = (f_string2 + '').toLowerCase(); + + if (string1 > string2) { + return 1; + } else if (string1 == string2) { + return 0; + } + + return -1; +} + +function strcmp (str1, str2) { + // Binary safe string comparison + // + // version: 1107.2516 + // discuss at: http://phpjs.org/functions/strcmp + // + original by: Waldo Malqui Silva + // + input by: Steve Hilder + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + revised by: gorthaur + // * example 1: strcmp( 'waldo', 'owald' ); + // * returns 1: 1 + // * example 2: strcmp( 'owald', 'waldo' ); + // * returns 2: -1 + return ((str1 == str2) ? 0 : ((str1 > str2) ? 1 : -1)); +} + +function strip_tags (input, allowed) { + // Strips HTML and PHP tags from a string + // + // version: 1107.2516 + // discuss at: http://phpjs.org/functions/strip_tags + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: Luke Godfrey + // + input by: Pul + // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + bugfixed by: Onno Marsman + // + input by: Alex + // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + input by: Marc Palau + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + input by: Brett Zamir (http://brett-zamir.me) + // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + bugfixed by: Eric Nagel + // + input by: Bobby Drake + // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + bugfixed by: Tomasz Wesolowski + // + input by: Evertjan Garretsen + // + revised by: Rafał Kukawski (http://blog.kukawski.pl/) + // * example 1: strip_tags('

Kevin

van Zonneveld', ''); + // * returns 1: 'Kevin van Zonneveld' + // * example 2: strip_tags('

Kevin van Zonneveld

', '

'); + // * returns 2: '

Kevin van Zonneveld

' + // * example 3: strip_tags("Kevin van Zonneveld", ""); + // * returns 3: 'Kevin van Zonneveld' + // * example 4: strip_tags('1 < 5 5 > 1'); + // * returns 4: '1 < 5 5 > 1' + // * example 5: strip_tags('1
1'); + // * returns 5: '1 1' + // * example 6: strip_tags('1
1', '
'); + // * returns 6: '1 1' + // * example 7: strip_tags('1
1', '

'); + // * returns 7: '1
1' + allowed = (((allowed || "") + "").toLowerCase().match(/<[a-z][a-z0-9]*>/g) || []).join(''); // making sure the allowed arg is a string containing only tags in lowercase () + var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi, + commentsAndPhpTags = /|<\?(?:php)?[\s\S]*?\?>/gi; + return input.replace(commentsAndPhpTags, '').replace(tags, function ($0, $1) { + return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : ''; + }); +} + +function stripslashes (str) { + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: Ates Goral (http://magnetiq.com) + // + fixed by: Mick@el + // + improved by: marrtins + // + bugfixed by: Onno Marsman + // + improved by: rezna + // + input by: Rick Waldron + // + reimplemented by: Brett Zamir (http://brett-zamir.me) + // + input by: Brant Messenger (http://www.brantmessenger.com/) + // + bugfixed by: Brett Zamir (http://brett-zamir.me) + // * example 1: stripslashes('Kevin\'s code'); + // * returns 1: "Kevin's code" + // * example 2: stripslashes('Kevin\\\'s code'); + // * returns 2: "Kevin\'s code" + return (str + '').replace(/\\(.?)/g, function (s, n1) { + switch (n1) { + case '\\': + return '\\'; + case '0': + return '\u0000'; + case '': + return ''; + default: + return n1; + } + }); +} + +function stripos (f_haystack, f_needle, f_offset) { + // Finds position of first occurrence of a string within another, case insensitive + // + // version: 1107.2516 + // discuss at: http://phpjs.org/functions/stripos + // + original by: Martijn Wieringa + // + revised by: Onno Marsman + // * example 1: stripos('ABC', 'a'); + // * returns 1: 0 + var haystack = (f_haystack + '').toLowerCase(); + var needle = (f_needle + '').toLowerCase(); + var index = 0; + + if ((index = haystack.indexOf(needle, f_offset)) !== -1) { + return index; + } + return false; +} + +function stristr (haystack, needle, bool) { + // Finds first occurrence of a string within another, case insensitive + // + // version: 1107.2516 + // discuss at: http://phpjs.org/functions/stristr + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + bugfxied by: Onno Marsman + // * example 1: stristr('Kevin van Zonneveld', 'Van'); + // * returns 1: 'van Zonneveld' + // * example 2: stristr('Kevin van Zonneveld', 'VAN', true); + // * returns 2: 'Kevin ' + var pos = 0; + + haystack += ''; + pos = haystack.toLowerCase().indexOf((needle + '').toLowerCase()); + if (pos == -1) { + return false; + } else { + if (bool) { + return haystack.substr(0, pos); + } else { + return haystack.slice(pos); + } + } +} + +function strrev (string) { + // Reverse a string + // + // version: 1107.2516 + // discuss at: http://phpjs.org/functions/strrev + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + bugfixed by: Onno Marsman + // + reimplemented by: Brett Zamir (http://brett-zamir.me) + // * example 1: strrev('Kevin van Zonneveld'); + // * returns 1: 'dlevennoZ nav niveK' + // * example 2: strrev('a\u0301haB') === 'Baha\u0301'; // combining + // * returns 2: true + // * example 3: strrev('A\uD87E\uDC04Z') === 'Z\uD87E\uDC04A'; // surrogates + // * returns 2: true + string = string + ''; + + // Performance will be enhanced with the next two lines of code commented + // out if you don't care about combining characters + // Keep Unicode combining characters together with the character preceding + // them and which they are modifying (as in PHP 6) + // See http://unicode.org/reports/tr44/#Property_Table (Me+Mn) + // We also add the low surrogate range at the beginning here so it will be + // maintained with its preceding high surrogate + var grapheme_extend = /(.)([\uDC00-\uDFFF\u0300-\u036F\u0483-\u0489\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u0610-\u061A\u064B-\u065E\u0670\u06D6-\u06DC\u06DE-\u06E4\u06E7\u06E8\u06EA-\u06ED\u0711\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F3\u0901-\u0903\u093C\u093E-\u094D\u0951-\u0954\u0962\u0963\u0981-\u0983\u09BC\u09BE-\u09C4\u09C7\u09C8\u09CB-\u09CD\u09D7\u09E2\u09E3\u0A01-\u0A03\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A70\u0A71\u0A75\u0A81-\u0A83\u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AE2\u0AE3\u0B01-\u0B03\u0B3C\u0B3E-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B62\u0B63\u0B82\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C01-\u0C03\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C82\u0C83\u0CBC\u0CBE-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CE2\u0CE3\u0D02\u0D03\u0D3E-\u0D44\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D62\u0D63\u0D82\u0D83\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EB9\u0EBB\u0EBC\u0EC8-\u0ECD\u0F18\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F71-\u0F84\u0F86\u0F87\u0F90-\u0F97\u0F99-\u0FBC\u0FC6\u102B-\u103E\u1056-\u1059\u105E-\u1060\u1062-\u1064\u1067-\u106D\u1071-\u1074\u1082-\u108D\u108F\u135F\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17B6-\u17D3\u17DD\u180B-\u180D\u18A9\u1920-\u192B\u1930-\u193B\u19B0-\u19C0\u19C8\u19C9\u1A17-\u1A1B\u1B00-\u1B04\u1B34-\u1B44\u1B6B-\u1B73\u1B80-\u1B82\u1BA1-\u1BAA\u1C24-\u1C37\u1DC0-\u1DE6\u1DFE\u1DFF\u20D0-\u20F0\u2DE0-\u2DFF\u302A-\u302F\u3099\u309A\uA66F-\uA672\uA67C\uA67D\uA802\uA806\uA80B\uA823-\uA827\uA880\uA881\uA8B4-\uA8C4\uA926-\uA92D\uA947-\uA953\uAA29-\uAA36\uAA43\uAA4C\uAA4D\uFB1E\uFE00-\uFE0F\uFE20-\uFE26]+)/g; + string = string.replace(grapheme_extend, '$2$1'); // Temporarily reverse + return string.split('').reverse().join(''); +} + +function strstr (haystack, needle, bool) { + // Finds first occurrence of a string within another + // + // version: 1107.2516 + // discuss at: http://phpjs.org/functions/strstr + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + bugfixed by: Onno Marsman + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // * example 1: strstr('Kevin van Zonneveld', 'van'); + // * returns 1: 'van Zonneveld' + // * example 2: strstr('Kevin van Zonneveld', 'van', true); + // * returns 2: 'Kevin ' + // * example 3: strstr('name@example.com', '@'); + // * returns 3: '@example.com' + // * example 4: strstr('name@example.com', '@', true); + // * returns 4: 'name' + var pos = 0; + + haystack += ''; + pos = haystack.indexOf(needle); + if (pos == -1) { + return false; + } else { + if (bool) { + return haystack.substr(0, pos); + } else { + return haystack.slice(pos); + } + } +} + +function substr (str, start, len) { + // Returns part of a string + // + // version: 909.322 + // discuss at: http://phpjs.org/functions/substr + // + original by: Martijn Wieringa + // + bugfixed by: T.Wild + // + tweaked by: Onno Marsman + // + revised by: Theriault + // + improved by: Brett Zamir (http://brett-zamir.me) + // % note 1: Handles rare Unicode characters if 'unicode.semantics' ini (PHP6) is set to 'on' + // * example 1: substr('abcdef', 0, -1); + // * returns 1: 'abcde' + // * example 2: substr(2, 0, -6); + // * returns 2: false + // * example 3: ini_set('unicode.semantics', 'on'); + // * example 3: substr('a\uD801\uDC00', 0, -1); + // * returns 3: 'a' + // * example 4: ini_set('unicode.semantics', 'on'); + // * example 4: substr('a\uD801\uDC00', 0, 2); + // * returns 4: 'a\uD801\uDC00' + // * example 5: ini_set('unicode.semantics', 'on'); + // * example 5: substr('a\uD801\uDC00', -1, 1); + // * returns 5: '\uD801\uDC00' + // * example 6: ini_set('unicode.semantics', 'on'); + // * example 6: substr('a\uD801\uDC00z\uD801\uDC00', -3, 2); + // * returns 6: '\uD801\uDC00z' + // * example 7: ini_set('unicode.semantics', 'on'); + // * example 7: substr('a\uD801\uDC00z\uD801\uDC00', -3, -1) + // * returns 7: '\uD801\uDC00z' + // Add: (?) Use unicode.runtime_encoding (e.g., with string wrapped in "binary" or "Binary" class) to + // allow access of binary (see file_get_contents()) by: charCodeAt(x) & 0xFF (see https://developer.mozilla.org/En/Using_XMLHttpRequest ) or require conversion first? + var i = 0, + allBMP = true, + es = 0, + el = 0, + se = 0, + ret = ''; + str += ''; + var end = str.length; + + // BEGIN REDUNDANT + this.php_js = this.php_js || {}; + this.php_js.ini = this.php_js.ini || {}; + // END REDUNDANT + switch ((this.php_js.ini['unicode.semantics'] && this.php_js.ini['unicode.semantics'].local_value.toLowerCase())) { + case 'on': + // Full-blown Unicode including non-Basic-Multilingual-Plane characters + // strlen() + for (i = 0; i < str.length; i++) { + if (/[\uD800-\uDBFF]/.test(str.charAt(i)) && /[\uDC00-\uDFFF]/.test(str.charAt(i + 1))) { + allBMP = false; + break; + } + } + + if (!allBMP) { + if (start < 0) { + for (i = end - 1, es = (start += end); i >= es; i--) { + if (/[\uDC00-\uDFFF]/.test(str.charAt(i)) && /[\uD800-\uDBFF]/.test(str.charAt(i - 1))) { + start--; + es--; + } + } + } else { + var surrogatePairs = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g; + while ((surrogatePairs.exec(str)) != null) { + var li = surrogatePairs.lastIndex; + if (li - 2 < start) { + start++; + } else { + break; + } + } + } + + if (start >= end || start < 0) { + return false; + } + if (len < 0) { + for (i = end - 1, el = (end += len); i >= el; i--) { + if (/[\uDC00-\uDFFF]/.test(str.charAt(i)) && /[\uD800-\uDBFF]/.test(str.charAt(i - 1))) { + end--; + el--; + } + } + if (start > end) { + return false; + } + return str.slice(start, end); + } else { + se = start + len; + for (i = start; i < se; i++) { + ret += str.charAt(i); + if (/[\uD800-\uDBFF]/.test(str.charAt(i)) && /[\uDC00-\uDFFF]/.test(str.charAt(i + 1))) { + se++; // Go one further, since one of the "characters" is part of a surrogate pair + } + } + return ret; + } + break; + } + // Fall-through + case 'off': + // assumes there are no non-BMP characters; + // if there may be such characters, then it is best to turn it on (critical in true XHTML/XML) + default: + if (start < 0) { + start += end; + } + end = typeof len === 'undefined' ? end : (len < 0 ? len + end : len + start); + // PHP returns false if start does not fall within the string. + // PHP returns false if the calculated end comes before the calculated start. + // PHP returns an empty string if start and end are the same. + // Otherwise, PHP returns the portion of the string from start to end. + return start >= str.length || start < 0 || start > end ? !1 : str.slice(start, end); + } + return undefined; // Please Netbeans +} + +function trim (str, charlist) { +// Strips whitespace from the beginning and end of a string +// +// version: 1107.2516 +// discuss at: http://phpjs.org/functions/trim +// + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) +// + improved by: mdsjack (http://www.mdsjack.bo.it) +// + improved by: Alexander Ermolaev (http://snippets.dzone.com/user/AlexanderErmolaev) +// + input by: Erkekjetter +// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) +// + input by: DxGx +// + improved by: Steven Levithan (http://blog.stevenlevithan.com) +// + tweaked by: Jack +// + bugfixed by: Onno Marsman +// * example 1: trim(' Kevin van Zonneveld '); +// * returns 1: 'Kevin van Zonneveld' +// * example 2: trim('Hello World', 'Hdle'); +// * returns 2: 'o Wor' +// * example 3: trim(16, 1); +// * returns 3: 6 +var whitespace, l = 0, +i = 0; +str += ''; + +if (!charlist) { +// default list +whitespace = " \n\r\t\f\x0b\xa0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000"; +} else { +// preg_quote custom list +charlist += ''; +whitespace = charlist.replace(/([\[\]\(\)\.\?\/\*\{\}\+\$\^\:])/g, '$1'); +} + +l = str.length; +for (i = 0; i < l; i++) { +if (whitespace.indexOf(str.charAt(i)) === -1) { +str = str.substring(i); +break; +} +} + +l = str.length; +for (i = l - 1; i >= 0; i--) { +if (whitespace.indexOf(str.charAt(i)) === -1) { +str = str.substring(0, i + 1); +break; +} +} + +return whitespace.indexOf(str.charAt(0)) === -1 ? str : ''; +} + +function ucwords (str) { + // Uppercase the first character of every word in a string + // + // version: 1107.2516 + // discuss at: http://phpjs.org/functions/ucwords + // + original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com) + // + improved by: Waldo Malqui Silva + // + bugfixed by: Onno Marsman + // + improved by: Robin + // + input by: James (http://www.james-bell.co.uk/) + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // * example 1: ucwords('kevin van zonneveld'); + // * returns 1: 'Kevin Van Zonneveld' + // * example 2: ucwords('HELLO WORLD'); + // * returns 2: 'HELLO WORLD' + return (str + '').replace(/^([a-z])|\s+([a-z])/g, function ($1) { + return $1.toUpperCase(); + }); +} + +function checkdate (m, d, y) { + // Returns true(1) if it is a valid date in gregorian calendar + // + // version: 1107.2516 + // discuss at: http://phpjs.org/functions/checkdate + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: Pyerre + // + improved by: Theriault + // * example 1: checkdate(12, 31, 2000); + // * returns 1: true + // * example 2: checkdate(2, 29, 2001); + // * returns 2: false + // * example 3: checkdate(3, 31, 2008); + // * returns 3: true + // * example 4: checkdate(1, 390, 2000); + // * returns 4: false + return m > 0 && m < 13 && y > 0 && y < 32768 && d > 0 && d <= (new Date(y, m, 0)).getDate(); +} + +function date (format, timestamp) { + // http://kevin.vanzonneveld.net + // + original by: Carlos R. L. Rodrigues (http://www.jsfromhell.com) + // + parts by: Peter-Paul Koch (http://www.quirksmode.org/js/beat.html) + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: MeEtc (http://yass.meetcweb.com) + // + improved by: Brad Touesnard + // + improved by: Tim Wiel + // + improved by: Bryan Elliott + // + // + improved by: Brett Zamir (http://brett-zamir.me) + // + improved by: David Randall + // + input by: Brett Zamir (http://brett-zamir.me) + // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: Brett Zamir (http://brett-zamir.me) + // + improved by: Brett Zamir (http://brett-zamir.me) + // + improved by: Theriault + // + derived from: gettimeofday + // + input by: majak + // + bugfixed by: majak + // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + input by: Alex + // + bugfixed by: Brett Zamir (http://brett-zamir.me) + // + improved by: Theriault + // + improved by: Brett Zamir (http://brett-zamir.me) + // + improved by: Theriault + // + improved by: Thomas Beaucourt (http://www.webapp.fr) + // + improved by: JT + // + improved by: Theriault + // + improved by: Rafał Kukawski (http://blog.kukawski.pl) + // + input by: Martin + // + input by: Alex Wilson + // % note 1: Uses global: php_js to store the default timezone + // % note 2: Although the function potentially allows timezone info (see notes), it currently does not set + // % note 2: per a timezone specified by date_default_timezone_set(). Implementers might use + // % note 2: this.php_js.currentTimezoneOffset and this.php_js.currentTimezoneDST set by that function + // % note 2: in order to adjust the dates in this function (or our other date functions!) accordingly + // * example 1: date('H:m:s \\m \\i\\s \\m\\o\\n\\t\\h', 1062402400); + // * returns 1: '09:09:40 m is month' + // * example 2: date('F j, Y, g:i a', 1062462400); + // * returns 2: 'September 2, 2003, 2:26 am' + // * example 3: date('Y W o', 1062462400); + // * returns 3: '2003 36 2003' + // * example 4: x = date('Y m d', (new Date()).getTime()/1000); + // * example 4: (x+'').length == 10 // 2009 01 09 + // * returns 4: true + // * example 5: date('W', 1104534000); + // * returns 5: '53' + // * example 6: date('B t', 1104534000); + // * returns 6: '999 31' + // * example 7: date('W U', 1293750000.82); // 2010-12-31 + // * returns 7: '52 1293750000' + // * example 8: date('W', 1293836400); // 2011-01-01 + // * returns 8: '52' + // * example 9: date('W Y-m-d', 1293974054); // 2011-01-02 + // * returns 9: '52 2011-01-02' + var that = this, + jsdate, f, formatChr = /\\?([a-z])/gi, + formatChrCb, + // Keep this here (works, but for code commented-out + // below for file size reasons) + //, tal= [], + _pad = function (n, c) { + if ((n = n + '').length < c) { + return new Array((++c) - n.length).join('0') + n; + } + return n; + }, + txt_words = ["Sun", "Mon", "Tues", "Wednes", "Thurs", "Fri", "Satur", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; + formatChrCb = function (t, s) { + return f[t] ? f[t]() : s; + }; + f = { + // Day + d: function () { // Day of month w/leading 0; 01..31 + return _pad(f.j(), 2); + }, + D: function () { // Shorthand day name; Mon...Sun + return f.l().slice(0, 3); + }, + j: function () { // Day of month; 1..31 + return jsdate.getDate(); + }, + l: function () { // Full day name; Monday...Sunday + return txt_words[f.w()] + 'day'; + }, + N: function () { // ISO-8601 day of week; 1[Mon]..7[Sun] + return f.w() || 7; + }, + S: function () { // Ordinal suffix for day of month; st, nd, rd, th + var j = f.j(); + return j > 4 || j < 21 ? 'th' : {1: 'st', 2: 'nd', 3: 'rd'}[j % 10] || 'th'; + }, + w: function () { // Day of week; 0[Sun]..6[Sat] + return jsdate.getDay(); + }, + z: function () { // Day of year; 0..365 + var a = new Date(f.Y(), f.n() - 1, f.j()), + b = new Date(f.Y(), 0, 1); + return Math.round((a - b) / 864e5) + 1; + }, + + // Week + W: function () { // ISO-8601 week number + var a = new Date(f.Y(), f.n() - 1, f.j() - f.N() + 3), + b = new Date(a.getFullYear(), 0, 4); + return _pad(1 + Math.round((a - b) / 864e5 / 7), 2); + }, + + // Month + F: function () { // Full month name; January...December + return txt_words[6 + f.n()]; + }, + m: function () { // Month w/leading 0; 01...12 + return _pad(f.n(), 2); + }, + M: function () { // Shorthand month name; Jan...Dec + return f.F().slice(0, 3); + }, + n: function () { // Month; 1...12 + return jsdate.getMonth() + 1; + }, + t: function () { // Days in month; 28...31 + return (new Date(f.Y(), f.n(), 0)).getDate(); + }, + + // Year + L: function () { // Is leap year?; 0 or 1 + return new Date(f.Y(), 1, 29).getMonth() === 1 | 0; + }, + o: function () { // ISO-8601 year + var n = f.n(), + W = f.W(), + Y = f.Y(); + return Y + (n === 12 && W < 9 ? -1 : n === 1 && W > 9); + }, + Y: function () { // Full year; e.g. 1980...2010 + return jsdate.getFullYear(); + }, + y: function () { // Last two digits of year; 00...99 + return (f.Y() + "").slice(-2); + }, + + // Time + a: function () { // am or pm + return jsdate.getHours() > 11 ? "pm" : "am"; + }, + A: function () { // AM or PM + return f.a().toUpperCase(); + }, + B: function () { // Swatch Internet time; 000..999 + var H = jsdate.getUTCHours() * 36e2, + // Hours + i = jsdate.getUTCMinutes() * 60, + // Minutes + s = jsdate.getUTCSeconds(); // Seconds + return _pad(Math.floor((H + i + s + 36e2) / 86.4) % 1e3, 3); + }, + g: function () { // 12-Hours; 1..12 + return f.G() % 12 || 12; + }, + G: function () { // 24-Hours; 0..23 + return jsdate.getHours(); + }, + h: function () { // 12-Hours w/leading 0; 01..12 + return _pad(f.g(), 2); + }, + H: function () { // 24-Hours w/leading 0; 00..23 + return _pad(f.G(), 2); + }, + i: function () { // Minutes w/leading 0; 00..59 + return _pad(jsdate.getMinutes(), 2); + }, + s: function () { // Seconds w/leading 0; 00..59 + return _pad(jsdate.getSeconds(), 2); + }, + u: function () { // Microseconds; 000000-999000 + return _pad(jsdate.getMilliseconds() * 1000, 6); + }, + + // Timezone + e: function () { // Timezone identifier; e.g. Atlantic/Azores, ... + // The following works, but requires inclusion of the very large + // timezone_abbreviations_list() function. +/* return this.date_default_timezone_get(); +*/ + throw 'Not supported (see source code of date() for timezone on how to add support)'; + }, + I: function () { // DST observed?; 0 or 1 + // Compares Jan 1 minus Jan 1 UTC to Jul 1 minus Jul 1 UTC. + // If they are not equal, then DST is observed. + var a = new Date(f.Y(), 0), + // Jan 1 + c = Date.UTC(f.Y(), 0), + // Jan 1 UTC + b = new Date(f.Y(), 6), + // Jul 1 + d = Date.UTC(f.Y(), 6); // Jul 1 UTC + return 0 + ((a - c) !== (b - d)); + }, + O: function () { // Difference to GMT in hour format; e.g. +0200 + var a = jsdate.getTimezoneOffset(); + return (a > 0 ? "-" : "+") + _pad(Math.abs(a / 60 * 100), 4); + }, + P: function () { // Difference to GMT w/colon; e.g. +02:00 + var O = f.O(); + return (O.substr(0, 3) + ":" + O.substr(3, 2)); + }, + T: function () { // Timezone abbreviation; e.g. EST, MDT, ... + // The following works, but requires inclusion of the very + // large timezone_abbreviations_list() function. +/* var abbr = '', i = 0, os = 0, default = 0; + if (!tal.length) { + tal = that.timezone_abbreviations_list(); + } + if (that.php_js && that.php_js.default_timezone) { + default = that.php_js.default_timezone; + for (abbr in tal) { + for (i=0; i < tal[abbr].length; i++) { + if (tal[abbr][i].timezone_id === default) { + return abbr.toUpperCase(); + } + } + } + } + for (abbr in tal) { + for (i = 0; i < tal[abbr].length; i++) { + os = -jsdate.getTimezoneOffset() * 60; + if (tal[abbr][i].offset === os) { + return abbr.toUpperCase(); + } + } + } +*/ + return 'UTC'; + }, + Z: function () { // Timezone offset in seconds (-43200...50400) + return -jsdate.getTimezoneOffset() * 60; + }, + + // Full Date/Time + c: function () { // ISO-8601 date. + return 'Y-m-d\\Th:i:sP'.replace(formatChr, formatChrCb); + }, + r: function () { // RFC 2822 + return 'D, d M Y H:i:s O'.replace(formatChr, formatChrCb); + }, + U: function () { // Seconds since UNIX epoch + return jsdate.getTime() / 1000 | 0; + } + }; + this.date = function (format, timestamp) { + that = this; + jsdate = ((typeof timestamp === 'undefined') ? new Date() : // Not provided + (timestamp instanceof Date) ? new Date(timestamp) : // JS Date() + new Date(timestamp * 1000) // UNIX timestamp (auto-convert to int) + ); + return format.replace(formatChr, formatChrCb); + }; + return this.date(format, timestamp); +} + +function gmdate (format, timestamp) { + // Format a GMT date/time + // + // version: 1107.2516 + // discuss at: http://phpjs.org/functions/gmdate + // + original by: Brett Zamir (http://brett-zamir.me) + // + input by: Alex + // + bugfixed by: Brett Zamir (http://brett-zamir.me) + // - depends on: date + // * example 1: gmdate('H:m:s \\m \\i\\s \\m\\o\\n\\t\\h', 1062402400); // Return will depend on your timezone + // * returns 1: '07:09:40 m is month' + var dt = typeof timestamp === 'undefined' ? new Date() : // Not provided + typeof timestamp === 'object' ? new Date(timestamp) : // Javascript Date() + new Date(timestamp * 1000); // UNIX timestamp (auto-convert to int) + timestamp = Date.parse(dt.toUTCString().slice(0, -4)) / 1000; + return this.date(format, timestamp); +} + +function idate (format, timestamp) { + // Format a local time/date as integer + // + // version: 1107.2516 + // discuss at: http://phpjs.org/functions/idate + // + original by: Brett Zamir (http://brett-zamir.me) + // + input by: Alex + // + bugfixed by: Brett Zamir (http://brett-zamir.me) + // + improved by: Theriault + // + derived from: date + // + derived from: gettimeofday + // * example 1: idate('y'); + // * returns 1: 9 + if (format === undefined) { + throw 'idate() expects at least 1 parameter, 0 given'; + } + if (!format.length || format.length > 1) { + throw 'idate format is one char'; + } + + // Fix: Need to allow date_default_timezone_set() (check for this.php_js.default_timezone and use) + var date = ((typeof timestamp === 'undefined') ? new Date() : // Not provided + (timestamp instanceof Date) ? new Date(timestamp) : // Javascript Date() + new Date(timestamp * 1000) // UNIX timestamp (auto-convert to int) + ), + a; + + switch (format) { + case 'B': + return Math.floor(((date.getUTCHours() * 36e2) + (date.getUTCMinutes() * 60) + date.getUTCSeconds() + 36e2) / 86.4) % 1e3; + case 'd': + return date.getDate(); + case 'h': + return date.getHours() % 12 || 12; + case 'H': + return date.getHours(); + case 'i': + return date.getMinutes(); + case 'I': + // capital 'i' + // Logic derived from getimeofday(). + // Compares Jan 1 minus Jan 1 UTC to Jul 1 minus Jul 1 UTC. + // If they are not equal, then DST is observed. + a = date.getFullYear(); + return 0 + (((new Date(a, 0)) - Date.UTC(a, 0)) !== ((new Date(a, 6)) - Date.UTC(a, 6))); + case 'L': + a = date.getFullYear(); + return (!(a & 3) && (a % 1e2 || !(a % 4e2))) ? 1 : 0; + case 'm': + return date.getMonth() + 1; + case 's': + return date.getSeconds(); + case 't': + return (new Date(date.getFullYear(), date.getMonth() + 1, 0)).getDate(); + case 'U': + return Math.round(date.getTime() / 1000); + case 'w': + return date.getDay(); + case 'W': + a = new Date(date.getFullYear(), date.getMonth(), date.getDate() - (date.getDay() || 7) + 3); + return 1 + Math.round((a - (new Date(a.getFullYear(), 0, 4))) / 864e5 / 7); + case 'y': + return parseInt((date.getFullYear() + '').slice(2), 10); // This function returns an integer, unlike date() + case 'Y': + return date.getFullYear(); + case 'z': + return Math.floor((date - new Date(date.getFullYear(), 0, 1)) / 864e5); + case 'Z': + return -date.getTimezoneOffset() * 60; + default: + throw 'Unrecognized date format token'; + } +} + +function mktime () { + // Get UNIX timestamp for a date + // + // version: 1107.2516 + // discuss at: http://phpjs.org/functions/mktime + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: baris ozdil + // + input by: gabriel paderni + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: FGFEmperor + // + input by: Yannoo + // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + input by: jakes + // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + bugfixed by: Marc Palau + // + improved by: Brett Zamir (http://brett-zamir.me) + // + input by: 3D-GRAF + // + bugfixed by: Brett Zamir (http://brett-zamir.me) + // + input by: Chris + // + revised by: Theriault + // % note 1: The return values of the following examples are + // % note 1: received only if your system's timezone is UTC. + // * example 1: mktime(14, 10, 2, 2, 1, 2008); + // * returns 1: 1201875002 + // * example 2: mktime(0, 0, 0, 0, 1, 2008); + // * returns 2: 1196467200 + // * example 3: make = mktime(); + // * example 3: td = new Date(); + // * example 3: real = Math.floor(td.getTime() / 1000); + // * example 3: diff = (real - make); + // * results 3: diff < 5 + // * example 4: mktime(0, 0, 0, 13, 1, 1997) + // * returns 4: 883612800 + // * example 5: mktime(0, 0, 0, 1, 1, 1998) + // * returns 5: 883612800 + // * example 6: mktime(0, 0, 0, 1, 1, 98) + // * returns 6: 883612800 + // * example 7: mktime(23, 59, 59, 13, 0, 2010) + // * returns 7: 1293839999 + // * example 8: mktime(0, 0, -1, 1, 1, 1970) + // * returns 8: -1 + var d = new Date(), + r = arguments, + i = 0, + e = ['Hours', 'Minutes', 'Seconds', 'Month', 'Date', 'FullYear']; + + for (i = 0; i < e.length; i++) { + if (typeof r[i] === 'undefined') { + r[i] = d['get' + e[i]](); + r[i] += (i === 3); // +1 to fix JS months. + } else { + r[i] = parseInt(r[i], 10); + if (isNaN(r[i])) { + return false; + } + } + } + + // Map years 0-69 to 2000-2069 and years 70-100 to 1970-2000. + r[5] += (r[5] >= 0 ? (r[5] <= 69 ? 2e3 : (r[5] <= 100 ? 1900 : 0)) : 0); + + // Set year, month (-1 to fix JS months), and date. + // !This must come before the call to setHours! + d.setFullYear(r[5], r[3] - 1, r[4]); + + // Set hours, minutes, and seconds. + d.setHours(r[0], r[1], r[2]); + + // Divide milliseconds by 1000 to return seconds and drop decimal. + // Add 1 second if negative or it'll be off from PHP by 1 second. + return (d.getTime() / 1e3 >> 0) - (d.getTime() < 0); +} + +function time () { + // Return current UNIX timestamp + // + // version: 1107.2516 + // discuss at: http://phpjs.org/functions/time + // + original by: GeekFG (http://geekfg.blogspot.com) + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: metjay + // + improved by: HKM + // * example 1: timeStamp = time(); + // * results 1: timeStamp > 1000000000 && timeStamp < 2000000000 + return Math.floor(new Date().getTime() / 1000); +} \ No newline at end of file