The error message is actually very relevant.
This is Pure-FTPd with an error in response to the PORT command when the client asks the server to open a data connection with an IP address different from the client IP address (as the server sees it). So this is a remote error message sent by the server, not a local error message generated by PHP.
The problem is usually caused by the fact that the client only knows its local IP address, and not the external IP address.
Now the question is why PHP uses PORT when you asked it to connect in passive mode ( ftp_pasv ).
This is clear because you are calling ftp_pasv before you log in.
Thus, the server rejects the PASV call with:
530 You are not logged in.
Unfortunately, PHP does not propagate error messages from a PASV call. And it silently returns to active mode by default. You can say that the call is rejected by its return value (which you do not check).
Just move the ftp_pasv call after 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 this:
Please note that ftp_pasv () can only be called after a successful login, otherwise it will fail.
And of course, you should better check for errors.
For a similar problem (only with ProFTPd) see:
PHP ftp_put return "Unable to establish a data connection: connection rejected"