章 51. 資料庫問題

本節內含 PHP 和資料庫之間關係的常見問題。是的,PHP 事實上可以訪問如今現有的任何資料庫。

1. 聽說 PHP 有可能訪問 Microsoft SQL Server,怎樣訪問?
2. 能訪問 Microsoft Access 資料庫嗎?
3. 我升級到了 PHP 4,結果 MySQL 不斷報告「Warning: MySQL: Unable to save result set in ..」,這是怎麼回事?
4. PHP 5 不再綁定 MySQL 用戶端庫,這對我意味著什麼?我還能在 PHP 中使用 MySQL 嗎?我試著使用 MySQL 結果得到「function undefined」錯誤,怎麼辦?
5. 在安裝共享 MySQL 支援之後,只要一加載 libphp4.so,Apache就會 core dump。這個問題能解決嗎?
6. 為什麼我得到類似如下的錯誤:「Warning: 0 is not a MySQL result index in <file> on line <x>」或是「Warning: Supplied argument is not a valid MySQL result resource in <file> on line <x>」?

1. 聽說 PHP 有可能訪問 Microsoft SQL Server,怎樣訪問?

在 Windows 機器中,可以簡單地使用內建的 ODBC 支援和正確的 ODBC 驅動程式。

在 Unix 機器中,可以用 Sybase-CT 驅動程式來訪問 Microsoft SQL Server,因為它們的協定是(至少大部分)相容的。Sybase 做了一個 Linux 系統下所需庫的免費版本。對於其它 Unix 動作系統,需要和 Sybase 聯繫來得到正確的庫。同樣也看看下一個問題的回答。

2. 能訪問 Microsoft Access 資料庫嗎?

可以。若果完全在 Windows 9x/Me/NT/2000 下運行,那已經有了所有所需的工具,可以用 ODBC 和 Microsoft's ODBC drivers for Microsoft Access database。

若果在 Unix 下運行 PHP 而想訪問 Windows 中的 MS Access,那需要 Unix ODBC 驅動程式。OpenLink Software 有一個基於 Unix 的 ODBC 驅動程式可以做這件事。可以下載和試用一個不會過期的免費程式,商業支援版本的價格從 $675 起。

另外一個替代專案是用帶 Windows ODBC 驅動的 SQL Server 並用它來儲存資料,可以通過 Microsoft Access(用 ODBC)和 PHP(用內建驅動)來訪問,或是用一個 Access 和 PHP 都識別的中間檔案格式,例如 flat 檔案或是 dBase 資料庫。關於這一點 OpenLink Software 的 Tim Hayes 寫道:

當可以通過 ODBC 直接從 PHP 訪問資料庫時--例如用 OpenLink 的驅動程式,使用其它資料庫做中間媒介不是一個好主意。若果確實需要一個中間檔案格式,OpenLink 已經發佈了對應於 Windows NT,Linux 和其它 Unix 平台的 Virtuoso(一個虛擬資料庫引擎)。請訪問我們的網站來免費下載。

還有一個已被證實有效的選取是在 Windows 下用 MySQL 和它的 MyODBC 驅動來同步資料庫。Steve Lawrence 寫道:

  • 根據 MySQL 的說明在你的平台上安裝 MySQL。可以從 www.mysql.com 得到最新版(從離你最近的對映站台下載!)。除了設定資料庫和配置會員帳號以外不需要特殊的配置,應該在 host 欄位中放一個 % 或是要用來訪問 MySQL 的 Windows 機器名。記下自己的伺服器名,會員名和密碼。

  • 從 MySQL 網站下載 MyODBC for Windows 驅動程式。最新版是 myodbc-2_50_19-win95.zip(也可以用於 NT,以及原始碼)。在你的 Windows 機器中安裝它。可以用此程式中內含的工具來測試其動作。

  • 用控制台中的 ODBC 管理器新增一個會員或系統 dsn,設定 dsn 名稱,輸入你在第一步中配置的 MySQL 資料庫的主電腦名,會員名,密碼,埠等。

  • 完整安裝 Access,這樣可以確保得到適當的外掛程式 ... 至少需要 ODBC 支援和連線表管理器。

  • 新增一個 Access 資料庫。在 Table 視窗點閱右鍵並選取 Link Tables,或是在 File 選單下選取 Get External Data -> Link Tables。當檔案瀏覽視窗開啟後,選取檔案類型為:ODBC。接著選取 System dsn 以及在第三步建立的 dsn 的名字。再選取要連線的表,點閱 OK。現在你可以在你的 MySQL 伺服器中開啟表並新增/移除/編輯資料了!也可以構造查詢,匯入/匯出表到 MySQL,構造表單和報告等。

提示與技巧:

  • 可以在 Access 中構造表並匯出到 MySQL 中,再把它們連線回來。這樣可以使表的建立更快。

  • 在 Access 中建立表時,必需定義一個基本鍵名來取得表的寫權限。確認在把表連線到 Access 之前在 MySQL 中建立了基本鍵名。

  • 若果在 MySQL 中修改了表,必須重新連線到 Access。開啟 Tools>Add-ins>Linked table manager,找到你的 ODBC DSN,然後在這裡選取要重新連線的表。也可以在這裡搬移 dsn 源,在點閱 OK 之前選中 always prompt for new location。

3. 我升級到了 PHP 4,結果 MySQL 不斷報告「Warning: MySQL: Unable to save result set in ..」,這是怎麼回事?

看上去最有可能的是,PHP 4 在編譯時使用了 --with-mysql 選項但沒有指定 MySQL 的路徑。這意味著 PHP 使用了它自己內建的 MySQL 用戶端庫。若果你的系統運行了使用其它版本的 MySQL 用戶端庫的套用程式,例如作為 Apache 模組的 PHP 3,那麼在兩個不同版本的用戶端之間有衝突。

重新編譯 PHP 4,並在旗標中加上 MySQL 的路徑「--with-mysql=/your/path/to/mysql」通常會解決此問題。

4. PHP 5 不再綁定 MySQL 用戶端庫,這對我意味著什麼?我還能在 PHP 中使用 MySQL 嗎?我試著使用 MySQL 結果得到「function undefined」錯誤,怎麼辦?

是的。PHP 總是支援 MySQL 的,不是這種方法就是那種方法。在 PHP 5 中唯一的改變就是不再綁定用戶端庫本身了。部分原因是(無特定順序):

  • 現今大多數系統已經安裝了用戶端庫了。

  • 由於以上原因,保持多個版本的庫檔案會導致混亂。例如,若果把 mod_auth_mysql 連線到某個版本,但把 PHP 連線到了另一個版本,然後在 Apache 中同時啟動了它們,會得到無數錯誤。此外,綁定的庫檔案也不總是能和伺服器端的版本很好地配合。對此最明顯的症狀是上哪裡去找 UNIX 功能變數套接字檔案 mysql.socket。

  • 維護有些鬆懈,並且已經越來越落後於發行的版本了。

  • 未來的庫版本是基於 GPL 的,因此我們沒有升級的途徑了,因為我們不能將基於 GPL 的庫和 BSD/Apache 風格許可證的項目綁定到一起。因此具有一個乾淨的 PHP 5 是最好的選取。

事實上這並不會影響到太多人。UNIX 會員,起碼是那些知道自己在做什麼的人,往往會在編譯 PHP 時通過 --with-mysql=/usr 將其綁定到自己系統中的 libmyqlclient 庫上。Windows 會員可以在 php.ini 中啟動 php_mysql.dll 增加庫。更多細節見 MySQL 函數中的安裝指南。此外,確認 libmysql.dll 在系統路徑中。具體怎樣做的明細,請閱讀 FAQ 中的設定 Windows 系統路徑。因為 libmysql.dll(以及很多其它 PHP 有關檔案)存放於 PHP 目錄中,可能需要將 PHP 目錄加入到系統路徑中。

5. 在安裝共享 MySQL 支援之後,只要一加載 libphp4.so,Apache就會 core dump。這個問題能解決嗎?

若果你的 MySQL 庫依靠 pthreads 連線就會這樣。檢查是否使用了 ldd。若果有的話,下載 MySQL 源程式編譯,或是從源 rpm 的 spec 檔案中去掉開啟 threaded client 的選項然後重新編譯。以上任一建議會解決此問題。然後再加上新的 MySQL 庫重新編譯 PHP。

6. 為什麼我得到類似如下的錯誤:「Warning: 0 is not a MySQL result index in <file> on line <x>」或是「Warning: Supplied argument is not a valid MySQL result resource in <file> on line <x>」?

你試圖用一個值為 0 的結果資源號。0 表示你的查詢由於某原因失敗了,需要在送出查詢之後和在使用返回結果資源號之前檢查錯誤。正確的方法是用類似如下的代碼:
<?php

$result 
mysql_query("SELECT * FROM tables_priv");
if (!
$result) {
    echo 
mysql_error();
    exit;
}
?>
或是
<?php

$result 
mysql_query("SELECT * FROM tables_priv")
    or die(
"Bad query: " mysql_error());
?>