summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--it.class18
-rw-r--r--it_debug.class2
-rw-r--r--it_html.class2
-rw-r--r--it_url.class16
-rw-r--r--itjs.class32
-rw-r--r--itjs.php23
-rwxr-xr-xtests/it.t4
7 files changed, 65 insertions, 32 deletions
diff --git a/it.class b/it.class
index 05efbee..b097e60 100644
--- a/it.class
+++ b/it.class
@@ -144,7 +144,7 @@ static function error($p = array())
'to' => $gods ? $gods : (get_current_user() ? get_current_user() : $_SERVER['SERVER_ADMIN']),
'graceperiod' => 60,
'timewindow' => 25*3600,
- 'backtraceskip' => 0,
+ 'backtraceskip' => 1,
'blockmail' => 3600,
'omitdebuginfo' => false,
'failcount' => 2,
@@ -169,7 +169,7 @@ static function error($p = array())
if ($toscreen && !it::is_live())
$GLOBALS['debug_noredir'] = 1;
- if (!$toscreen) # this error can only be sent by mail: find out if we want to suppress it
+ if (error_reporting() && !$toscreen) # not called with @ and this error can only be sent by mail: find out if we want to suppress it
{
if (!$p['id'])
$sendmail = true;
@@ -204,6 +204,7 @@ static function error($p = array())
{
$trace = it_debug::backtrace(array('skiplevels' => $p['backtraceskip'], 'skipfiles' => $p['skipfiles'])); # moved in here for performance in mass error case
+ $p['body'] = is_string($p['body']) || !$p['body'] ? $p['body'] : var_export($p['body'], true);
if (strlen($p['body']) > 500000)
{
file_put_contents($datafn = "/tmp/alertdata/error-" . substr(md5($p['body']), 0, 2), $p['body']);
@@ -651,6 +652,7 @@ static function cdist(/* $file1, ... */)
* @param $p['types'] Comma separated list of accepted input types, default "bmp,eps,gif,jp2,jpg,png,svg,tif"
* @param $p['quality'] JPEG quality (0-100), default is 75
* @param $p['keepalpha'] Don't add option --flatten to preserve alpha channel
+ * @param $p['pngcrush'] Use pngcrush for sm
* @param $p['-opts'] Custom command line options to ImageMagick convert
* @return Success of convert as true/false
*/
@@ -692,6 +694,9 @@ static function imageconvert($p)
if (in_array($type, explode(',', $p['types']))) # Valid type?
$cmdoutput = it::exec('( ' . $ultratimeout . 'gm convert 2>&1 {-opts} {in} {type}:{out} || echo "SHELL ERROR $?" ) | grep -v " iCCP: "', $p);
+ if ($p['pngcrush'] && $p['type'] == "png")
+ it::exec('pngcrush.sh 2>/dev/null {out} {out}.tmp && mv {out}.tmp {out} || rm {out}.tmp', $p);
+
return $cmdoutput === "";
}
@@ -1025,5 +1030,12 @@ static function json_decode($json)
return ($data = json_decode($json)) === null && $json != 'null' ? it::error(array('title' => "invalid json", 'body' => $json)) : $data;
}
+static function sort($array, $mode = "")
+{
+ $func = it::replace(array('n' => ""), count_chars($mode, 3)) . "sort"; # count_chars sorts flags
+ $func($array, it::match('n', $mode) ? SORT_NUMERIC : 0);
+
+ return $array;
+}
+
}
-?>
diff --git a/it_debug.class b/it_debug.class
index 6a4c387..89d5259 100644
--- a/it_debug.class
+++ b/it_debug.class
@@ -174,7 +174,7 @@ static function backtrace($p = array())
$p += array('levels' => 0, 'skiplevels'=> 0, 'skipfiles' => "###");
- foreach (array_slice(debug_backtrace(@constant('DEBUG_BACKTRACE_IGNORE_ARGS')), $p['skiplevels'] + 1) as $call)
+ foreach (array_slice(debug_backtrace(@constant('DEBUG_BACKTRACE_IGNORE_ARGS')), $p['skiplevels']) as $call)
{
if (($fn = $call['file']) && !it::match($p['skipfiles'], $call['file']))
{
diff --git a/it_html.class b/it_html.class
index e8969fb..e9e312b 100644
--- a/it_html.class
+++ b/it_html.class
@@ -509,7 +509,7 @@ function Q($string)
{
if (preg_match('/[<>&"\x00-\x08\x0a-\x0c\x0e-\x1f\x80-\xff]/', $string)) # WARNING: copy/pasted to _tag()
{
- $charset = $GLOBALS['it_html']->p['charset'];
+ $charset = $GLOBALS['it_html']->p['charset'] ?: ini_get('default_charset');
if ($GLOBALS['debug_utf8check'] && $charset == "utf-8")
$string = it::any2utf8($string, "error in Q()");
diff --git a/it_url.class b/it_url.class
index 2204b60..fb5a1ff 100644
--- a/it_url.class
+++ b/it_url.class
@@ -156,6 +156,7 @@ function is_reachable($timeout = 5)
* @param $p['filemtime'] Add HTTP header to only fetch when newer than this, otherwise return true instead of data
* @param $p['data']: POST data array with key-value pairs
* @param $p['retries']: Number of retries if download fails, default 1
+ * @param $p['retrysleep'] Number of seconds to wait before retry, fractions ok
* @return contents of resulting page, considering redirects, excluding headers, or false on error
*/
function get($p=null, $timeout=5)
@@ -190,7 +191,10 @@ function get($p=null, $timeout=5)
}
if (!$result && $p['retries'] > 0 && $url->result < 400)
+ {
+ usleep($p['retrysleep']*1000000);
$result = $url->get(array('retries' => $p['retries'] - 1) + $p);
+ }
if (($filter = EDC('res')) && strstr($p['url'], it::replace(array('1' => ":"), $filter)))
ED($result);
@@ -623,9 +627,12 @@ function get_cache($p = array())
if (!($result = @filesize($dstpath) && @rename($dstpath, $path)))
{
@unlink($dstpath);
- @unlink($path);
+ if (!$p['keepfailed'])
+ @unlink($path);
+ $result = file_exists($path);
}
+ $cachemiss = 1;
it_url::_unlock($path, $lock);
}
else
@@ -645,7 +652,10 @@ function get_cache($p = array())
exec("nohup bash -c 'cd {$p['cachedir']} && sleep 10 && find ?? -mmin +$maxagemin -print0 | xargs -0 -r rm' </dev/null >/dev/null 2>&1 &");
}
- EDC('getcache', $result, $path);
+ if (EDC('getcachelog'))
+ it::log('debug', 'getcachelog', "miss=" . intval($cachemiss), $p['url']);
+
+ ### EDC('getcache', $result, $path); # too verbose
return $result ? ($p['returnheaders'] ? array($path, $headers) : $path) : false;
}
@@ -669,7 +679,7 @@ function _expired($path, $maxage)
if ($result = EDC('nocache') ? false : @filemtime($path))
{
if (time() - $result > $maxage)
- EDC('getcache', "expired", $path);
+ EDC('getcache', "expired", $maxage, $path);
else
$result = false;
}
diff --git a/itjs.class b/itjs.class
index 6ef1c8f..c54abd3 100644
--- a/itjs.class
+++ b/itjs.class
@@ -160,7 +160,8 @@ static function filecontents($filenames, $execphp = true)
list($filename, $paramstr) = explode("?", $filename);
if ($paramstr && $execphp)
parse_str($paramstr, $_GET);
- $result .= it::replace(array('^1$' => ""), $execphp ? @include($filename) : @file_get_contents($filename), array('utf8' => false));
+ if (file_exists($filename))
+ $result .= it::replace(array('^1$' => ""), $execphp ? include($filename) : file_get_contents($filename), array('utf8' => false));
$_GET = $origget;
}
$result .= ob_get_clean();
@@ -206,14 +207,35 @@ static function checksum($fnlist, $p = array())
return it_cache::get($key) ?: it_cache::put($key, substr(md5(self::filecontents($filenames, false)), 0, 10), array('ttl' => 60));
}
-function crcurl($url)
+function crcurl($url, $p = array())
{
if (it::match('^http', $url)) # remote url, must fetch to crc
- $fn = it_url::get_cache(array('url' => $url, 'maxage' => 3600));
+ list($fn, $short_expire) = array(it_url::get_cache(array('url' => $url, 'maxage' => 3600) + $p), false);
else
- $fn = ($m = it::match("^//(\w+)(/.*)", $url)) ? "/www/$m[0].search.ch" . $m[1] : $GLOBALS['ULTRAHOME'] . $url;
+ list($fn, $short_expire) = array(($m = it::match("^//(\w+)(/.*)", $url)) ? "/www/$m[0].search.ch" . $m[1] : $GLOBALS['ULTRAHOME'] . $url, true);;
- return it::match('#', $url) ? U(trim($url, "#")) : U($url, array('c' => self::checksum(array($fn))));
+ return it::match('#', $url) ? U(trim($url, "#")) : U($url, array('c' => self::checksum(array($fn), array('short_expire' => $short_expire))));
+}
+
+# $p['nocrc'] means no $_REQUEST['c'] is needed for far future expire
+static function far_future_headers($p = array())
+{
+ $crc = $_REQUEST['c'] ?: $_REQUEST['s'];
+ if ($crc != "-" && !$_SERVER['HTTP_CACHE_CONTROL'] && $_SERVER['HTTP_IF_NONE_MATCH'] && !it::is_devel() && !$_REQUEST['retry'])
+ {
+ header("HTTP/1.0 304 Not Modified"); # client should always keep the component that fits the page it has
+ exit;
+ }
+
+ if ($crc != "-")
+ @header("Etag: alwaysvalid"); # we have checksums in the url. client should always keep the version he downloaded along with the html
+
+ if (it::is_live() && !$_REQUEST['retry'])
+ {
+ $keeptime = $crc == "-" ? 0 : ($crc || $p['nocrc'] ? 30*86400 : 900); # long expire if checksum present
+ header("Cache-Control: max-age=$keeptime, private"); # proxies should not cache since contents of same url can differ between browsers
+ header("Expires: " . gmdate("D, d M Y H:i:s", time() + $keeptime). " GMT");
+ }
}
}
diff --git a/itjs.php b/itjs.php
index 332e0dc..a1e5a0f 100644
--- a/itjs.php
+++ b/itjs.php
@@ -21,19 +21,14 @@
require "itools/itools.lib";
-if (EDC('slow' . it::match('\.(\w+)$', $_SERVER['PHP_SELF'])))
- sleep(10);
-
-$crc = $_REQUEST['c'] ?: $_REQUEST['s'];
-if ($crc != "-" && !$_SERVER['HTTP_CACHE_CONTROL'] && $_SERVER['HTTP_IF_NONE_MATCH'] && !it::is_devel() && !$_REQUEST['retry'])
-{
- header("HTTP/1.0 304 Not Modified"); # client should always keep the component that fits the page it has
- exit;
-}
+if (EDC('slow' . it::match('\.(css|js)\b', U($_GET))))
+ sleep(5);
if (it::match('/server/', $_SERVER['DOCUMENT_ROOT']))
exit; # useless here. cannot write tempfiles
+itjs::far_future_headers(); # may exit
+
$files = itjs::filenames($_GET['files'] ?: it::match('/itjs/([-a-z0-9_,.]*)', $_SERVER['PHP_SELF']));
$data = itjs::filecontents($files);
$file = end($files);
@@ -82,16 +77,6 @@ else if (!it::match('\.html$', $file))
header("Content-Type: application/x-javascript; charset=$charset");
}
-if ($crc != "-")
- @header("Etag: alwaysvalid"); # we have checksums in the url. client should always keep the version he downloaded along with the html
-
-if (it::is_live() && !$_REQUEST['retry'])
-{
- $keeptime = $crc == "-" ? 0 : ($crc ? 30*86400 : 900); # long expire if checksum present
- header("Cache-Control: max-age=$keeptime, private"); # proxies should not cache since contents of same url can differ between browsers
- header("Expires: " . gmdate("D, d M Y H:i:s", time() + $keeptime). " GMT");
-}
-
$data = itjs::strip($data);
if ($_REQUEST['boot'])
diff --git a/tests/it.t b/tests/it.t
index 10c4d0e..33a6c13 100755
--- a/tests/it.t
+++ b/tests/it.t
@@ -393,3 +393,7 @@ is(it::any2utf8(array(utf8_decode('Müller') => utf8_decode('Müller'))), array(
foreach (array($dummy, false, true, null, 1, "a", "Ä", "/", array()) as $var)
is(it::json_decode(it::json_encode($var)), $var);
+
+is(it::sort(array("2!","19!","1!")), array("1!", "19!", "2!"));
+is(it::sort(array("2!","19!","1!"), "r"), array("2!", "19!", "1!"));
+is(it::sort(array("2!","19!","1!"), "rn"), array("19!", "2!", "1!"));