I need to get the response messages from an ftp server I'm troubleshooting a connection to, so I am using PHP's ftp_raw
function, which allows me to send raw ftp commands to the remote server, and get the response string back. (The built-in PHP ftp commands don't return responses :(
Following this accepted answer, The command I'm sending is
PASV
STOR /local/path/to/file.txt
And the server response is
500 /local/path/to/file.txt: The system cannot find the path specified.
And I'm thinking to myself "Of course, the remote host has no idea of my local file system." My hunch is that I'm opening a socket, specifying a remote file name, and I still have to pipe the data through. But I haven't found anything conclusive in documentation in my searching.
What is the complete set of raw ftp commands to upload a file? At what point, and how, do I actually start sending data to the remote server? Can I use the connection set up from ftp_connect()
as the socket?
Disclaimer: The first thing you should know is that RFC959 was written a while after FTP became popular and there is still some broken software based on the lack of specification there was before (and some time after) RFC959 was published. Many older (and more stable) FTP libraries have some special handling for some servers to make sure it works the way you want 99.9% of the time. This is especially more common with handling of extensions to the FTP protocol.
The rest of my answer assumes the server is RFC959 compliant.
Also keep in mind that bypassing your FTP client library's higher-level request/response management means you'll need to re-implement a part of this library yourself. This means you should be comfortable with the specification since you'll need to refer to it. Where possible, I'll refer to the appropriate sections so that you can get around.
In an case, I strongly recommend that you debug your problems by stepping into PHP's FTP client library rather than implementing all of this yourself. It it's possible, you should really request that the library output all the commands it's using. All that being said, I will still guide you through the procedure to help diagnose your problem.
Managing the FTP data connection is somewhat of a pain. It's not as easy as it looks at first glance if you want to support all optional parts of the specification. Exactly how you transfer files mostly depends on the current state of the following options:
Pay attention to the specification because some configurations allow you to keep the data connection open while other may require you to close it (e.g. stream mode). If the data connection is already open, then you don't need to reconnect to the server on each transfer.
All this seems really complicated, but it's just informative. It might come in handy while you're debugging. There are really only two popular ways to transfer files using FTP:
The server connects to the client on a second port and sends the file in the image (binary) data type using the file data structure.
Configure the data type (required):
Configure the data structure (optional, default):
Configure the transfer mode (optional, default):
Choose an available port (this may be somewhat more subtle than you think) and start listening. If you choose the default port (20), skip the next step.
Tell the server we'll be listening on a given port (optional if default port is selected, but it doesn't hurt to be careful):
Tell the server to expect a file transfer:
Wait for incoming connection from the server.
Send the file contents
Close the data connection
The client connects to the server on a second port and sends the file in the image (binary) data type using the file data structure.
Configure the data type (required):
Configure the data structure (optional, default):
Configure the transfer mode (optional, default):
Tell the server we'll be listening on a given port (required):
Read the
PASV
command response containing IP address and port number the server is listening on.Tell the server to expect a file transfer:
Establish connection:
Send the file contents
Close the data connection
There are some inconvenient issues with the first method since choosing a port is a little tricky (after using a port, you need to wait for a short period before using it again) and your firewall or ISP may block incoming connections on some ports, etc. The second method is easiest and should be preferred unless the server rejects it.
Working solution (complete rewrite of earlier solution using PORT). The correct sequence is
Code