]> git.nbdom.net Git - nb.git/commitdiff
lib/php/db/table.php
authorNicolas Boisselier <nicolas.boisselier@gmail.com>
Sun, 28 Jan 2018 04:58:14 +0000 (04:58 +0000)
committerNicolas Boisselier <nicolas.boisselier@gmail.com>
Sun, 28 Jan 2018 04:58:14 +0000 (04:58 +0000)
lib/php/db.php
lib/php/db/table.php

index 5c79d7f29e41b36aeeb3b026dcbfe82973bd33d5..4278c1835a39efb6a645baf1db85f6e99aa6c23c 100644 (file)
@@ -1,9 +1,9 @@
 <?php
 /*****************************************************************************
 
-  Class DB
-  Render different output format example: html, xml, yaml, csv
-  from any database
+       Class DB
+       Render different output format example: html, xml, yaml, csv
+       from any database
 
 *****************************************************************************/
 require_once(realpath(dirname(__FILE__).'/nb.php'));
@@ -16,50 +16,50 @@ $DB_TYPES = []; # See db/types/*.php
 #if (!empty($argv) and $argv[1] == 'zaza') bye($arr);
 
 if (defined('PRODUCTION') and PRODUCTION) {
-  define('DB_DEFAUL_ERRMODE',PDO::ERRMODE_SILENT);
+       define('DB_DEFAUL_ERRMODE',PDO::ERRMODE_SILENT);
 } else {
-  define('DB_DEFAUL_ERRMODE',PDO::ERRMODE_EXCEPTION);
-  #define('DB_DEFAUL_ERRMODE',PDO::ERRMODE_WARNING);
+       define('DB_DEFAUL_ERRMODE',PDO::ERRMODE_EXCEPTION);
+       #define('DB_DEFAUL_ERRMODE',PDO::ERRMODE_WARNING);
 }
 
 #const DB::ERRMODE='';
 class Db extends nb {
 
-  # PDO Connection
+       # PDO Connection
 # NB 22.09.16   public static $encoding = 'utf-8';
 
 # NB 22.09.16: TODO 
-  public static $table_rows_dump = [
-    'praser' => false,
-  ];
-
-  public $conn;
-  public $pdo;
-  public $options = [ # See: http://php.net/manual/en/pdo.error-handling.php
-    PDO::ATTR_ERRMODE => DB_DEFAUL_ERRMODE,
+       public static $table_rows_dump = [
+               'praser' => false,
+       ];
+
+       public $conn;
+       public $pdo;
+       public $options = [ # See: http://php.net/manual/en/pdo.error-handling.php
+               PDO::ATTR_ERRMODE => DB_DEFAUL_ERRMODE,
                PDO::ATTR_TIMEOUT => 0,
-  ];
-  public $host = null;
-  public $port = null;
-  public $user = null;
-  public $password = null;
-  public $charset = 'utf8';
-
-  # Database infos
-  public $id;
-  public $name;
-  public $title;
-  public $notice;
-  public $type;
-  public $tables = [];
-  public $types = [];
-  public $conf = [];
-  public $attach = []; # for sqlite
-  public $row_parse_pre; # Function to call in table.rows()
-  public $row_parse_post; # Function to call in table.rows()
-
-  # Encryption
-  public $encrypt = [
+       ];
+       public $host = null;
+       public $port = null;
+       public $user = null;
+       public $password = null;
+       public $charset = 'utf8';
+
+       # Database infos
+       public $id;
+       public $name;
+       public $title;
+       public $notice;
+       public $type;
+       public $tables = [];
+       public $types = [];
+       public $conf = [];
+       public $attach = []; # for sqlite
+       public $row_parse_pre; # Function to call in table.rows()
+       public $row_parse_post; # Function to call in table.rows()
+
+       # Encryption
+       public $encrypt = [
 #   'secret' => '32_CHAR_KEY',
 #    'tables' => [
 #      'TABLE1' => [
@@ -68,413 +68,413 @@ class Db extends nb {
 #      ],
 #      ...,
 #    ],
-  ];
-
-  # Params
-  protected $default_params = [
-  ];
-
-  protected static $paliases = [
-    'd'   => 'db',
-    't'   => 'table',
-    'l'   => 'limit',
-    'a'   => 'action',
-    'h'   => 'header',
-
-    'f'   => 'format',
-    'out' => 'format',
-    'o'   => 'format',
-  ];
-
-  protected static $action_aliases = [
-    'help' => 'db.help',
-    'ls' => 'db.ls',
-    'exec' => 'db.exec',
-    'databases' => 'db.databases',
-
-    'tables' => 'db.tables',
-    'fields' => 'table.fields',
-    'rows' => 'table.rows',
-    'insert' => 'table.insert',
-    'replace' => 'table.replace',
-    'update' => 'table.update',
-    'delete' => 'table.delete',
-  ];
-
-  protected static $action_help = [
-    ['db.help','This help'],
-    ['db.ls','List databases from conf'],
-    ['db.database','List other databases on the same server'],
-    ['db.tables','List tables (name=* type=* count=1 engine=*)'],
-
-    ['table.rows','Dump one table, use format='],
-    ['table.fields','List fields'],
-    ['table.status','Table status (count= maxlen= max=)'],
-    ['table.sql','Sql source to create the table'],
-
-    ['table.insert','Insert a record'],
-    ['table.update','Update a record'],
-    ['table.delete','Delete a record'],
-
-  ];
-  # Web
-  public $default_table;
-  public $sort;
-  public $extras;
-  public $format = 'json';
-  public $formats = [ 'table','div','csv','xml','json','yaml','sh','sql','php' ];
-  public $limits = ['20','50','100','500','1000'];
-  public $limit; # Here not in Table becouse of Db::out()
-
-  # Classes
-  public $out;
-
-  function __construct($opt = []) {
-
-    # Args defaults
-    if ($opt==='') $opt = [];
-    $opt = is_scalar($opt) ? ['pdo' => $opt] : $opt;
-
-    # Options
-    if (isset($opt['options'])) {
-      foreach ($opt['options'] as $k=>$v) $this->options[$k] = $v;
-      unset($opt['options']);
-    }
-
-    # Charset
-    if (!empty($opt['charset'])) $opt['charset']
-      = preg_replace('/^ *utf-8 *$/','utf8',$opt['charset'])
-    ;
-
-    # Tables
-    if (isset($opt['tables'])) {
-      foreach ($opt['tables'] as $name=>$param) {
-        $this->table($name,$param);
-      }
-      unset($opt['tables']);
-    }
-
-    # connect
-    $connect = false;
-    if (isset($opt['connect'])) {
-      $connect = (bool) $opt['connect'];
-      unset($opt['connect']);
-    }
-
-    # Args into this
-    foreach ($opt as $k=>$v) $this->$k = $v;
-    #parent::__construct($opt);
-
-    # Out Class
-    if (empty($this->out)) $this->out = new Out(['charset'=>$this->charset]);
-
-    # Format
-    # Set format from client Accept if != html
-    if (!isset($opt['format'])) {
-      if ($this->out->client_type()) $this->format = $this->out->client_type();
-      if (self::p('format')) $this->format = self::p('format');
-    }
-
-    # Pdo
-    $this->connect_init();
-    if ($connect) $this->connect();
-
-    # Extras must disapear - NB 29.03.16
-    if (!empty($this->extras)) self::bye($this->extras);
-    return true;
-  }
-
-  public function __destruct() {
-    $this->disconnect();
-    foreach (array_keys((array)$this) as $k) { if (isset($this->$k)) unset($this->$k); };
-  }
+       ];
+
+       # Params
+       protected $default_params = [
+       ];
+
+       protected static $paliases = [
+               'd'   => 'db',
+               't'   => 'table',
+               'l'   => 'limit',
+               'a'   => 'action',
+               'h'   => 'header',
+
+               'f'   => 'format',
+               'out' => 'format',
+               'o'   => 'format',
+       ];
+
+       protected static $action_aliases = [
+               'help' => 'db.help',
+               'ls' => 'db.ls',
+               'exec' => 'db.exec',
+               'databases' => 'db.databases',
+
+               'tables' => 'db.tables',
+               'fields' => 'table.fields',
+               'rows' => 'table.rows',
+               'insert' => 'table.insert',
+               'replace' => 'table.replace',
+               'update' => 'table.update',
+               'delete' => 'table.delete',
+       ];
+
+       protected static $action_help = [
+               ['db.help','This help'],
+               ['db.ls','List databases from conf'],
+               ['db.database','List other databases on the same server'],
+               ['db.tables','List tables (name=* type=* count=1 engine=*)'],
+
+               ['table.rows','Dump one table, use format='],
+               ['table.fields','List fields'],
+               ['table.status','Table status (count= maxlen= max=)'],
+               ['table.sql','Sql source to create the table'],
+
+               ['table.insert','Insert a record'],
+               ['table.update','Update a record'],
+               ['table.delete','Delete a record'],
+
+       ];
+       # Web
+       public $default_table;
+       public $sort;
+       public $extras;
+       public $format = 'json';
+       public $formats = [ 'table','div','csv','xml','json','yaml','sh','sql','php' ];
+       public $limits = ['20','50','100','500','1000'];
+       public $limit; # Here not in Table becouse of Db::out()
+
+       # Classes
+       public $out;
+
+       function __construct($opt = []) {
+
+               # Args defaults
+               if ($opt==='') $opt = [];
+               $opt = is_scalar($opt) ? ['pdo' => $opt] : $opt;
+
+               # Options
+               if (isset($opt['options'])) {
+                       foreach ($opt['options'] as $k=>$v) $this->options[$k] = $v;
+                       unset($opt['options']);
+               }
+
+               # Charset
+               if (!empty($opt['charset'])) $opt['charset']
+                       = preg_replace('/^ *utf-8 *$/','utf8',$opt['charset'])
+               ;
+
+               # Tables
+               if (isset($opt['tables'])) {
+                       foreach ($opt['tables'] as $name=>$param) {
+                               $this->table($name,$param);
+                       }
+                       unset($opt['tables']);
+               }
+
+               # connect
+               $connect = false;
+               if (isset($opt['connect'])) {
+                       $connect = (bool) $opt['connect'];
+                       unset($opt['connect']);
+               }
+
+               # Args into this
+               foreach ($opt as $k=>$v) $this->$k = $v;
+               #parent::__construct($opt);
+
+               # Out Class
+               if (empty($this->out)) $this->out = new Out(['charset'=>$this->charset]);
+
+               # Format
+               # Set format from client Accept if != html
+               if (!isset($opt['format'])) {
+                       if ($this->out->client_type()) $this->format = $this->out->client_type();
+                       if (self::p('format')) $this->format = self::p('format');
+               }
+
+               # Pdo
+               $this->connect_init();
+               if ($connect) $this->connect();
+
+               # Extras must disapear - NB 29.03.16
+               if (!empty($this->extras)) self::bye($this->extras);
+               return true;
+       }
+
+       public function __destruct() {
+               $this->disconnect();
+               foreach (array_keys((array)$this) as $k) { if (isset($this->$k)) unset($this->$k); };
+       }
 
        function connect_init() {
 
-    if (empty($this->pdo) and $this->type) $this->pdo = $this->type.':';
-    # Extract args from pdo
-    foreach ($this->pdo2h($this->pdo) as $k=>$v) {
-      $this->$k = $v;
-    }
+               if (empty($this->pdo) and $this->type) $this->pdo = $this->type.':';
+               # Extract args from pdo
+               foreach ($this->pdo2h($this->pdo) as $k=>$v) {
+                       $this->$k = $v;
+               }
 
-    if (empty($this->type)) $this->type = strtolower(preg_replace('/^([^:]+):.*$/','\1',$this->pdo));
-    if (!$this->type) return false;
+               if (empty($this->type)) $this->type = strtolower(preg_replace('/^([^:]+):.*$/','\1',$this->pdo));
+               if (!$this->type) return false;
 
-    if ($v = $this->p('db_host')) $this->host = $v;
-    if ($this->conf_type('use_path')) {
+               if ($v = $this->p('db_host')) $this->host = $v;
+               if ($this->conf_type('use_path')) {
 
-      if (empty($this->host)) $this->host = preg_replace('/^\w+:/','',$this->pdo);
+                       if (empty($this->host)) $this->host = preg_replace('/^\w+:/','',$this->pdo);
 
-      # Add file
-      if (trim($this->pdo,'pdo:'.$this->type)=='') $this->pdo .= $this->host;
+                       # Add file
+                       if (trim($this->pdo,'pdo:'.$this->type)=='') $this->pdo .= $this->host;
 
-    } else {
+               } else {
 
-      # Add args to pdo
-      foreach ([
-        'host'     => 'host',
-        'port'     => 'port',
-        'user'     => 'user',
-        'password' => 'password',
-        'name'     => 'dbname',
-        'charset'  => 'charset',
-      ] as $k => $v) {
-        if ($v=='charset' and $this->type=='pgsql') continue;
-        if (empty($this->$k)) continue;
-        $this->pdo = preg_replace("/\b$v=[^;]*(;|$)/","",$this->pdo);
-        $this->pdo .= (preg_match('/[:;]$/',$this->pdo) ? '' : ';') . "$v=".$this->$k;
-      }
+                       # Add args to pdo
+                       foreach ([
+                               'host'     => 'host',
+                               'port'     => 'port',
+                               'user'     => 'user',
+                               'password' => 'password',
+                               'name'     => 'dbname',
+                               'charset'  => 'charset',
+                       ] as $k => $v) {
+                               if ($v=='charset' and $this->type=='pgsql') continue;
+                               if (empty($this->$k)) continue;
+                               $this->pdo = preg_replace("/\b$v=[^;]*(;|$)/","",$this->pdo);
+                               $this->pdo .= (preg_match('/[:;]$/',$this->pdo) ? '' : ';') . "$v=".$this->$k;
+                       }
 
-      if (strpos($this->host,'/') === 0) {
-        $this->pdo = preg_replace("/\b(host|port)=[^;]*(;|$)/","",$this->pdo).';unix_socket='.$this->host;
-      }
+                       if (strpos($this->host,'/') === 0) {
+                               $this->pdo = preg_replace("/\b(host|port)=[^;]*(;|$)/","",$this->pdo).';unix_socket='.$this->host;
+                       }
 
-    }
+               }
 
-    # Defaults
-    if (empty($this->title)) $this->title = prettyText($this->name);
-    if (empty($this->id) and !empty($this->name)) $this->id = preg_replace('/\W+/','',$this->name);
+               # Defaults
+               if (empty($this->title)) $this->title = prettyText($this->name);
+               if (empty($this->id) and !empty($this->name)) $this->id = preg_replace('/\W+/','',$this->name);
 
-    # Row parser
-    if (empty($this->row_parse_pre) and $this->conf_type('row_parse')) {
-      $this->row_parse_pre = $this->conf_type('row_parse');
-    }
+               # Row parser
+               if (empty($this->row_parse_pre) and $this->conf_type('row_parse')) {
+                       $this->row_parse_pre = $this->conf_type('row_parse');
+               }
 
-  } # < if else 'use_path'
+       } # < if else 'use_path'
 
        public function connect() {
-    if (!empty($this->conn)) return false;
+               if (!empty($this->conn)) return false;
 
-    # Pdo
-    if (empty($this->pdo)) $this->bye("db: `".$this->id."`: Missing pdo: check host, name, user, password");
-    if (empty($this->pdo)) return false;
+               # Pdo
+               if (empty($this->pdo)) $this->bye("db: `".$this->id."`: Missing pdo: check host, name, user, password");
+               if (empty($this->pdo)) return false;
 
-    # Type
-    $this->conf_type_load();
+               # Type
+               $this->conf_type_load();
 
-    # Connect
-    try {
-      $this->conn = new PDO($this->pdo,$this->user,$this->password,$this->options);
-      #if (isset($this->pdo_error)) $this->conn->setAttribute($this->pdo_error[0], $this->pdo_error[1]);
+               # Connect
+               try {
+                       $this->conn = new PDO($this->pdo,$this->user,$this->password,$this->options);
+                       #if (isset($this->pdo_error)) $this->conn->setAttribute($this->pdo_error[0], $this->pdo_error[1]);
 
-    } catch (PDOException $e) {
-      $msg = 'Connection failed:';
+               } catch (PDOException $e) {
+                       $msg = 'Connection failed:';
 
-      foreach(['name','host','file'] as $p) {
-        if (!empty($this->$p)) $msg .= " $p=".$this->$p;
-      }
+                       foreach(['name','host','file'] as $p) {
+                               if (!empty($this->$p)) $msg .= " $p=".$this->$p;
+                       }
 
-      $msg .= "\n  ".$e->getMessage();
-      #throw new Exception($msg, (int)$e->getCode());
-      self::bye($msg);
-    }
+                       $msg .= "\n  ".$e->getMessage();
+                       #throw new Exception($msg, (int)$e->getCode());
+                       self::bye($msg);
+               }
 
-    if (empty($this->conn)) {
-      $this->bye("Connection failed: ".$this->pdo_info());
-      return false;
-    }
+               if (empty($this->conn)) {
+                       $this->bye("Connection failed: ".$this->pdo_info());
+                       return false;
+               }
 
-    # Create functions
-    foreach ((array)$this->conf_type('sqliteCreateFunction') as $name => $fct) {
-      if (is_array($fct)) {
-        $this->conn->sqliteCreateFunction($name,$fct[0],$fct[1]);
-      } else {
-        $this->conn->sqliteCreateFunction($name,$fct);
-      }
-    }
+               # Create functions
+               foreach ((array)$this->conf_type('sqliteCreateFunction') as $name => $fct) {
+                       if (is_array($fct)) {
+                               $this->conn->sqliteCreateFunction($name,$fct[0],$fct[1]);
+                       } else {
+                               $this->conn->sqliteCreateFunction($name,$fct);
+                       }
+               }
 
-    $this->method('connect');
+               $this->method('connect');
 
-    return true;
-  }
+               return true;
+       }
 
        public function disconnect() {
-    if (empty($this->conn)) return null;
-    $this->method('disconnect');
-  }
-
-  function exec($sql) {
-
-    try {
-      #$r = $this->conn->exec($sql,$params);
-      $r = $this->conn->exec($sql);
-    } catch (PDOException $e) {
-      err(join(': ',[$e->getMessage(),"Db.exec()",$sql]));
-      $r = null;
-    }
-
-    return $r;
-  }
-
-  public function query($sql) {
-    # See: http://wiki.hashphp.org/PDO_Tutorial_for_MySQL_Developers
-
-    try {
-      $r = $this->conn->query($sql);
-    } catch (PDOException $e) {
-      err(join(': ',[$e->getMessage(),"Db.query()",$sql]));
-      $r = null;
-    }
-
-    return $r;
-
-  }
-
-  public function row($sql,$sep=' ') {
-    $query = $this->query($sql);
-    $result = $query->fetch(PDO::FETCH_NUM);
-    if (!is_array($result)) return $result;
-    return join($sep,$result);
-    return join($sep,$query->fetch(PDO::FETCH_NUM));
-  }
-
-  private function rows($sql,$style=PDO::FETCH_BOTH) {
-    return $this->query($sql)->fetchAll($style);
-    $sth = $this->conn->prepare($sql);
-    $sth->execute();
-    return $sth->fetchAll($style);
-  }
-
-  function query2a($sql) {
-    $r = $this->conn->query($sql,PDO::FETCH_COLUMN);
-    return $r ? $r->fetch() : $r;
-  }
-
-  function query2aa($sql) {
-    return $this->conn->query($sql,PDO::FETCH_COLUMN);
-  }
-
-  function query2h($sql) {
-    $r = $this->conn->query($sql,PDO::FETCH_ASSOC);
-    return $r ? $r->fetch() : $r;
-  }
-
-  function query2ah($sql) {
-    return $this->conn->query($sql,PDO::FETCH_ASSOC);
-  }
-
-  function quote($v) {
-    static $fct = false; if ($fct === false) $fct = $this->conf_type('quote');
-    if ($fct) return $fct($v);
-    return $this->conn->quote($v);
-  }
-
-  /**
-  * @author NB 12.08.16
-  * Return a table instance
-  */
-  public function table($name='',$params=[]) {
-    if ( !is_array($params) ) $this->bye('Usage: table($name,[type=>, sql=>, ...])');
-    if (!$name and !empty($this->default_table)) $name = $this->default_table;
-    if (!$name) $this->bye('table(): Missing table');
-
-    if (empty($params) or empty($params['db'])) $params['db'] = $this;
-
-    if (empty($this->tables[$name])) {
-      $this->tables[$name] = new Table($name,$params);
-    } elseif ($params) {
-      $this->tables[$name]->__construct($name,$params);
-    }
-
-    return $this->tables[$name];
-  }
-
-  public static function localFile($name='') {
-
-    if (!($config = self::type('localFile'))) return [];
-
-    $config[1] = str_replace('<NAME>',($name ? $name : $this->name),$config[1]);
-
-    if (!file_exists($config[0])) return [];
-
-    $return = [];
-    foreach (explode("\n",file_get_contents($config[0])) as $line) {
-      if (!preg_match('/'.($config[1]).'/',$line,$m)) continue;
-      foreach ($m as $k=>$v) if (preg_match('/^\d+$/',$k)) unset($m[$k]);
-      $return = array_replace_recursive($return,$m);
-    }
+               if (empty($this->conn)) return null;
+               $this->method('disconnect');
+       }
+
+       function exec($sql) {
+
+               try {
+                       #$r = $this->conn->exec($sql,$params);
+                       $r = $this->conn->exec($sql);
+               } catch (PDOException $e) {
+                       err(join(': ',[$e->getMessage(),"Db.exec()",$sql]));
+                       $r = null;
+               }
+
+               return $r;
+       }
+
+       public function query($sql) {
+               # See: http://wiki.hashphp.org/PDO_Tutorial_for_MySQL_Developers
+
+               try {
+                       $r = $this->conn->query($sql);
+               } catch (PDOException $e) {
+                       err(join(': ',[$e->getMessage(),"Db.query()",$sql]));
+                       $r = null;
+               }
+
+               return $r;
+
+       }
+
+       public function row($sql,$sep=' ') {
+               $query = $this->query($sql);
+               $result = $query->fetch(PDO::FETCH_NUM);
+               if (!is_array($result)) return $result;
+               return join($sep,$result);
+               return join($sep,$query->fetch(PDO::FETCH_NUM));
+       }
+
+       private function rows($sql,$style=PDO::FETCH_BOTH) {
+               return $this->query($sql)->fetchAll($style);
+               $sth = $this->conn->prepare($sql);
+               $sth->execute();
+               return $sth->fetchAll($style);
+       }
+
+       function query2a($sql) {
+               $r = $this->conn->query($sql,PDO::FETCH_COLUMN);
+               return $r ? $r->fetch() : $r;
+       }
+
+       function query2aa($sql) {
+               return $this->conn->query($sql,PDO::FETCH_COLUMN);
+       }
+
+       function query2h($sql) {
+               $r = $this->conn->query($sql,PDO::FETCH_ASSOC);
+               return $r ? $r->fetch() : $r;
+       }
+
+       function query2ah($sql) {
+               return $this->conn->query($sql,PDO::FETCH_ASSOC);
+       }
+
+       function quote($v) {
+               static $fct = false; if ($fct === false) $fct = $this->conf_type('quote');
+               if ($fct) return $fct($v);
+               return $this->conn->quote($v);
+       }
+
+       /**
+       * @author NB 12.08.16
+       * Return a table instance
+       */
+       public function table($name='',$params=[]) {
+               if ( !is_array($params) ) $this->bye('Usage: table($name,[type=>, sql=>, ...])');
+               if (!$name and !empty($this->default_table)) $name = $this->default_table;
+               if (!$name) $this->bye('table(): Missing table');
+
+               if (empty($params) or empty($params['db'])) $params['db'] = $this;
+
+               if (empty($this->tables[$name])) {
+                       $this->tables[$name] = new Table($name,$params);
+               } elseif ($params) {
+                       $this->tables[$name]->__construct($name,$params);
+               }
+
+               return $this->tables[$name];
+       }
+
+       public static function localFile($name='') {
+
+               if (!($config = self::type('localFile'))) return [];
+
+               $config[1] = str_replace('<NAME>',($name ? $name : $this->name),$config[1]);
+
+               if (!file_exists($config[0])) return [];
+
+               $return = [];
+               foreach (explode("\n",file_get_contents($config[0])) as $line) {
+                       if (!preg_match('/'.($config[1]).'/',$line,$m)) continue;
+                       foreach ($m as $k=>$v) if (preg_match('/^\d+$/',$k)) unset($m[$k]);
+                       $return = array_replace_recursive($return,$m);
+               }
 
 #debug(self::ar_map('$a == null ? "" : $a',$return));
 #debug($return);
-    if (empty($return['user']) and !empty($_SERVER['USER'])) $return['user'] = $_SERVER['USER'];
-    return $return;
-  }
-
-  public function unvar($value) {
-    #return $value;
-    if (empty($value)) return $value;
-    if (!is_scalar($value)) {
-      foreach ($value as $k=>$v) {
-        if (is_scalar($v)) $value[$k] = $this->unvar($v);
-      }
-      return $value;
-    }
-    $replace = [
-      '<D.NAME>' => $this->name,
-      '<D.CHARSET>' => $this->charset,
-    ];
-    #debug( str_replace(array_keys($replace),array_values($replace),$value) );
-    return str_replace(array_keys($replace),array_values($replace),$value);
-  }
-
-  public function method($key=null) {
-    $method = $this->conf_type($key);
-    if (is_callable($method)) return $this->unvar($method($this));
-    return $this->unvar($method);
-  }
-
-  public function loadPhp($name) {
-    static $require = [];
-
-    if (empty($name)) self::bye('Db file is required');
-
-    if (empty($require[$name])) {
-      $require[$name] = NB_ROOT.'/lib/php/db/'.$name.'.php';
-      if (!file_exists($require[$name])) return false;
-      require_once($require[$name]);
-    }
+               if (empty($return['user']) and !empty($_SERVER['USER'])) $return['user'] = $_SERVER['USER'];
+               return $return;
+       }
+
+       public function unvar($value) {
+               #return $value;
+               if (empty($value)) return $value;
+               if (!is_scalar($value)) {
+                       foreach ($value as $k=>$v) {
+                               if (is_scalar($v)) $value[$k] = $this->unvar($v);
+                       }
+                       return $value;
+               }
+               $replace = [
+                       '<D.NAME>' => $this->name,
+                       '<D.CHARSET>' => $this->charset,
+               ];
+               #debug( str_replace(array_keys($replace),array_values($replace),$value) );
+               return str_replace(array_keys($replace),array_values($replace),$value);
+       }
+
+       public function method($key=null) {
+               $method = $this->conf_type($key);
+               if (is_callable($method)) return $this->unvar($method($this));
+               return $this->unvar($method);
+       }
+
+       public function loadPhp($name) {
+               static $require = [];
+
+               if (empty($name)) self::bye('Db file is required');
+
+               if (empty($require[$name])) {
+                       $require[$name] = NB_ROOT.'/lib/php/db/'.$name.'.php';
+                       if (!file_exists($require[$name])) return false;
+                       require_once($require[$name]);
+               }
 
                return true;
-  }
+       }
 
-  public function conf_type_load($type=null) {
-    global $DB_TYPES;
-    static $require = [];
+       public function conf_type_load($type=null) {
+               global $DB_TYPES;
+               static $require = [];
 
-    if (empty($type)) $type = $this->type;
-    if (empty($type)) self::bye('Db type is required');
+               if (empty($type)) $type = $this->type;
+               if (empty($type)) self::bye('Db type is required');
 
-    if (empty($require[$type])) {
-      $require[$type] = NB_ROOT.'/lib/php/db/types/'.$type.'.php';
-      if (!file_exists($require[$type])) self::bye("Unknown type `$type`");
+               if (empty($require[$type])) {
+                       $require[$type] = NB_ROOT.'/lib/php/db/types/'.$type.'.php';
+                       if (!file_exists($require[$type])) self::bye("Unknown type `$type`");
 # NB 10.01.18       $require[$type] = dirname(__FILE__).'/db/types/'.$type.'.php';
-      require_once($require[$type]);
-    }
+                       require_once($require[$type]);
+               }
 
-    return $DB_TYPES[$type];
-  }
+               return $DB_TYPES[$type];
+       }
 
-  public function conf_type($key=null,$die_if_empty=false) {
+       public function conf_type($key=null,$die_if_empty=false) {
 
-    # Load php file
-    $db_type = $this->conf_type_load();
+               # Load php file
+               $db_type = $this->conf_type_load();
 
-    # Dump all array
-    if ($key === null) return $db_type;
+               # Dump all array
+               if ($key === null) return $db_type;
 
-    # Search for specifics from types
-    if (!empty($this->types) and !empty($this->types[$key])) {
-      $db_type[$key] = array_merge((empty($db_type[$key]) ? [] : $db_type[$key]),$this->types[$key]);
-    }
+               # Search for specifics from types
+               if (!empty($this->types) and !empty($this->types[$key])) {
+                       $db_type[$key] = array_merge((empty($db_type[$key]) ? [] : $db_type[$key]),$this->types[$key]);
+               }
 
-    # Check key exists
-    if (empty($db_type[$key])) {
-      if ($die_if_empty) self::bye("db_type(): Unknown key `$key` for type `".$this->type."`");#.' - '.print_r($db_type,true));
-      return;
-    }
+               # Check key exists
+               if (empty($db_type[$key])) {
+                       if ($die_if_empty) self::bye("db_type(): Unknown key `$key` for type `".$this->type."`");#.' - '.print_r($db_type,true));
+                       return;
+               }
 
-    return $this->unvar($db_type[$key]);
-  }
+               return $this->unvar($db_type[$key]);
+       }
 
 # NB 12.12.17   public function type($key=null,$die=false,$type=null) {
 # NB 12.12.17     if (empty($type)) $type = $this->type;
@@ -483,208 +483,208 @@ class Db extends nb {
 # NB 12.12.17     return $this->conf_type($key,$die);
 # NB 12.12.17   }
 
-  public function table_exist($table) {
-  # NB 02.11.16: TODO NEVEW USED 
-    $table = is_object($table) ? $table->name : $table;
+       public function table_exist($table) {
+       # NB 02.11.16: TODO NEVEW USED 
+               $table = is_object($table) ? $table->name : $table;
 
-    if ($this->_tables === true) {
-      if (array_key_exists($table)) return 1;
-    } else {
-    }
+               if ($this->_tables === true) {
+                       if (array_key_exists($table)) return 1;
+               } else {
+               }
 
-    return null;
+               return null;
 
-  }
+       }
 
-  public function tables() {
+       public function tables() {
 
-    if (!isset($this->_tables)) {
-    #if (!isset($this->tables)) {
-      $this->_tables = true;
+               if (!isset($this->_tables)) {
+               #if (!isset($this->tables)) {
+                       $this->_tables = true;
 
-      $sql = $this->method('tables');
+                       $sql = $this->method('tables');
 
-      if ($sql and !empty($this->conn)) {
-        foreach ($this->conn->query($sql,PDO::FETCH_ASSOC) as $row) {
-          $name = current($row);
+                       if ($sql and !empty($this->conn)) {
+                               foreach ($this->conn->query($sql,PDO::FETCH_ASSOC) as $row) {
+                                       $name = current($row);
 
-          # add to this->tables !!!
-          $t = $this->table($name,$row+['status'=>$row]);
-        }
-      }
+                                       # add to this->tables !!!
+                                       $t = $this->table($name,$row+['status'=>$row]);
+                               }
+                       }
 
-    }
+               }
 
-    return $this->tables;
-  }
+               return $this->tables;
+       }
 
-  public static function print_header($format,$value=null) {
-    if (empty($_SERVER['DOCUMENT_ROOT'])) return null;
+       public static function print_header($format,$value=null) {
+               if (empty($_SERVER['DOCUMENT_ROOT'])) return null;
 
-    if ($value!==null) return header("$format: $value");
+               if ($value!==null) return header("$format: $value");
 
-    if (!$mime=mime::get($format)) return false;
-    header('Content-type: '.$mime);
+               if (!$mime=mime::get($format)) return false;
+               header('Content-type: '.$mime);
 
-    return $mime;
-  }
+               return $mime;
+       }
 
-  public function sql_name($value) {
-    # no quote if contain comma for db
-    if (strpos($value,'.') !== false) return $value;
+       public function sql_name($value) {
+               # no quote if contain comma for db
+               if (strpos($value,'.') !== false) return $value;
 
-    # specific quote
-    if ($q=$this->conf_type('quote_name')) return $q.$value.$q;
+               # specific quote
+               if ($q=$this->conf_type('quote_name')) return $q.$value.$q;
 
-    # default quote
-    return '"'.$value.'"';
-  }
+               # default quote
+               return '"'.$value.'"';
+       }
 
-  public function out($rows,$head=[],$conf=[]) {
+       public function out($rows,$head=[],$conf=[]) {
 
 # NB 19.12.17          See www/dbq/dbq.php: $this->db->out($rows,$head,$conf);
                if (empty($rows)) return false;
 
-    if ($this->format) {
-      $format = $this->format;
-
-    } elseif ($this->format == 'null') {
-      return true;
+               if ($this->format) {
+                       $format = $this->format;
 
-    } elseif ($format=$this->format) {
+               } elseif ($this->format == 'null') {
+                       return true;
 
-    } else {
-      # NB 04.12.16: TODEL one day ! 
-      $format = $this->out->php_cli() ? 'csv' : 'table';
-    }
+               } elseif ($format=$this->format) {
 
-    // Handle limit
-    if ($this->limit) {
+               } else {
+                       # NB 04.12.16: TODEL one day ! 
+                       $format = $this->out->php_cli() ? 'csv' : 'table';
+               }
 
-      $limit = (int)$this->limit;
-      $i = empty($head) ? 1 : 0;
+               // Handle limit
+               if ($this->limit) {
 
-      foreach ($rows as $k=>$v) {
-        if ($i>$limit) unset($rows[$k]);
-        $i++;
-      }
+                       $limit = (int)$this->limit;
+                       $i = empty($head) ? 1 : 0;
 
-    }
+                       foreach ($rows as $k=>$v) {
+                               if ($i>$limit) unset($rows[$k]);
+                               $i++;
+                       }
 
-    $this->out->rows($format,$rows,$head,$conf);
-    return true;
-  }
+               }
 
-  public function tables_rows($o=[]) {
-    # Options
-    # Filters
-    $type = empty($o['type']) ? '' : $o['type'];
-    $name = empty($o['name']) ? '' : $o['name'];
-    $engine = empty($o['engine']) ? '' : $o['engine'];
-    $database = empty($o['database']) ? '' : $o['database'];
-    $count = empty($o['count']) ? '' : $o['count'];
-    $fields = empty($o['fields']) ? '' : $o['fields'];
+               $this->out->rows($format,$rows,$head,$conf);
+               return true;
+       }
 
-    #var_dump ($this->tables());
+       public function tables_rows($o=[]) {
+               # Options
+               # Filters
+               $type = empty($o['type']) ? '' : $o['type'];
+               $name = empty($o['name']) ? '' : $o['name'];
+               $engine = empty($o['engine']) ? '' : $o['engine'];
+               $database = empty($o['database']) ? '' : $o['database'];
+               $count = empty($o['count']) ? '' : $o['count'];
+               $fields = empty($o['fields']) ? '' : $o['fields'];
+
+               #var_dump ($this->tables());
 #foreach($this->tables as $t) debug($t->name.'='.$t->type);
 #bye($this->tables);
-    $rows = [];
-    foreach ($this->tables() as $t) {
-      #debug($t->name.'='.$t->type);
-
-      if ($name and !$this->str_match($t->name,$name)) continue;
-      if ($type and !$this->str_match($t->type,$type)) continue;
-      if ($count and !$this->str_match($t->count,$count)) continue;
-      if ($engine and !$this->str_match($t->engine,$engine)) continue;
-      if ($database and isset($t->database) and !$this->str_match($t->database,$database)) continue;
-
-      $row = $t->status();
-      if ($count) $row['count'] = $t->status('count');
-      #if ($fields) $row['fields'] = $t->status('fields');
-      if ($fields) $row['fields'] = join(',',array_keys($t->fields()));
-
-      #debug($t->name.'='.$t->database);
-      $rows[] = $row;
-    }
-
-    $rows = self::array_fill_assoc($rows);
-    usort($rows,function($a,$b) { return strcmp($a['name'],$b['name']); });
-
-    return $rows;
-  }
-
-  public function action($action,$table=null) {
-    #debug(($this->tables));
-    $actions = explode(',',$action);
+               $rows = [];
+               foreach ($this->tables() as $t) {
+                       #debug($t->name.'='.$t->type);
+
+                       if ($name and !$this->str_match($t->name,$name)) continue;
+                       if ($type and !$this->str_match($t->type,$type)) continue;
+                       if ($count and !$this->str_match($t->count,$count)) continue;
+                       if ($engine and !$this->str_match($t->engine,$engine)) continue;
+                       if ($database and isset($t->database) and !$this->str_match($t->database,$database)) continue;
+
+                       $row = $t->status();
+                       if ($count) $row['count'] = $t->status('count');
+                       #if ($fields) $row['fields'] = $t->status('fields');
+                       if ($fields) $row['fields'] = join(',',array_keys($t->fields()));
+
+                       #debug($t->name.'='.$t->database);
+                       $rows[] = $row;
+               }
+
+               $rows = self::array_fill_assoc($rows);
+               usort($rows,function($a,$b) { return strcmp($a['name'],$b['name']); });
+
+               return $rows;
+       }
+
+       public function action($action,$table=null) {
+               #debug(($this->tables));
+               $actions = explode(',',$action);
 # NB 02.12.16     $this->pdef('format',($this->php_cli() ? 'csv' : ''));
-    $rows = [];
-    $return = false;
+               $rows = [];
+               $return = false;
 
-    foreach ($actions as $action) {
+               foreach ($actions as $action) {
 
-        if ($action == 'db.help') {
-          $this->out(self::$action_help,['action','description']);
-          $return = true;
+                               if ($action == 'db.help') {
+                                       $this->out(self::$action_help,['action','description']);
+                                       $return = true;
 
-        } elseif ($action == 'db.cryptkey') {
-          echo $this->out($this->cryptkey(),['key']);
+                               } elseif ($action == 'db.cryptkey') {
+                                       echo $this->out($this->cryptkey(),['key']);
 
-        } elseif ($action == 'db.exec') {
+                               } elseif ($action == 'db.exec') {
 
-          $count = 0;
-          $sql = '';
+                                       $count = 0;
+                                       $sql = '';
 
-          while (($line = fgets(STDIN)) !== false and !feof(STDIN)) {
+                                       while (($line = fgets(STDIN)) !== false and !feof(STDIN)) {
 
-            if (strpos($line,'--') === 0) continue;
+                                               if (strpos($line,'--') === 0) continue;
 
-            $line = preg_replace('/[\r\n]+$/','',$line);
-            if ($line == 'db.exec') break;
+                                               $line = preg_replace('/[\r\n]+$/','',$line);
+                                               if ($line == 'db.exec') break;
 
-            $sql .= $line;
+                                               $sql .= $line;
 
-            if (!preg_match('/;$/',$sql)) continue;
-            #$line = preg_replace('/^\s*(.*?)\s*;?\s*$/','$1',$line);
-            #if (!$line or strpos($line,'--') === 0) continue;
+                                               if (!preg_match('/;$/',$sql)) continue;
+                                               #$line = preg_replace('/^\s*(.*?)\s*;?\s*$/','$1',$line);
+                                               #if (!$line or strpos($line,'--') === 0) continue;
 
-            $count++;
-            #echo "$count> $line\n";
-            $this->conn->exec($sql);
-            $sql = '';
-          }
-          $return = $this->out([
-            'count' => $count,
-          ]);
+                                               $count++;
+                                               #echo "$count> $line\n";
+                                               $this->conn->exec($sql);
+                                               $sql = '';
+                                       }
+                                       $return = $this->out([
+                                               'count' => $count,
+                                       ]);
 
-        } elseif ($action == 'db.tables') {
+                               } elseif ($action == 'db.tables') {
 
-          $rows = $this->tables_rows($this->p());
-          $return = $this->out($rows);
+                                       $rows = $this->tables_rows($this->p());
+                                       $return = $this->out($rows);
 
-        } elseif ($action == 'db.conf') {
-          $return = $this->out(array_values($this->conf));
+                               } elseif ($action == 'db.conf') {
+                                       $return = $this->out(array_values($this->conf));
 
-        } elseif ($action == 'db.ls') {
-          $return = $this->out($this->ls());
+                               } elseif ($action == 'db.ls') {
+                                       $return = $this->out($this->ls());
 
-        } elseif ($r=self::class_action_out($this,$action) !== null) {
-          return $r;
+                               } elseif ($r=self::class_action_out($this,$action) !== null) {
+                                       return $r;
 
-        } elseif($table) {
-          if ($r=$table->action($action)) $return = $r;
+                               } elseif($table) {
+                                       if ($r=$table->action($action)) $return = $r;
 
-        }
-    }
+                               }
+               }
 
-    return $return;
-  }
+               return $return;
+       }
 
-  /**
-  * @copyright NB 05.03.16
-  * @param [FILES] $files Files to load
-  * @return ARRAY the new/existing value of $this->db
-  */
-  public static function ar_merge($a,$b) {
+       /**
+       * @copyright NB 05.03.16
+       * @param [FILES] $files Files to load
+       * @return ARRAY the new/existing value of $this->db
+       */
+       public static function ar_merge($a,$b) {
                return array_replace_recursive($a,$b);
                #return array_combine($a,$b);
                $n = $a;
@@ -697,674 +697,674 @@ class Db extends nb {
                return $n;
        }
 
-  public static function conf_load($files=[],&$first=false) {
-    if (empty($files)) return [];
+       public static function conf_load($files=[],&$first=false) {
+               if (empty($files)) return [];
 
-    #
-    # Load all files into a $dbs if #files is not a hash
-    #
+               #
+               # Load all files into a $dbs if #files is not a hash
+               #
 
-    $DBQ = [];
-    $dbs = [];
-    $done = [];
-    foreach ((array)$files as $file) {
+               $DBQ = [];
+               $dbs = [];
+               $done = [];
+               foreach ((array)$files as $file) {
 
-      $file = self::untilde(realpath($file));
-      if (isset($done[$file])) continue;
-      else $done[$file] = 1;
+                       $file = self::untilde(realpath($file));
+                       if (isset($done[$file])) continue;
+                       else $done[$file] = 1;
 
-      if (!is_readable($file)) continue;
-      if (preg_match('/\.(yaml|yml)$/i',$file) and ($yaml = self::yaml_parse_file($file))) {
-        $dbs = self::ar_merge($dbs,$yaml);
+                       if (!is_readable($file)) continue;
+                       if (preg_match('/\.(yaml|yml)$/i',$file) and ($yaml = self::yaml_parse_file($file))) {
+                               $dbs = self::ar_merge($dbs,$yaml);
 
-      } elseif (preg_match('/\.php$/i',$file)) {
+                       } elseif (preg_match('/\.php$/i',$file)) {
                                $DBQ = [];
-        require($file);
-        if (!empty($DBQ)) $dbs = self::ar_merge($dbs,$DBQ);
+                               require($file);
+                               if (!empty($DBQ)) $dbs = self::ar_merge($dbs,$DBQ);
 
-      }
+                       }
 
-    }
+               }
 
-    unset($yaml,$DBQ);
-    if (!$dbs) return false;
+               unset($yaml,$DBQ);
+               if (!$dbs) return false;
 
-    #
-    # First iteration: Import database conf with key _import
-    #
-    foreach ($dbs as $id=>$params) {
-      $params = (array)$params;
+               #
+               # First iteration: Import database conf with key _import
+               #
+               foreach ($dbs as $id=>$params) {
+                       $params = (array)$params;
 
-      foreach ($params as $k => $v) {
-        if ($k != '_import') continue;
+                       foreach ($params as $k => $v) {
+                               if ($k != '_import') continue;
 
-        $import = is_array($v) ? $v : explode(',',$v);
-        foreach ($import as $v) {
-          if ($id == $v) self::bye("Infinite loop: _import $id = $v");
-          if (empty($dbs[$v])) continue;
+                               $import = is_array($v) ? $v : explode(',',$v);
+                               foreach ($import as $v) {
+                                       if ($id == $v) self::bye("Infinite loop: _import $id = $v");
+                                       if (empty($dbs[$v])) continue;
 
-          foreach ($dbs[$v] as $kk => $vv) {
-            if (!isset($params[$kk])) $dbs[$id][$kk] = $vv;
-          }
-        }
+                                       foreach ($dbs[$v] as $kk => $vv) {
+                                               if (!isset($params[$kk])) $dbs[$id][$kk] = $vv;
+                                       }
+                               }
 
-        unset($dbs[$id][$k]);
-      }
-    }
+                               unset($dbs[$id][$k]);
+                       }
+               }
 
-    $default = isset($dbs['_default']) ? $dbs['_default'] : [];
+               $default = isset($dbs['_default']) ? $dbs['_default'] : [];
 
-    #
-    # Second iteration: Remove db starting with _
-    #
-    foreach ($dbs as $db=>$params) { if (preg_match('/^_/',$db)) unset($dbs[$db]); }
+               #
+               # Second iteration: Remove db starting with _
+               #
+               foreach ($dbs as $db=>$params) { if (preg_match('/^_/',$db)) unset($dbs[$db]); }
 
-    if (!$dbs) return false;
+               if (!$dbs) return false;
 
-    #
-    # Third iteration: Add missing and default
-    #
-    foreach ($dbs as $db=>$params) {
-      if (empty($params['name'])) $dbs[$db]['name'] = $db;
-      if (empty($params['id'])) $dbs[$db]['id'] = $db;
+               #
+               # Third iteration: Add missing and default
+               #
+               foreach ($dbs as $db=>$params) {
+                       if (empty($params['name'])) $dbs[$db]['name'] = $db;
+                       if (empty($params['id'])) $dbs[$db]['id'] = $db;
 
                        # Ignore incomplete
-      if (empty($params['type'])) {
+                       if (empty($params['type'])) {
                                unset($dbs[$db]);
                                continue;
                        }
 
-      foreach ($default as $k=>$v) if (!isset($params[$k])) $dbs[$db][$k] = $v;
-    }
-
-    #
-    # Sort by `order`, min first
-    #
-    uasort($dbs,function($a,$b){
-      if (empty($a['order']) and empty($b['order'])) return strcmp($a['id'],$b['id']);
-      $a_ = !empty($a['order']) ? $a['order'] : 9999999;
-      $b_ = !empty($b['order']) ? $b['order'] : 9999999;
-      return($a_-$b_);
-    });
-
-    #
-    # Return
-    #
-    if (!$dbs) return false;
-    if ($first !== false) $first = self::ar_first($dbs);
-    return $dbs;
-  }
-
-  /**
-  * @copyright NB 19.11.16
-  * Return a db hash to create a new instance from $conf
-  */
-  public static function conf_param_db($id) {
-    if (!isset($id)) $id = self::p('db');
-
-    if (!$id or !preg_match('/^(\w+):(.*)/',$id,$m)) return [];
-    $conf = [$id => []];
-
-    $conf[$id] = $conf[$id] + self::pdo2h($id);
-    # NB 10.12.16: NEW 
-    if (empty($conf['id'])) $conf['id'] = $id;
-
-    return $conf;
-  }
-
-  /**
-  * @copyright NB 12.08.16
-  * Return a db hash to create a new instance from $conf
-  */
-  public static function conf_search_db($conf,$id=null) {
-
-    if (empty($id)) $id = self::p('db');
-
-    # Load databases
-    $conf = self::is_hash($conf) ? $conf : self::conf_load($conf);
-
-    $conf += self::conf_param_db($id);
-
-    if (!$conf) return false;
-
-    # Param - Default base on order hight num value
-    if (!$id) {
-      $id = self::ar_first($conf,true);
-      self::pset('db',$id);
-    }
-
-    if (!isset($conf[$id])) {
-      self::bye("Can't find db: `".$id."` in `".join(",",array_keys($conf))."`",false);
-    }
-
-    if (empty($conf[$id])) return [];
-
-    # Construct assoc array
-    $db = array_merge($conf[$id],[
-      'conf' => $conf,
-    ]);
-
-    return $db;
-  }
-
-  /**
-  * @copyright NB 12.08.16
-  * Create globals Db and Table
-  */
-  public static function init($conf) {
-
-    #
-    # Params
-    self::pinit();
-
-    #
-    # Load conf
-    $db = self::conf_search_db($conf);
-    if (self::p('localFile')) {
-      foreach (self::localFile($db['name']) as $k=>$v) {
-        if (empty($db[$k])) $db[$k] = $v;
-      }
-    }
-
-    #
-    # Db
-    #
-    global $Db, $Table;
-    if (isset($Table)) self::bye("Table.init(): GLOBALS['Table'] already exists !");
-    if (isset($Db)) self::bye("Db.init(): GLOBALS['Db'] already exists !");
-    $Db = new self();
-    #
-    # Connection
-    $Db->__construct($db);
-    $Db->connect();
-
-    #
-    # Table
-    #
-    if (self::p('action') and
-      !self::p('table') and
-      !preg_match('/^(table\.\w+|rows|insert|edit|delete|update)$/',self::p('action'))
-    ) {
-
-    } else {
-
-      # Search default_table
-      if (!self::p('table') and isset($Db->default_table)) self::pset('table',$Db->default_table);
-
-      # Choose first table
-      if (!self::p('table') and ($v = array_keys($Db->tables()))) self::pset('table',$Db->ar_first($v));
-
-      if (self::p('table')) $Table = $Db->table(self::p('table'),
-        ( empty($db['tables'][$Db->p('table')]) ? [] : $db['tables'][$Db->p('table')] )
-      );
-
-    }
-
-    return true;
-  }
-
-  /**
-  * @copyright NB 12.08.16
-  * Transform pdo string into assoc array
-  */
-  public static function pdo2h($pdo) {
-    $hash = [];
-
-    if (preg_match('/^(\w+):(.*)/',$pdo,$m)) {
-      $hash['type'] = $m[1];
-      $pdo = $m[2];
-    }
-
-    # YES - 'use_path' 
-    while (preg_match('/^(\w+)=([^;]*)(?:;?)(.*?)$/',$pdo,$m)) {
-      if ($m[1] == 'dbname') $m[1] = 'name';
-      $hash[$m[1]] = $m[2];
-      $pdo = $m[3];
-    }
-
-    # NO - 'use_path' 
-    if ($pdo) {
-      $hash['host'] = $pdo;
-      unset($pdo);
-    }
-
-    return $hash;
-  }
-
-  public function pdo_info() {#$pdo) {
-    $infos = [];
-
-    foreach (self::pdo2h($this->pdo) as $k=>$v) {
-      if (!preg_match('/^(host|port|dbname|name|user)/',$k)) continue;
-      $infos[] = "$k=$v";
-    }
-
-    return join(' ',$infos);
-  }
-
-  public function dump2csv() {
-
-    $this->pset('format','csv');
-
-    # Filters
-    $name = self::p('name',self::p('table',''));
-    $sep = self::p('sep',"\t");
-
-    foreach ($this->tables() as $t) {
-      if (
-        ($t->type == 'table')
-        and (empty($name) or $this->str_match($t->name,$name))
-      ) {
-        $o = [
-          'preffix' => $t->name.$sep
-        ]; $t->rows($o);
-      }
-    }
-
-  }
-
-  public function dump($db_type='') {
-    return $this->sql(true,$db_type);
-  }
-
-  public function sql($insert=null,$db_type='') {
-    if ($insert === null) $insert = self::p('insert');
-    if (empty($db_type)) $db_type = self::p('db-type');
-
-    # Params ! dirty !
+                       foreach ($default as $k=>$v) if (!isset($params[$k])) $dbs[$db][$k] = $v;
+               }
+
+               #
+               # Sort by `order`, min first
+               #
+               uasort($dbs,function($a,$b){
+                       if (empty($a['order']) and empty($b['order'])) return strcmp($a['id'],$b['id']);
+                       $a_ = !empty($a['order']) ? $a['order'] : 9999999;
+                       $b_ = !empty($b['order']) ? $b['order'] : 9999999;
+                       return($a_-$b_);
+               });
+
+               #
+               # Return
+               #
+               if (!$dbs) return false;
+               if ($first !== false) $first = self::ar_first($dbs);
+               return $dbs;
+       }
+
+       /**
+       * @copyright NB 19.11.16
+       * Return a db hash to create a new instance from $conf
+       */
+       public static function conf_param_db($id) {
+               if (!isset($id)) $id = self::p('db');
+
+               if (!$id or !preg_match('/^(\w+):(.*)/',$id,$m)) return [];
+               $conf = [$id => []];
+
+               $conf[$id] = $conf[$id] + self::pdo2h($id);
+               # NB 10.12.16: NEW 
+               if (empty($conf['id'])) $conf['id'] = $id;
+
+               return $conf;
+       }
+
+       /**
+       * @copyright NB 12.08.16
+       * Return a db hash to create a new instance from $conf
+       */
+       public static function conf_search_db($conf,$id=null) {
+
+               if (empty($id)) $id = self::p('db');
+
+               # Load databases
+               $conf = self::is_hash($conf) ? $conf : self::conf_load($conf);
+
+               $conf += self::conf_param_db($id);
+
+               if (!$conf) return false;
+
+               # Param - Default base on order hight num value
+               if (!$id) {
+                       $id = self::ar_first($conf,true);
+                       self::pset('db',$id);
+               }
+
+               if (!isset($conf[$id])) {
+                       self::bye("Can't find db: `".$id."` in `".join(",",array_keys($conf))."`",false);
+               }
+
+               if (empty($conf[$id])) return [];
+
+               # Construct assoc array
+               $db = array_merge($conf[$id],[
+                       'conf' => $conf,
+               ]);
+
+               return $db;
+       }
+
+       /**
+       * @copyright NB 12.08.16
+       * Create globals Db and Table
+       */
+       public static function init($conf) {
+
+               #
+               # Params
+               self::pinit();
+
+               #
+               # Load conf
+               $db = self::conf_search_db($conf);
+               if (self::p('localFile')) {
+                       foreach (self::localFile($db['name']) as $k=>$v) {
+                               if (empty($db[$k])) $db[$k] = $v;
+                       }
+               }
+
+               #
+               # Db
+               #
+               global $Db, $Table;
+               if (isset($Table)) self::bye("Table.init(): GLOBALS['Table'] already exists !");
+               if (isset($Db)) self::bye("Db.init(): GLOBALS['Db'] already exists !");
+               $Db = new self();
+               #
+               # Connection
+               $Db->__construct($db);
+               $Db->connect();
+
+               #
+               # Table
+               #
+               if (self::p('action') and
+                       !self::p('table') and
+                       !preg_match('/^(table\.\w+|rows|insert|edit|delete|update)$/',self::p('action'))
+               ) {
+
+               } else {
+
+                       # Search default_table
+                       if (!self::p('table') and isset($Db->default_table)) self::pset('table',$Db->default_table);
+
+                       # Choose first table
+                       if (!self::p('table') and ($v = array_keys($Db->tables()))) self::pset('table',$Db->ar_first($v));
+
+                       if (self::p('table')) $Table = $Db->table(self::p('table'),
+                               ( empty($db['tables'][$Db->p('table')]) ? [] : $db['tables'][$Db->p('table')] )
+                       );
+
+               }
+
+               return true;
+       }
+
+       /**
+       * @copyright NB 12.08.16
+       * Transform pdo string into assoc array
+       */
+       public static function pdo2h($pdo) {
+               $hash = [];
+
+               if (preg_match('/^(\w+):(.*)/',$pdo,$m)) {
+                       $hash['type'] = $m[1];
+                       $pdo = $m[2];
+               }
+
+               # YES - 'use_path' 
+               while (preg_match('/^(\w+)=([^;]*)(?:;?)(.*?)$/',$pdo,$m)) {
+                       if ($m[1] == 'dbname') $m[1] = 'name';
+                       $hash[$m[1]] = $m[2];
+                       $pdo = $m[3];
+               }
+
+               # NO - 'use_path' 
+               if ($pdo) {
+                       $hash['host'] = $pdo;
+                       unset($pdo);
+               }
+
+               return $hash;
+       }
+
+       public function pdo_info() {#$pdo) {
+               $infos = [];
+
+               foreach (self::pdo2h($this->pdo) as $k=>$v) {
+                       if (!preg_match('/^(host|port|dbname|name|user)/',$k)) continue;
+                       $infos[] = "$k=$v";
+               }
+
+               return join(' ',$infos);
+       }
+
+       public function dump2csv() {
+
+               $this->pset('format','csv');
+
+               # Filters
+               $name = self::p('name',self::p('table',''));
+               $sep = self::p('sep',"\t");
+
+               foreach ($this->tables() as $t) {
+                       if (
+                               ($t->type == 'table')
+                               and (empty($name) or $this->str_match($t->name,$name))
+                       ) {
+                               $o = [
+                                       'preffix' => $t->name.$sep
+                               ]; $t->rows($o);
+                       }
+               }
+
+       }
+
+       public function dump($db_type='') {
+               return $this->sql(true,$db_type);
+       }
+
+       public function sql($insert=null,$db_type='') {
+               if ($insert === null) $insert = self::p('insert');
+               if (empty($db_type)) $db_type = self::p('db-type');
+
+               # Params ! dirty !
 # NB 10.01.18     $this->pset('orderby',null);
 # NB 10.01.18     $this->pset('extras','0');
 # NB 10.01.18     $this->pset('format','sql');
 
-    # Filters
-    $type = self::p('table-type',''); $type = $type ? explode(',',$type) : $type;
-    $name = self::p('table-name',''); $name = $name ? explode(',',$name) : $name;
-
-    # Tables param filter
-    $tables = $this->tables();
-
-    # Caching before changing db type
-    $views = [];
-    foreach ($tables as $k=>$t) {
-
-      if (
-        ($t->type != 'table' and $t->type != 'view')
-        or (!empty($name) and !$this->str_match($t->name,$name))
-        or (!empty($type) and !$this->str_match($t->type,$type))
-      ) {
-        unset($tables[$k]);
-        continue;
-      }
-
-      if ($t->type == 'view') {
-        $views[$k] = $t;
-        unset($tables[$k]);
-      }
-      unset($t->orderby);
-
-      $t->fields();
-      $t->sql();
-    }
-
-    # HEADER
-    echo ''
-      #."-- Database : ".$this->name."\n"
-      ."-- Date     : ".strftime('%F %T')."\n"
+               # Filters
+               $type = self::p('table-type',''); $type = $type ? explode(',',$type) : $type;
+               $name = self::p('table-name',''); $name = $name ? explode(',',$name) : $name;
+
+               # Tables param filter
+               $tables = $this->tables();
+
+               # Caching before changing db type
+               $views = [];
+               foreach ($tables as $k=>$t) {
+
+                       if (
+                               ($t->type != 'table' and $t->type != 'view')
+                               or (!empty($name) and !$this->str_match($t->name,$name))
+                               or (!empty($type) and !$this->str_match($t->type,$type))
+                       ) {
+                               unset($tables[$k]);
+                               continue;
+                       }
+
+                       if ($t->type == 'view') {
+                               $views[$k] = $t;
+                               unset($tables[$k]);
+                       }
+                       unset($t->orderby);
+
+                       $t->fields();
+                       $t->sql();
+               }
+
+               # HEADER
+               echo ''
+                       #."-- Database : ".$this->name."\n"
+                       ."-- Date     : ".strftime('%F %T')."\n"
 # NB 07.01.18       ."-- Pdo      : ".$this->pdo_info()."\n"
-    ;
+               ;
 
-    # Change db type if needed
-    $type_from = $type_to = '';
-    if ($db_type) {
-      echo "-- Type     : ".$db_type."\n";
-      echo "-- Type from: ".$this->type."\n";
-      $type_from = $this->type;
-      $type_to = $db_type;
-      $this->type = $type_to;
+               # Change db type if needed
+               $type_from = $type_to = '';
+               if ($db_type) {
+                       echo "-- Type     : ".$db_type."\n";
+                       echo "-- Type from: ".$this->type."\n";
+                       $type_from = $this->type;
+                       $type_to = $db_type;
+                       $this->type = $type_to;
 
                } else {
-      echo "-- Type     : ".$this->type."\n";
-
-    }
-
-    # Specific function
-    $row_opt = [
-      'parser' => false,
-      'format' => 'sql',
-      'db_type_from' => $type_from,
-    ];
-
-    # SQL_PRE
-    $i = 0; foreach ((array)$this->method('schema.pre') as $s) {
-      if (($i++) == 0) echo "\n-- SQL.PRE\n";
-      echo rtrim($s,';').";\n";
-    }
-
-    if ($type_from == 'mysql') $views = []; # Mysql store sql create view in mysql format wich only works with mysql
-    echo "\n-- SQL\n";
-    foreach (array_merge($tables,$views) as $t) {
-
-      # DROP / CREATE
-      $create = rtrim($t->create(false),';');
-      $create = str_replace(';CREATE',";\nCREATE",$create);
-
-      if (!($drop = $this->method('sql.drop'))) $drop =
-        'DROP '.strtoupper($t->type).' IF EXISTS '.$t->sql_name()
-      ;
-
-      $t->sql_create = $drop.';'.NB_EOL
-        .$create.';'.NB_EOL
-      ;
-
-      if ($insert) $t->sql_create =
-        "\n-- ".strtoupper($t->type).": ".$t->name."\n".$t->sql_create
-      ;
-      echo $t->sql_create;
-
-      # INSERT
-      if ($insert and $t->type == 'table') {
+                       echo "-- Type     : ".$this->type."\n";
+
+               }
+
+               # Specific function
+               $row_opt = [
+                       'parser' => false,
+                       'format' => 'sql',
+                       'db_type_from' => $type_from,
+               ];
+
+               # SQL_PRE
+               $i = 0; foreach ((array)$this->method('schema.pre') as $s) {
+                       if (($i++) == 0) echo "\n-- SQL.PRE\n";
+                       echo rtrim($s,';').";\n";
+               }
+
+               if ($type_from == 'mysql') $views = []; # Mysql store sql create view in mysql format wich only works with mysql
+               echo "\n-- SQL\n";
+               foreach (array_merge($tables,$views) as $t) {
+
+                       # DROP / CREATE
+                       $create = rtrim($t->create(false),';');
+                       $create = str_replace(';CREATE',";\nCREATE",$create);
+
+                       if (!($drop = $this->method('sql.drop'))) $drop =
+                               'DROP '.strtoupper($t->type).' IF EXISTS '.$t->sql_name()
+                       ;
+
+                       $t->sql_create = $drop.';'.NB_EOL
+                               .$create.';'.NB_EOL
+                       ;
+
+                       if ($insert) $t->sql_create =
+                               "\n-- ".strtoupper($t->type).": ".$t->name."\n".$t->sql_create
+                       ;
+                       echo $t->sql_create;
+
+                       # INSERT
+                       if ($insert and $t->type == 'table') {
                                $o = $row_opt;
-        $t->rows($o);
-      }
+                               $t->rows($o);
+                       }
 
-    }
+               }
 
-    $i = 0; foreach ((array)$this->method('schema.post') as $s) {
-      if (($i++) == 0) echo "\n-- SQL.POST\n";
-      echo rtrim($s,';').";\n";
-    }
+               $i = 0; foreach ((array)$this->method('schema.post') as $s) {
+                       if (($i++) == 0) echo "\n-- SQL.POST\n";
+                       echo rtrim($s,';').";\n";
+               }
 
-    return true;
-  }
+               return true;
+       }
 
-  public function status() {
+       public function status() {
 
-    $status = $new = [];
+               $status = $new = [];
 
 #debug(array_keys($this->tables()));
-    $new = []
-    +[
-      'id' => (empty($this->id) ? '' : $this->id),
-      'name' => $this->name,
-      'type' => $this->type,
-      'host' => $this->host,
-      'tables' => count($this->tables()),
-    ]
-    +($this->conf_type('use_path') ? [] : [
-      'port' => $this->port,
-      'user' => $this->user,
-    ])
-    +[
-      'title' => $this->title,
-      'default_table' => $this->default_table,
-    ]
-    +$new;
-
-    if (($sqls=$this->conf_type('status'))) {
-
-      foreach ($sqls as $sql => $fct) {
-
-        try {
-          $sth = $this->conn->prepare($sql);
-          $sth->execute();
-        } catch(PDOException $e){ 
-          continue;
-        }
-
-        $rows = $sth->fetchAll(PDO::FETCH_BOTH);
-        foreach ($rows as $i=>$r) {
-          if ($v = $fct($r)) $new += $v;
-        }
-        #$sqls = $new;
-        #debug($rows);
-      }
-
-    } # << type.status
-
-    if (($call=$this->conf_type('status_callback'))) {
-      $call($new);
-    }
-
-    #debug($new);
-    foreach ($new as $k=>$v) {
-      $status[] = [
-        'name' => $k,
-        'value' => $v,
-      ];
-    }
-
-    return $status;
-  }
-
-  public function fields($st) {
-    # See: http://php.net/manual/en/pdostatement.getcolumnmeta.php
-    $fields = [];
-    #debug($st->columnCount());
-    #debug($st->getColumnMeta(0));
-
-    for ($i = 0; $i < $st->columnCount(); $i++) {
-      $col = $st->getColumnMeta($i);
-
-      $f = new Field();
-      $col['type'] = $f->pdo2type($col['pdo_type']);
-      unset($col['pdo_type']);
-
-      if (!empty($col['flags'])) {
-        $col['null'] = in_array('not_null',$col['flags']) ? false : true;
-        $col['key'] = in_array('primary_key',$col['flags']) ? true : false;
-      }
-      unset($col['flags']);
-
-      unset($col['len']); # never right !
-      unset($col['precision']); # ???
-
-      $f->__construct($col);
-      $fields[] = $f;
-    }
-
-    return $fields;
-  }
-
-  public function sql_pre() {
-    $return = [];
-
-    foreach ((array)$this->conf_type('sql_pre') as $s) {
-      if (!empty($s)) $return[] = $s;
-    }
-
-    if (!empty($this->sql_pre)) {
-      foreach ((array)$this->sql_pre as $s) {
-        if (!empty($s)) $return[] = $s;
-      }
-    }
-
-    return $return;
-  }
-
-  public function sql_post() {
-    $return = [];
-
-    foreach ((array)$this->conf_type('sql_post') as $s) {
-      if (!empty($s)) $return[] = $s;
-    }
-
-    if (!empty($this->sql_post)) {
-      foreach ((array)$this->sql_post as $s) {
-        if (!empty($s)) $return[] = $s;
-      }
-    }
+               $new = []
+               +[
+                       'id' => (empty($this->id) ? '' : $this->id),
+                       'name' => $this->name,
+                       'type' => $this->type,
+                       'host' => $this->host,
+                       'tables' => count($this->tables()),
+               ]
+               +($this->conf_type('use_path') ? [] : [
+                       'port' => $this->port,
+                       'user' => $this->user,
+               ])
+               +[
+                       'title' => $this->title,
+                       'default_table' => $this->default_table,
+               ]
+               +$new;
+
+               if (($sqls=$this->conf_type('status'))) {
+
+                       foreach ($sqls as $sql => $fct) {
+
+                               try {
+                                       $sth = $this->conn->prepare($sql);
+                                       $sth->execute();
+                               } catch(PDOException $e){ 
+                                       continue;
+                               }
+
+                               $rows = $sth->fetchAll(PDO::FETCH_BOTH);
+                               foreach ($rows as $i=>$r) {
+                                       if ($v = $fct($r)) $new += $v;
+                               }
+                               #$sqls = $new;
+                               #debug($rows);
+                       }
 
-    return $return;
-  }
+               } # << type.status
 
-  public function databases() {
+               if (($call=$this->conf_type('status_callback'))) {
+                       $call($new);
+               }
 
-    if (!isset($this->databases)) {
+               #debug($new);
+               foreach ($new as $k=>$v) {
+                       $status[] = [
+                               'name' => $k,
+                               'value' => $v,
+                       ];
+               }
 
-      $this->databases = [];
-      $name = self::p('name','');
+               return $status;
+       }
 
-      if ($sql = $this->conf_type('databases') and !empty($this->conn)) {
-        $fct = '';
-        if (is_array($sql)) list($sql,$fct) = count($sql)>1 ? $sql : [$sql[0],''];
+       public function fields($st) {
+               # See: http://php.net/manual/en/pdostatement.getcolumnmeta.php
+               $fields = [];
+               #debug($st->columnCount());
+               #debug($st->getColumnMeta(0));
 
-        $st = $this->conn->prepare($sql);
-        $st->execute();
-        $this->databases = [];
+               for ($i = 0; $i < $st->columnCount(); $i++) {
+                       $col = $st->getColumnMeta($i);
 
-        while ($row = $st->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_NEXT)) {
-          if ($fct) $fct($row,$this);
-          if ($row) $this->databases[] = $row;
-        }
+                       $f = new Field();
+                       $col['type'] = $f->pdo2type($col['pdo_type']);
+                       unset($col['pdo_type']);
 
-      }
+                       if (!empty($col['flags'])) {
+                               $col['null'] = in_array('not_null',$col['flags']) ? false : true;
+                               $col['key'] = in_array('primary_key',$col['flags']) ? true : false;
+                       }
+                       unset($col['flags']);
 
-    }
+                       unset($col['len']); # never right !
+                       unset($col['precision']); # ???
 
-    return $this->databases;
-  }
+                       $f->__construct($col);
+                       $fields[] = $f;
+               }
 
-  public static function pinit(&$changed=[]) {
-    if (!empty(self::$paliases)) self::paliases(self::$paliases,$changed);
+               return $fields;
+       }
 
-    if ($action=self::p('action') and !empty(self::$action_aliases)) {
-      foreach (self::$action_aliases as $src => $dest) {
-        if ($action === $src) self::pset('action',$dest);
-      }
-    }
+       public function sql_pre() {
+               $return = [];
 
-    # Param - Extract dbname from table
+               foreach ((array)$this->conf_type('sql_pre') as $s) {
+                       if (!empty($s)) $return[] = $s;
+               }
+
+               if (!empty($this->sql_pre)) {
+                       foreach ((array)$this->sql_pre as $s) {
+                               if (!empty($s)) $return[] = $s;
+                       }
+               }
+
+               return $return;
+       }
+
+       public function sql_post() {
+               $return = [];
+
+               foreach ((array)$this->conf_type('sql_post') as $s) {
+                       if (!empty($s)) $return[] = $s;
+               }
+
+               if (!empty($this->sql_post)) {
+                       foreach ((array)$this->sql_post as $s) {
+                               if (!empty($s)) $return[] = $s;
+                       }
+               }
+
+               return $return;
+       }
+
+       public function databases() {
+
+               if (!isset($this->databases)) {
+
+                       $this->databases = [];
+                       $name = self::p('name','');
+
+                       if ($sql = $this->conf_type('databases') and !empty($this->conn)) {
+                               $fct = '';
+                               if (is_array($sql)) list($sql,$fct) = count($sql)>1 ? $sql : [$sql[0],''];
+
+                               $st = $this->conn->prepare($sql);
+                               $st->execute();
+                               $this->databases = [];
+
+                               while ($row = $st->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_NEXT)) {
+                                       if ($fct) $fct($row,$this);
+                                       if ($row) $this->databases[] = $row;
+                               }
+
+                       }
+
+               }
+
+               return $this->databases;
+       }
+
+       public static function pinit(&$changed=[]) {
+               if (!empty(self::$paliases)) self::paliases(self::$paliases,$changed);
+
+               if ($action=self::p('action') and !empty(self::$action_aliases)) {
+                       foreach (self::$action_aliases as $src => $dest) {
+                               if ($action === $src) self::pset('action',$dest);
+                       }
+               }
+
+               # Param - Extract dbname from table
 # NB 12.11.16     if (false and preg_match('/^(\w+)\.(.*?)$/',self::p('table'),$m)) {
 # NB 12.11.16       self::pset('db',$m[1]);
 # NB 12.11.16       self::pset('table',$m[2]);
 # NB 12.11.16     }
 
-    # Select param
-    if (Db::p('table') and Db::p('select')) {
-      Db::pset('table','SELECT '.(Db::p('select')).' FROM '.Db::p('table'));
-      Db::pset('select','');
-    }
-
-  }
-
-  public function ls(&$fields=[]) {
-
-    $fields = ['id','name','title','type','host' ]; #,'order'];
-    $dbs = [];
-    $name = self::p('name','');
-    $type = self::p('type','');
-
-    if (empty($this->conf)) return null;
-
-    foreach ($this->conf as $id => $attr) {
-      $attr['id'] = $id;
-      $d = new Db($attr);
-      $db = [];
-
-      foreach ($fields as $k) {
-        $db[$k] = isset($d->$k) ? $d->$k : '';
-      }
-
-      if (!empty($name) and !$this->str_match($db['name'],$name)) continue;
-      if (!empty($type) and !$this->str_match($db['type'],$type)) continue;
-
-      $dbs[] = $db;
-    }
-
-    return $dbs;
-  }
-
-  public function table_row_encrypt(&$table,&$row) {
-    if (!empty($table->update_parse)) {
-      $fct = $table->update_parse;
-      $fct($row,$table);
-    }
-
-    if (0
-      or empty($this->encrypt)
-      or empty($this->encrypt['secret'])
-      or empty($this->encrypt['tables'])
-      or empty($this->encrypt['tables'][$table->name])
-    ) return $row;
-
-    foreach ($row as $k => $v) {
-      if (!in_array($k,$this->encrypt['tables'][$table->name])) continue;
-      $row[$k] = $this->encrypt($this->encrypt['secret'],$v);
-    }
-
-    return $row;
-  }
-
-  public function table_row_decrypt(&$table,&$row) {
-    if (0
-      or empty($this->encrypt)
-      or empty($this->encrypt['secret'])
-      or empty($this->encrypt['tables'])
-      or empty($this->encrypt['tables'][$table->name])
-    ) return $row;
-
-    foreach ($row as $k => $v) {
-      if (!in_array($k,$this->encrypt['tables'][$table->name])) continue;
-      $row[$k] = $this->decrypt($this->encrypt['secret'],$v);
-    }
-
-    return $row;
-  }
-
-  public static function content_type2format($content_type=null) {
-    if (empty($content_type)) $content_type = self::client_content_type();
-    switch (mime::ext($content_type)) {
-      case "html":
-        return 'table';
-      default:
-        return 'csv';
-    }
-  }
-
-  public function page($opt=[]) {
-    require_once(NB_ROOT.'/lib/php/page.php');
-    return new Page(array_merge([
-      'title' => ($this->title ? $this->title : this::prettyText($this->name)),
-      'css' => [
-        'css/*.css',
-        '/*.css',
-      ],
-      'js' => [
-        'js/*.js',
-        '/*.js',
-      ],
-      'content_type' => Page::content_type_and_set_format(),
-      'nav' => [
-        [ (!empty($this) and !empty($this->title)) ? $this->title : 'Home', '/'],
-        ( (!empty($this->table()) and !empty($this->table()->name)) ? [Page::prettyText($this->table()->name),Page::path().'?table='.urlencode($this->table()->name)] : '' ),
-        ( Page::p('action') ? Page::prettyText(preg_replace('/^\w+\./','',Page::p('action'))) : '' ),
-      ],
-    ],$opt));
-  }
-
-  public function ssha512_password($password='',$salt='') {
-    if (empty($password)) return $password;
-    if ($salt === '') $salt = substr(str_shuffle(str_repeat('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',4)),0,4);
-    $password = '{SSHA512}' . base64_encode(hash('sha512', $password . $salt). $salt);
-    return $password;
-  }
-
-  public function ssha_password($password='') {
-    if (empty($password)) return $password;
-    $salt = substr(str_shuffle(str_repeat('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',4)),0,4);
-    $password = '{SSHA}' . base64_encode(sha1( $password.$salt, TRUE ). $salt);
-    return $password;
-  }
-
-  public function cast_text($str) {
-    if ($fct = $this->conf_type('cast_text')) $str = $fct($str);
+               # Select param
+               if (Db::p('table') and Db::p('select')) {
+                       Db::pset('table','SELECT '.(Db::p('select')).' FROM '.Db::p('table'));
+                       Db::pset('select','');
+               }
+
+       }
+
+       public function ls(&$fields=[]) {
+
+               $fields = ['id','name','title','type','host' ]; #,'order'];
+               $dbs = [];
+               $name = self::p('name','');
+               $type = self::p('type','');
+
+               if (empty($this->conf)) return null;
+
+               foreach ($this->conf as $id => $attr) {
+                       $attr['id'] = $id;
+                       $d = new Db($attr);
+                       $db = [];
+
+                       foreach ($fields as $k) {
+                               $db[$k] = isset($d->$k) ? $d->$k : '';
+                       }
+
+                       if (!empty($name) and !$this->str_match($db['name'],$name)) continue;
+                       if (!empty($type) and !$this->str_match($db['type'],$type)) continue;
+
+                       $dbs[] = $db;
+               }
+
+               return $dbs;
+       }
+
+       public function table_row_encrypt(&$table,&$row) {
+               if (!empty($table->update_parse)) {
+                       $fct = $table->update_parse;
+                       $fct($row,$table);
+               }
+
+               if (0
+                       or empty($this->encrypt)
+                       or empty($this->encrypt['secret'])
+                       or empty($this->encrypt['tables'])
+                       or empty($this->encrypt['tables'][$table->name])
+               ) return $row;
+
+               foreach ($row as $k => $v) {
+                       if (!in_array($k,$this->encrypt['tables'][$table->name])) continue;
+                       $row[$k] = $this->encrypt($this->encrypt['secret'],$v);
+               }
+
+               return $row;
+       }
+
+       public function table_row_decrypt(&$table,&$row) {
+               if (0
+                       or empty($this->encrypt)
+                       or empty($this->encrypt['secret'])
+                       or empty($this->encrypt['tables'])
+                       or empty($this->encrypt['tables'][$table->name])
+               ) return $row;
+
+               foreach ($row as $k => $v) {
+                       if (!in_array($k,$this->encrypt['tables'][$table->name])) continue;
+                       $row[$k] = $this->decrypt($this->encrypt['secret'],$v);
+               }
+
+               return $row;
+       }
+
+       public static function content_type2format($content_type=null) {
+               if (empty($content_type)) $content_type = self::client_content_type();
+               switch (mime::ext($content_type)) {
+                       case "html":
+                               return 'table';
+                       default:
+                               return 'csv';
+               }
+       }
+
+       public function page($opt=[]) {
+               require_once(NB_ROOT.'/lib/php/page.php');
+               return new Page(array_merge([
+                       'title' => ($this->title ? $this->title : this::prettyText($this->name)),
+                       'css' => [
+                               'css/*.css',
+                               '/*.css',
+                       ],
+                       'js' => [
+                               'js/*.js',
+                               '/*.js',
+                       ],
+                       'content_type' => Page::content_type_and_set_format(),
+                       'nav' => [
+                               [ (!empty($this) and !empty($this->title)) ? $this->title : 'Home', '/'],
+                               ( (!empty($this->table()) and !empty($this->table()->name)) ? [Page::prettyText($this->table()->name),Page::path().'?table='.urlencode($this->table()->name)] : '' ),
+                               ( Page::p('action') ? Page::prettyText(preg_replace('/^\w+\./','',Page::p('action'))) : '' ),
+                       ],
+               ],$opt));
+       }
+
+       public function ssha512_password($password='',$salt='') {
+               if (empty($password)) return $password;
+               if ($salt === '') $salt = substr(str_shuffle(str_repeat('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',4)),0,4);
+               $password = '{SSHA512}' . base64_encode(hash('sha512', $password . $salt). $salt);
+               return $password;
+       }
+
+       public function ssha_password($password='') {
+               if (empty($password)) return $password;
+               $salt = substr(str_shuffle(str_repeat('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',4)),0,4);
+               $password = '{SSHA}' . base64_encode(sha1( $password.$salt, TRUE ). $salt);
+               return $password;
+       }
+
+       public function cast_text($str) {
+               if ($fct = $this->conf_type('cast_text')) $str = $fct($str);
                return $str;
-  }
+       }
 
-  public function like_nocase() {
-    if ($v = $this->conf_type('like_nocase')) return $v;
+       public function like_nocase() {
+               if ($v = $this->conf_type('like_nocase')) return $v;
                return 'LIKE';
-  }
+       }
 
 } # < Class
 
index 0866b7dbf630b5706d0d5573cb83565a4cd336bb..f2632ae197a55848931adfe669480107439e77c6 100644 (file)
@@ -3,1698 +3,1680 @@ require_once(realpath(dirname(__FILE__).'/../db.php'));
 require_once(realpath(NB_ROOT.'/lib/php/db/field.php'));
 require_once(realpath(NB_ROOT.'/lib/php/out.php'));
 $DB_TABLE_QUERY_ID = 0;
-function __table_define() {
-  define('TABLE_INDENT',NB_EOL ? "\t" : "");
-  define('TABLE_CSV_SEP',Table::p('sep',"\t"));
 
-  if (!defined('TABLE_TEMPLATE')) define('TABLE_TEMPLATE',dirname(__FILE__).'/../../../share/templates');
+// >> Define
+define('TABLE_INDENT',NB_EOL ? "\t" : "");
+define('TABLE_CSV_SEP',Table::p('sep',"\t"));
 
-  if (!defined('DB_HTML_EDIT')) define('DB_HTML_EDIT','Edit');
-  if (!defined('DB_HTML_DELETE')) define('DB_HTML_DELETE','Delete');
+if (!defined('TABLE_TEMPLATE')) define('TABLE_TEMPLATE',dirname(__FILE__).'/../../../share/templates');
 
-  # Create a temporary table when table is a SELECT
-  #if (!defined('DB_TABLE_QUERY_NAME'))
-  define('DB_TABLE_QUERY_NAME','_query_');
-}
+if (!defined('DB_HTML_EDIT')) define('DB_HTML_EDIT','Edit');
+if (!defined('DB_HTML_DELETE')) define('DB_HTML_DELETE','Delete');
+// << Define
+
+# Create a temporary table when table is a SELECT
+#if (!defined('DB_TABLE_QUERY_NAME'))
+define('DB_TABLE_QUERY_NAME','_query_');
 
 Class Table extends nb {
 
-  public $name;
-  public $type; # table, view, sql
-  public $sql;
-  public $replace = []; # to be process by by javascript (id="db-table-replace")
-  public $extras = [];
-  public $rows = []; # array inserted into temporary table
-  public $row_parse_pre; # Function to call in rows()
-  public $row_parse_post; # Function to call in rows()
-  public $update_parse; # Function to call in update, replace, insert
-  public $count;
-  public $engine;
-  public $created;
-  public static $is_admin = true;
-  public $key_preff = '_key_';
+       public $name;
+       public $type; # table, view, sql
+       public $sql;
+       public $replace = []; # to be process by by javascript (id="db-table-replace")
+       public $extras = [];
+       public $rows = []; # array inserted into temporary table
+       public $row_parse_pre; # Function to call in rows()
+       public $row_parse_post; # Function to call in rows()
+       public $update_parse; # Function to call in update, replace, insert
+       public $count;
+       public $engine;
+       public $created;
+       public static $is_admin = true;
+       public $key_preff = '_key_';
 # NB 19.10.17 TODO
-  public $field_preff = '';
-
-  public $fields = [];
-  public $fields_only = [];
-  public $indexes = [];
-
-  public $idtemplate;
-
-  # hidden, sort, ... fields
-  public $show_hidden_params = true;
-  public $show_buttons = true;
-  public $show_url_sort = true;
-  public $show_header = true;
-  public static $params = [
-    'db', 'table', 'limit', 'debug', 'action',
-    'page', 'paged', # wordpress
-  ];
-
-  function __construct($name,$opt=[]) {
-
-    if (!is_scalar($name)) {
-      $opt = $name;
-      #$name = $opt['name'];
-      $name = isset($opt['name']) ? $opt['name'] : '';
-
-    }
-
-    if(!empty($name)) $opt['name'] = $this->name = $name;
-    #debug($opt);
-
-    #unset($opt['db']); bye($opt);
-
-    // Type
-    if (isset($opt['sql'])) {
-      $this->type = 'sql'; unset($opt['type']);
-      $this->sql = $opt['sql']; unset($opt['sql']);
-    }
-
-    // Params
-    if (isset($opt['params'])) {
-      self::$params = $opt['params']; unset($opt['params']);
-    }
-
-    // Db / Connection
-    if (isset($opt['db'])) {
-      $this->db(is_object($opt['db']) ? $opt['db'] : new Db($opt['db']));
-      unset($opt['db']);
-
-    } elseif(isset($GLOBALS['Db'])) {
-      $this->db($GLOBALS['Db']);
-
-    } else {
-      $this->db(new Db());
-
-    }
-
-    // Extras
-    if (isset($opt['extras'])) {
-      $this->add_extras($opt['extras']);
-      unset($opt['extras']);
-    }
-
-    // Add others
-    foreach ($opt as $k => $v) { $this->$k = $v; }
-
-    if (empty($this->db()->limit)) {
-      if ($this->p('paged')) {
-        $this->db()->limit = ($this->db()->limit * $this->p('paged')).','.$this->db()->limit;
-      } elseif ($this->db()->limit=$this->p('limit')) {
-      }
-    }
-
-    if (isset($_GET['rows.header'])) $this->show_header = $_GET['rows.header'];
-    if (isset($_GET['rows.fields'])) $this->fields_only = explode(',',$_GET['rows.fields']);
-
-  }
-
-  public function create_temporary_rows() {
-    // For static rows
-    if(empty($this->rows)) return null;
-    if(!empty($this->rows) and empty($this->type)) $this->type = 'rows';
-
-    $fields = array_keys($this->rows[0]);
-    $sql_names = $this->sql_names($fields);
-
-    $this->db()->conn->query("CREATE ".$this->sql_temporary()." TABLE $this->name ("
-      .join(',',$this->ar_map('"$a text"',$sql_names))
-    .')');
-    $sql = 'INSERT INTO '. $this->sql_name("$this->name")
-      . ' (' . join(',',array_values($sql_names)).')'
-      .' VALUES (' . join(',',$this->ar_map('":$a"',$fields)) . ')'
-    ;
-
-    #debug($sql);
-    if (!($query = $this->db()->conn->prepare($sql))) {
-      $this->err_sql($sql);
-      return false;
-    }
-
-    $this->fields = [];
-    foreach ($fields as $name) {
-      $this->fields[$name] = new Field([
-        'name' => $name,
-        'table' => $this,
-      ]);
-    }
-    $this->_fields = 1;
-
-    foreach ($this->rows as $row) {
-
-      foreach ($row as $k=>$v) {
-        $field = $this->field($k);
-        $field->bindParam($query,$v,":$k");
-      }
-
-      if (!($execute = $query->execute())) {
-        $this->err_sql($sql);
-        return false;
-      }
-
-    }
-
-    return true;
-  }
-
-  private function sql_temporary() {
-    if ($this->db()->type == 'sqlite') return 'TEMP';
-    return 'TEMPORARY';
-  }
-
-  /*
-   * Function create_temporary
-   *
-   * Create temporary if needed
-   *
-   */
-  public function create_temporary() {
-    if (!empty($this->_create_temporary)) return;
-    $this->_create_temporary = true;
-
-    $this->create_temporary_rows();
-
-    // Name, could be a select
-    if (DB_TABLE_QUERY_NAME and stripos($this->name,'SELECT ')===0) {
-      $this->db()->conn->query("CREATE ".$this->sql_temporary()." TABLE ".DB_TABLE_QUERY_NAME." AS $this->name");
-      $this->name = DB_TABLE_QUERY_NAME;
-
-    // Virtual Table
-    } elseif (DB_TABLE_QUERY_NAME and !empty($this->sql)) {
+       public $field_preff = '';
+
+       public $fields = [];
+       public $fields_only = [];
+       public $indexes = [];
+
+       public $idtemplate;
+
+       # hidden, sort, ... fields
+       public $show_hidden_params = true;
+       public $show_buttons = true;
+       public $show_url_sort = true;
+       public $show_header = true;
+       public static $params = [
+               'db', 'table', 'limit', 'debug', 'action',
+               'page', 'paged', # wordpress
+       ];
+
+       function __construct($name,$opt=[]) {
+
+               if (!is_scalar($name)) {
+                       $opt = $name;
+                       #$name = $opt['name'];
+                       $name = isset($opt['name']) ? $opt['name'] : '';
+
+               }
+
+               if(!empty($name)) $opt['name'] = $this->name = $name;
+               #debug($opt);
+
+               #unset($opt['db']); bye($opt);
+
+               // Type
+               if (isset($opt['sql'])) {
+                       $this->type = 'sql'; unset($opt['type']);
+                       $this->sql = $opt['sql']; unset($opt['sql']);
+               }
+
+               // Params
+               if (isset($opt['params'])) {
+                       self::$params = $opt['params']; unset($opt['params']);
+               }
+
+               // Db / Connection
+               if (isset($opt['db'])) {
+                       $this->db(is_object($opt['db']) ? $opt['db'] : new Db($opt['db']));
+                       unset($opt['db']);
+
+               } elseif(isset($GLOBALS['Db'])) {
+                       $this->db($GLOBALS['Db']);
+
+               } else {
+                       $this->db(new Db());
+
+               }
+
+               // Extras
+               if (isset($opt['extras'])) {
+                       $this->add_extras($opt['extras']);
+                       unset($opt['extras']);
+               }
+
+               // Add others
+               foreach ($opt as $k => $v) { $this->$k = $v; }
+
+               if (empty($this->db()->limit)) {
+                       if ($this->p('paged')) {
+                               $this->db()->limit = ($this->db()->limit * $this->p('paged')).','.$this->db()->limit;
+                       } elseif ($this->db()->limit=$this->p('limit')) {
+                       }
+               }
+
+               if (isset($_GET['rows.header'])) $this->show_header = $_GET['rows.header'];
+               if (isset($_GET['rows.fields'])) $this->fields_only = explode(',',$_GET['rows.fields']);
+
+       }
+
+       public function create_temporary_rows() {
+               // For static rows
+               if(empty($this->rows)) return null;
+               if(!empty($this->rows) and empty($this->type)) $this->type = 'rows';
+
+               $fields = array_keys($this->rows[0]);
+               $sql_names = $this->sql_names($fields);
+
+               $this->db()->conn->query("CREATE ".$this->sql_temporary()." TABLE $this->name ("
+                       .join(',',$this->ar_map('"$a text"',$sql_names))
+               .')');
+               $sql = 'INSERT INTO '. $this->sql_name("$this->name")
+                       . ' (' . join(',',array_values($sql_names)).')'
+                       .' VALUES (' . join(',',$this->ar_map('":$a"',$fields)) . ')'
+               ;
+
+               #debug($sql);
+               if (!($query = $this->db()->conn->prepare($sql))) {
+                       $this->err_sql($sql);
+                       return false;
+               }
+
+               $this->fields = [];
+               foreach ($fields as $name) {
+                       $this->fields[$name] = new Field([
+                               'name' => $name,
+                               'table' => $this,
+                       ]);
+               }
+               $this->_fields = 1;
+
+               foreach ($this->rows as $row) {
+
+                       foreach ($row as $k=>$v) {
+                               $field = $this->field($k);
+                               $field->bindParam($query,$v,":$k");
+                       }
+
+                       if (!($execute = $query->execute())) {
+                               $this->err_sql($sql);
+                               return false;
+                       }
+
+               }
+
+               return true;
+       }
+
+       private function sql_temporary() {
+               if ($this->db()->type == 'sqlite') return 'TEMP';
+               return 'TEMPORARY';
+       }
+
+       /*
+        * Function create_temporary
+        *
+        * Create temporary if needed
+        *
+        */
+       public function create_temporary() {
+               if (!empty($this->_create_temporary)) return;
+               $this->_create_temporary = true;
+
+               $this->create_temporary_rows();
+
+               // Name, could be a select
+               if (DB_TABLE_QUERY_NAME and stripos($this->name,'SELECT ')===0) {
+                       $this->db()->conn->query("CREATE ".$this->sql_temporary()." TABLE ".DB_TABLE_QUERY_NAME." AS $this->name");
+                       $this->name = DB_TABLE_QUERY_NAME;
+
+               // Virtual Table
+               } elseif (DB_TABLE_QUERY_NAME and !empty($this->sql)) {
 # NB 29.12.16 table already exists !!!      if ($this->name) $this->name = DB_TABLE_QUERY_NAME;
-      $this->db()->conn->query("CREATE ".$this->sql_temporary()." TABLE $this->name AS $this->sql");
-
-    } elseif (preg_match('/\b(\.import|LOAD DATA|COPY|INSERT|REPLACE|DELETE|TRUNCATE|CREATE|DROP|ALERT)\b/',$this->name)) {
-      bye("Query not Allowed !");
-
-    } else {
-      return false;
-
-    }
-
-    return true;
-  }
-
-  /*
-   * Function db
-   *
-   * return the db object or init it
-   *
-   */
-  public function db($set=null) {
-    static $db = null;
-    #if ($set !== null) debug($set->name);
-    if ($set !== null) $db = $set;
-    return $db;
-  }
-
-  /*
-   * Function create
-   *
-   * return the sql to create the table build internaly
-   *
-   */
-  public function create($from_engine=true,$db_type='') {
-
-    // String replace function
-    $sql_replace_fct = $this->db()->conf_type('table.sql.create');
-    $db_sql_replace_fct = empty($this->db()->sql_replace) ? '' : $this->db()->sql_replace;
-    $sql_replace = function($sql) use ($sql_replace_fct,$db_sql_replace_fct) {
-      if ($db_sql_replace_fct) $sql = $db_sql_replace_fct($sql);
-      return $sql_replace_fct ? $sql_replace_fct($sql,$this) : $sql;
-    };
-
-    if ($from_engine) return $sql_replace($this->sql());
-
-    if ($this->type() == 'view') {
-      return $sql_replace('CREATE VIEW '.$this->sql_name().' AS '.preg_replace('/^CREATE\s+.*?\s+AS\s+.*?SELECT/i','SELECT',$this->sql()));
-    }
-
-    $indexes = [];
-    foreach ($this->indexes() as $i) {
-      if (!empty($i['unique']) or !empty($i['key'])) continue;
-      $indexes[] = 'CREATE INDEX '.$i['name'].' ON '.$this->sql_name().' ('.$i['field'].')';
-    }
-
-    # Get all fields
-    $fields = [];
-    foreach ($this->fields() as $f) {
-      if (!empty($f->extras)) continue;
-      $fields[] = $f;
-    }
-
-    $type = $this->db()->type;
-    if (!empty($db_type)) $this->db()->type = $db_type;
-
-    // Specific function for fields if return something use it instead of default
-    $_create_fct = $this->db()->conf_type('field.create',false);
-    $_create = function(&$field) use ($_create_fct) {
-      if ($_create_fct and ($sql=$_create_fct($field))) return $sql;
-
-      // Default
-      return $field->sql_name().' '.$field->type
-        .($field->null ? '' : ' NOT NULL')
-        .($field->default !== null ? ' DEFAULT '.$field->quote($field->default,true) : '')
-        .($field->key ? ' PRIMARY KEY' : '')
-        .($field->uniq ? ' UNIQUE' : '')
-      ;
-    };
-
-    $sql = 'CREATE '.strtoupper($this->type()).' '.$this->sql_name()
-      .' ('
-      .join(",",array_map(function($f) use ($_create) {return $_create($f);},$fields))
-      # done at the end for primary keys .')'
-    ;
-
-    // Handle multiple primary keys syntaxe
-    if (substr_count(strtoupper($sql),'PRIMARY KEY')>1) {
-      $sql = str_ireplace(' PRIMARY KEY','',$sql)
-        .', PRIMARY KEY ('.join(',',array_map(function($f){return $f->sql_name();},$this->fields_keys())).')'
-      ;
-    }
-
-    $this->db()->type = $type;
-    return $sql_replace($sql.')'.($indexes ? ';'.join(';',$indexes) : ''));
-  }
-
-  /*
-   * Function indexes
-   *
-   * return indexes
-   *
-   */
-  public function indexes() {
-    if (!isset($this->indexes)) {
-      $sql = $this->db()->conf_type('table.sql.index');
-      $fct = '';
-
-      if (is_array($sql)) list($sql,$fct) = (count($sql)==1 ? [$sql[0],null] : $sql);
-      if (!$sql) return [];
-
-      $sql = str_replace('<T.NAME>',$this->name,$sql);
-      $sql = str_replace('<D.NAME>',$this->db()->name,$sql);
-      $st = $this->db()->conn->prepare($sql);
-      $st->execute();
-      $this->indexes = [];
-      while ($row = $st->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_NEXT)) {
-
-        if (!$fct) $this->indexes[] = $row;
-        elseif ($r = $fct($row)) $this->indexes[] = $r;
-
-      }
-    }
-    return $this->indexes;
-  }
-
-  /*
-   * Function sql
-   *
-   * return the sql used create the table
-   *
-   */
-  public function sql() {
-    if (isset($this->sql)) return $this->sql;
-
-    if (!preg_match('/^[\w_-]+$/',$this->name) ) {
-      $this->sql = $this->name;
-      return $this->sql;
-    }
-
-    #$sql = str_replace('<T.NAME>',$this->name,$this->db()->conf_type('table.sql',true));
-    $sql = $this->unvar($this->db()->conf_type('table.sql',true));
-
-    # Noise before CREATE like MySql
-    $this->sql = explode('\0',$this->db()->row($sql,'\0'));
-    if (count($this->sql) > 1) {
-      $this->sql = $this->sql[1];
-    } else {
-      $this->sql = $this->sql[0];
-    }
-
-    # Remove comments
-    $this->sql = join(' ',preg_grep('/^ *--/',explode("\n",$this->sql),true));
-
-    # Delete new line and trim for line output
-    $this->sql = trim(preg_replace('/\s\s+/',' ',$this->sql));
-
-    if (self::p('ansi')) {
-      $this->sql = preg_replace("/\s*COLLATE NOCASE/i",'',$this->sql);
-    }
-
-    #bye($this->sql);
-    return $this->sql;
-  }
-
-  public function field($name) { return $this->fields($name); }
-# NB 14.12.17   public function field_del($name) { unset($this->fields[$name]); }
+                       $this->db()->conn->query("CREATE ".$this->sql_temporary()." TABLE $this->name AS $this->sql");
+
+               } elseif (preg_match('/\b(\.import|LOAD DATA|COPY|INSERT|REPLACE|DELETE|TRUNCATE|CREATE|DROP|ALERT)\b/',$this->name)) {
+                       bye("Query not Allowed !");
+
+               } else {
+                       return false;
+
+               }
+
+               return true;
+       }
+
+       /*
+        * Function db
+        *
+        * return the db object or init it
+        *
+        */
+       public function db($set=null) {
+               static $db = null;
+               #if ($set !== null) debug($set->name);
+               if ($set !== null) $db = $set;
+               return $db;
+       }
+
+       /*
+        * Function create
+        *
+        * return the sql to create the table build internaly
+        *
+        */
+       public function create($from_engine=true,$db_type='') {
+
+               // String replace function
+               $sql_replace_fct = $this->db()->conf_type('table.sql.create');
+               $db_sql_replace_fct = empty($this->db()->sql_replace) ? '' : $this->db()->sql_replace;
+               $sql_replace = function($sql) use ($sql_replace_fct,$db_sql_replace_fct) {
+                       if ($db_sql_replace_fct) $sql = $db_sql_replace_fct($sql);
+                       return $sql_replace_fct ? $sql_replace_fct($sql,$this) : $sql;
+               };
+
+               if ($from_engine) return $sql_replace($this->sql());
+
+               if ($this->type() == 'view') {
+                       return $sql_replace('CREATE VIEW '.$this->sql_name().' AS '.preg_replace('/^CREATE\s+.*?\s+AS\s+.*?SELECT/i','SELECT',$this->sql()));
+               }
+
+               $indexes = [];
+               foreach ($this->indexes() as $i) {
+                       if (!empty($i['unique']) or !empty($i['key'])) continue;
+                       $indexes[] = 'CREATE INDEX '.$i['name'].' ON '.$this->sql_name().' ('.$i['field'].')';
+               }
+
+               # Get all fields
+               $fields = [];
+               foreach ($this->fields() as $f) {
+                       if (!empty($f->extras)) continue;
+                       $fields[] = $f;
+               }
+
+               $type = $this->db()->type;
+               if (!empty($db_type)) $this->db()->type = $db_type;
+
+               // Specific function for fields if return something use it instead of default
+               $_create_fct = $this->db()->conf_type('field.create',false);
+               $_create = function(&$field) use ($_create_fct) {
+                       if ($_create_fct and ($sql=$_create_fct($field))) return $sql;
+
+                       // Default
+                       return $field->sql_name().' '.$field->type
+                               .($field->null ? '' : ' NOT NULL')
+                               .($field->default !== null ? ' DEFAULT '.$field->quote($field->default,true) : '')
+                               .($field->key ? ' PRIMARY KEY' : '')
+                               .($field->uniq ? ' UNIQUE' : '')
+                       ;
+               };
+
+               $sql = 'CREATE '.strtoupper($this->type()).' '.$this->sql_name()
+                       .' ('
+                       .join(",",array_map(function($f) use ($_create) {return $_create($f);},$fields))
+                       # done at the end for primary keys .')'
+               ;
+
+               // Handle multiple primary keys syntaxe
+               if (substr_count(strtoupper($sql),'PRIMARY KEY')>1) {
+                       $sql = str_ireplace(' PRIMARY KEY','',$sql)
+                               .', PRIMARY KEY ('.join(',',array_map(function($f){return $f->sql_name();},$this->fields_keys())).')'
+                       ;
+               }
+
+               $this->db()->type = $type;
+               return $sql_replace($sql.')'.($indexes ? ';'.join(';',$indexes) : ''));
+       }
+
+       /*
+        * Function indexes
+        *
+        * return indexes
+        *
+        */
+       public function indexes() {
+               if (!isset($this->indexes)) {
+                       $sql = $this->db()->conf_type('table.sql.index');
+                       $fct = '';
+
+                       if (is_array($sql)) list($sql,$fct) = (count($sql)==1 ? [$sql[0],null] : $sql);
+                       if (!$sql) return [];
+
+                       $sql = str_replace('<T.NAME>',$this->name,$sql);
+                       $sql = str_replace('<D.NAME>',$this->db()->name,$sql);
+                       $st = $this->db()->conn->prepare($sql);
+                       $st->execute();
+                       $this->indexes = [];
+                       while ($row = $st->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_NEXT)) {
+
+                               if (!$fct) $this->indexes[] = $row;
+                               elseif ($r = $fct($row)) $this->indexes[] = $r;
 
-  /*
-   * 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
-   */
-  public function fields($name=null) {
+                       }
+               }
+               return $this->indexes;
+       }
 
-    $this->create_temporary();
+       /*
+        * Function sql
+        *
+        * return the sql used create the table
+        *
+        */
+       public function sql() {
+               if (isset($this->sql)) return $this->sql;
+
+               if (!preg_match('/^[\w_-]+$/',$this->name) ) {
+                       $this->sql = $this->name;
+                       return $this->sql;
+               }
 
-    if (!isset($this->_fields)) {
-      $this->_fields = true;
+               #$sql = str_replace('<T.NAME>',$this->name,$this->db()->conf_type('table.sql',true));
+               $sql = $this->unvar($this->db()->conf_type('table.sql',true));
 
-      # Extras fields at the end
-      $save_fields = $this->fields;
-      $this->fields = [];
+               # Noise before CREATE like MySql
+               $this->sql = explode('\0',$this->db()->row($sql,'\0'));
+               if (count($this->sql) > 1) {
+                       $this->sql = $this->sql[1];
+               } else {
+                       $this->sql = $this->sql[0];
+               }
+
+               # Remove comments
+               $this->sql = join(' ',preg_grep('/^ *--/',explode("\n",$this->sql),true));
+
+               # Delete new line and trim for line output
+               $this->sql = trim(preg_replace('/\s\s+/',' ',$this->sql));
+
+               if (self::p('ansi')) {
+                       $this->sql = preg_replace("/\s*COLLATE NOCASE/i",'',$this->sql);
+               }
+
+               #bye($this->sql);
+               return $this->sql;
+       }
 
-      $conf = $this->unvar($this->db()->conf_type('table.fields',true));
-      if (is_scalar($conf)) $conf = ['sql'=>$conf];
-      # NB 25.09.17: dirty fixed for sqlite4 attache db 
-      $conf['sql'] = preg_replace("/^PRAGMA table_info\('([^'\.]+)\./","PRAGMA ".'$1'.".table_info('",$conf['sql']);
-      $rows = $this->db()->conn->query($conf['sql']);
+       public function field($name) { return $this->fields($name); }
+# NB 14.12.17   public function field_del($name) { unset($this->fields[$name]); }
 
-      if (!is_object($rows)) {
-        $this->bye("Can't get fields from table $this->name ");
-      }
+       /*
+        * 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
+        */
+       public function fields($name=null) {
+
+               $this->create_temporary();
+
+               if (!isset($this->_fields)) {
+                       $this->_fields = true;
+
+                       # Extras fields at the end
+                       $save_fields = $this->fields;
+                       $this->fields = [];
+
+                       $conf = $this->unvar($this->db()->conf_type('table.fields',true));
+                       if (is_scalar($conf)) $conf = ['sql'=>$conf];
+                       # NB 25.09.17: dirty fixed for sqlite4 attache db 
+                       $conf['sql'] = preg_replace("/^PRAGMA table_info\('([^'\.]+)\./","PRAGMA ".'$1'.".table_info('",$conf['sql']);
+                       $rows = $this->db()->conn->query($conf['sql']);
+
+                       if (!is_object($rows)) {
+                               $this->bye("Can't get fields from table $this->name ");
+                       }
 
-      $rows->setFetchMode(PDO::FETCH_ASSOC);
+                       $rows->setFetchMode(PDO::FETCH_ASSOC);
 
-      // Get other indexes
-      $indexes = [];
-      foreach ($this->indexes() as $i) {
-        if (empty($i['unique']) and empty($i['key'])) $indexes[$i['field']] = 1;
-      }
+                       // Get other indexes
+                       $indexes = [];
+                       foreach ($this->indexes() as $i) {
+                               if (empty($i['unique']) and empty($i['key'])) $indexes[$i['field']] = 1;
+                       }
 
-      $count = 0;
-      foreach ($rows as $row) {
+                       $count = 0;
+                       foreach ($rows as $row) {
 
-        $count++;
-        $row = array_change_key_case($row,CASE_LOWER);
+                               $count++;
+                               $row = array_change_key_case($row,CASE_LOWER);
 
-        // From config
-        $row['this'] = $this; # for use
-        if (isset($conf['map'])) {
+                               // From config
+                               $row['this'] = $this; # for use
+                               if (isset($conf['map'])) {
 
-          foreach ($conf['map'] as $from => $to) {
-            if (!isset($row[$from])) continue;
+                                       foreach ($conf['map'] as $from => $to) {
+                                               if (!isset($row[$from])) continue;
 
-            $row[$to] = $row[$from];
-            unset ($row[$from]);
-          }
+                                               $row[$to] = $row[$from];
+                                               unset ($row[$from]);
+                                       }
 
-        }
+                               }
 
-        if (isset($conf['fct'])) $conf['fct']($row);
+                               if (isset($conf['fct'])) $conf['fct']($row);
 
-        $field = [
-          'table'         => $this,
-          'name'          => $row['name'],
-          'type'          => strtolower($row['type']),
-          'key'           => (preg_match('/^(f.*|no|0)?\s*$/i',$row['key']) ? 0 : 1),
-          'index'         => (empty($indexes[$row['name']]) ? 0 : $indexes[$row['name']]),
-          'null'          => (preg_match('/^(f.*|no|0)?\s*$/i',$row['null']) ? 0 : 1),
-          'extra'         => (isset($row['extra']) ? $row['extra'] : null), # !!! nothing todo with array $extra, this info from the sql server
-          'autoincrement' => (isset($row['autoincrement']) ? $row['autoincrement'] : 0),
-        ];
+                               $field = [
+                                       'table'         => $this,
+                                       'name'          => $row['name'],
+                                       'type'          => strtolower($row['type']),
+                                       'key'           => (preg_match('/^(f.*|no|0)?\s*$/i',$row['key']) ? 0 : 1),
+                                       'index'         => (empty($indexes[$row['name']]) ? 0 : $indexes[$row['name']]),
+                                       'null'          => (preg_match('/^(f.*|no|0)?\s*$/i',$row['null']) ? 0 : 1),
+                                       'extra'         => (isset($row['extra']) ? $row['extra'] : null), # !!! nothing todo with array $extra, this info from the sql server
+                                       'autoincrement' => (isset($row['autoincrement']) ? $row['autoincrement'] : 0),
+                               ];
 
-        if (isset($row['uniq'])) $field['uniq'] = $row['uniq'];
-        if (isset($row['default'])) $field['default'] = $row['default'];
+                               if (isset($row['uniq'])) $field['uniq'] = $row['uniq'];
+                               if (isset($row['default'])) $field['default'] = $row['default'];
 
-        $this->fields[$field['name']] = new Field($field);
-        $this->fields[$field['name']]->size = $this->fields[$field['name']]->size();
+                               $this->fields[$field['name']] = new Field($field);
+                               $this->fields[$field['name']]->size = $this->fields[$field['name']]->size();
 
-      }
+                       }
 
-      # Extras fields at the end
-      $this->fields = array_merge($this->fields,$save_fields);
-      #if (empty($this->fields)) bye("Table `".$this->name."` does not exists");
+                       # Extras fields at the end
+                       $this->fields = array_merge($this->fields,$save_fields);
+                       #if (empty($this->fields)) bye("Table `".$this->name."` does not exists");
 
-    } # < $this->fields
+               } # < $this->fields
 
 #bye($this->fields);
-    if ($name !== null ) {
-      if (!isset($this->fields[$name])) return null;
-      return $this->fields[$name];
-    }
-
-    return $this->fields;
-  }
-
-  public function url_keys($values=null,$params=[],$preff='?',$sep='&amp;') {
-    if ($values === null) $values = $this->p();
-    $url = is_array($params) ? $params : [$params];
-
-    $keys = $this->fields_keys($others);
-    if (empty($keys)) $keys = $others;
-
-    foreach ($keys as $name => $field) {
-      if (isset($values[$name]))
-        $url[] = $this->field_preff.$name . '=' .urlencode($values[$name])
-      ;
-    }
-
-    foreach (self::$params as $p) if ($v=self::p($p)) $url[] = $p.'='.urlencode($v);
-    return $url ? $preff.join($sep,$url) : '';
-  }
-
-  public function fields_keys_values($values) {
-    $keys = $this->fields_keys();
-    if (empty($keys)) $keys = $this->fields();
-
-    $ret = [];
-    foreach ($keys as $name => $field) {
-      if (isset($values[$name]))
-        $ret[] = $values[$name];
-      ;
-    }
-    return $ret;
-  }
-
-  public function fields_keys(&$others=[]) {
-
-    $fields_keys = [];
-
-    foreach ($this->fields() as $name => $f) {
-      if ($f->key) {
-        $fields_keys[$name] = $f;
-      } else {
-        $others[$name] = $f;
-      }
-    }
-
-    return $fields_keys;
-
-  }
-
-  public static function params2hash($keys) {
-      $params = [];
-      foreach ($keys as $k) {
-        $params[$k] = self::p($k);
-        if (!isset($params[$k]) or (string)$params[$k] === '') unset($params[$k]);
-      }
-      return $params;
-  }
-
-  public static function form_hidden($ignore=[],$params=null) {
-    $h = '';
-    if (!isset($params)) {
-      $params = self::params2hash(self::$params);
-    }
+               if ($name !== null ) {
+                       if (!isset($this->fields[$name])) return null;
+                       return $this->fields[$name];
+               }
+
+               return $this->fields;
+       }
+
+       public function url_keys($values=null,$params=[],$preff='?',$sep='&amp;') {
+               if ($values === null) $values = $this->p();
+               $url = is_array($params) ? $params : [$params];
+
+               $keys = $this->fields_keys($others);
+               if (empty($keys)) $keys = $others;
+
+               foreach ($keys as $name => $field) {
+                       if (isset($values[$name]))
+                               $url[] = $this->field_preff.$name . '=' .urlencode($values[$name])
+                       ;
+               }
+
+               foreach (self::$params as $p) if ($v=self::p($p)) $url[] = $p.'='.urlencode($v);
+               return $url ? $preff.join($sep,$url) : '';
+       }
+
+       public function fields_keys_values($values) {
+               $keys = $this->fields_keys();
+               if (empty($keys)) $keys = $this->fields();
+
+               $ret = [];
+               foreach ($keys as $name => $field) {
+                       if (isset($values[$name]))
+                               $ret[] = $values[$name];
+                       ;
+               }
+               return $ret;
+       }
+
+       public function fields_keys(&$others=[]) {
+
+               $fields_keys = [];
+
+               foreach ($this->fields() as $name => $f) {
+                       if ($f->key) {
+                               $fields_keys[$name] = $f;
+                       } else {
+                               $others[$name] = $f;
+                       }
+               }
+
+               return $fields_keys;
+
+       }
+
+       public static function params2hash($keys) {
+                       $params = [];
+                       foreach ($keys as $k) {
+                               $params[$k] = self::p($k);
+                               if (!isset($params[$k]) or (string)$params[$k] === '') unset($params[$k]);
+                       }
+                       return $params;
+       }
+
+       public static function form_hidden($ignore=[],$params=null) {
+               $h = '';
+               if (!isset($params)) {
+                       $params = self::params2hash(self::$params);
+               }
 
                #debug([$params,array_diff($params,$ignore)]);
 # NB 07.01.18     foreach (array_diff($params,$ignore) as $k=>$v) {
-    foreach ($params as $k=>$v) {
+               foreach ($params as $k=>$v) {
                        if (!empty($ignore) and in_array($k,$ignore)) continue;
-      if (isset($v) or $k=='action') {
-        if (self::p('debug')) $h .= "<label>$k</label>";
-        $h .= '<input type="'.(self::p('debug')?'text':'hidden').'" name="'.$k.'" value="'.$v.'"/>'.NB_EOL;
-      }
-    }
-
-    return $h;
-  }
-
-  public function html_add($values = null,$form_action='?') {
-    return html_edit($values,$form_action,true);
-  }
-
-  public function sql_edit($values = null,&$add=false) {
-    $where = $this->where($this->fields(),$values);
-    if (empty($where)) {
-      $where = ' WHERE 1=0';
-      $add = true;
-    } else {
-      $where .= " LIMIT 1";
-    }
-
-    $sql = "SELECT *" . $this->select_extras();
-    $sql .= " FROM ".$this->sql_name().$where;
-    if ($this->type == 'sql' and !empty($this->sql)) $sql = $this->sql.$where;
-    $this->debug(preg_replace('/(,|FROM|WHERE|HAVING|GROUP|ORDER)/i',"\n\\1",$sql),1);
-
-    return $sql;
-  }
-
-  public function html_edit($values = null,$form_action='?',$add=false) {
-    if ($values === null) $values = $this->p();
-    if (!is_array($values)) $values = [$values];
+                       if (isset($v) or $k=='action') {
+                               if (self::p('debug')) $h .= "<label>$k</label>";
+                               $h .= '<input type="'.(self::p('debug')?'text':'hidden').'" name="'.$k.'" value="'.$v.'"/>'.NB_EOL;
+                       }
+               }
+
+               return $h;
+       }
+
+       public function html_add($values = null,$form_action='?') {
+               return html_edit($values,$form_action,true);
+       }
+
+       public function sql_edit($values = null,&$add=false) {
+               $where = $this->where($this->fields(),$values);
+               if (empty($where)) {
+                       $where = ' WHERE 1=0';
+                       $add = true;
+               } else {
+                       $where .= " LIMIT 1";
+               }
+
+               $sql = "SELECT *" . $this->select_extras();
+               $sql .= " FROM ".$this->sql_name().$where;
+               if ($this->type == 'sql' and !empty($this->sql)) $sql = $this->sql.$where;
+               $this->debug(preg_replace('/(,|FROM|WHERE|HAVING|GROUP|ORDER)/i',"\n\\1",$sql),1);
+
+               return $sql;
+       }
+
+       public function html_edit($values = null,$form_action='?',$add=false) {
+               if ($values === null) $values = $this->p();
+               if (!is_array($values)) $values = [$values];
 
 # NB 23.11.17     $fields = $this->fields();
 # NB 23.11.17     $keys = $this->fields_keys();
 
-    $sql = $this->sql_edit($values,$add);
-
-    $st = $this->db()->conn->prepare($sql);
-    $st->execute();
-
-    // Params
-    $form_hidden = '';
-    $url_params = [
-      'referer' => (!empty($_SERVER['HTTP_REFERER']) ? urlencode($_SERVER['HTTP_REFERER']) : ''),
-    ];
-    if ($this->show_hidden_params and !empty(self::$params)) {
-      $ignore = ['limit'];
-
-      $form_hidden = ''
-        .self::form_hidden($ignore,array_merge($this->params2hash(self::$params),[
-          'action' => ($add ? 'insert' : 'update'),
-          'referer' => (!empty($_SERVER['HTTP_REFERER']) ? urlencode($_SERVER['HTTP_REFERER']) : ''),
-        ]))
-      ;
-
-      foreach (array_diff(self::$params,$ignore) as $p) {
-        if (!($v = self::p($p))) continue;
-        $url_params[$p] = $v;
-      }
-
-      $url_params['action'] = ($add ? 'insert' : 'update');
-
-    } else {
-      $form_hidden = (!empty($_SERVER['HTTP_REFERER']) ? '<input type="hidden" name="referer" value="'.urlencode($_SERVER['HTTP_REFERER']).'" />' : '');
-
-    }
-
-    #debug($form_hidden);
-    if ($url_params) {
-      $flat = [];
-      foreach ($url_params as $k=>$v) {
-        if ((string)$v === '') continue;
-        $flat[] = $k . '=' . urlencode($v);
-      }
-      if (NB_P_GET) {
-        $form_action .= ( strpos('?',$form_action) === false ? '?' : '' ) . join('&amp;',$flat); 
-        $form_hidden = '';
-      }
-    }
-
-    // Form
-    echo '<form class="db edit form-table" method="post" action="'.$form_action.'">'.NB_EOL;
-    echo '<div class="fields">'.NB_EOL;
-    $count = 0;
-    if ( $add or ($row = $st->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_NEXT))) {
-
-      if (!empty($row)) $this->db()->table_row_decrypt($this,$row);
-      $count ++;
-
-      foreach ($this->fields() as $name => $field) {
+               $sql = $this->sql_edit($values,$add);
+
+               $st = $this->db()->conn->prepare($sql);
+               $st->execute();
+
+               // Params
+               $form_hidden = '';
+               $url_params = [
+                       'referer' => (!empty($_SERVER['HTTP_REFERER']) ? urlencode($_SERVER['HTTP_REFERER']) : ''),
+               ];
+               if ($this->show_hidden_params and !empty(self::$params)) {
+                       $ignore = ['limit'];
+
+                       $form_hidden = ''
+                               .self::form_hidden($ignore,array_merge($this->params2hash(self::$params),[
+                                       'action' => ($add ? 'insert' : 'update'),
+                                       'referer' => (!empty($_SERVER['HTTP_REFERER']) ? urlencode($_SERVER['HTTP_REFERER']) : ''),
+                               ]))
+                       ;
+
+                       foreach (array_diff(self::$params,$ignore) as $p) {
+                               if (!($v = self::p($p))) continue;
+                               $url_params[$p] = $v;
+                       }
+
+                       $url_params['action'] = ($add ? 'insert' : 'update');
+
+               } else {
+                       $form_hidden = (!empty($_SERVER['HTTP_REFERER']) ? '<input type="hidden" name="referer" value="'.urlencode($_SERVER['HTTP_REFERER']).'" />' : '');
+
+               }
+
+               #debug($form_hidden);
+               if ($url_params) {
+                       $flat = [];
+                       foreach ($url_params as $k=>$v) {
+                               if ((string)$v === '') continue;
+                               $flat[] = $k . '=' . urlencode($v);
+                       }
+                       if (NB_P_GET) {
+                               $form_action .= ( strpos('?',$form_action) === false ? '?' : '' ) . join('&amp;',$flat); 
+                               $form_hidden = '';
+                       }
+               }
+
+               // Form
+               echo '<form class="db edit form-table" method="post" action="'.$form_action.'">'.NB_EOL;
+               echo '<div class="fields">'.NB_EOL;
+               $count = 0;
+               if ( $add or ($row = $st->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_NEXT))) {
+
+                       if (!empty($row)) $this->db()->table_row_decrypt($this,$row);
+                       $count ++;
+
+                       foreach ($this->fields() as $name => $field) {
 
 # NB 08.01.18         if ($add and !preg_match('/^(null|.*\(.*)?$/',strtolower($field->default))) {
 # NB 08.01.18           $row[$name] = $field->default;
                                if ($add) {
-          $row[$name] = $field->default2str($field->default);
+                                       $row[$name] = $field->default2str($field->default);
 
-        } elseif(!isset($row[$name])) {
-          $row[$name] = '';
+                               } elseif(!isset($row[$name])) {
+                                       $row[$name] = '';
 
-        }
+                               }
 
-        if (!$add and $field->key) {
-          echo '<input name="'.$this->key_preff.$name.'" value="'.$row[$name].'" type="hidden" />'.NB_EOL;
-        }
-        echo $field->html_edit($row[$name]);
-      }
+                               if (!$add and $field->key) {
+                                       echo '<input name="'.$this->key_preff.$name.'" value="'.$row[$name].'" type="hidden" />'.NB_EOL;
+                               }
+                               echo $field->html_edit($row[$name]);
+                       }
 
-    }
-    echo '</div>'.NB_EOL; # < fields
+               }
+               echo '</div>'.NB_EOL; # < fields
 
-    echo ''
-      .'<div class="db buttons">'
-      .( empty($_SERVER['HTTP_REFERER']) ? '' : '<input type="button" onclick="document.location=document.referrer" value="Cancel" />')
-      .'<input type="reset" />'
-      .'<input type="submit" />'
-      .'</div>'.NB_EOL
-    ;
+               echo ''
+                       .'<div class="db buttons">'
+                       .( empty($_SERVER['HTTP_REFERER']) ? '' : '<input type="button" onclick="document.location=document.referrer" value="Cancel" />')
+                       .'<input type="reset" />'
+                       .'<input type="submit" />'
+                       .'</div>'.NB_EOL
+               ;
 
-    echo $form_hidden.'</form>'.NB_EOL;
+               echo $form_hidden.'</form>'.NB_EOL;
 
-  }
+       }
 
-  public function url_list($k='',$v='') {
+       public function url_list($k='',$v='') {
 
-    $params = [];
-    $fields = ($this->p('action') == 'delete') ? [] : $this->fields();
+               $params = [];
+               $fields = ($this->p('action') == 'delete') ? [] : $this->fields();
 
-    foreach ( array_diff( array_merge(self::$params,array_keys($fields)), ['action'] ) as $f) {
+               foreach ( array_diff( array_merge(self::$params,array_keys($fields)), ['action'] ) as $f) {
 
-      if (strcmp($this->p($f,''),'')==0) continue;
-      $params[$f] = $this->p($f);
+                       if (strcmp($this->p($f,''),'')==0) continue;
+                       $params[$f] = $this->p($f);
 
-    }
+               }
 
-    if ($k) {
+               if ($k) {
 
-      if (strcmp($v,'')==0) {
-        unset($params[$k]);
-      } else {
-        $params[$k] = $v;
-      }
+                       if (strcmp($v,'')==0) {
+                               unset($params[$k]);
+                       } else {
+                               $params[$k] = $v;
+                       }
 
-    }
+               }
 
-    $flat = [];
-    foreach ($params as $k=>$v) { $flat[] = $k.'='.urlencode($v); }
-    return $flat ? '?'. join('&amp;',$flat) : ''; 
+               $flat = [];
+               foreach ($params as $k=>$v) { $flat[] = $k.'='.urlencode($v); }
+               return $flat ? '?'. join('&amp;',$flat) : ''; 
 
-  }
+       }
 
-  public function url_sort($name) {
+       public function url_sort($name) {
 
-    if (!$this->show_url_sort or !($f=$this->field($name)) or !empty($f->dyn) or $f->is_encrypt()) return self::prettyText($name);
-    #debug($f);
+               if (!$this->show_url_sort or !($f=$this->field($name)) or !empty($f->dyn) or $f->is_encrypt()) return self::prettyText($name);
+               #debug($f);
 
-    # See: http://dev.w3.org/html5/html-author/charref
-    $html = '';
+               # See: http://dev.w3.org/html5/html-author/charref
+               $html = '';
 
                $title = $this->prettyText($name).': ';
 
-    # Asc
-    $sel = ( $this->p('orderby')=="$name asc") ? " sel" : "";
-    $html .= '<a title="'.$title.'first In (asc)" class="sort asc'.$sel.'" href="'.$this->url_list('orderby',"$name asc").'">'
-      .'<span class="asc">&darr;</span>'
-    .'</a>';
-    #$html .= '&nbsp;';
+               # Asc
+               $sel = ( $this->p('orderby')=="$name asc") ? " sel" : "";
+               $html .= '<a title="'.$title.'first In (asc)" class="sort asc'.$sel.'" href="'.$this->url_list('orderby',"$name asc").'">'
+                       .'<span class="asc">&darr;</span>'
+               .'</a>';
+               #$html .= '&nbsp;';
 
-    $html .= '<span class="name">'.$this->prettyText($name).'</span>';
+               $html .= '<span class="name">'.$this->prettyText($name).'</span>';
 
-    #$html .= '&nbsp;';
+               #$html .= '&nbsp;';
 
-    # Desc
-    $sel = ( $this->p('orderby')=="$name desc") ? " sel" : "";
-    $html .= '<a title="'.$title.'last In (desc)" class="sort desc'.$sel.'" href="'.$this->url_list('orderby',"$name desc").'">'
-      .'<span class="desc">&uarr;</span>'
-    .'</a>';
+               # Desc
+               $sel = ( $this->p('orderby')=="$name desc") ? " sel" : "";
+               $html .= '<a title="'.$title.'last In (desc)" class="sort desc'.$sel.'" href="'.$this->url_list('orderby',"$name desc").'">'
+                       .'<span class="desc">&uarr;</span>'
+               .'</a>';
 
-    return $html;
+               return $html;
 
-  }
+       }
 
-  public function nav($count,$tot,$limit) {
+       public function nav($count,$tot,$limit) {
 
-    $html = '';
+               $html = '';
 
-    if ($count<$tot) {
-      list($x,$y) = strpos($limit,',')!==false
-        ? preg_split('/\s*,\s*/',$limit)
-        : [0,$limit]
-      ;
+               if ($count<$tot) {
+                       list($x,$y) = strpos($limit,',')!==false
+                               ? preg_split('/\s*,\s*/',$limit)
+                               : [0,$limit]
+                       ;
 
-      $prev = $x - $y;
-      $next = $x + $y;
+                       $prev = $x - $y;
+                       $next = $x + $y;
 
-      $this->debug("x=$x limit=$y prev=$prev next=$next tot=$tot",1);
+                       $this->debug("x=$x limit=$y prev=$prev next=$next tot=$tot",1);
 
-    } else {
-      $x = 0;
-      $y = $tot;
-      $prev = -1;
-      $next = 999999;
-    }
+               } else {
+                       $x = 0;
+                       $y = $tot;
+                       $prev = -1;
+                       $next = 999999;
+               }
 
-    if ($prev>=0) $html .= '<span class="prev"><a href="'.$this->url_list('limit',preg_replace('/^0,/','',"$prev,$y")).'">&lt;&lt;</a></span>&nbsp;';
+               if ($prev>=0) $html .= '<span class="prev"><a href="'.$this->url_list('limit',preg_replace('/^0,/','',"$prev,$y")).'">&lt;&lt;</a></span>&nbsp;';
 
-    $html .= '<span class="count">'.($tot ? ($x+1) : 0).' - '.( $count<($x+$y) ? $count : ($x+$y) ).' / '.$tot.' results</span>';
+               $html .= '<span class="count">'.($tot ? ($x+1) : 0).' - '.( $count<($x+$y) ? $count : ($x+$y) ).' / '.$tot.' results</span>';
 
-    if ($next<$tot) $html .= '&nbsp;<span class="prev"><a href="'.$this->url_list('limit',"$next,$y").'">&gt;&gt;</a></span>';
+               if ($next<$tot) $html .= '&nbsp;<span class="prev"><a href="'.$this->url_list('limit',"$next,$y").'">&gt;&gt;</a></span>';
 
-    return $html;
+               return $html;
 
-  }
+       }
 
-  public function where($fields,$hvalues,$need_all_values=false) {
+       public function where($fields,$hvalues,$need_all_values=false) {
 
-    // Construct where
-    $where = [];
-    foreach ($fields as $k => $field) {
-      if (!isset($hvalues[$k])) {
-        if ($need_all_values) return null;
-        continue;
-      }
-      $where[] = $field->sql_name() . '=' . $field->quote($hvalues[$k]);
-    }
+               // Construct where
+               $where = [];
+               foreach ($fields as $k => $field) {
+                       if (!isset($hvalues[$k])) {
+                               if ($need_all_values) return null;
+                               continue;
+                       }
+                       $where[] = $field->sql_name() . '=' . $field->quote($hvalues[$k]);
+               }
 
-    return empty($where) ? '' : ' WHERE ' . join(' AND ',$where);
+               return empty($where) ? '' : ' WHERE ' . join(' AND ',$where);
 
-  }
+       }
 
-  public function where_criterias($values,$logic='') {
-    $having = $where = [];
-    if (empty($logic)) $logic = 'AND';
+       public function where_criterias($values,$logic='') {
+               $having = $where = [];
+               if (empty($logic)) $logic = 'AND';
 
-    $regexp = $this->db()->conf_type('regexp');
-    if (empty($regexp)) $regexp = 'REGEXP';
+               $regexp = $this->db()->conf_type('regexp');
+               if (empty($regexp)) $regexp = 'REGEXP';
 
-    foreach ($this->fields() as $k => $field) {
+               foreach ($this->fields() as $k => $field) {
 
-      // No empty values
-      $v = isset($values[$k]) ? $values[$k] : null;
-      if (strcmp($v,'')==0 or $v=='!' or $v=='~') continue;
+                       // No empty values
+                       $v = isset($values[$k]) ? $values[$k] : null;
+                       if (strcmp($v,'')==0 or $v=='!' or $v=='~') continue;
 
-      // Equal / Not Equal
-      $equal = '=';
-      $not = strpos($v,'!')===0 ? 1 : 0;
-      if ($not) $v = substr($v,1);
+                       // Equal / Not Equal
+                       $equal = '=';
+                       $not = strpos($v,'!')===0 ? 1 : 0;
+                       if ($not) $v = substr($v,1);
 
-      // Superior / Inferior
-      if (preg_match('/^(<|>|<=|>=)/',$v,$m)) {
-        $v = substr($v,strlen($m[1]));
-        $equal = $m[1];
-      }
+                       // Superior / Inferior
+                       if (preg_match('/^(<|>|<=|>=)/',$v,$m)) {
+                               $v = substr($v,strlen($m[1]));
+                               $equal = $m[1];
+                       }
 
                        $match = '';
 
-      // Regex
-      if (strpos($v,'~')===0) {
+                       // Regex
+                       if (strpos($v,'~')===0) {
                                $match = 'regexp';
-        $v = substr($v,1);
-        $v = $this->db()->quote($v);
-        $equal = ' '.($not ? 'NOT ' : '').$regexp.' ';
+                               $v = substr($v,1);
+                               $v = $this->db()->quote($v);
+                               $equal = ' '.($not ? 'NOT ' : '').$regexp.' ';
 
-      } elseif ($field->string()) {
+                       } elseif ($field->string()) {
 
-        if (strtolower($v)=='null') $v = '';
+                               if (strtolower($v)=='null') $v = '';
 
-        // * -> %
-        $v = str_replace('*','%',$v);
+                               // * -> %
+                               $v = str_replace('*','%',$v);
 
-        $v = $this->db()->quote($v);
-        if (preg_match('/[_%]/',$v)) {
+                               $v = $this->db()->quote($v);
+                               if (preg_match('/[_%]/',$v)) {
                                        $match = 'like';
 # NB 07.01.18           $equal = ' '.($not ? 'NOT ' : '').'LIKE ';
-          $equal = ' '.($not ? 'NOT ' : '').$this->db()->like_nocase().' ';
-        } else {
-          $equal = ($not ? '<> ' : $equal);
-        }
+                                       $equal = ' '.($not ? 'NOT ' : '').$this->db()->like_nocase().' ';
+                               } else {
+                                       $equal = ($not ? '<> ' : $equal);
+                               }
 
-      // Others
-      } else {
+                       // Others
+                       } else {
 
-        // Integer
-        if ($field->numeric()) {
-          if (strtolower($v)=='null') $v = '0';
-          #$k = "COLAESCE($k,0)";
+                               // Integer
+                               if ($field->numeric()) {
+                                       if (strtolower($v)=='null') $v = '0';
+                                       #$k = "COLAESCE($k,0)";
 
-        // Date, Time according to field->string() behavior
-        } else {
-          $v = $this->db()->quote($v);
+                               // Date, Time according to field->string() behavior
+                               } else {
+                                       $v = $this->db()->quote($v);
 
-        }
-        $equal = $not ? '<>' : $equal;
+                               }
+                               $equal = $not ? '<>' : $equal;
 
-      }
+                       }
 
                        $name = $field->sql_name(true);
 # NB 12.01.18                  if (!$field->text()) $name = $field->sql_name_cast_text();
 
-      if ($field->extras) {
-        $k = $this->extras[$k]->sql_name();
+                       if ($field->extras) {
+                               $k = $this->extras[$k]->sql_name();
 
 # NB 04.01.18       } elseif ($field->numeric() and $field->null) {
                        } elseif ($match) {
-        if ($field->null) $k = 'COALESCE('.$name.','.$this->db()->quote('').")";
+                               if ($field->null) $k = 'COALESCE('.$name.','.$this->db()->quote('').")";
 
-      } elseif ($field->numeric()) {
+                       } elseif ($field->numeric()) {
                                $name = $field->sql_name();
-        if ($field->null) $k = 'COALESCE('.$name.",0)";
+                               if ($field->null) $k = 'COALESCE('.$name.",0)";
 
-      } elseif (!$field->numeric() and $field->null) {
-        $k = 'COALESCE('.$name.",'')";
+                       } elseif (!$field->numeric() and $field->null) {
+                               $k = 'COALESCE('.$name.",'')";
 
-      } else {
-        $k = $name;
+                       } else {
+                               $k = $name;
 
-      }
+                       }
 
-      # having, denorm, EMPTY
-      if ($field->extras) {
-        $extra_where = (string)$this->db()->conf_type('extra_where');
-    #if ($_SERVER['REMOTE_USER'] == 'nico') debug($sql);
-        $k = $field->extras;
+                       # having, denorm, EMPTY
+                       if ($field->extras) {
+                               $extra_where = (string)$this->db()->conf_type('extra_where');
+               #if ($_SERVER['REMOTE_USER'] == 'nico') debug($sql);
+                               $k = $field->extras;
 
-        if ($extra_where == 'having') {
-          $having[] = "$k$equal$v";
-        } else {
-          $where[] = "$k$equal$v";
-        }
+                               if ($extra_where == 'having') {
+                                       $having[] = "$k$equal$v";
+                               } else {
+                                       $where[] = "$k$equal$v";
+                               }
 
-      } else {
-        $where[] = "$k$equal$v";
+                       } else {
+                               $where[] = "$k$equal$v";
 
-      }
+                       }
 
-    } #< foreach
+               } #< foreach
 
-    $sql = '';
-    if ($where) $sql .= ' WHERE '.join(" $logic ",$where);
-    if ($having) $sql .= ' HAVING '.join(" $logic ",$having);
-    return $sql;
+               $sql = '';
+               if ($where) $sql .= ' WHERE '.join(" $logic ",$where);
+               if ($having) $sql .= ' HAVING '.join(" $logic ",$having);
+               return $sql;
 
-  }
+       }
 
-  public function add_extras($extras) {
-    if ($this->p('extras') === '0') return false;
+       public function add_extras($extras) {
+               if ($this->p('extras') === '0') return false;
 
-    foreach ($extras as $k => $v) {
+               foreach ($extras as $k => $v) {
 
-      if ($v === false or $v === null) {
-        if (isset($this->fields[$k])) unset($this->fields[$k]);
-        #if (isset($this->extras[$k])) unset($this->extras[$k]);
-        $this->_rows_fields = true;
-        continue;
-      }
+                       if ($v === false or $v === null) {
+                               if (isset($this->fields[$k])) unset($this->fields[$k]);
+                               #if (isset($this->extras[$k])) unset($this->extras[$k]);
+                               $this->_rows_fields = true;
+                               continue;
+                       }
 
-      $v = new Field( ( is_array($v) ? $v : [] ) + [
-        'name' => $k,
-        'type' => 'text',
-        'extras' => $v,
-        'table' => $this,
-      ]);
+                       $v = new Field( ( is_array($v) ? $v : [] ) + [
+                               'name' => $k,
+                               'type' => 'text',
+                               'extras' => $v,
+                               'table' => $this,
+                       ]);
 
-      $this->fields[$k] = $v;
-      $this->extras[$k] = $v;
+                       $this->fields[$k] = $v;
+                       $this->extras[$k] = $v;
 
-    }
+               }
 
-  }
+       }
 
-  public function select_extras() {
+       public function select_extras() {
 
-    if (empty($this->extras)) return '';
+               if (empty($this->extras)) return '';
 
-    $select = []; foreach ($this->extras as $name => $field) {
-      $select[] = $field->extras." AS ".$field->sql_name();
-    }
+               $select = []; foreach ($this->extras as $name => $field) {
+                       $select[] = $field->extras." AS ".$field->sql_name();
+               }
 
-    if (!$select) return '';
-    return ','.join(',',$select);
-  }
+               if (!$select) return '';
+               return ','.join(',',$select);
+       }
 
-  public function rows_count() {
+       public function rows_count() {
                $opt = [ 'count' => 1 ];
-    return $this->db()->row($this->rows_sql($opt));
+               return $this->db()->row($this->rows_sql($opt));
        }
 
-  public function rows_sql(&$opt=[]) {
+       public function rows_sql(&$opt=[]) {
 
-    if (isset($this->orderby)) self::pdef('orderby',$this->orderby);
-    if (self::p('order')) self::pset('orderby',self::p('orderby').' '.self::p('order')); # from Wordpress
+               if (isset($this->orderby)) self::pdef('orderby',$this->orderby);
+               if (self::p('order')) self::pset('orderby',self::p('orderby').' '.self::p('order')); # from Wordpress
                $count = empty($opt['count']) ? 0 : 1;
 
-    //
-    // Select
-    //
-    if (stripos($this->name,' ') !== false) {
-      $sql = $this->name;
-      $limit = $where = '';
+               //
+               // Select
+               //
+               if (stripos($this->name,' ') !== false) {
+                       $sql = $this->name;
+                       $limit = $where = '';
                        if ($count) $sql = "SELECT count(*) FROM ".$this->sql_name();
 
-    } else {
+               } else {
 
-      $where = $this->where_criterias($this->p(),$this->p('op'));
-      $select_count = ( $where ? $this->db()->conf_type('select_count') : null );
-      if (empty($select_count)) $select_count = ['',''];
+                       $where = $this->where_criterias($this->p(),$this->p('op'));
+                       $select_count = ( $where ? $this->db()->conf_type('select_count') : null );
+                       if (empty($select_count)) $select_count = ['',''];
 
-      if (!empty($this->_rows_fields)) {
-        foreach ($this->fields() as $f) {
-          if (empty($f->extra)) $select_fields[] = $f->sql_name();
-        }
+                       if (!empty($this->_rows_fields)) {
+                               foreach ($this->fields() as $f) {
+                                       if (empty($f->extra)) $select_fields[] = $f->sql_name();
+                               }
 
-      } else {
-        $select_fields = ['*'];
+                       } else {
+                               $select_fields = ['*'];
 
-      }
+                       }
 
-      $sql = $count ? "SELECT count(*)" : "SELECT ".trim( $select_count[0].' '.join(',',$select_fields) ). $this->select_extras();
-      $sql .= " FROM ".$this->sql_name();
-      $sql .= $where;
+                       $sql = $count ? "SELECT count(*)" : "SELECT ".trim( $select_count[0].' '.join(',',$select_fields) ). $this->select_extras();
+                       $sql .= " FROM ".$this->sql_name();
+                       $sql .= $where;
 
-      if ($this->p('orderby') and !$count) $sql .= ' ORDER BY '.$this->p('orderby');
+                       if ($this->p('orderby') and !$count) $sql .= ' ORDER BY '.$this->p('orderby');
 
-      if ($limit = $this->db()->limit) {
-       $limit = str_replace(',',' OFFSET ',$limit);
-        $sql .= ' LIMIT '.$limit;
-      } else {
-        $limit = '';
-      }
+                       if ($limit = $this->db()->limit) {
+                               $limit = str_replace(',',' OFFSET ',$limit);
+                               $sql .= ' LIMIT '.$limit;
+                       } else {
+                               $limit = '';
+                       }
 
-    }
+               }
 
                if ($count) return $sql;
 
-    //
-    // Get results
-    //
-    $this->debug(preg_replace('/[\r\n]+[ ]*/',' ',$sql),1);
+               //
+               // Get results
+               //
+               $this->debug(preg_replace('/[\r\n]+[ ]*/',' ',$sql),1);
 # NB 03.09.16     $this->debug(preg_replace('/(,|FROM|WHERE|HAVING|GROUP|ORDER)/i',"\n\\1",$sql),1);
-    return [$sql,$where,$limit,$select_count];
-  }
-
-  public function buttons() {
-    if (!$this->show_buttons or empty(self::$params)) return false;
-    if (!preg_match('/(table|view)/',$this->type())) return false;
-    return true;
-  }
-
-  private function rows_parsers(&$row,&$opt=[]) {
-    $parser = isset($opt['parser']) ? $opt['parser'] : true;
-    $call = null;
-
-    //
-    // Decrypt
-    //
-    if ($parser) $this->db()->table_row_decrypt($this,$row);
-
-    //
-    // Pre
-    //
-    if ($parser and !empty($this->db()->row_parse_pre)) {
-      $call = $this->db()->row_parse_pre; $call($row,$this,$opt);
-    }
-
-    if ($parser and !empty($this->row_parse_pre)) {
-      $call = $this->row_parse_pre; $call($row,$this,$opt);
-    }
-
-    # Passed param on rows()
-    if ($parser and !empty($opt['row_parse_pre'])) {
-      $call = $opt['row_parse_pre']; $call($row,$this,$opt);
-    }
-
-    //
-    // Format
-    //
-    if ($opt['is_html'] and !$opt['use_out']) {
-      foreach ($row as $k=>$v) {
-        if (!isset($this->extras[$k])) $row[$k] = $this->db()->out->format($v);
-      }
-
-    }
-
-    //
-    // Post
-    //
-    if ($parser and !empty($this->row_parse_post)) {
-      $call = $this->row_parse_post; $call($row,$this,$opt);
-    }
-
-    if ($parser and !empty($this->db()->row_parse_post)) {
-      $call = $this->db()->row_parse_post; $call($row,$this,$opt);
-    }
-
-    # Passed param on rows()
-    if ($parser and !empty($opt['row_parse_post'])) {
-      $call = $opt['row_parse_post']; $call($row,$this,$opt);
-    }
-
-    return $call;
-  }
-
-
-  public function fields_add_missing(&$fields,$row) {
-    $new = [];
-    foreach (array_keys($row) as $name) {
-
-      #debug($name);
-      $new[$name] = isset($fields[$name])
-        ? $fields[$name]
-        : new Field([
-          'name' => $name,
-          'dyn' => true,
-          'table' => $this,
-          'preffix' => $this->field_preff,
-        ])
-      ;
-
-    }
-
-    $fields = $new;
-    return $fields;
-  }
-
-  public function rows(&$opt=[],$opt_by_val=null) {
-
-    #
-    # Db type change
-    #
-    $db_type = $this->db()->type;
-    if (!empty($opt['db_type_from'])) {
-      $this->db()->type = $opt['db_type_from'];
-    }
-
-    #
-    # Fields
-    #
-    if (!DB_TABLE_QUERY_NAME) {
-      $fields = [];
-      foreach ($this->db()->fields() as $f) { $fields[$f->name] = $f; }
-      $this->fields = $fields;
-    }
-
-    #
-    # Fields filter
-    #
-    $fields = $this->fields();
-    $fields_filter = [];
-    if ($this->fields_only) {
-      $fields_filter = $this->fields_only;
-      $new_fields = [];
-      foreach ($fields_filter as $k) {
-        $new_fields[$k] = $fields[$k];
-      }
-      $fields = $new_fields;
-      unset($new_fields);
-    }
-
-    #
-    # Build query
-    #
-    $this->create_temporary();
-
-    if ($opt_by_val !== null) $opt = $opt_by_val;
-
-    if (isset($opt['format']) and $opt['format']==='') {
-      $format = '';
-    } else {
-
-      $format = empty($opt['format']) ? $this->p('format') : $opt['format'];
-      if (!$format and $this->db()->format) $format = $this->db()->format;
-      if (!$format) $this->bye("Parameter `format` missing!");
-    }
+               return [$sql,$where,$limit,$select_count];
+       }
+
+       public function buttons() {
+               if (!$this->show_buttons or empty(self::$params)) return false;
+               if (!preg_match('/(table|view)/',$this->type())) return false;
+               return true;
+       }
+
+       private function rows_parsers(&$row,&$opt=[]) {
+               $parser = isset($opt['parser']) ? $opt['parser'] : true;
+               $call = null;
+
+               //
+               // Decrypt
+               //
+               if ($parser) $this->db()->table_row_decrypt($this,$row);
+
+               //
+               // Pre
+               //
+               if ($parser and !empty($this->db()->row_parse_pre)) {
+                       $call = $this->db()->row_parse_pre; $call($row,$this,$opt);
+               }
+
+               if ($parser and !empty($this->row_parse_pre)) {
+                       $call = $this->row_parse_pre; $call($row,$this,$opt);
+               }
+
+               # Passed param on rows()
+               if ($parser and !empty($opt['row_parse_pre'])) {
+                       $call = $opt['row_parse_pre']; $call($row,$this,$opt);
+               }
+
+               //
+               // Format
+               //
+               if ($opt['is_html'] and !$opt['use_out']) {
+                       foreach ($row as $k=>$v) {
+                               if (!isset($this->extras[$k])) $row[$k] = $this->db()->out->format($v);
+                       }
+
+               }
+
+               //
+               // Post
+               //
+               if ($parser and !empty($this->row_parse_post)) {
+                       $call = $this->row_parse_post; $call($row,$this,$opt);
+               }
+
+               if ($parser and !empty($this->db()->row_parse_post)) {
+                       $call = $this->db()->row_parse_post; $call($row,$this,$opt);
+               }
+
+               # Passed param on rows()
+               if ($parser and !empty($opt['row_parse_post'])) {
+                       $call = $opt['row_parse_post']; $call($row,$this,$opt);
+               }
+
+               return $call;
+       }
+
+
+       private function fields_add_missing(&$fields,$row) {
+               $new = [];
+               foreach (array_keys($row) as $name) {
+
+                       #debug($name);
+                       $new[$name] = isset($fields[$name])
+                               ? $fields[$name]
+                               : new Field([
+                                       'name' => $name,
+                                       'dyn' => true,
+                                       'table' => $this,
+                                       'preffix' => $this->field_preff,
+                               ])
+                       ;
+
+               }
+
+               $fields = $new;
+               return $fields;
+       }
+
+       public function rows(&$opt=[],$opt_by_val=null) {
+
+               #
+               # Db type change
+               #
+               $db_type = $this->db()->type;
+               if (!empty($opt['db_type_from'])) {
+                       $this->db()->type = $opt['db_type_from'];
+               }
+
+               #
+               # Fields
+               #
+               $fields = $this->fields();
+
+               #
+               # Build query
+               #
+               $this->create_temporary();
+
+               if ($opt_by_val !== null) $opt = $opt_by_val;
+
+               if (isset($opt['format']) and $opt['format']==='') {
+                       $format = '';
+               } else {
+
+                       $format = empty($opt['format']) ? $this->p('format') : $opt['format'];
+                       if (!$format and $this->db()->format) $format = $this->db()->format;
+                       if (!$format) $this->bye("Parameter `format` missing!");
+               }
 
 #debug($opt);
-    list($sql,$where,$limit,$select_count) = $this->rows_sql($opt);
-    $st = null;
-    $cursor = null;
-    $sql_orig = null;
+               list($sql,$where,$limit,$select_count) = $this->rows_sql($opt);
+               $st = null;
+               $cursor = null;
+               $sql_orig = null;
 
-    $fct = function() { return true; };
-    if ($this->db()->type == 'pgsql') {
+               $fct = function() { return true; };
+               if ($this->db()->type == 'pgsql') {
                        $sql_orig = $sql;
-       $this->db()->conn->beginTransaction();
-       $sql = "DECLARE table_rows CURSOR FOR $sql";
-       $cursor = $this->db()->conn->prepare($sql);
-       $cursor->execute();
-       $sql = "FETCH 1 FROM table_rows";
-
-    } else {
-       $this->db()->conn->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
-
-    }
-
-    $st = $this->db()->conn->prepare($sql);#,[PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT]);
-    if (empty($cursor)) {
-       $st->execute();
-    } else {
-       $fct = function() use($st) { return $st->execute(); };
-    }
-    if (!empty($opt['query'])) return $st;
-
-    #
-    # Use the module out when format unknow
-    #
-    $out_conf = null;
-    $opt['use_out'] = false;
-
-    if ($this->p('out') or !preg_match('/^('.join('|',
-      [ '','template','table','sql','_div','wp' ] # local
-    ).')$/',$format))
-    {
-
-      $opt['use_out'] = true;
-      if (!($out_conf = $this->db()->out->types($format))) $this->bye("Unknow format `$format`");
-      $out_conf = array_merge($opt,$out_conf);
-
-      # Function name should be format
-      $this->db()->out->type($format); self::$params += array_values($this->db()->out->types());
-
-      if (empty($out_conf['enclose'])) $out_conf['enclose'] = ['',''];
-      debug('Using out module!',3);
-
-    }
-
-    #
-    # Html
-    #
-    if (!isset($opt['is_html'])) $opt['is_html'] = preg_match('/^(table|div)$/',$format)
-      ? ( $this->show_header )
-      : false
-    ;
-
-    if ($opt['is_html'] and !empty(self::$params) and !$this->p('action') and !$this->p('inc')) {
-      echo $this->html_menu($opt);
-    }
-
-    if ($opt['is_html']) {
-       echo '<div class="results">'.NB_EOL;
+                       $this->db()->conn->beginTransaction();
+                       $sql = "DECLARE table_rows CURSOR FOR $sql";
+                       $cursor = $this->db()->conn->prepare($sql);
+                       $cursor->execute();
+                       $sql = "FETCH 1 FROM table_rows";
+
+               } else {
+                       $this->db()->conn->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
+
+               }
+
+               $st = $this->db()->conn->prepare($sql);#,[PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT]);
+               if (empty($cursor)) {
+                       $st->execute();
+               } else {
+                       $fct = function() use($st) { return $st->execute(); };
+               }
+               if (!empty($opt['query'])) return $st;
+
+               #
+               # Use the module out when format unknow
+               #
+               $out_conf = null;
+               $opt['use_out'] = false;
+
+               if ($this->p('out') or !preg_match('/^('.join('|',
+                       [ '','template','table','sql','_div','wp' ] # local
+               ).')$/',$format))
+               {
+
+                       $opt['use_out'] = true;
+                       if (!($out_conf = $this->db()->out->types($format))) $this->bye("Unknow format `$format`");
+                       $out_conf = array_merge($opt,$out_conf);
+
+                       # Function name should be format
+                       $this->db()->out->type($format); self::$params += array_values($this->db()->out->types());
+
+                       if (empty($out_conf['enclose'])) $out_conf['enclose'] = ['',''];
+                       debug('Using out module!',3);
+
+               }
+
+               #
+               # Html
+               #
+               if (!isset($opt['is_html'])) $opt['is_html'] = preg_match('/^(table|div)$/',$format)
+                       ? ( $this->show_header )
+                       : false
+               ;
+
+               if ($opt['is_html'] and !empty(self::$params) and !$this->p('action') and !$this->p('inc')) {
+                       echo $this->html_menu($opt);
+               }
+
+               if ($opt['is_html']) {
+                        echo '<div class="results">'.NB_EOL;
 # NB 07.01.18        if ($this->show_hidden_params and !$this->p('inc')) echo $this->form_hidden();
-    }
+               }
 
-    if ($opt['is_html']) $this->db()->out->type('html');
+               if ($opt['is_html']) $this->db()->out->type('html');
 
-    #
-    # Rows
-    #
+               #
+               # Rows
+               #
 
-    # Parser on/off (default: on)
-    if (!isset($opt['parser'])) $opt['parser'] = true;
+               # Parser on/off (default: on)
+               if (!isset($opt['parser'])) $opt['parser'] = true;
 
-    if (!empty($opt['db_type_from'])) {
-      $this->db()->type = $db_type;
-    }
+               if (!empty($opt['db_type_from'])) {
+                       $this->db()->type = $db_type;
+               }
 
-    $count = 0;
-    while ($fct() and $row = $st->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_NEXT)) {
+               $count = 0;
+               while ($fct() and $row = $st->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_NEXT)) {
 
-      $count++;
-      $call = null;
+                       $count++;
+                       $call = null;
 
-      $call = $this->rows_parsers($row,$opt);
+                       $call = $this->rows_parsers($row,$opt);
 
-      #
-      # Fields filter
-      #
-      if ($fields_filter) {
-        $new_row = [];
-        foreach ($fields_filter as $k) {
-          if (isset($row[$k])) $new_row[$k] = $row[$k];
-        }
-        $row = $new_row;
-      }
+                       #
+                       # Fields filter
+                       #
+                       if ($this->fields_only) {
+                               $new_row = [];
+                               foreach ($this->fields_only as $k) {
+                                       if (isset($row[$k])) $new_row[$k] = $row[$k];
+                               }
+                               $row = $new_row;
+                       }
 
-      #
-      # Preffix
-      #
-      if (!empty($opt['preffix'])) echo $opt['preffix'];
+                       #
+                       # Preffix
+                       #
+                       if (!empty($opt['preffix'])) echo $opt['preffix'];
 
-      #
-      # Head
-      #
-      if ($count === 1) {
-        if ($opt['is_html']) echo $this->html_rows_top();
+                       #
+                       # Head
+                       #
+                       if ($count === 1) {
+                               if ($opt['is_html']) echo $this->html_rows_top();
 
-        if ($call) {
-          $this->fields_add_missing($fields,$row);
-        }
+                               if ($call) {
+                                       $this->fields_add_missing($fields,$row);
+                               }
 
-        if ($out_conf) {
-          $this->db()->out->head($out_conf,array_keys($fields),[$row]);
+                               if ($out_conf) {
+                                       $this->db()->out->head($out_conf,array_keys($fields),[$row]);
 
-        } else {
-          echo $this->{"rows_begin_$format"}($fields,$opt);
+                               } else {
+                                       echo $this->{"rows_begin_$format"}($fields,$opt);
 
-        }
+                               }
 
-      }
+                       }
 
-      #
-      # Row
-      #
-      $count_fields = 0;
+                       #
+                       # Row
+                       #
+                       $count_fields = 0;
 
-      foreach ($fields as $f => $field) {
+                       foreach ($fields as $f => $field) {
                                if (!$this->field($f)) continue;
-        $row[$f] = $field->out(isset($row[$f]) ? $row[$f] : '');
-        $count_fields++;
-      }
+                               $row[$f] = $field->out(isset($row[$f]) ? $row[$f] : '');
+                               $count_fields++;
+                       }
 
-      if ($out_conf) {
-        $this->db()->out->row($out_conf,$row);
+                       if ($out_conf) {
+                               $this->db()->out->row($out_conf,$row);
 
-      } else {
-        echo $this->{"rows_rec_$format"}($row,$opt);
-      }
+                       } else {
+                               echo $this->{"rows_rec_$format"}($row,$opt);
+                       }
 
-    } # < while rows
+               } # < while rows
 
-    $st->closeCursor();
-    if (!empty($cursor)) $cursor->closeCursor();
-    if (!$count) return;
+               $st->closeCursor();
+               if (!empty($cursor)) $cursor->closeCursor();
+               if (!$count) return;
 
-    $this->count = $opt['count'] = $count;
-    $this->limit = $opt['limit'] = $limit;
+               $this->count = $opt['count'] = $count;
+               $this->limit = $opt['limit'] = $limit;
 
-    if ($opt['is_html'] or $format=='wp' or !empty($cursor)) {
+               if ($opt['is_html'] or $format=='wp' or !empty($cursor)) {
 
                        if (!empty($sql_orig)) $sql = $sql_orig;
-      //
-      // Tot
-      //
-      if (!$where and !$limit) {
-        $debug = "Table.rows(): Not using count(*), use $count";
-        $query = $this->db()->conn->query("SELECT $count");
-
-      } elseif ($select_count[1]) {
-        $debug = "Table.rows(): Using $select_count[1]";
-        $query = $this->db()->conn->query($select_count[1]);
-
-      } elseif ($where) {
-        $sql_count = $sql;
-        $sql_count = preg_replace('/ (ORDER|LIMIT) .*?$/s','',$sql_count);
-        $sql_count = preg_replace('/^SELECT .*FROM/s','SELECT count(*) FROM ',$sql_count);
-        $debug = "Table.rows(): Using $sql_count";
-        $query = $this->db()->conn->query($sql_count);
-
-      } else {
-        $query = $this->db()->conn->query('SELECT count(*) FROM '.$this->sql_name());
-
-      }
-
-      if (!$query) $this->err_sql($sql);
-
-      $tot = $query->fetch(PDO::FETCH_COLUMN);
-      $this->tot = $opt['tot'] = $tot;
-
-    } # < is_html
-
-    if ($count === 0 and !$format) {
-      echo $this->{"rows_begin_$format"}($fields,$opt);
-    }
-
-    if ($out_conf) {
-      $this->db()->out->end($out_conf);
-
-    } else {
-      echo $this->{"rows_end_$format"}();
-
-      if ($opt['is_html']) {
-        echo '<div class="nav bottom">'
-          .$this->nav($opt['count'],$opt['tot'],$opt['limit'])
-         .'</div>'.NB_EOL
-        ;
-       }
-
-    } # < out
-
-    if ($opt['is_html']) {
-      echo '</div>'.NB_EOL;
-    }
-
-    #return $count;
-  }
-
-  /*-----------------------------------------------------------------
-    No Out
-  -----------------------------------------------------------------*/
-  public function rows_begin_($fields,&$o) {
-    $o['sep'] = '';
-    $o['var'] = [
-      'head' => array_keys($fields),
-      'rows' => [],
-    ];
-  }
-
-  public function rows_rec_($row,&$o) {
-    $o['var']['rows'][] = $row;
-  }
-
-  public function rows_end_() {
-  }
-
-  /*-----------------------------------------------------------------
-    Template
-  -----------------------------------------------------------------*/
-  public function rows_begin_template($fields,&$o) {
-    $id = $this->idtemplate();
-
-    $id = preg_replace('/[^\w\._-]/','',$id);
-
-    $file = TABLE_TEMPLATE.'/'.$id.'.php';
-    if (!is_readable($file)) return false; #$this->bye("Wrong id `$id`");
+                       //
+                       // Tot
+                       //
+                       if (!$where and !$limit) {
+                               $debug = "Table.rows(): Not using count(*), use $count";
+                               $query = $this->db()->conn->query("SELECT $count");
+
+                       } elseif ($select_count[1]) {
+                               $debug = "Table.rows(): Using $select_count[1]";
+                               $query = $this->db()->conn->query($select_count[1]);
+
+                       } elseif ($where) {
+                               $sql_count = $sql;
+                               $sql_count = preg_replace('/ (ORDER|LIMIT) .*?$/s','',$sql_count);
+                               $sql_count = preg_replace('/^SELECT .*FROM/s','SELECT count(*) FROM ',$sql_count);
+                               $debug = "Table.rows(): Using $sql_count";
+                               $query = $this->db()->conn->query($sql_count);
+
+                       } else {
+                               $query = $this->db()->conn->query('SELECT count(*) FROM '.$this->sql_name());
+
+                       }
+
+                       if (!$query) $this->err_sql($sql);
+
+                       $tot = $query->fetch(PDO::FETCH_COLUMN);
+                       $this->tot = $opt['tot'] = $tot;
+
+               } # < is_html
+
+               if ($count === 0 and !$format) {
+                       echo $this->{"rows_begin_$format"}($fields,$opt);
+               }
+
+               if ($out_conf) {
+                       $this->db()->out->end($out_conf);
+
+               } else {
+                       echo $this->{"rows_end_$format"}();
+
+                       if ($opt['is_html']) {
+                               echo '<div class="nav bottom">'
+                                       .$this->nav($opt['count'],$opt['tot'],$opt['limit'])
+                                .'</div>'.NB_EOL
+                               ;
+                        }
+
+               } # < out
+
+               if ($opt['is_html']) {
+                       echo '</div>'.NB_EOL;
+               }
+
+               #return $count;
+       }
+
+       /*-----------------------------------------------------------------
+               No Out
+       -----------------------------------------------------------------*/
+       public function rows_begin_($fields,&$o) {
+               $o['sep'] = '';
+               $o['var'] = [
+                       'head' => array_keys($fields),
+                       'rows' => [],
+               ];
+       }
+
+       public function rows_rec_($row,&$o) {
+               $o['var']['rows'][] = $row;
+       }
+
+       public function rows_end_() {
+       }
+
+       /*-----------------------------------------------------------------
+               Template
+       -----------------------------------------------------------------*/
+       public function rows_begin_template($fields,&$o) {
+               $id = $this->idtemplate();
+
+               $id = preg_replace('/[^\w\._-]/','',$id);
+
+               $file = TABLE_TEMPLATE.'/'.$id.'.php';
+               if (!is_readable($file)) return false; #$this->bye("Wrong id `$id`");
 # NB 02.12.16     $o['file'] = $file;
-    $this->__file = $file;
-    $this->__fields = array_keys($fields);
+               $this->__file = $file;
+               $this->__fields = array_keys($fields);
 # NB 02.12.16     $HEAD = array_keys($fields);
 # NB 02.12.16     $ROWS = [];
 # NB 02.12.16     $ROW = [];
 # NB 02.12.16     require $o['file'];
-  }
-
-  public function rows_rec_template($row,&$o) {
-    $i = 0;
-    foreach ($row as $k=>$v) {
-      $row[$i] = $v;
-      $i++;
-    }
-    $this->__rows[] = $row;
+       }
+
+       public function rows_rec_template($row,&$o) {
+               $i = 0;
+               foreach ($row as $k=>$v) {
+                       $row[$i] = $v;
+                       $i++;
+               }
+               $this->__rows[] = $row;
 # NB 02.12.16     $HEAD = [];
 # NB 02.12.16     $ROWS = [$row];
 # NB 02.12.16     $ROW = $row;
-  }
-
-  public function rows_end_template() {
-    $HEAD = &$this->__fields;
-    $ROWS = &$this->__rows;
-    $ROW = &$ROWS[0];;
-    require $this->__file;
-    unset($this->__file);
-    unset($this->__fields);
-    unset($this->__rows);
-  }
-
-  /*-----------------------------------------------------------------
-    Wordpress
-  -----------------------------------------------------------------*/
-  public function rows_begin_wp() {
-    require_once(NB_ROOT.'/lib/php/db/wp.php');
-    $this->_html_table = new html_table($this);
-    return '';
-  }
-
-  public function rows_rec_wp(&$row) {
-    $this->_html_table->items[] = $row;
-    return '';
-  }
-
-  public function rows_end_wp() {
-
-    $limit = preg_replace('/^.*,\s*/','',$this->limit);
-
-    $this->_html_table->set_pagination_args([
-      'total_items' => $this->tot, // total items defined above
-      'per_page' => $limit, // per page constant defined at top of method
-      'total_pages' => ceil($this->tot / $limit) // calculate pages count
-    ]);
-
-    #$this->_html_table->display_tablenav('top');
-    $this->_html_table->display();
-    #$this->_html_table->display_tablenav('bottom');
-    unset($this->_html_table);
-    return '';
-  }
+       }
+
+       public function rows_end_template() {
+               $HEAD = &$this->__fields;
+               $ROWS = &$this->__rows;
+               $ROW = &$ROWS[0];;
+               require $this->__file;
+               unset($this->__file);
+               unset($this->__fields);
+               unset($this->__rows);
+       }
+
+       /*-----------------------------------------------------------------
+               Wordpress
+       -----------------------------------------------------------------*/
+       public function rows_begin_wp() {
+               require_once(NB_ROOT.'/lib/php/db/wp.php');
+               $this->_html_table = new html_table($this);
+               return '';
+       }
+
+       public function rows_rec_wp(&$row) {
+               $this->_html_table->items[] = $row;
+               return '';
+       }
+
+       public function rows_end_wp() {
+
+               $limit = preg_replace('/^.*,\s*/','',$this->limit);
+
+               $this->_html_table->set_pagination_args([
+                       'total_items' => $this->tot, // total items defined above
+                       'per_page' => $limit, // per page constant defined at top of method
+                       'total_pages' => ceil($this->tot / $limit) // calculate pages count
+               ]);
+
+               #$this->_html_table->display_tablenav('top');
+               $this->_html_table->display();
+               #$this->_html_table->display_tablenav('bottom');
+               unset($this->_html_table);
+               return '';
+       }
 
        /*-----------------------------------------------------------------
-       Sql
+               Sql
        -----------------------------------------------------------------*/
        public function rows_begin_sql() {
-       return '';
-       return "\n-- ".$this->name."\n";
+               return '';
+               return "\n-- ".$this->name."\n";
        }
 
        public function rows_rec_sql(&$row,&$opt) {
-       $keys = $values = [];
+               $keys = $values = [];
 
-       foreach ($row as $k=>$v) {
-       if (isset($this->extras[$k])) continue;
-       $f = $this->field($k);
+               foreach ($row as $k=>$v) {
+                       if (isset($this->extras[$k])) continue;
+                       $f = $this->field($k);
 
-       $values[] = $f->quote($v);
-       $keys[] = $f->sql_name();
-       }
+                       $values[] = $f->quote($v);
+                       $keys[] = $f->sql_name();
+               }
 
-       $fields = $this->fields_only ? ' ('.join(',',$keys).')' : '';
-       $sql = "INSERT INTO ".$this->sql_name().$fields." VALUES(".join(',',array_values($values)).");";
+               $fields = $this->fields_only ? ' ('.join(',',$keys).')' : '';
+               $sql = "INSERT INTO ".$this->sql_name().$fields." VALUES(".join(',',array_values($values)).");";
 
-       $fct = !empty($opt['fct']) ? $opt['fct'] : null;
-       if ($fct) $sql = $fct($sql,$this);
+               $fct = !empty($opt['fct']) ? $opt['fct'] : null;
+               if ($fct) $sql = $fct($sql,$this);
 
-       return $sql.NB_EOL;
+               return $sql.NB_EOL;
        }
 
        public function rows_end_sql() {
-       return '';
-       }
-
-  /*-----------------------------------------------------------------
-    Text
-  -----------------------------------------------------------------*/
-  public function rows_begin_text() {
-    $this->_row_text = null;
-    return '';
-  }
-
-  public function rows_rec_text(&$row) {
-    $text = '';
-    if ($this->_row_text === null) {
-      $this->_row_text = true;
-    } else {
-      $text .= "\t";
-    }
-    return $text.$row."\n";
-  }
-
-  public function rows_end_text() {
-    unset($this->_row_text);
-    return '';
-  }
-
-  /*-----------------------------------------------------------------
-    Json
-  -----------------------------------------------------------------*/
-  public function rows_begin_json() {
-    $this->_row_json = null;
-    return '['.NB_EOL;
-    return ''
-      #."// database: ".$this->db()->name."\n"
-      #."// table: $this->name\n"
-    .'['.NB_EOL;
-  }
-
-  public function rows_rec_json(&$row) {
-    if ($this->_row_json === null) {
-      $json = '';
-      $this->_row_json = true;
-    } else {
-      $json = ','.NB_EOL;
-    }
-    return $json . json_encode($row);
-  }
-
-  public function rows_end_json() {
-    unset($this->_row_json);
-    return NB_EOL.']'.NB_EOL;
-  }
-
-  /*-----------------------------------------------------------------
-    Xml
-  -----------------------------------------------------------------*/
-  public function rows_begin_xml() {
-    return ''
-      .'<?xml version="1.0" encoding="utf-8"?>'.NB_EOL #<?
-      .'<rows name="'.$this->name.'" database="'.$this->db()->name.'" database-type="'.$this->db()->conf_type('type').'">'.NB_EOL
-    ;
-  }
-
-  public function rows_rec_xml(&$row) {
-    $xml = '';
-    $xml .= TABLE_INDENT."<row>".NB_EOL;
-    foreach ($row as $k=>$v) {
-      if ($v !== '') $xml .= ''
-        . TABLE_INDENT.TABLE_INDENT."<".$k.">"
-        .'<![CDATA['.$v.']]>'
-        . '</'.$k.'>'
-      . NB_EOL;
-    }
-    $xml .= TABLE_INDENT."</row>".NB_EOL;
-    return $xml;
-  }
-
-  public function rows_end_xml() {
-    return '</rows>'.NB_EOL;
-  }
-
-  public function zaza() { return [ ['A','B'], ['a','bb'] ]; }
-
-  /*-----------------------------------------------------------------
-    Csv
-  -----------------------------------------------------------------*/
-  public function rows_begin_csv($fields) {
-
-    if (self::p('rows_head_char')!=='') echo self::p('rows_head_char');
-    if (!$this->show_header) return '';
-    return join(TABLE_CSV_SEP,array_keys($fields))."\n";
-  }
-
-  public function rows_rec_csv(&$row) {
-    return str_replace("\n",'|',join(TABLE_CSV_SEP,array_values($row)))."\n";
-  }
-
-  public function rows_end_csv() {
-    return '';
-  }
-
-  /*-----------------------------------------------------------------
-    Html Table
-  -----------------------------------------------------------------*/
-  public function rows_begin_table($fields) {
-
-    $html = '';
-
-    $html .= '<table class="rows wp-list-table widefat striped">'.NB_EOL;
-
-    $this->__rows_table_attr = [];
-    foreach ($fields as $name => $f) {
-      $this->__rows_table_attr[$name] = ''
-        . ' class="' . $name
-               . ($f->key ? ' key' : '')
-               . (isset($this->extras[$name]) ? ' extra' : '')
-               . ' ' . preg_replace('/\W.*$/','',$f->type)
-        .'"'
-      ;
-    }
-
-    if ($this->show_header) {
-      $html .= '<thead>'.NB_EOL;
-
-      // Columns names
-      $html .= '<tr class="head">'.NB_EOL;
-      if ($this->buttons() and DB_HTML_EDIT) $html .= '<th class="edit"></th>'.NB_EOL;
-      foreach ($fields as $name => $f) {
-        $html .= '<th'.$this->__rows_table_attr[$name].'>'.$this->url_sort($name).'</th>'.NB_EOL;
-      }
-      if ($this->buttons() and DB_HTML_DELETE) $html .= '<th class="delete"></th>'.NB_EOL;
-      $html .= '</tr>'.NB_EOL;
-      $html .= '</thead>'.NB_EOL;
-    }
-
-    $html .= '<tbody>'.NB_EOL;
-    return $html;
-  }
-
-  public function rows_rec_table(&$row,&$opt) {
-
-    $buttons = $this->html_row_buttons($row);
-
-    $html = '<tr class="row">'.NB_EOL;
-
-    if ($this->buttons() and !empty($buttons[0])) $html .= '<td class="action">'.$buttons[0].'</td>'.NB_EOL;
-
-    foreach ($row as $k => $v) {
-      if ( !empty($this) and !empty($this->field($k)) ) {
-        $v = $this->field($k)->htmlValue($v);
-      }
-      $html .= '<td'.$this->__rows_table_attr[$k].'>'.$v.'</td>'.NB_EOL;
-    }
-
-    if ($this->buttons() and !empty($buttons[1])) $html .= '<td class="action">'.$buttons[1].'</td>'.NB_EOL;
-
-    $html .= '</tr>'.NB_EOL;
+               return '';
+       }
 
-    return $html;
-  }
+       /*-----------------------------------------------------------------
+               Text
+       -----------------------------------------------------------------*/
+       public function rows_begin_text() {
+               $this->_row_text = null;
+               return '';
+       }
 
-  public function rows_end_table() {
-    unset($this->__rows_table_attr);
-    $html = '';
-    $html .= '</tbody>'.NB_EOL;
-    $html .= '</table>'.NB_EOL;
-    return $html;
-  }
+       public function rows_rec_text(&$row) {
+               $text = '';
+               if ($this->_row_text === null) {
+                       $this->_row_text = true;
+               } else {
+                       $text .= "\t";
+               }
+               return $text.$row."\n";
+       }
 
-  /*-----------------------------------------------------------------
-    Html Div
-  -----------------------------------------------------------------*/
-  public function rows_begin_div() {
-    return '<div class="rows search-results">'.NB_EOL;
-  }
+       public function rows_end_text() {
+               unset($this->_row_text);
+               return '';
+       }
 
-  public function rows_rec_div(&$row) {
+       /*-----------------------------------------------------------------
+               Json
+       -----------------------------------------------------------------*/
+       public function rows_begin_json() {
+               $this->_row_json = null;
+               return '['.NB_EOL;
+               return ''
+                       #."// database: ".$this->db()->name."\n"
+                       #."// table: $this->name\n"
+               .'['.NB_EOL;
+       }
 
-    $html = '';
+       public function rows_rec_json(&$row) {
+               if ($this->_row_json === null) {
+                       $json = '';
+                       $this->_row_json = true;
+               } else {
+                       $json = ','.NB_EOL;
+               }
+               return $json . json_encode($row);
+       }
 
-    $html .= '<ul class="row">'.NB_EOL;
+       public function rows_end_json() {
+               unset($this->_row_json);
+               return NB_EOL.']'.NB_EOL;
+       }
 
-    if ($this->buttons()) {
-      $html .= '<li class="buttons">'.NB_EOL;
-      $html .= join('',$this->html_row_buttons($row));
-      $html .= '</li>'.NB_EOL;
-    }
+       /*-----------------------------------------------------------------
+               Xml
+       -----------------------------------------------------------------*/
+       public function rows_begin_xml() {
+               return ''
+                       .'<?xml version="1.0" encoding="utf-8"?>'.NB_EOL #<?
+                       .'<rows name="'.$this->name.'" database="'.$this->db()->name.'" database-type="'.$this->db()->conf_type('type').'">'.NB_EOL
+               ;
+       }
 
-    foreach ($row as $k => $v) {
-      $html .= '<li>'
-        .( $k == '0' ? '' : '<label>'.prettyText($k).'</label>')
-        .'<span class="'.$k.'">'.$v.'</span>'
-        .'</li>'.NB_EOL;
-    }
+       public function rows_rec_xml(&$row) {
+               $xml = '';
+               $xml .= TABLE_INDENT."<row>".NB_EOL;
+               foreach ($row as $k=>$v) {
+                       if ($v !== '') $xml .= ''
+                               . TABLE_INDENT.TABLE_INDENT."<".$k.">"
+                               .'<![CDATA['.$v.']]>'
+                               . '</'.$k.'>'
+                       . NB_EOL;
+               }
+               $xml .= TABLE_INDENT."</row>".NB_EOL;
+               return $xml;
+       }
 
-    $html .= '</ul>'.NB_EOL;
+       public function rows_end_xml() {
+               return '</rows>'.NB_EOL;
+       }
 
-    return $html;
-  }
+       public function zaza() { return [ ['A','B'], ['a','bb'] ]; }
 
-  public function rows_end_div() {
-    return '</div>'.NB_EOL;
-  }
+       /*-----------------------------------------------------------------
+               Csv
+       -----------------------------------------------------------------*/
+       public function rows_begin_csv($fields) {
+
+               if (self::p('rows_head_char')!=='') echo self::p('rows_head_char');
+               if (!$this->show_header) return '';
+               return join(TABLE_CSV_SEP,array_keys($fields))."\n";
+       }
+
+       public function rows_rec_csv(&$row) {
+               return str_replace("\n",'|',join(TABLE_CSV_SEP,array_values($row)))."\n";
+       }
+
+       public function rows_end_csv() {
+               return '';
+       }
+
+       /*-----------------------------------------------------------------
+               Html Table
+       -----------------------------------------------------------------*/
+       public function rows_begin_table($fields) {
+
+               $html = '';
+
+               $html .= '<table class="rows wp-list-table widefat striped">'.NB_EOL;
+
+               $this->__rows_table_attr = [];
+               foreach ($fields as $name => $f) {
+                       $this->__rows_table_attr[$name] = ''
+                               . ' class="' . $name
+                                       . ($f->key ? ' key' : '')
+                                       . (isset($this->extras[$name]) ? ' extra' : '')
+                                       . ' ' . preg_replace('/\W.*$/','',$f->type)
+                               .'"'
+                       ;
+               }
 
-  public function sql_names($value) {
+               if ($this->show_header) {
+                       $html .= '<thead>'.NB_EOL;
 
-    $new = [];
-    foreach ($value as $k=>$v) {
-      $new[$k] = $this->sql_name($v);
-    }
-    return $new;
-  }
+                       // Columns names
+                       $html .= '<tr class="head">'.NB_EOL;
+                       if ($this->buttons() and DB_HTML_EDIT) $html .= '<th class="edit"></th>'.NB_EOL;
+                       foreach ($fields as $name => $f) {
+                               $html .= '<th'.$this->__rows_table_attr[$name].'>'.$this->url_sort($name).'</th>'.NB_EOL;
+                       }
+                       if ($this->buttons() and DB_HTML_DELETE) $html .= '<th class="delete"></th>'.NB_EOL;
+                       $html .= '</tr>'.NB_EOL;
+                       $html .= '</thead>'.NB_EOL;
+               }
 
-  public function sql_name($value=null) {
+               $html .= '<tbody>'.NB_EOL;
+               return $html;
+       }
 
-    return $this->db()->sql_name($value === null ? $this->name : $value);
-  }
+       public function rows_rec_table(&$row,&$opt) {
 
-  private function _post2sql($post) {
-    $keys = [];
-    $keys_values = [];
-    $fields = [];
-    $fields_values = [];
-    foreach ($this->fields() as $name => $field) {
+               $buttons = $this->html_row_buttons($row);
 
-      if ($field->extras) continue;
+               $html = '<tr class="row">'.NB_EOL;
 
-      $value = $post[$this->field_preff.$name];
+               if ($this->buttons() and !empty($buttons[0])) $html .= '<td class="action">'.$buttons[0].'</td>'.NB_EOL;
 
-      if ($field->key) {
-        $keys[] = $name;
+               foreach ($row as $k => $v) {
+                       if ( !empty($this) and !empty($this->field($k)) ) {
+                               $v = $this->field($k)->htmlValue($v);
+                       }
+                       $html .= '<td'.$this->__rows_table_attr[$k].'>'.$v.'</td>'.NB_EOL;
+               }
 
-        if (!isset($post[$this->key_preff.$name])) {
-          if ($field->key) $this->bye("Missing `$name`!");
-          continue;
-        }
+               if ($this->buttons() and !empty($buttons[1])) $html .= '<td class="action">'.$buttons[1].'</td>'.NB_EOL;
 
-        if (isset($post[$this->key_preff.$name])) {
-          $keys_values[] = $post[$this->key_preff.$name];
+               $html .= '</tr>'.NB_EOL;
 
-        } else {
-          $keys_values[] = $value;
-        }
+               return $html;
+       }
 
-      } else {
+       public function rows_end_table() {
+               unset($this->__rows_table_attr);
+               $html = '';
+               $html .= '</tbody>'.NB_EOL;
+               $html .= '</table>'.NB_EOL;
+               return $html;
+       }
 
-        $fields[] = $name;
-        $fields_values[] = $value;
+       /*-----------------------------------------------------------------
+               Html Div
+       -----------------------------------------------------------------*/
+       public function rows_begin_div() {
+               return '<div class="rows search-results">'.NB_EOL;
+       }
+
+       public function rows_rec_div(&$row) {
+
+               $html = '';
+
+               $html .= '<ul class="row">'.NB_EOL;
+
+               if ($this->buttons()) {
+                       $html .= '<li class="buttons">'.NB_EOL;
+                       $html .= join('',$this->html_row_buttons($row));
+                       $html .= '</li>'.NB_EOL;
+               }
 
-      }
+               foreach ($row as $k => $v) {
+                       $html .= '<li>'
+                               .( $k == '0' ? '' : '<label>'.prettyText($k).'</label>')
+                               .'<span class="'.$k.'">'.$v.'</span>'
+                               .'</li>'.NB_EOL;
+               }
+
+               $html .= '</ul>'.NB_EOL;
+
+               return $html;
+       }
+
+       public function rows_end_div() {
+               return '</div>'.NB_EOL;
+       }
+
+       public function sql_names($value) {
+
+               $new = [];
+               foreach ($value as $k=>$v) {
+                       $new[$k] = $this->sql_name($v);
+               }
+               return $new;
+       }
+
+       public function sql_name($value=null) {
+
+               return $this->db()->sql_name($value === null ? $this->name : $value);
+       }
+
+       private function _post2sql($post) {
+               $keys = [];
+               $keys_values = [];
+               $fields = [];
+               $fields_values = [];
+               foreach ($this->fields() as $name => $field) {
+
+                       if ($field->extras) continue;
+
+                       $value = $post[$this->field_preff.$name];
+
+                       if ($field->key) {
+                               $keys[] = $name;
+
+                               if (!isset($post[$this->key_preff.$name])) {
+                                       if ($field->key) $this->bye("Missing `$name`!");
+                                       continue;
+                               }
+
+                               if (isset($post[$this->key_preff.$name])) {
+                                       $keys_values[] = $post[$this->key_preff.$name];
+
+                               } else {
+                                       $keys_values[] = $value;
+                               }
+
+                       } else {
+
+                               $fields[] = $name;
+                               $fields_values[] = $value;
+
+                       }
                }
 
                return [
-       'keys' => $keys,
-       'keys_values' => $keys_values,
-       'fields' => $fields,
-       'fields_values' => $fields_values,
-       'all_keys' => array_combine($keys,$keys_values),
-       'all_fields' => array_combine($fields,$fields_values),
+                       'keys' => $keys,
+                       'keys_values' => $keys_values,
+                       'fields' => $fields,
+                       'fields_values' => $fields_values,
+                       'all_keys' => array_combine($keys,$keys_values),
+                       'all_fields' => array_combine($fields,$fields_values),
                ];
-  }
+       }
 
-  public function replace($hvalues,&$info=[]) {
+       public function replace($hvalues,&$info=[]) {
                # NB 12.12.17: When REPLACE is not supported where call a personalized function to modify $sql
                $fct = $this->db()->conf_type('replace_insert');
                if (!empty($fct)) {
                        $info['fct'] = $fct;
                        return $this->insert($hvalues,$info);
                }
-    return $this->insert($hvalues,$info,'REPLACE');
-  }
+               return $this->insert($hvalues,$info,'REPLACE');
+       }
 
-  public function insert($post,&$info=[],$insert_word='INSERT') {
+       public function insert($post,&$info=[],$insert_word='INSERT') {
 
-    if (empty($info['values'])) $info['values'] = [];
-    if (empty($post)) $this->bye('insert(): No values');
+               if (empty($info['values'])) $info['values'] = [];
+               if (empty($post)) $this->bye('insert(): No values');
 
-    $sql_names = $fields = $values = [];
+               $sql_names = $fields = $values = [];
 
-    foreach ($this->fields() as $name => $field) {
-      if ($field->key and $field->autoincrement()) continue;
+               foreach ($this->fields() as $name => $field) {
+                       if ($field->key and $field->autoincrement()) continue;
 
-      if (!isset($post[$this->field_preff.$name])) {
+                       if (!isset($post[$this->field_preff.$name])) {
 
                                # For postgres and replace mode, we want to update timestamp for example
                                if (!empty($info['fct']) and isset($field->default)) {
@@ -1705,100 +1687,100 @@ Class Table extends nb {
 
                        }
 
-      $fields[$name] = $field;
-      $sql_names[$name] = $field->sql_name();
-      $values[] = $post[$this->field_preff.$name];
-    }
+                       $fields[$name] = $field;
+                       $sql_names[$name] = $field->sql_name();
+                       $values[] = $post[$this->field_preff.$name];
+               }
 
-    if (empty($fields)) $this->bye('insert(): No fields for table');
+               if (empty($fields)) $this->bye('insert(): No fields for table');
 
-    $sql = 
-      $insert_word.' INTO '. $this->sql_name() . ' (' . join(',',array_values($sql_names)).')'
-      .' VALUES (' . join(',',ar_map('":$a"',array_keys($fields))) . ')'
-    ;
+               $sql = 
+                       $insert_word.' INTO '. $this->sql_name() . ' (' . join(',',array_values($sql_names)).')'
+                       .' VALUES (' . join(',',ar_map('":$a"',array_keys($fields))) . ')'
+               ;
 
                if (!empty($info['fct'])) {
                        $fct = $info['fct'];
                        unset($info['fct']);
                        $fct($sql,$this,$fields);
                }
-    $info['sql'] = $sql;
+               $info['sql'] = $sql;
 
-    if (!($query = $this->db()->conn->prepare($sql))) {
-      $this->err_sql($sql);
-      return false;
-    }
+               if (!($query = $this->db()->conn->prepare($sql))) {
+                       $this->err_sql($sql);
+                       return false;
+               }
 
-    $info['values'] = $post;
+               $info['values'] = $post;
 
-    foreach ($fields as $name => $field) {
-      $row = [ $name => $post[$name] ];
-      $this->db()->table_row_encrypt($this,$row);
-      #debug($name.': '.$row[$name]);
-      if (!empty($info['values'][$name])) $info['values'][$name] = $row[$name];
-      $field->bindParam($query,$row[$name],":$name");
-    }
+               foreach ($fields as $name => $field) {
+                       $row = [ $name => $post[$name] ];
+                       $this->db()->table_row_encrypt($this,$row);
+                       #debug($name.': '.$row[$name]);
+                       if (!empty($info['values'][$name])) $info['values'][$name] = $row[$name];
+                       $field->bindParam($query,$row[$name],":$name");
+               }
 
-    if (self::p('debug')) {
-      $this->debug($info,1);
-      return true;
-    }
+               if (self::p('debug')) {
+                       $this->debug($info,1);
+                       return true;
+               }
 
-    if (!($execute = $query->execute())) {
-      $this->err_sql($sql);
-      return false;
-    }
+               if (!($execute = $query->execute())) {
+                       $this->err_sql($sql);
+                       return false;
+               }
 
-    $info['rowCount'] = $query->rowCount();
-    return $query->rowCount();
-  }
+               $info['rowCount'] = $query->rowCount();
+               return $query->rowCount();
+       }
 
-  public function update($post,&$info=[]) {
+       public function update($post,&$info=[]) {
 
-    $keys = [];
-    $keys_values = [];
-    $fields = [];
-    $fields_values = [];
+               $keys = [];
+               $keys_values = [];
+               $fields = [];
+               $fields_values = [];
 # NB 14.12.17     $bindParam = false; # NB 12.05.17: Not working ???? 
-    $bindParam = true; # NB 12.05.17: Not working ???? 
+               $bindParam = true; # NB 12.05.17: Not working ???? 
 
-    foreach ($this->fields() as $name => $field) {
+               foreach ($this->fields() as $name => $field) {
 
-      if ($field->extras) continue;
+                       if ($field->extras) continue;
 
-      $value = $post[$this->field_preff.$name];
+                       $value = $post[$this->field_preff.$name];
 
-      if ($field->key) {
-        $keys[] = $name;
+                       if ($field->key) {
+                               $keys[] = $name;
 
-        if (!isset($post[$this->key_preff.$name])) {
-          if ($field->key) $this->bye("Missing `$name`!");
-          continue;
-        }
+                               if (!isset($post[$this->key_preff.$name])) {
+                                       if ($field->key) $this->bye("Missing `$name`!");
+                                       continue;
+                               }
 
 # NB 12.12.17         $_value = isset($post[$this->key_preff.$name]) ? $post[$this->key_preff.$name] : null;
 
-        if (isset($post[$this->key_preff.$name])) {
-          $fields[] = $name;
-          $fields_values[] = $post[$this->key_preff.$name];
-          $keys_values[] = $post[$this->key_preff.$name];
+                               if (isset($post[$this->key_preff.$name])) {
+                                       $fields[] = $name;
+                                       $fields_values[] = $post[$this->key_preff.$name];
+                                       $keys_values[] = $post[$this->key_preff.$name];
 
-        } else {
-          $keys_values[] = $value;
-        }
+                               } else {
+                                       $keys_values[] = $value;
+                               }
 
-      } else {
+                       } else {
 
-        $fields[] = $name;
-        $fields_values[] = $value;
+                               $fields[] = $name;
+                               $fields_values[] = $value;
 
-      }
+                       }
 
-    }
+               }
 
-    $info['keys'] = array_combine($keys,$keys_values);
-    $info['fields'] = array_combine($fields,$fields_values);
-    $info['post'] = $post;
+               $info['keys'] = array_combine($keys,$keys_values);
+               $info['fields'] = array_combine($fields,$fields_values);
+               $info['post'] = $post;
 
 #bye([$keys,$keys_values]);
 #debug([$post,$this->fields()]);
@@ -1806,245 +1788,245 @@ Class Table extends nb {
 #      $fields = $keys;
 #      $fields_values = $keys_values;
 #    }
-    if (empty($fields)) $this->bye("Missing fields!");
-
-    if (empty($keys)) {
-      $this->bye("Missing keys!");
-      $keys = $fields;
-      $keys_values = $fields_values;
-    }
-
-    $sql =  ''
-      .'UPDATE ' . $this->sql_name()
-      .' SET '   . join(',',$this->ar_map('"$a=:$a"',$fields))
-      .' WHERE ' . join(' AND ',$this->ar_map('"$a=:key_$a"',$keys))
-    ;
-    #$info['sql'] = $sql;
-    $info = [ 'sql' => $sql ] + $info;
-
-    if ($bindParam and !($query = $this->db()->conn->prepare($sql))) {
-      $this->err('PDO::errorInfo(): ' .join(' ', $this->db()->conn->errorInfo()) .NB_EOL);
-      return false;
-    }
-
-    foreach ($fields as $name) {
-      #debug("$name: ".$post[$name]);
-      $row = [ $name => $post[$name] ];
-      $this->db()->table_row_encrypt($this,$row);
-      if ($bindParam) $field->bindParam($query,$row[$name],":$name");
-      $sql = str_replace(":$name",$this->field($name)->quote($row[$name]),$sql);
-    }
-
-    foreach ($info['keys'] as $name => $value) {
-      #debug("$name: ".$post[$name]);
-      if ($bindParam) $field->bindParam($query,$value,":key_$name");
-      $sql = str_replace(":key_$name",$this->field($name)->quote($value),$sql);
-    }
-
-    $info['sql'] = $sql;
-    if (!$bindParam) {
-      $query = $this->db()->conn->prepare($sql);
-    }
-    #return $sql;
-    if (self::p('debug')) {
-      $this->debug($info,1);
-      return false;
-    }
-
-    if (!($ex = $query->execute())) {
-      $this->err_sql($sql);
-      return false;
-    }
-
-    $info = [ 'rowCount' => $query->rowCount()] + $info;
-    #debug($info); return 0;
-    return $info['rowCount'];
-
-  }
-
-  public function delete($post,&$info=[]) {
-    if (empty($info['values'])) $info['values'] = [];
-    $info['values'] = $post;
-
-    $keys = $this->fields_keys();
-
-    // If no primary keys, we use all field
-    if (empty($keys)) $keys = $this->fields();
-
-    if (!($where = $this->where($keys,$post,self::$is_admin ? false : true))) {
-      err('Db.delete(): Missing keys values');
-      return null;
-    }
+               if (empty($fields)) $this->bye("Missing fields!");
+
+               if (empty($keys)) {
+                       $this->bye("Missing keys!");
+                       $keys = $fields;
+                       $keys_values = $fields_values;
+               }
+
+               $sql =  ''
+                       .'UPDATE ' . $this->sql_name()
+                       .' SET '   . join(',',$this->ar_map('"$a=:$a"',$fields))
+                       .' WHERE ' . join(' AND ',$this->ar_map('"$a=:key_$a"',$keys))
+               ;
+               #$info['sql'] = $sql;
+               $info = [ 'sql' => $sql ] + $info;
+
+               if ($bindParam and !($query = $this->db()->conn->prepare($sql))) {
+                       $this->err('PDO::errorInfo(): ' .join(' ', $this->db()->conn->errorInfo()) .NB_EOL);
+                       return false;
+               }
+
+               foreach ($fields as $name) {
+                       #debug("$name: ".$post[$name]);
+                       $row = [ $name => $post[$name] ];
+                       $this->db()->table_row_encrypt($this,$row);
+                       if ($bindParam) $field->bindParam($query,$row[$name],":$name");
+                       $sql = str_replace(":$name",$this->field($name)->quote($row[$name]),$sql);
+               }
+
+               foreach ($info['keys'] as $name => $value) {
+                       #debug("$name: ".$post[$name]);
+                       if ($bindParam) $field->bindParam($query,$value,":key_$name");
+                       $sql = str_replace(":key_$name",$this->field($name)->quote($value),$sql);
+               }
+
+               $info['sql'] = $sql;
+               if (!$bindParam) {
+                       $query = $this->db()->conn->prepare($sql);
+               }
+               #return $sql;
+               if (self::p('debug')) {
+                       $this->debug($info,1);
+                       return false;
+               }
+
+               if (!($ex = $query->execute())) {
+                       $this->err_sql($sql);
+                       return false;
+               }
+
+               $info = [ 'rowCount' => $query->rowCount()] + $info;
+               #debug($info); return 0;
+               return $info['rowCount'];
+
+       }
+
+       public function delete($post,&$info=[]) {
+               if (empty($info['values'])) $info['values'] = [];
+               $info['values'] = $post;
+
+               $keys = $this->fields_keys();
+
+               // If no primary keys, we use all field
+               if (empty($keys)) $keys = $this->fields();
+
+               if (!($where = $this->where($keys,$post,self::$is_admin ? false : true))) {
+                       err('Db.delete(): Missing keys values');
+                       return null;
+               }
 
                # NB 07.12.17: Add LIMIT 1. If a table as not primary key when want to delete only on record
 # NB 12.12.17     $sql = 'DELETE FROM ' . $this->sql_name() . $where . ($this->db()->type == 'pgsql' ? '' : ' LIMIT 1');
-    $sql = 'DELETE FROM ' . $this->sql_name() . $where . ($this->db()->conf_type('delete_no_limit') ? '' : ' LIMIT 1');
-    $info['sql'] = $sql;
+               $sql = 'DELETE FROM ' . $this->sql_name() . $where . ($this->db()->conf_type('delete_no_limit') ? '' : ' LIMIT 1');
+               $info['sql'] = $sql;
 
-    if (self::p('debug')) {
-      $this->debug($info,1);
-      return false;
-    }
+               if (self::p('debug')) {
+                       $this->debug($info,1);
+                       return false;
+               }
 
-    $query = $this->db()->exec($sql);
-    $info['rowCount'] = $query;
+               $query = $this->db()->exec($sql);
+               $info['rowCount'] = $query;
 
-    return $info['rowCount'];
-  }
+               return $info['rowCount'];
+       }
 
-  public function out($v,$head=[],$conf=[]) { return $this->db()->out($v,$head,$conf); }
+       public function out($v,$head=[],$conf=[]) { return $this->db()->out($v,$head,$conf); }
 
-  public function url_referer($default='') {
+       public function url_referer($default='') {
 
-    if (self::p('referer')) {
-      return urldecode($this->p('referer'));
+               if (self::p('referer')) {
+                       return urldecode($this->p('referer'));
 
-    } elseif(!empty($default)) {
-      return $default;
+               } elseif(!empty($default)) {
+                       return $default;
 
-    } else {
-      return '?table=' . urlencode($this->name) . (self::p('db') ? '&db='.self::p('db') : '');
+               } else {
+                       return '?table=' . urlencode($this->name) . (self::p('db') ? '&db='.self::p('db') : '');
 
-    }
+               }
 
-  }
+       }
 
 # NB 12.01.18   public function maxlengths() {
 # NB 12.01.18     $sql = 'MAX(LENGTH('.$field->sql_name(true).'))';
 # NB 12.01.18  }
 
-  public function fields_rows() {
-    $rows = array_values($this->object2array($this->fields()));
-
-    list($sql,$where,$limit,$select_count) = $this->rows_sql();
-    foreach ([
-      'maxlen' => 'MAX(LENGTH('.$this->db()->cast_text('<NAME>').'))',
-      'max' => 'MAX(<NAME>)',
-    ] as $name => $select) {
-      if (!$this->p($name)) continue;
-      $sql = '';
+       public function fields_rows() {
+               $rows = array_values($this->object2array($this->fields()));
 
-      foreach ($this->fields() as $f) {
-        $sql .= ($sql == '' ? 'SELECT ' : ', '); 
-        $sql .= str_replace('<NAME>',$f->sql_name(),$select);
-      }
+               list($sql,$where,$limit,$select_count) = $this->rows_sql();
+               foreach ([
+                       'maxlen' => 'MAX(LENGTH('.$this->db()->cast_text('<NAME>').'))',
+                       'max' => 'MAX(<NAME>)',
+               ] as $name => $select) {
+                       if (!$this->p($name)) continue;
+                       $sql = '';
 
-      $sql .= ' FROM ' . $this->sql_name() . $where . ($limit ? " LIMIT ".$limit : '');
-      $len = $this->db()->query($sql)->fetch(PDO::FETCH_NUM);
+                       foreach ($this->fields() as $f) {
+                               $sql .= ($sql == '' ? 'SELECT ' : ', '); 
+                               $sql .= str_replace('<NAME>',$f->sql_name(),$select);
+                       }
 
-      $i = 0;
-      foreach ($rows as $k => $v) { $rows[$k][$name] = $len[$i]; $i++; }
+                       $sql .= ' FROM ' . $this->sql_name() . $where . ($limit ? " LIMIT ".$limit : '');
+                       $len = $this->db()->query($sql)->fetch(PDO::FETCH_NUM);
 
-    }
+                       $i = 0;
+                       foreach ($rows as $k => $v) { $rows[$k][$name] = $len[$i]; $i++; }
 
-    return $rows;
-  }
+               }
 
-  public function action($action=null) {
+               return $rows;
+       }
 
-    if ($action == 'table.fields') {
-      $rows = $this->fields_rows();
-      return $this->out($rows);
+       public function action($action=null) {
 
-    } elseif ($action == 'table.rows') {
-      $this->db()->print_header($this->p('format'));
-      $this->rows();
-      return true;
+               if ($action == 'table.fields') {
+                       $rows = $this->fields_rows();
+                       return $this->out($rows);
 
-    } elseif ($action == 'table.info') {
-      return $this->out($this->info());
+               } elseif ($action == 'table.rows') {
+                       $this->db()->print_header($this->p('format'));
+                       $this->rows();
+                       return true;
 
-    } elseif ($action == 'table.delete') {
-      if (!$this->delete($_POST,$e) and !isset($e['rowCount'])) bye($e);
-      $this->db()->print_header('Location',$this->url_referer(str_replace('&amp;','&',$this->url_list())));
-      $this->out($e);
-      return true;
+               } elseif ($action == 'table.info') {
+                       return $this->out($this->info());
 
-    } elseif ($action == 'table.replace') {
-      if (!$this->replace($_POST,$e) and !isset($e['rowCount'])) bye($e);
-      $this->db()->print_header('Location',$this->url_referer());
-      $this->out($e);
-      return true;
+               } elseif ($action == 'table.delete') {
+                       if (!$this->delete($_POST,$e) and !isset($e['rowCount'])) bye($e);
+                       $this->db()->print_header('Location',$this->url_referer(str_replace('&amp;','&',$this->url_list())));
+                       $this->out($e);
+                       return true;
 
-    } elseif ($action == 'table.insert') {
-      if (!$this->insert($_POST,$e)) bye();
-      $this->db()->print_header('Location',$this->url_referer());
-      $this->out($e);
-      return true;
+               } elseif ($action == 'table.replace') {
+                       if (!$this->replace($_POST,$e) and !isset($e['rowCount'])) bye($e);
+                       $this->db()->print_header('Location',$this->url_referer());
+                       $this->out($e);
+                       return true;
 
-    } elseif ($action == 'table.update') {
-      if ($this->update($_POST,$e) === false) bye($e);
-      $this->db()->print_header('Location',$this->url_referer());
-      $this->out($e);
-      return true;
+               } elseif ($action == 'table.insert') {
+                       if (!$this->insert($_POST,$e)) bye();
+                       $this->db()->print_header('Location',$this->url_referer());
+                       $this->out($e);
+                       return true;
 
-    } elseif ($action == 'table.truncate') {
-      $this->db()->query('TRUNCATE '.$this->sql_name());
-      return true;
+               } elseif ($action == 'table.update') {
+                       if ($this->update($_POST,$e) === false) bye($e);
+                       $this->db()->print_header('Location',$this->url_referer());
+                       $this->out($e);
+                       return true;
 
-    } elseif (self::class_action_out($this,$action) !== null) {
-      return true;
+               } elseif ($action == 'table.truncate') {
+                       $this->db()->query('TRUNCATE '.$this->sql_name());
+                       return true;
 
-    } elseif ($this->p('format') and !preg_match('/^(table|div)$/',$this->p('format'))) {
+               } elseif (self::class_action_out($this,$action) !== null) {
+                       return true;
 
-      $opt = ['format' => $this->p('format')];
-      $this->rows($opt);
-      return true;
+               } elseif ($this->p('format') and !preg_match('/^(table|div)$/',$this->p('format'))) {
 
-    } elseif ($action == 'edit') {
-      return $this->html_edit();
+                       $opt = ['format' => $this->p('format')];
+                       $this->rows($opt);
+                       return true;
 
-    } elseif ($this->p('table')) {
-    # NB 17.03.16 } else {
-      $this->pdef('limit','20');
+               } elseif ($action == 'edit') {
+                       return $this->html_edit();
 
-      // Rows
-      return $this->rows();
+               } elseif ($this->p('table')) {
+               # NB 17.03.16 } else {
+                       $this->pdef('limit','20');
 
-    }
+                       // Rows
+                       return $this->rows();
 
-    return false;
-  }
+               }
 
-  public function html_row_buttons(&$row) {
-    if (!$this->show_buttons or empty(self::$params)) return [];
-    return [
-      (!DB_HTML_EDIT ? '' : '<a class="edit button" href="'.$this->url_keys($row,'action=edit').'">'.DB_HTML_EDIT.'</a>'.NB_EOL),
-      (!DB_HTML_DELETE ? '' : '<a class="delete button" href="'.$this->url_keys($row,'action=delete')
-        .'&amp;referer='
-        .( isset($_SERVER['REQUEST_URI']) ? urlencode($_SERVER['REQUEST_URI']) : '' )
-      .'">'.DB_HTML_DELETE.'</a>'.NB_EOL),
-    ];
-  }
+               return false;
+       }
+
+       public function html_row_buttons(&$row) {
+               if (!$this->show_buttons or empty(self::$params)) return [];
+               return [
+                       (!DB_HTML_EDIT ? '' : '<a class="edit button" href="'.$this->url_keys($row,'action=edit').'">'.DB_HTML_EDIT.'</a>'.NB_EOL),
+                       (!DB_HTML_DELETE ? '' : '<a class="delete button" href="'.$this->url_keys($row,'action=delete')
+                               .'&amp;referer='
+                               .( isset($_SERVER['REQUEST_URI']) ? urlencode($_SERVER['REQUEST_URI']) : '' )
+                       .'">'.DB_HTML_DELETE.'</a>'.NB_EOL),
+               ];
+       }
 
-  public function html_rows_top() {
-    if (self::p('replace') === '0') return '';
-    $html = '';
+       public function html_rows_top() {
+               if (self::p('replace') === '0') return '';
+               $html = '';
 
-    if (!empty($this->replace)) {
+               if (!empty($this->replace)) {
 
-      $replace = [];
-      foreach ($this->replace as $k=>$v) { $replace[] = "$k.$v"; }
-      $html .= '<span id="db-table-replace" style="display:none">'.join(' ',$replace).'</span>'.NB_EOL;
+                       $replace = [];
+                       foreach ($this->replace as $k=>$v) { $replace[] = "$k.$v"; }
+                       $html .= '<span id="db-table-replace" style="display:none">'.join(' ',$replace).'</span>'.NB_EOL;
 
-    }
+               }
 
-    return $html;
+               return $html;
 
-  }
+       }
 
-  public function count() {
+       public function count() {
 
-    if (isset($this->count)) return $this->count;
+               if (isset($this->count)) return $this->count;
 
-    $sql_count = $this->name;
+               $sql_count = $this->name;
 
-    # We could use it instead of query, but wont be cached ! $this->create_temporary();
-    if ($this->type == 'sql' and $this->name !== DB_TABLE_QUERY_NAME) {
-      if (!$this->sql) return;
+               # We could use it instead of query, but wont be cached ! $this->create_temporary();
+               if ($this->type == 'sql' and $this->name !== DB_TABLE_QUERY_NAME) {
+                       if (!$this->sql) return;
 
-      $sql_count = "SELECT COUNT(*) FROM ($this->sql) _table_count" ;
-      #debug([$this->name,$sql_count]);
+                       $sql_count = "SELECT COUNT(*) FROM ($this->sql) _table_count" ;
+                       #debug([$this->name,$sql_count]);
 # NB 08.08.17       if (preg_match('/SELECT.*SELECT|UNION/i',$this->sql)) {
 # NB 08.08.17         $sql_count = "SELECT COUNT(*) FROM ($this->sql) _table_count" ;
 # NB 08.08.17       } else {
@@ -2052,313 +2034,312 @@ Class Table extends nb {
 # NB 08.08.17         bye($sql_count);
 # NB 08.08.17       }
 
-    } elseif (preg_match('/^[\w_-]+$/',$sql_count)) {
-      $sql_count = "SELECT count(*) FROM ".$this->sql_name($sql_count);
-
-    } else {
-      $sql_count = preg_replace('/ (ORDER|LIMIT) .*?$/s','',$sql_count);
-      $sql_count = preg_replace('/^SELECT .*FROM/s','SELECT count(*) FROM ',$sql_count);
-
-    }
-
-    $this->count = (int)$this->db()->row($sql_count);
-    return $this->count;
-
-  }
-
-  public function err_sql($sql) {
-    $err = $this->db()->conn->errorInfo();
-    $err[] = $sql;
-    $this->bye(join(' | ',$err));
-  }
-
-  public function html_menu($opt=[]) {
-
-    $buttons = '<input type="submit" class="button button-small" value="Go"/>';
-    if (!empty($opt['buttons'])) $buttons = $opt['buttons'];
-
-    $r = '<form class="menu" method="get" action="?">'.NB_EOL;
-    #$r = '<form class="menu" method="get" action="'.preg_replace('/\?.*$/','',$_SERVER["REQUEST_URI"]).'">'.NB_EOL;
-
-    # See: http://html5doctor.com/html5-forms-input-types/
-    #$r .= '<input id="skill" type="range" min="1" max="100" value="0" />';
-    #$r .= '<input id="startdate" name="startdate" min="2012-01-01" max="2013-01-01" type="date" />';
-
-    //
-    // Options
-    //
-    if ($this->p('options')!=='0') {
-
-      $r .= '<div class="options">';
-
-      // Tables - see default.js if you change class
-      $tables = array_keys($this->db()->tables());
-      if (count($tables)>1) {
-        $r .= '<span class="label">';
-        $r .= '<label for="table">Tables</label>'.html_select_array($tables,[
-          'html'       => 'class="tables" name="table" id="table"',
-          'selected'   => $this->name,
-          'prettyText' => true,
-          'sort'       => 'natcasesort',
-        ]);
-        $r .= '</span>';
-      }
-
-      // Dbs - see default.js if you change class
-      if (!empty($this->db()->dbs) and count($this->db()->dbs)>1) {
-        $r .= '<span class="label">';
-        $r .= '<label for="db">Db</label>'.html_select_array($this->db()->dbs,[
-          'html'       => 'class="dbs" id="db" name="db" onchange="document.location=\''.preg_replace('/\?.*$/','',$_SERVER['REQUEST_URI']).'?db=\'+this.value"',
-          'selected'   => $this->db()->name,
-          'prettyText' => true,
-          'sort' => 'natcasesort',
-        ]);
-        $r .= '</span>';
-      }
-
-      // Format
-      $r .= '<span class="label">';
-      #debug($this->db()->formats);
-      $r .= '<label for="format">Format</label>'.html_select_array($this->db()->formats,[
-        'html'       => 'class="format" name="format" id="format"',
-        'selected'   => $this->db()->format,
-        'prettyText' => true,
+               } elseif (preg_match('/^[\w_-]+$/',$sql_count)) {
+                       $sql_count = "SELECT count(*) FROM ".$this->sql_name($sql_count);
+
+               } else {
+                       $sql_count = preg_replace('/ (ORDER|LIMIT) .*?$/s','',$sql_count);
+                       $sql_count = preg_replace('/^SELECT .*FROM/s','SELECT count(*) FROM ',$sql_count);
+
+               }
+
+               $this->count = (int)$this->db()->row($sql_count);
+               return $this->count;
+
+       }
+
+       public function err_sql($sql) {
+               $err = $this->db()->conn->errorInfo();
+               $err[] = $sql;
+               $this->bye(join(' | ',$err));
+       }
+
+       public function html_menu($opt=[]) {
+
+               $buttons = '<input type="submit" class="button button-small" value="Go"/>';
+               if (!empty($opt['buttons'])) $buttons = $opt['buttons'];
+
+               $r = '<form class="menu" method="get" action="?">'.NB_EOL;
+               #$r = '<form class="menu" method="get" action="'.preg_replace('/\?.*$/','',$_SERVER["REQUEST_URI"]).'">'.NB_EOL;
+
+               # See: http://html5doctor.com/html5-forms-input-types/
+               #$r .= '<input id="skill" type="range" min="1" max="100" value="0" />';
+               #$r .= '<input id="startdate" name="startdate" min="2012-01-01" max="2013-01-01" type="date" />';
+
+               //
+               // Options
+               //
+               if ($this->p('options')!=='0') {
+
+                       $r .= '<div class="options">';
+
+                       // Tables - see default.js if you change class
+                       $tables = array_keys($this->db()->tables());
+                       if (count($tables)>1) {
+                               $r .= '<span class="label">';
+                               $r .= '<label for="table">Tables</label>'.html_select_array($tables,[
+                                       'html'       => 'class="tables" name="table" id="table"',
+                                       'selected'   => $this->name,
+                                       'prettyText' => true,
+                                       'sort'       => 'natcasesort',
+                               ]);
+                               $r .= '</span>';
+                       }
+
+                       // Dbs - see default.js if you change class
+                       if (!empty($this->db()->dbs) and count($this->db()->dbs)>1) {
+                               $r .= '<span class="label">';
+                               $r .= '<label for="db">Db</label>'.html_select_array($this->db()->dbs,[
+                                       'html'       => 'class="dbs" id="db" name="db" onchange="document.location=\''.preg_replace('/\?.*$/','',$_SERVER['REQUEST_URI']).'?db=\'+this.value"',
+                                       'selected'   => $this->db()->name,
+                                       'prettyText' => true,
+                                       'sort' => 'natcasesort',
+                               ]);
+                               $r .= '</span>';
+                       }
+
+                       // Format
+                       $r .= '<span class="label">';
+                       #debug($this->db()->formats);
+                       $r .= '<label for="format">Format</label>'.html_select_array($this->db()->formats,[
+                               'html'       => 'class="format" name="format" id="format"',
+                               'selected'   => $this->db()->format,
+                               'prettyText' => true,
 # NB 26.12.16         'sort'       => 'natcasesort',
-      ]);
-      $r .= '</span>';
-
-      // Limit
-      if (!empty($this->db()->limits) and count($this->db()->limits)>1) {
-        $r .= '<span class="label">';
-        $r .= '<label for="limit">Limit</label>'.html_select_array($this->db()->limits,[
-          'html'       => 'class="limit" name="limit" id="limit"',
-          'selected'   => $this->p('limit'),
-          'prettyText' => true,
-          'sort' => 'sort',
-          'default_value' => $this->db()->limits[0],
-        ]);
-        $r .= '</span>';
-      }
-
-      // Submit
-      $r .= $buttons;
-
-      // Order By
-      /*
-      $r .= '<span class="label">';
-      $r .= '<label for="limit">OrderBy</label>'.html_select_array(array_keys($this->fields()),[
-        'html'       => 'class="orderby" name="orderby" id="orderby"',
-        'selected'   => $this->p('orderby'),
-        'prettyText' => true,
-      ]);
-      $r .= '</span>';
-      */
-
-      // Hiddens
-      $form_hidden = ['db','table','format','limit','download'];
-      if ($this->show_hidden_params) $r .= ''#.print_r(self::$params,true)
-        .self::form_hidden($form_hidden)
-        // Embed for no html format (rent)
-        .'<input type="'.($this->p('debug') ? 'text' : 'hidden').'" name="download" value="0"/>';
-      ;
-
-      $r .= '</div>'; # < Options
-
-    }
-
-    //
-    // Criterias
-    //
-    $r .= '<div class="criterias">';
-    foreach ( $this->fields() as $k => $f) {
-
-      if ($f->is_encrypt()) continue;
-      $v = $this->p($k);
-
-      $r .= ''
-        .'<span class="label '.$k.'">'
-        . '<label>'.prettyText($k).'</label>'
-        . '<input type="text" id="'.$k.'" name="'.$this->field_preff.$k.'" value="'.$v.'" />'
-        .'</span>'
-      ;
-
-    }
-
-    if ($this->p('options')==='0') $r .= $buttons;
-    $r .= '</div>'; # < Criterias
-
-    ///
-    // Bye
-    ///
-    $r .= '</form>'.NB_EOL;
-    return $r;
-  }
-
-  public function __sleep() {
-    return [
-      'name',
-      'sql',
-      'type',
-      'fields',
-      'extras',
-      'row_parse_pre',
-      'row_parse_post',
-      'count',
-      'engine',
-      'created',
-    ];
-  }
-
-  public function serialize() {
-    $this->fields();
-    #$this->count();
-    return serialize($this);
-  }
-
-  public function unserialize() {
-    $o = unserialize($this->serialize());
-    return var_export($o,true);
-  }
-
-  public function type() {
-    if (isset($this->type)) return $this->type;
-    return $this->type = $this->status('type');
-  }
-
-  public function unvar($value) {
-    if (empty($value)) return $value;
-    if (!is_scalar($value)) {
-      foreach ($value as $k=>$v) {
-        if (is_scalar($v)) $value[$k] = $this->unvar($v);
-      }
-      return $value;
-    }
-    $replace = [
-      '<T.NAME>' => $this->name,
-      '<T.TYPE>' => $this->type,
-    ];
-    return str_replace(array_keys($replace),array_values($replace),$value);
-  }
-
-  public function status($key=null) {
-
-    if (!isset($this->status)) {
-
-      if ($this->type == 'sql') {
-
-        $this->status = [
-          'type' => $this->type,
-          'name' => $this->name,
-        ];
-
-      } else {
-
-        $this->create_temporary();
-        $sql = $this->db()->method('tables');
-        if (!$this->p('count')) $sql .= " LIMIT 0";
-        $sql = "SELECT * FROM ($sql) t WHERE name=".$this->db()->quote($this->name);
-
-        $sth = $this->db()->conn->query($sql,PDO::FETCH_ASSOC);
-        if (!empty($sth)) $this->status = $sth->fetch();
-
-      } # if ($this->type == 'sql')
-
-      if (empty($this->status)) $this->status = [];
-
-      # Add to status array
-      foreach ([
-        'name',
-        'type',
-      ] as $k) {
-        if (!empty($this->$k)) $this->status[$k] = $this->$k;
-      }
-
-      # Add from status array
-      foreach ([
-        'engine',
-        'created',
-      ] as $k) {
-        if (empty($this->$k) and !empty($this->status[$k])) $this->$k = $this->status[$k];
-      }
-    }
-
-    # Params
-    foreach ([
-      'count',
-      'fields',
-      'sql',
-    ] as $k) {
-      if (isset($this->status[$k])) continue;
+                       ]);
+                       $r .= '</span>';
+
+                       // Limit
+                       if (!empty($this->db()->limits) and count($this->db()->limits)>1) {
+                               $r .= '<span class="label">';
+                               $r .= '<label for="limit">Limit</label>'.html_select_array($this->db()->limits,[
+                                       'html'       => 'class="limit" name="limit" id="limit"',
+                                       'selected'   => $this->p('limit'),
+                                       'prettyText' => true,
+                                       'sort' => 'sort',
+                                       'default_value' => $this->db()->limits[0],
+                               ]);
+                               $r .= '</span>';
+                       }
+
+                       // Submit
+                       $r .= $buttons;
+
+                       // Order By
+                       /*
+                       $r .= '<span class="label">';
+                       $r .= '<label for="limit">OrderBy</label>'.html_select_array(array_keys($this->fields()),[
+                               'html'       => 'class="orderby" name="orderby" id="orderby"',
+                               'selected'   => $this->p('orderby'),
+                               'prettyText' => true,
+                       ]);
+                       $r .= '</span>';
+                       */
+
+                       // Hiddens
+                       $form_hidden = ['db','table','format','limit','download'];
+                       if ($this->show_hidden_params) $r .= ''#.print_r(self::$params,true)
+                               .self::form_hidden($form_hidden)
+                               // Embed for no html format (rent)
+                               .'<input type="'.($this->p('debug') ? 'text' : 'hidden').'" name="download" value="0"/>';
+                       ;
+
+                       $r .= '</div>'; # < Options
+
+               }
+
+               //
+               // Criterias
+               //
+               $r .= '<div class="criterias">';
+               foreach ( $this->fields() as $k => $f) {
+
+                       if ($f->is_encrypt()) continue;
+                       $v = $this->p($k);
+
+                       $r .= ''
+                               .'<span class="label '.$k.'">'
+                               . '<label>'.prettyText($k).'</label>'
+                               . '<input type="text" id="'.$k.'" name="'.$this->field_preff.$k.'" value="'.$v.'" />'
+                               .'</span>'
+                       ;
+
+               }
+
+               if ($this->p('options')==='0') $r .= $buttons;
+               $r .= '</div>'; # < Criterias
+
+               ///
+               // Bye
+               ///
+               $r .= '</form>'.NB_EOL;
+               return $r;
+       }
+
+       public function __sleep() {
+               return [
+                       'name',
+                       'sql',
+                       'type',
+                       'fields',
+                       'extras',
+                       'row_parse_pre',
+                       'row_parse_post',
+                       'count',
+                       'engine',
+                       'created',
+               ];
+       }
+
+       public function serialize() {
+               $this->fields();
+               #$this->count();
+               return serialize($this);
+       }
+
+       public function unserialize() {
+               $o = unserialize($this->serialize());
+               return var_export($o,true);
+       }
+
+       public function type() {
+               if (isset($this->type)) return $this->type;
+               return $this->type = $this->status('type');
+       }
+
+       public function unvar($value) {
+               if (empty($value)) return $value;
+               if (!is_scalar($value)) {
+                       foreach ($value as $k=>$v) {
+                               if (is_scalar($v)) $value[$k] = $this->unvar($v);
+                       }
+                       return $value;
+               }
+               $replace = [
+                       '<T.NAME>' => $this->name,
+                       '<T.TYPE>' => $this->type,
+               ];
+               return str_replace(array_keys($replace),array_values($replace),$value);
+       }
+
+       public function status($key=null) {
+
+               if (!isset($this->status)) {
+
+                       if ($this->type == 'sql') {
+
+                               $this->status = [
+                                       'type' => $this->type,
+                                       'name' => $this->name,
+                               ];
+
+                       } else {
+
+                               $this->create_temporary();
+                               $sql = $this->db()->method('tables');
+                               if (!$this->p('count')) $sql .= " LIMIT 0";
+                               $sql = "SELECT * FROM ($sql) t WHERE name=".$this->db()->quote($this->name);
+
+                               $sth = $this->db()->conn->query($sql,PDO::FETCH_ASSOC);
+                               if (!empty($sth)) $this->status = $sth->fetch();
+
+                       } # if ($this->type == 'sql')
+
+                       if (empty($this->status)) $this->status = [];
+
+                       # Add to status array
+                       foreach ([
+                               'name',
+                               'type',
+                       ] as $k) {
+                               if (!empty($this->$k)) $this->status[$k] = $this->$k;
+                       }
+
+                       # Add from status array
+                       foreach ([
+                               'engine',
+                               'created',
+                       ] as $k) {
+                               if (empty($this->$k) and !empty($this->status[$k])) $this->$k = $this->status[$k];
+                       }
+               }
+
+               # Params
+               foreach ([
+                       'count',
+                       'fields',
+                       'sql',
+               ] as $k) {
+                       if (isset($this->status[$k])) continue;
 # NB 08.08.17       if (!empty($this->status[$k])) continue;
 
-      if (empty($key)) {
-        if (!$this->p($k)) continue;
+                       if (empty($key)) {
+                               if (!$this->p($k)) continue;
 
-      } elseif(is_array($key)) {
-        if (!in_array($k,$key)) continue;
+                       } elseif(is_array($key)) {
+                               if (!in_array($k,$key)) continue;
 
-      } else {
-        if ($k!=$key) continue;
-      }
+                       } else {
+                               if ($k!=$key) continue;
+                       }
 
-      $this->status[$k] = $this->$k();
-      if (is_array($this->status[$k])) $this->status[$k] = count($this->status[$k]);
-    }
+                       $this->status[$k] = $this->$k();
+                       if (is_array($this->status[$k])) $this->status[$k] = count($this->status[$k]);
+               }
 
-    if (!empty($key) and is_scalar($key)) return ( empty($this->status[$key]) ? '' : $this->status[$key] );
-    return $this->status;
-  }
+               if (!empty($key) and is_scalar($key)) return ( empty($this->status[$key]) ? '' : $this->status[$key] );
+               return $this->status;
+       }
 
-  private function idtemplate($id=null) {
-    if (empty($id)
-      and !( $id=$this->p('idtemplate') )
-      and !( $id = $this->idtemplate )
-    ) $this->bye('Wrong parameter!');
-    return $id;
-  }
+       private function idtemplate($id=null) {
+               if (empty($id)
+                       and !( $id=$this->p('idtemplate') )
+                       and !( $id = $this->idtemplate )
+               ) $this->bye('Wrong parameter!');
+               return $id;
+       }
 
-  public function template($id=null) {
-    $id = $this->idtemplate($id);
+       public function template($id=null) {
+               $id = $this->idtemplate($id);
 
-    $id = preg_replace('/[^\w\._-]/','',$id);
+               $id = preg_replace('/[^\w\._-]/','',$id);
 
-    $file = TABLE_TEMPLATE.'/'.$id.'.php';
-    if (!is_readable($file)) return false; #$this->bye("Wrong id `$id`");
+               $file = TABLE_TEMPLATE.'/'.$id.'.php';
+               if (!is_readable($file)) return false; #$this->bye("Wrong id `$id`");
 
-    $opt = [ 'format'=> '' ];
-    $this->rows($opt);
+               $opt = [ 'format'=> '' ];
+               $this->rows($opt);
 
-    $HEAD = &$opt['var']['head'];
-    $ROWS = &$opt['var']['rows'];
-    $ROW = &$opt['var']['rows'][0];
-    foreach ($ROWS as $key=>$row) {
-      $i=0;
-      foreach ($row as $k=>$v) {
-        $ROWS[$key][$i] = $v;
-        $i++;
-      }
-    }
-    #$opt['var']['rows']=[];
+               $HEAD = &$opt['var']['head'];
+               $ROWS = &$opt['var']['rows'];
+               $ROW = &$opt['var']['rows'][0];
+               foreach ($ROWS as $key=>$row) {
+                       $i=0;
+                       foreach ($row as $k=>$v) {
+                               $ROWS[$key][$i] = $v;
+                               $i++;
+                       }
+               }
+               #$opt['var']['rows']=[];
 
-    # Protect $_REQUEST !
-    $_REQUEST_BAK = $_REQUEST;
-    $_REQUEST = array_merge($_REQUEST,$ROW);
+               # Protect $_REQUEST !
+               $_REQUEST_BAK = $_REQUEST;
+               $_REQUEST = array_merge($_REQUEST,$ROW);
 
-    $ex = require $file;
+               $ex = require $file;
 
-    $_REQUEST = $_REQUEST_BAK;
+               $_REQUEST = $_REQUEST_BAK;
 
-    #return $ex;
-  }
+               #return $ex;
+       }
 
-  public function ssha_password($password) {
-    return $this->db()->ssha_password($password);
-  }
+       public function ssha_password($password) {
+               return $this->db()->ssha_password($password);
+       }
 
-  static public function _bye($msg = '__bye__', $backtrace_deep = 0) {
-    die($msg);
-  }
+       static public function _bye($msg = '__bye__', $backtrace_deep = 0) {
+               die($msg);
+       }
 
 } # < Class
-__table_define();
 ?>