]> git.nbdom.net Git - nb.git/commitdiff
share/templates/test.php
authorNicolas Boisselier <nicolas.boisselier@gmail.com>
Fri, 8 Dec 2017 06:44:30 +0000 (06:44 +0000)
committerNicolas Boisselier <nicolas.boisselier@gmail.com>
Fri, 8 Dec 2017 06:44:30 +0000 (06:44 +0000)
lib/php/nb.php
share/templates/test.php [new file with mode: 0644]
www/dbq/dbq.php

index 33c43c406aa5eadf0e1d069a843d7c522bb77fa8..0c8709556239b3bbdf8ce22cdada6f8ade1ecbd6 100644 (file)
@@ -1048,6 +1048,16 @@ class NB {
 
     return $code;
   }
+
+  public static function http_user() {
+    foreach ([
+      'PHP_AUTH_USER',
+      'REMOTE_USER',
+    ] as $k) {
+      if (!empty($_SERVER[$k])) return $_SERVER[$k];
+    }
+  }
+
 } # < Class
 
 /*
diff --git a/share/templates/test.php b/share/templates/test.php
new file mode 100644 (file)
index 0000000..8711cbc
--- /dev/null
@@ -0,0 +1,5 @@
+<?php
+       foreach ($ROW as $k=>$v) {
+               echo "$k => $v\n";
+       }
+?>
index b409c8c3a4bbf2ad1536bdb6d7120f0de347f571..e86007a11e9d4166974628eef12551189a4fed78 100644 (file)
@@ -7,858 +7,877 @@ require_once(NB_ROOT.'/lib/php/http.php');
 require_once(NB_ROOT.'/lib/php/mime.php');
 
 function dbqErrHandle($errNo, $errStr, $errFile, $errLine) {
-    $msg = "$errStr in $errFile on line $errLine";
-    if ($errNo == E_NOTICE || $errNo == E_WARNING) {
-        header("HTTP/1.0 500 Internal Server Error");
-        throw new ErrorException($msg, $errNo);
-    } else {
-        echo $msg;
-    }
+               $msg = "$errStr in $errFile on line $errLine";
+               if ($errNo == E_NOTICE || $errNo == E_WARNING) {
+                               header("HTTP/1.0 500 Internal Server Error");
+                               throw new ErrorException($msg, $errNo);
+               } else {
+                               echo $msg;
+               }
 }
 
 set_error_handler('dbqErrHandle');
 
 class DbQ extends nb {
 
-  const ACTIONS_NO_TITLE = ['ls','vi'];
-  const PARAM_DB_DEFAULT = 'ls';
-  
-  const ADMIN = 9;
-  const DELETE = 4;
-  const WRITE = 3;
-  const READ = 1;
-  public $perm = self::ADMIN;
-  public $perms = [ # keys in lowercase !!!!
-    'admin' => self::ADMIN,
-    'delete' => self::DELETE,
-    'write' => self::WRITE,
-    'read' => self::READ,
-  ];
-
-  public $title = 'Dbq';
-  public $sep_title = ' / ';
-
-  public $format_cli = 'human';
-  public $format_html = 'table';
-  public $format_html_ua_exp = '/^\S+\s+.Windows|iPhone|Android|Macintosh|Linux/';
-
-  public $hide_keys_exp = 'PHP_AUTH_DIGEST|PHP_AUTH_PW|PHP_AUTH_USER|REMOTE_PASSWORD|Authorization|HTTP_AUTHORIZATION';
-  public $hide_keys_value = '****************';
-
-  public $uri;
-  public $uri_params;
-  private $param_args_sep = ' ';
-  private $param_exp_value = '[\w\._:-]{2,100}';
-
-  public $params = [
-    'format' => '',
-    'db' => '',
-    'table' => '',
-    'action' => '',
-    'args' => '',
-  ];
-  public $params_deep = []; # contain index in case if we decide to use a regexp
-
-  # Db
-  #public $limits = [];
-  public $default_limit = '30';
-  public $limits = ['30','100','500','1000'];
-  public $formats = [ 'html','csv','xml','json','yaml','sh','sql','php' ];
-  public $is_html;
-
-  # Page
-  public $css = '/default'.(PRODUCTION ? '.min' : '').'.css';
-  public $js = '/default'.(PRODUCTION ? '.min' : '').'.js';
-  public $ext;
-
-  # Others
-  public $expode_args = '&';
-
-  # Object
-  public $page;
-  public $table;
-  public $db;
-
-  public function __construct($opt=[]) {
-    //
-    // Pre defaults values
-
-    //
-    // Init
-    $this->parse_uri();
-
-    // Envs -> var
-    foreach ([
-      'perm',
-      'title',
-      'css',
-      'js',
-      'format_html_ua_exp'
-    ] as $k) {
-      $env = 'DBQ_'.strtoupper($k);
-
-      if (isset($_SERVER[$env])) $this->$k = $_SERVER[$env];
-    }
-
-    // Envs -> params
-    foreach ([
-      'format',
-      'db',
-      'table',
-    ] as $k) {
-      $env = 'DBQ_PARAM_'.strtoupper($k);
-      if (!empty($_SERVER[$env])) $this->params[$k] = $_SERVER[$env];
-    }
-
-    $run = isset($opt['run']) ? $opt['run'] : false;
-    unset($opt['run']);
-
-    // Format perm into int value
-    $perm = strtolower($this->perm);
-    if (isset($this->perms[$perm])) $this->perm = $this->perms[$perm];
-    if (!preg_match('/^[0-9]+$/',$perm)) $perm = 0;
-
-    parent::__construct($opt);
-
-    //
-    // Page
-    require_once(NB_ROOT.'/lib/php/page.php');
-
-    $this->page = new Page([
-      'css' => $this->css,
-      'sep' => $this->sep_title,
-      #'body_class' => 'fixed',
-    ]);
-
-    if ($run) $this->run();
-  }
-
-  public function conf() {
-    $rows = [];
-    foreach ($this->conf as $k=>$v) $rows[] = ['name'=>$k,'value'=>$v];
-    return $rows;
-  }
-
-  public function limit($set=false) {
-    static $limit = false;
-    if ($set !== false) return ($limit = $set);
-
-    if ($limit !== false) return $limit;
-
-    if ($limit = $this->p('limit')) return $limit;
-    if ($this->page->is('html')) return ($limit = $this->default_limit);
-
-  }
-
-  public function page($obj,$meth=null,$head=[],$fct=null) {
-
-    // Defaults
-    if (empty($head)) $head = [];
-    if (empty($this->default_limit)) $this->default_limit = $this->db->limits[0];
-
-    // Write output
-    if (empty($this->_nopage)) {
-
-      $this->page->headers_no_cache();
-      $this->page->js = $this->js;
-      $this->conf = [
-        'db.base' => ( empty($this->db) ? '' : $this->db->base ),
-        'table.base' => ( empty($this->table) ? '' : $this->table->base ),
-        'default.format' => $this->format_html,
-        'default.limit' => $this->default_limit,
-        'param.format' => $this->params['format'],
-        'param.db' => $this->params['db'],
-        'param.table' => $this->params['table'],
-        'param.action' => $this->params['action'],
-        'param.args' => $this->params['args'],
-        'param.deep' => $this->params_deep,
-        'text.add' => 'Add New',
-        'text.clear' => 'Clear',
-        'perm' => $this->perm,
-        'perms' => $this->perms,
-      ];
-      $this->page->js_code = 'window._dbq = '.json_encode($this->conf);
+       const ACTIONS_NO_TITLE = ['ls','vi'];
+       const PARAM_DB_DEFAULT = 'ls';
+       
+       const ADMIN = 9;
+       const DELETE = 4;
+       const WRITE = 3;
+       const READ = 1;
+       public $perm = self::ADMIN;
+       public $perms = [ # keys in lowercase !!!!
+               'admin' => self::ADMIN,
+               'delete' => self::DELETE,
+               'write' => self::WRITE,
+               'read' => self::READ,
+       ];
+
+       public $title = 'Dbq';
+       public $sep_title = ' / ';
+
+       public $format_cli = 'human';
+       public $format_html = 'table';
+       public $format_html_ua_exp = '/^\S+\s+.Windows|iPhone|Android|Macintosh|Linux/';
+
+       public $hide_keys_exp = 'PHP_AUTH_DIGEST|PHP_AUTH_PW|PHP_AUTH_USER|REMOTE_PASSWORD|Authorization|HTTP_AUTHORIZATION';
+       public $hide_keys_value = '****************';
+
+       public $uri;
+       public $uri_params;
+       private $param_args_sep = ' ';
+       private $param_exp_value = '[\w\._:-]{2,100}';
+
+       public $params = [
+               'format' => '',
+               'db' => '',
+               'table' => '',
+               'action' => '',
+               'args' => '',
+       ];
+       public $params_deep = []; # contain index in case if we decide to use a regexp
+
+       # Db
+       #public $limits = [];
+       public $default_limit = '30';
+       public $limits = ['30','100','500','1000'];
+       public $formats = [ 'html','csv','xml','json','yaml','sh','sql','php' ];
+       public $is_html;
+
+       # Page
+       public $css = '/default'.(PRODUCTION ? '.min' : '').'.css';
+       public $js = '/default'.(PRODUCTION ? '.min' : '').'.js';
+       public $ext;
+
+       # Others
+       public $expode_args = '&';
+
+       # Object
+       public $page;
+       public $table;
+       public $db;
+
+       public function __construct($opt=[]) {
+               //
+               // Pre defaults values
+
+               //
+               // Init
+               $this->parse_uri();
+
+               // Envs -> var
+               foreach ([
+                       'perm',
+                       'title',
+                       'css',
+                       'js',
+                       'format_html_ua_exp'
+               ] as $k) {
+                       $env = 'DBQ_'.strtoupper($k);
+
+                       if (isset($_SERVER[$env])) $this->$k = $_SERVER[$env];
+               }
+
+               // Envs -> params
+               foreach ([
+                       'format',
+                       'db',
+                       'table',
+               ] as $k) {
+                       $env = 'DBQ_PARAM_'.strtoupper($k);
+                       if (!empty($_SERVER[$env])) $this->params[$k] = $_SERVER[$env];
+               }
+
+               $run = isset($opt['run']) ? $opt['run'] : false;
+               unset($opt['run']);
+
+               // Format perm into int value
+               $perm = strtolower($this->perm);
+               if (isset($this->perms[$perm])) $this->perm = $this->perms[$perm];
+               if (!preg_match('/^[0-9]+$/',$perm)) $perm = 0;
+
+               parent::__construct($opt);
+
+               //
+               // Page
+               require_once(NB_ROOT.'/lib/php/page.php');
+
+               $this->page = new Page([
+                       'css' => $this->css,
+                       'sep' => $this->sep_title,
+                       #'body_class' => 'fixed',
+               ]);
+
+               if ($run) $this->run();
+       }
+
+       public function conf() {
+               $rows = [];
+               foreach ($this->conf as $k=>$v) $rows[] = ['name'=>$k,'value'=>$v];
+               return $rows;
+       }
+
+       public function limit($set=false) {
+               static $limit = false;
+               if ($set !== false) return ($limit = $set);
+
+               if ($limit !== false) return $limit;
+
+               if ($limit = $this->p('limit')) return $limit;
+               if ($this->page->is('html')) return ($limit = $this->default_limit);
+
+       }
+
+       public function page($obj,$meth=null,$head=[],$fct=null) {
+
+               // Defaults
+               if (empty($head)) $head = [];
+               if (empty($this->default_limit)) $this->default_limit = $this->db->limits[0];
+
+               // Write output
+               if (empty($this->_nopage)) {
+
+                       $this->page->headers_no_cache();
+                       $this->page->js = $this->js;
+                       $this->conf = [
+                               'db.base' => ( empty($this->db) ? '' : $this->db->base ),
+                               'table.base' => ( empty($this->table) ? '' : $this->table->base ),
+                               'default.format' => $this->format_html,
+                               'default.limit' => $this->default_limit,
+                               'param.format' => $this->params['format'],
+                               'param.db' => $this->params['db'],
+                               'param.table' => $this->params['table'],
+                               'param.action' => $this->params['action'],
+                               'param.args' => $this->params['args'],
+                               'param.deep' => $this->params_deep,
+                               'text.add' => 'Add New',
+                               'text.clear' => 'Clear',
+                               'perm' => $this->perm,
+                               'perms' => $this->perms,
+                       ];
+                       $this->page->js_code = 'window._dbq = '.json_encode($this->conf);
 
 # NB 22.05.17       if (is_scalar($obj) and $obj != 'logout') {
-      if ($obj != 'logout') {
-        list($title,$nav) = $this->title_nav();
-        $this->page->title = join($this->sep_title,$title);
-        $this->page->nav = $nav;
-      }
-
-      $this->page->body_class = ''
-        .(empty($this->params['db']) ? '' : ' db-'.$this->params['db'])
-        .(empty($this->params['table']) ? '' : ' table-'.$this->params['table'])
-        .(empty($this->params['action']) ? ' action-'.self::PARAM_DB_DEFAULT : ' action-'.($this->params['action'] == 'add' ? 'vi' : $this->params['action']))
-
-      ;
-      $this->page->begin();
-    }
-
-    #die($obj);
-    #if (is_scalar($obj)) {
-    $conf = ['row_parse_post'=>$fct];
+                       if ($obj != 'logout') {
+                               list($title,$nav) = $this->title_nav();
+                               $this->page->title = join($this->sep_title,$title);
+                               $this->page->nav = $nav;
+                       }
 
-    $rows = '';
-    if (is_array($obj)) {
-      $rows = $obj;
+                       $this->page->body_class = ''
+                               .(empty($this->params['db']) ? '' : ' db-'.$this->params['db'])
+                               .(empty($this->params['table']) ? '' : ' table-'.$this->params['table'])
+                               .(empty($this->params['action']) ? ' action-'.self::PARAM_DB_DEFAULT : ' action-'.($this->params['action'] == 'add' ? 'vi' : $this->params['action']))
 
-    } elseif (empty($meth)) {
-      echo $obj;
+                       ;
+                       $this->page->begin();
+               }
 
-    } elseif (is_array($meth)) {
-      $rows = $meth;
+               #die($obj);
+               #if (is_scalar($obj)) {
+               $conf = ['row_parse_post'=>$fct];
 
-    } elseif(is_scalar($meth)) { # Objects Method
-      $rows = $obj->$meth();
-      if (empty($this->params['table'])) $this->params['table'] = $meth;
+               $rows = '';
+               if (is_array($obj)) {
+                       $rows = $obj;
 
-    } else {
-      $this->error("Page error");
-
-    }
+               } elseif (empty($meth)) {
+                       echo $obj;
 
-    if (!empty($rows)) $this->db->out($rows,$head,$conf);
-
-    if (empty($this->_nopage)) $this->page->end();
-    exit;
-  }
-
-  public function user() {
-    if (!empty($_SERVER['REMOTE_USER'])) return $_SERVER['REMOTE_USER']; # empty since jessie
-    if (!empty($_SERVER['PHP_AUTH_USER'])) return $_SERVER['PHP_AUTH_USER'];
-  }
-
-  public function db($connect=[]) {
-
-    // Connect
-    if (!empty($connect)) {
-
-      if (!$this->params['db']) $this->not_implemented('Params db missing');
-      if (!isset($this->db)) $this->db = $this->db();
-
-      # From conf
-      if (!is_array($connect)
-        and $connect === true
-      ) {
-        if (empty($this->db->conf[$this->params['db']]))
-          $this->not_found('Unknown db: '.$this->params['db']);
-        $connect = $this->db->conf[$this->params['db']];
-      }
-
-      $connect['id'] = $this->params['db'];
-
-      $this->db->__construct($connect);
-      $this->db->connect();
-      $this->db->base = '/'.$this->db->id;
-      return $this->db;
-    }
-
-    // Re use
-    if (!empty($this->db)) return $this->db;
-    require_once(NB_ROOT.'/lib/php/db.php');
-
-    // New
-    global $DB_CONFS;
-    if (!empty($_SERVER['DBQ_CONF_DIR'])) {
-      $DB_CONFS = Db::conf_load(array_merge(
-        (array)glob($_SERVER['DBQ_CONF_DIR'].'/*.yml'),
-        (array)glob($_SERVER['DBQ_CONF_DIR'].'/*.yaml'),
-        (array)glob($_SERVER['DBQ_CONF_DIR'].'/*.php'),
-      []));
-
-    } elseif (!empty($_SERVER['DBQ_CONF_FILE'])) {
-      $DB_CONFS = Db::conf_load(explode(' ',$_SERVER['DBQ_CONF_FILE']));
-
-    } else {
-      require_once(NB_ROOT.'/lib/php/db/config.php');
-    }
-    $this->db = new Db(['conf'=>$DB_CONFS]);
-    $this->db->base = '';
-
-    return $this->db;
-  }
-
-  public function add() {
-    $this->vi(true);
-  }
-
-  private function vi_extract_fields() {
-    $sep = $this->param_args_sep . $this->param_args_sep;
-    #$sep ='@';
-
-    $fields = [];
-    if (strpos($this->params['args'],$sep) !== false) {
-      list($fields,$this->params['args']) = explode($sep, $this->params['args']);
-      $fields = explode(',',$fields);
-    }
+               } elseif (is_array($meth)) {
+                       $rows = $meth;
 
-    return $fields;
-  }
-
-  public function vi($add=false) {
-    $all = [];
-
-    $keys = $this->table->fields_keys($all);
-    if (!$keys) $keys = $all;
-    $keys = array_keys($keys);
+               } elseif(is_scalar($meth)) { # Objects Method
+                       $rows = $obj->$meth();
+                       if (empty($this->params['table'])) $this->params['table'] = $meth;
 
-    $fields = $this->vi_extract_fields();
+               } else {
+                       $this->error("Page error");
 
-    $values = $add ? array_fill(0,count($keys),'') : explode($this->param_args_sep,$this->params['args']);
-    $values = array_combine($keys,$values);
+               }
 
-    # NB 23.11.17: Handle format for /vi/ 
-    if ($this->params['format'] != $this->format_html) {
+               if (!empty($rows)) $this->db->out($rows,$head,$conf);
 
-      $row = $this->db->query2h($this->table->sql_edit($values));
-      if ($fields) {
-        foreach ($row as $k=>$v) {
-          if (!in_array($k,$fields)) unset($row[$k]);
-        }
-      }
+               if (empty($this->_nopage)) {
 
-      if ($this->params['format'] == $this->format_cli) $this->db->format = $this->params['format'] = 'txt';
-      $this->db->out->header($this->p('header',false));
-      $this->db->out($row);
-      return;
-    }
+                       $bottom = [];
 
-    $this->table->html_edit($values,
-      $this->table->base . '/' . ($add ? 'insert' : 'update' . '/' . urlencode($this->params['args'])) . '/'
-    ,$add);
-  }
+                       if ($this->perm >= self::ADMIN and !empty($this->db->pdo)) {
+                               $r = [
+                               '/(^|;)password=[^;]*/' => '',
+                               '/;/' => ' ',
+                               ];
+                               $bottom[] = 'Database: '.preg_replace(array_keys($r),$r,$this->db->pdo);
+                       }
 
-  public function table_rw() {
-    return (1
-      and ($this->perm >= self::READ)
-      and !empty($this->table)
-        and ( strpos('table view',$this->table->type()) !== false )
-    );
-  }
-
-  public function table_rows($fct=null) {
-    $this->db->limit = $this->limit();
-
-    $opt = ($this->page->is('html')
-      and $this->table_rw()
-    ) ? [
-      'row_parse_pre' => function(&$r){
-        $GLOBALS['dbq_args'] = urlencode( join($this->param_args_sep,$this->table->fields_keys_values($r)) );
-      },
-      'row_parse_post' => function(&$r){
+                       #debug($_SERVER);
+                       if ($this->http_user()) $bottom[] = '<a href="/logout">Logout: '.$this->http_user().' ('.$this->perm2h().')'.'</a>';
 
-        $args = $GLOBALS['dbq_args'];
+                       if ($bottom and $this->page->is('html')) echo $this->page->tag('div class="block" style="display:inline-block"',join('<br />'.NB_EOL,$bottom));
 
-        $r = ['view' => join(' ',[
-          '<a class="button select vi" href="'.$this->table->base.'/vi/'.$args.'/">View</a>'
-        ]) ] + $r;
+                       $this->page->end();
+               }
 
-        if ($this->perm < self::DELETE) return;
-        if ($this->db->type == 'sqlite' and !is_writeable($this->db->host)) return;
+               exit;
+       }
 
-        $rm = $this->table->base.'/rm/'.$args;
-        $r['delete'] = ''
-          .'<form action="'.$rm.'" method="post">'
-          .'<a class="button rm" href="'.$rm.'" onclick="parentNode.submit();return false;">Delete</a>'
-          .$this->form_hidden($r)
-          .'</form>'
-        ;
+       public function user() {
+               if (!empty($_SERVER['REMOTE_USER'])) return $_SERVER['REMOTE_USER']; # empty since jessie
+               if (!empty($_SERVER['PHP_AUTH_USER'])) return $_SERVER['PHP_AUTH_USER'];
+       }
 
-      },
-    ] : [];
+       public function db($connect=[]) {
 
-    $this->table->rows($opt);
-    unset($GLOBALS['dbq_args']);
-  }
+               // Connect
+               if (!empty($connect)) {
+
+                       if (!$this->params['db']) $this->not_implemented('Params db missing');
+                       if (!isset($this->db)) $this->db = $this->db();
+
+                       # From conf
+                       if (!is_array($connect)
+                               and $connect === true
+                       ) {
+                               if (empty($this->db->conf[$this->params['db']]))
+                                       $this->not_found('Unknown db: '.$this->params['db']);
+                               $connect = $this->db->conf[$this->params['db']];
+                       }
+
+                       $connect['id'] = $this->params['db'];
+
+                       $this->db->__construct($connect);
+                       $this->db->connect();
+                       $this->db->base = '/'.$this->db->id;
+                       return $this->db;
+               }
+
+               // Re use
+               if (!empty($this->db)) return $this->db;
+               require_once(NB_ROOT.'/lib/php/db.php');
+
+               // New
+               global $DB_CONFS;
+               if (!empty($_SERVER['DBQ_CONF_DIR'])) {
+                       $DB_CONFS = Db::conf_load(array_merge(
+                               (array)glob($_SERVER['DBQ_CONF_DIR'].'/*.yml'),
+                               (array)glob($_SERVER['DBQ_CONF_DIR'].'/*.yaml'),
+                               (array)glob($_SERVER['DBQ_CONF_DIR'].'/*.php'),
+                       []));
+
+               } elseif (!empty($_SERVER['DBQ_CONF_FILE'])) {
+                       $DB_CONFS = Db::conf_load(explode(' ',$_SERVER['DBQ_CONF_FILE']));
+
+               } else {
+                       require_once(NB_ROOT.'/lib/php/db/config.php');
+               }
+               $this->db = new Db(['conf'=>$DB_CONFS]);
+               $this->db->base = '';
 
+               return $this->db;
+       }
+
+       public function add() {
+               $this->vi(true);
+       }
 
-  public static function form_hidden($r) {
-    $h = '';
-    foreach ($r as $k => $v) {
-      $h .= '<input type="hidden" name="'.htmlentities($k).'" value="'.htmlentities($v).'"/>';
-    }
-    return $h;
-  }
+       private function vi_extract_fields() {
+               $sep = $this->param_args_sep . $this->param_args_sep;
+               #$sep ='@';
 
+               $fields = [];
+               if (strpos($this->params['args'],$sep) !== false) {
+                       list($fields,$this->params['args']) = explode($sep, $this->params['args']);
+                       $fields = explode(',',$fields);
+               }
 
-  public function table($param=[]) {
+               return $fields;
+       }
 
-    if (!in_array($this->params['table'],array_keys($this->db->tables()))) {
+       public function vi($add=false) {
+               $all = [];
+
+               $keys = $this->table->fields_keys($all);
+               if (!$keys) $keys = $all;
+               $keys = array_keys($keys);
+
+               $fields = $this->vi_extract_fields();
+
+               $values = $add ? array_fill(0,count($keys),'') : explode($this->param_args_sep,$this->params['args']);
+               $values = array_combine($keys,$values);
+
+               # NB 23.11.17: Handle format for /vi/ 
+               if ($this->params['format'] != $this->format_html) {
 
-      # We Allow SELECT only in admin
-      if ($this->perm < self::ADMIN or !preg_match('/^SELECT /',$this->params['table'])) {
-        $this->not_found('Unknown table: '.$this->params['table']);
-      }
+                       $row = $this->db->query2h($this->table->sql_edit($values));
+                       if ($fields) {
+                               foreach ($row as $k=>$v) {
+                                       if (!in_array($k,$fields)) unset($row[$k]);
+                               }
+                       }
 
-    }
+                       if ($this->params['format'] == $this->format_cli) $this->db->format = $this->params['format'] = 'txt';
+                       $this->db->out->header($this->p('header',false));
+                       $this->db->out($row);
+                       return;
+               }
 
-    $this->table = $this->db->table($this->params['table'],array_merge([
-      'db' => $this->db,
-      'show_hidden_params' => false,
-      'show_buttons' => false,
-      'show_header' => $this->is_html,
-    ],$param));
+               $this->table->html_edit($values,
+                       $this->table->base . '/' . ($add ? 'insert' : 'update' . '/' . urlencode($this->params['args'])) . '/'
+               ,$add);
+       }
 
-    $this->table->base = $this->db->base.'/'.$this->table->name;
+       public function table_rw() {
+               return (1
+                       and ($this->perm >= self::READ)
+                       and !empty($this->table)
+                               and ( strpos('table view',$this->table->type()) !== false )
+               );
+       }
+
+       public function table_rows($fct=null) {
+               $this->db->limit = $this->limit();
+
+               $opt = ($this->page->is('html')
+                       and $this->table_rw()
+               ) ? [
+                       'row_parse_pre' => function(&$r){
+                               $GLOBALS['dbq_args'] = urlencode( join($this->param_args_sep,$this->table->fields_keys_values($r)) );
+                       },
+                       'row_parse_post' => function(&$r){
 
-  }
+                               $args = $GLOBALS['dbq_args'];
 
-  public function title_nav() {
-    $params = $this->params;
-    $ext = $this->ext;
+                               $r = ['view' => join(' ',[
+                                       '<a class="button select vi" href="'.$this->table->base.'/vi/'.$args.'/">View</a>'
+                               ]) ] + $r;
 
-    $title = [];
-    if (!empty($this->title)) $title['title'] = $this->title;
+                               if ($this->perm < self::DELETE) return;
+                               if ($this->db->type == 'sqlite' and !is_writeable($this->db->host)) return;
 
-    foreach (array_unique(array_slice(array_keys($params),1,3)) as $k) {
-      if (in_array($k,self::ACTIONS_NO_TITLE)) continue;
-      $v = $params[$k];
-      if ($v) $title[$k] = $v;
-    }
+                               $rm = $this->table->base.'/rm/'.$args;
+                               $r['delete'] = ''
+                                       .'<form action="'.$rm.'" method="post">'
+                                       .'<a class="button rm" href="'.$rm.'" onclick="parentNode.submit();return false;">Delete</a>'
+                                       .$this->form_hidden($r)
+                                       .'</form>'
+                               ;
 
+                       },
+               ] : [];
 
-    $path = '/';
-    $nav = [];
+               $this->table->rows($opt);
+               unset($GLOBALS['dbq_args']);
+       }
 
-    $i = 0;
-    foreach ($title as $k=>$v) {
 
-      if ($i == 0) {
-        $nav[] = [$v,'/'];
+       public static function form_hidden($r) {
+               $h = '';
+               foreach ($r as $k => $v) {
+                       $h .= '<input type="hidden" name="'.htmlentities($k).'" value="'.htmlentities($v).'"/>';
+               }
+               return $h;
+       }
 
-      } else {
 
-        $nav[] = [
-          $this->prettyText($v),
-          [
-            'href' => "$path" . urlencode($v) . "." . $ext,
-            'class' => $k,
-          ],
-        ];
+       public function table($param=[]) {
 
-        $path .= $v . "/";
-        $title[$k] = $this->prettyText($v);
+               if (!in_array($this->params['table'],array_keys($this->db->tables()))) {
 
-      }
+                       # We Allow SELECT only in admin
+                       if ($this->perm < self::ADMIN or !preg_match('/^SELECT /',$this->params['table'])) {
+                               $this->not_found('Unknown table: '.$this->params['table']);
+                       }
 
-      $i++;
+               }
 
-    }
+               $this->table = $this->db->table($this->params['table'],array_merge([
+                       'db' => $this->db,
+                       'show_hidden_params' => false,
+                       'show_buttons' => false,
+                       'show_header' => $this->is_html,
+               ],$param));
 
-    return [array_values($title),$nav];
-  }
+               $this->table->base = $this->db->base.'/'.$this->table->name;
 
-  public function parse_uri() {
-    #
-    # Parse path, respect params order
-    #
-    $values = [];
-    $path = '';
-    $args = '';
+       }
 
-    if (empty($_SERVER['REQUEST_URI'])) $_SERVER['REQUEST_URI'] = join('/',( count($GLOBALS['argv'])>0 ) ? array_slice($GLOBALS['argv'],1) : []);
+       public function title_nav() {
+               $params = $this->params;
+               $ext = $this->ext;
 
-    list ($path,$args) = strpos($_SERVER['REQUEST_URI'],'?') ? explode('?',$_SERVER['REQUEST_URI']) : [$_SERVER['REQUEST_URI'],''];
-    $this->uri = $path;
-    $this->uri_params = explode($this->expode_args,$args);
+               $title = [];
+               if (!empty($this->title)) $title['title'] = $this->title;
 
-    if (preg_match('/\.(\w+)$/',$path,$m)) {
-      $values[] = $m[1];
-      $path = substr($path,0,strlen($path)-strlen($m[1])-1);
-    } else {
-      $values[] = '';
-    }
+               foreach (array_unique(array_slice(array_keys($params),1,3)) as $k) {
+                       if (in_array($k,self::ACTIONS_NO_TITLE)) continue;
+                       $v = $params[$k];
+                       if ($v) $title[$k] = $v;
+               }
 
-    $path = trim($path,'/');
-    if ($path) $values = array_merge($values,explode('/',$path));
 
-    $i=0;
-    $count = count($values);
-    #var_export($values);
+               $path = '/';
+               $nav = [];
 
-    foreach ($this->params as $p => $default) {
-      #if ($i>=$count) break;
+               $i = 0;
+               foreach ($title as $k=>$v) {
 
-      if ($i<$count) {
+                       if ($i == 0) {
+                               $nav[] = [$v,'/'];
 
-        # Can be overwrite by get request
-        if (isset($_GET[$p])) $values[$i] = $_GET[$p];
+                       } else {
 
-        # Sanitize
-        if ($values[$i]!=='') {
+                               $nav[] = [
+                                       $this->prettyText($v),
+                                       [
+                                               'href' => "$path" . urlencode($v) . "." . $ext,
+                                               'class' => $k,
+                                       ],
+                               ];
 
-          $values[$i] = urldecode($values[$i]);
+                               $path .= $v . "/";
+                               $title[$k] = $this->prettyText($v);
 
-          if (
-            $this->perm < self::ADMIN
-            and
-            !preg_match('/^'.$this->param_exp_value.'$/',$values[$i])
-          ) $this->error('Wrong value');
+                       }
 
-          $this->params[$p] = $values[$i];
+                       $i++;
 
-        }
+               }
 
-        $this->params_deep[$p] = $i;
-      }
+               return [array_values($title),$nav];
+       }
 
-      $i++;
+       public function parse_uri() {
+               #
+               # Parse path, respect params order
+               #
+               $values = [];
+               $path = '';
+               $args = '';
 
-    }
+               if (empty($_SERVER['REQUEST_URI'])) $_SERVER['REQUEST_URI'] = join('/',( count($GLOBALS['argv'])>0 ) ? array_slice($GLOBALS['argv'],1) : []);
 
-    return $this->params;
-  }
+               list ($path,$args) = strpos($_SERVER['REQUEST_URI'],'?') ? explode('?',$_SERVER['REQUEST_URI']) : [$_SERVER['REQUEST_URI'],''];
+               $this->uri = $path;
+               $this->uri_params = explode($this->expode_args,$args);
 
-  public function not_found($admin_msg='') {
-    header('Content-type: text/plain');
-    $msg = '404 Not Found';
+               if (preg_match('/\.(\w+)$/',$path,$m)) {
+                       $values[] = $m[1];
+                       $path = substr($path,0,strlen($path)-strlen($m[1])-1);
+               } else {
+                       $values[] = '';
+               }
 
-    if (empty($_SERVER['SERVER_PROTOCOL'])) $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0';
+               $path = trim($path,'/');
+               if ($path) $values = array_merge($values,explode('/',$path));
 
-    header($_SERVER['SERVER_PROTOCOL'].' '.$msg);
-    echo "$msg\n";
+               $i=0;
+               $count = count($values);
+               #var_export($values);
 
-    if (!empty($admin_msg) and $this->perm >= self::ADMIN) echo "$admin_msg\n";
-    exit;
-  }
+               foreach ($this->params as $p => $default) {
+                       #if ($i>=$count) break;
 
-  public function error($admin_msg='') {
-    header('Content-type: text/plain');
-    $msg = '500 Internal Server Error';
+                       if ($i<$count) {
 
-    if (empty($_SERVER['SERVER_PROTOCOL'])) $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0';
+                               # Can be overwrite by get request
+                               if (isset($_GET[$p])) $values[$i] = $_GET[$p];
 
-    header($_SERVER['SERVER_PROTOCOL'].' '.$msg);
-    echo "$msg\n";
+                               # Sanitize
+                               if ($values[$i]!=='') {
 
-    if (!empty($admin_msg) and $this->perm >= self::ADMIN) echo "$admin_msg\n";
-    exit;
-  }
+                                       $values[$i] = urldecode($values[$i]);
 
-  public function not_implemented($admin_msg='') {
-    header('Content-type: text/plain');
-    $msg = '501 Not Implemented';
-    if (empty($_SERVER['SERVER_PROTOCOL'])) $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0';
-    header($_SERVER['SERVER_PROTOCOL'].' '.$msg);
-    echo "$msg\n";
-    if (!empty($admin_msg) and $this->perm >= self::READ) echo "$admin_msg\n";
-    exit;
-  }
+                                       if (
+                                               $this->perm < self::ADMIN
+                                               and
+                                               !preg_match('/^'.$this->param_exp_value.'$/',$values[$i])
+                                       ) $this->error('Wrong value');
 
-  public function ssha512_password($password='') {
-    if ($password=='') {
-      if ($password=='') $password = $this->params['table'];
-      if ($password=='' and !empty($_POST['password'])) $password = $_POST['password'];
-      if ($this->is_html) echo <<<EOF
+                                       $this->params[$p] = $values[$i];
+
+                               }
+
+                               $this->params_deep[$p] = $i;
+                       }
+
+                       $i++;
+
+               }
+
+               return $this->params;
+       }
+
+       public function not_found($admin_msg='') {
+               header('Content-type: text/plain');
+               $msg = '404 Not Found';
+
+               if (empty($_SERVER['SERVER_PROTOCOL'])) $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0';
+
+               header($_SERVER['SERVER_PROTOCOL'].' '.$msg);
+               echo "$msg\n";
+
+               if (!empty($admin_msg) and $this->perm >= self::ADMIN) echo "$admin_msg\n";
+               exit;
+       }
+
+       public function error($admin_msg='') {
+               header('Content-type: text/plain');
+               $msg = '500 Internal Server Error';
+
+               if (empty($_SERVER['SERVER_PROTOCOL'])) $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0';
+
+               header($_SERVER['SERVER_PROTOCOL'].' '.$msg);
+               echo "$msg\n";
+
+               if (!empty($admin_msg) and $this->perm >= self::ADMIN) echo "$admin_msg\n";
+               exit;
+       }
+
+       public function not_implemented($admin_msg='') {
+               header('Content-type: text/plain');
+               $msg = '501 Not Implemented';
+               if (empty($_SERVER['SERVER_PROTOCOL'])) $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0';
+               header($_SERVER['SERVER_PROTOCOL'].' '.$msg);
+               echo "$msg\n";
+               if (!empty($admin_msg) and $this->perm >= self::READ) echo "$admin_msg\n";
+               exit;
+       }
+
+       public function ssha512_password($password='') {
+               if ($password=='') {
+                       if ($password=='') $password = $this->params['table'];
+                       if ($password=='' and !empty($_POST['password'])) $password = $_POST['password'];
+                       if ($this->is_html) echo <<<EOF
 <form action="$this->uri" method="post" class="block" style="padding:1.5em">
 <label>Password</label><input type="text" name="password" value="$password" />
 <input type="submit" />
 </form>
 EOF;
-    }
-    return $this->db->ssha512_password($password);
-  }
-
-  public function ssha_password($password='') {
-    if ($password=='') {
-      if ($password=='') $password = $this->params['table'];
-      if ($password=='' and !empty($_POST['password'])) $password = $_POST['password'];
-      if ($this->is_html) echo <<<EOF
+               }
+               return $this->db->ssha512_password($password);
+       }
+
+       public function ssha_password($password='') {
+               if ($password=='') {
+                       if ($password=='') $password = $this->params['table'];
+                       if ($password=='' and !empty($_POST['password'])) $password = $_POST['password'];
+                       if ($this->is_html) echo <<<EOF
 <form action="$this->uri" method="post" class="block" style="padding:1.5em">
 <label>Password</label><input type="text" name="password" value="$password" />
 <input type="submit" />
 </form>
 EOF;
-    }
-    return $this->db->ssha_password($password);
-  }
-
-  public function perm2h() {
-    foreach ($this->perms as $k => $v) {
-      if ( strtolower($this->perm) === strtolower($v) ) return $k;
-    }
-    return $this->perm;
-  }
-
-  public function status() { #$this->perm--;
-    $rows = [];
-
-    // Server
-    foreach ([
-      'addr',
-      'port',
-      'software',
-      'remote_user',
-    ] as $k) {
-      if ($this->perm < self::ADMIN and $k == 'software') continue;
-
-      $v = 'SERVER_'.strtoupper($k);
-      $v = isset($_SERVER[$v]) ? $_SERVER[$v] : '';
-      if ($v==='') continue;
-
-      $rows[] = [ 'name' => 'server.'.$k, 'value' => $v ];
-    }
-
-    // Client headers
-    foreach ($this->client_header() as $k=>$v) {
-      if ( preg_match('/^(' . $this->hide_keys_exp . ')$/', $k)) $v = $this->hide_keys_value;
-      if ($k == 'Host') continue;
-
-      $rows[] = [
-        'name' => 'client.header.'.$k,
-        'value' => ( is_scalar($v) ? $v : json_encode($v) ),
-      ];
-    }
-
-    // Admin or bye !
-    #if ($this->perm < self::ADMIN) return $rows;
-
-    /*
-    // Headers sent
-    foreach (headers_list() as $v) {
-      list($k,$v) = explode(': ',$v);
-      $rows[] = [
-        'name' => 'server.header.'.$k,
-        'value' => ( is_scalar($v) ? $v : json_encode($v) ),
-      ];
-    }
-    */
-
-    // Dbq
-    if ($this->client_content_type()) $rows[] = [
-      'name' => 'dbq.client_content_type',
-      'value' => $this->client_content_type(),
-    ];
-    $rows[] = [
-      'name' => 'dbq.page.content_type',
-      'value' => $this->page->content_type(),
-    ];
-    $rows[] = [
-      'name' => 'dbq.params.format',
-      'value' => $this->params['format'],
-    ];
-    if (0) $rows[] = [
-      'name' => 'dbq.page.is.html',
-      'value' => ($this->page->is('html') ? 1 : 0),
-    ];
-    $user = '';
-    if (true or $user = $this->logged()) {
-      if ($user) $rows[] = [ 'name' => 'dbq.user.name', 'value' => $user ];
-      $rows[] = [ 'name' => 'dbq.user.perm', 'value' => $this->perm2h() ];
-    }
-
-    // Machine
-    if ($this->perm >= self::ADMIN)
-    if (function_exists('posix_uname')) {
-      foreach (posix_uname() as $k => $v) {
-        if ($k == 'domainname' and $v == '(none)') continue;
-        $rows[] = [ 'name' => 'posix.uname.'.$k, 'value' => $v ];
-      }
-    }
-
-    return $rows;
-  }
-
-  public function run_init() {
-    $this->db();
-
-    // Format first !
-    if ($this->params['format']) {
-      $format = $this->params['format'];
-
-    } else if ($content_type = self::client_content_type() and ( $format=Mime::toExt($content_type) )) {
-      #$format = $format;
-
-    } else {
-      $format = 
-        (!empty($_SERVER['HTTP_USER_AGENT']) and preg_match($this->format_html_ua_exp,$_SERVER['HTTP_USER_AGENT']))
-          ? 'html'
-          : $this->format_cli
-      ;
-
-    }
-
-    // Post defaults values
-    if (empty($this->ext)) $this->ext = $format;
-
-    if (!empty($this->formats)) $this->db->formats = $this->formats;
-    if (!empty($this->limits)) $this->db->limits = $this->limits;
-
-    // Then content type
-    if (empty($content_type)) $content_type = Mime::fromExt($format==$this->format_cli ? 'txt' : $format);
-    if (empty($content_type) and $this->db->out->is_html($format)) $content_type = 'text/html';
-    if (empty($content_type)) $content_type = 'text/plain';
-    if ($content_type) $this->page->content_type($content_type);
-
-    // Affect values to objects
-    if ($format == 'html') $format = $this->format_html;
-    $this->params['format'] = $format;
-    $this->db->format = $format;
-    $this->is_html = strpos($content_type,'html') ? true : false;
-    $this->db->is_html = $this->is_html;
-
-    #if ( $format == 'json' and isset($_GET['json']) ) {
-    #bye($this->p('json'));
-    /*
-    if ( $format == 'json' and isset($_POST['json']) ) {
-      #bye($_POST['json']);
-      #$this->pset($this->json_decode($_POST['json']));
-      $_POST = $this->json_decode($_POST['json']);
-      #bye($this->p());
-    }
-
-    if ( $format == 'json' and $this->p('json') ) {
-      #bye($this->p('json'));
-      #bye($this->json_decode($this->p('json')));
-      #bye($this->json_decode('{"id": "2"}'));
-      $this->pset($this->json_decode($this->p('json')));
-    }
-     */
-
-  }
-
-  public function phpinfo_rows() {
-    $txt = $this->page->is('html') ? 0 : 1;
-
-    if (0 and !$this->page->is('html')) {
-      return $this->page->phpinfo();
-      #return $this->page($this->page->phpinfo($txt));
-    }
-
-    $rows = [];
-    $row = [];
-    $section = '';
-    $p = [
-      'section' => $this->p('section',''),
-      'name' => $this->p('name',''),
-      'value' => $this->p('value',''),
-    ];
-
-    foreach (explode("\n",$this->page->phpinfo()) as $line) {
-
-      if (preg_match(',<h2[^>]*>(.*?)</h2>,',$line,$m)) {
-        $section = strtoupper(strip_tags(preg_replace('/\W+/','_',$m[1])));
-
-      } elseif (preg_match_all(',<td>(.*?)</td>,',$line,$m)) {
-        $name = strip_tags($m[1][0]);
-        $value = isset($m[1][1]) ? strip_tags($m[1][1]) : '';
-
-        if (preg_match('/^\$_([A-Z_]+)\[["\']([^"\']+)["\']\]/',$name,$m)) {
-          $_section = $m[1];
-          $name = $m[2];
-        } else {
-          $_section = $section;
-        }
-
-        #debug($m);
-        if ($p['name'] and !$this->str_match($name,$p['name'])) continue;
-        if ($p['value'] and !$this->str_match($value,$p['value'])) continue;
-        if ($p['section'] and !$this->str_match($_section,$p['section'])) continue;
-
-        if (
-          $_section == 'PHP_VARIABLES'
-          and preg_match('/^(._SERVER\[.)?(.' . $this->hide_keys_exp . ')(.\])?$/', $name)
-        ) {
-          $value = $this->hide_keys_value;
-        }
-
-        $rows[] = [
-          'section' => $_section,
-          'name' => $name,
-          'value' => $value,
-        ];
-
-      } else {
-        #debug($sec." ".$line);
-      }
-
-    }
-
-    return $rows;
-    #return $this->page($rows);
-  }
-
-  public function rows_table($name,$rows) {
-    $this->params['table'] = $name;
-    $this->params['db'] = ' ';
-
-    $this->db->conf[ $this->params['db'] ] = [
-      'name' => $this->params['table'],
-      'type' => 'sqlite',
-      'host' => ':memory:',
-      'type' => 'sqlite',
-      'tables' => [ $this->params['table'] => [
-          'rows' => $rows
-      ] ],
-    ];
-    $this->db->__construct($this->db->conf[ $this->params['db'] ]);
-    if (empty($this->db->conn)) $this->db(true);
-
-    if (empty($this->table)) $this->table();
-    #$this->table->base = '';
-
-    $this->page($this,'table_rows');
-
-  }
-
-  public function logged() {
-    if (!empty($_SERVER['PHP_AUTH_USER'])) return $_SERVER['PHP_AUTH_USER'];
-    if (!empty($_SERVER['REMOTE_USER'])) return $_SERVER['REMOTE_USER'];
-    return '';
-  }
-
-  public function logout() {
-
-    if (0) {
-      unset($_SERVER["PHP_AUTH_DIGEST"]);
-      unset($_SERVER['PHP_AUTH_PW']);
-      unset($_SERVER['PHP_AUTH_USER']);
-      unset($_SERVER['REMOTE_PASSWORD']);
-      unset($_SERVER['REMOTE_USER']);
-
-      #header('Content-type: text/html');
-      if (!empty($_REQUEST['realm'])) header('WWW-Authenticate: Basic realm="'.$_REQUEST['realm'].'"');
-      else header('WWW-Authenticate: Basic');
-
-    }
-
-    header('HTTP/1.1 401 Access Denied');
-    header('HTTP/1.1 401 Unauthorized');
-    if (1) echo <<<EOF
+               }
+               return $this->db->ssha_password($password);
+       }
+
+       public function perm2h() {
+               foreach ($this->perms as $k => $v) {
+                       if ( strtolower($this->perm) === strtolower($v) ) return $k;
+               }
+               return $this->perm;
+       }
+
+       public function status() { #$this->perm--;
+               $rows = [];
+
+               // Server
+               foreach ([
+                       'addr',
+                       'port',
+                       'software',
+                       'remote_user',
+               ] as $k) {
+                       if ($this->perm < self::ADMIN and $k == 'software') continue;
+
+                       $v = 'SERVER_'.strtoupper($k);
+                       $v = isset($_SERVER[$v]) ? $_SERVER[$v] : '';
+                       if ($v==='') continue;
+
+                       $rows[] = [ 'name' => 'server.'.$k, 'value' => $v ];
+               }
+
+               // Client headers
+               foreach ($this->client_header() as $k=>$v) {
+                       if ( preg_match('/^(' . $this->hide_keys_exp . ')$/', $k)) $v = $this->hide_keys_value;
+                       if ($k == 'Host') continue;
+
+                       $rows[] = [
+                               'name' => 'client.header.'.$k,
+                               'value' => ( is_scalar($v) ? $v : json_encode($v) ),
+                       ];
+               }
+
+               // Admin or bye !
+               #if ($this->perm < self::ADMIN) return $rows;
+
+               /*
+               // Headers sent
+               foreach (headers_list() as $v) {
+                       list($k,$v) = explode(': ',$v);
+                       $rows[] = [
+                               'name' => 'server.header.'.$k,
+                               'value' => ( is_scalar($v) ? $v : json_encode($v) ),
+                       ];
+               }
+               */
+
+               // Dbq
+               if ($this->client_content_type()) $rows[] = [
+                       'name' => 'dbq.client_content_type',
+                       'value' => $this->client_content_type(),
+               ];
+               $rows[] = [
+                       'name' => 'dbq.page.content_type',
+                       'value' => $this->page->content_type(),
+               ];
+               $rows[] = [
+                       'name' => 'dbq.params.format',
+                       'value' => $this->params['format'],
+               ];
+               if (0) $rows[] = [
+                       'name' => 'dbq.page.is.html',
+                       'value' => ($this->page->is('html') ? 1 : 0),
+               ];
+               $user = '';
+               if (true or $user = $this->logged()) {
+                       if ($user) $rows[] = [ 'name' => 'dbq.user.name', 'value' => $user ];
+                       $rows[] = [ 'name' => 'dbq.user.perm', 'value' => $this->perm2h() ];
+               }
+
+               // Machine
+               if ($this->perm >= self::ADMIN)
+               if (function_exists('posix_uname')) {
+                       foreach (posix_uname() as $k => $v) {
+                               if ($k == 'domainname' and $v == '(none)') continue;
+                               $rows[] = [ 'name' => 'posix.uname.'.$k, 'value' => $v ];
+                       }
+               }
+
+               return $rows;
+       }
+
+       public function run_init() {
+               $this->db();
+
+               // Format first !
+               if ($this->params['format']) {
+                       $format = $this->params['format'];
+
+               } else if ($content_type = self::client_content_type() and ( $format=Mime::toExt($content_type) )) {
+                       #$format = $format;
+
+               } else {
+                       $format = 
+                               (!empty($_SERVER['HTTP_USER_AGENT']) and preg_match($this->format_html_ua_exp,$_SERVER['HTTP_USER_AGENT']))
+                                       ? 'html'
+                                       : $this->format_cli
+                       ;
+
+               }
+
+               // Post defaults values
+               if (empty($this->ext)) $this->ext = $format;
+
+               if (!empty($this->formats)) $this->db->formats = $this->formats;
+               if (!empty($this->limits)) $this->db->limits = $this->limits;
+
+               // Then content type
+               if (empty($content_type)) $content_type = Mime::fromExt($format==$this->format_cli ? 'txt' : $format);
+               if (empty($content_type) and $this->db->out->is_html($format)) $content_type = 'text/html';
+               if (empty($content_type)) $content_type = 'text/plain';
+               if ($content_type) $this->page->content_type($content_type);
+
+               // Affect values to objects
+               if ($format == 'html') $format = $this->format_html;
+               $this->params['format'] = $format;
+               $this->db->format = $format;
+               $this->is_html = strpos($content_type,'html') ? true : false;
+               $this->db->is_html = $this->is_html;
+
+               #if ( $format == 'json' and isset($_GET['json']) ) {
+               #bye($this->p('json'));
+               /*
+               if ( $format == 'json' and isset($_POST['json']) ) {
+                       #bye($_POST['json']);
+                       #$this->pset($this->json_decode($_POST['json']));
+                       $_POST = $this->json_decode($_POST['json']);
+                       #bye($this->p());
+               }
+
+               if ( $format == 'json' and $this->p('json') ) {
+                       #bye($this->p('json'));
+                       #bye($this->json_decode($this->p('json')));
+                       #bye($this->json_decode('{"id": "2"}'));
+                       $this->pset($this->json_decode($this->p('json')));
+               }
+                */
+
+       }
+
+       public function phpinfo_rows() {
+               $txt = $this->page->is('html') ? 0 : 1;
+
+               if (0 and !$this->page->is('html')) {
+                       return $this->page->phpinfo();
+                       #return $this->page($this->page->phpinfo($txt));
+               }
+
+               $rows = [];
+               $row = [];
+               $section = '';
+               $p = [
+                       'section' => $this->p('section',''),
+                       'name' => $this->p('name',''),
+                       'value' => $this->p('value',''),
+               ];
+
+               foreach (explode("\n",$this->page->phpinfo()) as $line) {
+
+                       if (preg_match(',<h2[^>]*>(.*?)</h2>,',$line,$m)) {
+                               $section = strtoupper(strip_tags(preg_replace('/\W+/','_',$m[1])));
+
+                       } elseif (preg_match_all(',<td>(.*?)</td>,',$line,$m)) {
+                               $name = strip_tags($m[1][0]);
+                               $value = isset($m[1][1]) ? strip_tags($m[1][1]) : '';
+
+                               if (preg_match('/^\$_([A-Z_]+)\[["\']([^"\']+)["\']\]/',$name,$m)) {
+                                       $_section = $m[1];
+                                       $name = $m[2];
+                               } else {
+                                       $_section = $section;
+                               }
+
+                               #debug($m);
+                               if ($p['name'] and !$this->str_match($name,$p['name'])) continue;
+                               if ($p['value'] and !$this->str_match($value,$p['value'])) continue;
+                               if ($p['section'] and !$this->str_match($_section,$p['section'])) continue;
+
+                               if (
+                                       $_section == 'PHP_VARIABLES'
+                                       and preg_match('/^(._SERVER\[.)?(.' . $this->hide_keys_exp . ')(.\])?$/', $name)
+                               ) {
+                                       $value = $this->hide_keys_value;
+                               }
+
+                               $rows[] = [
+                                       'section' => $_section,
+                                       'name' => $name,
+                                       'value' => $value,
+                               ];
+
+                       } else {
+                               #debug($sec." ".$line);
+                       }
+
+               }
+
+               return $rows;
+               #return $this->page($rows);
+       }
+
+       public function rows_table($name,$rows) {
+               $this->params['table'] = $name;
+               $this->params['db'] = ' ';
+
+               $this->db->conf[ $this->params['db'] ] = [
+                       'name' => $this->params['table'],
+                       'type' => 'sqlite',
+                       'host' => ':memory:',
+                       'type' => 'sqlite',
+                       'tables' => [ $this->params['table'] => [
+                                       'rows' => $rows
+                       ] ],
+               ];
+               $this->db->__construct($this->db->conf[ $this->params['db'] ]);
+               if (empty($this->db->conn)) $this->db(true);
+
+               if (empty($this->table)) $this->table();
+               #$this->table->base = '';
+
+               $this->page($this,'table_rows');
+
+       }
+
+       public function logged() {
+               if (!empty($_SERVER['PHP_AUTH_USER'])) return $_SERVER['PHP_AUTH_USER'];
+               if (!empty($_SERVER['REMOTE_USER'])) return $_SERVER['REMOTE_USER'];
+               return '';
+       }
+
+       public function logout() {
+
+               if (0) {
+                       unset($_SERVER["PHP_AUTH_DIGEST"]);
+                       unset($_SERVER['PHP_AUTH_PW']);
+                       unset($_SERVER['PHP_AUTH_USER']);
+                       unset($_SERVER['REMOTE_PASSWORD']);
+                       unset($_SERVER['REMOTE_USER']);
+
+                       #header('Content-type: text/html');
+                       if (!empty($_REQUEST['realm'])) header('WWW-Authenticate: Basic realm="'.$_REQUEST['realm'].'"');
+                       else header('WWW-Authenticate: Basic');
+
+               }
+
+               header('HTTP/1.1 401 Access Denied');
+               header('HTTP/1.1 401 Unauthorized');
+               if (1) echo <<<EOF
 <script type="text/javascript">
 document.addEventListener("DOMContentLoaded", function(event){
 function dbq_logout(referrer='') {
 
-  if (referrer == '') referrer = document.referrer;
-  var userAgent = navigator.userAgent.toLowerCase();
-
-  if (userAgent.indexOf("msie") != -1) {
-    document.execCommand("ClearAuthenticationCache", false);
-  }
-
-  var http;
-  if (window.XMLHttpRequest) {
-    http = new XMLHttpRequest();
-  } else if(window.ActiveXObject) {
-    http = new ActiveXObject("Microsoft.XMLHTTP");
-  } else {
-    alert ("Your browser is too old, please close your browser to logout.");
-    return false;
-  }
-
-  /*
-  if (referrer) document.location = referrer;
-  return;
-  */
-  var url = '/logout/';
-  http.open("GET", url, true, '\\0', 'password');
-  http.onload = function() {
-    if (!this.status || this.readyState != 4) return;
-    if (referrer) { document.location = referrer; return; }
-    // document.location = '/';
-  };
-  http.send();
+       if (referrer == '') referrer = document.referrer;
+       var userAgent = navigator.userAgent.toLowerCase();
+
+       if (userAgent.indexOf("msie") != -1) {
+               document.execCommand("ClearAuthenticationCache", false);
+       }
+
+       var http;
+       if (window.XMLHttpRequest) {
+               http = new XMLHttpRequest();
+       } else if(window.ActiveXObject) {
+               http = new ActiveXObject("Microsoft.XMLHTTP");
+       } else {
+               alert ("Your browser is too old, please close your browser to logout.");
+               return false;
+       }
+
+       /*
+       if (referrer) document.location = referrer;
+       return;
+       */
+       var url = '/logout/';
+       http.open("GET", url, true, '\\0', 'password');
+       http.onload = function() {
+               if (!this.status || this.readyState != 4) return;
+               if (referrer) { document.location = referrer; return; }
+               // document.location = '/';
+       };
+       http.send();
 
 }
 
@@ -867,241 +886,237 @@ dbq_logout();
 </script>
 EOF;
 
-    #exit;
-  }
-
-  public function run_root() {
-    $action = $this->params['db'];
-    if (!$action and self::PARAM_DB_DEFAULT) $action = self::PARAM_DB_DEFAULT;
-    #$this->params = [ 'action' => $action ];
-
-    if ($action == 'help') {
-      $this->page($this->db,[
-        [ 'help', 'This help' ],
-        [ 'ls', 'List configured databases' ],
-        [ 'databases', 'List others databases' ],
-        [ 'cryptkey', 'Generate a random encryption key' ],
-        [ 'ssha_password', 'Encrypt a password' ],
-        [ 'ssha512_password', 'Encrypt a password' ],
-        [ 'logout', 'Clear Basic Auth' ],
-        [ 'status', 'Status infos page' ],
-        [ 'conf', 'Dump json infos' ],
-        [ 'types', 'Available mime types' ],
-      ] + (
-        ($this->perm < self::ADMIN) ? [] :
-      [
-        [ 'phpinfo', 'Phpinfo datas' ],
-        [ '_SERVER', 'Dumper _SERVER' ],
-        [ '_REQUEST', 'Dumper _REQUEST' ],
-      ]
-      )
-      ,['command','description'],function(&$r) {
-        $r['command'] = $this->page->tag('a',$r['command'],'href="'
-          .$this->db->base.'/'.($r['command'] == self::PARAM_DB_DEFAULT
-            ? ''
-# NB 25.05.17             : $r['command'].'.'.$this->ext
-            : $r['command']
-          )
-        .'"');
-      });
-
-    } elseif ($action == 'ls') {
-      #$this->params += [ 'db' => '', 'table' => '', 'action' => '' ];
-      #$this->params = array_merge($this->params,[ 'db' => '', 'table' => '', 'action' => '' ]);
-
-      $this->page($this->db,'ls',[],function(&$r){
-# NB 25.05.17         $r['id'] = $this->page->tag('a',$r['id'],'href="'.$this->db->base.'/'.$r['id'].'.'.$this->ext.'"');
-        $r['id'] = $this->page->tag('a',$r['id'],'href="'.$this->db->base.'/'.$r['id'].'"');
-      });
-
-    } elseif ($action == 'logout') { $this->page($this,'logout'); 
-    } elseif ($action == 'ssha_password') { $this->page($this,'ssha_password');
-    } elseif ($action == 'ssha512_password') { $this->page($this,'ssha512_password');
-    } elseif ($action == 'cryptkey') { $this->page($this->db,'cryptkey',['key']);
-    } elseif ($action == 'status') { $this->page($this,'status');
-    } elseif ($action == 'conf') { $this->page($this,'conf');
-    } elseif ($action == 'types') {
-      $types = [];
-      foreach (array_keys($this->db->out->types()) as $type) {
-        $types[] = [ 'type' => $type ];
-      }
-      $this->page($types);
-
-    // NOW ONLY FOR ADMIN !
-    } elseif ($this->perm < self::ADMIN) {
-
-    } elseif ($action == 'phpinfo') {
-      $this->rows_table($action,$this->phpinfo_rows());
-      #$this->page(['phpinfo'=>$this->page->phpinfo(true)]);
-      #$this->page($this->page->phpinfo());
-      #$this->page($this,'phpinfo_rows');
-      #$this->phpinfo_rows();
-
-    } elseif (0
-      or $action == '_SERVER'
-      or $action == '_REQUEST'
-    ) {
-      $rows = [];
-      foreach ($GLOBALS[$action] as $k=>$v) {
-        if (preg_match('/^(' . $this->hide_keys_exp . ')/', $k)) $v = $this->hide_keys_value;
-        $rows[] = [
-          'name' => $k,
-          'value' => ( is_scalar($v) ? $v : json_encode($v) ),
-        ];
-      }
-      $this->page($rows);
-
-    }
-  }
-
-  public function run_db() {
-    $this->db(true); # Db Connections
-    $action = $this->params['table'];
-    if (!$action and self::PARAM_DB_DEFAULT) $action = self::PARAM_DB_DEFAULT;
+               #exit;
+       }
+
+       public function run_root() {
+               $action = $this->params['db'];
+               if (!$action and self::PARAM_DB_DEFAULT) $action = self::PARAM_DB_DEFAULT;
+               #$this->params = [ 'action' => $action ];
+
+               if ($action == 'help') {
+                       $this->page($this->db,[
+                               [ 'help', 'This help' ],
+                               [ 'ls', 'List configured databases' ],
+                               [ 'databases', 'List others databases' ],
+                               [ 'cryptkey', 'Generate a random encryption key' ],
+                               [ 'ssha_password', 'Encrypt a password' ],
+                               [ 'ssha512_password', 'Encrypt a password' ],
+                               [ 'logout', 'Clear Basic Auth' ],
+                               [ 'status', 'Status infos page' ],
+                               [ 'conf', 'Dump json infos' ],
+                               [ 'types', 'Available mime types' ],
+                       ] + (
+                               ($this->perm < self::ADMIN) ? [] :
+                       [
+                               [ 'phpinfo', 'Phpinfo datas' ],
+                               [ '_SERVER', 'Dumper _SERVER' ],
+                               [ '_REQUEST', 'Dumper _REQUEST' ],
+                       ]
+                       )
+                       ,['command','description'],function(&$r) {
+                               $r['command'] = $this->page->tag('a',$r['command'],'href="'
+                                       .$this->db->base.'/'.($r['command'] == self::PARAM_DB_DEFAULT
+                                               ? ''
+                                               : $r['command']
+                                       )
+                               .'"');
+                       });
+
+               } elseif ($action == 'ls') {
+
+                       $this->page($this->db,'ls',[],function(&$r){
+                               $r['id'] = $this->page->tag('a',$r['id'],'href="'.$this->db->base.'/'.$r['id'].'"');
+                       });
+
+               } elseif ($action == 'logout') { $this->page($this,'logout'); 
+               } elseif ($action == 'ssha_password') { $this->page($this,'ssha_password');
+               } elseif ($action == 'ssha512_password') { $this->page($this,'ssha512_password');
+               } elseif ($action == 'cryptkey') { $this->page($this->db,'cryptkey',['key']);
+               } elseif ($action == 'status') { $this->page($this,'status');
+               } elseif ($action == 'conf') { $this->page($this,'conf');
+               } elseif ($action == 'types') {
+                       $types = [];
+                       foreach (array_keys($this->db->out->types()) as $type) {
+                               $types[] = [ 'type' => $type ];
+                       }
+                       $this->page($types);
+
+               // NOW ONLY FOR ADMIN !
+               } elseif ($this->perm < self::ADMIN) {
+
+               } elseif ($action == 'phpinfo') {
+                       $this->rows_table($action,$this->phpinfo_rows());
+                       #$this->page(['phpinfo'=>$this->page->phpinfo(true)]);
+                       #$this->page($this->page->phpinfo());
+                       #$this->page($this,'phpinfo_rows');
+                       #$this->phpinfo_rows();
+
+               } elseif (0
+                       or $action == '_SERVER'
+                       or $action == '_REQUEST'
+               ) {
+                       $rows = [];
+                       foreach ($GLOBALS[$action] as $k=>$v) {
+                               if (preg_match('/^(' . $this->hide_keys_exp . ')/', $k)) $v = $this->hide_keys_value;
+                               $rows[] = [
+                                       'name' => $k,
+                                       'value' => ( is_scalar($v) ? $v : json_encode($v) ),
+                               ];
+                       }
+                       $this->page($rows);
+
+               }
+       }
+
+       public function run_db() {
+               $this->db(true); # Db Connections
+               $action = $this->params['table'];
+               if (!$action and self::PARAM_DB_DEFAULT) $action = self::PARAM_DB_DEFAULT;
 # NB 27.12.16     $this->params['table'] = '';
 
-    if ($action == 'help') {
-      $this->page($this->db,[
-        [ 'help', 'This help' ],
-        [ 'status', 'Database status' ],
-        [ 'ls', 'List tables' ],
-        [ 'databases', 'List databases' ],
-        [ 'schema', 'Dump database structure only' ],
-        [ 'dump', 'Dump database structure with datas' ],
-        [ 'csv', 'Dump database data in csv with table name as first colum' ],
-      ],['command','description'],function(&$r){
-        $r['command'] = $this->page->tag('a',$r['command'],'href="'
-          .$this->db->base.'/'.($r['command'] == self::PARAM_DB_DEFAULT
-            ? ''
-            : $r['command'].'.'.$this->ext
-          )
-        .'"');
-      });
-
-    } elseif ($action == 'ls') {
-      $this->page('',$this->db->tables_rows(),[],function(&$r){
-        $r['name'] = $this->page->tag('a',$r['name'],'href="'.$this->db->base.'/'.$r['name'].'.'.$this->ext.'"');
-      });
-
-    } elseif ($action == 'status') {
-      $this->page($this->db,'status');
-
-    } elseif ($action == 'databases') {
-      $this->page($this->db,'databases');
-
-    } elseif ($action == 'dump') {
-      header('Content-type: text/plain');
-      $this->db->dump();
-      exit;
-      #echo serialize($this->db->tables());
-      $this->page(array_values($this->db()->conf));
-
-    } elseif ($action == 'csv') {
-      header('Content-type: text/plain');
-      $this->db->dump2csv();
-      exit;
-
-    } elseif ($action == 'schema') {
-      header('Content-type: text/plain');
-      $this->db->sql();
-      exit;
-
-    }
-
-  }
-
-  public function run_table() {
-    $this->table(); # Table init
-    $action = $this->params['action'];
-    if (!$action and self::PARAM_DB_DEFAULT) $action = self::PARAM_DB_DEFAULT;
+               if ($action == 'help') {
+                       $this->page($this->db,[
+                               [ 'help', 'This help' ],
+                               [ 'status', 'Database status' ],
+                               [ 'ls', 'List tables' ],
+                               [ 'databases', 'List databases' ],
+                               [ 'schema', 'Dump database structure only' ],
+                               [ 'dump', 'Dump database structure with datas' ],
+                               [ 'csv', 'Dump database data in csv with table name as first colum' ],
+                       ],['command','description'],function(&$r){
+                               $r['command'] = $this->page->tag('a',$r['command'],'href="'
+                                       .$this->db->base.'/'.($r['command'] == self::PARAM_DB_DEFAULT
+                                               ? ''
+                                               : $r['command'].'.'.$this->ext
+                                       )
+                               .'"');
+                       });
+
+               } elseif ($action == 'ls') {
+                       $this->page('',$this->db->tables_rows(),[],function(&$r){
+                               $r['name'] = $this->page->tag('a',$r['name'],'href="'.$this->db->base.'/'.$r['name'].'.'.$this->ext.'"');
+                       });
+
+               } elseif ($action == 'status') {
+                       $this->page($this->db,'status');
+
+               } elseif ($action == 'databases') {
+                       $this->page($this->db,'databases');
+
+               } elseif ($action == 'dump') {
+                       header('Content-type: text/plain');
+                       $this->db->dump();
+                       exit;
+                       #echo serialize($this->db->tables());
+                       $this->page(array_values($this->db()->conf));
+
+               } elseif ($action == 'csv') {
+                       header('Content-type: text/plain');
+                       $this->db->dump2csv();
+                       exit;
+
+               } elseif ($action == 'schema') {
+                       header('Content-type: text/plain');
+                       $this->db->sql();
+                       exit;
+
+               }
+
+       }
+
+       public function run_table() {
+               $this->table(); # Table init
+               $action = $this->params['action'];
+               if (!$action and self::PARAM_DB_DEFAULT) $action = self::PARAM_DB_DEFAULT;
 
 #bye([$this->params,$action]);
-    if ($action == 'help') {
-      $this->page($this->table,[
-        [ 'help', 'Table help' ],
-        [ 'ls', 'List records' ],
-        [ 'fields', 'List fields' ],
-        [ 'status', 'Status page' ],
-      ],['command','description'],function(&$r){
-        $r['command'] = $this->page->tag('a',$r['command'],'href="'
-          .$this->table->base.'/'.($r['command'] == self::PARAM_DB_DEFAULT
-            ? ''
-            : $r['command'].'.'.$this->ext
-          )
-        .'"');
-      });
-
-    } elseif ($action == 'ls' and $this->perm >= self::READ) {
-      $this->page($this,'table_rows');
-
-    } elseif ($action == 'fields') {
-      $this->page($this->table,'fields_rows');
-
-    } elseif ($action == 'status') {
-      $this->page($this->table->status()+$this->table->status(['fields']));
-
-    } elseif ($action == 'add' and $this->perm >= self::WRITE) {
-      $this->page($this,'add');
-
-    } elseif ($action == 'vi' and $this->perm >= self::READ) {
-      $this->page($this,'vi');
-
-    } elseif ($action == 'insert' and $this->perm >= self::WRITE) {
-      if (!$this->table->insert($_POST,$info)) $this->error('insert: '.print_r($info,true));
-      header('Location: '.$this->table->base.'/');
-      $this->page($info);
-
-    } elseif ($action == 'update' and $this->perm >= self::WRITE) {
-      if (!$this->table->update($_POST,$info)) $this->error('update: '.print_r($info,true));
-      # NB 23.08.17: TODO 
-      $this->redirect_if_no_referer($this->table->base.'/');
-      #header('Location: '.$this->table->base.'/');
-      $this->page($info);
-
-    } elseif ($action == 'rm' and $this->perm >= self::DELETE) {
-      if (!$this->table->delete($_POST,$info)) $this->error('rm: '.print_r($info,true));
-      header('Location: '.$this->table->base.'/');
-      $this->page($info);
-
-
-    } else {
-      $this->not_implemented('Unknown table action'." `$action`");
-
-    }
-  }
-
-  public function redirect_if_no_referer($url) {
-    if ($this->p('referer')) $url = urldecode($this->p('referer'));
-    header('Location: '.$url);
-  }
-
-  public function run() {
-    #$this->bye($_POST);
-
-    #
-    # Init
-    #
-    $this->run_init();
-
-    #
-    # Root Actions
-    #
-    $this->run_root();
-
-    #
-    # Db actions
-    #
-    $this->run_db();
-    
-    #
-    # Table action
-    #
-    $this->run_table();
-
-    #$this->error("Page error");
-    $this->not_implemented('Nothing here!');
-    return true;
-  }
+               if ($action == 'help') {
+                       $this->page($this->table,[
+                               [ 'help', 'Table help' ],
+                               [ 'ls', 'List records' ],
+                               [ 'fields', 'List fields' ],
+                               [ 'status', 'Status page' ],
+                       ],['command','description'],function(&$r){
+                               $r['command'] = $this->page->tag('a',$r['command'],'href="'
+                                       .$this->table->base.'/'.($r['command'] == self::PARAM_DB_DEFAULT
+                                               ? ''
+                                               : $r['command'].'.'.$this->ext
+                                       )
+                               .'"');
+                       });
+
+               } elseif ($action == 'ls' and $this->perm >= self::READ) {
+                       $this->page($this,'table_rows');
+
+               } elseif ($action == 'fields') {
+                       $this->page($this->table,'fields_rows');
+
+               } elseif ($action == 'status') {
+                       $this->page($this->table->status()+$this->table->status(['fields']));
+
+               } elseif ($action == 'add' and $this->perm >= self::WRITE) {
+                       $this->page($this,'add');
+
+               } elseif ($action == 'vi' and $this->perm >= self::READ) {
+                       $this->page($this,'vi');
+
+               } elseif ($action == 'insert' and $this->perm >= self::WRITE) {
+                       if (!$this->table->insert($_POST,$info)) $this->error('insert: '.print_r($info,true));
+                       header('Location: '.$this->table->base.'/');
+                       $this->page($info);
+
+               } elseif ($action == 'update' and $this->perm >= self::WRITE) {
+                       if (!$this->table->update($_POST,$info)) $this->error('update: '.print_r($info,true));
+                       # NB 23.08.17: TODO 
+                       $this->redirect_if_no_referer($this->table->base.'/');
+                       #header('Location: '.$this->table->base.'/');
+                       $this->page($info);
+
+               } elseif ($action == 'rm' and $this->perm >= self::DELETE) {
+                       if (!$this->table->delete($_POST,$info)) $this->error('rm: '.print_r($info,true));
+                       header('Location: '.$this->table->base.'/');
+                       $this->page($info);
+
+
+               } else {
+                       $this->not_implemented('Unknown table action'." `$action`");
+
+               }
+       }
+
+       public function redirect_if_no_referer($url) {
+               if ($this->p('referer')) $url = urldecode($this->p('referer'));
+               header('Location: '.$url);
+       }
+
+       public function run() {
+               #$this->bye($_POST);
+
+               #
+               # Init
+               #
+               $this->run_init();
+
+               #
+               # Root Actions
+               #
+               $this->run_root();
+
+               #
+               # Db actions
+               #
+               $this->run_db();
+               
+               #
+               # Table action
+               #
+               $this->run_table();
+
+               #$this->error("Page error");
+               $this->not_implemented('Nothing here!');
+               return true;
+       }
 
 }
 $DBQ = new DbQ(['run'=>true]);