我有一个用于测试的 Docker Compose 系统,我在其中对单页 Web 应用程序进行端到端测试。网站中的几个按钮将导致在一个容器 ( missive-transmitter
) 中启动 FTP 连接,然后转到另一个容器 ( missive-testbox
) 中的测试 FTP 服务器。
我在 PHP 中的 FTP 逻辑总是使用“被动”模式,我认为这是导致问题的原因。我创建了一个脚本来运行missive-transmitter
,它是真实事物的简化版本。如下,直接从控制台运行:
<?php
# ftptest.php
error_reporting(-1);
ini_set('display_errors', true);
$conn = ftp_connect('missive-testbox', 21);
$ok1 = ftp_login($conn, 'missive_test', 'password');
if (!$ok1)
{
die("Cannot log in\n");
}
// *** Start problem section
$ok2 = ftp_pasv($conn, true);
if (!$ok2)
{
die("Cannot switch to passive mode\n");
}
// *** End problem section
$info = ftp_systype($conn);
echo "Info: $info\n";
$ok3 = ftp_put($conn, 'ftptest.php', 'ftptest.php', FTP_ASCII);
if (!$ok3)
{
die("Cannot send a file\n");
}
现在,如果我删除该***
部分(启用被动模式),那么脚本将起作用。如果我把它留在里面,我会得到这个:
信息:UNIX
警告:ftp_put(): php_connect_nonb() failed: Operation in progress (115) in /root/src/ftptest.php on line 23
警告:ftp_put(): TYPE 现在是 ASCII 在 /root/src/ftptest.php 的第 23 行
无法发送文件
我希望我的 FTP 操作在 PASV 模式下工作。
奇怪的是,如果我安装了一个 FTP 客户端,那么它似乎可以在主动或被动模式下工作,这是我不明白的。missive-transmitter
侧面:
~/src $ # This is the `sh` shell in `missive-transmitter`
~/src $ #
~/src $ # Install LFTP in Alpine environment
~/src $ apk add lftp
~/src $ lftp missive_test@missive-testbox
Password:
lftp missive_test@missive-testbox:~> set ftp:passive-mode off
lftp missive_test@missive-testbox:~> put ftptest.php
457 bytes transferred
lftp missive_test@missive-testbox:/> set ftp:passive-mode on
lftp missive_test@missive-testbox:/> put ftptest.php
457 bytes transferred
lftp missive_test@missive-testbox:/>
PHP 是在做不同的事情,还是我实际上没有在控制台客户端中使用 PASV 模式?
我已经确认两个容器可以ping
从各自的sh
控制台相互连接。它们位于同一个(自定义)Docker 网络上。
missive-testbox
Docker容器是基于的,gists/pure-ftpd
所以据我所知应该配置正确。
更新
以下答案中的一个有用点是关于 NAT 可能如何使一侧使用错误的 IP 地址建立连接。但是,虽然我不是网络专家,但 IP 地址似乎在同一个子网上。
来自missive-transmitter
:
~ # ping missive-testbox
PING missive-testbox (172.19.0.2): 56 data bytes
64 bytes from 172.19.0.2: seq=0 ttl=64 time=0.076 ms
从missive-testbox
:
~ # ping missive-transmitter
PING missive-transmitter (172.19.0.4): 56 data bytes
64 bytes from 172.19.0.4: seq=0 ttl=64 time=0.119 ms
我认为他们都是172.19.0.x
地址的事实意味着他们应该能够完全看到对方,尽管我愿意对这个假设进行更正。
更新 2
有人建议获取一些 FTP 客户端或服务器日志是调试此问题的好方法。客户端很简单。这里是与上面相同的操作,但在 LFTP 的调试模式下。
主动模式为先:
~/src # lftp -d missive_test@missive-testbox
Password:
---- Resolving host address...
---- 1 address found: 172.19.0.2
lftp missive_test@missive-testbox:~> set ftp:passive-mode off
lftp missive_test@missive-testbox:~> put ftptest.php
---- Connecting to missive-testbox (172.19.0.2) port 21
<--- 220-Welcome to Pure-FTPd.
<--- 220-You are user number 1 of 5 allowed.
<--- 220-Local time is now 17:54. Server port: 21.
<--- 220-This is a private system - No anonymous login
<--- 220-IPv6 connections are also welcome on this server.
<--- 220 You will be disconnected after 15 minutes of inactivity.
---> FEAT
<--- 530 You aren't logged in
---> AUTH TLS
<--- 500 This security scheme is not implemented
---> USER missive_test
<--- 331 User missive_test OK. Password required
---> PASS XXXX
<--- 230 OK. Current directory is /
---> FEAT
<--- 500 Unknown command
---> PWD
<--- 257 "/" is your current location
---> TYPE I
<--- 200 TYPE is now 8-bit binary
---> PORT 172,19,0,4,159,62
<--- 200 PORT command successful
---> ALLO 457
<--- 500 Unknown command
---> STOR ftptest.php
---- Accepted data connection from (172.19.0.2) port 20
<--- 150 Connecting to port 40766
---- Closing data socket
<--- 226-File successfully transferred
<--- 226 0.000 seconds (measured here), 3.16 Mbytes per second
---> SITE UTIME 20171030154823 ftptest.php
<--- 500 Unknown command
---> SITE UTIME ftptest.php 20171030154823 20171030154823 20171030154823 UTC
<--- 500 Unknown command
457 bytes transferred
好的,这很成功。这是LFTP中的被动版本,再次成功。
我注意到一开始的警告,关于需要修复的地址 - 这可能是相关的吗?如果任何一方将自己宣传为“本地主机”,这可能是一个问题:-)
:
lftp missive_test@missive-testbox:/> set ftp:passive-mode on
lftp missive_test@missive-testbox:/> put ftptest.php
---> PASV
<--- 227 Entering Passive Mode (127,0,0,1,117,54)
---- Address returned by PASV seemed to be incorrect and has been fixed
---- Connecting data socket to (172.19.0.2) port 30006
---- Data connection established
---> STOR ftptest.php
<--- 150 Accepted data connection
---- Closing data socket
<--- 226-File successfully transferred
<--- 226 0.000 seconds (measured here), 1.79 Mbytes per second
457 bytes transferred