首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

UCHome 數據庫操作類 class_mysql.php 深度代碼審計:連接管理、查詢執行、調試與錯誤處理機制

     編輯:MySQL 資料庫相關知識

類概覽

dbstuff 是 UCHome (Comsenz) 早期版本使用的 MySQL 封裝類,基於 mysql_* 扩展,提供連接管理、查詢執行、結果集獲取、調試統計、錯誤處理等核心功能。代碼風格典型的「單文件萬能類」,適合快速開發,但存在明顯技術債務。

核心方法剖析

1. connect():連接建立與字符集初始化

function connect($dbhost, $dbuser, $dbpw, $dbname='', $pconnect=0, $halt=TRUE) {
    if ($pconnect) {
        $this->link = @mysql_pconnect($dbhost, $dbuser, $dbpw);  // 持久連接
    } else {
        $this->link = @mysql_connect($dbhost, $dbuser, $dbpw, 1); // 第4參數 new_link=true,強制新連接
    }
    if (!$this->link) $halt && $this->halt('Can not connect to MySQL Server');

    // MySQL 4.1+ 字符集設置
    if ($this->version() > '4.1') {
        if ($this->charset) {
            @mysql_query("SET character_set_connection=$this->charset, character_set_results=$this->charset, character_set_client=binary", $this->link);
        }
        if ($this->version() > '5.0.1') {
            @mysql_query("SET sql_mode=''", $this->link);  // 關閉嚴格模式,兼容舊代碼
        }
    }
    if ($dbname) @mysql_select_db($dbname, $this->link);
}

關鍵點:
- mysql_pconnect 進程級連接復用,需配合 Apache Prefork MPM,PHP-FPM 不支援。
- character_set_client=binary 避免客戶端編碼干擾,由服務端按 connection/results 轉碼。
- sql_mode='' 關閉 ONLY_FULL_GROUP_BY 等嚴格檢查,**隱患:數據完整性保護失效**。

2. query():SQL 執行與調試統計

function query($sql, $type='') {
    if (D_BUG) {  // 常量開關
        $sqlstarttime = microtime(true) * 1000;
    }
    $func = ($type == 'UNBUFFERED' && function_exists('mysql_unbuffered_query'))
        ? 'mysql_unbuffered_query' : 'mysql_query';
    if (!($query = $func($sql, $this->link)) && $type != 'SILENT') {
        $this->halt('MySQL Query Error', $sql);
    }
    if (D_BUG) {
        $sqlendtime = microtime(true) * 1000;
        $sqltime = round($sqlendtime - $sqlstarttime, 3);
        $explain = [];
        if ($query && preg_match('/^(select )/i', $sql)) {
            $explain = mysql_fetch_assoc(mysql_query('EXPLAIN '.$sql, $this->link));
        }
        $_SGLOBAL['debug_query'][] = [
            'sql' => $sql, 'time' => $sqltime,
            'info' => mysql_info(), 'explain' => $explain
        ];
    }
    $this->querynum++;
    return $query;
}

亮點:
- UNBUFFERED 模式適用於大結果集流式讀取,避免記憶體暴漲。
- 自動 EXPLAIN SELECT 語句,開發期即時發現全表掃描。
- 統計 querynum、耗時、mysql_info(),構建簡易 APM。

3. 錯誤處理 halt():用戶友好報錯 + 幫助鏈接

function halt($message='', $sql='') {
    $dberror = $this->error();
    $dberrno = $this->errno();
    $help_link = "https://faq.comsenz.com/?type=mysql&dberrno=".rawurlencode($dberrno)."&dberror=".rawurlencode($dberror);
    echo "
MySQL Error
Message: $message
SQL: $sql
Error: $dberror
Errno.: $dberrno
Click here to seek help.
"; exit(); }

4. 其它輔助方法

  • fetch_array($query, MYSQL_ASSOC):預設關聯數組。
  • affected_rows()、insert_id():寫入確認必備。
  • free_result():釋放記憶體,防洩漏。
  • version():獲取服務端版本,驅動兼容判斷依據。

代碼審計發現的主要問題

問題風險等級建議修復
使用已棄用 mysql_* 扩展🔴 高全量遷移至 PDO / MySQLi,啟用預處理防注入
@ 抑制錯誤,配合 halt() 強制退出🟠 中改用異常處理,區分可恢復/不可恢復錯誤
SET sql_mode='' 關閉嚴格模式🔴 高修正不兼容 SQL,保持嚴格模式開啟
mysql_pconnect 在 PHP-FPM 下無效甚至洩漏連接🟠 中移除持久連接選項,使用連接池中間件
EXPLAIN 自動執行可能加重主庫負載🟡 低僅開發環境開啟,生產關閉 D_BUG
無預處理介面,SQL 拼接風險極大🔴 高新增 prepare()/execute() 方法
單例/全局變量 $_SGLOBAL 耦合調試數據🟡 低注入 Logger 介面,解耦

現代化重構方向

  1. 實現 PDOInterface 兼容層,逐步替換調用點。
  2. 引入 Read/Write Connection Pool(如 ProxySQL、PHP 連接池)。
  3. 查詢構建器分離:QueryBuilder 產出 SQL + 參數,Executor 執行。
  4. 錯誤處理標準化:自定義異常體系 DBConnectionException、DBQueryException、DBConstraintException。
  5. 觀測性接入:OpenTelemetry 追蹤 SQL 耗時、執行計劃、錯誤率。

總結

dbstuff 是 Discuz!/UCHome 早期生態的縮影:**功能完備、調試貼心、但緊耦合 mysql_* 扩展、缺乏預處理、錯誤處理粗暴**。對於存量項目,建議**凍結功能、僅做安全修補**,新業務模塊**強制使用 PDO/MySQLi + 預處理 + 連接池**,逐步完成技術棧現代化。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved