FTPSSL(3)
๐ Net::FTPSSL ๐
okay bestie, sit down, we're doing FTP over TLS/SSL and we're doing it right. this is Net::FTPSSL, a Perl class for talking FTPS, and honestly? it's giving secure. ๐ฆ
โจ VERSION 0.42 โจ
(yeah that's the version, write it down, it matters)
๐ธ SYNOPSIS ๐ธ
here's the whole vibe in one code block, look at her:
use Net::FTPSSL;
my $ftps = Net::FTPSSL->new('ftp.your-secure-server.com',
Encryption => EXP_CRYPT,
Debug => 1, DebugLogFile => "myLog.txt",
Croak => 1);
$ftps->trapWarn (); # Only call if opening a CPAN bug report.
$ftps->login('anonymous', 'user@localhost');
$ftps->cwd("/pub");
$ftps->get("file");
$ftps->quit();
and here's the chef's kiss part: since I passed Croak => 1 in the options to new, it literally called die for me the second any Net::FTPSSL command flopped. so no messy error checking in my code. none. zero. not a single or die. periodt. ๐
๐ DESCRIPTION ๐
"Net::FTPSSL" is a class that implements a simple FTP client over a Transport Layer Security (TLS) or Secure Sockets Layer (SSL) connection, written in Perl, exactly as described in RFC959 and RFC2228. ๐
by default it uses TLS v1.2, because TLS is more secure than SSL โ that's just the truth, no cap. but if you really wanna downgrade, you can do that with SSL_version. (we don't recommend it but we're not your mom.) ๐
๐ง CONSTRUCTOR ๐ง
๐ new( HOST [, OPTIONS ] )
makes you a brand new Net::FTPSSL object and opens a connection to "HOST". "HOST" is the address of the FTPS server and it is a required argument, bestie, you cannot skip it. โ
OPTIONS come in hash-style, as key and value pairs. and if you're feeling fancy, you can also pass OPTIONS as a hash reference. either way works. ๐ซถ
if it can't create a new Net::FTPSSL object, it returns undef โ unless you set the Croak option, in which case it croaks instead. either way, the cause of the failure will be sitting right there in $Net::FTPSSL::ERRSTR. ๐
and now, the "OPTIONS":
Encryptionโ the connection can be implicitly encrypted (IMP_CRYPT), explicitly encrypted (EXP_CRYPT), or just regular FTP (CLR_CRYPT). with the explicit ones, the connection starts out clear and becomes encrypted once an"AUTH"command gets sent. implicit starts off encrypted from the jump. and forCLR_CRYPT, the connection never becomes encrypted, at all, ever. default value isEXP_CRYPT. ๐Portโ which port number to connect to on the remote FTPS server. default port is21forEXP_CRYPTandCLR_CRYPT. but forIMP_CRYPTthe default port is990. you only need to hand over a port if you need to override the default. ๐ชDataProtLevelโ the level of security on the data channel. default isDATA_PROT_PRIVATE, where the data is also encrypted.DATA_PROT_CLEARis for data sent as clear text (๐).DATA_PROT_SAFEandDATA_PROT_CONFIDENTIALare not currently supported. and ifCLR_CRYPTwas selected, the data channel is alwaysDATA_PROT_CLEARand cannot be overridden. sorry, that's the rule. ๐ก๏ธProxyArgsโ a hash reference to pass to the proxy server. when a proxy server shows up, this class uses Net::HTTPTunnel to get through to the server you actually need to talk to. see Net::HTTPTunnel for what values are supported. the optionsremote-hostandremote-portare hard coded to the same values as provided by HOST and PORT above and cannot be overridden. locked in. ๐PreserveTimestampโ during all puts and gets, attempt to preserve the file's timestamp. by default it will not preserve the timestamps.
set it to a value > zero if the MDTM & MFMT commands properly use GMT. set it to a value < zero if the server incorrectly uses its local time zone instead. and listen โ using the wrong value can result in really wacky modify times on your files if you pick the wrong one for your server. ๐ญ t/10-complex.t does include a test that tries to guess which one the server uses, so there's that. ๐ต๏ธ
Pretโ set this if you're talking to a distributed FTPS server like DrFtpd that needs aPRETcommand issued before every single call toPASV. you only need to use this option if the server barfs at thePRETauto-detect logic. ๐คขTraceโ turns on/off (1/0) put/get download tracing to STDERR. default is off. ๐ขDebugโ turns the debug tracing option on/off. default is off. (0,1,2) ๐DebugLogFileโ redirects the output of Debug from STDERR to the requested error log file name. this option is ignored unless Debug is also turned on โ enforced that way for backwards compatibility. if Debug is set to2, the log file gets opened in append mode instead of creating a new log file. this log file is closed when this class instance goes out of scope. ๐
instead of a file name, you may also specify an open file handle or GLOB and it will write the logs there instead. (not really recommended, just saying.) ๐
Croakโ forces most methods to callcroak()on failure instead of returning FALSE. the default is to return FALSE or undef on failure. when it croaks, it will also attempt to close the FTPS connection, preserving the last message before it tries to close โ which lets the server know the client is going away. this will cause$Net::FTPSSL::ERRSTRto be set as well. ๐ธReuseSessionโ tells the FTP/S server that we wish to reuse the command channel session for all data channel connections. (0/1/2/etc.) it defaults to0, meaning no reuse. ๐
when requested, it uses a default session cache size of 5, but you can increase the cache's size by setting ReuseSession to a larger value. the session cache size is (4 + the ReuseSession value). math! ๐งฎ
DisableContextโ tells the FTP/S server that we don't wish to reuse the command channel context for all data channel connections. (0/1) if the optionReuseSessionorSSL_Client_Certificateare also used, this option is ignored! by default the context is always reused on encrypted data channels viaSSL_reuse_ctx. ๐ซSSL_*โ SSL arguments which can be applied whenstart_SSL()is finally called to encrypt the command channel. see IO::Socket::SSL for a list of valid arguments. ๐
this is an alternative to using the SSL_Client_Certificate option. but any SSL_* options provided here override what's provided in that hash. ๐
SSL_Client_Certificateโ expects a reference to a hash. its main purpose is to let you use client certificates when talking to your FTP/S server. options here apply to the creation of the command channel. and when a data channel is needed later, it uses theSSL_reuse_ctxoption to reuse the command channel's context. ๐ซ
see start_SSL() in IO::Socket::SSL for more details on this and other options available besides the certificate ones. if an option provided via this hash conflicts with other options we'd normally use, the entries in this hash take precedence โ except for any direct SSL_* options provided in both places. ๐ฅ
Domainโ specify the domain to use, i.e.AF_INETorAF_INET6. this argument gets passed to theIO::Socket::*class when creating the socket connection. it's a way to enforce using IPv4 vs IPv6 even when it would default to the other.Familyis an accepted alias for theDomaintag if you prefer it. ๐Bufferโ this is the block size thatNet::FTPSSLwill use when a transfer is made over the Data Channel. default value is10240. it does not affect the Command Channel. ๐ฆTimeoutโ set a connection timeout value. default value is120. โฐxWaitโ used withxput&xtransfer. tells how long to wait after the upload has completed before renaming the file. the default is no wait, but if you specify a number here, it will wait that number of seconds before issuing the rename command. some servers force you to wait a bit before they'll honor theRNTOpart of the rename command. ๐คLocalAddrโ local address to use for all socket connections. this argument gets passed to allIO::Socket::INETcalls. ๐OverridePASVโ some FTPS servers sitting behind a firewall incorrectly return their local IP Address instead of their external IP Address (the one used outside the firewall where the client is). to use this option to correct that problem, you must specify the correct host to use for the data channel connection. this should usually match what you provided as the host! but if this server also does load balancing, you are out of luck. ๐ต this option may not be able to help you if multiple IP Addresses can be returned.OverrideHELPโ some FTPS servers on encrypted connections incorrectly send back part of the response to theHELPcommand in clear text instead of it all being encrypted, which breaks the command channel connection. this module callsHELPinternally viasupported()for some conditional logic, which makes a work around necessary to be able to talk to such servers. ๐ฉน
this option supports four distinct modes to support your needs:
- pass a reference to an array that lists all the FTP commands your server supports
- set it to
1to say all commands are supported - set it to
0to say none of the commands are supported - set it to
-1to callFEATinstead ofHELPfor the list of supported commands
see supported() or fix_supported() for more details.
this option can also be useful when your server doesn't support the HELP command itself and you need to trigger some of the conditional logic. ๐ง
useSSLโ this option is being deprecated in favor of IO::Socket::SSL'sSSL_versionoption. it's just a quick and dirty way to downgrade your connection from TLS to SSL, which is no longer recommended. โ ๏ธ
๐ METHODS ๐
most of the methods return true or false โ true when the operation was a success, false when it failed. methods like list or nlst return an empty array when they fail. and remember, this behavior can be modified by the Croak option. ๐
๐ login( USER, PASSWORD )
use the given information to log into the FTPS server. ๐
๐ quit()
this method breaks the connection to the FTPS server. bye bestie ๐
๐ force_epsv( [1/2] )
used to force EPSV instead of PASV when establishing a data channel. once this method is called, it is impossible to swap back to PASV. so this method should be called as soon as possible after you log in if EPSV is required. โณ
it does this by sending "EPSV ALL" to the server. afterwards the server will reject all EPTR, PORT and PASV commands. ๐ซ
after "EPSV ALL" is sent, it will attempt to verify your choice of IP Protocol to use: 1 or 2 (v4 or v6). the default is 1. it will use the selected protocol for all future EPSV calls. and if you need to change which protocol to use, you may call this function a second time to swap to the other EPSV Protocol. ๐
this method returns true if it succeeds, or false if it fails. โจ
๐ซถ set_croak( [1/0] )
okay so this one is your little after-the-fact toggle for the Croak option โ you use it when your Net::FTPSSL object is already alive and thriving and you've decided Croak is doing too much.
It returns the previous Croak setting, like, the one that was in place before the change you just made. And if you don't hand it an argument at all? It just sits there and returns the current setting. No drama, no change. ๐
It exists purely for the case where the Croak option turns out to be too restrictive in some situations. Been there bestie.
๐ list( [DIRECTORY [, PATTERN]] )
returns you a list of files, in a format kind of like this โ and heads up, it's Server Specific:
drwxrwx--- 1 owner group 512 May 31 11:16 .
drwxrwx--- 1 owner group 512 May 31 11:16 ..
-rwxrwx--- 1 owner group 512 Oct 27 2004 foo
-rwxrwx--- 1 owner group 512 Oct 27 2004 pub
drwxrwx--- 1 owner group 512 Mar 29 12:09 bar
If you omit DIRECTORY, it just gives you the list of the current directory. easy.
If you pass a PATTERN, it narrows the results down the same way the unix ls command or the Windows dir command would. The only wild cards it supports are * and ? โ that's match 0 or more chars, or any one char. So a pattern of f*, ?Oo or FOO would find just foo out of that list above. โ ๏ธ But files with spaces in their name can cause strange results when you're searching with a pattern. so, yk, watch out.
๐ฆ nlst( [DIRECTORY [, PATTERN]] )
same as list but it returns the list in this format instead:
foo
pub
bar
Spaces in the filename do not cause problems with the PATTERN when you use nlst. ๐
And ngl, the author of this module says personally they suggest using nlst instead of list. so like, take the hint bestie.
โจ mlsd( [DIRECTORY [, PATTERN [, FTYPE]]] )
returns a list of files/directories in a standardized machine readable format designed for easy parsing. The list of features about each file/directory is defined by your FTPS server and may be modifiable by you. cute, customizable, we love that.
modify=20041027194930;type=file;size=28194; foo
modify=20041027194932;type=file;size=3201931; pub
modify=20180329120944;type=dir;size=256; bar
Spaces in the filename don't cause problems with the PATTERN with mlsd either. ๐ซถ
If FTYPE is provided, it does additional filtering based on the type of file. heads up though โ if the type attribute isn't returned, and FTYPE is non-zero, it will filter out everything! not one single file. sobbing.
0โ All file types. (default)1โ Regular Directories only.2โ Regular Files only.3โ Special Files only.4โ Special Directories only.
๐ mlst( FILE )
asks the FTPS server to return the feature set for the requested FILE. Where FILE may be any type of file or directory exactly matching the given name. exact match only, no guessing.
If the requested file/directory doesn't exist, it will return undef or croak. If it does exist, it returns the features about the file the same way mlsd does โ except the returned filename may contain path info, where dir is the current directory name.
For example, if we were looking for file pub again:
modify=20041027194932;type=file;size=3201931; /dir/pub
๐ธ parse_mlsx( VALUE [, LOWER_CASE_FLAG] )
takes the VALUE returned by mlst, or one of the array values from mlsd, and converts it into a hash. Where the key ;file; is the filename, and literally anything else was a feature describing the file.
It returns a hash reference containing the data. If the LINE isn't in the proper format, it returns undef. The only key that's guaranteed to exist in the hash after a successful parse is ;file;. Every other key/feature returned depends entirely on how your FTPS server has been configured. server-specific vibes.
For example:
Type=File;Size=3201931; Pub
would return (Type=>File, Size=>3201931, ;file;=>Pub)
But if LOWER_CASE_FLAG was set to a non-zero value, it would then convert everything except the file's name into lower case. so:
Type=File;Size=3201931; Pub
would return (type=>file, size=>3201931, ;file;=>Pub)
see how Pub stayed pretty and capitalized? yeah. that's the point. ๐
๐ ascii()
sets the file transfer mode to ASCII. CR LF transformations will be done. And fun fact โ ASCII is the default transfer mode. so if you do nothing at all, congrats, you're already here.
๐ binary()
sets the file transfer mode to binary. No CR LF transformation will be done. raw. untouched. unbothered. โจ
๐ mixedModeAI()
a mixture of ASCII & binary mode. The server does CR LF transformations while the client side does not. (For a really weird server.)
๐ mixedModeIA()
a mixture of binary & ASCII mode. The client does CR LF transformations while the server side does not. (Also for a really weird server.)
๐ฅ put( LOCAL_FILE [, REMOTE_FILE [, OFFSET]] )
stores the LOCAL_FILE onto the remote ftps server. LOCAL_FILE may be an open IO::Handle or GLOB, but in that case REMOTE_FILE is required. It returns undef if put() fails.
If you provide an OFFSET, this method assumes you're trying to continue an upload that was aborted earlier. And it is your responsibility to verify that it's the same file on the server you tried to upload earlier. no pressure or anything.
By providing the OFFSET, this function will send a REST command to the FTPS Server to skip over that many bytes before it starts writing to the file. This method will also skip over the requested OFFSET after opening the LOCAL_FILE for reading โ but if you passed it a file handle, it will assume you've already positioned it correctly. trust.
If you provide an OFFSET of -1, this method will calculate the offset for you by issuing a SIZE command against the file on the FTPS server. So REMOTE_FILE must already exist to use -1, or it's an error. It is also an error to make OFFSET larger than the REMOTE_FILE.
careful bestie: if the OFFSET you provide turns out to be smaller than the current size ofREMOVE_FILE, the server will truncate theREMOTE_FILEto that size before appending to the end ofREMOTE_FILE. (This may not be consistent across all FTPS Servers, so don't depend on this feature without testing it first.)
If the option PreserveTimestamp was used, and the FTPS server supports it, it will attempt to reset the timestamp on REMOTE_FILE to the timestamp on LOCAL_FILE. ๐
๐ง append( LOCAL_FILE [, REMOTE_FILE [, OFFSET]] )
appends the LOCAL_FILE onto the REMOTE_FILE on the ftps server. If REMOTE_FILE doesn't exist, the file will be created. LOCAL_FILE may be an open IO::Handle or GLOB, but in this case REMOTE_FILE is required and OFFSET is ignored. It returns undef if append() fails.
If you provide an OFFSET, it will skip over that number of bytes in the LOCAL_FILE โ except when it was a file handle โ but it will not send a REST command to the server. It will just append to the end of REMOTE_FILE on the server. You can also provide an OFFSET of -1 with the same limitations as with put(). If you need the REST command sent to the FTPS server, use put() instead. periodt.
If the option PreserveTimestamp was used, and the FTPS server supports it, it will attempt to reset the timestamp on REMOTE_FILE to the timestamp on LOCAL_FILE. ๐
๐ uput( LOCAL_FILE, [REMOTE_FILE] )
stores the LOCAL_FILE onto the remote FTPS server. LOCAL_FILE may be an open IO::Handle or GLOB, but in this case REMOTE_FILE is required. Do not put any path info in REMOTE_FILE! Its default is LOCAL_FILE.
This command can be implemented differently on different FTPS servers, which is the whole chaotic thing about it. On some servers it ignores REMOTE_FILE and just assigns it a unique name. On other servers it uses REMOTE_FILE as a starting point. In either case, sometimes it returns the final file name used โ and on other servers it keeps it a secret. ๐
So if your FTPS server honors the REMOTE_FILE, it may use that name on the upload if it doesn't already exist. But if it already exists, then it will generate a unique name instead.
If the file transfer succeeds, this function will try to return the actual name used on the remote FTPS server. If the server accepts the REMOTE_FILE hint and doesn't return the filename, it will assume REMOTE_FILE. If it doesn't accept REMOTE_FILE and doesn't return the name used, we'll return a single '?' instead. In this case the request worked, but this command has no way to figure out what name was generated on the remote FTPS server โ and we know REMOTE_FILE is wrong! So we want to return a printable value that will evaluate to true for success but still tell you the actual name used is unknown! it's giving honesty. ๐
Just be aware that spaces in the filename used on the FTPS server could mean an incomplete filename is returned by this method.
If the option PreserveTimestamp was used, and the FTPS server supports it, it will attempt to reset the timestamp on the remote file โ using the file name being returned by this function โ to the timestamp on LOCAL_FILE. So if the wrong name is being returned, the wrong file could get its timestamp updated. yeah. yikes. ๐ญ
๐ uput2( LOCAL_FILE, [REMOTE_FILE] )
a much, much slower version of uput. Only useful when regular uput can't determine the actual filename used for the upload to your FTPS server, or it returns the wrong answer for that server. And you really, really need the right filename!
It gets the right answer by calling nlst, uput, and then nlst again. And as long as there is only one new file returned in the 2nd nlst call, we have the actual filename used on the FTPS server. So having spaces in this filename causes no issues at all. ๐
This function assumes you are uploading to the FTPS server's current directory, since the uput command doesn't always honor REMOTE_FILE on all servers.
It returns undef if the upload fails. It returns '?' if it still can't figure out what the FTPS server called the file after the upload (very rare and unusual). Otherwise, it's the name of the file on the FTPS server. ๐ฆ
๐ xput( LOCAL_FILE, [REMOTE_FILE, [PREFIX, [POSTFIX, [BODY]]]] )
use this when the directory you're dropping REMOTE_FILE into is monitored by a file recognizer that might pick the file up before the file transfer has completed. like, imagine being grabbed mid-glow-up. embarrassing.
So the file is transferred using a temporary name, using a naming convention that the file recognizer will ignore and that is guaranteed to be unique. Once the file transfer successfully completes, it will be renamed to REMOTE_FILE for immediate pickup by the file recognizer. iconic behavior honestly.
If you requested to preserve the file's timestamp, this step is done after the file is renamed, and so it can't be 100% guaranteed if the file recognizer picks it up first. Since if it was done before the rename, other more serious problems could crop up if the resulting timestamp was old enough. so like, it's a trade-off, bestie.
On failure this function will attempt to delete the scratch file for you if it's at all possible. ๐ซถ And if the defaults just aren't it for your setup? Go talk to your FTPS server administrator about good values for PREFIX and POSTFIX, bestie.
PREFIXโ defaults to_tmp.unless you override it. Set to""if you need to suppress the PREFIX. This PREFIX can be a path to another directory if needed, but that directory must already exist! Set toundefto keep this default and you need to change the default for POSTFIX or BODY.POSTFIXโ defaults to.tmpunless you override it. Set to""if you need to suppress the POSTFIX. Set toundefto keep this default and you need to change the default for BODY.BODYโ defaults toclient-name.PIDso that you are guaranteed the temp file will have an unique name on the remote server. It is strongly recommended that you don't override this value.
So the temp scratch file would be called something like this by default: _tmp.testclient.51243.tmp. ๐
As a final note, if REMOTE_FILE has path information in it's name, the temp scratch file will have the same directory added to it unless you override the PREFIX with a different directory to drop the scratch file into. This avoids forcing you to change into the requested directory first when you have multiple files to send out into multiple directories. Lowkey genius, honestly. ๐ง
get( REMOTE_FILE [, LOCAL_FILE [, OFFSET]] )
Retrieves the REMOTE_FILE from the ftps server. LOCAL_FILE may be a filename or a open IO::Handle or GLOB. It returns undef if get() fails. You don't usually need to use OFFSET. ๐
If you provide an OFFSET, this method assumes your are attempting to continue with a download that was aborted earlier. And it's your responsibility to verify that it's the same file you tried to download earlier. By providing the OFFSET, it will send a REST command to the FTPS Server to skip over that many bytes before it starts downloading the file again. If you provide an OFFSET of -1, this method will calculate the offset for you based on the size of LOCAL_FILE using the current transfer mode. (ASCII or BINARY). It is an error to set it to -1 if the LOCAL_FILE is a file handle.
On the client side of the download, the OFFSET will do the following: Open the file and truncate everything after the given OFFSET. So if you give an OFFSET that is too big, it's an error. If it's too small, the file will be truncated to that OFFSET before appending what's being downloaded. If the LOCAL_FILE is a file handle, it will assume the file handle has already been positioned to the proper OFFEST and it will not perform a truncate. Instead it will just append to that file handle's current location. Just beware that using huge OFFSETs in ASCII mode can be a bit slow if the LOCAL_FILE needs to be truncated. ๐ญ
If the option PreserveTimestamp was used, and the FTPS Server supports it, it will attempt to reset the timestamp on LOCAL_FILE to the timestamp on REMOTE_FILE after the download completes. โจ
xget( REMOTE_FILE, [LOCAL_FILE, [PREFIX, [POSTFIX, [BODY]]]] )
The inverse of xput, where the file recognizer is on the client side. The only other difference being what BODY defaults to. It defaults to reverse(testclient).PID. So your default scratch file would be something like: _tmp.tneilctset.51243.tmp. ๐ฆ
Just be aware that in this case LOCAL_FILE can no longer be a open IO::Handle or glob. ๐
transfer( dest_server, REMOTE_FILE [, DEST_FILE [, OFFSET]] )
Retrieves the REMOTE_FILE from the current ftps server and uploads it to the dest_server as DEST_FILE without making any copy of the file on your local file system. If DEST_FILE isn't provided, it uses REMOTE_FILE on the dest_server. ๐ฅ
It assumes that dest_server is an Net::FTPSSL object and you have already successfully logged onto dest_server and set both ends to either binary or ascii mode! So this function skips over the CR/LF logic and lets the other servers handle it. You must also set the Croak option to the same value on both ends.
Finally, if logging is turned on, the logs to this function will be split between the logs on each system. So the logs may be a bit of a pain to follow since you'd need to look in two places for each half. ๐
xtransfer( dest_server, REMOTE_FILE, [DEST_FILE, [PREFIX, [POSTFIX, [BODY]]]] )
Same as transfer, but it uses a temporary filename on the dest_server during the transfer. And then renames it to DEST_FILE afterwards. ๐
See xput for the meaning of the remaining parameters.
delete( REMOTE_FILE )
Deletes the indicated REMOTE_FILE. poof, gone, no cap. ๐
cwd( DIR )
Attempts to change directory to the directory given in DIR on the remote server.
pwd( )
Returns the full pathname of the current directory on the remote server. iconic.
cdup( )
Changes directory to the parent of the current directory on the remote server.
mkdir( DIR )
Creates the indicated directory DIR on the remote server. No recursion at the moment. ๐
rmdir( DIR )
Removes the empty indicated directory DIR on the remote server. No recursion at the moment.
noop( )
It requires no action other than the server send an OK reply. literally the chillest call in the whole module. ๐
rename( OLD, NEW )
Allows you to rename the file on the remote server.
site( ARGS )
Send a SITE command to the remote server and wait for a response.
mfmt( time_str, remote_file ) or _mfmt( timestamp, remote_file [, local_flag] )
Both are boolean functions that attempt to reset the remote file's timestamp on the FTPS server and returns true on success. The 1st version can call croak on failure if Croak is turned on, while the 2nd version will not do this. The other difference between these two functions is the format of the file's timestamp to use.
time_str expects the timestamp to be GMT time in format YYYYMMDDHHMMSS. While timestamp expects to be in the same format as returned by localtime() and converts it to the YYYYMMDDHHMMSS format for you in GMT time.
But some servers incorectly use local time instead of GMT. So the local_flag option was added to tell it to use local time instead of GMT time when converting the timestamp into a string. When used internally by this module, this functionality is controlled by PreserveTimestamp instead. ๐
mdtm( remote_file ) or _mdtm( remote_file [, local_flag] )
The 1st version returns the file's timestamp as a string in YYYYMMDDHHMMSS format using GMT time, it will return undef or call croak on failure. (Some servers incorrectly use local time instead.) ๐ญ
The 2nd version returns the file's timestamp in the same format as returned by gmtime() and will never call croak. But some servers incorectly use local time instead of GMT. So the local_flag option was added to tell it to use local time instead of GMT time for this conversion. When used internally by this module, this functionality is controlled by PreserveTimestamp instead.
size( remote_file )
This function will return undef or croak on failure. Otherwise it will return the file's size in bytes, which may also be zero bytes! Just be aware for text files that the size returned may not match the file's actual size after the file has been downloaded to your system in ASCII mode. This is an OS specific issue. It will always match if you are using BINARY mode. ๐
Also SIZE may return a different size for ASCII & BINARY modes. This issue depends on what OS the FTPS server is running under. Should they be different, the ASCII size will be the BINARY size plus the number of lines in the file. ๐ตโ๐ซ
Finally if the file isn't a regular file, it may in some cases return undef. Depending on which FTP command was available to calculate the file's size with.
dir( [DIRECTORY [, PATTERN]] )
This is an alias to list. Returns an array of filenames in the long detailed format.
ls( [DIRECTORY [, PATTERN]] )
This is an alias to nlst. Returns an array of filenames in name only format.
last_message() or message()
Use either one to collect the last response from the FTPS server. This is the same response printed to STDERR when Debug is turned on. It may also contain any fatal error message encountered.
If you couldn't create a Net::FTPSSL object, you should get your error message from $Net::FTPSSL::ERRSTR instead. Be careful since $Net::FTPSSL::ERRSTR is shared between instances of Net::FTPSSL, while message & last_message are not shared between instances! ๐
last_status_code( )
Returns the one digit status code associated with the last response from the FTPS server. The status is the first digit from the full 3 digit response code.
The possible values are exposed via the following 7 constants: CMD_INFO, CMD_OK, CMD_MORE, CMD_REJECT, CMD_ERROR, CMD_PROTECT and CMD_PENDING. ๐
quot( CMD [,ARGS] )
Send a command, that Net::FTPSSL does not directly support, to the remote server and wait for a response. You are responsible for parsing anything you need from message() yourself.
Returns the most significant digit of the response code. So it will ignore the Croak request.
WARNING This call should only be used on commands that do not require data connections. Misuse of this method can hang the connection if the internal list of FTP commands using a data channel is incomplete. ๐
ccc( [ DataProtLevel ] )
Sends the clear command channel request to the FTPS server. If you provide the DataProtLevel, it will change it from the current data protection level to this one before it sends the CCC command. After the CCC command, the data channel protection level cannot be changed again and will always remain at this setting. Once you execute the CCC request, you will have to create a new Net::FTPSSL object to secure the command channel again. Due to security concerns it is recommended that you do not use this method. ๐
โโ๏ธ
supported( CMD [, SUB_CMD] )
Returns TRUE if the remote server supports the given command. CMD must match exactly. This function will ignore the Croak request.
If the CMD is SITE, FEAT or OPTS and SUB_CMD is supplied, it will also check if the specified SUB_CMD sub-command is supported by that command. Not all servers will support the use of SUB_CMD. ๐ฆ
It determines if a command is supported by calling HELP and then parses the results for a match. And if FEAT is supported, it calls FEAT too and adds those commands to the HELP list. โจ The results are cached, so HELP and FEAT only ever get called once. Efficiency, we love to see it.
๐จ okay warning time bestie โ some rare servers sendHELPresults partially encrypted and partially in clear text, and that breaks the encrypted channel. Like, the channel just dies. In that case you will need to override this method for things to work correctly with these non-conforming servers. See theOverrideHELPoption in the constructor for how to do this.
And plot twist: some servers don't support the HELP command itself! ๐ When that happens, this method will always return FALSE unless you set the OverrideHELP option in the constructor.
This command assumes that the FTP/S server is configured correctly. But โ and I need you to hear me on this โ I've run into some servers where HELP says a command is present when it's really unknown. So I'm assuming the reverse may be true sometimes as well. So when you hit this issue, use OverrideHELP or fix_supported to work around this problem. ๐ ๏ธ
This method is used internally for conditional logic, such as when checking if ALLO is supported during any file upload requests. In all, there are about a dozen different commands checked internally in various situations.
๐ all_supported( CMD1 [, CMD2 [, CMD3 [, CMD4 [, ...]]]] )
Similar to supported, except it tests everything in this list of one or more FTP commands you pass to it to see if they're supported. ๐
If the list is empty, or if even one command in the list isn't supported, it returns FALSE. Otherwise it returns TRUE. It will also ignore the Croak request. ๐
๐ fix_supported( MODE, CMD1 [, CMD2 [, CMD3 [, CMD4 [, ...]]]] )
Sometimes the FTPS server lies to us about what commands are supported. Rude!! ๐ญ This function gives you a way to push supported-command updates.
This method is a NOOP if OverrideHELP => 1 was used. Any other OverrideHELP option will cause HELP to be ignored if it's one of the commands.
- If
MODEis true, it adds these commands to the list of supported commands. - If
MODEis false, it removes these commands as being supported.
Returns the number of FTP commands added/removed from support! ๐ข
๐ฆ feat()
Asks the server for a list of features supported by this server. It returns the list of commands as keys to a hash reference whose value (behavior) is usually the empty string. But if a command returns more details about the command, the command's value in the hash will be those details (aka behavior).
Ex: MLST size*;create;modify*;perm;media-type, where MLST would be the hash key & the rest of the line describes that command's behavior.
While the OPTS command is never returned by a FEAT call to the server, it will be automatically added to this hash if any command listed has a behavior string after it. Since OPTS only has meaning if at least one command has a behavior string defined. And many servers only implement the OPTS command if there is a behavior that can be modified. So in this case OPTS will point to a hash of commands the OPTS command can modify! โจ
So if the OPTS command appears in the hash, then each call to feat will result in a server hit. Otherwise the result is cached. This is because calls to OPTS could modify the behaviour of FEAT.
If OverrideHELP was used, HELP will be removed from the FEAT hash returned, since you stated this server doesn't support the HELP command.
Should the FEAT command fail for any reason, the returned hash reference will be empty or Croak will be called. ๐
๐ซถ restart( OFFSET )
Set the byte offset at which to begin the next data transfer. Net::FTPSSL simply records this value and uses it during the next data transfer. For this reason this method will never return an error, but setting it may cause subsequent data transfers to fail. ๐ฌ
I recommend using the OFFSET directly in get(), put(), append() and transfer() instead of using this method. It was only added to make Net::FTPSSL compatible with Net::FTP. A non-zero offset in those methods will override what you provide here. If you call any of the other get()/put() variants after calling this function, you will get an error.
It is OK to use an OFFSET of -1 here to have Net::FTPSSL calculate the correct OFFSET for you before it gets used. Just like if you had provided it directly to the get(), put(), append() and transfer() calls. ๐งฎ
This OFFSET will be automatically zeroed out after the 1st time it is used.
๐ธ is_file( FILE )
Returns true if the passed FILE name is recognized as a regular file on the remote FTPS server. Otherwise it returns false.
If the MLST command is supported with the TYPE feature turned on, we can get a definitive answer. ๐ Otherwise it's assumed a regular file if the size function works! (IE. returns a size >= 0 Bytes.)
๐ง is_dir( DIRECTORY )
Returns true if the passed DIRECTORY name is recognized as a directory on the remote FTPS server. It returns false if it can't prove it or it's not a directory.
If the MLST command is supported with the TYPE feature turned on, we can get a definitive answer. Otherwise it's assumed a directory if you can cwd into it.
๐ญ But if it's using this backup method and your login doesn't have permission to cwd into that directory, this function will not recognize it as a directory, even if it really is one!
๐
set_callback( [cb_func_ref, end_cb_func_ref [, cb_data_ref]] )
This function allows the user to define a callback function to use whenever a data channel to the server is open. If either cb_func_ref or end_cb_func_ref is undefined, it disables the callback functionality, since both are required for call backs to function properly.
The cb_func_ref is a reference to a function to handle processing the data channel data. This is a void function that can be called multiple times. It is called each time a chunk of data is read from or written to the data channel.
The end_cb_func_ref is a reference to a function to handle closing the callback for this data channel connection. This function is allowed to return a string of additional data to process before the data channel is closed. It is called only once per command after processing all the data channel data.
The cb_data_ref is an optional reference to an array or hash that the caller can use to store values between calls to the callback function and the end callback function. If you don't need such a work area, it's safe to not provide one. The Net::FTPSSL class doesn't look at this reference. ๐
The callback function must take the following 5 arguments:
B<callback> (ftps_func_name, data_ref, data_len_ref, total_len, cb_data_ref);
The ftps_func_name will tell what Net::FTPSSL function requested the callback, so that your callback function can determine what the data is for and do conditional logic accordingly. We don't provide a reference to the Net::FTPSSL object itself since the class is not recursive. Each Net::FTPSSL object should have it's own cb_dat_ref to work with. But methods within the class can share one.
Since we pass the data going through the data channel as a reference, you are allowed to modify the data. But if you do, be sure to update data_len_ref to the new data length as well if it changes. Otherwise you will get buggy responses. Just be aware that if you change the length, more than likely you'll be unable to reliably restart an upload or download via restart() or using OFFSET in the put & get commands.
Finally, the total_len is how many bytes have already been processed. It does not include the data passed for the current callback call. So it will always be zero the first time it's called.
Once we finish processing data for the data channel, a different callback function will be called to tell you that the data channel is closing. That will be your last chance to affect what is going over the data channel and to do any needed post processing. The end callback function must take the following arguments:
$end = B<end_callback> (ftps_func_name, total_len, cb_data_ref);
These arguments have the same meaning as for the callback function, except that this function allows you to optionally provide additional data to/from the data channel. If reading from the data channel, it will treat the return value as the last data returned before it was closed. Otherwise it will be written to the data channel before it is closed. Please return undef if there is nothing extra for the Net::FTPSSL command to process.
๐งผ You should also take care to clean up the contents ofcb_data_refin theend_callbackfunction. Otherwise the next callback sequence that uses this work area may behave strangely.
As a final note, should the data channel be empty, it is very likely that just the end_callback function will be called without any calls to the callback function. โจ
๐ get_log_filehandle()
Returns the open file handle for the file specified by the DebugLogFile option specified by new(). If you did not use this option, it will return undef.
โ ๏ธ Just be aware that once this object goes out of scope, the returned file handle becomes invalid.
๐ set_dc_from_hash( HASH )
This function provides you a way to micro manage the SSL characteristics of the FTPS Data Channel without having to hack the Net::FTPSSL code base. It should be called as soon as possible after the call to new().
It takes a HASH as it's argument. Either by value or by address. This hash of key/value pairs will be used to control the Data Channel SSL options.
- If the key's value is set to
undef, it is an instruction to delete an existing Data Channel option. - If the key has a value, it is an instruction to add this key/value pair to the Data Channel options. If the option already exists, it will override that value.
It returns the number of entries updated for the Data Channel. ๐ข
โญ copy_cc_to_dc( FORCE, ARRAY )
This function provides you a way to copy some of the SSL options used to manage the Command Channel over to the Data Channel as well, without having to hack the Net::FTPSSL code base. It should be called as soon as possible after the call to new(). ๐ซถ
It takes an ARRAY as its arguments, bestie. Either by value or by address, your call. โจ
Then it goes through every value in that array and looks it up in the Command Channel's SSL characteristics, and copies it over to use as a Data Channel option. Like a little glow-up transplant. ๐
- If the option doesn't exist for the Command Channel, that array entry just gets ignored. No drama, no error, it's giving "we move on". ๐
- If the option is already set in the Data Channel, the array entry overrides whatever value the Data Channel currently has. New value, who dis.
- It returns the number of entries updated for the Data Channel. Count them, queen. ๐
trapWarn()
This method is only active if Debug is turned on and DebugLogFile is provided as well. Otherwise calling it literally does nothing. Which is fine. It's fine. ๐ญ
This trap for warnings automatically turns itself off when the instance of this class goes out of scope. It returns 1 if the trap was turned on, otherwise 0 if it wasn't.
Calling this method makes all Perl warnings get written to the log file you specified when you called new(). The warnings show up in the log file at the moment they occur, to help with debugging this module. It automatically sticks the word WARNING: in front of the message being logged. Iconic behaviour, honestly.
So this method is only really useful if you want to open a CPAN ticket to report a problem with Net::FTPSSL and you think having the generated warning show up in the logs will help get your issue resolved. Teamwork makes the dream work. ๐ซถ
You may call this method for multiple Net::FTPSSL instances and it will cause the warning to be written to multiple log files. The more the merrier.
And if your program already traps warnings before you call this method, this code will forward the warning to your trap logic as well. Sharing is caring.
โจ INTERPRETING THE LOGS โจ
The logs generated by Net::FTPSSL are very easy to interpret, ngl. Once you get past the initial configuration info you need for opening a CPAN ticket, it's basically just the FTPS traffic going back and forth between your perl Client and the FTPS Server you're talking to. That's the whole vibe. ๐ธ
Every single line starts with a prefix that tells you what's happening:
">>>"โ represents outbound traffic sent to the FTPS Server. ๐ค"<<<"โ represents inbound traffic received from the FTPS Server. ๐ฅ"<<+"โ represents messages from Net::FTPSSL itself in response to a request that doesn't hit the FTPS Server."WARNING:"โ represents a trapped perl warning written to the logs. โ ๏ธ"SKT >>>"&"SKT <<<"โ represent socket traffic before the Net::FTPSSL object gets created. Baby's first bytes. ๐ฃ
There are a couple of other rare variants on the above theme, but they're purely information only. So yeah, this is basically it. That's the whole decoder ring. ๐
๐ AUTHORS ๐
- Marco Dalla Stella โ
<kral at paranoici dot org> - Curtis Leach โ
<cleach at cpan dot org>โ As of v0.05
๐ฆ SEE ALSO ๐ฆ
- Net::Cmd
- Net::FTP
- Net::SSLeay::Handle
- IO::Socket::SSL
- RFC 959 โ <http://www.rfc-editor.org/info/rfc959>
- RFC 2228 โ <http://www.rfc-editor.org/info/rfc2228>
- RFC 2246 โ <http://www.rfc-editor.org/info/rfc2246>
- RFC 4217 โ <http://www.rfc-editor.org/info/rfc4217>
๐ CREDITS ๐
Graham Barr <gbarr at pobox dot com> โ for have written such a great collection of modules (libnet). Absolute legend, no notes. ๐
๐จ BUGS ๐จ
Please report any bugs with a FTPS log file created via options Debug=>1 and DebugLogFile=>"file.txt" along with your sample code at <https://metacpan.org/pod/Net::FTPSSL>.
Patches are appreciated when a log file and sample code are also provided. (Log + sample code = the magic combo. Don't skip it, bestie. ๐)
๐ COPYRIGHT ๐
Copyright (c) 2009 - 2019 Curtis Leach. All rights reserved.
Copyright (c) 2005 Marco Dalla Stella. All rights reserved.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
And that's a wrap on the whole page, fr fr. ๐ This was perl v5.42.0, dated 2025-07-25, for FTPSSL(3) โ go forth and encrypt your file transfers, you absolute main character. ๐
โจ
๐ฆ where this page comes from
- fedora 43: perl-Net-FTPSSL 0.42-19.fc43 ยท GPL-1.0-or-later OR Artistic-1.0-Perl
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms