PHP警告:ftp_get():无法打开到端口39997的数据连接:连接超时

时间:2016-06-17 12:44:32

标签: php apache symfony ftp

我希望我能清楚地解释我的问题,因为我感到迷茫,不知道什么是真正的问题。 使用Symfony 2.8和https://github.com/iJanki/FtpBundle我正在尝试连接到ftp服务器并下载文件。整个过程只能通过symfony的app / console启动。

这是我的服务,其中包含整个逻辑:

<?php

namespace xxx\Services\Import;

use Doctrine\ORM\EntityManager;
use Ijanki\Bundle\FtpBundle\Ftp;
use Ijanki\Bundle\FtpBundle\Exception\FtpException;
use xxx\Entity\Product;
use xxx\Entity\ProductImage;

class ImageImport
{
    const FTP_HOST = 'xxx';
    const FTP_USER = 'xxx';
    const FTP_PASSWORD = 'xxx';
    const FTP_PNG_DIR = 'xxx';

    const FTP_FILES_EXT = 'png';

    /**
     *
     * @var EntityManager
     */
    private $em;

    /**
     *
     * @var string
     */
    private $rootDir;

    /**
     *
     * @var Ftp
     */
    private $ftp;

    /**
     * 
     * @param EntityManager $em
     * @param string $rootDir
     * @param Ftp $ftp
     */
    public function __construct(EntityManager $em, $rootDir, Ftp $ftp)
    {
        $this->em = $em;
        $this->rootDir = $rootDir;
        $this->ftp = $ftp;
    }

    public function import()
    {
        set_time_limit(10000);
        ini_set('max_input_time', 10000);
        $this->connectToFtp();
        $this->copyAndMatch();
        $this->disconnectFtp();
    }

    /**
     * 
     * @return boolean
     */
    public function connectToFtp()
    {
        try {
            $this->ftp->connect(self::FTP_HOST, 21, 10000);
            $this->ftp->login(self::FTP_USER, self::FTP_PASSWORD);
            $this->ftp->chdir(self::FTP_PNG_DIR);
            $this->ftp->pasv(false);
            return true;
        } catch (FtpException $e) {
            echo 'Error: ', $e->getMessage();

            return false;
        }
    }

    public function copyAndMatch()
    {
        $matches = $this->getCsvMatches();

        $this->matchWithProducts($matches);
    }

    public function disconnectFtp()
    {
        $this->ftp->close();
    }

    public function __destruct()
    {
        try {
            if (false !== $this->ftp->pwd()) {
                $this->ftp->close();
            }
        } catch (FtpException $ex) {

        }
    }

    /**
     * 
     * @return array|null
     */
    private function getCsvMatches()
    {
//...
    }

    /**
     * 
     * @param array $matches
     * @return true|null
     */
    private function matchWithProducts(array $matches)
    {
        if (empty($matches) || !is_array($matches)) {
            return;
        }

        foreach ($matches as $pair) {
//...

                $filename = $pair['image'] . '.' . self::FTP_FILES_EXT;
                if (false === $this->fileAlreadyAdded($product, $filename) and null !== $this->downloadFile($filename)) {
//...
                }
            }
        }

        $this->em->flush();

        return true;
    }

    /**
     * 
     * @param Product $product
     * @param string $filename
     * @return boolean
     */
    private function fileAlreadyAdded(Product $product, $filename)
    {
//...
    }

    /**
     * 
     * @param string $filename
     * @return string|null
     */
    private function downloadFile($filename)
    {
        try {
            $localFile = $this->rootDir . '/../' . ImportHelper::UPLOAD_DIR . '/' . $filename;
            if ($this->remoteFileExists($filename)) {
                if (false === $this->ftp->pwd()) {
                    $this->connectToFtp();
                }
                $this->ftp->get($localFile, $filename, FTP_BINARY);
            }
            return file_exists($localFile) ? $filename : null;
        } catch (FtpException $ex) {
            echo $ex->getMessage();
            return null;
        }
    }

    /**
     * 
     * @param string $filename
     * @return boolean
     */
    private function remoteFileExists($filename)
    {
        return $this->ftp->size($filename) !== -1;
    }
}

注释掉或删除的代码包含Doctrine操作,并且不相关,因为它们不会导致任何问题。

作为本地环境,我在Windows 7上使用Xampp和Apache2服务器。此外,我测试了与Filezilla的FTP连接,我发现只有在使用ftp活动模式时它才有效。 此外,我发现我的Windows防火墙是警告的原因,我可以连接但在启用时不做任何其他操作。所以我添加了php.exe和apache httpd.exe的例外,所以当我的本地服务器上启动php脚本时,一切都运行正常。 启用Windows防火墙后,ftp_nlist在使用被动模式时返回false,并在使用活动模式时返回警告。

但我的目标是在安装了Ubuntu 14.04.3 LTS的VPS上的生产Web服务器上启动该脚本。我对Unix的了解非常差,但VPS提供商确信在这台服务器上没有启用防火墙但是我一直都会收到警告: PHP警告:ftp_get():无法打开到端口39997的数据连接:连接超时 我的Windows防火墙启用后得到的警告相同。 我还打电话给那些用FTP管理服务器的人(我想要dl的文件)并要求他在防火墙上为端口21上的ftp连接添加例外,但它根本没用。

我确定我没有从ftp服务器获取dicsonnected,我从来没有得到FtpException。我可以看到,下载proccess启动,因为文件出现在目标文件夹中,但它是空的。

我的问题是我不知道连接的哪一方导致了这个问题。我该怎么做才能修复我的代码才能正常工作。

2 个答案:

答案 0 :(得分:1)

    Chain INPUT (policy DROP)
target     prot opt source               destination
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
ACCEPT     tcp  --  anywhere             anywhere             multiport dports 7727,http
ACCEPT     icmp --  anywhere             anywhere             icmp echo-request
ACCEPT     all  --  anywhere             anywhere

sudo iptables -L

的输出 来自sudo ufw status

输出为Status: inactive

你知道是什么解决了我的问题吗? sudo ufw enable 我仍然不知道为什么它是一个解决方案,问题是什么。但它现在有效。

答案 1 :(得分:0)

“在活动模式FTP中,客户端从随机非特权端口(N> 1023)连接到FTP服务器的命令端口,端口21.然后,客户端开始侦听端口N + 1并发送FTP命令PORT N +1到FTP服务器。然后服务器将从其本地数据端口(即端口20)连接回客户端指定的数据端口。“

看起来您必须将此39997端口添加到防火墙例外。

sudo ufw allow out 39997/tcp
sudo ufw allow in 39997/tcp
sudo ufw reload

我不确定这个捆绑包是否可以开始使用“39997”端口以外的其他端口。但看起来在这种情况下它是不变的。