生產環境 PHP 已編譯安裝,需添加 FTP 擴展但不想重新編譯整個 PHP。使用 phpize 進行擴展單獨編譯是標準解決方案。
cd /usr/local/src/php-7.4.33/ext/ftp
注意:必須使用與當前運行 PHP 版本完全一致的源碼目錄。
/usr/local/php/bin/phpize
輸出應包含:
Configuring for:
PHP Api Version: 20190902
Zend Module Api No: 20190902
Zend Extension Api No: 320190902
./configure --with-php-config=/usr/local/php/bin/php-config
--with-php-config:指定目標 PHP 安裝的 php-config 路徑(不是 php.ini)--enable-ftp,但通常默認即啟用make && make install
成功後會提示安裝路徑,類似:
Installing shared extensions: /usr/local/php/lib/php/extensions/no-debug-non-zts-20190902/
# 創建擴展存放目錄
mkdir -p /usr/local/php/etc/ext
# 複製編譯產物
cp /usr/local/php/lib/php/extensions/no-debug-non-zts-20190902/ftp.so /usr/local/php/etc/ext/
vi /usr/local/php/etc/php.ini
添加/修改:
; 擴展目錄
extension_dir = "/usr/local/php/etc/ext"
; 載入 FTP 擴展
extension = ftp.so
/usr/local/php/bin/php -m | grep ftp
# 或
/usr/local/php/bin/php -r "var_dump(function_exists('ftp_connect'));"
# 輸出 bool(true) 表示成功
| 要點 | 說明 |
|---|---|
| 源碼版本一致 | phpize 所用源碼必須與運行的 PHP 版本完全一致(主版本.次版本.修訂版本) |
| php-config 路徑 | 必須指向目標 PHP 安裝的 php-config,而非系統默認或其他版本 |
| 線程安全性 | 編譯產物目錄名包含 zts(線程安全) 或 non-zts,必須與 PHP 運行模式匹配 |
| 依賴庫 | FTP 擴展通常無額外依賴,但某些擴展需預裝開發庫(如 libpng-dev, libcurl4-openssl-dev) |
| 權限 | 編譯安裝需 root 權限,或確保目標目錄可寫 |
#!/bin/bash
# compile_php_extension.sh
# 用法: ./compile_php_extension.sh ftp
set -e
EXT_NAME=$1
PHP_PREFIX="/usr/local/php"
SRC_DIR="/usr/local/src/php-$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')"
if [ -z "$EXT_NAME" ]; then
echo "用法: $0 "
exit 1
fi
cd "$SRC_DIR/ext/$EXT_NAME"
$PHP_PREFIX/bin/phpize
./configure --with-php-config=$PHP_PREFIX/bin/php-config
make -j$(nproc)
make install
# 自動更新 php.ini
INI_FILE="$PHP_PREFIX/etc/php.ini"
EXT_DIR="$PHP_PREFIX/etc/ext"
mkdir -p "$EXT_DIR"
# 複製 .so
cp $PHP_PREFIX/lib/php/extensions/$(ls $PHP_PREFIX/lib/php/extensions/)/$EXT_NAME.so $EXT_DIR/
# 更新配置
if ! grep -q "^extension_dir" "$INI_FILE"; then
echo "extension_dir = \"$EXT_DIR\"" >> "$INI_FILE"
fi
if ! grep -q "^extension = $EXT_NAME.so" "$INI_FILE"; then
echo "extension = $EXT_NAME.so" >> "$INI_FILE"
fi
echo "擴展 $EXT_NAME 安裝完成,請重啟 PHP-FPM 生效"
<?php
// test_ftp.php
$conn = ftp_connect('ftp.gnu.org');
if ($conn) {
echo "連接成功\n";
$login = ftp_login($conn, 'anonymous', 'test@example.com');
echo $login ? "登錄成功\n" : "登錄失敗\n";
// 列出根目錄
$list = ftp_nlist($conn, '/');
print_r(array_slice($list, 0, 5));
ftp_close($conn);
} else {
echo "連接失敗\n";
}
?>
| 現象 | 原因 | 解決 |
|---|---|---|
| phpize: command not found | 未安裝 php-dev/php-devel 包 | apt install php-dev / yum install php-devel |
| configure: error: Cannot find php-config | 路徑錯誤或未安裝 | 指定正確的 --with-php-config 路徑 |
| make: *** [ftp.lo] Error 1 | 源碼版本不匹配/缺少依賴 | 對齊源碼版本、安裝開發庫 |
| PHP Warning: Unable to load dynamic library 'ftp.so' | extension_dir 錯誤/位數不匹配/ZTS 不匹配 | 檢查 phpinfo() 中的 Extension Dir、Thread Safety、Architecture |
| function_exists('ftp_connect') 為 false | 擴展未載入/載入順序/語法錯誤 | 檢查 php.ini 語法、重啟 PHP-FPM、查看錯誤日志 |
如果項目使用 Composer,推薦使用純 PHP 實現的 FTP 客戶端,避免編譯擴展的維護成本:
composer require phpseclib/phpseclib
# 或
composer require league/flysystem-ftp
<?php
use phpseclib\Net\FTP;
$ftp = new FTP('ftp.example.com');
if ($ftp->login('user', 'pass')) {
$ftp->put('remote.txt', 'local.txt', FTP::SOURCE_LOCAL_FILE);
$list = $ftp->nlist();
print_r($list);
}
?>
phpize 動態編譯擴展是 PHP 運維核心技能,關鍵在於:源碼版本精確匹配、php-config 路徑正確、ZTS/位數一致性、extension_dir 配置準確。現代項目優先考慮 Composer 純 PHP 庫替代原生擴展,減少運維複雜度。