]> git.nbdom.net Git - nb.git/commitdiff
Bed
authorNicolas Boisselier <nicolas.boisselier@gmail.com>
Sun, 27 Mar 2016 03:32:39 +0000 (04:32 +0100)
committerNicolas Boisselier <nicolas.boisselier@gmail.com>
Sun, 27 Mar 2016 03:32:39 +0000 (04:32 +0100)
lib/php/db.php
lib/php/db/index.php
lib/php/db/table.php
lib/php/functions.php
lib/php/nb.php
lib/php/out.php
lib/php/page.php

index 04b491e1ff4adbfd3c1ed042c2dc0c0e7ff3320b..914f41ed0d84540476cd96a42cc334cf2f9b2428 100644 (file)
@@ -33,6 +33,67 @@ $DB_TYPES = array(
     ,
     'sqlite' => "SELECT name,type FROM sqlite_master WHERE type IN('table','view') AND name NOT LIKE 'sqlite_%' ORDER BY name",
   ),
+  'table.fields' => array(
+      'pgsql' => "SELECT
+a.attname AS name,
+pg_catalog.format_type(a.atttypid, a.atttypmod) AS type,
+CASE a.attnotnull WHEN 't' then 1 ELSE 0 END AS notnull,
+(SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128) FROM pg_catalog.pg_attrdef d WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef) AS pg_default,
+(SELECT 1 FROM pg_index i WHERE a.attrelid = i.indrelid AND a.attnum = ANY(i.indkey) AND i.indrelid = '<NAME>'::regclass AND i.indisprimary) as pk
+FROM pg_catalog.pg_attribute a WHERE a.attrelid = (SELECT c.oid FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE c.relname='<NAME>' AND pg_catalog.pg_table_is_visible(c.oid) ) AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum",
+      'mysql' => "SHOW COLUMNS FROM `<NAME>`",
+      'sqlite' => "PRAGMA table_info('<NAME>')",
+    ),
+  'table.sql' => array(
+    'pgsql' => "
+SELECT
+  'CREATE TABLE '||sql.table||'('
+    ||array_to_string(array_agg(sql),', ')
+  ||')' as sql
+FROM (
+  (
+    SELECT -- FIELDS
+      c.oid AS id
+      ,c.relname as table
+      ,9 as prio
+      ,''
+        || f.attname
+        || ' ' || pg_catalog.format_type(f.atttypid,f.atttypmod)
+        ||CASE WHEN f.attnotnull THEN ' NOT NULL' ELSE '' END
+        ||CASE WHEN f.atthasdef = 't' AND d.adsrc !=''THEN ' DEFAULT '||d.adsrc ELSE '' END
+      AS sql
+    FROM pg_attribute f
+        JOIN pg_class c ON c.oid = f.attrelid
+        LEFT JOIN pg_attrdef d ON d.adrelid = c.oid AND d.adnum = f.attnum
+    WHERE c.relkind = 'r'::char
+        AND f.attnum > 0
+    ORDER BY f.attnum
+  )  UNION (
+    SELECT -- CONSTRAINTS
+        c.oid as id
+        ,c.relname as table
+        ,0 as prio
+        ,CASE
+          WHEN p.contype = 'p' THEN 'PRIMARY KEY'
+          WHEN p.contype = 'u' THEN 'UNIQ'
+          ELSE '' END
+        ||'('||array_to_string(array_agg(f.attname),', ')||')' AS sql
+    FROM pg_attribute f
+        JOIN pg_class c ON c.oid = f.attrelid
+        LEFT JOIN pg_constraint p ON p.conrelid = c.oid AND f.attnum = ANY (p.conkey)
+    WHERE c.relkind = 'r'::char
+        AND f.attnum > 0
+        AND p.contype IN ('u','p')
+    GROUP BY c.oid,p.contype,f.attrelid,c.relname
+    ORDER BY c.oid,f.attrelid
+  )
+ORDER BY prio DESC) sql
+WHERE sql.table='<NAME>'
+GROUP BY sql.id,sql.table
+",
+    'mysql' => "SHOW CREATE TABLE `<NAME>`",
+    'sqlite' => "SELECT sql FROM sqlite_master WHERE name='<NAME>'",
+  ),
 );
 #die($DB_TYPES['tables']['mysql']);
 
@@ -284,10 +345,9 @@ class Db extends nb {
   }
 
   public function config() {
-    #bye($this->types('config'));
-    if (!($config = $this->types('config')))
-      self::bye("db.config(): Unknow db type: ".$this->type." from ".print_r($GLOBALS['DB_TYPES'],1))
-    ;
+
+    $config = $this->type('config',true);
+
     $config[1] = str_replace('<NAME>',$this->name,$config[1]);
 
     if (!file_exists($config[0])) return array();
@@ -305,7 +365,7 @@ class Db extends nb {
     return $return;
   }
 
-  public function types($key=false,$die=false) {
+  public function type($key=false,$die=false) {
     #if (!isset($DB_TYPES[$key][$this->type])) return;
     global $DB_TYPES;
 
@@ -326,12 +386,12 @@ class Db extends nb {
       !isset($DB_TYPES[$key])
       or !isset($DB_TYPES[$key][$this->type])
       or empty($DB_TYPES[$key][$this->type])
-    )
-    # ??? not working ???
-      #self::bye("db.types(): Unknow key `$key` for type `".$this->type."`".print_r($DB_TYPES,1));
-      #if ($die) self::bye("db.types(): Unknow key `$key` for type `".$this->type."`");
+    ) {
+      #self::bye("db.type(): Unknow key `$key` for type `".$this->type."`".print_r($DB_TYPES,1));
+      #nb::msg(">>>".$DB_TYPES[$key][$this->type]);
+      if ($die) self::bye("db.type(): Unknow key `$key` for type `".$this->type."`");
       return;
-    ;
+    }
 
     return $DB_TYPES[$key][$this->type];
   }
@@ -340,9 +400,7 @@ class Db extends nb {
     if (isset($this->_tables) and $this->_tables) return ($return_hash ? $this->tables : $this->_tables);
     if (!isset($this->_tables)) $this->_tables = array();
 
-    if (!($sql = $this->types('tables')))
-      self::bye("db.types(): Unknow db type: ".$this->type." from ".print_r($GLOBALS['DB_TYPES'],1))
-    ;
+    $sql = $this->type('tables',true);
 
     $rows = $this->conn->query($sql,PDO::FETCH_ASSOC);
     foreach ($rows as $row) {
@@ -487,8 +545,6 @@ EOF;
   public function out2($rows,$head=array()) {
     #if (is_scalar($head)) bye(var_dump($head,true));
 
-    if ($this->p('header') === '0' ) $head = false;
-    elseif (is_scalar($head)) $head = array($head);
 # NB 09.03.16     elseif (count($rows)) {
 # NB 09.03.16       $first = self::ar_first($row);
 # NB 09.03.16       #if (self::is_hash($first))
@@ -555,17 +611,15 @@ EOF;
           echo $this->html_menu();
           $return = true;
 
-        } elseif (preg_match('/db\.(\w+)/',$action,$m)) {
+        } elseif (preg_match('/^db\.(\w+)/',$action,$m)) {
           $meth = $m[1];
           $rows = $this->$meth();
-          #$return = $this->out2($rows);
-          if ($rows) $return =
-            out::rows($this->p('format',out::php_cli() ? 'csv' : 'csv'),$rows)
-          ;
+          if ($rows) $return = $this->out2($rows,self::is_hash($rows) ? true : array($meth));
           $return = true;
 
         } elseif($table) {
           if ($r=$table->action($action)) $return = $r;
+          #if (!is_scalar($return)) $return = $this->out2($return);
 
         }
     }
@@ -689,15 +743,22 @@ EOF;
 
   }
 
-  public function dump() {
+  public function sql() {
     $this->pset('orderby',null);
+    $r = array();
     foreach ($this->tables() as $t) {
       $t = $this->table($t);
       #$this->pset('format','sql');
-      echo preg_replace('/\s+/',' ',$t->sql()).";\n";
-      $t->rows();
+      #$r[] = preg_replace('/\s+/',' ',$t->sql()).";";
+      #if (0)
+      #$r[] = preg_replace('/ +/',' ',$t->sql()).";";
+      $r[] = preg_replace('/\s+/',' ',
+        # Filter comment to generate one sql per line
+        join(' ',preg_grep('/^ *--/',explode("\n",$t->sql()),true))
+      ).";";
+      #$t->rows();
     }
-    return array();
+    return $r;
   }
 
 } # < Class
index ee8c0c0729c9056fdf88f846f98e42b1e98b371e..3a38e9d6c640669183c9bc2690eab0a09921479d 100755 (executable)
@@ -9,13 +9,16 @@
 require_once(dirname(__FILE__).'/../config.php');
 require_once(dirname(__FILE__).'/../db.php');
 
-if($format = out::client_type()) Db::pdef('format',$format);
+#bye(out::client_type());
+Db::pdef('format',out::client_type());
+#if($format = out::client_type()) Db::pset('format',$format);
 
 # Param - Extract dbname from table
 if (preg_match('/^(\w+)\.(.*?)$/',Db::p('table'),$m)) {
   Db::pset('db',$m[1]);
   Db::pset('table',$m[2]);
 }
+#$conf = Db::conf_dbs(array( Db::$root_dir.'/etc/dbs.yaml','/etc/dbs.yaml' )); Db::init($conf);
 Db::init(array( Db::$root_dir.'/etc/dbs.yaml','/etc/dbs.yaml' ));
 
 if( defined('DB_JUST_INIT')) return true;
index 04b9c2882684164a03a8dec6162329b5b3c0edfc..33d359c3a08cccef501f8065cde580fc9f1f4dec 100644 (file)
@@ -23,7 +23,7 @@ if (!defined('DB_HTML_EDIT')) define('DB_HTML_EDIT','Edit');
 if (!defined('DB_HTML_DELETE')) define('DB_HTML_DELETE','Delete');
 if (!defined('DB_TABLE_QUERY_NAME')) define('DB_TABLE_QUERY_NAME','_query_');
 
-class Table extends nb {
+Class Table extends nb {
 
   public $name;
   public $db;
@@ -41,14 +41,19 @@ class Table extends nb {
 
   function __construct($name,$opt=array()) {
 
+    if (!is_scalar($name)) {
+      $opt = $name;
+      $name = null;
+    }
+
     foreach ($opt as $k => $v) { $this->$k = $v; }
     #unset($opt['db']); bye($opt);
 
     // Connection
     if (isset($opt['db'])) {
-      $this->db = $opt['db'];
+      $this->db = is_object($opt['db']) ? $opt['db'] : new Db($opt['db']);
     } else {
-      $this->db = new db();
+      $this->db = new Db();
     }
 
     // Name, could be a select
@@ -102,62 +107,10 @@ class Table extends nb {
       return $this->sql;
     }
 
-    if ($this->db->type == 'sqlite') {
-      $sql = "SELECT sql FROM sqlite_master WHERE name='$this->name'";
-    } elseif ($this->db->type == 'mysql') {
-      $sql = "SHOW CREATE TABLE `$this->name`";
-    } elseif ($this->db->type == 'pgsql') {
-      $sql = "SELECT show_create_table('$this->name')";
-      $sql = "
-SELECT
-  'CREATE TABLE '||sql.table||'('
-    ||array_to_string(array_agg(sql),', ')
-  ||')' as sql
-FROM (
-  (
-    SELECT -- FIELDS
-      c.oid AS id
-      ,c.relname as table
-      ,9 as prio
-      ,''
-        || f.attname
-        || ' ' || pg_catalog.format_type(f.atttypid,f.atttypmod)
-        ||CASE WHEN f.attnotnull THEN ' NOT NULL' ELSE '' END
-        ||CASE WHEN f.atthasdef = 't' AND d.adsrc !=''THEN ' DEFAULT '||d.adsrc ELSE '' END
-      AS sql
-    FROM pg_attribute f
-        JOIN pg_class c ON c.oid = f.attrelid
-        LEFT JOIN pg_attrdef d ON d.adrelid = c.oid AND d.adnum = f.attnum
-    WHERE c.relkind = 'r'::char
-        AND f.attnum > 0
-    ORDER BY f.attnum
-  )  UNION (
-    SELECT -- CONSTRAINTS
-        c.oid as id
-        ,c.relname as table
-        ,0 as prio
-        ,CASE
-          WHEN p.contype = 'p' THEN 'PRIMARY KEY'
-          WHEN p.contype = 'u' THEN 'UNIQ'
-          ELSE '' END
-        ||'('||array_to_string(array_agg(f.attname),', ')||')' AS sql
-    FROM pg_attribute f
-        JOIN pg_class c ON c.oid = f.attrelid
-        LEFT JOIN pg_constraint p ON p.conrelid = c.oid AND f.attnum = ANY (p.conkey)
-    WHERE c.relkind = 'r'::char
-        AND f.attnum > 0
-        AND p.contype IN ('u','p')
-    GROUP BY c.oid,p.contype,f.attrelid,c.relname
-    ORDER BY c.oid,f.attrelid
-  )
-ORDER BY prio DESC) sql
-WHERE sql.table='$this->name'
-GROUP BY sql.id,sql.table
-";
-    } else {
-      err('table.sql(): Unknow db type: '.$this->db->type);
-    }
+    $sql = str_replace('<NAME>',$this->name,$this->db->type('table.sql',true));
     $this->sql = $this->db->row($sql);
+    $this->sql = preg_replace("/^\w+\s+(CREATE)/i",'$1',$this->sql); # for mysql
+    #$this->sql = trim($this->sql);
     #bye($this->sql);
     return $this->sql;
   }
@@ -174,28 +127,7 @@ GROUP BY sql.id,sql.table
 
     if ($this->fields === null) {
       $this->fields = array();
-
-      if ($this->db->type == 'sqlite') {
-        $sql = "PRAGMA table_info('$this->name')";
-
-      } elseif ($this->db->type == 'pgsql') {
-        $sql = "SELECT
-a.attname AS name,
-pg_catalog.format_type(a.atttypid, a.atttypmod) AS type,
-CASE a.attnotnull WHEN 't' then 1 ELSE 0 END AS notnull,
-(SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128) FROM pg_catalog.pg_attrdef d WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef) AS pg_default,
-(SELECT 1 FROM pg_index i WHERE a.attrelid = i.indrelid AND a.attnum = ANY(i.indkey) AND i.indrelid = '$this->name'::regclass AND i.indisprimary) as pk
-FROM pg_catalog.pg_attribute a WHERE a.attrelid = (SELECT c.oid FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE c.relname='$this->name' AND pg_catalog.pg_table_is_visible(c.oid) ) AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum";
-
-      } elseif ($this->db->type == 'mysql') {
-        $sql = "SHOW COLUMNS FROM `$this->name`";
-
-      } else {
-        err('table.fields(): Unknow db type: '.$this->db->type);
-        return array();
-
-      }
-
+      $sql = str_replace('<NAME>',$this->name,$this->db->type('table.fields',true));
       $rows = $this->db->conn->query($sql);
       $rows->setFetchMode(PDO::FETCH_ASSOC);
 
@@ -233,7 +165,7 @@ FROM pg_catalog.pg_attribute a WHERE a.attrelid = (SELECT c.oid FROM pg_catalog.
         if (isset($row['extra']) and $row['extra'] == 'auto_increment') {
           $field['autoincrement'] = true;
 
-        # sqlite autoincrement
+        # sqlite autoincrement only in sql
         } elseif ($this->db->type == 'sqlite'
           and preg_match('/[\(,]'.$row['name'].' [^\),]+ AUTOINCREMENT/',$this->sql())
         ) {
@@ -668,7 +600,7 @@ FROM pg_catalog.pg_attribute a WHERE a.attrelid = (SELECT c.oid FROM pg_catalog.
         if ($opt['is_html']) echo $this->html_nav_top();
 
         if ($out_conf) {
-          out::begin($out_conf,$this->fields(),array($row));
+          out::head($out_conf,$this->fields(),array($row));
 
         } else {
           echo $this->{"rows_begin_$format"}($this->fields());
@@ -1127,13 +1059,14 @@ FROM pg_catalog.pg_attribute a WHERE a.attrelid = (SELECT c.oid FROM pg_catalog.
       $this->db->print_header($this->p('format'));
       $this->rows(); return true;
 
-# NB 06.03.16     } elseif ($action == 'table') {
-# NB 06.03.16       return $this->out(array(
-# NB 06.03.16         #"count" => $this->count(),
-# NB 06.03.16         "sql_name" => $this->sql_name(),
-# NB 06.03.16         "sql" => $this->sql(),
-# NB 06.03.16         "fields" => $this->object2array($this->fields()),
-# NB 06.03.16       ),true);
+    } elseif ($action == 'table') {
+      return $this->out2(array(
+        #"count" => $this->count(),
+        #"sql_name" => $this->sql_name(),
+        "name" => $this->name,
+        "sql" => $this->sql(),
+        #"fields" => $this->object2array($this->fields()),
+      ));
 
     } elseif ($action == 'table.delete' or $action == 'delete') {
       if (!$this->delete($this->p(),$e)) bye($e);
@@ -1163,6 +1096,12 @@ FROM pg_catalog.pg_attribute a WHERE a.attrelid = (SELECT c.oid FROM pg_catalog.
       $this->out2($out);
       return $r;
 
+    } elseif (preg_match('/^table\.(\w+)/',$action,$m)) {
+      $meth = $m[1];
+      $rows = $this->$meth();
+      if ($rows) $return = $this->out2($rows,self::is_hash($rows) ? true : array($meth));
+      return true;
+
     } elseif ($this->p('format') and !preg_match('/^(table|div)$/',$this->p('format'))) {
 
       $this->rows(array( 'format' => $this->p('format')));
@@ -1318,6 +1257,51 @@ FROM pg_catalog.pg_attribute a WHERE a.attrelid = (SELECT c.oid FROM pg_catalog.
     return $r;
   }
 
+  public function unserialize() {
+    $o = unserialize($this->serialize());
+    if (empty($o->db)) {
+      global $Db; $o->db = $Db;
+    }
+    #var_export($o->db);
+    return($o->sql_name());
+    debug($o->sql_name());
+    return var_export($o,true);
+  }
+
+  public function __sleep() {
+    if (1) return array(
+      'name',
+      'sql',
+      'type',
+      'fields',
+      'fields_keys',
+      'replace',
+      'extras',
+      'params',
+      'order_by',
+    );
+
+    $vars = array();
+    #foreach (get_class_vars(get_class($this)) as $k=>$v) { if ($k=!'db') $vars[]=$k; };
+    foreach (get_class_vars(get_class($this)) as $k=>$v) { if ($k=!'db') $vars[]=$k; };
+    #foreach (get_class_vars(__CLASS__) as $k=>$v) { if ($k=!'db') $vars[]=$k; };
+    debug($vars);
+    #$vars = get_object_vars($this);
+    return $vars;
+  }
+
+  public function serialize() {
+    #$o = new self(null,$this);
+    $clone = clone($this);
+    #foreach (get_object_vars($clone) as $k=>$v) { if (is_object($v)) unset($clone->$k); };
+    #var_export($clone->db);
+    #unset($clone->db);
+    #$clone->db = array();
+    #foreach (get_object_vars($this->db) as $k=>$v) { if (!is_object($v)) $clone->db[$k] = $v; };
+    #debug($clone->db);
+    #foreach (get_object_vars($this) as $k=>$v) { unset($this->$k); };
+    return serialize($clone);
+  }
 
-}
+} # < Class
 ?>
index bf13f2c46d9cd29cb13b2c37e5c5ba6986f2174b..a3e92f6b6dbb784578d31447a1eaaf124bf4601c 100644 (file)
@@ -99,6 +99,7 @@ function bye($msg='__bye__',$backtrace_deep=0) {
   if ($msg!=='__bye__') err($msg,'bye',( $backtrace_deep !== false ? (1+$backtrace_deep) : $backtrace_deep ));
   #if ($msg) err($msg,'bye',1+$backtrace_deep);
   exit;
+  #die("Can't exit from BYE!!!");
 }
 
 function warn ($msg) {
index 421ea0726667d22bb888c2dec5e82b9259a8a2c4..fa36bb24c5eda8c966b64358b327c311b371357d 100644 (file)
@@ -33,10 +33,12 @@ class nb {
   function __destruct() {
     #foreach (get_object_vars($this) as $k=>$v) { echo ("$k: $v\n"); }
     #if (is_object($this))
-    try {
-      foreach (get_object_vars($this) as $k=>$v) { unset($this->$k); };
-    } catch(Exception $e) {
-    }
+    foreach (get_object_vars($this) as $k=>$v) { unset($this->$k); };
+    #foreach (get_class_vars($this) as $k=>$v) { unset($this->$k); };
+# NB 27.03.16     try {
+# NB 27.03.16       foreach (get_object_vars($this) as $k=>$v) { unset($this->$k); };
+# NB 27.03.16     } catch(Exception $e) {
+# NB 27.03.16     }
   }
 
   /*
index 1b6844c5d2b0fbe21c6b778cc7668df8ef63bb9f..d6ee7e1d67f474259e770904082d7d1eb46d7cdb 100644 (file)
@@ -6,9 +6,12 @@ require_once('nb.php');
 # NB 07.03.16 define('OUT_BRACE2','}');
 # NB 07.03.16 define('OUT_COMA',','.NB_EOL);
 
-class Out extends Nb {
+Class Out extends Nb {
 
-  public static $types; public static function types() {
+  public static $charset = 'utf-8';
+  public static $types;
+  public static $type;
+  public static function init() {
     self::$types = array(
       'sql' => array(
       ),
@@ -61,20 +64,43 @@ class Out extends Nb {
         'rec' => ',',
       ),
     );
+    self::$type = self::client_type();
   }
 
   public function __construct($type,&$data,$head=array()) {
     if (!empty($type) and !empty($data)) return $this->rows($type,$data,$head);
   }
 
-  public static function begin($o,$head,$data=array()) {
+  public static function scalar($v) {
+    if (is_scalar($v)) return $v;
+    #if (is_array($v) and !self::is_hash($v)) return join(', ',$v);
+    #return var_export($v,true);
+    return trim(preg_replace(array(
+      '/^\s*\'(.*?)\' => \'?(.*?)\'?,$/m', # hash
+      '/^\s*(array \(|\),?)$/m', # sub array
+      '/ *\'(.*?)\' =>\s*$\r?\n/m', # sub hash
+      '/\s*\d+ => \'(.*?)\'(,)?\r?\n/m', # aray
+      '/$(\r?\n)+$/m', # blank lines
+      '/,\s*$/m', # last ,
+    ),array(
+      '$1=$2',
+      '',
+      '$1=',
+      '$1$2 ',
+      '',
+      '',
+    ),var_export($v,true)));
+    return var_export($v,true);
+    return is_scalar($v) ? $v : json_encode($v);
+  }
+
+  public static function head($o,$head,$data=array()) {
     #if (self::p('header')==="0") return;
     if (isset($o['enclose'])) echo $o['enclose'][0];
     if (!isset($o['head'])) return;
 
 #var_dump($head); return;
-    if ($head === false) return;
-    if (empty($head)) {
+    if (empty($head) and $head!== false) {
       if (self::is_hash($data[0])) {
         $head = array_keys($data[0]);
       } else {
@@ -82,6 +108,8 @@ class Out extends Nb {
       }
     }
 
+    if (self::p('header') === '0' ) return;
+    if ($head === false) return;
     echo $o['head']($head,$o) . empty($o['eol']) ? '' : $o['eol'];
 
   }
@@ -112,14 +140,16 @@ class Out extends Nb {
   public static function rows_get($type,$data,$head=array()) {
     ob_start();
     self::rows($type,$data,$head);
+               $contents = ob_get_contents();
+               ob_end_clean();
+               return $contents;
     return ob_get_flush();
   }
   public static function rows($type,&$data,$head=array()) {
 
     # Ex: for action=tables when header=0
+
     if (is_scalar($data)) $data = array(array($data));
-    #bye($data);
-    #if (empty($head)) $head = array_fill(0,count($data[0]),'?');
     if (!isset(self::$types[$type])) self::bye("Unknow type: `$type`");
     $conf = self::$types[$type];
 
@@ -130,13 +160,13 @@ class Out extends Nb {
     if (self::is_hash($data)) $data = array($data);
     if (is_scalar($data)) $data = array($data);
 
-    if (is_scalar($head) and !is_bool($head)) $head = array($head);
-
     $tot = count($data);
     $count = 0;
 
     # Function head
-    self::begin($conf,$head,$data);
+    #elseif (is_scalar($head)) $head = array($head);
+    if (is_scalar($head) and !is_bool($head)) $head = array($head);
+    self::head($conf,$head,$data);
 
     foreach ($data as $row) {
       if ($count>0) out::concat($conf);
@@ -173,13 +203,51 @@ class Out extends Nb {
   public static function client_type() {
     foreach (array_keys(self::$types) as $t) {
       if (preg_match("@^\w+/$t@",self::client_header('Accept'))) return $t;
-      #if (preg_match("@^\w+/$t@",self::client_header('Accept'),$m)) bye( $m );
-      #if (self::client_header('Accept',$t)) return $t;
     }
     return;
   }
 
-} Out::types() ; # < Class
+  public static function escape($v,$type=null) {
+    static $replace_flags = null;
+
+    $is_scalar = is_scalar($v);
+    $v = out::scalar($v);
+
+    if ($replace_flags === null) {
+
+      #$replace_flags = ENT_COMPAT | ENT_DISALLOWED;
+      $replace_flags = ENT_COMPAT;
+
+      if ($type === null) $type = self::$type;
+      if (!$type) {
+        return $v;
+
+      } elseif ($type=='xhtml' or (
+        !empty(self::$types[$type]['is_html'])
+        and !empty(self::$types[$type]['is_xml'])
+      )) {
+        $replace_flags = $replace_flags | ENT_XHTML;
+
+      } elseif ($type=='xml' or !empty(self::$types[$type]['is_xml'])) {
+        $replace_flags = $replace_flags | ENT_XML1;
+
+      } elseif ($type=='html' or !empty(self::$types[$type]['is_html'])) {
+        $replace_flags = $replace_flags | ENT_HTML5;
+
+      } else { # text
+        return $v;
+        return preg_replace('/\n/','',$v);
+
+      }
+
+    }
+
+    $v = htmlspecialchars($v,$replace_flags,strtoupper(self::$charset));
+    if (!$is_scalar) $v = '<pre>'.NB_EOL.$v.NB_EOL.'</pre>';
+    return $v;
+  }
+
+} Out::init() ; # < Class
 /****************************************************************************/
 
 function out_yaml(&$row,$o) {
@@ -195,12 +263,13 @@ function out_yaml(&$row,$o) {
 }
 
 function out_csv(&$row,$o) {
+
   $values = array();
 
   foreach (array_values($row) as $k=>$v) {
     #if (!is_scalar($v)) $v = join('',$v);
-    if (!is_scalar($v)) $v = json_encode($v);
-    $values[] = $v;
+    $values[] = preg_replace('/zAZA/','',out::scalar($v));
+    #$values[] = preg_replace('/\r?\n/','',out::scalar($v));
   }
 
   #echo join($o['sep'],array_values($row));
@@ -249,12 +318,13 @@ function out_tag(&$row,&$o) {
 
     # Tag = o[tag] or key
     if (isset($o['tag'])) {
-      $class = ' class="'.$k.'"';
+      $class = is_numeric($k) ? '' : ' class="'.$k.'"';
       $k = $o['tag']; 
     } else {
       $class = '';
     }
 
+    $v = out::escape($v);
     echo ''
       .(NB_EOL ? '    ' : '')
       ."<$k$class>$v</$k>"
@@ -268,7 +338,7 @@ function out_tag(&$row,&$o) {
 function out_xml(&$row,$o) {
   echo (NB_EOL ? '  ' : '')."<row>".NB_EOL;
   foreach ($row as $k => $v) {
-    echo (NB_EOL ? '    ' : '')."<$k><![CDATA[$v]]></$k>".NB_EOL;
+    echo (NB_EOL ? '    ' : '')."<$k><![CDATA[".out::scalar($v)."]]></$k>".NB_EOL;
   }
   echo (NB_EOL ? '  ' : '')."</row>".NB_EOL;
 }
index 0df3e42dc075a45d70b1754ed23bd058b1631fb0..28ee215718a650e7e3ac1ac414c222e5600be1f7 100644 (file)
@@ -166,7 +166,7 @@ class Page extends nb {
     }
 
     if ($content===null) {
-      $this->end_tag($tag);
+      $this->tag_end($tag);
       return '<' . $tag . ($attrs ? " $attrs" : "") . '>';
     }
 
@@ -250,12 +250,12 @@ class Page extends nb {
 
   }
 
-  function end_tag($tag=null) {
+  function tag_end($tag=null) {
     static $tags = array();
     if ($tag !== null) return array_unshift($tags,$tag);
     foreach ($tags as $t) echo "</$t>".NB_EOL;
     $tags = array();
-    return false;
+    return $tags;
     return join('',self::ar_map('',$tags));
     if ($tag === null) return $tags;
     array_unshift($tags,$tag);
@@ -264,8 +264,8 @@ class Page extends nb {
   function end() {
 
     if (preg_match('/ml$/',$this->content_type)) {
-      #foreach ($this->end_tag() as $t) echo "</$t>".NB_EOL;
-      $this->end_tag();
+      #foreach ($this->tag_end() as $t) echo "</$t>".NB_EOL;
+      $this->tag_end();
       echo '</body>' . NB_EOL;
       echo '</html>' . NB_EOL;
     }
@@ -444,6 +444,26 @@ class Page extends nb {
     $Page->h1 = join(' / ',$nav);
 
     $Page->title = join(' / ',$title);
+
+    return $Page;
+  }
+
+  public function action() {
+    $action = self::p('action');
+    $format = self::p('format',self::php_cli() ? 'csv' : 'table');
+
+    if ($action == 'page.info') {
+      $out = array('path' => $this->path());
+      foreach (get_object_vars($this) as $k=>$v) { if (!empty($this->$k)) $out[$k] = $this->$k; }
+      $out['p'] = self::p();
+      $out['_SERVER'] = $_SERVER;
+
+      $out = array_map(function($k, $v) { return array("name"=>$k,"value"=>$v); },array_keys($out),$out);
+      out::rows($format,$out);
+      return true;
+    }
+
+    return false;
   }
 
   public static function html_embed($iframe,$mime='text/html') {