代码如下:

$ftp = ftp_connect($config['host'], $config['port'], 10);
ftp_login($ftp, $config['user'], $config['password']);
ftp_pasv($ftp, true);

$dist = 'test.txt';
$src = '/tmp/test.txt';
$result = ftp_put($ftp, $dist, $src, FTP_BINARY);

var_dump($result);

始终上传不上去,$result为false。但是用FileZilla却能正常上传。 用tcpdump抓包看返回:500 OOPS: vsf_sysutil_recv_peek: no data 如图:

这是因为被动模式下,FTP SERVER返回了个私有地址(172那个),然后FTP CLIENT无法识别。

解决办法有两个:

  1. 在ftp_pasv前面加上ftp_set_option($ftp, FTP_USEPASVADDRESS, false); 但是5.6.10版本不支持,需要升级到5.6.30+(没仔细看哪个版本提交的bugfix)

2.如果FTP server是vsftpd, 可在server端设置 pasv_addr_resolve=YES 被动模式是否用设置好的的地址返回给客户端,如果是NO,则从链接的套接字中自己获取地址,如果为YES,则设置为下面这个地址 pasv_address=202.101.104.126 被动模式下返回的地址,安全需要,隐掉后面两个地址段

参考链接:

  1. https://winscp.net/eng/docs/ftp_modes
  2. https://stackoverflow.com/questions/38982901/php-ftp-passive-ftp-server-behind-nat
  3. https://github.com/php/php-src/pull/1668