user2842799 user2842799 - 5 months ago 23
PHP Question

PHP Warning: ftp_get(): Could not open data connection to port 39997: Connection timed out

I hope i will explain my problem clearly because i feel lost and don't know what is real problem.
Using Symfony 2.8 and https://github.com/iJanki/FtpBundle i'm trying to connect to ftp server and download files. Whole proccess will be launched only through symfony's app/console.

Here's my service which contain whole logic:

<?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;
}
}


Commented out or removed code includes Doctrine operations and are not relevant as they don't cause any problems.

As local enviroment I use Xampp with Apache2 server on Windows 7. Also i test FTP connection with Filezilla and i discovered that it works only when using ftp active mode.
Also I discovered that my Windows firewall was reason for warnings and I could connect but do nothing more when it was enabled. So I added exceptions for php.exe and apache httpd.exe so everything works perfectly when php script is launched on my local server.
With Windows firewall enabled, ftp_nlist returned false when using passive mode, and returned warnings when using active mode.

But my goal is to launch that script on production web server which is on VPS which has Ubuntu 14.04.3 LTS installed. My knowledge about Unix is very poor but I was assured by VPS provider that there's no firewall enabled on this server but i get all the time warnings:
PHP Warning: ftp_get(): Could not open data connection to port 39997: Connection timed out
Same warnings that i got when my windows firewall was enabled.
I also called person who's administrating server with FTP (with files i want to dl) and asked him to add exceptions in firewall for ftp connection on port 21 but it didn't help at all.

I'm sure i don't get dicsonnected from ftp server, i never get FtpException. As I can see, download proccess starts because file appears in destination folder but it's empty.

And my problem is that i don't know which side of connection is causing this issues. And what can i do to fix my code to work properly.

Answer
    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

that is output from sudo iptables -L

output from sudo ufw status was Status: inactive

You know what fixed my problem? sudo ufw enable I still dont know why it's a fix and what was the problem. But it works now.