vistable

The Inline Google Spreadsheet Viewer vistable class.

Defined (1)

The class is defined in the following location(s).

/lib/vistable.php  
  1. abstract class vistable { 
  2. protected $query; 
  3. protected $params; 
  4. protected $needs_total_rows; 
  5. protected $total_rows; 
  6. protected $first_row; 
  7. protected $num_rows; 
  8.  
  9. private $response; 
  10. private $tqrt; 
  11. private $tq; 
  12. private $tz; 
  13. private $locale; 
  14. protected $fields; 
  15. protected $debug; 
  16. private $aggregates; 
  17. private $visited = 0; 
  18. private $agr_reset = 0; 
  19.  
  20. public function __construct($tqx, $tq, $tqrt, $tz, $locale, $extra=NULL) { 
  21. $this->response = array('status' => 'ok'); 
  22.  
  23. $this->params = array( 
  24. 'version' => '0.6',  
  25. 'sig' => '',  
  26. 'responseHandler' => 'google.visualization.Query.setResponse' 
  27. ); 
  28.  
  29. if ($extra) { 
  30. foreach ($extra as $key => $value) { 
  31. $this->params[$key] = $value; 
  32.  
  33. if ($tqx) { 
  34. foreach (explode(';', $tqx) as $kvpair) { 
  35. $kva = explode(':', $kvpair, 2); 
  36. if (count($kva) == 2) { 
  37. $this->params[$kva[0]] = $kva[1]; 
  38.  
  39. if (get_magic_quotes_gpc()) { 
  40. $tq = stripslashes($tq); 
  41.  
  42. $this->debug = $extra && $extra['debug']; 
  43.  
  44. $this->tq = $tq; 
  45. $this->tqrt = $tqrt; 
  46. $this->tz = $tz; 
  47. $this->locale = $locale; 
  48.  
  49. $timezone = new DateTimeZone($tz); 
  50. $date = new DateTime("", $timezone); 
  51. $this->gmt_offset = $timezone->getOffset($date); 
  52.  
  53. public function get_param($param, $default = NULL) 
  54. return isset($this->params[$param]) ? $this->params[$param] : $default; 
  55.  
  56. public function get_sig() 
  57. return isset($this->response['sig']) ? $this->response['sig'] : FALSE; 
  58.  
  59. public function set_param($param, $value) 
  60. $this->params[$param] = $value; 
  61.  
  62. private function diagnostic($kind, $reason, $message, $detailed_message) 
  63. if ($this->response['status'] == 'ok' || $kind == 'error') { 
  64. $this->response['status'] = $kind; 
  65. }  
  66. $kind .= "s"; 
  67.  
  68. if (!isset($this->response[$kind])) { 
  69. $this->response[$kind] = array(); 
  70.  
  71. array_push($this->response[$kind], array( 
  72. 'reason' => $reason,  
  73. 'message' => $message,  
  74. 'detailed_message' => $detailed_message)); 
  75.  
  76. public function error($reason, $message, $detailed_message) 
  77. $this->diagnostic('error', $reason, $message, $detailed_message); 
  78.  
  79. public function warning($reason, $message, $detailed_message) 
  80. $this->diagnostic('warning', $reason, $message, $detailed_message); 
  81.  
  82. abstract protected function fetch_table($query); 
  83. protected function pre_write($q) { return NULL; } 
  84.  
  85. protected function write_func($v, $q, $rev = FALSE) 
  86. $args = array(); 
  87. for ($i=0;isset($q[$i]);$i++) { 
  88. $args[] = $this->write_expr($q[$i]); 
  89. if ($rev) $args = array_reverse($args); 
  90. return "$v(".implode(", ", $args).")"; 
  91.  
  92. protected function write_expr($q) 
  93. $r = $this->pre_write($q); 
  94. if (is_string($r)) { 
  95. return $r; 
  96. } else if ($r !== NULL) { 
  97. $q = $r; 
  98. $v = $q[VALUE]; 
  99. switch ($q[TYPE]) { 
  100. case LITERAL: 
  101. switch ($q['type']) { 
  102. case 'string': 
  103. case 'date': 
  104. case 'datetime': 
  105. case 'timeofday': 
  106. return "'".mysql_real_escape_string($v)."'"; 
  107. case 'number': 
  108. return $v; 
  109. break; 
  110. case OPERATOR: 
  111. $e0 = $this->write_expr($q[0]); 
  112. if (isset($q[1])) { 
  113. $e1 = $this->write_expr($q[1]); 
  114. return "$e0 $v $e1"; 
  115. } else { 
  116. return "$v $e0"; 
  117. case FUNCT: 
  118. return $this->write_func($v, $q); 
  119. case SIMPLE: 
  120. return $v; 
  121. private function datepart($part, $date) 
  122. $dateParts = array('dayofweek' => array('w', 1),  
  123. 'day' => 'j',  
  124. 'month' => 'n',  
  125. 'year' => 'Y',  
  126. 'hour' => 'G',  
  127. 'minute' => 'i',  
  128. 'second' => 's',  
  129. ); 
  130.  
  131. $part = $dateParts[$part]; 
  132. $offset = 0; 
  133. if (is_array($part)) { 
  134. $offset = $part[1]; 
  135. $part = $part[0]; 
  136.  
  137. $date += $this->gmt_offset; 
  138. return intval(gmdate($part, $date)) + $offset; 
  139.  
  140. private function dateparts($parts, $date) 
  141. $result = array(); 
  142. foreach ($parts as $part) { 
  143. $result[] = $this->datepart($part, $date); 
  144. return $result; 
  145.  
  146. public function evaluate($row, &$q) 
  147. $v = $q[VALUE]; 
  148. switch ($q[TYPE]) { 
  149. case STRING: 
  150. break; 
  151. case OPERATOR: 
  152. case FUNCT: 
  153. $args = array(); 
  154. for ($i=0;isset($q[$i]);$i++) { 
  155. $args[] = $this->evaluate($row, $q[$i]); 
  156. switch ($v) { 
  157. case '*': $v = $args[0] * $args[1]; break; 
  158. case '/': $v = $args[0] / $args[1]; break; 
  159. case '+': $v = $args[0] + $args[1]; break; 
  160. case '-': $v = $args[0] - $args[1]; break; 
  161. case '<': $v = $args[0] < $args[1]; break; 
  162. case '>': $v = $args[0] > $args[1]; break; 
  163. case '<=': $v = $args[0] <= $args[1]; break; 
  164. case '>=': $v = $args[0] >= $args[1]; break; 
  165. case 'starts_with': $v = !strncmp($args[0], $args[1], strlen($args[1])); break; 
  166. case 'ends_with': $v = substr($args[0], -strlen($args[1])) == $args[1]; break; 
  167. case 'contains': $v = strpos($args[0], $args[1]) !== FALSE; break; 
  168. case 'matches': $v = preg_match("/^{$args[1]}$/", $args[0]); break; 
  169. case '=': $v = $args[0] == $args[1]; break; 
  170. case '!=': 
  171. case '<>': $v = $args[0] != $args[1]; break; 
  172. case 'and': $v = $args[0] && $args[1]; break; 
  173. case 'or': $v = $args[0] || $args[1]; break; 
  174. case 'not': $v = !$args[0]; break; 
  175. case 'millisecond':$v = 0; break; 
  176. case 'year': 
  177. case 'month': 
  178. case 'day': 
  179. case 'hour': 
  180. case 'minute': 
  181. case 'second': 
  182. case 'dayofweek': 
  183. $v = $this->datepart($v, $args[0]); 
  184. break; 
  185. case 'quarter':$a=getdate($args[0]);$v = (int)(($a['mon']-1)/3)+1; break; 
  186. case 'datediff':$v = (int)($args[0] / (3600 * 24)) - (int)($args[1] / (3600 * 24)); break; 
  187. case 'now': $v = time(); break; 
  188. case 'date': 
  189. case 'datetime': 
  190. case 'timeofday': 
  191. $v = $this->convert_literal($v, $args[0]); 
  192. break; 
  193. case 'todate': 
  194. $v = 0; 
  195. switch ($q[0]["type"]) { 
  196. case 'date': 
  197. case 'datetime': 
  198. $v = (int)($args[0] / (3600 * 24)) * (3600 * 24); 
  199. break; 
  200. case 'number': 
  201. $v = (int)($args[0] / 1000); 
  202. break; 
  203. break; 
  204. case 'upper': $v = strtoupper($args[0]); break; 
  205. case 'lower': $v = strtolower($args[0]); break; 
  206.  
  207. case 'count': 
  208. case 'max': 
  209. case 'min': 
  210. case 'sum': 
  211. case 'avg': 
  212. if ($q[0]['visited'] != $this->visited) { 
  213. $q[0]['visited'] = $this->visited; 
  214. if ($this->agr_reset || !isset($q[0]['agr-count'])) { 
  215. $q[0]['agr-count'] = 1; 
  216. $q[0]['agr-max'] = $args[0]; 
  217. $q[0]['agr-min'] = $args[0]; 
  218. $q[0]['agr-sum'] = $args[0]; 
  219. $q[0]['agr-avg'] = $args[0]; 
  220. } else { 
  221. $q[0]['agr-count'] += 1; 
  222. if ($args[0] > $q[0]['agr-max']) { 
  223. $q[0]['agr-max'] = $args[0]; 
  224. if ($args[0] < $q[0]['agr-max']) { 
  225. $q[0]['agr-min'] = $args[0]; 
  226. $q[0]['agr-sum'] += $args[0]; 
  227. $q[0]['agr-avg'] = $q[0]['agr-sum'] / $q[0]['agr-count']; 
  228. $this->aggregates = 1; 
  229. $v = $q[0]['agr-'.$v]; 
  230. break; 
  231. break; 
  232. case SIMPLE: 
  233. $v = $row[$v]; 
  234. case LITERAL: 
  235. $v = $this->convert_literal($q['type'], $v); 
  236. if ($this->debug) { 
  237. echo "{$q[TYPE]}:{$q[VALUE]}:{$q['type']} = $v\n"; 
  238. return $v; 
  239.  
  240. private function mktime($year, $month, $day, $hour, $minute, $second, $ms = 0) 
  241. $year = intval($year, 10); 
  242. $month = intval($month, 10); 
  243. $day = intval($day, 10); 
  244. $hour = intval($hour, 10); 
  245. $minute = intval($minute, 10); 
  246. $second = intval($second, 10); 
  247. return gmmktime($hour, $minute, $second, $month, $day, $year); 
  248.  
  249. private function convert_literal($type, $v) 
  250. if ($v !== NULL) { 
  251. switch ($type) { 
  252. case 'date': 
  253. if (is_string($v) && preg_match('/^(....)-(..)-(..)( (..):(..):(..))?$/', $v, $matches)) { 
  254. $v = $this->mktime($matches[1], $matches[2], $matches[3], 0, 0, 0); 
  255. } else { 
  256. $v = (double)$v; 
  257. break; 
  258. case 'timeofday': 
  259. if (is_string($v) && preg_match('/^((....)-(..)-(..) )?(..):(..):(..)$/', $v, $matches)) { 
  260. $v = $this->mktime(1971, 1, 1, $matches[5], $matches[6], $matches[7]); 
  261. } else { 
  262. $v = (double)$v; 
  263. break; 
  264. case 'datetime': 
  265. if (is_string($v) && preg_match('/^(....)-(..)-(..) (..):(..):(..)$/', $v, $matches)) { 
  266. $v = $this->mktime($matches[1], $matches[2], $matches[3],  
  267. $matches[4], $matches[5], $matches[6]); 
  268. } else { 
  269. $v = (double)$v; 
  270. break; 
  271. case 'number': 
  272. $v = (double)$v; 
  273. break; 
  274. case 'boolean': 
  275. if (is_string($v) && !strcasecmp($v, "false")) { 
  276. $v = FALSE; 
  277. } else { 
  278. $v = (bool)$v; 
  279. break; 
  280. return $v; 
  281.  
  282. private function value_convert($type, $v) 
  283. if ($v !== NULL) { 
  284. switch ($type) { 
  285. case 'date': 
  286. $a = $this->dateparts(array('year', 'month', 'day'), $v); 
  287. $m = $a[1]-1; 
  288. return "new Date({$a[0]}, $m, {$a[2]})"; 
  289. case 'timeofday': 
  290. $a = $this->dateparts(array('hour', 'minute', 'second'), $v); 
  291. return "[{$a[0]}, {$a[1]}, {$a[2]}]"; 
  292. case 'datetime': 
  293. $a = $this->dateparts(array('year', 'month', 'day', 'hour', 'minute', 'second'), $v); 
  294. $m = $a[1]-1; 
  295. return "new Date({$a[0]}, $m, {$a[2]}, {$a[3]}, {$a[4]}, {$a[5]})"; 
  296. return $v; 
  297.  
  298. protected function make_order($elist, $order, &$cols, &$exprs) 
  299. foreach ($elist as &$col) { 
  300. $dir = isset($col['dir']) && $col['dir'] == 'desc' ? -1 : 1; 
  301. $s = $this->write_expr($col); 
  302. if (!isset($exprs[$s])) { 
  303. $cols[] = array('id' => $s, 'label' => $s, 'type' => $col['type']); 
  304. $exprs[$s] = $col; 
  305. $order[$s] = $dir; 
  306. return $order; 
  307.  
  308. protected function setup_rownums($query, $total) 
  309. $this->total_rows = $total; 
  310. $this->first_row = $query['offset'] ? $this->evaluate(NULL, $query['offset']) : 0; 
  311. $this->num_rows = $query['limit'] ? $this->evaluate(NULL, $query['limit']) : $total; 
  312.  
  313. if ($total >= 0 && isset($this->params['pagenum']) && isset($this->params['pagerow'])) { 
  314. $pr = intval($this->params['pagerow']); 
  315. $pn = intval($this->params['pagenum']); 
  316. $np = 1; 
  317. if (isset($this->params['numpage'])) { 
  318. $np = intval($this->params['numpage']); 
  319. if ($pr > 0 && $total > 0) { 
  320. if ($pr > $total) $pr = $total; 
  321. $mp = ceil($total / $pr); 
  322. if ($pn > $mp) $pn = $mp; 
  323. if ($pn < 1) $pn = 1; 
  324. $this->first_row = ($pn - 1) * $pr; 
  325. $this->num_rows = $pr * $np; 
  326. if ($this->first_row + $this->num_rows > $total) { 
  327. $this->num_rows = $total-$this->first_row; 
  328. $this->page_num = floor($this->first_row / $pr) + 1; 
  329. $this->total_pages = $mp; 
  330.  
  331. public function query_filter(&$rows, $query) 
  332. $pivot_key = "pivot|key"; 
  333. $group_key = "group|key"; 
  334.  
  335. $cols = array(); 
  336. $order = array(); 
  337. $exprs = array(); 
  338. foreach ($query['select'] as &$col) { 
  339. $s = $this->write_expr($col); 
  340. $c = array('id' => $s, 'label' => $s, 'type' => $col['type']); 
  341. if ($col['type'] != 'string' && $col['format']) { 
  342. $c['pattern'] = $col['format']; 
  343. if ($col['label']) { 
  344. $c['label'] = $col['label']; 
  345. if ($col['is_pivot'] || $col['is_group']) { 
  346. $c['group'] = 1; 
  347. if ($col['is_aggregate']) { 
  348. $c['is_aggregate'] = 1; 
  349. $cols[] = $c; 
  350. $exprs[$s] =& $col; 
  351.  
  352. unset($col); 
  353.  
  354. $ncol = count($cols); 
  355. if (isset($this->params['sortcol']) && 
  356. isset($exprs[$this->params['sortcol']])) 
  357. $order[$this->params['sortcol']] = !strcasecmp($this->params['sortdir'], 'desc') ? 'desc' : 'asc'; 
  358.  
  359. if (isset($query['order'])) { 
  360. $order = $this->make_order($query['order'], $order, $cols, $exprs); 
  361. } else if (isset($query['group'])) { 
  362. $order = $this->make_order($query['group'], $order, $cols, $exprs); 
  363.  
  364. /** If grouping/pivoting is required, match the rows to their groups */ 
  365. $groups = array(); 
  366. $ga = isset($query['group']) ? $query['group'] : array(); 
  367. $pa = isset($query['pivot']) ? $query['pivot'] : array(); 
  368. $porder = NULL; 
  369. if ($pa || $ga) { 
  370. if ($pa) { 
  371. $porder = $this->make_order($query['pivot'], array(), $cols, $exprs); 
  372. foreach ($rows as $row) { 
  373. if (!$query['where'] || 
  374. $this->evaluate($row, $query['where'])) { 
  375. $gkey = ""; 
  376. foreach ($ga as &$value) { 
  377. $k = $this->evaluate($row, $value); 
  378. $k = str_replace('|', '||', $k); 
  379. $gkey .= "$k|"; 
  380. $pkey = ""; 
  381. foreach ($pa as &$value) { 
  382. $k = $this->evaluate($row, $value); 
  383. $k = str_replace('|', '||', $k); 
  384. $pkey .= "$k|"; 
  385. if ($pa) { 
  386. $row[$pivot_key] = $pkey; 
  387. $row[$group_key] = $gkey; 
  388. $groups[$pkey.$gkey][] = $row; 
  389. $this->aggregates = 1; 
  390. } else { 
  391. if ($query['where']) { 
  392. foreach ($rows as $row) { 
  393. if ($this->evaluate($row, $query['where'])) { 
  394. $groups[""][] = $row; 
  395. } else { 
  396. $groups[""] = $rows; 
  397. $this->aggregates = 0; 
  398.  
  399. /** 
  400. Evaluate the rows by groups. Note that $this->aggregates may become 
  401. true even if there are no groups, if any of the aggregation functions 
  402. is used. 
  403. */ 
  404. $rout = array(); 
  405. foreach ($groups as $pgkey => $grows) { 
  406. $this->agr_reset = 1; 
  407. foreach ($grows as $row) { 
  408. $this->visited++; 
  409. $r = array(); 
  410. $i = 0; 
  411. foreach ($exprs as &$col) { 
  412. $v = $this->evaluate($row, $col); 
  413. $r[$cols[$i++]['id']] = $v; 
  414. if ($pa) { 
  415. $r[$pivot_key] = $row[$pivot_key]; 
  416. $r[$group_key] = $row[$group_key]; 
  417. if (!$this->aggregates) { 
  418. $rout[] = $r; 
  419. $this->agr_reset = 0; 
  420. if (!$this->agr_reset && 
  421. $this->aggregates && 
  422. (!$query['having'] || 
  423. $this->evaluate($row, $query['having']))) 
  424. $rout[] = $r; 
  425.  
  426. unset($col); 
  427.  
  428. global $vistable_ordering; 
  429. if ($pa) { 
  430. $vistable_ordering = $porder; 
  431. usort($rout, "vistable_order_function"); 
  432.  
  433. $pivots = array(); 
  434. foreach ($rout as $row) { 
  435. if (!isset($pivots[$row[$pivot_key]])) { 
  436. $pivots[$row[$pivot_key]] = 1; 
  437.  
  438. if ($order) { 
  439. $vistable_ordering = $order; 
  440. usort($rout, "vistable_order_function"); 
  441.  
  442. if (count($cols) > $ncol) { 
  443. $cols = array_slice($cols, 0, $ncol); 
  444. foreach ($rout as &$row) { 
  445. $pk = $row[$pivot_key]; 
  446. $gk = $row[$group_key]; 
  447. $row = array_slice($row, 0, $ncol, TRUE); 
  448. if ($pa) { 
  449. $row[$pivot_key] = $pk; 
  450. $row[$group_key] = $gk; 
  451. unset($row); 
  452.  
  453. if ($pa) { 
  454. $groups = array(); 
  455.  
  456. foreach ($rout as $row) { 
  457. $groups[$row[$group_key]][$row[$pivot_key]] = $row; 
  458.  
  459. $nrows = array(); 
  460. $ncols = array(); 
  461.  
  462. // Copy "grouped" columns to new col array 
  463. foreach ($cols as $col) { 
  464. if (!$col['is_aggregate']) { 
  465. $ncols[] = $col; 
  466.  
  467. // Create pivoted columns for non-"grouped" columns 
  468. foreach ($pivots as $pivot => $value) { 
  469. foreach ($cols as $col) { 
  470. if ($col['is_aggregate']) { 
  471. $col['id'] = $pivot.$col["id"]; 
  472. $col['label'] = $pivot.$col["label"]; 
  473. $ncols[] = $col; 
  474.  
  475. foreach ($groups as $gkey => $rs) { 
  476. $nrow = array(); 
  477. // get the "grouped" elements of the row 
  478. foreach ($cols as $col) { 
  479. if (!$col['is_aggregate']) { 
  480. foreach ($rs as $row) { 
  481. $nrow[] = $row[$col['id']]; 
  482. break; 
  483. // and now the "pivoted" elements 
  484. foreach ($pivots as $pivot => $value) { 
  485. $row = isset($rs[$pivot]) ? $rs[$pivot] : NULL; 
  486. foreach ($cols as $col) { 
  487. if ($col['is_aggregate']) { 
  488. $nrow[] = $row !== NULL ? $row[$col['id']] : NULL; 
  489.  
  490. $nrows[] = $nrow; 
  491.  
  492. $cols = $ncols; 
  493. $rout = $nrows; 
  494.  
  495. $this->setup_rownums($query, count($rout)); 
  496.  
  497. $rows = array_slice($rout, $this->first_row, $this->num_rows); 
  498. return $cols; 
  499.  
  500. public function execute() 
  501. $table = NULL; 
  502.  
  503. $outfmt = "json"; 
  504. if (isset($this->params["out"])) { 
  505. $outfmt = $this->params["out"]; 
  506. if ($outfmt == 'jqgrid' || $outfmt == 'jqgrid-xml') { 
  507. $this->needs_total_rows = TRUE; 
  508.  
  509. if ($this->response['status'] != 'error') { 
  510.  
  511. $parser = new visparser($this->fields); 
  512. $this->query = $parser->parse($this->tq); 
  513.  
  514. if ($this->debug) { 
  515. print "tq: $tq\n"; 
  516. print_r($parser); 
  517.  
  518. if (!$this->query) { 
  519. $this->error('invalid_query', "", $parser->error_message); 
  520. } else { 
  521. $table = $this->fetch_table($this->query); 
  522.  
  523. if ($table) { 
  524. $no_values = isset($this->query["options"]["no_values"]); 
  525. $no_format = isset($this->query["options"]["no_format"]); 
  526. if ($outfmt != "json") { 
  527. $no_values = true; 
  528. $no_format = false; 
  529. $rows = array(); 
  530. $cols = $table['cols']; 
  531. $formatters = array('date' => new DateFormatter($this->locale, $this->tz,  
  532. 'yyyy-MM-dd'),  
  533. 'timeofday' => new DateFormatter($this->locale, $this->tz,  
  534. 'HH:mm:ss'),  
  535. 'datetime' => new DateFormatter($this->locale, $this->tz,  
  536. 'yyyy-MM-dd HH:mm:ss')); 
  537.  
  538. foreach ($cols as &$colref) { 
  539. if (isset($colref['pattern'])) { 
  540. switch ($colref['type']) { 
  541. case 'number': 
  542. $colref['fmt'] = new NumberFormatter($this->locale,  
  543. NumberFormatter::PATTERN_DECIMAL,  
  544. $colref['pattern']); 
  545. if ($this->debug) { 
  546. print_r($colref['fmt']); 
  547. break; 
  548. case 'date': 
  549. case 'datetime': 
  550. case 'timeofday': 
  551. $colref['fmt'] = new DateFormatter($this->locale, $this->tz,  
  552. $colref['pattern']); 
  553. if ($this->debug) { 
  554. print_r($colref['fmt']); 
  555. break; 
  556. case 'boolean': 
  557. $colref['fmt'] = new BoolFormatter($colref['pattern']); 
  558. if ($this->debug) { 
  559. print_r($colref['fmt']); 
  560. break; 
  561. } else if (isset($formatters[$colref['type']])) { 
  562. $colref['fmt'] = $formatters[$colref['type']]; 
  563.  
  564. foreach ($table['rows'] as $row) { 
  565. $r = array(); 
  566. foreach ($row as $key => $value) { 
  567. $val = $v = $f = $value; 
  568. $c = count($r); 
  569. $col = $cols[$c]; 
  570. $type = $col['type']; 
  571. $v = $this->convert_literal($type, $v); 
  572. if ($v === NULL) { 
  573. $a = NULL; 
  574. } else { 
  575. $a = array(); 
  576. if (!$no_values) { 
  577. $a['v'] = $this->value_convert($type, $v); 
  578. if (!$no_format) { 
  579. if ($col['fmt']) { 
  580. $f = $col['fmt']->format($v); 
  581. $a['f'] = $f; 
  582. $r[] = $a; 
  583. $rows[] = array('c'=>$r); 
  584. $table['rows'] = $rows; 
  585. $this->response['table'] = $table; 
  586.  
  587. $sig = json_encode($this->response); 
  588. if ($this->needs_total_rows) { 
  589. $sig .= ":".$this->total_rows.":".$this->first_row; 
  590.  
  591. $sig = md5($sig); 
  592.  
  593. if ($sig == $this->params['sig']) { 
  594. $this->error('not_modified', '', ''); 
  595.  
  596. unset($this->response['table']); 
  597. $this->response['version'] = $this->params['version']; 
  598. if (isset($this->params['reqId'])) { 
  599. $this->response['reqId'] = $this->params['reqId']; 
  600.  
  601. $this->response['sig'] = $sig; 
  602.  
  603. if ($this->response['status'] == 'error') { 
  604. $table = NULL; 
  605. unset($this->response['warnings']); 
  606. if ($table) { 
  607. $this->response['table'] = $table; 
  608.  
  609. if ($this->debug) { 
  610. $outfmt = "debug"; 
  611.  
  612. $out = ""; 
  613. switch ($outfmt) { 
  614. case 'json': 
  615. header('Content-type: text/plain; charset="UTF-8"'); 
  616.  
  617. $out = json_encode($this->response); 
  618. $out = preg_replace('/"(new Date\(.*?\))"/', "$1", $out); 
  619. $out = preg_replace('/([\{, ])"([A-Za-z_][A-Za-z0-9_]*)"/', "$1$2", $out); 
  620. $out = $this->params['responseHandler']."($out);\n"; 
  621. break; 
  622. case 'csv': 
  623. if (isset($this->params['outFileName'])) { 
  624. header('Content-type: text/csv; charset="UTF-8"'); 
  625. header('Content-disposition: attachment; filename='.$this->params['outFileName']); 
  626. } else { 
  627. header('Content-type: text/plain; charset="UTF-8"'); 
  628.  
  629. if ($table) { 
  630. $out = self::csv_row($table['cols'], "label"); 
  631. foreach ($table['rows'] as $row) { 
  632. $out .= self::csv_row($row['c'], 'f'); 
  633. break; 
  634. case 'html': 
  635. header('Content-type: text/html; charset="UTF-8"'); 
  636.  
  637. $out = "<html><body><table border='1' cellpadding='2' cellspacing='0'>"; 
  638. if ($this->response['status'] != 'ok') { 
  639. if (isset($this->response['errors'])) { 
  640. $out .= self::html_diagnostic($this->response['errors'], "#f00"); 
  641. if (isset($this->response['warnings'])) { 
  642. $out .= self::html_diagnostic($this->response['warnings'], "#ff0"); 
  643. $out .= "</table><table border='1' cellpadding='2' cellspacing='0'>"; 
  644. if ($table) { 
  645. $out .= self::html_row($table['cols'], 'label', 'font-weight: bold; background-color: #aaa;'); 
  646. $colors = array('#f0f0f0', '#ffffff'); 
  647. $cix = 0; 
  648. foreach ($table['rows'] as $row) { 
  649. $out .= self::html_row($row['c'], 'f', 'background-color: '.$colors[$cix]); 
  650. $cix ^= 1; 
  651. $out .= "</table></body></html>"; 
  652. break; 
  653. case 'tsv-excel': 
  654. if (isset($this->params['outFileName'])) { 
  655. header('Content-type: text/tab-separated-values; charset="UTF-16"'); 
  656. header('Content-disposition: attachment; filename='.$this->params['outFileName']); 
  657. } else { 
  658. header('Content-type: text/plain; charset="UTF-16"'); 
  659. if ($table) { 
  660. $out = self::tsv_row($table['cols'], "label"); 
  661. foreach ($table['rows'] as $row) { 
  662. $out .= self::tsv_row($row['c'], 'f'); 
  663. break; 
  664. case 'jqgrid': 
  665. header('Content-type: text/json; charset="UTF-8"'); 
  666. $out = array("records" => $this->total_rows); 
  667. if ($this->num_rows > 0) { 
  668. $out['page'] = $this->page_num; 
  669. $out['total'] = $this->total_pages; 
  670. $out['num_rows'] = $this->num_rows; 
  671. } else { 
  672. $out['page'] = 0; 
  673. $out['total'] = 1; 
  674.  
  675. $rows = array(); 
  676. foreach ($table['rows'] as $row) { 
  677. $r = array(); 
  678. foreach ($row['c'] as $c) { 
  679. array_push($r, $c['f']); 
  680. array_push($rows, $r); 
  681. $out['rows'] = $rows; 
  682.  
  683. $out = json_encode($out); 
  684. break; 
  685. case 'jqgrid-xml': 
  686. header('Content-type: application/xml; charset="UTF-8"'); 
  687. $out = '<?xml version="1.0" encoding="UTF-8" standalone="no" ?>'; 
  688. $page = $this->num_rows > 0 ? $this->page_num : 0; 
  689. $total = $this->num_rows > 0 ? $this->total_pages : 1; 
  690. $out .= "<jqgrid><rows>"; 
  691. $out .= "<records>{$this->total_rows}</records>"; 
  692. $out .= "<page>{$page}</page>"; 
  693. $out .= "<total>{$total}</total>"; 
  694. $out .= "<num_rows>{$this->num_rows}</num_rows>"; 
  695. $rows = array(); 
  696. foreach ($table['rows'] as $row) { 
  697. $out .= "<row>"; 
  698. foreach ($row['c'] as $c) { 
  699. $out .= "<cell>".htmlspecialchars($c['f'], ENT_COMPAT, "UTF-8")."</cell>"; 
  700. $out .= "</row>"; 
  701. $out .= "</rows></jqgrid>"; 
  702. break; 
  703.  
  704. case 'jqgrid-config': 
  705. header('Content-type: text/plain; charset="UTF-8"'); 
  706. $colmodel = array(); 
  707. foreach ($table['cols'] as $col) { 
  708. $c = array('label' => $col['label'],  
  709. 'name' => $col['id']); 
  710. switch ($col['type']) { 
  711. case 'number': 
  712. $c['align'] = 'right'; 
  713. $c['sortorder'] = 'float'; 
  714. break; 
  715. case 'date': 
  716. $c['sortorder'] = 'date'; 
  717. break; 
  718. array_push($colmodel, $c); 
  719.  
  720. $out = array("jsonReader" => array("root" => "rows",  
  721. "page" => "page",  
  722. "total" => "total",  
  723. "records" => "records",  
  724. "cell" => "",  
  725. "id" => "0"),  
  726. "colModel" => $colmodel 
  727. ); 
  728.  
  729. $out = json_encode($out); 
  730. break; 
  731.  
  732. case 'debug': 
  733. header('Content-type: text/plain; charset="UTF-8"'); 
  734. ob_start(); 
  735. var_dump($this->response); 
  736. $out=ob_get_contents(); 
  737. ob_end_clean(); 
  738. break; 
  739.  
  740. return $out; 
  741.  
  742. private static function csv_row($r, $id) 
  743. return self::sv_row($r, $id, ', '); 
  744.  
  745. private static function tsv_row($r, $id) 
  746. return iconv("UTF-8", "UTF-16", self::sv_row($r, $id, "\t")); 
  747.  
  748. private static function sv_row($r, $id, $sep) 
  749. $out = array(); 
  750. foreach ($r as $v) { 
  751. if (!$v) { 
  752. $x = ""; 
  753. } else {  
  754. $x = $v[$id]; 
  755. if (strpbrk($x, '"'.$sep)) { 
  756. $x = str_replace('"', '""', $x); 
  757. $x = '"'.$x.'"'; 
  758. $out[] = $x; 
  759. return implode($sep, $out)."\n"; 
  760.  
  761. private static function html_diagnostic($diagnostics, $color) 
  762. $out = ""; 
  763. foreach ($diagnostics as $diag) { 
  764. $out .= "<tr style='background-color: $color'>"; 
  765. $out .= "<td>{$diag['reason']}</td>"; 
  766. $msg = isset($diag['message']) ? $diag['message'] : " "; 
  767. $out .= "<td>$msg</td>"; 
  768. $msg = isset($diag['detailed_message']) ? $diag['detailed_message'] : " "; 
  769. $out .= "<td>$msg</td>"; 
  770. $out .= "</tr>"; 
  771. return $out; 
  772.  
  773. private static function html_row($r, $id, $style) 
  774. $out = "<tr style='$style'>"; 
  775. foreach ($r as $v) { 
  776. if (!$v) { 
  777. $x = ""; 
  778. } else {  
  779. $x = $v[$id]; 
  780. if ($x == "") { 
  781. $x = ""; 
  782. if ($x == "") { 
  783. $x = " "; 
  784. } else { 
  785. $x = htmlspecialchars($x, ENT_COMPAT, "UTF-8"); 
  786. $out .= "<td>$x</td>"; 
  787. return $out."\n"; 
  788. };