草庐IT

带有显式 TLS/SSL 的 PHP curl FTPes

coder 2024-04-12 原文

我一直在尝试使用显式 TLS/SSL 服务器推送到远程 FTP,但连接一直超时。它正在连接,但我不知道它在哪里停止,但我假设它与 FTP/TLS/SSL 控制 channel 有关。任何帮助将不胜感激。

通过 FileZilla,我可以毫无问题地连接,但不能通过 curl。我可能遗漏了一些东西,希望这里的人知道使用 curl 重新创建 session 的最佳方法。这是 FileZilla 的调试输出和我一直在 PHP/curl 中处理的示例代码。这是 PHP 代码,下面是成功的 FileZilla session 的副本。

这里是版本,但我在不同的系统上试过,结果相同。

Curl: v7.43.0

└─(08:04:00 on master ✹)──> php -v                                          ──(Thu,Sep10)─┘
PHP 5.5.27 (cli) (built: Jul 14 2015 17:04:01)
Copyright (c) 1997-2015 The PHP Group
Zend Engine v2.5.0, Copyright (c) 1998-2015 Zend Technologies
    with Xdebug v2.3.3, Copyright (c) 2002-2015, by Derick Rethans

这是实际的代码。

<?php

$server_data = array(
   'transfer_id' => 123456789,
   'post_url' => "ftps://ftps.widgetsltd.com",
   'port' => 21,
   'username' => 'widgetsftp',
   'password' => 'password',
);

$filename = sprintf("%s-%s-%s.csv",
                    $server_data['transfer_id'],
                    microtime(TRUE),
                    rand(1000, 9999));

$temp_filename = sprintf("/tmp/%s", $filename);
$ftp_data = "This is a test";

$fp = fopen($temp_filename, 'w');
fprintf($fp, "%s", $ftp_data);
fclose($fp);

$fp = fopen($temp_filename, 'r');

$ch = curl_init();

curl_setopt($ch, CURLOPT_VERBOSE, TRUE);    
curl_setopt($ch, CURLOPT_URL, sprintf("%s/%s", $server_data['post_url'], $filename));
curl_setopt($ch, CURLOPT_PORT, 21);    
curl_setopt($ch, CURLOPT_USERPWD, sprintf("%s:%s", $server_data['username'], $server_data['password']));

curl_setopt($ch, CURLOPT_UPLOAD, TRUE);
curl_setopt($ch, CURLOPT_INFILE, $fp);
curl_setopt($ch, CURLOPT_INFILESIZE, filesize($temp_filename));

curl_setopt($ch, CURLOPT_USE_SSL, TRUE);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_0);
curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, 'AES-128-CBC');

curl_setopt($ch, CURLOPT_FTP_SSL, CURLOPT_FTPSSLAUTH);
curl_setopt($ch, CURLOPT_FTPSSLAUTH, CURLFTPAUTH_TLS);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);

print_r(array('curl_exec' => curl_exec($ch)));
print_r(array(
           'curl_errno' => curl_errno($ch),
           'curl_error' => curl_error($ch),
        ));

这是 FileZilla session 。

Status:        Resolving address of ftps.widgetsltd.com
Status:        Connecting to 123.123.123.123:21...
Status:        Connection established, waiting for welcome message...
Trace:         CFtpControlSocket::OnReceive()
Response:  220-Microsoft FTP Service
Response:  220 Widgets, LTD FTP server
Trace:         CFtpControlSocket::SendNextCommand()
Command:   AUTH TLS
Trace:         CFtpControlSocket::OnReceive()
Response:  234 AUTH command ok. Expecting TLS Negotiation.
Status:        Initializing TLS...
Trace:         CTlsSocket::Handshake()
Trace:         CTlsSocket::ContinueHandshake()
Trace:         CTlsSocket::OnSend()
Trace:         CTlsSocket::OnRead()
Trace:         CTlsSocket::ContinueHandshake()
Trace:         CTlsSocket::OnRead()
Trace:         CTlsSocket::ContinueHandshake()
Trace:         TLS Handshake successful
Trace:         Protocol: TLS1.0, Key exchange: RSA, Cipher: AES-128-CBC, MAC: SHA1
Status:        Verifying certificate...
Status:        TLS connection established.
Trace:         CFtpControlSocket::SendNextCommand()
Command:   USER s-rokfri
Trace:         CTlsSocket::OnRead()
Trace:         CFtpControlSocket::OnReceive()
Response:  331 Password required for s-rokfri.
Trace:         CFtpControlSocket::SendNextCommand()
Command:   PASS ********
Trace:         CTlsSocket::OnRead()
Trace:         CFtpControlSocket::OnReceive()
Response:  230-This service and information contained therein belong to Widgets, LTD.
Response:  230 User logged in.
Trace:         CFtpControlSocket::SendNextCommand()
Command:   OPTS UTF8 ON
Trace:         CTlsSocket::OnRead()
Trace:         CFtpControlSocket::OnReceive()
Response:  200 OPTS UTF8 command successful - UTF8 encoding now ON.
Trace:         CFtpControlSocket::SendNextCommand()
Command:   PBSZ 0
Trace:         CTlsSocket::OnRead()
Trace:         CFtpControlSocket::OnReceive()
Response:  200 PBSZ command successful.
Trace:         CFtpControlSocket::SendNextCommand()
Command:   PROT P
Trace:         CTlsSocket::OnRead()
Trace:         CFtpControlSocket::OnReceive()
Response:  200 PROT command successful.
Status:        Connected
Trace:         CFtpControlSocket::ResetOperation(0)
Trace:         CControlSocket::ResetOperation(0)
Trace:         CFileZillaEnginePrivate::ResetOperation(0)
Trace:         Measured latency of 141 ms
Status:        Retrieving directory listing...
Trace:         CFtpControlSocket::SendNextCommand()
Trace:         CFtpControlSocket::ChangeDirSend()
Command:   PWD
Trace:         CTlsSocket::OnRead()
Trace:         CFtpControlSocket::OnReceive()
Response:  257 "/" is current directory.
Trace:         CFtpControlSocket::ResetOperation(0)
Trace:         CControlSocket::ResetOperation(0)
Trace:         CFtpControlSocket::ParseSubcommandResult(0)
Trace:         CFtpControlSocket::ListSubcommandResult()
Trace:           state = 1
Trace:         CFtpControlSocket::ResetOperation(0)
Trace:         CControlSocket::ResetOperation(0)
Status:        Directory listing of "/" successful
Trace:         CFileZillaEnginePrivate::ResetOperation(0)

这是 curl 输出。

*   Trying 123.123.123.123...
* Connected to ftps.widgetsltd.com (123.123.123.123) port 21 (#0)
* SSL connection timeout
* Closing connection 0
Array
(
    [curl_exec] =>
)
Array
(
    [curl_errno] => 28
    [curl_error] => SSL connection timeout
)

最佳答案

curl 显然尝试使用隐式 FTP(因为它甚至在与服务器交换任何 FTP 命令之前就初始化 TLS/SSL session )。

这是因为您指定了 ftps:// 前缀,该前缀用于隐式 TLS。它具有特殊前缀,因为隐式 TLS 使用特殊端口 (990)。但是您使用 CURLOPT_PORT 覆盖了默认值。

虽然显式 TLS 使用标准的 FTP 端口 (21),因此它使用标准的 ftp:// 前缀。要启用显式 TLS,请使用 CURLOPT_USE_SSL (你已经在做什么,只是通过一个错误的值,选项类型是枚举,而不是 bool 值)。

所以代码应该是:

$server_data = array(
   ...
   'post_url' => "ftp://ftps.widgetsltd.com", // ftp:// URL
   ...
);

$url = sprintf("%s/%s", $server_data['post_url'], $filename);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_USE_SSL, CURLUSESSL_ALL); // Enable TLS/SSL

请注意,CURLOPT_FTP_SSL 已过时,是 CURLOPT_USE_SSL 的别名。因此,同时设置两者没有意义。

关于带有显式 TLS/SSL 的 PHP curl FTPes,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32491790/

有关带有显式 TLS/SSL 的 PHP curl FTPes的更多相关文章

  1. ruby-on-rails - 带有 Zeus 的 RSpec 3.1,我应该在 spec_helper 中要求 'rspec/rails' 吗? - 2

    使用rspec-rails3.0+,测试设置分为spec_helper和rails_helper我注意到生成的spec_helper不需要'rspec/rails'。这会导致zeus崩溃:spec_helper.rb:5:in`':undefinedmethod`configure'forRSpec:Module(NoMethodError)对thisissue最常见的回应是需要'rspec/rails'。但这是否会破坏仅使用spec_helper拆分rails规范和PORO规范的全部目的?或者这无关紧要,因为Zeus无论如何都会预加载Rails?我应该在我的spec_helper中做

  2. Ruby:如何使用带有散列的 'send' 方法调用方法? - 2

    假设我有一个类A,里面有一些方法。假设stringmethodName是这些方法之一,我已经知道我想给它什么参数。它们在散列中{'param1'=>value1,'param2'=>value2}所以我有:params={'param1'=>value1,'param2'=>value2}a=A.new()a.send(methodName,value1,value2)#callmethodnamewithbothparams我希望能够通过传递我的哈希以某种方式调用该方法。这可能吗? 最佳答案 确保methodName是一个符号,而

  3. ruby-on-rails - 带有 Pry 的 Rails 控制台 - 2

    当我进入Rails控制台时,我已将pry设置为加载代替irb。我找不到该页面或不记得如何将其恢复为默认行为,因为它似乎干扰了我的Rubymine调试器。有什么建议吗? 最佳答案 我刚发现问题,pry-railsgem。忘记了它的目的是让“railsconsole”打开pry。 关于ruby-on-rails-带有Pry的Rails控制台,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/question

  4. 带有 attr_accessor 的类上的 Ruby instance_eval - 2

    我了解instance_eval和class_eval之间的基本区别。我在玩弄时发现的是一些涉及attr_accessor的奇怪东西。这是一个例子:A=Class.newA.class_eval{attr_accessor:x}a=A.newa.x="x"a.x=>"x"#...expectedA.instance_eval{attr_accessor:y}A.y="y"=>NoMethodError:undefinedmethod`y='forA:Classa.y="y"=>"y"#WHATTT?这是怎么回事:instance_eval没有访问我们的A类(对象)然后它实际上将它添加到

  5. ruby-on-rails - Rails 渲染带有驼峰命名法的 json 对象 - 2

    我在一个简单的RailsAPI中有以下Controller代码:classApi::V1::AccountsControllerehead:not_foundendendend问题在于,生成的json具有以下格式:{id:2,name:'Simpleaccount',cash_flows:[{id:1,amount:34.3,description:'simpledescription'},{id:2,amount:1.12,description:'otherdescription'}]}我需要我生成的json是camelCase('cashFlows'而不是'cash_flows'

  6. ruby-on-rails - 在 Ruby 或 Rails 中,hash.merge({ :order => 'asc' }) can return a new hash with a new key. 什么可以返回带有已删除键的新散列? - 2

    在Ruby(或Rails)中,我们可以做到new_params=params.merge({:order=>'asc'})现在new_params是一个带有添加键:order的散列。但是是否有一行可以返回带有已删除key的散列?线路new_params=params.delete(:order)不会工作,因为delete方法返回值,仅此而已。我们必须分3步完成吗?tmp_params=paramstmp_params.delete(:order)returntmp_params有没有更好的方法?因为我想做一个new_params=(params[:order].blank?||para

  7. Ruby SSL 错误 - sslv3 警报意外消息 - 2

    我正在尝试在ruby​​脚本中连接到服务器https://www.xpiron.com/schedule。但是,当我尝试连接时:require'open-uri'doc=open('https://www.xpiron.com/schedule')我收到以下错误消息:OpenSSL::SSL::SSLError:SSL_connectreturned=1errno=0state=SSLv2/v3readserverhelloA:sslv3alertunexpectedmessagefrom/usr/local/lib/ruby/1.9.1/net/http.rb:678:in`conn

  8. ruby - 如何在非 SSL 或 http 网站上使用 Stripe? - 2

    我正在使用Rails3.2.6和Stipe进行支付。是否有可能在不购买ssl证书的情况下进行付款。我可以使用Stripe页面作为我的支付页面吗? 最佳答案 您可以使用stripe.js在技术上跳过SSL但我强烈建议您设置SSL。它所做的是将信用卡信息直接传递给stripe,然后stripe会给你一个token,用于实际进行收费。这样做意味着信用卡信息永远不会接触您的服务器,您不必担心PCI合规性。但是,您仍应设置SSL以防止中间人攻击。您可以在https://stripe.com/docs/tutorials/forms找到有关如何

  9. ruby - HTTP POST 上的 SSL 错误(未知协议(protocol)) - 2

    尝试通过SSL连接到ImgurAPI时出现错误。这是代码和错误:API_URI=URI.parse('https://api.imgur.com')API_PUBLIC_KEY='Client-ID--'ENDPOINTS={:image=>'/3/image',:gallery=>'/3/gallery'}#Public:Uploadanimage##args-Theimagepathfortheimagetoupload#defupload(image_path)http=Net::HTTP.new(API_URI.host)http.use_ssl=truehttp.verify

  10. ruby-on-rails - 从带有 ruby​​ on rails 的网站获取 html - 2

    如何使用ruby​​onrails获取网络上某处其他网站的页面数据? 最佳答案 您可以使用httparty只是获取数据示例代码(来自example):requireFile.join(dir,'httparty')require'pp'classGoogleincludeHTTPartyformat:htmlend#google.comredirectstowww.google.comsothisislivetestforredirectionppGoogle.get('http://google.com')puts'','*'*7

随机推荐