任何一個正式運作的網站,都不會在網站運作中,試著更改某些程式碼來測試某些新的功能,或是試圖解決某些問題、安全性漏洞等。都會在另外的「地下網站」或是「鏡像網站」來進行各種測試、開發。我們的insoler當然也不例外。
我在試著解決這兩個問題的時候:
修正升級到MySQL Community Server 5.7.17造成「照片檔名」排序錯誤的問題
修正DolphinPro 7.3.3某些PHP程式以「;;」雙分號結尾的錯誤
發現只有我一個人可以連上的「地下社群網站」,從MySQLWorkbench或是phpMyAdmin可以看到竟然有好幾個相同的帳號連接MySQL!我搜尋整個Dolphin程式裡面的「mysql_connect」與「mysql_pconnect」發現確實是有好幾個連接資料庫指令。理論上,每次開啟網頁,應該只需要一個「mysql_connect」來連接MySQL資料庫才對。如果有不同的需求,也應該不能太多次,甚至是不斷連接MySQL才對。
首先我發現就算是只有我一個人可以連上的「地下社群網站」,只要打開forum討論區首頁,或是打開photos相片首頁,就很容易導致MySQL當機!雖然MySQL會自動重新啟動,但是到可以穩定運作之前,MySQL可能需要20-30秒的時間來重新啟動。
用BBEdit搜尋整個Dolphin-v.7.3.3,發現有3個mysql_connect連接指令,其中兩個是mysql_connect,一個是mysql_pconnect。
Dolphin-v.7.3.3/flash/modules/global/inc/db.inc.php:44:
@$this->rLink = mysql_connect($dbHost, $this->sUser, $this->sPassword);
Dolphin-v.7.3.3/modules/boonex/forum/classes/BxDb.php:40:
$this->link = @mysql_connect($full_host, $this->user, $this->password) or $this->error('Cannot connect to database');
Dolphin-v.7.3.3/inc/classes/BxDolDb.php:66:
$this->link = @mysql_pconnect($full_host, $this->user, $this->password);
因為總共有3個mysql_connect連接指令,而且3個指令對於「無法連接MySQL」的處理方式也不同,難怪當「無法連接MySQL」的時候,在不同的網頁上會看到不同的「無法連接MySQL」的錯誤訊息!
首先處理forum討論區的「modules/boonex/forum/classes/BxDb.php」連接資料庫的部分。如果沒有特別的需求,forum討論區應該不需要自己另外連接MySQL資料庫才對!只要使用整個系統已經連上的MySQL即可。討論區自己另外連接MySQL可說是只會浪費「MySQL連接數」以及增加MySQL Server運作上的負擔。表面上這裡只有增加一次的「連接MySQL資料庫」而已,但如果網站上有幾萬、幾百萬個會員的時候呢?這個連接數量就會很可觀了。
原版classes/BxDb.ph程式碼的內容是這樣:
/**
* connect to database with appointed parameters
*/
function connect()
{
$full_host = $this->host;
$full_host .= $this->port ? ':'.$this->port : '';
$full_host .= $this->socket ? ':'.$this->socket : '';
$this->link = @mysql_connect($full_host, $this->user, $this->password) or $this->error('Cannot connect to database');
if (!$this->link) {
echo 'Could not connect to MySQL database. < br / >Did you properly edit inc/header.inc.php file ?';
exit;;
}
if (!$this->select_db()) {
echo 'Could not select MySQL database. < br / >Did you properly edit inc/header.inc.php file ?';
exit;
}
mysql_query ("SET NAMES 'utf8'", $this->link);
}
我修改成這樣:
/**
* connect to database with appointed parameters
*/
function connect()
{
$full_host = $this->host;
$full_host .= $this->port ? ':'.$this->port : '';
$full_host .= $this->socket ? ':'.$this->socket : '';
if (empty($GLOBALS['bx_db_link'])) { //BNW
$GLOBALS['MySQL']->connect();
}
$this->link = $GLOBALS['bx_db_link'];
if (!$this->link) {
echo 'Could not connect to MySQL database. < br / >Did you properly edit inc/header.inc.php file ?';
exit;
}
if (!$this->select_db()) {
echo 'Could not select MySQL database. < br / >Did you properly edit inc/header.inc.php file ?';
exit;
}
//mysql_query ("SET NAMES 'utf8'", $this->link);
}
其中「if (empty($GLOBALS['bx_db_link']))」的意思是,如果沒有連接MySQL資料庫,才需要執行「$GLOBALS['MySQL']->connect();」的連接資料庫動作。但就算單獨開啟forum討論區首頁,也不可能在開啟討論區首頁以前沒有連接過MySQL!因此程式執行到這裡的時候,應該都已經連接好MySQL了。這樣就可以減少因為開啟forum討論區網頁,又另外連接MySQL一次的動作!
另外也減少一次mysql_query的查訊設定為utf8的動作。這個utf8設定可以在my.cnf裡面事先設定好。
在「flash/modules/global/inc/db.inc.php」也有這樣的連接MySQL伺服器的程式碼。同樣是不理會之前有沒有連接過MySQL,就直接連接一個新的MySQL:
function connect()
{
if($this->bConnected) return;
$dbHost = strlen($this->iPort) ? $this->sHost . ":" . $this->iPort : $this->sHost;
$dbHost .= strlen($this->iSocket) ? ":" . $this->iSocket : "";
@$this->rLink = mysql_connect($dbHost, $this->sUser, $this->sPassword);
if($this->rLink)$this->bConnected = true;
else $this->bConnected = false;
@mysql_select_db($this->sDb, $this->rLink);
mysql_query("SET NAMES 'utf8'", $this->rLink);
mysql_query("SET sql_mode = ''", $this->rLink);
mysql_query("SET @@local.wait_timeout=9000;", $this->rLink);
mysql_query("SET @@local.interactive_timeout=9000;", $this->rLink);
}
這個部分的程式碼我改成這樣,首先判斷整個網站的全域變數有沒有連接過MySQL?如果沒有連接MySQL的話,才連接MySQL。:
function connect()
{
if($this->bConnected) return;
$dbHost = strlen($this->iPort) ? $this->sHost . ":" . $this->iPort : $this->sHost;
$dbHost .= strlen($this->iSocket) ? ":" . $this->iSocket : "";
if (empty($GLOBALS['bx_db_link'])) { //BNW
$MyCount = 1;
do {
$this->rLink = @mysql_connect($dbHost, $this->sUser, $this->sPassword);
if ($this->rLink != false) break;
$MyCount++;
sleep(1);
} while ($MyCount <= 60);
} else {
$this->rLink = $GLOBALS['bx_db_link'];
}
if($this->rLink)$this->bConnected = true;
else $this->bConnected = false;
@mysql_select_db($this->sDb, $this->rLink);
//mysql_query("SET NAMES 'utf8'", $this->rLink);
//mysql_query("SET sql_mode = ''", $this->rLink);
//mysql_query("SET @@local.wait_timeout=9000;", $this->rLink);
//mysql_query("SET @@local.interactive_timeout=9000;", $this->rLink);
}
如果無法連接MySQL資料庫的話,會暫停1秒再重新嘗試連線,如果連接60秒都無法連接資料庫才會產生錯誤訊息。
所以我也用同樣的方式來修改「inc/classes/BxDolDb.php」。原版的程式碼是這樣:
/**
* connect to database with appointed parameters
*/
function connect()
{
$full_host = $this->host;
$full_host .= $this->port ? ':'.$this->port : '';
$full_host .= $this->socket ? ':'.$this->socket : '';
$this->link = @mysql_pconnect($full_host, $this->user, $this->password);
if (!$this->link)
$this->error('Database connect failed', true);
if (!$this->select_db())
$this->error('Database select failed', true);
mysql_query("SET NAMES 'utf8'", $this->link);
mysql_query("SET sql_mode = ''", $this->link);
$GLOBALS['bx_db_link'] = $this->link;
}
我修改好的連接MySQL資料庫程式碼,改成這樣:
/**
* connect to database with appointed parameters
*/
function connect()
{
$full_host = $this->host;
$full_host .= $this->port ? ':'.$this->port : '';
$full_host .= $this->socket ? ':'.$this->socket : '';
if (empty($GLOBALS['bx_db_link'])) { //BNW
$MyCount = 1;
do {
$this->link = @mysql_connect($full_host, $this->user, $this->password);
if ($this->link != false) break;
$MyCount++;
sleep(1);
} while ($MyCount <= 60);
} else {
$this->link = $GLOBALS['bx_db_link'];
}
if (!$this->link)
$this->error('Database connect failed', true);
if (!$this->select_db())
$this->error('Database select failed', true);
//mysql_query("SET NAMES 'utf8'", $this->link);
//mysql_query("SET sql_mode = ''", $this->link);
$GLOBALS['bx_db_link'] = $this->link;
}
不需要執行的「SET NAMES 'utf8'」與「SET sql_mode = ''」也被我用註解的方式關閉。
盡量減少MySQL資料庫的連接、設定動作以後,觀察一個星期多的時間,看起來MySQL比以前穩定了許多。
當然,在「非同步處理上傳照片」的程式碼裡面,連接資料庫的程式碼也與上面這一段很類似。
$MyCount = 1;
do {
$mysql = @mysql_connect($db['host'], $db['user'], $db['passwd']);
if ($mysql != false) {
@mysql_select_db($db['db'], $mysql);
break;
}
$MyCount++;
sleep(10);
} while ($MyCount <= 30);
if ($MyCount >= 30) exit;
「非同步處理上傳照片」因為是在Web Server的背景執行,不會影響普通的user,所以當無法連接MySQL資料庫的時候,會先執行「sleep(10);」睡眠10秒,然後再重新嘗試連接MySQL資料庫。要是不斷錯誤達到30次,才會正式放棄,結束程式。