Pārlūkot izejas kodu

Security update / 安全更新

star7th 4 gadi atpakaļ
vecāks
revīzija
b5260f087f

+ 1 - 0
server/Application/Common/Conf/config.php

@@ -40,4 +40,5 @@ return array(
                             'bucket' => '', 
                         )
                     ),
+    'DATA_CACHE_KEY'=>'file_cache_safe',
 );

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 389 - 294
server/ThinkPHP/Library/Think/Db/Driver.class.php


+ 73 - 48
server/ThinkPHP/Library/Think/Db/Driver/Firebird.class.php

@@ -9,13 +9,15 @@
 // | Author: liu21st <liu21st@gmail.com>
 // +----------------------------------------------------------------------
 namespace Think\Db\Driver;
+
 use Think\Db\Driver;
 
 /**
- * Firebird数据库驱动 
+ * Firebird数据库驱动
  */
-class Firebird extends Driver{
-    protected $selectSql  =     'SELECT %LIMIT% %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%';
+class Firebird extends Driver
+{
+    protected $selectSql = 'SELECT %LIMIT% %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%';
 
     /**
      * 解析pdo连接的dsn信息
@@ -23,11 +25,12 @@ class Firebird extends Driver{
      * @param array $config 连接信息
      * @return string
      */
-    protected function parseDsn($config){
-       $dsn  =   'firebird:dbname='.$config['hostname'].'/'.($config['hostport']?:3050).':'.$config['database'];
-       return $dsn;
+    protected function parseDsn($config)
+    {
+        $dsn = 'firebird:dbname=' . $config['hostname'] . '/' . ($config['hostport'] ?: 3050) . ':' . $config['database'];
+        return $dsn;
     }
-    
+
     /**
      * 执行语句
      * @access public
@@ -35,38 +38,45 @@ class Firebird extends Driver{
      * @param boolean $fetchSql  不执行只是获取SQL
      * @return mixed
      */
-    public function execute($str,$fetchSql=false) {
+    public function execute($str, $fetchSql = false)
+    {
         $this->initConnect(true);
-        if ( !$this->_linkID ) return false;
+        if (!$this->_linkID) {
+            return false;
+        }
+
         $this->queryStr = $str;
-        if(!empty($this->bind)){
-            $that   =   $this;
-            $this->queryStr =   strtr($this->queryStr,array_map(function($val) use($that){ return '\''.$that->escapeString($val).'\''; },$this->bind));
+        if (!empty($this->bind)) {
+            $that           = $this;
+            $this->queryStr = strtr($this->queryStr, array_map(function ($val) use ($that) {return '\'' . $that->escapeString($val) . '\'';}, $this->bind));
         }
-        if($fetchSql){
+        if ($fetchSql) {
             return $this->queryStr;
         }
         //释放前次的查询结果
-        if ( !empty($this->PDOStatement) ) $this->free();
+        if (!empty($this->PDOStatement)) {
+            $this->free();
+        }
+
         $this->executeTimes++;
-        N('db_write',1); // 兼容代码
+        N('db_write', 1); // 兼容代码
         // 记录开始执行时间
         $this->debug(true);
-        $this->PDOStatement =   $this->_linkID->prepare($str);
-        if(false === $this->PDOStatement) {
+        $this->PDOStatement = $this->_linkID->prepare($str);
+        if (false === $this->PDOStatement) {
             E($this->error());
         }
         foreach ($this->bind as $key => $val) {
-            if(is_array($val)){
+            if (is_array($val)) {
                 $this->PDOStatement->bindValue($key, $val[0], $val[1]);
-            }else{
+            } else {
                 $this->PDOStatement->bindValue($key, $val);
             }
         }
-        $this->bind =   array();
-        $result =   $this->PDOStatement->execute();
+        $this->bind = array();
+        $result     = $this->PDOStatement->execute();
         $this->debug(false);
-        if ( false === $result) {
+        if (false === $result) {
             $this->error();
             return false;
         } else {
@@ -74,23 +84,24 @@ class Firebird extends Driver{
             return $this->numRows;
         }
     }
-    
+
     /**
      * 取得数据表的字段信息
      * @access public
      */
-    public function getFields($tableName) {
+    public function getFields($tableName)
+    {
         $this->initConnect(true);
         list($tableName) = explode(' ', $tableName);
-        $sql='SELECT RF.RDB$FIELD_NAME AS FIELD,RF.RDB$DEFAULT_VALUE AS DEFAULT1,RF.RDB$NULL_FLAG AS NULL1,TRIM(T.RDB$TYPE_NAME) || \'(\' || F.RDB$FIELD_LENGTH || \')\' as TYPE FROM RDB$RELATION_FIELDS RF LEFT JOIN RDB$FIELDS F ON (F.RDB$FIELD_NAME = RF.RDB$FIELD_SOURCE) LEFT JOIN RDB$TYPES T ON (T.RDB$TYPE = F.RDB$FIELD_TYPE) WHERE RDB$RELATION_NAME=UPPER(\''.$tableName.'\') AND T.RDB$FIELD_NAME = \'RDB$FIELD_TYPE\' ORDER By RDB$FIELD_POSITION';
-        $result = $this->query($sql);
-        $info   =   array();
-        if($result){
-            foreach($result as $key => $val){
+        $sql             = 'SELECT RF.RDB$FIELD_NAME AS FIELD,RF.RDB$DEFAULT_VALUE AS DEFAULT1,RF.RDB$NULL_FLAG AS NULL1,TRIM(T.RDB$TYPE_NAME) || \'(\' || F.RDB$FIELD_LENGTH || \')\' as TYPE FROM RDB$RELATION_FIELDS RF LEFT JOIN RDB$FIELDS F ON (F.RDB$FIELD_NAME = RF.RDB$FIELD_SOURCE) LEFT JOIN RDB$TYPES T ON (T.RDB$TYPE = F.RDB$FIELD_TYPE) WHERE RDB$RELATION_NAME=UPPER(\'' . $tableName . '\') AND T.RDB$FIELD_NAME = \'RDB$FIELD_TYPE\' ORDER By RDB$FIELD_POSITION';
+        $result          = $this->query($sql);
+        $info            = array();
+        if ($result) {
+            foreach ($result as $key => $val) {
                 $info[trim($val['field'])] = array(
                     'name'    => trim($val['field']),
                     'type'    => $val['type'],
-                    'notnull' => (bool) ($val['null1'] ==1), // 1表示不为Null
+                    'notnull' => (bool) (1 == $val['null1']), // 1表示不为Null
                     'default' => $val['default1'],
                     'primary' => false,
                     'autoinc' => false,
@@ -98,35 +109,37 @@ class Firebird extends Driver{
             }
         }
         //获取主键
-        $sql='select b.rdb$field_name as field_name from rdb$relation_constraints a join rdb$index_segments b on a.rdb$index_name=b.rdb$index_name where a.rdb$constraint_type=\'PRIMARY KEY\' and a.rdb$relation_name=UPPER(\''.$tableName.'\')';
+        $sql     = 'select b.rdb$field_name as field_name from rdb$relation_constraints a join rdb$index_segments b on a.rdb$index_name=b.rdb$index_name where a.rdb$constraint_type=\'PRIMARY KEY\' and a.rdb$relation_name=UPPER(\'' . $tableName . '\')';
         $rs_temp = $this->query($sql);
-        foreach($rs_temp as $row) {
-            $info[trim($row['field_name'])]['primary']= true;
+        foreach ($rs_temp as $row) {
+            $info[trim($row['field_name'])]['primary'] = true;
         }
         return $info;
     }
-    
+
     /**
      * 取得数据库的表信息
      * @access public
      */
-    public function getTables($dbName='') {
-        $sql='SELECT DISTINCT RDB$RELATION_NAME FROM RDB$RELATION_FIELDS WHERE RDB$SYSTEM_FLAG=0';
-        $result   =  $this->query($sql);
-        $info   =   array();
+    public function getTables($dbName = '')
+    {
+        $sql    = 'SELECT DISTINCT RDB$RELATION_NAME FROM RDB$RELATION_FIELDS WHERE RDB$SYSTEM_FLAG=0';
+        $result = $this->query($sql);
+        $info   = array();
         foreach ($result as $key => $val) {
             $info[$key] = trim(current($val));
         }
         return $info;
     }
-    
+
     /**
      * SQL指令安全过滤
      * @access public
      * @param string $str  SQL指令
      * @return string
      */
-    public function escapeString($str) {
+    public function escapeString($str)
+    {
         return str_replace("'", "''", $str);
     }
 
@@ -136,16 +149,28 @@ class Firebird extends Driver{
      * @param $limit limit表达式
      * @return string
      */
-    public function parseLimit($limit) {
-        $limitStr    = '';
-        if(!empty($limit)) {
-            $limit  =   explode(',',$limit);
-            if(count($limit)>1) {
-                 $limitStr = ' FIRST '.$limit[1].' SKIP '.$limit[0].' ';
-            }else{
-              $limitStr = ' FIRST '.$limit[0].' ';
+    public function parseLimit($limit)
+    {
+        $limitStr = '';
+        if (!empty($limit)) {
+            $limit = explode(',', $limit);
+            if (count($limit) > 1) {
+                $limitStr = ' FIRST ' . $limit[1] . ' SKIP ' . $limit[0] . ' ';
+            } else {
+                $limitStr = ' FIRST ' . $limit[0] . ' ';
             }
         }
         return $limitStr;
     }
+
+    /**
+     * 随机排序
+     * @access protected
+     * @return string
+     */
+    protected function parseRand()
+    {
+        return 'rand()';
+    }
+
 }

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 374 - 316
server/ThinkPHP/Library/Think/Db/Driver/Mongo.class.php


+ 144 - 99
server/ThinkPHP/Library/Think/Db/Driver/Mysql.class.php

@@ -10,12 +10,14 @@
 // +----------------------------------------------------------------------
 
 namespace Think\Db\Driver;
+
 use Think\Db\Driver;
 
 /**
- * mysql数据库驱动 
+ * mysql数据库驱动
  */
-class Mysql extends Driver{
+class Mysql extends Driver
+{
 
     /**
      * 解析pdo连接的dsn信息
@@ -23,18 +25,19 @@ class Mysql extends Driver{
      * @param array $config 连接信息
      * @return string
      */
-    protected function parseDsn($config){
-        $dsn  =   'mysql:dbname='.$config['database'].';host='.$config['hostname'];
-        if(!empty($config['hostport'])) {
-            $dsn  .= ';port='.$config['hostport'];
-        }elseif(!empty($config['socket'])){
-            $dsn  .= ';unix_socket='.$config['socket'];
+    protected function parseDsn($config)
+    {
+        $dsn = 'mysql:dbname=' . $config['database'] . ';host=' . $config['hostname'];
+        if (!empty($config['hostport'])) {
+            $dsn .= ';port=' . $config['hostport'];
+        } elseif (!empty($config['socket'])) {
+            $dsn .= ';unix_socket=' . $config['socket'];
         }
 
-        if(!empty($config['charset'])){
+        if (!empty($config['charset'])) {
             //为兼容各版本PHP,用两种方式设置编码
-            $this->options[\PDO::MYSQL_ATTR_INIT_COMMAND]    =   'SET NAMES '.$config['charset'];
-            $dsn  .= ';charset='.$config['charset'];
+            $this->options[\PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES ' . $config['charset'];
+            $dsn .= ';charset=' . $config['charset'];
         }
         return $dsn;
     }
@@ -43,27 +46,28 @@ class Mysql extends Driver{
      * 取得数据表的字段信息
      * @access public
      */
-    public function getFields($tableName) {
+    public function getFields($tableName)
+    {
         $this->initConnect(true);
         list($tableName) = explode(' ', $tableName);
-        if(strpos($tableName,'.')){
-        	list($dbName,$tableName) = explode('.',$tableName);
-			$sql   = 'SHOW COLUMNS FROM `'.$dbName.'`.`'.$tableName.'`';
-        }else{
-        	$sql   = 'SHOW COLUMNS FROM `'.$tableName.'`';
+        if (strpos($tableName, '.')) {
+            list($dbName, $tableName) = explode('.', $tableName);
+            $sql                      = 'SHOW COLUMNS FROM `' . $dbName . '`.`' . $tableName . '`';
+        } else {
+            $sql = 'SHOW COLUMNS FROM `' . $tableName . '`';
         }
-        
+
         $result = $this->query($sql);
-        $info   =   array();
-        if($result) {
+        $info   = array();
+        if ($result) {
             foreach ($result as $key => $val) {
-				if(\PDO::CASE_LOWER != $this->_linkID->getAttribute(\PDO::ATTR_CASE)){
-					$val = array_change_key_case ( $val ,  CASE_LOWER );
-				}
+                if (\PDO::CASE_LOWER != $this->_linkID->getAttribute(\PDO::ATTR_CASE)) {
+                    $val = array_change_key_case($val, CASE_LOWER);
+                }
                 $info[$val['field']] = array(
                     'name'    => $val['field'],
                     'type'    => $val['type'],
-                    'notnull' => (bool) ($val['null'] === ''), // not null is empty, null is yes
+                    'notnull' => (bool) ('' === $val['null']), // not null is empty, null is yes
                     'default' => $val['default'],
                     'primary' => (strtolower($val['key']) == 'pri'),
                     'autoinc' => (strtolower($val['extra']) == 'auto_increment'),
@@ -77,10 +81,11 @@ class Mysql extends Driver{
      * 取得数据库的表信息
      * @access public
      */
-    public function getTables($dbName='') {
-        $sql    = !empty($dbName)?'SHOW TABLES FROM '.$dbName:'SHOW TABLES ';
+    public function getTables($dbName = '')
+    {
+        $sql    = !empty($dbName) ? 'SHOW TABLES FROM ' . $dbName : 'SHOW TABLES ';
         $result = $this->query($sql);
-        $info   =   array();
+        $info   = array();
         foreach ($result as $key => $val) {
             $info[$key] = current($val);
         }
@@ -89,18 +94,39 @@ class Mysql extends Driver{
 
     /**
      * 字段和表名处理
-     * @access protected
+     * @access public
      * @param string $key
+     * @param bool   $strict
      * @return string
      */
-    protected function parseKey(&$key) {
-        $key   =  trim($key);
-        if(!is_numeric($key) && !preg_match('/[,\'\"\*\(\)`.\s]/',$key)) {
-           $key = '`'.$key.'`';
+    public function parseKey($key, $strict = false)
+    {
+        if (is_int($key)) {
+            return $key;
+        }
+
+        $key = trim($key);
+
+        if ($strict && !preg_match('/^[\w\.\*]+$/', $key)) {
+            E('not support data:' . $key);
+        }
+
+        if ('*' != $key && !preg_match('/[,\'\"\*\(\)`.\s]/', $key)) {
+            $key = '`' . $key . '`';
         }
         return $key;
     }
 
+    /**
+     * 随机排序
+     * @access protected
+     * @return string
+     */
+    protected function parseRand()
+    {
+        return 'rand()';
+    }
+
     /**
      * 批量插入记录
      * @access public
@@ -109,81 +135,96 @@ class Mysql extends Driver{
      * @param boolean $replace 是否replace
      * @return false | integer
      */
-    public function insertAll($dataSet,$options=array(),$replace=false) {
-        $values  =  array();
-        $this->model  =   $options['model'];
-        if(!is_array($dataSet[0])) return false;
-        $this->parseBind(!empty($options['bind'])?$options['bind']:array());
-        $fields =   array_map(array($this,'parseKey'),array_keys($dataSet[0]));
-        foreach ($dataSet as $data){
-            $value   =  array();
-            foreach ($data as $key=>$val){
-                if(is_array($val) && 'exp' == $val[0]){
-                    $value[]   =  $val[1];
-                }elseif(is_null($val)){
-                    $value[]   =   'NULL';
-                }elseif(is_scalar($val)){
-                    if(0===strpos($val,':') && in_array($val,array_keys($this->bind))){
-                        $value[]   =   $this->parseValue($val);
-                    }else{
-                        $name       =   count($this->bind);
-                        $value[]   =   ':'.$name;
-                        $this->bindParam($name,$val);
+    public function insertAll($dataSet, $options = array(), $replace = false)
+    {
+        $values      = array();
+        $this->model = $options['model'];
+        if (!is_array($dataSet[0])) {
+            return false;
+        }
+
+        $this->parseBind(!empty($options['bind']) ? $options['bind'] : array());
+        $fields = array_map(array($this, 'parseKey'), array_keys($dataSet[0]));
+        foreach ($dataSet as $data) {
+            $value = array();
+            foreach ($data as $key => $val) {
+                if (is_array($val) && 'exp' == $val[0]) {
+                    $value[] = $val[1];
+                } elseif (is_null($val)) {
+                    $value[] = 'NULL';
+                } elseif (is_scalar($val)) {
+                    if (0 === strpos($val, ':') && in_array($val, array_keys($this->bind))) {
+                        $value[] = $this->parseValue($val);
+                    } else {
+                        $name    = count($this->bind);
+                        $value[] = ':' . $name;
+                        $this->bindParam($name, $val);
                     }
                 }
             }
-            $values[]    = '('.implode(',', $value).')';
+            $values[] = '(' . implode(',', $value) . ')';
         }
         // 兼容数字传入方式
-        $replace= (is_numeric($replace) && $replace>0)?true:$replace;
-        $sql    =  (true===$replace?'REPLACE':'INSERT').' INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES '.implode(',',$values).$this->parseDuplicate($replace);
-        $sql    .= $this->parseComment(!empty($options['comment'])?$options['comment']:'');
-        return $this->execute($sql,!empty($options['fetch_sql']) ? true : false);
+        $replace = (is_numeric($replace) && $replace > 0) ? true : $replace;
+        $sql     = (true === $replace ? 'REPLACE' : 'INSERT') . ' INTO ' . $this->parseTable($options['table']) . ' (' . implode(',', $fields) . ') VALUES ' . implode(',', $values) . $this->parseDuplicate($replace);
+        $sql .= $this->parseComment(!empty($options['comment']) ? $options['comment'] : '');
+        return $this->execute($sql, !empty($options['fetch_sql']) ? true : false);
     }
 
     /**
      * ON DUPLICATE KEY UPDATE 分析
      * @access protected
-     * @param mixed $duplicate 
+     * @param mixed $duplicate
      * @return string
      */
-    protected function parseDuplicate($duplicate){
+    protected function parseDuplicate($duplicate)
+    {
         // 布尔值或空则返回空字符串
-        if(is_bool($duplicate) || empty($duplicate)) return '';
-        
-        if(is_string($duplicate)){
-        	// field1,field2 转数组
-        	$duplicate = explode(',', $duplicate);
-        }elseif(is_object($duplicate)){
-        	// 对象转数组
-        	$duplicate = get_class_vars($duplicate);
-        }
-        $updates                    = array();
-        foreach((array) $duplicate as $key=>$val){
-            if(is_numeric($key)){ // array('field1', 'field2', 'field3') 解析为 ON DUPLICATE KEY UPDATE field1=VALUES(field1), field2=VALUES(field2), field3=VALUES(field3)
-                $updates[]          = $this->parseKey($val)."=VALUES(".$this->parseKey($val).")";
-            }else{
-                if(is_scalar($val)) // 兼容标量传值方式
-                    $val            = array('value', $val);
-                if(!isset($val[1])) continue;
-                switch($val[0]){
+        if (is_bool($duplicate) || empty($duplicate)) {
+            return '';
+        }
+
+        if (is_string($duplicate)) {
+            // field1,field2 转数组
+            $duplicate = explode(',', $duplicate);
+        } elseif (is_object($duplicate)) {
+            // 对象转数组
+            $duplicate = get_class_vars($duplicate);
+        }
+        $updates = array();
+        foreach ((array) $duplicate as $key => $val) {
+            if (is_numeric($key)) {
+                // array('field1', 'field2', 'field3') 解析为 ON DUPLICATE KEY UPDATE field1=VALUES(field1), field2=VALUES(field2), field3=VALUES(field3)
+                $updates[] = $this->parseKey($val) . "=VALUES(" . $this->parseKey($val) . ")";
+            } else {
+                if (is_scalar($val)) // 兼容标量传值方式
+                {
+                    $val = array('value', $val);
+                }
+
+                if (!isset($val[1]) && !is_null($val[1])) {
+                    continue;
+                }
+
+                switch ($val[0]) {
                     case 'exp': // 表达式
-                        $updates[]  = $this->parseKey($key)."=($val[1])";
+                        $updates[] = $this->parseKey($key) . "=($val[1])";
                         break;
                     case 'value': // 值
                     default:
-                        $name       = count($this->bind);
-                        $updates[]  = $this->parseKey($key)."=:".$name;
+                        $name      = count($this->bind);
+                        $updates[] = $this->parseKey($key) . "=:" . $name;
                         $this->bindParam($name, $val[1]);
                         break;
                 }
             }
         }
-        if(empty($updates)) return '';
-        return " ON DUPLICATE KEY UPDATE ".join(', ', $updates);
+        if (empty($updates)) {
+            return '';
+        }
+
+        return " ON DUPLICATE KEY UPDATE " . join(', ', $updates);
     }
-    
-	
 
     /**
      * 执行存储过程查询 返回多个数据集
@@ -192,41 +233,45 @@ class Mysql extends Driver{
      * @param boolean $fetchSql  不执行只是获取SQL
      * @return mixed
      */
-    public function procedure($str,$fetchSql=false) {
+    public function procedure($str, $fetchSql = false)
+    {
         $this->initConnect(false);
         $this->_linkID->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_WARNING);
-        if ( !$this->_linkID ) return false;
-        $this->queryStr     =   $str;
-        if($fetchSql){
+        if (!$this->_linkID) {
+            return false;
+        }
+
+        $this->queryStr = $str;
+        if ($fetchSql) {
             return $this->queryStr;
         }
         //释放前次的查询结果
-        if ( !empty($this->PDOStatement) ) $this->free();
+        if (!empty($this->PDOStatement)) {
+            $this->free();
+        }
+
         $this->queryTimes++;
-        N('db_query',1); // 兼容代码
+        N('db_query', 1); // 兼容代码
         // 调试开始
         $this->debug(true);
         $this->PDOStatement = $this->_linkID->prepare($str);
-        if(false === $this->PDOStatement){
+        if (false === $this->PDOStatement) {
             $this->error();
             return false;
         }
-        try{
+        try {
             $result = $this->PDOStatement->execute();
             // 调试结束
             $this->debug(false);
-            do
-            {
+            do {
                 $result = $this->PDOStatement->fetchAll(\PDO::FETCH_ASSOC);
-                if ($result)
-                {
+                if ($result) {
                     $resultArr[] = $result;
                 }
-            }
-            while ($this->PDOStatement->nextRowset());
+            } while ($this->PDOStatement->nextRowset());
             $this->_linkID->setAttribute(\PDO::ATTR_ERRMODE, $this->options[\PDO::ATTR_ERRMODE]);
             return $resultArr;
-        }catch (\PDOException $e) {
+        } catch (\PDOException $e) {
             $this->error();
             $this->_linkID->setAttribute(\PDO::ATTR_ERRMODE, $this->options[\PDO::ATTR_ERRMODE]);
             return false;

+ 78 - 48
server/ThinkPHP/Library/Think/Db/Driver/Oracle.class.php

@@ -10,15 +10,17 @@
 // +----------------------------------------------------------------------
 
 namespace Think\Db\Driver;
+
 use Think\Db\Driver;
 
 /**
  * Oracle数据库驱动
  */
-class Oracle extends Driver{
+class Oracle extends Driver
+{
 
-    private     $table        = '';
-    protected   $selectSql    = 'SELECT * FROM (SELECT thinkphp.*, rownum AS numrow FROM (SELECT  %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%) thinkphp ) %LIMIT%%COMMENT%';
+    private $table       = '';
+    protected $selectSql = 'SELECT * FROM (SELECT thinkphp.*, rownum AS numrow FROM (SELECT  %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%) thinkphp ) %LIMIT%%COMMENT%';
 
     /**
      * 解析pdo连接的dsn信息
@@ -26,10 +28,11 @@ class Oracle extends Driver{
      * @param array $config 连接信息
      * @return string
      */
-    protected function parseDsn($config){
-        $dsn  =   'oci:dbname=//'.$config['hostname'].($config['hostport']?':'.$config['hostport']:'').'/'.$config['database'];
-        if(!empty($config['charset'])) {
-            $dsn  .= ';charset='.$config['charset'];
+    protected function parseDsn($config)
+    {
+        $dsn = 'oci:dbname=//' . $config['hostname'] . ($config['hostport'] ? ':' . $config['hostport'] : '') . '/' . $config['database'];
+        if (!empty($config['charset'])) {
+            $dsn .= ';charset=' . $config['charset'];
         }
         return $dsn;
     }
@@ -38,52 +41,59 @@ class Oracle extends Driver{
      * 执行语句
      * @access public
      * @param string $str  sql指令
-     * @param boolean $fetchSql  不执行只是获取SQL     
+     * @param boolean $fetchSql  不执行只是获取SQL
      * @return integer
      */
-    public function execute($str,$fetchSql=false) {
+    public function execute($str, $fetchSql = false)
+    {
         $this->initConnect(true);
-        if ( !$this->_linkID ) return false;
+        if (!$this->_linkID) {
+            return false;
+        }
+
         $this->queryStr = $str;
-        if(!empty($this->bind)){
-            $that   =   $this;
-            $this->queryStr =   strtr($this->queryStr,array_map(function($val) use($that){ return '\''.$that->escapeString($val).'\''; },$this->bind));
+        if (!empty($this->bind)) {
+            $that           = $this;
+            $this->queryStr = strtr($this->queryStr, array_map(function ($val) use ($that) {return '\'' . $that->escapeString($val) . '\'';}, $this->bind));
         }
-        if($fetchSql){
+        if ($fetchSql) {
             return $this->queryStr;
         }
         $flag = false;
-        if(preg_match("/^\s*(INSERT\s+INTO)\s+(\w+)\s+/i", $str, $match)) {
-            $this->table = C("DB_SEQUENCE_PREFIX").str_ireplace(C("DB_PREFIX"), "", $match[2]);
-            $flag = (boolean)$this->query("SELECT * FROM user_sequences WHERE sequence_name='" . strtoupper($this->table) . "'");
+        if (preg_match("/^\s*(INSERT\s+INTO)\s+(\w+)\s+/i", $str, $match)) {
+            $this->table = C("DB_SEQUENCE_PREFIX") . str_ireplace(C("DB_PREFIX"), "", $match[2]);
+            $flag        = (boolean) $this->query("SELECT * FROM user_sequences WHERE sequence_name='" . strtoupper($this->table) . "'");
         }
         //释放前次的查询结果
-        if ( !empty($this->PDOStatement) ) $this->free();
+        if (!empty($this->PDOStatement)) {
+            $this->free();
+        }
+
         $this->executeTimes++;
-        N('db_write',1); // 兼容代码        
+        N('db_write', 1); // 兼容代码
         // 记录开始执行时间
         $this->debug(true);
-        $this->PDOStatement	=	$this->_linkID->prepare($str);
-        if(false === $this->PDOStatement) {
+        $this->PDOStatement = $this->_linkID->prepare($str);
+        if (false === $this->PDOStatement) {
             $this->error();
             return false;
         }
         foreach ($this->bind as $key => $val) {
-            if(is_array($val)){
+            if (is_array($val)) {
                 $this->PDOStatement->bindValue($key, $val[0], $val[1]);
-            }else{
+            } else {
                 $this->PDOStatement->bindValue($key, $val);
             }
         }
-        $this->bind =   array();        
-        $result	=	$this->PDOStatement->execute();
+        $this->bind = array();
+        $result     = $this->PDOStatement->execute();
         $this->debug(false);
-        if ( false === $result) {
+        if (false === $result) {
             $this->error();
             return false;
         } else {
             $this->numRows = $this->PDOStatement->rowCount();
-            if($flag || preg_match("/^\s*(INSERT\s+INTO|REPLACE\s+INTO)\s+/i", $str)) {
+            if ($flag || preg_match("/^\s*(INSERT\s+INTO|REPLACE\s+INTO)\s+/i", $str)) {
                 $this->lastInsID = $this->_linkID->lastInsertId();
             }
             return $this->numRows;
@@ -94,14 +104,15 @@ class Oracle extends Driver{
      * 取得数据表的字段信息
      * @access public
      */
-     public function getFields($tableName) {
+    public function getFields($tableName)
+    {
         list($tableName) = explode(' ', $tableName);
-        $result = $this->query("select a.column_name,data_type,decode(nullable,'Y',0,1) notnull,data_default,decode(a.column_name,b.column_name,1,0) pk "
-                  ."from user_tab_columns a,(select column_name from user_constraints c,user_cons_columns col "
-          ."where c.constraint_name=col.constraint_name and c.constraint_type='P'and c.table_name='".strtoupper($tableName)
-          ."') b where table_name='".strtoupper($tableName)."' and a.column_name=b.column_name(+)");
-        $info   =   array();
-        if($result) {
+        $result          = $this->query("select a.column_name,data_type,decode(nullable,'Y',0,1) notnull,data_default,decode(a.column_name,b.column_name,1,0) pk "
+            . "from user_tab_columns a,(select column_name from user_constraints c,user_cons_columns col "
+            . "where c.constraint_name=col.constraint_name and c.constraint_type='P'and c.table_name='" . strtoupper($tableName)
+            . "') b where table_name='" . strtoupper($tableName) . "' and a.column_name=b.column_name(+)");
+        $info = array();
+        if ($result) {
             foreach ($result as $key => $val) {
                 $info[strtolower($val['column_name'])] = array(
                     'name'    => strtolower($val['column_name']),
@@ -120,9 +131,10 @@ class Oracle extends Driver{
      * 取得数据库的表信息(暂时实现取得用户表信息)
      * @access public
      */
-    public function getTables($dbName='') {
+    public function getTables($dbName = '')
+    {
         $result = $this->query("select table_name from user_tables");
-        $info   =   array();
+        $info   = array();
         foreach ($result as $key => $val) {
             $info[$key] = current($val);
         }
@@ -135,7 +147,8 @@ class Oracle extends Driver{
      * @param string $str  SQL指令
      * @return string
      */
-    public function escapeString($str) {
+    public function escapeString($str)
+    {
         return str_ireplace("'", "''", $str);
     }
 
@@ -144,16 +157,19 @@ class Oracle extends Driver{
      * @access public
      * @return string
      */
-	public function parseLimit($limit) {
-        $limitStr    = '';
-        if(!empty($limit)) {
-            $limit	=	explode(',',$limit);
-            if(count($limit)>1)
-                $limitStr = "(numrow>" . $limit[0] . ") AND (numrow<=" . ($limit[0]+$limit[1]) . ")";
-            else
-                $limitStr = "(numrow>0 AND numrow<=".$limit[0].")";
+    public function parseLimit($limit)
+    {
+        $limitStr = '';
+        if (!empty($limit)) {
+            $limit = explode(',', $limit);
+            if (count($limit) > 1) {
+                $limitStr = "(numrow>" . $limit[0] . ") AND (numrow<=" . ($limit[0] + $limit[1]) . ")";
+            } else {
+                $limitStr = "(numrow>0 AND numrow<=" . $limit[0] . ")";
+            }
+
         }
-        return $limitStr?' WHERE '.$limitStr:'';
+        return $limitStr ? ' WHERE ' . $limitStr : '';
     }
 
     /**
@@ -161,8 +177,22 @@ class Oracle extends Driver{
      * @access protected
      * @return string
      */
-    protected function parseLock($lock=false) {
-        if(!$lock) return '';
+    protected function parseLock($lock = false)
+    {
+        if (!$lock) {
+            return '';
+        }
+
         return ' FOR UPDATE NOWAIT ';
     }
+
+    /**
+     * 随机排序
+     * @access protected
+     * @return string
+     */
+    protected function parseRand()
+    {
+        return 'DBMS_RANDOM.value';
+    }
 }

+ 36 - 21
server/ThinkPHP/Library/Think/Db/Driver/Pgsql.class.php

@@ -10,12 +10,14 @@
 // +----------------------------------------------------------------------
 
 namespace Think\Db\Driver;
+
 use Think\Db\Driver;
 
 /**
  * Pgsql数据库驱动
  */
-class Pgsql extends Driver{
+class Pgsql extends Driver
+{
 
     /**
      * 解析pdo连接的dsn信息
@@ -23,10 +25,11 @@ class Pgsql extends Driver{
      * @param array $config 连接信息
      * @return string
      */
-    protected function parseDsn($config){
-        $dsn  =   'pgsql:dbname='.$config['database'].';host='.$config['hostname'];
-        if(!empty($config['hostport'])) {
-            $dsn  .= ';port='.$config['hostport'];
+    protected function parseDsn($config)
+    {
+        $dsn = 'pgsql:dbname=' . $config['database'] . ';host=' . $config['hostname'];
+        if (!empty($config['hostport'])) {
+            $dsn .= ';port=' . $config['hostport'];
         }
         return $dsn;
     }
@@ -36,16 +39,17 @@ class Pgsql extends Driver{
      * @access public
      * @return array
      */
-    public function getFields($tableName) {
+    public function getFields($tableName)
+    {
         list($tableName) = explode(' ', $tableName);
-        $result =   $this->query('select fields_name as "field",fields_type as "type",fields_not_null as "null",fields_key_name as "key",fields_default as "default",fields_default as "extra" from table_msg('.$tableName.');');
-        $info   =   array();
-        if($result){
+        $result          = $this->query('select fields_name as "field",fields_type as "type",fields_not_null as "null",fields_key_name as "key",fields_default as "default",fields_default as "extra" from table_msg(\'' . $tableName . '\');');
+        $info            = array();
+        if ($result) {
             foreach ($result as $key => $val) {
                 $info[$val['field']] = array(
                     'name'    => $val['field'],
                     'type'    => $val['type'],
-                    'notnull' => (bool) ($val['null'] === ''), // not null is empty, null is yes
+                    'notnull' => (bool) ('' === $val['null']), // not null is empty, null is yes
                     'default' => $val['default'],
                     'primary' => (strtolower($val['key']) == 'pri'),
                     'autoinc' => (strtolower($val['extra']) == 'auto_increment'),
@@ -60,9 +64,10 @@ class Pgsql extends Driver{
      * @access public
      * @return array
      */
-    public function getTables($dbName='') {
-        $result =   $this->query("select tablename as Tables_in_test from pg_tables where  schemaname ='public'");
-        $info   =   array();
+    public function getTables($dbName = '')
+    {
+        $result = $this->query("select tablename as Tables_in_test from pg_tables where  schemaname ='public'");
+        $info   = array();
         foreach ($result as $key => $val) {
             $info[$key] = current($val);
         }
@@ -75,17 +80,27 @@ class Pgsql extends Driver{
      * @param mixed $lmit
      * @return string
      */
-    public function parseLimit($limit) {
-        $limitStr    = '';
-        if(!empty($limit)) {
-            $limit  =   explode(',',$limit);
-            if(count($limit)>1) {
-                $limitStr .= ' LIMIT '.$limit[1].' OFFSET '.$limit[0].' ';
-            }else{
-                $limitStr .= ' LIMIT '.$limit[0].' ';
+    public function parseLimit($limit)
+    {
+        $limitStr = '';
+        if (!empty($limit)) {
+            $limit = explode(',', $limit);
+            if (count($limit) > 1) {
+                $limitStr .= ' LIMIT ' . $limit[1] . ' OFFSET ' . $limit[0] . ' ';
+            } else {
+                $limitStr .= ' LIMIT ' . $limit[0] . ' ';
             }
         }
         return $limitStr;
     }
 
+    /**
+     * 随机排序
+     * @access protected
+     * @return string
+     */
+    protected function parseRand()
+    {
+        return 'RANDOM()';
+    }
 }

+ 44 - 28
server/ThinkPHP/Library/Think/Db/Driver/Sqlite.class.php

@@ -10,12 +10,14 @@
 // +----------------------------------------------------------------------
 
 namespace Think\Db\Driver;
+
 use Think\Db\Driver;
 
 /**
  * Sqlite数据库驱动
  */
-class Sqlite extends Driver {
+class Sqlite extends Driver
+{
 
     /**
      * 解析pdo连接的dsn信息
@@ -23,8 +25,9 @@ class Sqlite extends Driver {
      * @param array $config 连接信息
      * @return string
      */
-    protected function parseDsn($config){
-        $dsn  =   'sqlite:'.$config['database'];
+    protected function parseDsn($config)
+    {
+        $dsn = 'sqlite:' . $config['database'];
         return $dsn;
     }
 
@@ -33,20 +36,20 @@ class Sqlite extends Driver {
      * @access public
      * @return array
      */
-    public function getFields($tableName) {
+    public function getFields($tableName)
+    {
         list($tableName) = explode(' ', $tableName);
-        $result =   $this->query('PRAGMA table_info( '.$tableName.' )');
-        $info   =   array();
-        if($result){
+        $result          = $this->query('PRAGMA table_info( ' . $tableName . ' )');
+        $info            = array();
+        if ($result) {
             foreach ($result as $key => $val) {
-                $name = isset($val['field']) ? $val['field'] : $val['name'];
-                $info[$name] = array(
-                    'name'    => $name,
+                $info[$val['name']] = array(
+                    'name'    => $val['name'],
                     'type'    => $val['type'],
-                    'notnull' => (bool)(((isset($val['null'])) && ($val['null'] === '')) || ((isset($val['notnull'])) && ($val['notnull'] === ''))), // not null is empty, null is yes
-                    'default' => isset($val['default']) ? $val['default'] : (isset($val['dflt_value'])?$val['dflt_value']:""),
-                    'primary' => isset($val['key']) ? strtolower($val['key']) == 'pri' : (isset($val['pk']) ? $val['pk'] : false),
-                    'autoinc' => isset($val['extra']) ? strtolower($val['extra']) == 'auto_increment' : (isset($val['key']) ? $val['key'] : false),
+                    'notnull' => (bool) (1 === $val['notnull']),
+                    'default' => $val['dflt_value'],
+                    'primary' => '1' == $val['pk'],
+                    'autoinc' => false,
                 );
             }
         }
@@ -58,11 +61,12 @@ class Sqlite extends Driver {
      * @access public
      * @return array
      */
-    public function getTables($dbName='') {
-        $result =   $this->query("SELECT name FROM sqlite_master WHERE type='table' "
-             . "UNION ALL SELECT name FROM sqlite_temp_master "
-             . "WHERE type='table' ORDER BY name");
-        $info   =   array();
+    public function getTables($dbName = '')
+    {
+        $result = $this->query("SELECT name FROM sqlite_master WHERE type='table' "
+            . "UNION ALL SELECT name FROM sqlite_temp_master "
+            . "WHERE type='table' ORDER BY name");
+        $info = array();
         foreach ($result as $key => $val) {
             $info[$key] = current($val);
         }
@@ -75,7 +79,8 @@ class Sqlite extends Driver {
      * @param string $str  SQL指令
      * @return string
      */
-    public function escapeString($str) {
+    public function escapeString($str)
+    {
         return str_ireplace("'", "''", $str);
     }
 
@@ -84,16 +89,27 @@ class Sqlite extends Driver {
      * @access public
      * @return string
      */
-    public function parseLimit($limit) {
-        $limitStr    = '';
-        if(!empty($limit)) {
-            $limit  =   explode(',',$limit);
-            if(count($limit)>1) {
-                $limitStr .= ' LIMIT '.$limit[1].' OFFSET '.$limit[0].' ';
-            }else{
-                $limitStr .= ' LIMIT '.$limit[0].' ';
+    public function parseLimit($limit)
+    {
+        $limitStr = '';
+        if (!empty($limit)) {
+            $limit = explode(',', $limit);
+            if (count($limit) > 1) {
+                $limitStr .= ' LIMIT ' . $limit[1] . ' OFFSET ' . $limit[0] . ' ';
+            } else {
+                $limitStr .= ' LIMIT ' . $limit[0] . ' ';
             }
         }
         return $limitStr;
     }
+
+    /**
+     * 随机排序
+     * @access protected
+     * @return string
+     */
+    protected function parseRand()
+    {
+        return 'RANDOM()';
+    }
 }

+ 78 - 57
server/ThinkPHP/Library/Think/Db/Driver/Sqlsrv.class.php

@@ -10,20 +10,22 @@
 // +----------------------------------------------------------------------
 
 namespace Think\Db\Driver;
-use Think\Db\Driver;
+
 use PDO;
+use Think\Db\Driver;
 
 /**
  * Sqlsrv数据库驱动
  */
-class Sqlsrv extends Driver{
-    protected $selectSql  =     'SELECT T1.* FROM (SELECT thinkphp.*, ROW_NUMBER() OVER (%ORDER%) AS ROW_NUMBER FROM (SELECT %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING% %UNION%) AS thinkphp) AS T1 %LIMIT%%COMMENT%';
+class Sqlsrv extends Driver
+{
+    protected $selectSql = 'SELECT T1.* FROM (SELECT thinkphp.*, ROW_NUMBER() OVER (%ORDER%) AS ROW_NUMBER FROM (SELECT %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING% %UNION%) AS thinkphp) AS T1 %LIMIT%%COMMENT%';
     // PDO连接参数
     protected $options = array(
-        PDO::ATTR_CASE              =>  PDO::CASE_LOWER,
-        PDO::ATTR_ERRMODE           =>  PDO::ERRMODE_EXCEPTION,
-        PDO::ATTR_STRINGIFY_FETCHES =>  false,
-        PDO::SQLSRV_ATTR_ENCODING   =>  PDO::SQLSRV_ENCODING_UTF8,
+        PDO::ATTR_CASE              => PDO::CASE_LOWER,
+        PDO::ATTR_ERRMODE           => PDO::ERRMODE_EXCEPTION,
+        PDO::ATTR_STRINGIFY_FETCHES => false,
+        PDO::SQLSRV_ATTR_ENCODING   => PDO::SQLSRV_ENCODING_UTF8,
     );
 
     /**
@@ -32,10 +34,11 @@ class Sqlsrv extends Driver{
      * @param array $config 连接信息
      * @return string
      */
-    protected function parseDsn($config){
-        $dsn  =   'sqlsrv:Database='.$config['database'].';Server='.$config['hostname'];
-        if(!empty($config['hostport'])) {
-            $dsn  .= ','.$config['hostport'];
+    protected function parseDsn($config)
+    {
+        $dsn = 'sqlsrv:Database=' . $config['database'] . ';Server=' . $config['hostname'];
+        if (!empty($config['hostport'])) {
+            $dsn .= ',' . $config['hostport'];
         }
         return $dsn;
     }
@@ -45,22 +48,23 @@ class Sqlsrv extends Driver{
      * @access public
      * @return array
      */
-    public function getFields($tableName) {
+    public function getFields($tableName)
+    {
         list($tableName) = explode(' ', $tableName);
-        $result =   $this->query("SELECT   column_name,   data_type,   column_default,   is_nullable
+        $result          = $this->query("SELECT   column_name,   data_type,   column_default,   is_nullable
         FROM    information_schema.tables AS t
         JOIN    information_schema.columns AS c
         ON  t.table_catalog = c.table_catalog
         AND t.table_schema  = c.table_schema
         AND t.table_name    = c.table_name
         WHERE   t.table_name = '$tableName'");
-        $info   =   array();
-        if($result) {
+        $info = array();
+        if ($result) {
             foreach ($result as $key => $val) {
                 $info[$val['column_name']] = array(
                     'name'    => $val['column_name'],
                     'type'    => $val['data_type'],
-                    'notnull' => (bool) ($val['is_nullable'] === ''), // not null is empty, null is yes
+                    'notnull' => (bool) ('' === $val['is_nullable']), // not null is empty, null is yes
                     'default' => $val['column_default'],
                     'primary' => false,
                     'autoinc' => false,
@@ -75,40 +79,49 @@ class Sqlsrv extends Driver{
      * @access public
      * @return array
      */
-    public function getTables($dbName='') {
-        $result   =  $this->query("SELECT TABLE_NAME
+    public function getTables($dbName = '')
+    {
+        $result = $this->query("SELECT TABLE_NAME
             FROM INFORMATION_SCHEMA.TABLES
             WHERE TABLE_TYPE = 'BASE TABLE'
             ");
-        $info   =   array();
+        $info = array();
         foreach ($result as $key => $val) {
             $info[$key] = current($val);
         }
         return $info;
     }
 
-	/**
+    /**
      * order分析
      * @access protected
      * @param mixed $order
      * @return string
      */
-    protected function parseOrder($order) {
-        return !empty($order)?  ' ORDER BY '.$order:' ORDER BY rand()';
+    protected function parseOrder($order)
+    {
+        return !empty($order) ? ' ORDER BY ' . $order : ' ORDER BY rand()';
     }
 
     /**
-     * 字段名分析
-     * @access protected
+     * 字段和表名处理
+     * @access public
      * @param string $key
+     * @param bool   $strict
      * @return string
      */
-    protected function parseKey(&$key) {
-        $key   =  trim($key);
-        if(!is_numeric($key) && !preg_match('/[,\'\"\*\(\)\[.\s]/',$key)) {
-           $key = '['.$key.']';
+    public function parseKey($key, $strict = false)
+    {
+        $key = trim($key);
+
+        if ($strict && !preg_match('/^[\w\.\*]+$/', $key)) {
+            E('not support data:' . $key);
         }
-        return $key;   
+
+        if ($strict || (!is_numeric($key) && !preg_match('/[,\'\"\*\(\)\[.\s]/', $key))) {
+            $key = '[' . $key . ']';
+        }
+        return $key;
     }
 
     /**
@@ -117,14 +130,20 @@ class Sqlsrv extends Driver{
      * @param mixed $limit
      * @return string
      */
-    public function parseLimit($limit) {
-        if(empty($limit)) return '';
-        $limit	=	explode(',',$limit);
-        if(count($limit)>1)
-            $limitStr	=	'(T1.ROW_NUMBER BETWEEN '.$limit[0].' + 1 AND '.$limit[0].' + '.$limit[1].')';
-        else
-            $limitStr = '(T1.ROW_NUMBER BETWEEN 1 AND '.$limit[0].")";
-        return 'WHERE '.$limitStr;
+    public function parseLimit($limit)
+    {
+        if (empty($limit)) {
+            return '';
+        }
+
+        $limit = explode(',', $limit);
+        if (count($limit) > 1) {
+            $limitStr = '(T1.ROW_NUMBER BETWEEN ' . $limit[0] . ' + 1 AND ' . $limit[0] . ' + ' . $limit[1] . ')';
+        } else {
+            $limitStr = '(T1.ROW_NUMBER BETWEEN 1 AND ' . $limit[0] . ")";
+        }
+
+        return 'WHERE ' . $limitStr;
     }
 
     /**
@@ -134,16 +153,17 @@ class Sqlsrv extends Driver{
      * @param array $options 表达式
      * @return false | integer
      */
-    public function update($data,$options) {
-        $this->model  =   $options['model'];
-        $this->parseBind(!empty($options['bind'])?$options['bind']:array());
-        $sql   = 'UPDATE '
-            .$this->parseTable($options['table'])
-            .$this->parseSet($data)
-            .$this->parseWhere(!empty($options['where'])?$options['where']:'')
-            .$this->parseLock(isset($options['lock'])?$options['lock']:false)
-            .$this->parseComment(!empty($options['comment'])?$options['comment']:'');
-        return $this->execute($sql,!empty($options['fetch_sql']) ? true : false);
+    public function update($data, $options)
+    {
+        $this->model = $options['model'];
+        $this->parseBind(!empty($options['bind']) ? $options['bind'] : array());
+        $sql = 'UPDATE '
+        . $this->parseTable($options['table'])
+        . $this->parseSet($data)
+        . $this->parseWhere(!empty($options['where']) ? $options['where'] : '')
+        . $this->parseLock(isset($options['lock']) ? $options['lock'] : false)
+        . $this->parseComment(!empty($options['comment']) ? $options['comment'] : '');
+        return $this->execute($sql, !empty($options['fetch_sql']) ? true : false);
     }
 
     /**
@@ -152,15 +172,16 @@ class Sqlsrv extends Driver{
      * @param array $options 表达式
      * @return false | integer
      */
-    public function delete($options=array()) {
-        $this->model  =   $options['model'];
-        $this->parseBind(!empty($options['bind'])?$options['bind']:array());
-        $sql   = 'DELETE FROM '
-            .$this->parseTable($options['table'])
-            .$this->parseWhere(!empty($options['where'])?$options['where']:'')
-            .$this->parseLock(isset($options['lock'])?$options['lock']:false)
-            .$this->parseComment(!empty($options['comment'])?$options['comment']:'');
-        return $this->execute($sql,!empty($options['fetch_sql']) ? true : false);
+    public function delete($options = array())
+    {
+        $this->model = $options['model'];
+        $this->parseBind(!empty($options['bind']) ? $options['bind'] : array());
+        $sql = 'DELETE FROM '
+        . $this->parseTable($options['table'])
+        . $this->parseWhere(!empty($options['where']) ? $options['where'] : '')
+        . $this->parseLock(isset($options['lock']) ? $options['lock'] : false)
+        . $this->parseComment(!empty($options['comment']) ? $options['comment'] : '');
+        return $this->execute($sql, !empty($options['fetch_sql']) ? true : false);
     }
 
-}
+}

+ 223 - 156
server/ThinkPHP/Library/Think/Db/Lite.class.php

@@ -10,63 +10,66 @@
 // +----------------------------------------------------------------------
 
 namespace Think\Db;
+
+use PDO;
 use Think\Config;
 use Think\Debug;
-use Think\Log;
-use PDO;
 
-class Lite {
+class Lite
+{
     // PDO操作实例
     protected $PDOStatement = null;
     // 当前操作所属的模型名
-    protected $model      = '_think_';
+    protected $model = '_think_';
     // 当前SQL指令
-    protected $queryStr   = '';
-    protected $modelSql   = array();
+    protected $queryStr = '';
+    protected $modelSql = array();
     // 最后插入ID
-    protected $lastInsID  = null;
+    protected $lastInsID = null;
     // 返回或者影响记录数
-    protected $numRows    = 0;
+    protected $numRows = 0;
+   	// 事物操作PDO实例
+    protected $transPDO = null;
     // 事务指令数
     protected $transTimes = 0;
     // 错误信息
-    protected $error      = '';
+    protected $error = '';
     // 数据库连接ID 支持多个连接
-    protected $linkID     = array();
+    protected $linkID = array();
     // 当前连接ID
-    protected $_linkID    = null;
+    protected $_linkID = null;
     // 数据库连接参数配置
-    protected $config     = array(
-        'type'              =>  '',     // 数据库类型
-        'hostname'          =>  '127.0.0.1', // 服务器地址
-        'database'          =>  '',          // 数据库名
-        'username'          =>  '',      // 用户名
-        'password'          =>  '',          // 密码
-        'hostport'          =>  '',        // 端口     
-        'dsn'               =>  '', //          
-        'params'            =>  array(), // 数据库连接参数        
-        'charset'           =>  'utf8',      // 数据库编码默认采用utf8  
-        'prefix'            =>  '',    // 数据库表前缀
-        'debug'             =>  false, // 数据库调试模式
-        'deploy'            =>  0, // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
-        'rw_separate'       =>  false,       // 数据库读写是否分离 主从式有效
-        'master_num'        =>  1, // 读写分离后 主服务器数量
-        'slave_no'          =>  '', // 指定从服务器序号
+    protected $config = array(
+        'type'        => '', // 数据库类型
+        'hostname'    => '127.0.0.1', // 服务器地址
+        'database'    => '', // 数据库名
+        'username'    => '', // 用户名
+        'password'    => '', // 密码
+        'hostport'    => '', // 端口
+        'dsn'         => '', //
+        'params'      => array(), // 数据库连接参数
+        'charset'     => 'utf8', // 数据库编码默认采用utf8
+        'prefix'      => '', // 数据库表前缀
+        'debug'       => false, // 数据库调试模式
+        'deploy'      => 0, // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
+        'rw_separate' => false, // 数据库读写是否分离 主从式有效
+        'master_num'  => 1, // 读写分离后 主服务器数量
+        'slave_no'    => '', // 指定从服务器序号
     );
     // 数据库表达式
-    protected $comparison = array('eq'=>'=','neq'=>'<>','gt'=>'>','egt'=>'>=','lt'=>'<','elt'=>'<=','notlike'=>'NOT LIKE','like'=>'LIKE','in'=>'IN','notin'=>'NOT IN');
+    protected $comparison = array('eq' => '=', 'neq' => '<>', 'gt' => '>', 'egt' => '>=', 'lt' => '<', 'elt' => '<=', 'notlike' => 'NOT LIKE', 'like' => 'LIKE', 'in' => 'IN', 'notin' => 'NOT IN');
     // 查询表达式
-    protected $selectSql  = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT% %UNION%%COMMENT%';
+    protected $selectSql = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT% %UNION%%COMMENT%';
     // 查询次数
-    protected $queryTimes   =   0;
+    protected $queryTimes = 0;
     // 执行次数
-    protected $executeTimes =   0;
+    protected $executeTimes = 0;
     // PDO连接参数
     protected $options = array(
-        PDO::ATTR_CASE              =>  PDO::CASE_LOWER,
-        PDO::ATTR_ERRMODE           =>  PDO::ERRMODE_EXCEPTION,
-        PDO::ATTR_ORACLE_NULLS      =>  PDO::NULL_NATURAL,
-        PDO::ATTR_STRINGIFY_FETCHES =>  false,
+        PDO::ATTR_CASE              => PDO::CASE_LOWER,
+        PDO::ATTR_ERRMODE           => PDO::ERRMODE_EXCEPTION,
+        PDO::ATTR_ORACLE_NULLS      => PDO::NULL_NATURAL,
+        PDO::ATTR_STRINGIFY_FETCHES => false,
     );
 
     /**
@@ -74,11 +77,12 @@ class Lite {
      * @access public
      * @param array $config 数据库配置数组
      */
-    public function __construct($config=''){
-        if(!empty($config)) {
-            $this->config           =   array_merge($this->config,$config);
-            if(is_array($this->config['params'])){
-                $this->options  +=   $this->config['params'];
+    public function __construct($config = '')
+    {
+        if (!empty($config)) {
+            $this->config = array_merge($this->config, $config);
+            if (is_array($this->config['params'])) {
+                $this->options += $this->config['params'];
             }
         }
     }
@@ -87,18 +91,23 @@ class Lite {
      * 连接数据库方法
      * @access public
      */
-    public function connect($config='',$linkNum=0) {
-        if ( !isset($this->linkID[$linkNum]) ) {
-            if(empty($config))  $config =   $this->config;
-            try{
-                if(empty($config['dsn'])) {
-                    $config['dsn']  =   $this->parseDsn($config);
+    public function connect($config = '', $linkNum = 0)
+    {
+        if (!isset($this->linkID[$linkNum])) {
+            if (empty($config)) {
+                $config = $this->config;
+            }
+
+            try {
+                if (empty($config['dsn'])) {
+                    $config['dsn'] = $this->parseDsn($config);
                 }
-                if(version_compare(PHP_VERSION,'5.3.6','<=')){ //禁用模拟预处理语句
-                    $this->options[PDO::ATTR_EMULATE_PREPARES]  =   false;
+                if (version_compare(PHP_VERSION, '5.3.6', '<=')) {
+                    //禁用模拟预处理语句
+                    $this->options[PDO::ATTR_EMULATE_PREPARES] = false;
                 }
-                $this->linkID[$linkNum] = new PDO( $config['dsn'], $config['username'], $config['password'],$this->options);
-            }catch (\PDOException $e) {
+                $this->linkID[$linkNum] = new PDO($config['dsn'], $config['username'], $config['password'], $this->options);
+            } catch (\PDOException $e) {
                 E($e->getMessage());
             }
         }
@@ -111,13 +120,15 @@ class Lite {
      * @param array $config 连接信息
      * @return string
      */
-    protected function parseDsn($config){}
+    protected function parseDsn($config)
+    {}
 
     /**
      * 释放查询结果
      * @access public
      */
-    public function free() {
+    public function free()
+    {
         $this->PDOStatement = null;
     }
 
@@ -128,34 +139,43 @@ class Lite {
      * @param array $bind  参数绑定
      * @return mixed
      */
-    public function query($str,$bind=array()) {
+    public function query($str, $bind = array())
+    {
         $this->initConnect(false);
-        if ( !$this->_linkID ) return false;
-        $this->queryStr     =   $str;
-        if(!empty($bind)){
-            $that   =   $this;
-            $this->queryStr =   strtr($this->queryStr,array_map(function($val) use($that){ return '\''.$that->escapeString($val).'\''; },$bind));
+        if (!$this->_linkID) {
+            return false;
+        }
+
+        $this->queryStr = $str;
+        if (!empty($bind)) {
+            $that           = $this;
+            $this->queryStr = strtr($this->queryStr, array_map(function ($val) use ($that) {return '\'' . $that->escapeString($val) . '\'';}, $bind));
         }
         //释放前次的查询结果
-        if ( !empty($this->PDOStatement) ) $this->free();
+        if (!empty($this->PDOStatement)) {
+            $this->free();
+        }
+
         $this->queryTimes++;
-        N('db_query',1); // 兼容代码        
+        N('db_query', 1); // 兼容代码
         // 调试开始
         $this->debug(true);
         $this->PDOStatement = $this->_linkID->prepare($str);
-        if(false === $this->PDOStatement)
+        if (false === $this->PDOStatement) {
             E($this->error());
+        }
+
         foreach ($bind as $key => $val) {
-            if(is_array($val)){
+            if (is_array($val)) {
                 $this->PDOStatement->bindValue($key, $val[0], $val[1]);
-            }else{
+            } else {
                 $this->PDOStatement->bindValue($key, $val);
             }
         }
-        $result =   $this->PDOStatement->execute();
+        $result = $this->PDOStatement->execute();
         // 调试结束
         $this->debug(false);
-        if ( false === $result ) {
+        if (false === $result) {
             $this->error();
             return false;
         } else {
@@ -170,39 +190,46 @@ class Lite {
      * @param array $bind  参数绑定
      * @return integer
      */
-    public function execute($str,$bind=array()) {
+    public function execute($str, $bind = array())
+    {
         $this->initConnect(true);
-        if ( !$this->_linkID ) return false;
+        if (!$this->_linkID) {
+            return false;
+        }
+
         $this->queryStr = $str;
-        if(!empty($bind)){
-            $that   =   $this;
-            $this->queryStr =   strtr($this->queryStr,array_map(function($val) use($that){ return '\''.$that->escapeString($val).'\''; },$bind));
-        }      
+        if (!empty($bind)) {
+            $that           = $this;
+            $this->queryStr = strtr($this->queryStr, array_map(function ($val) use ($that) {return '\'' . $that->escapeString($val) . '\'';}, $bind));
+        }
         //释放前次的查询结果
-        if ( !empty($this->PDOStatement) ) $this->free();
+        if (!empty($this->PDOStatement)) {
+            $this->free();
+        }
+
         $this->executeTimes++;
-        N('db_write',1); // 兼容代码        
+        N('db_write', 1); // 兼容代码
         // 记录开始执行时间
         $this->debug(true);
-        $this->PDOStatement =   $this->_linkID->prepare($str);
-        if(false === $this->PDOStatement) {
+        $this->PDOStatement = $this->_linkID->prepare($str);
+        if (false === $this->PDOStatement) {
             E($this->error());
         }
         foreach ($bind as $key => $val) {
-            if(is_array($val)){
+            if (is_array($val)) {
                 $this->PDOStatement->bindValue($key, $val[0], $val[1]);
-            }else{
+            } else {
                 $this->PDOStatement->bindValue($key, $val);
             }
         }
-        $result =   $this->PDOStatement->execute();
+        $result = $this->PDOStatement->execute();
         $this->debug(false);
-        if ( false === $result) {
+        if (false === $result) {
             $this->error();
             return false;
         } else {
             $this->numRows = $this->PDOStatement->rowCount();
-            if(preg_match("/^\s*(INSERT\s+INTO|REPLACE\s+INTO)\s+/i", $str)) {
+            if (preg_match("/^\s*(INSERT\s+INTO|REPLACE\s+INTO)\s+/i", $str)) {
                 $this->lastInsID = $this->_linkID->lastInsertId();
             }
             return $this->numRows;
@@ -214,15 +241,21 @@ class Lite {
      * @access public
      * @return void
      */
-    public function startTrans() {
+    public function startTrans()
+    {
         $this->initConnect(true);
-        if ( !$this->_linkID ) return false;
+        if (!$this->_linkID) {
+            return false;
+        }
+
         //数据rollback 支持
-        if ($this->transTimes == 0) {
+        if (0 == $this->transTimes) {
+            // 记录当前操作PDO
+            $this->transPdo = $this->_linkID;
             $this->_linkID->beginTransaction();
         }
         $this->transTimes++;
-        return ;
+        return;
     }
 
     /**
@@ -230,14 +263,19 @@ class Lite {
      * @access public
      * @return boolean
      */
-    public function commit() {
-        if ($this->transTimes > 0) {
+    public function commit()
+    {
+        if ($this->transTimes == 1) {
+            // 由嵌套事物的最外层进行提交
             $result = $this->_linkID->commit();
             $this->transTimes = 0;
-            if(!$result){
+            $this->transPdo = null;
+            if (!$result) {
                 $this->error();
                 return false;
             }
+        } else {
+            $this->transTimes--;
         }
         return true;
     }
@@ -247,11 +285,13 @@ class Lite {
      * @access public
      * @return boolean
      */
-    public function rollback() {
+    public function rollback()
+    {
         if ($this->transTimes > 0) {
             $result = $this->_linkID->rollback();
             $this->transTimes = 0;
-            if(!$result){
+            $this->transPdo = null;
+            if (!$result) {
                 $this->error();
                 return false;
             }
@@ -264,10 +304,11 @@ class Lite {
      * @access private
      * @return array
      */
-    private function getResult() {
+    private function getResult()
+    {
         //返回数据集
-        $result =   $this->PDOStatement->fetchAll(PDO::FETCH_ASSOC);
-        $this->numRows = count( $result );
+        $result        = $this->PDOStatement->fetchAll(PDO::FETCH_ASSOC);
+        $this->numRows = count($result);
         return $result;
     }
 
@@ -277,8 +318,9 @@ class Lite {
      * @param boolean $execute 是否包含所有查询
      * @return integer
      */
-    public function getQueryTimes($execute=false){
-        return $execute?$this->queryTimes+$this->executeTimes:$this->queryTimes;
+    public function getQueryTimes($execute = false)
+    {
+        return $execute ? $this->queryTimes + $this->executeTimes : $this->queryTimes;
     }
 
     /**
@@ -286,7 +328,8 @@ class Lite {
      * @access public
      * @return integer
      */
-    public function getExecuteTimes(){
+    public function getExecuteTimes()
+    {
         return $this->executeTimes;
     }
 
@@ -294,7 +337,8 @@ class Lite {
      * 关闭数据库
      * @access public
      */
-    public function close() {
+    public function close()
+    {
         $this->_linkID = null;
     }
 
@@ -304,33 +348,36 @@ class Lite {
      * @access public
      * @return string
      */
-    public function error() {
-        if($this->PDOStatement) {
-            $error = $this->PDOStatement->errorInfo();
-            $this->error = $error[1].':'.$error[2];
-        }else{
+    public function error()
+    {
+        if ($this->PDOStatement) {
+            $error       = $this->PDOStatement->errorInfo();
+            $this->error = $error[1] . ':' . $error[2];
+        } else {
             $this->error = '';
         }
-        if('' != $this->queryStr){
-            $this->error .= "\n [ SQL语句 ] : ".$this->queryStr;
+        if ('' != $this->queryStr) {
+            $this->error .= "\n [ SQL语句 ] : " . $this->queryStr;
         }
         // 记录错误日志
-        trace($this->error,'','ERR');
-        if($this->config['debug']) {// 开启数据库调试模式
+        trace($this->error, '', 'ERR');
+        if ($this->config['debug']) {
+            // 开启数据库调试模式
             E($this->error);
-        }else{
+        } else {
             return $this->error;
         }
     }
 
     /**
-     * 获取最近一次查询的sql语句 
+     * 获取最近一次查询的sql语句
      * @param string $model  模型名
      * @access public
      * @return string
      */
-    public function getLastSql($model='') {
-        return $model?$this->modelSql[$model]:$this->queryStr;
+    public function getLastSql($model = '')
+    {
+        return $model ? $this->modelSql[$model] : $this->queryStr;
     }
 
     /**
@@ -338,7 +385,8 @@ class Lite {
      * @access public
      * @return string
      */
-    public function getLastInsID() {
+    public function getLastInsID()
+    {
         return $this->lastInsID;
     }
 
@@ -347,7 +395,8 @@ class Lite {
      * @access public
      * @return string
      */
-    public function getError() {
+    public function getError()
+    {
         return $this->error;
     }
 
@@ -357,7 +406,8 @@ class Lite {
      * @param string $str  SQL字符串
      * @return string
      */
-    public function escapeString($str) {
+    public function escapeString($str)
+    {
         return addslashes($str);
     }
 
@@ -367,8 +417,9 @@ class Lite {
      * @param string $model  模型名
      * @return void
      */
-    public function setModel($model){
-        $this->model =  $model;
+    public function setModel($model)
+    {
+        $this->model = $model;
     }
 
     /**
@@ -376,16 +427,18 @@ class Lite {
      * @access protected
      * @param boolean $start  调试开始标记 true 开始 false 结束
      */
-    protected function debug($start) {
-        if($this->config['debug']) {// 开启数据库调试模式
-            if($start) {
+    protected function debug($start)
+    {
+        if ($this->config['debug']) {
+            // 开启数据库调试模式
+            if ($start) {
                 G('queryStartTime');
-            }else{
-                $this->modelSql[$this->model]   =  $this->queryStr;
+            } else {
+                $this->modelSql[$this->model] = $this->queryStr;
                 //$this->model  =   '_think_';
                 // 记录操作结束时间
                 G('queryEndTime');
-                trace($this->queryStr.' [ RunTime:'.G('queryStartTime','queryEndTime').'s ]','','SQL');
+                trace($this->queryStr . ' [ RunTime:' . G('queryStartTime', 'queryEndTime') . 's ]', '', 'SQL');
             }
         }
     }
@@ -396,13 +449,23 @@ class Lite {
      * @param boolean $master 主服务器
      * @return void
      */
-    protected function initConnect($master=true) {
-        if(!empty($this->config['deploy']))
-            // 采用分布式数据库
+    protected function initConnect($master = true)
+    {
+        // 开启事物时用同一个连接进行操作
+        if ($this->transPDO) {
+            return $this->transPDO;
+        }
+
+        if (!empty($this->config['deploy']))
+        // 采用分布式数据库
+        {
             $this->_linkID = $this->multiConnect($master);
-        else
-            // 默认单数据库
-            if ( !$this->_linkID ) $this->_linkID = $this->connect();
+        } else
+        // 默认单数据库
+        if (!$this->_linkID) {
+            $this->_linkID = $this->connect();
+        }
+
     }
 
     /**
@@ -411,56 +474,60 @@ class Lite {
      * @param boolean $master 主服务器
      * @return void
      */
-    protected function multiConnect($master=false) {
+    protected function multiConnect($master = false)
+    {
         // 分布式数据库配置解析
-        $_config['username']    =   explode(',',$this->config['username']);
-        $_config['password']    =   explode(',',$this->config['password']);
-        $_config['hostname']    =   explode(',',$this->config['hostname']);
-        $_config['hostport']    =   explode(',',$this->config['hostport']);
-        $_config['database']    =   explode(',',$this->config['database']);
-        $_config['dsn']         =   explode(',',$this->config['dsn']);
-        $_config['charset']     =   explode(',',$this->config['charset']);
+        $_config['username'] = explode(',', $this->config['username']);
+        $_config['password'] = explode(',', $this->config['password']);
+        $_config['hostname'] = explode(',', $this->config['hostname']);
+        $_config['hostport'] = explode(',', $this->config['hostport']);
+        $_config['database'] = explode(',', $this->config['database']);
+        $_config['dsn']      = explode(',', $this->config['dsn']);
+        $_config['charset']  = explode(',', $this->config['charset']);
 
         // 数据库读写是否分离
-        if($this->config['rw_separate']){
+        if ($this->config['rw_separate']) {
             // 主从式采用读写分离
-            if($master)
-                // 主服务器写入
-                $r  =   floor(mt_rand(0,$this->config['master_num']-1));
-            else{
-                if(is_numeric($this->config['slave_no'])) {// 指定服务器读
+            if ($master)
+            // 主服务器写入
+            {
+                $r = floor(mt_rand(0, $this->config['master_num'] - 1));
+            } else {
+                if (is_numeric($this->config['slave_no'])) {
+// 指定服务器读
                     $r = $this->config['slave_no'];
-                }else{
+                } else {
                     // 读操作连接从服务器
-                    $r = floor(mt_rand($this->config['master_num'],count($_config['hostname'])-1));   // 每次随机连接的数据库
+                    $r = floor(mt_rand($this->config['master_num'], count($_config['hostname']) - 1)); // 每次随机连接的数据库
                 }
             }
-        }else{
+        } else {
             // 读写操作不区分服务器
-            $r = floor(mt_rand(0,count($_config['hostname'])-1));   // 每次随机连接的数据库
+            $r = floor(mt_rand(0, count($_config['hostname']) - 1)); // 每次随机连接的数据库
         }
         $db_config = array(
-            'username'  =>  isset($_config['username'][$r])?$_config['username'][$r]:$_config['username'][0],
-            'password'  =>  isset($_config['password'][$r])?$_config['password'][$r]:$_config['password'][0],
-            'hostname'  =>  isset($_config['hostname'][$r])?$_config['hostname'][$r]:$_config['hostname'][0],
-            'hostport'  =>  isset($_config['hostport'][$r])?$_config['hostport'][$r]:$_config['hostport'][0],
-            'database'  =>  isset($_config['database'][$r])?$_config['database'][$r]:$_config['database'][0],
-            'dsn'       =>  isset($_config['dsn'][$r])?$_config['dsn'][$r]:$_config['dsn'][0],
-            'charset'   =>  isset($_config['charset'][$r])?$_config['charset'][$r]:$_config['charset'][0],
+            'username' => isset($_config['username'][$r]) ? $_config['username'][$r] : $_config['username'][0],
+            'password' => isset($_config['password'][$r]) ? $_config['password'][$r] : $_config['password'][0],
+            'hostname' => isset($_config['hostname'][$r]) ? $_config['hostname'][$r] : $_config['hostname'][0],
+            'hostport' => isset($_config['hostport'][$r]) ? $_config['hostport'][$r] : $_config['hostport'][0],
+            'database' => isset($_config['database'][$r]) ? $_config['database'][$r] : $_config['database'][0],
+            'dsn'      => isset($_config['dsn'][$r]) ? $_config['dsn'][$r] : $_config['dsn'][0],
+            'charset'  => isset($_config['charset'][$r]) ? $_config['charset'][$r] : $_config['charset'][0],
         );
-        return $this->connect($db_config,$r);
+        return $this->connect($db_config, $r);
     }
 
-   /**
+    /**
      * 析构方法
      * @access public
      */
-    public function __destruct() {
+    public function __destruct()
+    {
         // 释放查询
-        if ($this->PDOStatement){
+        if ($this->PDOStatement) {
             $this->free();
         }
         // 关闭连接
         $this->close();
     }
-}
+}

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 345 - 292
server/ThinkPHP/Library/Think/Model.class.php


Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels