Tommy 碎碎念

Tommy Wu's blog

« 上一篇 | 下一篇 »

在 Win32 下的 PHP 使用 ftp_ssl_connect()
post by tommy @ 07 九月, 2008 10:17

在 php 官方的說明文件中, 提到要使用 ftp_ssl_connect() 必須要有 openssl 的支援才可以. 而且在 Windows 下頭, 必須要自行重新編譯一個內建 openssl 支援的版本才可以.

文件上頭, 有人提到了這個網頁, 上頭有說明如何自行在 Windows 下頭編譯出支援 ftp_ssl_connect() 的 php 版本. 不過上頭的說明, 也許是編排有誤的關係, 發現有一段少了幾句話, 會無法正常的編譯出 php 的執行檔. 所以我重新整理了一下.

  1. 安裝 Visual C++.
    使用 Visual Studio Express 或 Visual Studio 2005 都可以.
  2. 安裝所需要的函式庫.
    這兒下載 zip.zip, 這是編譯 php 所需要的 library.
  3. 如果你編譯 php 時, 有出現找不到 xmlXPathCompiledEvalToBoolean 的錯誤時, 表示你下載的 zip.zip 裡頭的 libxml2 並未更新到新的版本. 請到這兒抓取新的 libxml2 回來.
  4. php 官方網站下載 php 的原始碼.
    我是使用 php 5.2.6 的版本.
  5. 把 php 的原始碼解開來, 放在 c:\work\php5 下頭.
  6. 把 zip.zip 裡頭的 php_build 解開來, 放到 c:\work\php_build 下頭.
  7. 如果有 xml 的錯誤, 把 libxml2 解開來, 裡頭的 include, lib, util 目錄, 搬到 c:\work\php_build 下頭, 覆蓋原來的檔案.
  8. 打開一個 Command Prompt 視窗, 然後執行 vcvars32.bat
    這個批次檔應該是在你的 VC++ 下頭的 bin 目錄中.
  9. 使用 patch 修正你的 ftp.c, 修正如下:
    --- php-5.2.6.orig/ext/ftp/ftp.c Mon Dec 31 15:20:06 2007
    +++ php-5.2.6/ext/ftp/ftp.c Sun Sep 7 10:10:39 2008
    @@ -242,6 +242,7 @@
    ftp_login(ftpbuf_t *ftp, const char *user, const char *pass TSRMLS_DC)
    {
    #if HAVE_OPENSSL_EXT
    + int errcode;
    SSL_CTX *ctx = NULL;
    #endif
    if (ftp == NULL) {
    @@ -290,11 +291,23 @@
     
    SSL_set_fd(ftp->ssl_handle, ftp->fd);
     
    - if (SSL_connect(ftp->ssl_handle) <= 0) {
    - php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSL/TLS handshake failed");
    - SSL_shutdown(ftp->ssl_handle);
    - return 0;
    - }
    + do {
    + errcode = SSL_connect(ftp->ssl_handle);
    + switch (SSL_get_error(ftp->ssl_handle, errcode)) {
    + case SSL_ERROR_NONE:
    + errcode = 1;
    + break;
    + case SSL_ERROR_WANT_WRITE:
    + case SSL_ERROR_WANT_READ:
    + case SSL_ERROR_WANT_X509_LOOKUP:
    + errcode = 0;
    + break;
    + default:
    + php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSL/TLS handshake failed");
    + SSL_shutdown(ftp->ssl_handle);
    + return 0;
    + }
    + } while (errcode == 0 && !SSL_is_init_finished(ftp->ssl_handle));
     
    ftp->ssl_active = 1;
     
    @@ -1272,6 +1285,9 @@
    my_recv(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len)
    {
    int n, nr_bytes;
    +#if HAVE_OPENSSL_EXT
    + int no_error;
    +#endif
     
    n = php_pollfd_for_ms(s, PHP_POLLREADABLE, ftp->timeout_sec * 1000);
    if (n < 1) {
    @@ -1287,7 +1303,25 @@
    if (ftp->use_ssl && ftp->fd == s && ftp->ssl_active) {
    nr_bytes = SSL_read(ftp->ssl_handle, buf, len);
    } else if (ftp->use_ssl && ftp->fd != s && ftp->use_ssl_for_data && ftp->data->ssl_active) {
    - nr_bytes = SSL_read(ftp->data->ssl_handle, buf, len);
    + no_error = 1; // there is no error
    + do {
    + nr_bytes = SSL_read(ftp->data->ssl_handle, buf, len);
    + switch (SSL_get_error(ftp->data->ssl_handle, nr_bytes)) {
    + case SSL_ERROR_NONE:
    + case SSL_ERROR_ZERO_RETURN:
    + case SSL_ERROR_WANT_WRITE:
    + case SSL_ERROR_WANT_X509_LOOKUP:
    + case SSL_ERROR_WANT_READ:
    + break;
    + case SSL_ERROR_WANT_CONNECT:
    + case SSL_ERROR_WANT_ACCEPT:
    + case SSL_ERROR_SSL:
    + case SSL_ERROR_SYSCALL:
    + default:
    + no_error = 0; //major error, get out
    + break;
    + }
    + } while (nr_bytes < 0 && no_error);
    } else {
    #endif
    nr_bytes = recv(s, buf, len, 0);
    @@ -1491,6 +1525,7 @@
    socklen_t size;
     
    #if HAVE_OPENSSL_EXT
    + int errcode;
    SSL_CTX *ctx;
    #endif
     
    @@ -1534,11 +1569,23 @@
    SSL_copy_session_id(data->ssl_handle, ftp->ssl_handle);
    }
     
    - if (SSL_connect(data->ssl_handle) <= 0) {
    - php_error_docref(NULL TSRMLS_CC, E_WARNING, "data_accept: SSL/TLS handshake failed");
    - SSL_shutdown(data->ssl_handle);
    - return 0;
    - }
    + do {
    + errcode = SSL_connect(data->ssl_handle);
    + switch (SSL_get_error(data->ssl_handle, errcode)) {
    + case SSL_ERROR_NONE:
    + errcode = 1;
    + break;
    + case SSL_ERROR_WANT_WRITE:
    + case SSL_ERROR_WANT_READ:
    + case SSL_ERROR_WANT_X509_LOOKUP:
    + errcode = 0;
    + break;
    + default:
    + php_error_docref(NULL TSRMLS_CC, E_WARNING, "data_accept: SSL/TLS handshake failed");
    + SSL_shutdown(data->ssl_handle);
    + return 0;
    + }
    + } while (errcode == 0 && !SSL_is_init_finished(data->ssl_handle));
     
    data->ssl_active = 1;
    }
    檔案可以由這兒抓取.
  10. 執行下列幾個指令.
    set PATH=%PATH%;C:\work\php_build\bin;
    set BISON_SIMPLE=C:\work\php_build\bin\bison.simple
    set INCLUDE=C:\work\php_build\include;%INCLUDE%
    set LIB=C:\work\php_build\lib;%LIB%
    set LIBPATH=C:\work\php_build\lib;%LIBPATH%
  11. 開始編譯 php. 執行下列的指令:
    cd c:\work\php5
    buildconf
    cscript /nologo configure.js --with-openssl
    nmake
  12. 如果沒有錯誤 (會有一堆 warnning, 可以忽略), 最後在 c:\work\php5\Release_TS 下頭會有最後產生的檔案. 把 php.exe, php5ts.dll, php-cgi.exe 複製到你原本安裝 php 的目錄下, 覆蓋舊的檔案.
  13. 把 zip.zip 裡頭 dev\template\dlls 裡頭的 libeay32.dll, ssleay32.dll 複製到你原本安裝的 php 的目錄下.

幾過上頭的動作, 你的 php 就應該可以使用 ftp_ssl_connect() 了. 如果你不知道怎麼編譯, 且不怕我編出來的執行檔有問題的話, 可以下載這個檔案 (php 5.2.6) 回去, 解開來放到你安裝 php 的目錄下, 覆蓋舊的檔案就可以了. 不過.... 如果因為這個檔案所造成的任何問題, 請自行負責, 不要來找我. :-)

Del.icio.us Furl HEMiDEMi Technorati MyShare
迴響
暱稱:
標題:
個人網頁:
電子郵件:
authimage

迴響

  

Bad Behavior 已經阻擋了 96 個過去 7 天試圖闖關的垃圾迴響與引用。
Power by LifeType. Template design by JamesHuang. Valid XHTML and CSS