【discuzX2】/source/class/class_core.php文件中数据库操作类DB及db_mysql分析

  1. <?php  
  2. /** 
  3.  * Discuz MySQL 类的支持 程序中一般不直接使用此类,而是使用DB类,DB类对db_mysql类中的方法又进行了二次封装 
  4.  * 
  5.  */  
  6. class db_mysql  
  7. {  
  8.     var $tablepre;  
  9.     var $version = '';  
  10.     var $querynum = 0;  
  11.     var $slaveid = 0;  
  12.     var $curlink;  
  13.     var $link = array();  
  14.     var $config = array();  
  15.     var $sqldebug = array();  
  16.     var $map = array();  
  17.   
  18.     function db_mysql($config = array()) {  
  19.         if(!empty($config)) {  
  20.             $this->set_config($config);  
  21.         }  
  22.     }  
  23.   
  24.     function set_config($config) {  
  25.         $this->config = &$config;  
  26.         $this->tablepre = $config['1']['tablepre'];  
  27.         if(!empty($this->config['map'])) {  
  28.             $this->map = $this->config['map'];  
  29.         }  
  30.     }  
  31.   
  32.     function connect($serverid = 1) {  
  33.   
  34.         if(empty($this->config) || empty($this->config[$serverid])) {  
  35.             $this->halt('config_db_not_found');  
  36.         }  
  37.   
  38.         $this->link[$serverid] = $this->_dbconnect(  
  39.             $this->config[$serverid]['dbhost'],  
  40.             $this->config[$serverid]['dbuser'],  
  41.             $this->config[$serverid]['dbpw'],  
  42.             $this->config[$serverid]['dbcharset'],  
  43.             $this->config[$serverid]['dbname'],  
  44.             $this->config[$serverid]['pconnect']  
  45.             );  
  46.         $this->curlink = $this->link[$serverid];  
  47.   
  48.     }  
  49.   
  50.     function _dbconnect($dbhost, $dbuser, $dbpw, $dbcharset, $dbname, $pconnect) {  
  51.         $link = null;  
  52.         $func = empty($pconnect) ? 'mysql_connect' : 'mysql_pconnect';  
  53.         if(!$link = @$func($dbhost, $dbuser, $dbpw, 1)) {  
  54.             $this->halt('notconnect');  
  55.         } else {  
  56.             $this->curlink = $link;  
  57.             if($this->version() > '4.1') {  
  58.                 $dbcharset = $dbcharset ? $dbcharset : $this->config[1]['dbcharset'];  
  59.                 $serverset = $dbcharset ? 'character_set_connection='.$dbcharset.', character_set_results='.$dbcharset.', character_set_client=binary' : '';  
  60.                 $serverset .= $this->version() > '5.0.1' ? ((empty($serverset) ? '' : ',').'sql_mode=\'\'') : '';  
  61.                 $serverset && mysql_query("SET $serverset", $link);  
  62.             }  
  63.             $dbname && @mysql_select_db($dbname, $link);  
  64.         }  
  65.         return $link;  
  66.     }  
  67.   
  68.     function table_name($tablename) {  
  69.         if(!empty($this->map) && !empty($this->map[$tablename])) {  
  70.             $id = $this->map[$tablename];  
  71.             if(!$this->link[$id]) {  
  72.                 $this->connect($id);  
  73.             }  
  74.             $this->curlink = $this->link[$id];  
  75.             return $this->config[$id]['tablepre'].$tablename;  
  76.         } else {  
  77.             $this->curlink = $this->link[1];  
  78.         }  
  79.         return $this->tablepre.$tablename;  
  80.     }  
  81.   
  82.     function select_db($dbname) {  
  83.         return mysql_select_db($dbname, $this->curlink);  
  84.     }  
  85.   
  86.     function fetch_array($query, $result_type = MYSQL_ASSOC) {  
  87.         return mysql_fetch_array($query, $result_type);  
  88.     }  
  89.   
  90.     function fetch_first($sql) {  
  91.         return $this->fetch_array($this->query($sql));  
  92.     }  
  93.   
  94.     function result_first($sql) {  
  95.         return $this->result($this->query($sql), 0);  
  96.     }  
  97.   
  98.     function query($sql, $type = '') {  
  99.   
  100.         if(defined('DISCUZ_DEBUG') && DISCUZ_DEBUG) {  
  101.             $starttime = dmicrotime();  
  102.         }  
  103.         $func = $type == 'UNBUFFERED' && @function_exists('mysql_unbuffered_query') ?  
  104.         'mysql_unbuffered_query' : 'mysql_query';  
  105.         if(!($query = $func($sql, $this->curlink))) {  
  106.             if(in_array($this->errno(), array(2006, 2013)) && substr($type, 0, 5) != 'RETRY') {  
  107.                 $this->connect();  
  108.                 return $this->query($sql, 'RETRY'.$type);  
  109.             }  
  110.             if($type != 'SILENT' && substr($type, 5) != 'SILENT') {  
  111.                 $this->halt('query_error', $sql);  
  112.             }  
  113.         }  
  114.   
  115.         if(defined('DISCUZ_DEBUG') && DISCUZ_DEBUG) {  
  116.             $this->sqldebug[] = array($sql, number_format((dmicrotime() - $starttime), 6), debug_backtrace());  
  117.         }  
  118.   
  119.         $this->querynum++;  
  120.         return $query;  
  121.     }  
  122.   
  123.     function affected_rows() {  
  124.         return mysql_affected_rows($this->curlink);  
  125.     }  
  126.   
  127.     function error() {  
  128.         return (($this->curlink) ? mysql_error($this->curlink) : mysql_error());  
  129.     }  
  130.   
  131.     function errno() {  
  132.         return intval(($this->curlink) ? mysql_errno($this->curlink) : mysql_errno());  
  133.     }  
  134.   
  135.     function result($query, $row = 0) {  
  136.         $query = @mysql_result($query, $row);  
  137.         return $query;  
  138.     }  
  139.   
  140.     function num_rows($query) {  
  141.         $query = mysql_num_rows($query);  
  142.         return $query;  
  143.     }  
  144.   
  145.     function num_fields($query) {  
  146.         return mysql_num_fields($query);  
  147.     }  
  148.   
  149.     function free_result($query) {  
  150.         return mysql_free_result($query);  
  151.     }  
  152.   
  153.     function insert_id() {  
  154.         return ($id = mysql_insert_id($this->curlink)) >= 0 ? $id : $this->result($this->query("SELECT last_insert_id()"), 0);  
  155.     }  
  156.   
  157.     function fetch_row($query) {  
  158.         $query = mysql_fetch_row($query);  
  159.         return $query;  
  160.     }  
  161.   
  162.     function fetch_fields($query) {  
  163.         return mysql_fetch_field($query);  
  164.     }  
  165.   
  166.     function version() {  
  167.         if(empty($this->version)) {  
  168.             $this->version = mysql_get_server_info($this->curlink);  
  169.         }  
  170.         return $this->version;  
  171.     }  
  172.   
  173.     function close() {  
  174.         return mysql_close($this->curlink);  
  175.     }  
  176.   
  177.     function halt($message = '', $sql = '') {  
  178.         require_once libfile('class/error');  
  179.         discuz_error::db_error($message, $sql);  
  180.     }  
  181.   
  182. }  
  183.   
  184. /** 
  185.  * 对Discuz CORE 中 DB Object中的主要方法进行二次封装,方便程序调用 
  186.  * 
  187.  */  
  188. class DB  
  189. {  
  190.   
  191.         /** 
  192.      * 返回表名(pre_$table) 
  193.      * 
  194.      * @param 原始表名 $table 
  195.      * @return 增加pre之后的名字 
  196.      */  
  197.     function table($table) {  
  198.         return DB::_execute('table_name', $table);  
  199.     }  
  200.   
  201.         /** 
  202.      * 删除一条或者多条记录 
  203.      * 
  204.      * @param string $table 原始表名 
  205.      * @param string $condition 条件语句,不需要写WHERE 
  206.      * @param int $limit 删除条目数 
  207.      * @param boolean $unbuffered 立即返回? 
  208.      */  
  209.     function delete($table, $condition, $limit = 0, $unbuffered = true) {  
  210.         if(empty($condition)) {  
  211.             $where = '1';  
  212.         } elseif(is_array($condition)) {  
  213.             $where = DB::implode_field_value($condition, ' AND ');  
  214.         } else {  
  215.             $where = $condition;  
  216.         }  
  217.         $sql = "DELETE FROM ".DB::table($table)." WHERE $where ".($limit ? "LIMIT $limit" : '');  
  218.         return DB::query($sql, ($unbuffered ? 'UNBUFFERED' : ''));  
  219.     }  
  220.   
  221.         /** 
  222.      * 插入一条记录 
  223.      * 
  224.      * @param string $table 原始表名 
  225.      * @param array $data 数组field->vlaue 对 
  226.      * @param boolen $return_insert_id 返回 InsertID? 
  227.      * @param boolen $replace 是否是REPLACE模式 
  228.      * @param boolen $silent 屏蔽错误? 
  229.      * @return InsertID or Result 
  230.      */  
  231.     function insert($table, $data, $return_insert_id = false, $replace = false, $silent = false) {  
  232.   
  233.         $sql = DB::implode_field_value($data);  
  234.   
  235.         $cmd = $replace ? 'REPLACE INTO' : 'INSERT INTO';  
  236.   
  237.         $table = DB::table($table);  
  238.         $silent = $silent ? 'SILENT' : '';  
  239.   
  240.         $return = DB::query("$cmd $table SET $sql", $silent);  
  241.   
  242.         return $return_insert_id ? DB::insert_id() : $return;  
  243.   
  244.     }  
  245.   
  246.         /** 
  247.      * 更新一条或者多条数据记录 
  248.      * 
  249.      * @param string $table 原始表名 
  250.      * @param array $data 数据field-value 
  251.      * @param string $condition 条件语句,不需要写WHERE 
  252.      * @param boolean $unbuffered 迅速返回? 
  253.      * @param boolan $low_priority 延迟更新? 
  254.      * @return result 
  255.      */  
  256.     function update($table, $data, $condition, $unbuffered = false, $low_priority = false) {  
  257.         $sql = DB::implode_field_value($data);  
  258.         $cmd = "UPDATE ".($low_priority ? 'LOW_PRIORITY' : '');  
  259.         $table = DB::table($table);  
  260.         $where = '';  
  261.         if(empty($condition)) {  
  262.             $where = '1';  
  263.         } elseif(is_array($condition)) {  
  264.             $where = DB::implode_field_value($condition, ' AND ');  
  265.         } else {  
  266.             $where = $condition;  
  267.         }  
  268.         $res = DB::query("$cmd $table SET $sql WHERE $where", $unbuffered ? 'UNBUFFERED' : '');  
  269.         return $res;  
  270.     }  
  271.   
  272.         /** 
  273.      * 格式化field字段和value,并组成一个字符串 
  274.      * 
  275.      * @param array $array 格式为 key=>value 数组 
  276.      * @param 分割符 $glue 
  277.      * @return string 
  278.      */  
  279.     function implode_field_value($array, $glue = ',') {  
  280.         $sql = $comma = '';  
  281.         foreach ($array as $k => $v) {  
  282.             $sql .= $comma."`$k`='$v'";  
  283.             $comma = $glue;  
  284.         }  
  285.         return $sql;  
  286.     }  
  287.   
  288.         /** 
  289.      * 返回插入的ID 
  290.      * 
  291.      * @return int 
  292.      */  
  293.     function insert_id() {  
  294.         return DB::_execute('insert_id');  
  295.     }  
  296.   
  297.         /** 
  298.      * 依据查询结果,返回一行数据 
  299.      * 
  300.      * @param resourceID $resourceid 
  301.      * @return array 
  302.      */  
  303.     function fetch($resourceid, $type = MYSQL_ASSOC) {  
  304.         return DB::_execute('fetch_array', $resourceid, $type);  
  305.     }  
  306.   
  307.         /** 
  308.      * 依据SQL语句,返回第一条查询结果 
  309.      * 
  310.      * @param string $query 查询语句 
  311.      * @return array 
  312.      */  
  313.     function fetch_first($sql) {  
  314.         DB::checkquery($sql);  
  315.         return DB::_execute('fetch_first', $sql);  
  316.     }  
  317.   
  318.         /** 
  319.      * 依据查询结果,返回结果数值 
  320.      * 
  321.      * @param resourceid $resourceid 
  322.      * @return string or int 
  323.      */  
  324.     function result($resourceid, $row = 0) {  
  325.         return DB::_execute('result', $resourceid, $row);  
  326.     }  
  327.   
  328.         /** 
  329.      * 依据查询语句,返回结果数值 
  330.      * 
  331.      * @param string $query SQL查询语句 
  332.      * @return unknown 
  333.      */  
  334.     function result_first($sql) {  
  335.         DB::checkquery($sql);  
  336.         return DB::_execute('result_first', $sql);  
  337.     }  
  338.   
  339.         /** 
  340.      * 执行查询 
  341.      * 
  342.      * @param string $sql 
  343.      * @param 类型定义 $type UNBUFFERED OR SILENT 
  344.      * @return Resource OR Result 
  345.      */  
  346.     function query($sql, $type = '') {  
  347.         DB::checkquery($sql);  
  348.         return DB::_execute('query', $sql, $type);  
  349.     }  
  350.   
  351.         /** 
  352.      * 返回select的结果行数 
  353.      * 
  354.      * @param resource $resourceid 
  355.      * @return int 
  356.      */  
  357.     function num_rows($resourceid) {  
  358.         return DB::_execute('num_rows', $resourceid);  
  359.     }  
  360.   
  361.         /** 
  362.      * 返回sql语句所影响的记录行数 
  363.      * 
  364.      * @return int 
  365.      */  
  366.     function affected_rows() {  
  367.         return DB::_execute('affected_rows');  
  368.     }  
  369.   
  370.     function free_result($query) {  
  371.         return DB::_execute('free_result', $query);  
  372.     }  
  373.   
  374.     function error() {  
  375.         return DB::_execute('error');  
  376.     }  
  377.   
  378.     function errno() {  
  379.         return DB::_execute('errno');  
  380.     }  
  381.   
  382.     function _execute($cmd , $arg1 = '', $arg2 = '') {//DB类中的很多方法都调用了此方法,此方法又调用了 &object()方法,详情请查看&object()方法,其实&object()方法返回一个db_mysql类的实例化对象,而且是statics类型的实例化对象  
  383.         static $db;  
  384.         if(empty($db)) $db = & DB::object();//返回db_mysql操作类的实例化对象  
  385.         $res = $db->$cmd($arg1, $arg2);  
  386.         return $res;  
  387.     }  
  388.   
  389.         /** 
  390.      * 返回 DB object 指针 
  391.      * 
  392.      * @return pointer of db object from discuz core 
  393.      */  
  394.     function &object($dbclass = 'db_mysql') {  
  395.         static $db;  
  396.         if(empty($db)) $db = new $dbclass();//返回db_mysql数据库操作类的一个statics类型的实例化对象  
  397.         return $db;  
  398.     }  
  399.   
  400.     function checkquery($sql) {  
  401.         static $status = null, $checkcmd = array('SELECT', 'UPDATE', 'INSERT', 'REPLACE', 'DELETE');  
  402.         if($status === null) $status = getglobal('config/security/querysafe/status');  
  403.         if($status) {  
  404.             $cmd = trim(strtoupper(substr($sql, 0, strpos($sql, ' '))));  
  405.             if(in_array($cmd, $checkcmd)) {  
  406.                 $test = DB::_do_query_safe($sql);  
  407.                 if($test < 1) DB::_execute('halt', 'security_error', $sql);  
  408.             }  
  409.         }  
  410.         return true;  
  411.     }  
  412.   
  413.     function _do_query_safe($sql) {  
  414.         static $_CONFIG = null;  
  415.         if($_CONFIG === null) {  
  416.             $_CONFIG = getglobal('config/security/querysafe');  
  417.         }  
  418.   
  419.         $sql = str_replace(array('\\\\', '\\\'', '\\"', '\'\''), '', $sql);  
  420.         $mark = $clean = '';  
  421.         if(strpos($sql, '/') === false && strpos($sql, '#') === false && strpos($sql, '-- ') === false) {  
  422.             $clean = preg_replace("/'(.+?)'/s", '', $sql);  
  423.         } else {  
  424.             $len = strlen($sql);  
  425.             $mark = $clean = '';  
  426.             for ($i = 0; $i <$len; $i++) {  
  427.                 $str = $sql[$i];  
  428.                 switch ($str) {  
  429.                     case '\'':  
  430.                         if(!$mark) {  
  431.                             $mark = '\'';  
  432.                             $clean .= $str;  
  433.                         } elseif ($mark == '\'') {  
  434.                             $mark = '';  
  435.                         }  
  436.                         break;  
  437.                     case '/':  
  438.                         if(empty($mark) && $sql[$i+1] == '*') {  
  439.                             $mark = '/*';  
  440.                             $clean .= $mark;  
  441.                             $i++;  
  442.                         } elseif($mark == '/*' && $sql[$i -1] == '*') {  
  443.                             $mark = '';  
  444.                             $clean .= '*';  
  445.                         }  
  446.                         break;  
  447.                     case '#':  
  448.                         if(empty($mark)) {  
  449.                             $mark = $str;  
  450.                             $clean .= $str;  
  451.                         }  
  452.                         break;  
  453.                     case "\n":  
  454.                         if($mark == '#' || $mark == '--') {  
  455.                             $mark = '';  
  456.                         }  
  457.                         break;  
  458.                     case '-':  
  459.                         if(empty($mark)&& substr($sql, $i, 3) == '-- ') {  
  460.                             $mark = '-- ';  
  461.                             $clean .= $mark;  
  462.                         }  
  463.                         break;  
  464.   
  465.                     default:  
  466.   
  467.                         break;  
  468.                 }  
  469.                 $clean .= $mark ? '' : $str;  
  470.             }  
  471.         }  
  472.   
  473.         $clean = preg_replace("/[^a-z0-9_\-#\*\/\"]+/is", "", strtolower($clean));  
  474.   
  475.         if($_CONFIG['afullnote']) {  
  476.             $clean = str_replace('/**/','',$clean);  
  477.         }  
  478.   
  479.         if(is_array($_CONFIG['dfunction'])) {  
  480.             foreach($_CONFIG['dfunction'] as $fun) {  
  481.                 if(strpos($clean, $fun.'(') !== false) return '-1';  
  482.             }  
  483.         }  
  484.   
  485.         if(is_array($_CONFIG['daction'])) {  
  486.             foreach($_CONFIG['daction'] as $action) {  
  487.                 if(strpos($clean,$action) !== false) return '-3';  
  488.             }  
  489.         }  
  490.   
  491.         if($_CONFIG['dlikehex'] && strpos($clean, 'like0x')) {  
  492.             return '-2';  
  493.         }  
  494.   
  495.         if(is_array($_CONFIG['dnote'])) {  
  496.             foreach($_CONFIG['dnote'] as $note) {  
  497.                 if(strpos($clean,$note) !== false) return '-4';  
  498.             }  
  499.         }  
  500.   
  501.         return 1;  
  502.   
  503.     }  
  504.   
  505. }  
  506. ?>  

posted on 2017-09-09 16:04  alleyonine  阅读(322)  评论(0编辑  收藏  举报

导航