summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--auto_prepend.php12
-rw-r--r--it.class69
-rw-r--r--it_dbi.class6
-rw-r--r--it_debug.class6
-rw-r--r--it_html.class6
-rw-r--r--it_pipe.class16
-rw-r--r--it_text.class1
-rw-r--r--it_url.class8
-rw-r--r--it_xml.class3
-rwxr-xr-xtest/exec.t2
-rwxr-xr-xtest/getopt.t3
-rwxr-xr-xtest/it.t54
-rwxr-xr-xtest/it_dbi.t37
-rw-r--r--test/it_url.testserver.php2
-rwxr-xr-xtest/it_xml.t4
15 files changed, 132 insertions, 97 deletions
diff --git a/auto_prepend.php b/auto_prepend.php
index 19108fb..8d0a94e 100644
--- a/auto_prepend.php
+++ b/auto_prepend.php
@@ -63,8 +63,8 @@ function EDX(...$args)
* Return a text in the selected language
* Replaces variables of the form {var} with quoted values from argument $values
* @param $label Label of text to return
- * @param $language Optional value array or language string (will be sent through Q())
- * @param $values Optional value array or language string (will be sent through Q())
+ * @param $language Optional value array (will be sent through Q()) or language string
+ * @param $values Optional value array (will be sent through Q()) or language string
* @return Localized text string
*/
function T($label, $language = null, $values = null)
@@ -177,14 +177,6 @@ function debug($text, $level=0)
}
/**
- * Convert a htmlentities-encoded string back to normal
- */
-function it_htmlentities_decode($string)
-{
- return strtr($string, array_flip(get_html_translation_table(HTML_ENTITIES)));
-}
-
-/**
* Clone an object and return copy, works for all PHP versions
*/
function &it_clone(&$object)
diff --git a/it.class b/it.class
index 4856a3c..ed08f95 100644
--- a/it.class
+++ b/it.class
@@ -123,21 +123,27 @@ static function timerlog($label = '')
/**
* If display_errors is on or stdout is a tty, shows error in page or on stdout respectively
* If display_errors is off, mails (with rate limiting) diagnostics to .diffnotice addresses or file owner or SERVER_ADMIN
- * @param $p either error title or assoc array of params, see below
- * @param $p['title'] error title, one line. also accepted in $p[0] (with priority). false means ignore error
- * @param $p['body'] error body: multiline string or any data type (will be dumped)
- * @param $p['to'] comma separated recipient list
- * @param $p['id'] id of error, used with timewindow, defaults to file and line of caller
- * @param $p['graceperiod'] in seconds. deprecated, see $p['timewindow']
- * @param $p['timewindow'] in secs. "5-35" means for an notice to be sent, a second error must occur 5 to 35 seconds after first err
- * @param $p['blockmailid'] block mail for $p['blockmail'] seconds with same id. Default: $p['to']
- * @param $p['blockmail'] number of seconds to block mails after having sent a mail [3600]
- * @param $p['backtraceskip'] number of stack levels to drop
- * @param $p['skipfiles'] files to skip in backtrace
- * @param $p['okstate'] give current ok label and ok state, e.g. telresult=1 for working. see failcount
- * @param $p['failcount'] give number of consecutive okstate failures needed for creating an error [2]
- * @param $p['omitdebuginfo'] value 1 omits long stack and var dumps, value 2 also minimal infos
- * @param $p['fatal'] exit after displaying error
+ *
+ * Controlling error mail content
+ * @param $p either error title or assoc array of params, see below
+ * @param $p['title'] error title, one line. also accepted in $p[0] (with priority). false means suppress error
+ * @param $p['body'] error body: multiline string or any data type (will be dumped)
+ * @param $p['backtraceskip'] number of stack levels to drop
+ * @param $p['skipfiles'] files to skip in backtrace
+ * @param $p['omitdebuginfo'] value 1 omits long stack and var dumps, value 2 also minimal infos
+ *
+ * Controlling the sending of mails
+ * @param $p['to'] comma separated recipient list
+ * @param $p['timewindow'] in secs. "5-35" means for an mail to be sent, another err must occur 5 to 35 seconds after first one
+ * @param $p['id'] id of error, used with timewindow, defaults to file and line of caller
+ * @param $p['blockmailid'] block mail for $p['blockmail'] seconds with same id. Default: $p['to']
+ * @param $p['blockmail'] number of seconds to block mails after having sent a mail [3600]
+ * @param $p['okstate'] give current ok label and ok state, e.g. telresult=1 for working. see failcount
+ * @param $p['failcount'] give number of consecutive okstate failures needed for creating an error [2]
+ * @param $p['fatal'] exit after displaying error
+ * @param $p['graceperiod'] in seconds. DEPRECATED, see $p['timewindow']
+ * Use debug param 'verboseerrors' to include $p['body'] when interactive
+ *
* @return always null (so users can return it::error() in error cases)
*
* TIMEWINDOW 5-35 (x = error occurs, no mail; m = error occurs, mail sent)
@@ -164,6 +170,7 @@ static function error($p = array(), $extra = null)
$p['title'] = $p[0] ?: $p['title']; # handle 'it_error' => "oops" that was cast to array on the way
$p['title'] = grapheme_substr($p['title'], 0, 2000) ?: substr($p['title'], 0, 2000);
+ # support for errlike() in tests
$GLOBALS['ULTRAERROR'] = $p['title'];
if ($GLOBALS['ULTRANOERRORS'])
return null;
@@ -391,20 +398,6 @@ static function servertype($pattern)
/**
- * Convert a string to ASCII-only chars, map/strip ISO-8859-1 accents
- * @param $text Text to convert
- * @return mapped/stripped version of $text contains only chars [0..127]
- */
-static function toascii($text)
-{
- return strtr(strtr($text,
- utf8_decode( 'ÇéâàåçêëèïîìÅÉôòûùÿøØáíóúñÑÁÂÀãÃÊËÈÍÎÏÓÔõÕÚÛÙýÝ'),
- 'CeaaaceeeiiiAEoouuyooaiounNAAAaAEEEIIIOOoOUUUyY'),
- array("\xe4" => 'ae', "\xf6" => 'oe', "\xfc" => 'ue', "\xc4" => 'Ae', "\xd6" => 'Oe', "\xdc" => 'Ue', "\xe6" => 'ae', "\xc6" => 'Ae', "\xdf" => 'ss'));
-}
-
-
-/**
* Check whether an IP adress lies within a given range. Supports IPv4 and IPv6
* @param $ip IP address (192.168.42.123)
* @param $cidrs IP range in CIDR notation (192.168.42.64/26) or array of ranges
@@ -601,9 +594,9 @@ static function any2utf8($value, $errprefix = "")
else if (is_string($value))
{
if (grapheme_strlen($value) === null)
- list($value, $error) = array(utf8_encode($value), utf8_encode("incorrect utf8-encoding. input=$value"));
+ list($value, $error) = array(it::utf8_encode($value), it::utf8_encode("incorrect utf8-encoding. input=$value"));
if (preg_match('/\xc3[\x82\x83]\xc2[\x82\x83\xbc\xa9\xa4\xb6\xa8\xa2\xa0\xb4\xaa\xa7\x84\xab\xae\x9c\xaf\x96\xb2\xbb\xb9\x9f]/', $value))
- list($value, $error) = array(it::any2utf8(preg_replace_callback('/\xc3[\x82\x83]\xc2[\x82\x83\xbc\xa9\xa4\xb6\xa8\xa2\xa0\xb4\xaa\xa7\x84\xab\xae\x9c\xaf\x96\xb2\xbb\xb9\x9f]/', function($m) {return utf8_decode($m[0]);}, $value)), $errprefix ? "double utf8-encoding. input=$value" : "");
+ list($value, $error) = array(it::any2utf8(preg_replace_callback('/\xc3[\x82\x83]\xc2[\x82\x83\xbc\xa9\xa4\xb6\xa8\xa2\xa0\xb4\xaa\xa7\x84\xab\xae\x9c\xaf\x96\xb2\xbb\xb9\x9f]/', function($m) {return it::utf8_decode($m[0]);}, $value)), $errprefix ? "double utf8-encoding. input=$value" : "");
if (preg_match('/\xef\xb7[\x90-\xaf]|\xef\xbf[\xbe\xbf]/', $value))
list($value, $error) = array(preg_replace('/\xef\xb7[\x90-\xaf]|\xef\xbf[\xbe\xbf]/', " ", $value), "forbidden utf-8 character. input=$value");
$value = preg_replace('/\xc2\xad/', '', $value); # Kill invisible soft hyphens
@@ -909,7 +902,7 @@ static function getopt($usage, $p = array())
foreach(explode("\n", trim($usage)) as $usageline)
{
$shortoptname = $shortoptarg = $longoptname = $longoptarg = "";
- foreach (explode(',', $usageline) as $optdesc)
+ foreach (explode(',', $usageline, 2) as $optdesc)
{
$optdesc = trim($optdesc);
if ($matches = (array)it::match('^--(\w[\w-]*)(=[A-Z])?', $optdesc))
@@ -1058,7 +1051,7 @@ static function date($format = "", $stamp = null)
if (!isset($stamp))
$stamp = it::time();
else if (is_string($stamp) && !ctype_digit($stamp))
- $stamp = strtotime($stamp, it::time());
+ $stamp = strtotime(it::replace(['\s(--|\+\+)\s*(\d)' => ' +\2', '\s(\+-|-\+)\s*(\d)' => ' -\2'], $stamp), it::time());
list($name, $language) = explode(":", $format);
@@ -1383,4 +1376,14 @@ static function request_body()
return it::any2utf8(it::file_get_contents('php://input'));
}
+static function utf8_decode($utf8)
+{
+ return UConverter::transcode($utf8, 'ISO-8859-1', 'UTF8', ['to_subst' => '?']);
+}
+
+static function utf8_encode($latin1)
+{
+ return UConverter::transcode($latin1, 'UTF8', 'ISO-8859-1');
+}
+
}
diff --git a/it_dbi.class b/it_dbi.class
index b365f59..786fb90 100644
--- a/it_dbi.class
+++ b/it_dbi.class
@@ -19,7 +19,8 @@
** dbi.class - UltraFlexible Database Interface 3000
*/
-class it_dbi
+#[AllowDynamicProperties]
+class it_dbi implements Iterator
{
static $_global_key = 'it_dbi'; # $GLOBAL key to use for singleton
@@ -176,9 +177,8 @@ static function createclass($p)
if (substr($classname, 0, 4) != 'PMA_') # It is designed behaviour that an error is generated if this class already exists!
{
- $interface = function_exists("interface_exists") && interface_exists("Iterator", false) ? "implements Iterator" : "";
$parentname = static::$_global_key;
- $code = "class $classname extends $parentname $interface
+ $code = "class $classname extends $parentname
{
function __construct(\$query = null, ...\$args)
{
diff --git a/it_debug.class b/it_debug.class
index 3361933..91342bd 100644
--- a/it_debug.class
+++ b/it_debug.class
@@ -170,13 +170,13 @@ static function dump($args, $p = [])
$var = array_shift($argnames);
$item = gettype($arg) == 'resource' || is_array($arg) && isset($arg['GLOBALS']) || is_object($arg) && is_a($arg, "SimpleXMLElement") ? trim(print_r($arg, true)) : trim(var_export($arg, true));
- # Replace PHP 5 var_export object representation by old style
+ # Replace PHP 5+ var_export object representation by old readable style
while (preg_match("#(.*\b)(\w+)::__set_state\(array\(([^()]+)\)\)(.*)#s", $item, $regs) && ++$iterations < 100)
{
list (, $head, $classname, $values, $tail) = $regs;
$classname = strtolower($classname);
$values = preg_replace("#'(\w+)' =>\s*([^\n]+),#", 'var \$$1 = $2;', $values);
- $item = $head . "class $classname { $values }$tail";
+ $item = rtrim($head, '\\') . "class $classname {" . $values . "}" . $tail;
}
$item = preg_replace_callback('/\b(1[2-9]\d\d\d\d\d\d\d\d)\b(.*)/', function($m) { return $m[1] . $m[2] . " # " . date('Y-m-d H:i:s', $m[1]); }, $item);
@@ -211,7 +211,7 @@ static function dump($args, $p = [])
if ($p['html'])
return "<pre title='$title' style='color:#c00; text-align:left; background:white; border-bottom:1px solid #ddd; z-index:9999; position:relative; line-height:1'>$r</pre>\n";
else
- return $ansiok || $p['short'] ? "$r\n" : "\xe2\x96\x88\xe2\x96\x8c" . preg_replace("#\n#", "\n\xe2\x96\x88 ", "$r") . "\n";
+ return $ansiok || $p['short'] || EDC('edplain') ? "$r\n" : "\u{2588}\u{258c}" . preg_replace("#\n#", "\n\u{2588} ", "$r") . "\n";
}
/**
diff --git a/it_html.class b/it_html.class
index d7e1db3..93057bd 100644
--- a/it_html.class
+++ b/it_html.class
@@ -59,6 +59,10 @@ class it_html
var $p; # constructor params plus defaults
+ var $doctypes;
+ var $alltags;
+ var $hasnonewline;
+
/**
* Create a HTML object and global functions for all methods (exlcluding
* methods starting with '_') in this class plus the default tags (see below).
@@ -507,7 +511,7 @@ static function U(...$args)
list($u['path'], $u['query']) = explode("?", $base, 2);
}
- $u['host'] = preg_match('/[^-_.0-9a-z]/i', $u['host']) && function_exists('idn_to_ascii') && ($idnahost = idn_to_ascii($GLOBALS['it_html']->p['charset'] == "iso-8859-1" ? utf8_encode($u['host']) : $u['host'])) ? $idnahost : $u['host']; # Punycode hostname to include into webpage
+ $u['host'] = preg_match('/[^-_.0-9a-z]/i', $u['host']) && function_exists('idn_to_ascii') && ($idnahost = idn_to_ascii($GLOBALS['it_html']->p['charset'] == "iso-8859-1" ? it::utf8_encode($u['host']) : $u['host'])) ? $idnahost : $u['host']; # Punycode hostname to include into webpage
$u['host'] = preg_replace_callback('/[^-_.0-9a-z\x80-\xff]/i', function($m) { return rawurlencode($m[0]); }, $u['host']); # Encode garbage chars in host
# handle scheme, user (urlencoded), password, host
diff --git a/it_pipe.class b/it_pipe.class
index edc6dd8..0ffb7af 100644
--- a/it_pipe.class
+++ b/it_pipe.class
@@ -101,22 +101,6 @@ function filter($expr)
}
/**
- * Convert pipe from utf8 to iso-latin
- */
-function latin()
-{
- return $this->map('utf8_decode($v)');
-}
-
-/**
- * Convert pipe from iso-latin to uft8
- */
-function utf8()
-{
- return $this->map('utf8_encode($v)');
-}
-
-/**
* Select cols from tab-separated cols in each line and tab-joins them again. Key order relevant.
*/
function cut($picks)
diff --git a/it_text.class b/it_text.class
index 5e33395..61a6006 100644
--- a/it_text.class
+++ b/it_text.class
@@ -25,6 +25,7 @@ class it_text
var $languages_available = array(); # Available languages
var $statictext = array(); # Text array, read from php file on init
var $label_to_service = array(); # which label belongs to which service - only used for debug parameter texts
+ var $allowedfuncs;
var $p; # Constructor Parameters
/**
diff --git a/it_url.class b/it_url.class
index b2dad3c..e2cd993 100644
--- a/it_url.class
+++ b/it_url.class
@@ -39,6 +39,7 @@ class it_url
var $redir = 0; /* Redirect count */
var $header; /* http header */
var $errstr; /* request error string */
+ var $curlinfo;
static $retryable = "^(5..)$";
@@ -573,6 +574,7 @@ static function get_cache_filename($p)
* @param $p['cachedir'] directory to store cache files in, @see get_cache_dir
* @param $p['timeout'] timeout in seconds, default 10. fractions allowed
* @param $p['maxage'] maximum age of cache entries in seconds, default 23 hours. id mandatory if given
+ * @param $p['randomexpire'] chance to randomly expunge an entry, 0..1
* @param $p['cleanbefore'] maximum seconds since midnight when initiating expire, default 10800
* @param $p['preprocess'] callback function (or array for methods) to change received file or array('function' => ..., 'in' => $src, 'out' => $dst, ...) with callback function plus args
* @param $p['safety'] DEPRECATED. see $p['it_error']
@@ -599,7 +601,7 @@ static function get_cache($p = array())
if (!is_writable(dirname($path)))
it::error("parent dir not writable: " . trim(it::exec('ls -ld {dir} 2>&1', ['dir' => dirname($path)])));
- if (($filemtime = it_url::_expired($path, $p['maxage'])) || ($p['returnheaders'] && !file_exists(("$path.headers")))) # Outdated(non-zero int) or non-existant(true)?
+ if (($filemtime = it_url::_expired($path, $p['maxage'], $p['randomexpire'])) || ($p['returnheaders'] && !file_exists(("$path.headers")))) # Outdated(non-zero int) or non-existant(true)?
{
$fileexists = $filemtime !== true;
@@ -736,11 +738,11 @@ static function get_cache_contents($p)
* @param $maxage Maximum age of file in seconds
* @return Not expired: false | Non-existant file: true | Timestamp of expired file
*/
-static function _expired($path, $maxage)
+static function _expired($path, $maxage, $randomexpire = 0)
{
if ($result = EDC('nocache') ? false : @filemtime($path))
{
- if (time() - $result > $maxage)
+ if (time() - $result > $maxage || rand(0, 100000) <= $randomexpire * 100000)
EDC('getcache', "expired", $maxage, $path);
else
$result = false;
diff --git a/it_xml.class b/it_xml.class
index 57f4555..7765054 100644
--- a/it_xml.class
+++ b/it_xml.class
@@ -19,6 +19,7 @@
** it_xml.class - XML parser / object factory
*/
+#[AllowDynamicProperties]
class it_xml
{
/*
@@ -140,7 +141,7 @@ function _sanitize($xmldata, $isutf8 = null)
# Encode non-utf8 characters in a string, leave utf8 alone
static function _utf8_fix($str)
{
- return preg_match('/^([\xc0-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf][\x80-\xbf]|[\xf0-\xf7][\x80-\xbf][\x80-\xbf][\x80-\xbf])$/', $str) ? $str : utf8_encode($str);
+ return preg_match('/^([\xc0-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf][\x80-\xbf]|[\xf0-\xf7][\x80-\xbf][\x80-\xbf][\x80-\xbf])$/', $str) ? $str : it::utf8_encode($str);
}
function consume(/* $p */)
diff --git a/test/exec.t b/test/exec.t
index 09e16da..04850fc 100755
--- a/test/exec.t
+++ b/test/exec.t
@@ -70,7 +70,7 @@ foreach (["", "C", "de_CH", "de_CH.utf8"] as $locale)
setlocale(LC_ALL, $locale);
$arg = "preüpost";
if (it::match('utf8', $locale))
- $arg = utf8_encode($arg);
+ $arg = it::any2utf8($arg);
is(it::exec("echo " . $arg), $arg . "\n", "exec with umlaut (locale '$locale')");
is(it::exec("echo {arg}", ['arg' => $arg]), $arg . "\n", "exec with argument and umlaut (locale '$locale')");
}
diff --git a/test/getopt.t b/test/getopt.t
index 77e52ae..380d0fd 100755
--- a/test/getopt.t
+++ b/test/getopt.t
@@ -9,6 +9,7 @@ $GLOBALS['usage'] = "Usage: doesnotexist.php [OPTIONS] POSITIONAL [VARARGS]
-a,--argument=ARG the arg argument
-d,--default=ARG an argument with default [defäult]
-0,--zero testworthy shortarg
+ -c,--comma option with comma and, -minus in the description
";
function getopt_ok($argv, $exp, $name)
@@ -26,6 +27,7 @@ foreach (["" => "blah gnaber", " (umlaute)" => "pre üäpost"] as $variant => $t
getopt_ok([$testarg, "--argument=$testarg"], $exp, "Long version with equal" . $variant);
}
+getopt_ok(['posargs', '-c'], ['args' => [], 'positional' => 'posargs', 'comma' => true, 'default' => 'defäult'], "comma and minus in description doesn't break shortopt");
$exp = ['args' => [], 'positional' => 'posarg', 'zero' => true, 'default' => 'defäult'];
getopt_ok(['posarg', '-0'], $exp, 'short argument -0 without value');
getopt_ok(['posarg', '--zero'], $exp, 'long argument --zero without value');
@@ -33,6 +35,7 @@ getopt_ok(['posarg', '-0', 'vararg'], ['args' => ['vararg']] + $exp, "additional
getopt_ok(['posarg', '--zero', 'vararg'], ['args' => ['vararg']] + $exp, "additional value after long argument --zero");
fclose(STDERR);
+getopt_ok(['posargs', '-m'], false, "comma and minus in description doesn't break shortopt 2");
getopt_ok(['posarg', '--unknown'], false, "Unknown long named argument fails");
getopt_ok(['posarg', '-u'], false, "Unknown short named argument fails");
getopt_ok([], false, "Missing positional argument fails");
diff --git a/test/it.t b/test/it.t
index 7733c00..3003ccf 100755
--- a/test/it.t
+++ b/test/it.t
@@ -221,15 +221,15 @@ _match(
);
_match(
- utf8_decode('ö'), utf8_decode('Ö'),
- utf8_decode('Ö'),
+ it::utf8_decode('ö'), it::utf8_decode('Ö'),
+ it::utf8_decode('Ö'),
'match umlaute in de_CH.latin1 case insensitive',
['utf8' => false]
);
_match(
- utf8_decode('aöBÜ'), utf8_decode('AÖbü'),
- utf8_decode('AÖbü'),
+ it::utf8_decode('aöBÜ'), it::utf8_decode('AÖbü'),
+ it::utf8_decode('AÖbü'),
"match umlaute with non-utf-8 override in p",
['utf8' => false]
);
@@ -270,6 +270,12 @@ _match(
['all' => 1, 'pattern_order' => 1]
);
+_match(
+ preg_quote('a/b!c(d\\e{f$g^h|i??**++'), 'faa/b!c(d\\e{f$g^h|i??**++ar',
+ 'a/b!c(d\\e{f$g^h|i??**++',
+ 'match with preg_quote of special characters in pattern'
+);
+
ini_set('default_charset', 'iso-8859-1');
_match(
'aöBÜ', "AÖbü",
@@ -388,7 +394,19 @@ _time("152715", it::date('', '15:27:15'));
_time("yesterday", it::date('', 'yesterday'));
is(it::date('date', '2011-10-25'), '25.10.2011', 'parse date string with strtotime');
-is(it::date('date', '2011-10-25 + 3 days'), '28.10.2011', 'some date arithmetic');
+is(it::date('date', '2011-10-25 + 3 days'), '28.10.2011', 'date arithmetic (add)');
+is(it::date('date', '2011-10-25 - 3 days'), '22.10.2011', 'date arithmetic (subtract)');
+is(it::date('date', '2011-10-25 +-3 days'), '22.10.2011', 'date arithmetic (negative value)');
+is(it::date('date', '2011-10-25 --3 days'), '28.10.2011', 'date arithmetic (double negative)');
+is(it::date('date', '2011-10-25 ++ 3 days'), '28.10.2011', 'date arithmetic (double positive with space)');
+is(it::date('date', '2011-10-25 -+ 3 days'), '22.10.2011', 'date arithmetic (negative positive with space)');
+is(it::date('datetime', '2011-10-25 +12 hours +30 minutes'), '25.10.2011 12:30', 'datetime arithmetic (hours minutes)');
+is(it::date('datetime', '2011-10-25 +24 hours +30 minutes'), '26.10.2011 00:30', 'datetime arithmetic (hours minutes over midnight)');
+is(it::date('datetime', '2011-10-25 8:00 +10 minutes'), '25.10.2011 08:10', 'time arithmetic (add)');
+is(it::date('datetime', '2011-10-25 8:00 -10 minutes'), '25.10.2011 07:50', 'time arithmetic (subtract)');
+is(it::date('datetime', '2011-10-25 8:00 +-10 minutes'), '25.10.2011 07:50', 'time arithmetic (negative value)');
+is(it::date('datetime', '2011-10-25 8:00 --10 minutes'), '25.10.2011 08:10', 'time arithmetic (double negative)');
+is(it::date('datetime', '2011-10-25 --1 month --3 days 8:00 +- 4 hours +-10 minutes'), '28.11.2011 03:50', 'date and time arithmetic (multiple signs)');
is(it::date('datetime', it::time()), it::date('datetime'), 'recognize int as timestamp');
is(it::date('datetime', it::time()*1.0), it::date('datetime'), 'recognize float as timestamp');
is(it::date('datetime', it::time() . ''), it::date('datetime'), 'recognize digit string as timestamp');
@@ -419,32 +437,32 @@ is(grapheme_strlen("\xc1"), null, "need grapheme_strlen side effect for any2utf8
is(it::any2utf8('Meier'), 'Meier', "it::any2utf8 ascii input");
is(it::any2utf8('Müller'), 'Müller', "it::any2utf8 utf8 input");
is(it::any2utf8('Aslı'), 'Aslı', "it::any2utf8 utf8 non-latin1 input");
-is(it::any2utf8(utf8_decode('Müller')), 'Müller', "it::any2utf8 latin1 input");
+is(it::any2utf8(it::utf8_decode('Müller')), 'Müller', "it::any2utf8 latin1 input");
is(it::any2utf8(
' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ'), # omit soft hyphen cause we filter it
' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ',
"it::any2utf8 utf8 input (exhaustive alphabet)");
is(it::any2utf8(
- utf8_decode(' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ')),
+ it::utf8_decode(' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ')),
' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ',
"it::any2utf8 latin1 input (exhaustive alphabet)");
-is(it::any2utf8(utf8_encode("ü")), "ü", "it::any2utf8 double encoding");
+is(it::any2utf8(it::utf8_encode("ü")), "ü", "it::any2utf8 double encoding");
is(it::any2utf8("Meier"), "Meier", "it::any2utf8 ascii");
is(it::any2utf8("Müller"), "Müller", "it::any2utf8 utf-8 latin1");
is(it::any2utf8("Aslı"), "Aslı", "it::any2utf8 utf-8 non-latin1");
is(it::any2utf8("é»"), "é»", "it::any2utf8 utf-8 latin1 special combination");
-is(it::any2utf8(utf8_encode("Müller")), "Müller", "it::any2utf8 doubly encoded utf8");
-is(it::any2utf8(utf8_encode(utf8_encode("Müller"))), "Müller", "it::any2utf8 triply encoded utf8");
-is(it::any2utf8(utf8_decode("Müller")), "Müller", "it::any2utf8 incorrectly encoded latin1");
+is(it::any2utf8(it::utf8_encode("Müller")), "Müller", "it::any2utf8 doubly encoded utf8");
+is(it::any2utf8(it::utf8_encode(it::utf8_encode("Müller"))), "Müller", "it::any2utf8 triply encoded utf8");
+is(it::any2utf8(it::utf8_decode("Müller")), "Müller", "it::any2utf8 incorrectly encoded latin1");
is(it::any2utf8("a💚b"), "a💚b", "it::any2utf8 correctly handles 4-byte utf-8 character GREEN HEART");
-is(it::any2utf8(["foo", utf8_decode("bär")]), ["foo", "bär"], "any2utf8 on arrays");
-is(it::any2utf8(["foo", [utf8_decode("bär")]]), ["foo", ["bär"]], "any2utf8 on recursive arrays");
+is(it::any2utf8(["foo", it::utf8_decode("bär")]), ["foo", "bär"], "any2utf8 on arrays");
+is(it::any2utf8(["foo", [it::utf8_decode("bär")]]), ["foo", ["bär"]], "any2utf8 on recursive arrays");
is(it::any2utf8([1, true, false, null]), [1, true, false, null], "any2utf8 should leave types alone");
-is(it::any2utf8([utf8_decode('Müller') => utf8_decode('Müller')]), ['Müller' => 'Müller'], "it::any2utf8 latin1 keys");
+is(it::any2utf8([it::utf8_decode('Müller') => it::utf8_decode('Müller')]), ['Müller' => 'Müller'], "it::any2utf8 latin1 keys");
is(it::any2utf8("\xc2\xad"), "", "it::any2utf8 remove soft hyphens");
@@ -532,10 +550,10 @@ it::file_put($tmpfile, "bb");
is(it::file_get($tmpfile), "bb");
unlink($tmpfile);
-requesturi(utf8_decode("lüönd"), "lüönd");
-requesturi(utf8_decode("ü").utf8_encode("ü"), "üü");
-requesturi(utf8_encode("müller"), "müller");
-requesturi(utf8_encode(utf8_encode("müller")), "müller");
+requesturi(it::utf8_decode("lüönd"), "lüönd");
+requesturi(it::utf8_decode("ü").it::utf8_encode("ü"), "üü");
+requesturi(it::utf8_encode("müller"), "müller");
+requesturi(it::utf8_encode(it::utf8_encode("müller")), "müller");
requesturi("I 💚 Nü York", "I 💚 Nü York");
function requesturi($teststring, $expect)
diff --git a/test/it_dbi.t b/test/it_dbi.t
index 2b5b0c5..2a601b6 100755
--- a/test/it_dbi.t
+++ b/test/it_dbi.t
@@ -27,6 +27,7 @@ $dbi->query("create temporary table it_dbi_test (
$autoid,
x int,
y float,
+ z bigint,
foo varchar(42),
flag boolean,
$dyncols,
@@ -44,9 +45,9 @@ try {
is(it::match('syntax', $e->getMessage()), 'syntax', "Syntax error triggers error");
}
-$record->insert(['x' => 42, 'y' => 0.0001, 'foo' => null, 'flag' => 1]);
-$record->insert(['foo' => "bar", 'y' => 1e-10, 'flag' => 0]);
-$record->insert(['x' => 64738, 'y' => 1, 'foo' => "q'uux"]);
+$record->insert(['x' => 42, 'y' => 0.0001, 'z' => 0, 'foo' => null, 'flag' => 1]);
+$record->insert(['foo' => "bar", 'y' => 1e-10, 'z' => 0, 'flag' => 0]);
+$record->insert(['x' => 64738, 'y' => 1, 'z' => 0, 'foo' => "q'uux"]);
is(
$record->ID,
@@ -192,6 +193,22 @@ is(
"update with function"
);
+$value = pow(2, 24) + 1;
+$record->update(['x' => $value]);
+is($record->x, $value, "update 32bit integer without float representation");
+is($record->select(['x' => $value]), 1, "select 32bit integer without float representation");
+
+$value = pow(2, 53) + 1;
+$record->update(['z' => $value]);
+is($record->z, $value, "update 64bit integer without double representation");
+is($record->select(['z' => $value]), 1, "select 64bit integer without double representation");
+
+$record->update(['foo' => "10", 'x' => 10]);
+is($record->select(['x <' => 9]), 0, "always use integer comparision for int field");
+is($record->select(['x <' => '9']), 0, "always use integer comparision for int field");
+is($record->select(['foo <' => 9]), 1, "always use string comparision for varchar field");
+is($record->select(['foo <' => '9']), 1, "always use string comparision for varchar field");
+
$record->update(['foo' => "00"]);
$rand = $record->x;
is (
@@ -253,6 +270,14 @@ foreach (new it_dbi_test as $id => $record)
is($count, 3, "Iterator without select");
$count = 0;
+foreach (new it_dbi($db + ['table' => 'it_dbi_test']) as $id => $record)
+{
+ $count++;
+ is($record->_key, $id, "Iterator id $id (it_dbi object)");
+}
+is($count, 3, "Iterator without select (it_dbi_object)");
+
+$count = 0;
foreach (new it_dbi_test(['foo <>' => ""]) as $id => $record)
{
$count++;
@@ -489,14 +514,14 @@ $record->delete(['WHERE TRUE' ]);
$record->upsert(['ID' => 1, 'x' => 42, 'y' => 2.5, 'foo' => ['value' => "a"], 'flag' => 0]);
$record->read(1);
is($record->x, 42, 'value of x after reading with _read_postprocess');
-is($record->_data, ["ID" => 1, "x" => 42, 'y' => 2.5, 'foo' => '{"value":"a"}', 'flag' => 0], 'data after reading with _read_postprocess');
+is($record->_data, ["ID" => 1, "x" => 42, 'y' => 2.5, 'z' => NULL, 'foo' => '{"value":"a"}', 'flag' => 0], 'data after reading with _read_postprocess');
is($record->foo, ['value' => "a"], 'field after reading with _read_postprocess');
$record2 = new it_dbi_test;
$record2->read(1);
is($record2->x, 43, 'raw value of x after writing with _write_preprocess');
-is($record2->_data, ["ID" => 1, "x" => 43, 'y' => 2.5, 'foo' => '{"value":"a"}', 'flag' => 0], 'raw data after writing with _write_preprocess');
+is($record2->_data, ["ID" => 1, "x" => 43, 'y' => 2.5, 'z' => NULL, 'foo' => '{"value":"a"}', 'flag' => 0], 'raw data after writing with _write_preprocess');
$record->update(['foo' => ['value' => "b"]]);
-is($record->_data, ["ID" => 1, "x" => 42, 'y' => 2.5, 'foo' => '{"value":"b"}', 'flag' => 0], 'raw data after updating with _write_preprocess');
+is($record->_data, ["ID" => 1, "x" => 42, 'y' => 2.5, 'z' => NULL, 'foo' => '{"value":"b"}', 'flag' => 0], 'raw data after updating with _write_preprocess');
is($record->foo, ['value' => "b"], 'field data after updating with _write_preprocess');
diff --git a/test/it_url.testserver.php b/test/it_url.testserver.php
index 2d1bca4..242ccf6 100644
--- a/test/it_url.testserver.php
+++ b/test/it_url.testserver.php
@@ -42,6 +42,8 @@ switch ($_SERVER['PHP_SELF'])
break;
case "/long_sleep":
+ echo "a\n";
+ flush();
sleep(6);
echo 'Testserver output after long sleep';
break;
diff --git a/test/it_xml.t b/test/it_xml.t
index e21f052..88a5cf4 100755
--- a/test/it_xml.t
+++ b/test/it_xml.t
@@ -63,7 +63,7 @@ _match(
_match(
'<foo>x &uuml; y</foo>',
- utf8_decode('foo Object ( [val] => x ü y ) '),
+ it::utf8_decode('foo Object ( [val] => x ü y ) '),
'Manual encoding override',
"",
['encoding' => "iso-8859-1"]
@@ -77,7 +77,7 @@ _match(
_match(
'<foo>&amp;amp; &lt;a&gt; &#38;amp; &#60;b&#62; &#x26;amp; &#x3C;c&#x3E; &#xFC;</foo>',
- utf8_decode('foo Object ( [val] => &amp; <a> &amp; <b> &amp; <c> ü ) '),
+ it::utf8_decode('foo Object ( [val] => &amp; <a> &amp; <b> &amp; <c> ü ) '),
'Predecode illegal entities while keeping properly encoded ones (iso-8859-1)',
"",
['encoding' => "iso-8859-1"]