PHP 4在Windows平台引入了對Microsoft COM(Component Object Model)技術的支援,使PHP腳本能直接調用Windows系統組件、Office應用程式、資料庫引擎等COM物件。官方文檔較為簡略,本文通過實戰範例詳細演示COM在PHP中的應用模式。
┌─────────────────────────────────────┐
│ 應用層 (PHP/ASP/VB) │
└──────────────┬──────────────────────┘
▼
┌─────────────────────────────────────┐
│ ADO (ActiveX Data Objects) │
│ 統一的資料存取物件模型介面 │
└──────────────┬──────────────────────┘
▼
┌─────────────────┬─────────────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ OLEDB │ │ ODBC │ │ 其他 │
│ 提供者 │ │ 驅動程式│ │ 提供者 │
└────┬────┘ └────┬────┘ └────┬────┘
▼ ▼ ▼
┌─────────────────────────────────────────┐
│ 實體資料源 (SQL Server, Access, Oracle, MySQL...) │
└─────────────────────────────────────────┘
php.ini啟用 extension=php_com_dotnet.dllnwind 指向 Northwind.mdb<?php
/**
* PHP COM ADO 連線 Access 資料庫範例
* 顯示 Products 表前三欄位資料
*/
try {
// 1. 建立ADO連線物件
$conn = new COM("ADODB.Connection") or die("無法建立ADODB.Connection物件");
// 2. 設定提供者與連線字串
$conn->Provider = "MSDASQL"; // 使用ODBC橋接器
$conn->Open("nwind"); // 使用系統DSN名稱
// 3. 執行SQL查詢,取得Recordset
$sql = "SELECT ProductID, ProductName, UnitPrice FROM Products";
$rs = $conn->Execute($sql);
if ($rs === false) {
throw new Exception("查詢執行失敗");
}
// 4. 取得欄位物件參考(效能優化:避免重複索引)
$fldId = $rs->Fields(0); // ProductID
$fldName = $rs->Fields(1); // ProductName
$fldPrice = $rs->Fields(2); // UnitPrice
// 5. 迴圈輸出資料
echo "<table border='1' cellpadding='5'>";
echo "<tr><th>ID</th><th>產品名稱</th><th>單價</th></tr>";
$count = 0;
while (!$rs->EOF) {
// MoveNext()會更新Fields集合的Value屬性
echo "<tr>";
echo "<td>" . htmlspecialchars($fldId->Value) . "</td>";
echo "<td>" . htmlspecialchars($fldName->Value) . "</td>";
echo "<td>" . number_format($fldPrice->Value, 2) . "</td>";
echo "</tr>";
$rs->MoveNext();
$count++;
// 安全限制:防止無限迴圈
if ($count > 1000) break;
}
echo "</table>";
echo "<p>共 {$count} 筆記錄</p>";
} catch (com_exception $e) {
echo "COM錯誤: " . $e->getMessage() . " (Code: {$e->getCode()})";
} catch (Exception $e) {
echo "執行錯誤: " . $e->getMessage();
} finally {
// 6. 釋放資源(重要:COM物件需顯式釋放)
if (isset($rs)) {
$rs->Close();
$rs = null;
}
if (isset($conn)) {
$conn->Close();
$conn = null;
}
// 強制垃圾回收
gc_collect_cycles();
}
?>
<?php
$conn = new COM("ADODB.Connection");
$conn->Provider = "SQLOLEDB"; // SQL Server原生OLEDB提供者
$conn->Open(
"Data Source=192.168.1.100;".
"Initial Catalog=MyDatabase;".
"User Id=sa;Password=your_password;"
);
// 參數化查詢防注入
$cmd = new COM("ADODB.Command");
$cmd->ActiveConnection = $conn;
$cmd->CommandText = "SELECT * FROM Users WHERE UserID = ? AND Status = ?";
$cmd->CommandType = 1; // adCmdText
// 建立參數
$param1 = $cmd->CreateParameter("@uid", 3, 1, 4, 1001); // adInteger=3, adParamInput=1
$param2 = $cmd->CreateParameter("@status", 200, 1, 10, "Active"); // adVarChar=200
$cmd->Parameters->Append($param1);
$cmd->Parameters->Append($param2);
$rs = $cmd->Execute();
// ... 處理結果集 ...
$obj = null釋放引用,配合gc_collect_cycles()Close()再釋放| ADO類型常數 | 值 | PHP對應類型 | 說明 |
|---|---|---|---|
| adInteger | 3 | int | 4位元組整數 |
| adVarChar | 200 | string | 可變長度字串 |
| adDouble | 5 | float | 雙精度浮點數 |
| adDate | 7 | string/VARIANT | 日期時間,建議用Format轉字串 |
| adBoolean | 11 | bool | True/False (-1/0) |
| adLongVarBinary | 205 | string | 二進位資料(BLOB) |
0x800A0E7A:提供者不可用 → 驅動未安裝或Provider名稱錯誤0x80004005:未指定錯誤 → 連線字串錯誤、權限不足、資料庫不存在0x800A0BB9:引數型別錯誤 → CreateParameter類型/長度不匹配0x800A0BCD:物件或提供者無法執行操作 → Recordset已關閉或游標類型不支援adOpenForwardOnly (0) + adLockReadOnly (1) 效能最佳adLockBatchOptimistic配合UpdateBatch()$data = $rs->GetRows() 返回二維陣列,避免逐行COM呼叫開銷雖然COM+ADO在Windows平台可行,但現代PHP開發建議:
PHP透過COM操作ADO實現Windows平台資料庫存取,適用於維護舊系統、Office自動化、系統管理腳本等場景。掌握Connection/Recordset/Command/Field物件模型、參數化查詢、資源釋放規範,即可構建穩健的資料存取層。新專案優先考慮PDO等原生擴展。