]> git.nbdom.net Git - nb.git/commitdiff
db
authorNicolas Boisselier <nicolas.boisselier@gmail.com>
Thu, 9 Jul 2015 00:26:34 +0000 (01:26 +0100)
committerNicolas Boisselier <nicolas.boisselier@gmail.com>
Thu, 9 Jul 2015 00:26:34 +0000 (01:26 +0100)
lib/php/cache.php
lib/php/db.php
lib/php/db/field.php [new file with mode: 0644]
lib/php/db/table.php [new file with mode: 0644]

index 90f1bbaae786e61fd0bec8eafa87c3c9704203b0..e304bf6ae43273a35d81f17f6f40609624ff979d 100644 (file)
@@ -1,6 +1,6 @@
 <?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) {
index ed2cb559fe3b9b22f7d3089f0a47dacf23d1addd..e28405cfb7fca54dde994fa2e752bd60cace7ba7 100644 (file)
@@ -7,7 +7,9 @@
 
 *****************************************************************************/
 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 {
 
@@ -31,6 +33,7 @@ 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];
@@ -242,719 +245,4 @@ EOF;
 
 }
 
-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='&amp;') {
-    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('&amp;',$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">&darr;</span>'
-    .'</a>';
-    $html .= '&nbsp;';
-
-    $html .= ucfirst($name);
-
-    $html .= '&nbsp;';
-
-    # 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">&uarr;</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")).'">&lt;&lt;</a></span>&nbsp;';
-
-    echo '<span class="count">'.($tot ? ($x+1) : 0).' - '.($x+$y).' / '.$tot.' results</span>';
-
-    if ($next<$tot) echo '&nbsp;<span class="prev"><a href="'.$this->url_params('limit',"$next,$y").'">&gt;&gt;</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,'&amp;').'">'.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;
 ?>
diff --git a/lib/php/db/field.php b/lib/php/db/field.php
new file mode 100644 (file)
index 0000000..297c10d
--- /dev/null
@@ -0,0 +1,91 @@
+<?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";
+  }
+
+}
+?>
diff --git a/lib/php/db/table.php b/lib/php/db/table.php
new file mode 100644 (file)
index 0000000..a7527fa
--- /dev/null
@@ -0,0 +1,727 @@
+<?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='&amp;') {
+    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('&amp;',$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">&darr;</span>'
+    .'</a>';
+    $html .= '&nbsp;';
+
+    $html .= ucfirst($name);
+
+    $html .= '&nbsp;';
+
+    # 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">&uarr;</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")).'">&lt;&lt;</a></span>&nbsp;';
+
+    echo '<span class="count">'.($tot ? ($x+1) : 0).' - '.($x+$y).' / '.$tot.' results</span>';
+
+    if ($next<$tot) echo '&nbsp;<span class="prev"><a href="'.$this->url_params('limit',"$next,$y").'">&gt;&gt;</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,'&amp;').'">'.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();
+
+  }
+
+}
+?>