diff --git a/Util.php b/Util.php
index 798dfdd..53ab1cf 100644
--- a/Util.php
+++ b/Util.php
@@ -35,4 +35,6 @@ class Util {
}
return $median;
}
+
}
+
diff --git a/buffer.php b/buffer.php
index 9297b20..d5a2637 100644
--- a/buffer.php
+++ b/buffer.php
@@ -3,6 +3,8 @@
// Based on PHP code by Dennis Pallett: www.phpit.net
// Please acknowledge use of this code by including this header.
+ // Updated to include and use last-modified and etag headers
+
// location and prefix for cache files
define('CACHE_PATH', "/tmp/cache_");
@@ -22,7 +24,20 @@
// check that cache file exists and is not too old
if(!file_exists($file)) return;
- if(filemtime($file) < time() - CACHE_TIME) return;
+ $last_modified_time = filemtime($file);
+ if($last_modified_time < time() - CACHE_TIME) return;
+ $etag = md5_file($file);
+
+ // always send headers
+ header("Last-Modified: ".gmdate("D, d M Y H:i:s", $last_modified_time)." GMT");
+ header("Etag: $etag");
+
+ // exit if not modified
+ if (@strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $last_modified_time ||
+ @trim($_SERVER['HTTP_IF_NONE_MATCH']) == $etag) {
+ header("HTTP/1.1 304 Not Modified");
+ exit;
+ }
// if so, display cache file and stop processing
readfile($file);
@@ -36,6 +51,13 @@
fwrite($f, $content);
fclose($f);
}
+ $last_modified_time = filemtime($file);
+ $etag = md5_file($file);
+
+ // always send headers
+ header("Last-Modified: ".gmdate("D, d M Y H:i:s", $last_modified_time)." GMT");
+ header("Etag: $etag");
+
return $content;
}
diff --git a/cms_chart.php b/cms_chart.php
deleted file mode 100644
index 1305fff..0000000
--- a/cms_chart.php
+++ /dev/null
@@ -1,676 +0,0 @@
- '1.2.3.4') exit;
- //if ($_SERVER['HTTP_REFERER'] <> 'topnew.net') exit; // etc
- cms_chart($_GET['data'], $init);
-}
-**** disabled for security reasons
- */
-
-/**
- * Topnew CMS Chart v5.5.5 - Released on 2016.05.05
- * The MIT License (MIT) Copyright (c) 1998-2015, Topnew Geo, topnew.net/chart
- * Draw an SVG chart (bar, barV, barS, line or pie), responsive to parent box
- *
- * Method 2 - include this file and call cms_chart() in your php file
- *
- * @param array $data = array() or string -- check cms_chart_data() for details
- * @param array $init = array() as following:
- * chart = bar [default], line, pie, barV, barS
- * w = px of SVG width default 480px. Tip: bigger w will produce fine charts
- * w = fix : will auto set w according to number of bar/line
- * h = px of SVG height default 250px. Pie chart will auto set h according to w
- * gapT, gapR, gapB, gapL = px of gaps on Top, Right, Bottom and Left
- * title = title of the chart
- * xTitle = title on axisX
- * yTitle = title on axisY
- * titleAlign, xTitleAlign, yTitleAlign = 1 Left 2 Center [default] 3 Right
- * xSkip = 5 means skip 5 labels between each two
- * xSkipMax = 50 means skip floor(xNum / 50)
- * xSkip = -5 when negative it means substr(xKey,-2) % -5 is true eg 5 10 15 ...
- * legend = T(op), R(ight) [default], B(ottom), 0 none
- * legendW = px of legend width
- * yUnit = additional text after axisY label
- * xFormat, yFormat = php . substr|fm|to or format|decimal|,|. or date|M
- * xKey = year, month, week, day, hour
- * xMin, xMax default to data min and max
- * sort = y (sort on axisY labels, or yVal for only one serial chart)
- * sort = x (sort on axisX labels), '' default none
- * color = fffccc,cccfff : add 2 color at front
- * colorAdd = fffccc,cccfff : add 2 color at end
- * colorDel = 0,2 : delete color #0 and #2
- * ySum = 1 : sum up yVal while x moves, default 0
- * xSum = 8 (substr(xAxis,0,8)) or 5,2 or -2 to call php::substr
- * pieArc = 0 ~ 360 for pie : start Arc
- * pieStripe = 0 / 1 for pie
- * piePct = 0 / 1 for pie to include %
- * pieDonut = 0 / 1 pie or donut
- * css = 0 / 1 to cout default chart css style
- * style = '...' : to include customized css style to over-write default css
- * fmt = '' sxy xsy sxx xss, str str_***, sql sql_*** please check chart_data()
- * sepCol = , : data seperator to cut columns for str_*** data
- * sepRow = ; : data seperator to cut rows for str_*** data
- * valShow = 0 / 1 : show value
- * valAngle = -90 ~ 90
- * xAngle = -90 ~ 90
- *
- * TODO: barV with negative values, it is confusing and not displaying correctly
- * legendW looks like buggy
- * &init looks horrible -- need redesign
- * also negative value for pie is ignored
- * other para tobe added = font fontSize yAxis=2
- */
-function cms_chart(&$data = null, $init = null) {
- $ceil = array('w', 'h', 'gapT', 'gapR', 'gapB', 'gapL', 'legendW', 'titleAlign', 'xTitleAlign', 'yTitleAlign', 'xSkip', 'xSkipMax', 'xAngle', 'ySum', 'pieArc', 'pieStripe', 'piePct', 'pieDonut', 'css', 'valAngle', 'valShow');
- $trim = array('chart', 'fmt', 'title', 'legend', 'style', 'sepCol', 'sepRow', 'xTitle', 'yTitle', 'yUnit', 'xFormat', 'yFormat', 'xMin', 'xMax', 'xKey', 'sort', 'xSum');
- foreach ($ceil as $k) $arr[$k] = isset($init[$k]) ? ceil($init[$k]) : 0;
- foreach ($trim as $k) $arr[$k] = isset($init[$k]) ? trim($init[$k]) : '';
- $data = cms_chart_data($data, $arr['fmt'], $arr['sort'], $arr['xKey'], $arr['xMin'], $arr['xMax'], $arr['sepRow'], $arr['sepCol'], $arr['ySum'], 'barS' === $arr['chart']);
- if (!$data) return;
- $color = cms_chart_color($init);
- $init = cms_chart_init($arr, $data, 'fix' === (isset($init['w']) ? $init['w'] : ''));
- extract($init);
- $init['color'] = $color;
- echo "\n" . '\n";
-}
-/**
- * ---------------------------------------------------------------------------
- * data fmt = '' || sxy, xsy, xss, sxx (all as array)
- * ---------------------------------------------------------------------------
- * fmt = '' or sxy (default) : col1 = serial, col2 = xAxis, col3 = yVal
- * max 3 cols, col4+ will be ignored
- * eg. select manager,month,count(*) qty from sales group by 1,2
- * Tom Jan 123
- * Sam May 234
- * data = cms_arr(sql,2) dirty or cms_arr(sql,2,1) clean
- *
- * fmt = xsy : col1 = xAxis, col2 = serial, col3 = yVal
- * max 3 cols, col4+ will be ignored
- * eg. select month,manager,count(*) qty from sales group by 1,2
- * Jan Tom 123
- * May Sam 234
- * data = cms_arr(sql,2) dirty or cms_arr(sql,2,1) clean
- * -- as a result this data same as xss
- *
- * fmt = xss : col1 = xAxis, col2...x = serial, yVal in the grid
- * eg. select month,count(*) qty,sum(amt) amt from sales group by 1
- * Jan 123 956 789 ...
- * Feb 222 933 444 ...
- * data = cms_arr(sql,1) -- only this need to convert to default sxy
- *
- * fmt = sxx : col1 = serial, col2...x = xAxis, yVal in the grid
- * very rarely when the col name is xAxis
- * eg. select manager,jan,feb,march from rep_sales
- * Tom 123 456 789 ...
- * Sam 222 333 444 ...
- * data = cms_arr(sql,1) -- data same as default sxy
- *
- * when there is only 2 cols, which means only 1 serial
- * no matter which fmt : col1 = xAxis, col2 = yVal
- * eg. select month,count(*) qty from sales group by 1
- * Jan 123
- * Feb 234
- * data = cms_row(sql,2) = cms_arr(sql,1,1) or dirty cms_arr(sql,1)
- * ---------------------------------------------------------------------------
- * as a result, if you can not remember which func to get data, remember this:
- * data = cms_arr(sql,2) : when fmt got 3 different chars eg xsy sxy
- * data = cms_arr(sql,1) : when fmt only has 2 different chars eg xss sxx
- *
- * ---------------------------------------------------------------------------
- * fmt = str || str_sxy, str_xsy, str_xss, str_sxx (all as string)
- * ---------------------------------------------------------------------------
- * default sepCol = , sepRow = ;
- *
- * str_sxy = 'Staff,month,Qty;Tom,Feb,12;Tom,Mar,34;Sam,Jan,112;...'
- * str_xsy = 'month,Staff,Qty;Feb,Tom,12;Mar,Tom,34;Jan,Sam,112;...'
- * str_xss = 'month,Qty,Vol;Feb,22,12;Mar,31,34;May,12,112;...'
- * str_sxx = 'Staff,Jan,Feb,Mar;Tom,1,2,3;Sam,2,3,4;...'
- *
- * ---------------------------------------------------------------------------
- * fmt = sql || sql_sxy, sql_xsy, sql_xss, sql_sxx (all as SQL)
- * ---------------------------------------------------------------------------
- * you need cms_arr() and cms_row() etc cms db function plugin to run this
- *
- * sql_sxy cms_arr(sql,2) select staff,year,count(*) from sales group by 1,2;
- * sql_xsy cms_arr(sql,2) select year,staff,count(*) from sales group by 1,2;
- * sql_xss cms_arr(sql,1) select year,count(*) qty,sum(amt) vol from sales group by 1;
- * sql_sxx cms_arr(sql,1) select staff,jan,feb,mar from rep_sales;
- *
- * if you only have 2 cols in sql, you have to set fmt = sql_sxx or sql_xss!!!
- * sql_*** cms_arr(sql,1) select a,b from tab -- only 2 cols
- */
-function cms_chart_data($data, $fmt, $sort, $xKey, $xMin, $xMax, $sepRow, $sepCol, $ySum, $is_barS) {
- $fmt3 = substr($fmt, 0, 3);
- if ('sql' === $fmt3) {
- $fmt = substr($fmt, 4);
- $data = cms_arr($data, ('sxx' === $fmt || 'xss' === $fmt ? 1 : 2));
- } elseif ('str' === $fmt3) {
- $fmt = substr($fmt, 4);
- $data = cms_chart_data_str($data, $fmt, $sepRow, $sepCol);
- } elseif ('jso' === $fmt3) {
- $data = json_decode($data, 1);
- }
- $num = count($data);
- if (!$num) return;
- if (!is_array(reset($data))) {
- $data = array($data); // only 2 cols
- $num = 1;
- } elseif ('xss' === $fmt || 'xsy' === $fmt) {
- foreach ($data as $x => $arr) {
- foreach ($arr as $s => $y) $sxy[$s][$x] = $y;
- }
- $data = $sxy;
- }
- $keys = array(); // x labels
- foreach ($data as $s => $arr) {
- foreach ($arr as $x => $y) {
- if (!in_array($x, $keys)) $keys[] = $x;
- if (is_array($y)) $data[$s][$x] = reset($y); // clean dirty data
- }
- }
- if (in_array($xKey, array('year','month','week','day','hour'))) {
- $keys = cms_chart_data_ymdH($xKey, $keys, $xMin, $xMax);
- } elseif ('x' === $sort) {
- sort($keys);
- }
- if ('y' === $sort && $num > 1) ksort($data);
- foreach ($data as $k => $arr) {
- foreach ($keys as $k2) $res[$k][$k2] = isset($arr[$k2]) ? $arr[$k2] + 0 : 0;
- }
- if ('y' === $sort && 1 == $num) { // if pie make sure only 1 array
- $pie = reset($res);
- arsort($pie);
- $res = array($pie);
- }
- if ($ySum) {
- foreach ($res as $k => $arr) {
- $j = $hold = 0;
- foreach ($arr as $k2 => $v) {
- if ($j++) $res[$k][$k2] += $hold;
- $hold += $v;
- }
- }
- }
- if ($is_barS) {
- foreach ($res as $k => $arr) $sortS[$k] = array_sum($arr);
- array_multisort($sortS, SORT_DESC, $res);
- }
- return $res;
-}
-function cms_chart_data_str($str, $fmt, $sepRow, $sepCol) {
- if (!$sepRow) $sepRow = ';';
- if (!$sepCol) $sepCol = ',';
- $rows = explode($sepRow, trim($str));
- $head = explode($sepCol, trim(array_shift($rows)));
- foreach ($head as $v) $cols[] = trim($v);
- unset($cols[0]);
- if (1 === count($cols)) {
- foreach ($rows as $i => $r) {
- $r = explode($sepCol, trim($r));
- $data[trim($r[0])] = trim($r[1]);
- }
- return $data;
- }
- foreach ($rows as $i => $r) {
- $r = explode($sepCol, trim($r));
- foreach ($r as $j => $v) $r[$j] = trim($v);
- if ('xss' === $fmt || 'sxx' === $fmt) {
- foreach ($r as $j => $v) {
- if ($j) $data[$r[0]][$cols[$j]] = $v;
- }
- } else {
- $data[$r[0]][$r[1]] = isset($r[2]) ? $r[2] : 0;
- }
- }
- return $data;
-}
-function cms_chart_data_ymdH($xKey, $keys, $xMin, $xMax) {
- if (!$xMin) $xMin = min($keys);
- if (!$xMax) $xMax = max($keys);
- $y1 = substr($xMin, 0, 4); $y2 = substr($xMax, 0, 4);
- if ('year' === $xKey) return range($y1, $y2);
- $keys = array();
- if ('week' === $xKey) {
- $xMin = substr($xMin, 0, 6); $xMax = substr($xMax, 0, 6);
- for ($Y = $y1; $Y <= $y2; $Y++) { for ($W = 1; $W < 54; $W++) {
- $yw = $Y . str_pad($W, 2, 0, STR_PAD_LEFT);
- if ($yw >= $xMin && $yw <= $xMax) $keys[] = $yw;
- }} // year week
- return $keys;
- }
- $m1 = substr($xMin, 0, 7); $d1 = substr($xMin, 0, 10);
- $m2 = substr($xMax, 0, 7); $d2 = substr($xMax, 0, 10);
- for ($Y = $y1; $Y <= $y2; $Y++) { for ($M = 1; $M < 13; $M++) {
- $ym = $Y .'-'. str_pad($M, 2, 0, STR_PAD_LEFT);
- if ($ym >= $m1 && $ym <= $m2) {
- if ('month' === $xKey) $keys[] = $ym;
- else { for ($D = 1; $D < 32; $D++) {
- $ymd = $ym .'-'. str_pad($D, 2, 0, STR_PAD_LEFT);
- if (checkdate($M, $D, $Y) && $ymd >= $d1 && $ymd <= $d2) {
- if ('day' === $xKey) $keys[] = $ymd;
- else { for ($H = 0; $H < 24; $H++) {
- $keys[] = $ymd .' '. str_pad($H, 2, 0, STR_PAD_LEFT);
- }} // hour
- } // valid day
- }} // day
- } // valid m
- }} // y m
- return $keys;
-}
-function cms_chart_init($arr, $data, $wFix = 0) {
- $num = count($data);
- $xNum = count(reset($data));
- if (!$arr['xSkip'] && $arr['xSkipMax'] > 0) $arr['xSkip'] = floor($xNum / $arr['xSkipMax']);
- if (!$arr['chart'] || !in_array($arr['chart'], array('line','pie','barV','barS'))) $arr['chart'] = 'bar';
- $is_pie = ('pie' === $arr['chart']);
- $arr['gapL'] += 9; // default box margin 9px each side
- $arr['gapT'] += 9;
- $arr['gapR'] += 9;
- $arr['gapB'] += 9;
- if ($arr['title']) $arr['gapT'] += 15;
- if ($arr['xTitle']) $arr['gapB'] += 15;
- if ($arr['yTitle']) $arr['gapL'] += 15;
- if (!strlen($arr['legend'])) $arr['legend'] = ($num > 1 || $is_pie) ? 'R' : '0';
- if ($arr['legendW'] < 1) $arr['legendW'] = 80;
- if ($arr['legend']) { // 0 T B R
- if ('T' === $arr['legend']) $arr['gapT'] += 15;
- elseif ('B' === $arr['legend']) $arr['gapB'] += 15;
- elseif ('L' === $arr['legend']) $arr['gapL'] += $arr['legendW'];
- else $arr['gapR'] += $arr['legendW'];
- }
- if ($is_pie) {
- if ($arr['yTitle']) $arr['gapL'] += 3;
- if ('L' === $arr['legend']) $arr['gapL'] += 51;
- elseif ('R' === $arr['legend']) $arr['gapR'] += 51;
- } else {
- $arr['gapL'] += 51; // default yLabel
- $arr['gapB'] += 16; // default xLabel
- }
- $arr['x1'] = $arr['gapL'];
- $arr['y1'] = $arr['gapT'];
- if ($arr['x1'] < 0) $arr['x1'] = 0;
- if ($arr['y1'] < 0) $arr['y1'] = 0;
-
- if (!$is_pie && $wFix) {
- $arr['x2'] = 10 * $num * $xNum + $xNum + 1;
- $arr['w'] = $arr['x1'] + $arr['x2'] + $arr['gapR'];
- } else {
- if ($arr['w'] < 1) $arr['w'] = 480;
- $arr['x2'] = $arr['w'] - $arr['x1'] - $arr['gapR'];
- if ($arr['x2'] > $arr['w'] || $arr['x2'] < $arr['x1']) $arr['x2'] = $arr['w'];
- }
- if ($arr['h'] < 1) $arr['h'] = 250;
- if ($arr['h'] > $arr['w']) $arr['h'] = $arr['w'];
- if ($is_pie) {
- $arr['y2'] = $arr['x2'];
- $arr['h'] = $arr['y1'] + $arr['y2'] + $arr['gapB']; // pie h auto calculated
- } else {
- $arr['y2'] = $arr['h'] - $arr['y1'] - $arr['gapB'];
- if ($arr['y2'] > $arr['h'] || $arr['y2'] < $arr['y1']) $arr['y2'] = $arr['h'];
- }
- return $arr;
-}
-function cms_chart_color($init) {
- // the following are default 11 colors
- $defa = array('d9534f', 'f0ad4e', '5bc0de', '5cb85c', '337ab7', 'f26522', '754c24', 'd9ce00', '0e2e42', 'ce1797','672d8b');
- // add colors at front
- if (isset($init['color']) && !is_array($init['color'])) {
- $col = explode(',', $init['color']);
- if (is_array($col)) {
- foreach ($col as $c) {
- $c = trim(substr(trim($c), 0, 6));
- if (strlen($c) > 2) $color[] = $c;
- }
- }
- }
- // del colors
- if (isset($init['colorDel'])) {
- $col = explode(',', $init['colorDel']);
- if (is_array($col)) {
- foreach ($col as $c) {
- unset($defa[ceil($c)]);
- }
- }
- }
- foreach ($defa as $c) $color[] = $c;
- // add colors at end
- if (isset($init['colorAdd'])) {
- $col = explode(',', $init['colorAdd']);
- if (is_array($col)) {
- foreach ($col as $c) {
- $c = trim(substr(trim($c), 0, 6));
- if (strlen($c) > 2) $color[] = $c;
- }
- }
- }
- return $color;
-}
-function cms_chart_axisX($data, $x1, $y1, $x2, $y2, &$xVal, $xSkip, $xFormat, $is_bar, $xAngle, $yUnit, $yFormat, $color, &$mouseInfo) {
- $xNum = count(reset($data));
- if ($is_bar) {
- $xDiv = ($x2 - $xNum - 1) / $xNum;
- $xVal[0] = round($xDiv / 2 + 1, 5);
- $xDiv++;
- $xLeft = 0;
- } else {
- $xDiv = $x2 / ($xNum - 1);
- $xVal[0] = 0;
- $xLeft = $xDiv / 2;
- }
- $xLabel = array_keys(reset($data));
- if ($xAngle) {
- $angle1 = '