首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >当控制台FTP似乎运行良好时,如何调试PHP在PASV模式下不能工作的原因?

当控制台FTP似乎运行良好时,如何调试PHP在PASV模式下不能工作的原因?
EN

Stack Overflow用户
提问于 2017-10-30 16:33:22
回答 2查看 6.3K关注 0票数 2

我有一个码头撰写系统的测试,在其中我正在做一个单一网页的应用程序的端到端测试。网站中的几个按钮将导致在一个容器(missive-transmitter)中启动FTP连接,并在另一个容器(missive-testbox)中测试FTP服务器。

我在PHP中的FTP逻辑总是使用“被动”模式,我认为这是造成问题的原因。我已经创建了一个在missive-transmitter中运行的脚本,这是一个简化的真实版本。它如下所示,并直接从控制台运行:

代码语言:javascript
复制
<?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()失败:第23行/root/src/ftptest.php中正在执行的操作(115) 警告: ftp_put():TYPE现在是第23行/root/src/ftptest.php中的ASCII 无法发送文件

我希望我的FTP操作在PASV模式下工作。

奇怪的是,如果我安装了FTP客户端,那么它似乎在主动或被动模式下工作,这正是我所不理解的。在missive-transmitter方面:

代码语言:javascript
复制
~/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模式?

我已经确认,这两个容器可以从各自的sh控制台上彼此连接。他们在同一个(自定义)码头网络上。

missive-testbox Docker容器基于gists/pure-ftpd,因此据我所知,应该正确配置它。

更新

下面回答的一个有用的问题是NAT可能如何使一方使用错误的IP地址进行连接。然而,IP地址似乎在同一个子网上,尽管我不是网络专家。

来自missive-transmitter

代码语言:javascript
复制
~ # 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

代码语言:javascript
复制
~ # 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的调试模式下。

活动模式首先是:

代码语言:javascript
复制
~/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中的被动版本,再次成功。

我注意到了一开始的警告,关于一个需要修复的地址--这是否相关?如果任何一方向另一方宣传自己为"localhost",这可能是一个问题,:-)

代码语言:javascript
复制
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
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-10-30 17:28:00

很难说这里完成了哪些FTP操作。但是,可能是PHP使用PASV,而lftp使用EPSV设置被动模式。

PASV的情况下,服务器同时发送IP地址和端口号,等待连接。使用EPSV,服务器只提供端口号,目标IP地址是当前FTP控制连接的地址。如果涉及NAT (网络地址转换)(在Docker设置中并非不太可能),则与从FTP客户端外部可见的IP地址相比,服务器可能会看到一个不同的内部IP地址,这意味着客户端无法连接到在响应PASV命令时给出的(错误)IP地址。对于EPSV,这个问题不存在,因为客户端不使用提供的服务器地址作为目标。

票数 2
EN

Stack Overflow用户

发布于 2017-10-30 18:31:47

综合了有用的答案和评论,再加上来自LFTP的警告,我找到了一个解决方案。正如Steffen所推测的,这个问题与PASV模式下的IP可见性有关。LFTP客户端帮助检测到我的服务器配置错误,因此透明地修复了它,这就是产生混乱的地方。

值得注意的是,PHP并不是那么聪明或善良--它没有这样的修复(当然,这在技术上是正确的)。

这种配置的原因是默认Dockerfile设置

代码语言:javascript
复制
ENV PUBLIC_HOST localhost

所以,我现在所做的就是用LAN IP替换我自己的Dockerfile中的这个文件:

代码语言:javascript
复制
ENV PUBLIC_HOST 172.19.0.2

一次重新启动后,修复消息就从LFTP中消失了,我的PHP脚本也能工作。

更新

由于我不知道是否可以依赖上述IP地址的静态性,所以将其重置为容器的名称:

代码语言:javascript
复制
ENV PUBLIC_HOST missive-testbox

这看起来挺好的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47020129

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档