Is There an Easy-To-Use Ftp Library for Ruby

Quick FTP server

The ftpd gem supports TLS, and comes with a file system driver. Like em-ftpd, you supply a driver, but that driver doesn't need to do much. Here's a bare-minimum FTP server that accepts any username/password, and serves files out of a temporary directory:

require 'ftpd'
require 'tmpdir'

class Driver

def initialize(temp_dir)
@temp_dir = temp_dir
end

def authenticate(user, password)
true
end

def file_system(user)
Ftpd::DiskFileSystem.new(@temp_dir)
end

end

Dir.mktmpdir do |temp_dir|
driver = Driver.new(temp_dir)
server = Ftpd::FtpServer.new(driver)
server.start
puts "Server listening on port #{server.bound_port}"
gets
end

NOTE: This example allows an FTP client to upload, delete, rename, etc.

To enable TLS:

include Ftpd::InsecureCertificate
...
server.certfile_path = insecure_certfile_path
server.tls = :explicit
server.start

Disclosure: I am ftpd's author and current maintainer

Ruby Net::FTP - Downloading files from a server

The error message comes from the FTP server. The problem is that the FTP server cannot interpret these unicode filenames. Please check if UTF8 feature is enabled for the connection.

From an existing answer on stackoverflow:

It is not enough for you just to encode your string as UTF8 and send it as filename to FTP server. In the past all FTP servers understood ASCII only and nowadays to maintain backward compatibility - even if they are Unicode aware - when they start they treat all filenemes as ASCII too.

To make it all work you (your program) must first check what your server is capable of. Servers send their features after client connects - in your case you must check for FEAT UTF8. If your server sends that - it means it understands UTF8. Nevertheless - even if it understands it - you must tell it explicitly that from now on you will send your filenames UTF8 encoded and now it is the stuff that your program lacks (as your server supports utf8 as you've stated).

Your client must send to FTP server the following OPTS UTF8 ON. After sending that you may use UTF8 or speak UTF8-ish (so to speak) to your sever.

Read here for details Internationalization of the File Transfer Protocol

Sources:

https://stackoverflow.com/a/19903611/1305200

https://wiki.filezilla-project.org/Character_Encoding

Why can't Net::FTP connect to server?

Your code works fine for me. I suspect problem could be because of Net::FTP connection mode, which is by default active. Try connecting using passive mode, following code sample -

ftp = Net::FTP.new(server)
ftp.passive = true
ftp.login user, password
files = ftp.chdir('mydirectory/')
files = ftp.list
puts "list out of directory:"
puts files
ftp.close

And if you're curious, following is the difference (from wikipedia) between active and passive modes.

  1. In Active mode, the client creates a TCP control connection to the server and sends the server the client's IP address and an arbitrary client port number, and then waits until the server initiates the data connection over TCP to that client IP address and client port number. In situations where the client is behind a firewall and unable to accept incoming TCP connections, passive mode may be used.
  2. In Passive mode, the client uses the control connection to send a PASV command to the server and then receives a server IP address and server port number from the server which the client then uses to open a data connection from an arbitrary client port to the server IP address and server port number received.

Is it possible to transfer the contents of a whole directory using the built in Ruby Net::FTP class?

First, get all files and subdirectories in your directory:

entries = Dir.glob('my_dir/**/*').sort

(sort is required to ensure that every directory goes before its files)

Now you can upload all files and create all subdirectories:

Net::FTP.open(ftp_server, username, password) do |ftp|
entries.each do |name|
if File::directory? name
ftp.mkdir name
else
File.open(name) { |file| ftp.putbinaryfile(file, name) }
end
end
end

I had no time to test this, so I could miss something.

How to FTP in Ruby without first saving the text file

StringIO.new provides an object that acts like an opened file. It's easy to create a method like puttextfile, by using StringIO object instead of file.

require 'net/ftp'
require 'stringio'

class Net::FTP
def puttextcontent(content, remotefile, &block)
f = StringIO.new(content)
begin
storlines("STOR " + remotefile, f, &block)
ensure
f.close
end
end
end

file_content = <<filecontent
<html>
<head><title>Hello!</title></head>
<body>Hello.</body>
</html>
filecontent

ftp = Net::FTP.new(domain)
ftp.passive = true
ftp.login(username, password)
ftp.chdir(path_on_server)
ftp.puttextcontent(file_content, path_to_web_file)
ftp.close


Related Topics



Leave a reply



Submit