<?php
require_once('functions.php');
-define('CACHE_DIR',"/tmp/cache.php");
+if (!defined('CACHE_DIR')) define('CACHE_DIR',"/tmp/cache.php");
if (!file_exists(CACHE_DIR)) mkdir(CACHE_DIR,7770);
function cache_get_file($id,$expires) {
*****************************************************************************/
require_once(dirname(__FILE__).'/functions.php');
-if (!defined('DB_HTML_EDIT')) define('DB_HTML_EDIT','Edit');
+require_once(dirname(__FILE__).'/db/table.php');
+require_once(dirname(__FILE__).'/db/field.php');
+if (!defined('DB_ERR_PRINT')) define('DB_ERR_PRINT',true);
class db {
#bye($db['conn']);
$this->conn = new PDO($db['conn']);
+ if (DB_ERR_PRINT) $this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
#if (empty($this->name)) $this->name = preg_replace('/^(?:(?:sqlite:.*(.*?)(\.\w+)?)|(?:.*?dbname=([^;]+).*?))$/','\1',$db['conn']);
if (empty($this->name) and preg_match('/(?:sqlite:|dbname=)([^;\.]+)/',$db['conn'],$m)) {
$this->name = $m[1];
}
-class table {
-
- public $name;
- public $db;
- public $sql;
- public $fields = array();
- public $fields_keys = array();
- public $extras = array();
- public $params = array(
- 'table',
- 'limit',
- 'debug',
- );
-
- function __construct($name,$opt=array()) {
-
- // Connection
- if (@$opt['db']) {
- $this->db = @$opt['db'];
- } else {
- $this->db = new db();
- }
-
- // Table could be a select
- if (stripos($name,'SELECT ')===0) {
- $this->db->conn->query("CREATE TEMPORARY TABLE _query_ AS $name");
- $name = '_query_';
- } elseif (preg_match('/\b(\.import|LOAD DATA|COPY|INSERT|REPLACE|DELETE|TRUNCATE|CREATE|DROP|ALERT)\b/',$name)) {
- bye("Query not Allowed !");
- }
-
- $this->name = $name;
-
- if (@$opt['extras']) $this->add_extras($opt['extras']);
-
- return $this->fields();
- }
-
- /*
- * Function db.fields
- *
- * return all or one fields from a table
- *
- * @name (string) name of the field to return. Default: null
- * @return (array) return null where name does not exsts
- */
- function fields($name=null) {
-
- if (!$this->fields) {
-
- if ($this->db->type == 'sqlite') {
- $sql = "PRAGMA table_info('$this->name')";
-
- } elseif ($this->db->type == 'pgsql') {
-$sql = "SELECT
-a.attname AS name,
-pg_catalog.format_type(a.atttypid, a.atttypmod) AS type,
-CASE a.attnotnull WHEN 't' then 1 ELSE 0 END AS notnull,
-(SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128) FROM pg_catalog.pg_attrdef d WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef) AS default,
-(SELECT 1 FROM pg_index i WHERE a.attrelid = i.indrelid AND a.attnum = ANY(i.indkey) AND i.indrelid = '$this->name'::regclass AND i.indisprimary) as pk
-FROM pg_catalog.pg_attribute a WHERE a.attrelid = (SELECT c.oid FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE c.relname='$this->name' AND pg_catalog.pg_table_is_visible(c.oid) ) AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum";
-
- } elseif ($this->db->type == 'mysql') {
- $sql = "SHOW COLUMNS FROM `$this->name`";
-
- } else {
- err('table.fields(): Unknow db type: '.$this->db->type);
- return array();
-
- }
-
- $rows = $this->db->conn->query($sql);
-
- $rows->setFetchMode(PDO::FETCH_ASSOC);
-
- foreach ($rows as $row) {
-
- $this->fields[$row['name']] = array(
- 'extra' => null,
- 'type' => null,
- 'default' => null,
- 'key' => null,
- );
-
- $this->fields[$row['name']]['type'] = $row['type'];
-
- if (isset($row['notnull'])) {
- $this->fields[$row['name']]['null'] = $row['notnull'] == '0' ? 1 : 0;
-
- } else {
- $this->fields[$row['name']]['null'] = preg_match('/^1|yes|t/i',$row['null']) ? 1 : 0;
-
- }
-
- foreach (array('dflt_value') as $f) {
- if (!isset($row[$f])) continue;
- $this->fields[$row['name']]['default'] = $row[$f];
- }
-
- foreach (array('pk','Key') as $f) {
- if (!isset($row[$f])) continue;
- $this->fields[$row['name']]['key'] = preg_match('/^1|yes|t/i',$row[$f]) ? 1 : 0;
- }
-
- }
-
- }
-
- if ($name !== null ) {
- if (!isset($this->fields[$name])) return null;
- return $this->fields[$name];
- }
-
- return $this->fields;
- }
-
- function url_edit($values=null,$sep='&') {
- if ($values === null) $values = $this->db->p();
- $url_edit = array();
-
- foreach ($this->fields_keys() as $name => $spec) {
- $url_edit[] = $name . '=' .urlencode($values[$name]);
- }
-
- return $url_edit ? 'edit/?table='.$this->db->p('table').$sep.join($sep,$url_edit) : '';
-
- }
-
- function fields_keys() {
-
- if (!$this->fields_keys) {
- $this->fields_keys = array();
-
- foreach ($this->fields() as $name => $f) {
- #debug($f);
- if (@$f['key'] == 1) $this->fields_keys[$name] = $f;
- }
-
- }
-
- return $this->fields_keys;
-
- }
-
- function html_edit($values = null) {
- if ($values === null) $values = $this->db->p();
- if (!is_array($values)) $values = array($values);
-
- $sql = "SELECT *" . $this->select_extras();
- $sql .= " FROM $this->name".str_replace(' LIKE ','=',$this->where_criterias($values));
- $sql .= " LIMIT 1";
- $this->sql = $sql;
-
- $this->debug($sql,1);
- $st = $this->db->conn->prepare($sql);
- $st->execute();
-
- echo '<form class="db edit" method="post">'.PHP_EOL;
- $count = 0;
- if ($row = $st->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_NEXT)) {
- $count ++;
-
- foreach ($this->fields() as $name => $attr) {
- $field = new field($name,$attr);
- $field->html_edit(array_key_exists($name,$row) ? $row[$name] : $attr['default']);
-// NB 03.07.15 continue;
-// NB 03.07.15
-// NB 03.07.15 $value = array_key_exists($name,$row) ? $row[$name] : $attr['default'];
-// NB 03.07.15
-// NB 03.07.15 echo '<label for="'.$name.'">'.htmlspecialchars($name).'</label>'
-// NB 03.07.15 .'<input name="'.$name.'" id="'.$name.'" value="'.htmlspecialchars($value).'" />'
-// NB 03.07.15 .PHP_EOL;
- }
- }
-
- echo ''
- .'<div class="db buttons">'
- .'<input type="submit" name="update"/>'
- .'<input type="text" name="table" value="'.$this->db->p('table').'"/>'
- .'<input type="reset" />'
- .( empty($_SERVER['HTTP_REFERER']) ? '' : '<input type="button" onclick="document.location=document.referrer" value="Cancel" />')
- .'</div>'.PHP_EOL
- .'</form>'.PHP_EOL;
-
- $this->row = $row;
- return $this;
- }
-
- function debug($msg,$level=0) { return debug($msg,$level); }
-
- function url_params($k='',$v='') {
-
- $params = array();
-
- foreach (array_merge( $this->params, array_keys($this->fields()) ) as $f) {
-
- if (@strcmp($this->db->p($f),'')==0) continue;
- $params[$f] = $this->db->p($f);
-
- }
-
- if ($k) {
-
- if (strcmp($v,'')==0) {
- unset($params[$k]);
- } else {
- $params[$k] = $v;
- }
-
- }
-
- $flat = array();
- foreach ($params as $k=>$v) { $flat[] = $k.'='.urlencode($v); }
- return $flat ? '?'. join('&',$flat) : '';
-
- }
-
- function url_sort($name) {
-
- $html = '';
-
- # Asc
- $sel = ( $this->db->p('sort')=="$name asc") ? " sel" : "";
- $html .= '<a title="First In (asc)" class="sort asc'.$sel.'" href="'.$this->url_params("sort","$name asc").'">'
- .'<span class="asc">↓</span>'
- .'</a>';
- $html .= ' ';
-
- $html .= ucfirst($name);
-
- $html .= ' ';
-
- # Desc
- $sel = ( $this->db->p('sort')=="$name desc") ? " sel" : "";
- $html .= '<a title="Last In (desc)" class="sort desc'.$sel.'" href="'.$this->url_params("sort","$name desc").'">'
- .'<span class="desc">↑</span>'
- .'</a>';
-
- return $html;
-
- }
-
- function nav($count,$tot,$limit) {
-
- if ($count<$tot) {
- list($x,$y) = strpos($limit,',')!==false
- ? preg_split('/\s*,\s*/',$limit)
- : array(0,$limit)
- ;
-
- $prev = $x - $y;
- $next = $x + $y;
-
- $this->debug("x=$x limit=$y prev=$prev next=$next tot=$tot",1);
- } else {
- $x = 0;
- $y = $tot;
- $prev = -1;
- $next = 999999;
- }
-
- echo '<div align="center" class="nav" id="nav_bottom">';
-
- if ($prev>=0) echo '<span class="prev"><a href="'.$this->url_params('limit',preg_replace('/^0,/','',"$prev,$y")).'"><<</a></span> ';
-
- echo '<span class="count">'.($tot ? ($x+1) : 0).' - '.($x+$y).' / '.$tot.' results</span>';
-
- if ($next<$tot) echo ' <span class="prev"><a href="'.$this->url_params('limit',"$next,$y").'">>></a></span>';
-
- echo '</div>'.PHP_EOL;
- static $js = null;
- if ($js === null) {
- echo '<script type="text/javascript"><!-- '.PHP_EOL
- ."var rb = document.getElementById('nav_bottom'); var rt = document.getElementById('nav_top'); if (rb && rt) rt.innerHTML = rb.innerHTML;\n"
- . ' --></script>'.PHP_EOL
- ;
- $js = '1';
- }
-
- }
-
- function form_criterias($opt=array()) {
-
- echo '<form class="criteria bgcolor border rad inline" method="get" action="">'.PHP_EOL;
- echo '<div class="small help">Use: '.join(' | ',$this->db->help_criterias).'</div>'.PHP_EOL;
-
- foreach ($this->params as $k) {
- $v = @$_REQUEST[$k];
- if ($k == 'limit') $v = '';
- echo '<input type="hidden" name="'.$k.'" value="'.$v.'" />'.PHP_EOL;
- }
-
- $criteria = array();
- foreach ( array_keys($this->fields()) as $k ) {
-
- $v = @$_REQUEST[$k];
-
- $criteria[] = ''
- . '<label>'.prettyText($k).':</label>'
- . '<input type="text" id="'.$k.'" name="'.$k.'" value="'.$v.'" />'
- ;
-
- }
-
- $criteria[] = html_select_array(array(
- 'AND',
- 'OR',
- ),array(
- 'html' => 'name="op"',
- 'selected' => $this->db->p('op'),
- ));
-
- $criteria[] = html_select_array(array(
- array('','HTML'),
- array('csv','CSV'),
- array('xml','XML'),
- array('yaml','YAML'),
- array('json','JSON'),
- ),array(
- 'html' => 'name="format"',
- 'selected' => $this->db->p('format'),
- ));
- $criteria[] = '<input type="submit" class="button" value="GO"/>';
-
- echo join(''.PHP_EOL,$criteria);
-
- echo '</form>'.PHP_EOL;
-
- }
-
- function where_criterias($values,$logic='AND') {
- $having = $where = array();
-
- foreach ($this->fields() as $k => $spec) {
-
- $field = new field($k,$spec);
-
- // No empty values
- $v = @$values[$k];
- if (strcmp($v,'')==0 or $v=='!' or $v=='~') continue;
-// NB 03.07.15 $number = preg_match('/int|float|number|currency/',$spec['type']) ? 1 : 0;
- $number = $field->is_num();
-
- // Equal / Not Equal
- $equal = '=';
- $not = strpos($v,'!')===0 ? 1 : 0;
- if ($not) $v = substr($v,1);
-
- // Regex
- if (strpos($v,'~')===0) {
- $v = substr($v,1);
- $v = $this->db->conn->quote($v);
- $equal = ' '.($not ? 'NOT ' : '').'REGEXP ';
-
- // Text
- } elseif (preg_match('/text|char|blob/',$spec['type'])
- or !preg_match('/^\d+(\.\d*)?$/',$v) # text criteria value
-
- ) {
-
- if (strtolower($v)=='null') $v = '';
- #$k = "COLAESCE($k,'')";
-
- // * -> %
- $v = str_replace('*','%',$v);
-
- $v = $this->db->conn->quote($v);
- $equal = ' '.($not ? 'NOT ' : '').'LIKE ';
-
- // Others
- } else {
-
- // Integer
- if ($number) {
- if (strtolower($v)=='null') $v = '0';
-
- // Date, Time
- } else {
- $v = $this->db->conn->quote($v);
-
- }
- $equal = $not ? '<>' : '=';
-
- }
-
- if (preg_match('/(LIKE|REGEXP) ..$/',"$equal$v")) {
- $k = "COALESCE($k,".$this->db->conn->quote('').")";
- }
-
- if ($this->db->type == 'mysql' and $spec['extra']) {
- $having[] = "$k$equal$v";
-
- } elseif ($this->db->type == 'pgsql' and $spec['extra']) {
- $where[] = $this->extras[$k]."$equal$v";
-
- } else {
- $where[] = "$k$equal$v";
- }
-
- }
-
- $sql = '';
- if ($where) $sql .= ' WHERE '.join(' '. $logic.' ',$where);
- if ($having) $sql .= ' HAVING '.join(' '. $logic.' ',$having);
- return $sql;
-
- }
-
- function add_extras($extras) {
- $this->fields();
-
- foreach ($extras as $k => $v) {
-
- $this->fields[$k] = array(
- 'type' => 'text',
- 'null' => 0,
- 'extra' => $v,
- );
-
- $this->extras[$k] = $v;
-
- }
-
- }
-
- function select_extras() {
-
- if (!$this->extras) return '';
-
- $select = array();
-
- foreach ($this->extras as $k => $v) {
-
- $select[] = "$v AS ".($this->db->type == 'pgsql'
- ? '"'.str_replace('"','\"',$k).'"'
- : $this->db->conn->quote($k)
- );
- /*
- $select[] = "$v AS ".$this->db->conn->quote($k);
- */
-
- /*
- $k = $this->db->conn->quote($k);
- if ($this->db->type == 'pgsqpl') $k = str_replace(
- $select[] = "$v AS $k"
- */
-
- }
-
- return ','.join(',',$select);
- }
-
- /******************************************************************
- Html Output
- ******************************************************************/
- function rows($opt=array()) {
-
- //
- // Select
- //
- $sql = "SELECT *" . $this->select_extras();
- $sql .= " FROM $this->name".$this->where_criterias($this->db->p(),$this->db->p('op'));
- $this->sql = $sql;
- #$this->debug($sql);
- $this->debug($sql,1);
-
- //
- // Tot
- //
- $query = $this->db->conn->query("SELECT count(*) FROM ($sql) count",PDO::FETCH_COLUMN,0);
- if (!$query) {
- $err = $this->db->conn->errorInfo();
- $err[] = $sql;
- err(join(' | ',$err));
- return $err[0];
- }
- $tot = $query->fetch();
- #if (!$tot) return;
-
- if ($this->db->p('sort')) $sql .= ' ORDER BY '.$this->db->p('sort');
-
- if ($this->db->p('limit')) {
- $limit = $this->db->p('limit');
- $sql .= ' LIMIT '.$limit;
- } else {
- $limit = '';
- }
-
- //
- // Get results
- //
- $st = $this->db->conn->prepare($sql);
- $st->execute();
-
- $format = (!empty($opt['format']) ? $opt['format'] : 'table');
-
- if (!@$opt['is_html']) $opt['is_html'] = preg_match('/^(table)$/',$format) ? true : false;
- if ($opt['is_html']) echo '<div align="center" class="nav" id="nav_top"></div>'.PHP_EOL;
-
- $escape = preg_match('/^(table|row|xml)$/',$format) ? true : false;
- if (preg_match('/^(1)?$/',$this->db->p('header'))) echo $this->{"rows_begin_$format"}($opt);
-
- $count = 0;
- while ($row = $st->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_NEXT)) {
- $count++;
- $count_fields = 0;
-
- foreach ($this->fields() as $f => $spec) {
-
- if (!$spec['extra']) {
- if ($escape) $row[$f] = htmlspecialchars($row[$f]);
- }
-
- if ($this->db->type == 'sqlite' and preg_match('/^float\((?:\d+,)?(\d+)\)/',$spec['type'],$m)) {
- $row[$f] = sprintf('%.'.$m[1].'f',$row[$f]);
- }
-
- if ($count_fields === 0) {
- #$row[$f] = '<a href="'.$count_fields.'">' . $row[$f] . '</a>';
- }
-
- $count_fields++;
- /* only if in latin1
- if ($this->db->p('format') == 'csv') {
- $row[$f] = utf8_encode($row[$f]);
- } elseif ($spec['extra']) {
- $row[$f] = htmlentities($row[$f]);
-
- }
- */
-
- }
-
- #debug($this->url_edit($row));
- if ($format == 'table') array_unshift($row,'<a class="edit button" href="'.$this->url_edit($row,'&').'">'.DB_HTML_EDIT.'</a>');
- echo $this->{"rows_rec_$format"}($row);
-
- }
-
- echo $this->{"rows_end_$format"}($opt);
- if ($opt['is_html']) echo $this->nav($count,$tot,$limit);
-
- $st->closeCursor();
-
- return $count;
- }
-
- /*-----------------------------------------------------------------
- Json
- -----------------------------------------------------------------*/
- function rows_begin_json() {
- $this->_row_json = null;
- echo '['.PHP_EOL;
- }
-
- function rows_rec_json($row) {
- if ($this->_row_json === null) {
- $this->_row_json = true;
- } else {
- echo ',';
- }
- echo json_encode($row).PHP_EOL;
- }
-
- function rows_end_json() {
- unset($this->_row_json);
- echo ']'.PHP_EOL;
- }
-
- /*-----------------------------------------------------------------
- Yaml
- -----------------------------------------------------------------*/
- function rows_begin_yaml() {
- echo "---\n";
- }
-
- function rows_rec_yaml($row) {
- $yaml = yaml_emit($row);
- $yaml = preg_replace('/^---\n/','',$yaml);
- $yaml = preg_replace('/\n\.\.\.$/','',$yaml);
- $yaml = preg_replace('/^/m',' ',$yaml);
- echo '- '.trim($yaml)."\n";
- }
-
- function rows_end_yaml() {
- echo '';
- }
-
- /*-----------------------------------------------------------------
- Xml
- -----------------------------------------------------------------*/
- function rows_begin_xml() {
- echo ''
- .'<?xml version=“1.0” encoding=“utf-8”?>'.PHP_EOL
- .'<db name="'.$this->db->name.'" table="'.$this->name.'" type="'.$this->db->type.'">'.PHP_EOL
- ;
- }
-
- function rows_rec_xml($row) {
- echo "\t<".$this->name.">".PHP_EOL;
- foreach (array_keys($this->fields()) as $f) {
- if ($row[$f] !== '') echo ''
- . "\t\t<".$f.'>'
- .'<![CDATA['.$row[$f].']]>'
- . '</'.$f.'>'
- .PHP_EOL;
- }
- echo "\t</".$this->name.">".PHP_EOL;
- }
-
- function rows_end_xml() {
- #echo '</'.$this->name.'>'.PHP_EOL;
- echo '</db>'.PHP_EOL;
- }
-
- /*-----------------------------------------------------------------
- Csv
- -----------------------------------------------------------------*/
- function rows_begin_csv() {
- echo join("\t",array_keys($this->fields()))."\n";
- }
-
- function rows_rec_csv($row) {
- echo join("\t",array_values($row))."\n";
- }
-
- function rows_end_csv() {
- }
-
- /*-----------------------------------------------------------------
- Html Table
- -----------------------------------------------------------------*/
-// NB 14.04.14 function rows_begin_table($opt=array()) {
- function rows_begin_table() {
-
- echo '<table class="'.$this->name.' rows border">'.PHP_EOL;
-
- echo '<tr class="'.$this->name.' row bold">';
- echo '<th class="'.DB_HTML_EDIT.'"></th>';
- foreach (array_keys($this->fields()) as $f) {
- echo '<th class="'.$f.'">'.$this->url_sort($f).'</th>';
- }
-
- echo '</tr>'.PHP_EOL;
- }
-
- function rows_rec_table($row) {
- echo '<tr>';
-
- foreach ($row as $k => $v) {
- echo '<td class="'.$k.'">'.$v.'</td>';
- }
-
- echo '</tr>'.PHP_EOL;
- }
-
- function rows_end_table() {
- echo '</table>'.PHP_EOL;
- }
-
- /*-----------------------------------------------------------------
- Html Div
- -----------------------------------------------------------------*/
- function rows_begin_div() {
- echo '<div class="'.$this->name.' rows">'.PHP_EOL;
- }
-
- function rows_rec_div($row) {
-
- echo '<ul class="border rad bgcolor">';
-
- foreach ($row as $k => $v) {
- echo '<li>'
- .'<span class="k">'.$k.'</span>'
- .': '
- .'<span class="v">'.$v.'</span>'
- .'</li>';
- }
-
- echo '</ul>'.PHP_EOL;
- }
-
- function rows_end_div() {
- return "</div>".PHP_EOL;
- }
-
-}
-
-class field {
-
- public $name;
- public $extras = array();
- public $type = 'text';
- public $default = null;
- public $key = false;
-
- function __construct($name,$attr=array()) {
- foreach ($attr as $k => $v) { $this->$k = $v; }
- }
-
- function is_num() {
- return preg_match('/int|float|number|currency/',$this->type) ? 1 : 0;
- }
-
- function html_edit($value) {
-
- echo '<label for="'.$this->name.'">'.htmlspecialchars($this->name).'</label>'
- .'<input name="'.$this->name.'" id="'.$this->name.'" value="'.htmlspecialchars($value).'" />'
- .PHP_EOL;
-
- }
-
-}
-
-return;
?>
--- /dev/null
+<?php
+$DB_FIELD_CONN = isset($Db) ? $Db->conn : null;
+class field {
+
+ public $name;
+ public $type = 'text';
+ public $default = null;
+ public $key = false;
+
+ function __construct($name,$attr=array()) {
+ foreach ($attr as $k => $v) { $this->$k = $v; }
+ }
+
+ function is_num() {
+ return preg_match('/int|float|number|currency/',$this->type) ? 1 : 0;
+ }
+
+ function html_edit($value) {
+
+ echo '<label for="'.$this->name.'">'.htmlspecialchars($this->name).'</label>'
+ .'<input name="'.$this->name.'" id="'.$this->name.'" value="'.htmlspecialchars($value).'" />'
+ .PHP_EOL;
+
+ }
+
+ function quote($value,$force_quote=false) {
+
+ if ($DB_FIELD_CONN === null) return "'".str_replace("'","\\'",$value)."'";
+ return $DB_FIELD_CONN->quote($value);
+
+// TODEL - NB 08.07.15
+ if ($force_quote or !$field->is_num()) {
+
+ if ($DB_FIELD_CONN === null) return "'".preg_replace("/'/","\\'",$value)."'";
+ return $DB_FIELD_CONN->quote($value);
+ }
+
+ return $value;
+ }
+
+ function where($value) {
+
+ // No empty value
+ $v = isset($value) ? $value : null;
+ if (strcmp($v,'')==0
+ or $v=='!'
+ or $v=='!~'
+ or $v=='~'
+ ) return null;
+
+// NB 03.07.15 $number = preg_match('/int|float|number|currency/',$this->type) ? 1 : 0;
+ $number = $this->is_num();
+
+ // Equal / Not Equal
+ $equal = '=';
+
+ $not = strpos($v,'!')===0 ? 1 : 0;
+ if ($not) $v = substr($v,1);
+
+ // Regex
+ if (strpos($v,'~')===0) {
+ return $this->name . ($not ? 'NOT ' : '').'REGEXP ' . $DB_FIELD_CONN->quote( substr($v,1) );
+ }
+
+ // Text
+ if (!$this->num() or !preg_match('/^\d+(\.\d*)?$/',$v)) { # text criteria value
+
+ if (strtolower($v)=='null') $v = '';
+ return $this->name.' '.($not ? 'NOT ' : '').'LIKE '.$DB_FIELD_CONN->quote(str_replace('*','%',$v));
+
+ // Others
+ } else {
+
+ // Integer
+ if ($number) {
+ if (strtolower($v)=='null') $v = '0';
+
+ // Date, Time
+ } else {
+ $v = $DB_FIELD_CONN->quote($v);
+
+ }
+ $equal = $not ? '<>' : '=';
+
+ }
+
+ return "$k$equal$v";
+ }
+
+}
+?>
--- /dev/null
+<?php
+require_once(dirname(__FILE__).'/../functions.php');
+if (!defined('DB_HTML_EDIT')) define('DB_HTML_EDIT','Edit');
+class table {
+
+ public $name;
+ public $db;
+ public $sql;
+ public $fields = array();
+ public $fields_keys = array();
+ public $extras = array();
+ public $params = array(
+ 'table',
+ 'limit',
+ 'debug',
+ );
+
+ function __construct($name,$opt=array()) {
+
+ // Connection
+ if (isset($opt['db'])) {
+ $this->db = $opt['db'];
+ } else {
+ $this->db = new db();
+ }
+
+ // Table could be a select
+ if (stripos($name,'SELECT ')===0) {
+ $this->db->conn->query("CREATE TEMPORARY TABLE _query_ AS $name");
+ $name = '_query_';
+ } elseif (preg_match('/\b(\.import|LOAD DATA|COPY|INSERT|REPLACE|DELETE|TRUNCATE|CREATE|DROP|ALERT)\b/',$name)) {
+ bye("Query not Allowed !");
+ }
+
+ $this->name = $name;
+
+ if (@$opt['extras']) $this->add_extras($opt['extras']);
+
+ return $this->fields();
+ }
+
+ /*
+ * Function db.fields
+ *
+ * return all or one fields from a table
+ *
+ * @name (string) name of the field to return. Default: null
+ * @return (array) return null where name does not exsts
+ */
+ function fields($name=null) {
+
+ if (!$this->fields) {
+
+ if ($this->db->type == 'sqlite') {
+ $sql = "PRAGMA table_info('$this->name')";
+
+ } elseif ($this->db->type == 'pgsql') {
+$sql = "SELECT
+a.attname AS name,
+pg_catalog.format_type(a.atttypid, a.atttypmod) AS type,
+CASE a.attnotnull WHEN 't' then 1 ELSE 0 END AS notnull,
+(SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128) FROM pg_catalog.pg_attrdef d WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef) AS default,
+(SELECT 1 FROM pg_index i WHERE a.attrelid = i.indrelid AND a.attnum = ANY(i.indkey) AND i.indrelid = '$this->name'::regclass AND i.indisprimary) as pk
+FROM pg_catalog.pg_attribute a WHERE a.attrelid = (SELECT c.oid FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE c.relname='$this->name' AND pg_catalog.pg_table_is_visible(c.oid) ) AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum";
+
+ } elseif ($this->db->type == 'mysql') {
+ $sql = "SHOW COLUMNS FROM `$this->name`";
+
+ } else {
+ err('table.fields(): Unknow db type: '.$this->db->type);
+ return array();
+
+ }
+
+ $rows = $this->db->conn->query($sql);
+
+ $rows->setFetchMode(PDO::FETCH_ASSOC);
+
+ foreach ($rows as $row) {
+
+ $this->fields[$row['name']] = array(
+ 'extra' => null,
+ 'type' => null,
+ 'default' => null,
+ 'key' => null,
+ );
+
+ $this->fields[$row['name']]['type'] = $row['type'];
+
+ if (isset($row['notnull'])) {
+ $this->fields[$row['name']]['null'] = $row['notnull'] == '0' ? 1 : 0;
+
+ } else {
+ $this->fields[$row['name']]['null'] = preg_match('/^1|yes|t/i',$row['null']) ? 1 : 0;
+
+ }
+
+ foreach (array('dflt_value') as $f) {
+ if (!isset($row[$f])) continue;
+ $this->fields[$row['name']]['default'] = $row[$f];
+ }
+
+ foreach (array('pk','Key') as $f) {
+ if (!isset($row[$f])) continue;
+ $this->fields[$row['name']]['key'] = preg_match('/^1|yes|t/i',$row[$f]) ? 1 : 0;
+ }
+
+ }
+
+ }
+
+ if ($name !== null ) {
+ if (!isset($this->fields[$name])) return null;
+ return $this->fields[$name];
+ }
+
+ return $this->fields;
+ }
+
+ function url_edit($values=null,$sep='&') {
+ if ($values === null) $values = $this->db->p();
+ $url_edit = array();
+
+ foreach ($this->fields_keys() as $name => $spec) {
+ $url_edit[] = $name . '=' .urlencode($values[$name]);
+ }
+
+ return $url_edit ? 'edit/?table='.$this->db->p('table').$sep.join($sep,$url_edit) : '';
+
+ }
+
+ function fields_keys(&$others=array()) {
+
+ #if (!$this->fields_keys) {
+ $this->fields_keys = array();
+
+ foreach ($this->fields() as $name => $f) {
+ #debug($f);
+ if ((int)$f['key'] == 1) {
+ $this->fields_keys[$name] = $f;
+ } else {
+ $others[$name] = $f;
+ }
+ }
+
+ #}
+
+ return $this->fields_keys;
+
+ }
+
+ function html_edit($values = null) {
+ if ($values === null) $values = $this->db->p();
+ if (!is_array($values)) $values = array($values);
+
+ $sql = "SELECT *" . $this->select_extras();
+ $sql .= " FROM $this->name".str_replace(' LIKE ','=',$this->where_criterias($values));
+ $sql .= " LIMIT 1";
+ $this->sql = $sql;
+
+ $this->debug($sql,1);
+ $st = $this->db->conn->prepare($sql);
+ $st->execute();
+
+ echo '<form class="db edit" method="post">'.PHP_EOL;
+ $count = 0;
+ if ($row = $st->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_NEXT)) {
+ $count ++;
+
+ foreach ($this->fields() as $name => $attr) {
+ $field = new field($name,$attr);
+ $field->html_edit(array_key_exists($name,$row) ? $row[$name] : $attr['default']);
+// NB 03.07.15 continue;
+// NB 03.07.15
+// NB 03.07.15 $value = array_key_exists($name,$row) ? $row[$name] : $attr['default'];
+// NB 03.07.15
+// NB 03.07.15 echo '<label for="'.$name.'">'.htmlspecialchars($name).'</label>'
+// NB 03.07.15 .'<input name="'.$name.'" id="'.$name.'" value="'.htmlspecialchars($value).'" />'
+// NB 03.07.15 .PHP_EOL;
+ }
+ }
+
+ echo ''
+ .'<div class="db buttons">'
+ .'<input type="submit" name="update"/>'
+ .'<input type="text" name="table" value="'.$this->db->p('table').'"/>'
+ .'<input type="reset" />'
+ .( empty($_SERVER['HTTP_REFERER']) ? '' : '<input type="button" onclick="document.location=document.referrer" value="Cancel" />')
+ .'</div>'.PHP_EOL
+ .'</form>'.PHP_EOL;
+
+ $this->row = $row;
+ return $this;
+ }
+
+ function debug($msg,$level=0) { return debug($msg,$level); }
+
+ function url_params($k='',$v='') {
+
+ $params = array();
+
+ foreach (array_merge( $this->params, array_keys($this->fields()) ) as $f) {
+
+ if (@strcmp($this->db->p($f),'')==0) continue;
+ $params[$f] = $this->db->p($f);
+
+ }
+
+ if ($k) {
+
+ if (strcmp($v,'')==0) {
+ unset($params[$k]);
+ } else {
+ $params[$k] = $v;
+ }
+
+ }
+
+ $flat = array();
+ foreach ($params as $k=>$v) { $flat[] = $k.'='.urlencode($v); }
+ return $flat ? '?'. join('&',$flat) : '';
+
+ }
+
+ function url_sort($name) {
+
+ $html = '';
+
+ # Asc
+ $sel = ( $this->db->p('sort')=="$name asc") ? " sel" : "";
+ $html .= '<a title="First In (asc)" class="sort asc'.$sel.'" href="'.$this->url_params("sort","$name asc").'">'
+ .'<span class="asc">↓</span>'
+ .'</a>';
+ $html .= ' ';
+
+ $html .= ucfirst($name);
+
+ $html .= ' ';
+
+ # Desc
+ $sel = ( $this->db->p('sort')=="$name desc") ? " sel" : "";
+ $html .= '<a title="Last In (desc)" class="sort desc'.$sel.'" href="'.$this->url_params("sort","$name desc").'">'
+ .'<span class="desc">↑</span>'
+ .'</a>';
+
+ return $html;
+
+ }
+
+ function nav($count,$tot,$limit) {
+
+ if ($count<$tot) {
+ list($x,$y) = strpos($limit,',')!==false
+ ? preg_split('/\s*,\s*/',$limit)
+ : array(0,$limit)
+ ;
+
+ $prev = $x - $y;
+ $next = $x + $y;
+
+ $this->debug("x=$x limit=$y prev=$prev next=$next tot=$tot",1);
+ } else {
+ $x = 0;
+ $y = $tot;
+ $prev = -1;
+ $next = 999999;
+ }
+
+ echo '<div align="center" class="nav" id="nav_bottom">';
+
+ if ($prev>=0) echo '<span class="prev"><a href="'.$this->url_params('limit',preg_replace('/^0,/','',"$prev,$y")).'"><<</a></span> ';
+
+ echo '<span class="count">'.($tot ? ($x+1) : 0).' - '.($x+$y).' / '.$tot.' results</span>';
+
+ if ($next<$tot) echo ' <span class="prev"><a href="'.$this->url_params('limit',"$next,$y").'">>></a></span>';
+
+ echo '</div>'.PHP_EOL;
+ static $js = null;
+ if ($js === null) {
+ echo '<script type="text/javascript"><!-- '.PHP_EOL
+ ."var rb = document.getElementById('nav_bottom'); var rt = document.getElementById('nav_top'); if (rb && rt) rt.innerHTML = rb.innerHTML;\n"
+ . ' --></script>'.PHP_EOL
+ ;
+ $js = '1';
+ }
+
+ }
+
+ function form_criterias($opt=array()) {
+
+ echo '<form class="criteria bgcolor border rad inline" method="get" action="">'.PHP_EOL;
+ echo '<div class="small help">Use: '.join(' | ',$this->db->help_criterias).'</div>'.PHP_EOL;
+
+ foreach ($this->params as $k) {
+ $v = @$_REQUEST[$k];
+ if ($k == 'limit') $v = '';
+ echo '<input type="hidden" name="'.$k.'" value="'.$v.'" />'.PHP_EOL;
+ }
+
+ $criteria = array();
+ foreach ( array_keys($this->fields()) as $k ) {
+
+ $v = @$_REQUEST[$k];
+
+ $criteria[] = ''
+ . '<label>'.prettyText($k).':</label>'
+ . '<input type="text" id="'.$k.'" name="'.$k.'" value="'.$v.'" />'
+ ;
+
+ }
+
+ $criteria[] = html_select_array(array(
+ 'AND',
+ 'OR',
+ ),array(
+ 'html' => 'name="op"',
+ 'selected' => $this->db->p('op'),
+ ));
+
+ $criteria[] = html_select_array(array(
+ array('','HTML'),
+ array('csv','CSV'),
+ array('xml','XML'),
+ array('yaml','YAML'),
+ array('json','JSON'),
+ ),array(
+ 'html' => 'name="format"',
+ 'selected' => $this->db->p('format'),
+ ));
+ $criteria[] = '<input type="submit" class="button" value="GO"/>';
+
+ echo join(''.PHP_EOL,$criteria);
+
+ echo '</form>'.PHP_EOL;
+
+ }
+
+ function where_criterias($values,$logic='AND') {
+ $having = $where = array();
+
+ foreach ($this->fields() as $k => $spec) {
+
+ $field = new field($k,$spec);
+
+ // No empty values
+ $v = isset($values[$k]) ? $values[$k] : null;
+ if (strcmp($v,'')==0 or $v=='!' or $v=='~') continue;
+// NB 03.07.15 $number = preg_match('/int|float|number|currency/',$spec['type']) ? 1 : 0;
+ $number = $field->is_num();
+
+ // Equal / Not Equal
+ $equal = '=';
+ $not = strpos($v,'!')===0 ? 1 : 0;
+ if ($not) $v = substr($v,1);
+
+ // Regex
+ if (strpos($v,'~')===0) {
+ $v = substr($v,1);
+ $v = $this->db->conn->quote($v);
+ $equal = ' '.($not ? 'NOT ' : '').'REGEXP ';
+
+ // Text
+ } elseif (preg_match('/text|char|blob/',$spec['type'])
+ or !preg_match('/^\d+(\.\d*)?$/',$v) # text criteria value
+ ) {
+
+ if (strtolower($v)=='null') $v = '';
+ #$k = "COLAESCE($k,'')";
+
+ // * -> %
+ $v = str_replace('*','%',$v);
+
+ $v = $this->db->conn->quote($v);
+ $equal = ' '.($not ? 'NOT ' : '').'LIKE ';
+
+ // Others
+ } else {
+
+ // Integer
+ if ($number) {
+ if (strtolower($v)=='null') $v = '0';
+
+ // Date, Time
+ } else {
+ $v = $this->db->conn->quote($v);
+
+ }
+ $equal = $not ? '<>' : '=';
+
+ }
+
+ if (preg_match('/(LIKE|REGEXP) ..$/',"$equal$v")) {
+ $k = "COALESCE($k,".$this->db->conn->quote('').")";
+ }
+
+ if ($this->db->type == 'mysql' and $spec['extra']) {
+ $having[] = "$k$equal$v";
+
+ } elseif ($this->db->type == 'pgsql' and $spec['extra']) {
+ $where[] = $this->extras[$k]."$equal$v";
+
+ } else {
+ $where[] = "$k$equal$v";
+ }
+
+ }
+
+ $sql = '';
+ if ($where) $sql .= ' WHERE '.join(' '. $logic.' ',$where);
+ if ($having) $sql .= ' HAVING '.join(' '. $logic.' ',$having);
+ return $sql;
+
+ }
+
+ function add_extras($extras) {
+ $this->fields();
+
+ foreach ($extras as $k => $v) {
+
+ $this->fields[$k] = array(
+ 'type' => 'text',
+ 'null' => 0,
+ 'extra' => $v,
+ );
+
+ $this->extras[$k] = $v;
+
+ }
+
+ }
+
+ function select_extras() {
+
+ if (!$this->extras) return '';
+
+ $select = array();
+
+ foreach ($this->extras as $k => $v) {
+
+ $select[] = "$v AS ".($this->db->type == 'pgsql'
+ ? '"'.str_replace('"','\"',$k).'"'
+ : $this->db->conn->quote($k)
+ );
+ /*
+ $select[] = "$v AS ".$this->db->conn->quote($k);
+ */
+
+ /*
+ $k = $this->db->conn->quote($k);
+ if ($this->db->type == 'pgsqpl') $k = str_replace(
+ $select[] = "$v AS $k"
+ */
+
+ }
+
+ return ','.join(',',$select);
+ }
+
+ /******************************************************************
+ Html Output
+ ******************************************************************/
+ function rows($opt=array()) {
+
+ //
+ // Select
+ //
+ $sql = "SELECT *" . $this->select_extras();
+ $sql .= " FROM $this->name".$this->where_criterias($this->db->p(),$this->db->p('op'));
+ $this->sql = $sql;
+ #$this->debug($sql);
+ $this->debug($sql,1);
+
+ //
+ // Tot
+ //
+ $query = $this->db->conn->query("SELECT count(*) FROM ($sql) count",PDO::FETCH_COLUMN,0);
+ if (!$query) {
+ $err = $this->db->conn->errorInfo();
+ $err[] = $sql;
+ err(join(' | ',$err));
+ return $err[0];
+ }
+ $tot = $query->fetch();
+ #if (!$tot) return;
+
+ if ($this->db->p('sort')) $sql .= ' ORDER BY '.$this->db->p('sort');
+
+ if ($this->db->p('limit')) {
+ $limit = $this->db->p('limit');
+ $sql .= ' LIMIT '.$limit;
+ } else {
+ $limit = '';
+ }
+
+ //
+ // Get results
+ //
+ $st = $this->db->conn->prepare($sql);
+ $st->execute();
+
+ $format = (!empty($opt['format']) ? $opt['format'] : 'table');
+
+ if (!@$opt['is_html']) $opt['is_html'] = preg_match('/^(table)$/',$format) ? true : false;
+ if ($opt['is_html']) echo '<div align="center" class="nav" id="nav_top"></div>'.PHP_EOL;
+
+ $escape = preg_match('/^(table|row|xml)$/',$format) ? true : false;
+ if (preg_match('/^(1)?$/',$this->db->p('header'))) echo $this->{"rows_begin_$format"}($opt);
+
+ $count = 0;
+ while ($row = $st->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_NEXT)) {
+ $count++;
+ $count_fields = 0;
+
+ foreach ($this->fields() as $f => $spec) {
+
+ if (!$spec['extra']) {
+ if ($escape) $row[$f] = htmlspecialchars($row[$f]);
+ }
+
+ if ($this->db->type == 'sqlite' and preg_match('/^float\((?:\d+,)?(\d+)\)/',$spec['type'],$m)) {
+ $row[$f] = sprintf('%.'.$m[1].'f',$row[$f]);
+ }
+
+ if ($count_fields === 0) {
+ #$row[$f] = '<a href="'.$count_fields.'">' . $row[$f] . '</a>';
+ }
+
+ $count_fields++;
+ /* only if in latin1
+ if ($this->db->p('format') == 'csv') {
+ $row[$f] = utf8_encode($row[$f]);
+ } elseif ($spec['extra']) {
+ $row[$f] = htmlentities($row[$f]);
+
+ }
+ */
+
+ }
+
+ #debug($this->url_edit($row));
+ if ($format == 'table') array_unshift($row,'<a class="edit button" href="'.$this->url_edit($row,'&').'">'.DB_HTML_EDIT.'</a>');
+ echo $this->{"rows_rec_$format"}($row);
+
+ }
+
+ echo $this->{"rows_end_$format"}($opt);
+ if ($opt['is_html']) echo $this->nav($count,$tot,$limit);
+
+ $st->closeCursor();
+
+ return $count;
+ }
+
+ /*-----------------------------------------------------------------
+ Json
+ -----------------------------------------------------------------*/
+ function rows_begin_json() {
+ $this->_row_json = null;
+ echo '['.PHP_EOL;
+ }
+
+ function rows_rec_json($row) {
+ if ($this->_row_json === null) {
+ $this->_row_json = true;
+ } else {
+ echo ',';
+ }
+ echo json_encode($row).PHP_EOL;
+ }
+
+ function rows_end_json() {
+ unset($this->_row_json);
+ echo ']'.PHP_EOL;
+ }
+
+ /*-----------------------------------------------------------------
+ Yaml
+ -----------------------------------------------------------------*/
+ function rows_begin_yaml() {
+ echo "---\n";
+ }
+
+ function rows_rec_yaml($row) {
+ $yaml = yaml_emit($row);
+ $yaml = preg_replace('/^---\n/','',$yaml);
+ $yaml = preg_replace('/\n\.\.\.$/','',$yaml);
+ $yaml = preg_replace('/^/m',' ',$yaml);
+ echo '- '.trim($yaml)."\n";
+ }
+
+ function rows_end_yaml() {
+ echo '';
+ }
+
+ /*-----------------------------------------------------------------
+ Xml
+ -----------------------------------------------------------------*/
+ function rows_begin_xml() {
+ echo ''
+ .'<?xml version=“1.0” encoding=“utf-8”?>'.PHP_EOL
+ .'<db name="'.$this->db->name.'" table="'.$this->name.'" type="'.$this->db->type.'">'.PHP_EOL
+ ;
+ }
+
+ function rows_rec_xml($row) {
+ echo "\t<".$this->name.">".PHP_EOL;
+ foreach (array_keys($this->fields()) as $f) {
+ if ($row[$f] !== '') echo ''
+ . "\t\t<".$f.'>'
+ .'<![CDATA['.$row[$f].']]>'
+ . '</'.$f.'>'
+ .PHP_EOL;
+ }
+ echo "\t</".$this->name.">".PHP_EOL;
+ }
+
+ function rows_end_xml() {
+ #echo '</'.$this->name.'>'.PHP_EOL;
+ echo '</db>'.PHP_EOL;
+ }
+
+ /*-----------------------------------------------------------------
+ Csv
+ -----------------------------------------------------------------*/
+ function rows_begin_csv() {
+ echo join("\t",array_keys($this->fields()))."\n";
+ }
+
+ function rows_rec_csv($row) {
+ echo join("\t",array_values($row))."\n";
+ }
+
+ function rows_end_csv() {
+ }
+
+ /*-----------------------------------------------------------------
+ Html Table
+ -----------------------------------------------------------------*/
+// NB 14.04.14 function rows_begin_table($opt=array()) {
+ function rows_begin_table() {
+
+ echo '<table class="'.$this->name.' rows border">'.PHP_EOL;
+
+ echo '<tr class="'.$this->name.' row bold">';
+ echo '<th class="'.DB_HTML_EDIT.'"></th>';
+ foreach (array_keys($this->fields()) as $f) {
+ echo '<th class="'.$f.'">'.$this->url_sort($f).'</th>';
+ }
+
+ echo '</tr>'.PHP_EOL;
+ }
+
+ function rows_rec_table($row) {
+ echo '<tr>';
+
+ foreach ($row as $k => $v) {
+ echo '<td class="'.$k.'">'.$v.'</td>';
+ }
+
+ echo '</tr>'.PHP_EOL;
+ }
+
+ function rows_end_table() {
+ echo '</table>'.PHP_EOL;
+ }
+
+ /*-----------------------------------------------------------------
+ Html Div
+ -----------------------------------------------------------------*/
+ function rows_begin_div() {
+ echo '<div class="'.$this->name.' rows">'.PHP_EOL;
+ }
+
+ function rows_rec_div($row) {
+
+ echo '<ul class="border rad bgcolor">';
+
+ foreach ($row as $k => $v) {
+ echo '<li>'
+ .'<span class="k">'.$k.'</span>'
+ .': '
+ .'<span class="v">'.$v.'</span>'
+ .'</li>';
+ }
+
+ echo '</ul>'.PHP_EOL;
+ }
+
+ function rows_end_div() {
+ return "</div>".PHP_EOL;
+ }
+
+ function sql_name() {
+ if ($this->type == 'mysql') return '`'.$this->name.'`';
+ return $this->name;
+ }
+
+ function update($hvalues) {
+
+ $keys = $this->fields_keys($values);
+ $values = array_keys($values);
+ $keys = $keys ? array_keys($keys) : $values;
+ #bye($keys);
+
+ $sql =
+ ($this->type == 'mysql' ? 'REPLACE' : 'REPLACE')
+ .' INTO ' . $this->sql_name() . ' (' . join(',',$values).')'
+ .' VALUES (' . join(',',ar_map('":$a"',$values)).')'
+ #.' WHERE ' . join(' AND ',ar_map('"$a=:$a"',$keys))
+ ;
+ debug($sql);
+ $query = $this->db->conn->prepare($sql);
+ #echo '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!';
+
+ #bye($hvalues);
+ foreach (array_keys($this->fields()) as $k) {
+ echo $hvalues[$k].PHP_EOL;
+ $query->bindParam(":$k", $hvalues[$k]);
+ }
+
+ #return $sql;
+ return $query->execute();
+
+ }
+
+}
+?>