Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP upload via FTP - ftp_put() I won't open a connection to x.x.x.x (only to y.y.y.y)

Tags:

php

ftp

I'm trying to use one host to upload content to another via FTP.

The "I won't open a connection to 172.xxx.xxx.xxx (only to 54.xxx.xxx.xxx)" is not even relevant because I am not connecting to that host. That's the IP address to the server that is hosting the script. But not to the server that is being accessed via FTP.

$conn_id = ftp_connect('50.xxx.xxx.xxx');
ftp_pasv($conn_id, true);

$login_result = ftp_login($conn_id, 'user', 'pass');

$file = "http://example.com/filelocation.swf";

if (ftp_put($conn_id, "test.swf", $file, FTP_BINARY)) {
    echo 'File Uploaded'; 
} 
else {
    echo 'Problem with uploading'; 
}

ftp_put() I won't open a connection to 172.xxx.xxx.xxx (only to 54.xxx.xxx.xxx)

The IP addresses within this error, does not go to the server I am trying to connect to. The ftp_login connects and no issues. ( I don't even want it to make a connection to those IP addresses anyways, so why does it even think that?)

I can use ftp_mkdir to add a directory on the server. However, when I use ftp_put, it throws that error.

like image 605
tmarois Avatar asked Aug 04 '15 21:08

tmarois


1 Answers

The error message is actually very relevant.

It's Pure-FTPd error response to PORT command, when the client is asking the server to open a data connection to an IP address different to that of the client (as the server sees it). So it's a remote error message sent by the server, not a local error message produced by PHP.

The problem is typically caused by the client knowing only its local IP address, not the external IP address.


Now, the question is why PHP uses PORT, when you asked it to connect using passive mode (ftp_pasv).

It's clearly because you call ftp_pasv before even logging in.

So the server rejects the PASV call with:

530 You aren't logged in

Unfortunately the PHP does not propagate error messages from PASV call. And it silently falls back to the default active mode. You can tell the call failed by its return value (that you do not check).


Just move the ftp_pasv call after the ftp_login.

$conn_id = ftp_connect('50.xx.xx.xx');

ftp_login($conn_id, 'user', 'pass');

ftp_pasv($conn_id, true);

The documentation clearly suggests it:

Please note that ftp_pasv() can only be called after a successful login or otherwise it will fail.


And of course, you should do a better error checking.


For a similar issue (just with ProFTPd), see:
PHP ftp_put returning "Unable to build data connection: Connection refused"

like image 145
Martin Prikryl Avatar answered Oct 08 '22 01:10

Martin Prikryl