<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Tyler Clemons &#187; FTP</title>
	<atom:link href="http://www.tylerclemons.com/category/programming/ftp/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.tylerclemons.com</link>
	<description>tylerclemons.com</description>
	<lastBuildDate>Thu, 27 Oct 2011 17:06:25 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>FTP fun with Ruby</title>
		<link>http://www.tylerclemons.com/ftp-fun-with-ruby/</link>
		<comments>http://www.tylerclemons.com/ftp-fun-with-ruby/#comments</comments>
		<pubDate>Sun, 15 Jun 2008 21:09:23 +0000</pubDate>
		<dc:creator>Tyler</dc:creator>
				<category><![CDATA[FTP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Class]]></category>
		<category><![CDATA[OOP]]></category>
		<category><![CDATA[Recursion]]></category>
		<category><![CDATA[WordPress themes]]></category>

		<guid isPermaLink="false">http://tylershome.nfshost.com/?p=19</guid>
		<description><![CDATA[WordPress is pretty cool, save the editor.  One of the coolest features is being able to switch the look and feel of my website without doing much extra work.
To do this, I just search Google for WordPress themes and about a dozen websites pop up with hundreds of themes.  Cool.  I download [...]]]></description>
			<content:encoded><![CDATA[<p>WordPress is pretty cool, save the editor.  One of the coolest features is being able to switch the look and feel of my website without doing much extra work.</p>
<p>To do this, I just search <a title="Google" href="http://www.google.com/search?hl=en&amp;safe=off&amp;client=firefox-a&amp;rls=org.mozilla%3Aen-US%3Aofficial&amp;hs=78J&amp;q=Wordpress+themes&amp;btnG=Search">Google</a> for WordPress themes and about a dozen websites pop up with hundreds of themes.  Cool.  I download a couple of them, all free, and look for the easiest way to deploy them.  However, the only way to do that, is to upload all of the files onto my web server via FTP.</p>
<p>No problem, FTP has multiple file commands&#8230; that don&#8217;t exactly work with directories <img src='http://tylershome.nfshost.com/home/public/wp-includes/images/smilies/icon_sad.gif' alt=':(' class='wp-smiley' />   The simple solution is to find an FTP client for MacOS X and resort to a drag and drop method.  Of course there exist some programs out there for free like <a title="CyberDuck" href="http://cyberduck.ch/" target="_blank">Cyberduck</a>, or <a href="http://filezilla-project.org/">Filezilla</a> (but I use OS 10.4 so FileZilla is out), but since it&#8217;s the summer time, I decided to make my own.  To be honest, I didn&#8217;t actually look for an FTP program before making my own lol!  I fired up <a title="Ruby" href="http://www.ruby-lang.org/en/" target="_blank">Ruby</a> for a little fun.</p>
<p><span id="more-9"></span>It is a simple enough task to create an FTP instance in Ruby and to login.  The fun part is deciding how to automate the placing of subdirectories because that feature is not supported by traditional FTP.  It can be done iteratively, but that would be a nightmare for bookkeeping.  For that method to work, you might have to employ a queue type structure that stores found directories.  Or you could just use recursion which makes things a little bit simpler.</p>
<p>For those new to the idea of recursion, read about it <a title="Recursion" href="http://en.wikipedia.org/wiki/Recursion_%28computer_science%29" target="_blank">HERE.</a> Basically, we can call a function that opens a remote FTP directory, lets call it directory A, and iterates through it&#8217;s contents.  When a directory, lets call it directory B, is found, instead of storing it away, we call the same function again on B.  After the function operates on B, the stack returns back to the caller, in this case A, and continues through the contents of A.  If any directories are found in A, B, or any subdirectories, the function just makes another recursive call.  Of course, the recursive stack only goes so far but 99.99% of the time the stack won&#8217;t need to get close to the limit.  Judging from the test I ran, Ruby 1.8.6 exhausted at a little over 6200 levels.</p>
<div id="codebox" style="overflow: auto; ">
<p><em><span style="color: #0000ff;">def</span> <span style="color: #ff00ff;">test_depth</span>(x)</em></p>
<p style="padding-left: 30px;"><em>puts x</em></p>
<p style="padding-left: 30px;"><em>test_depth(x+1)</em></p>
<p><em><span style="color: #0000ff;">end</span></em></p>
<p><em>test_depth(1)</em></p>
<p style="text-align: left;">
</div>
<p>Of course the length of the recursive stack depends on the amount of local variables declared.  I found that for every 4 local variables, and every 4 parameters passed into a function, you should expect to sacrifice 85 levels or 85 recursive calls. Of course those metrics only apply to basic data structures like integers and not complex structures like classes.</p>
<p>If you aren&#8217;t familiar with Ruby FTP, click <a title="Ruby FTP Class" href="http://www.ruby-doc.org/stdlib/libdoc/net/ftp/rdoc/classes/Net/FTP.html" target="_blank">HERE.</a> The FTP code, without error handling, some comments, and output statements, looks like:</p>
<div id="codebox" style="overflow: auto; ">
<p><em><span style="color: #0000ff;">def</span> <span style="color: #ff00ff;">send_it</span>()</em></p>
<p style="padding-left: 30px;"><em>#open local directory<br />
<span style="color: #339966;"> Dir</span>.chdir(<span style="color: #ff6600;">@current_directory</span>[0][-1])</em></p>
<p style="padding-left: 30px;"><em>#make a local copy of file list to reduce network calls<br />
remote_list = <span style="color: #ff6600;">@ftp</span>.nlst()</em></p>
<p style="padding-left: 30px;"><em><span style="color: #339966;">Dir</span>.entries(&#8221;.&#8221;).each { |thefile|</em></p>
<p style="padding-left: 60px;"><em>#be sure not to try and send the current and parent directory<br />
<span style="color: #0000ff;"> if</span> thefile != &#8220;.&#8221; <span style="color: #0000ff;">and</span> thefile != &#8220;..&#8221;</em></p>
<p style="padding-left: 60px;"><em>filename = <span style="color: #339966;">File</span>.basename(thefile)<br />
#check if this is a file<br />
<span style="color: #0000ff;"> if</span> <span style="color: #0000ff;">not</span> <span style="color: #339966;">File</span>.directory?(thefile)</em></p>
<p style="padding-left: 90px;"><em><span style="color: #ffcc00;"> <span style="color: #ff6600;">@ftp</span></span>.putbinaryfile(thefile,thefile)</em></p>
<p style="padding-left: 60px;"><em><span style="color: #0000ff;">else</span></em></p>
<p style="padding-left: 90px;"><em><span style="color: #0000ff;">if not</span> remote_list.index(filename)</em></p>
<p style="padding-left: 120px;"><em><span style="color: #ffcc00;"><span style="color: #ff6600;">@ftp</span>.</span>mkdir(filename)</em></p>
<p style="padding-left: 90px;"><em><span style="color: #0000ff;"> end</span></em></p>
<p style="padding-left: 60px;">
<p style="padding-left: 60px;"><em>#change directory and make recursive call<br />
<span style="color: #ffcc00;"> <span style="color: #ff6600;">@ftp</span></span>.chdir(filename)<br />
<span style="color: #ffcc00;"> <span style="color: #ff6600;">@current_directory</span></span>[0] &lt;&lt; filename<br />
<span style="color: #ffcc00;"> <span style="color: #ff6600;">@current_directory</span></span>[1] &lt;&lt; filename<br />
send_it()</em></p>
<p style="padding-left: 60px;"><em>#move onto next file after sending directory<br />
<span style="color: #ffcc00;"> <span style="color: #ff6600;">@ftp</span></span>.chdir(&#8221;..&#8221;)<br />
<span style="color: #ffcc00;"> <span style="color: #ff6600;">@current_directory</span></span>[1].delete_at(-1)<br />
<span style="color: #339966;"> Dir</span>.chdir(&#8221;..&#8221;)<br />
<span style="color: #ffcc00;"> <span style="color: #ff6600;">@current_directory</span></span>[0].delete_at(-1)<br />
<span style="color: #0000ff;"> end</span></em></p>
<p style="padding-left: 60px;"><em><span style="color: #0000ff;"> end</span></em></p>
<p style="padding-left: 30px;">}</p>
<p><em><span style="color: #0000ff;">end</span></em></div>
<p>That is the basics of the code for the send method.  There are some bookkeepers that were created.  The <em>@ftp</em> object holds the ftp instance and the <em>@current_directory</em> is a multi-dimensional array that stores where the ftp server directory is and where the local directory is.  There is also a temporary object that stores the remote server&#8217;s contents called <em>remote_list.</em> Storing these locally allows us to reduce the amount of remote calls to the server because network communication <strong>ALWAYS</strong> has a varying time.  One of the nice things about sending is having the ability to check if a directory exist.  Ruby FTP can&#8217;t tell you if a remote object is a directory, or if the remote directory exist, automatically, it takes a little bit of work to find out.</p>
<p>Something else to note, it is not necessary to use the bookkeepers such as <em>@current_directory</em>.  It is possible to pass the local directory and remote directory as parameters into the recursive function instead of building a list to handle the current directories.  This type of design would be best suited for a standalone function that does not use the data found in the list but the method written above is used as a class method.  The following is a simple recursive method, assuming that the @ftp instance is already created:</p>
<p><em><span style="color: #0000ff;">def</span> <span style="color: #ff00ff;">send_it</span>(remote,local)</em></p>
<p style="padding-left: 30px;"><em>#open local and remote directories<br />
<span style="color: #339966;"> Dir</span>.chdir(local)</em><br />
<em><span style="color: #ffcc00;"> <span style="color: #ff6600;">@ftp</span></span>.chdir(remote)</em></p>
<p style="padding-left: 30px;"><em>#make a local copy of file list to reduce network calls<br />
remote_list = <span style="color: #ff6600;">@ftp</span>.nlst()</em></p>
<p style="padding-left: 30px;"><em><span style="color: #339966;">Dir</span>.entries(&#8221;.&#8221;).each { |thefile|</em></p>
<p style="padding-left: 60px;"><em>#be sure not to try and send the current and parent directory<br />
<span style="color: #0000ff;"> if</span> thefile != &#8220;.&#8221; <span style="color: #0000ff;">and</span> thefile != &#8220;..&#8221;</em></p>
<p style="padding-left: 60px;"><em>filename = <span style="color: #339966;">File</span>.basename(thefile)<br />
#check if this is a file<br />
<span style="color: #0000ff;"> if</span> <span style="color: #0000ff;">not</span> <span style="color: #339966;">File</span>.directory?(thefile)</em></p>
<p style="padding-left: 90px;"><em><span style="color: #ffcc00;"> <span style="color: #ff6600;">@ftp</span></span>.putbinaryfile(thefile,thefile)</em></p>
<p style="padding-left: 60px;"><em><span style="color: #0000ff;">else</span></em></p>
<p style="padding-left: 90px;"><em><span style="color: #0000ff;">if not</span> remote_list.index(filename)</em></p>
<p style="padding-left: 120px;"><em><span style="color: #ffcc00;"><span style="color: #ff6600;">@ftp</span>.</span>mkdir(filename)</em></p>
<p style="padding-left: 90px;"><em><span style="color: #0000ff;"> end</span></em></p>
<p style="padding-left: 60px;"><em>#make recursive call<br />
send_it(filename,filename)</em></p>
<p style="padding-left: 60px;"><em>#move back up to parent directory after sending directory</em></p>
<p style="padding-left: 60px;"><em><span style="color: #ffcc00;"><span style="color: #ff6600;">@ftp</span></span>.chdir(&#8221;..&#8221;)<br />
<span style="color: #339966;"> Dir</span>.chdir(&#8221;..&#8221;)<br />
<span style="color: #0000ff;"> end</span></em></p>
<p style="padding-left: 60px;"><em><span style="color: #0000ff;"> end</span></em></p>
<p style="padding-left: 30px;">}</p>
<p><em><span style="color: #0000ff;">end</span></em></p>
<p>FTP also fails miserably in deleting remote directories.  To delete a remote directory, all of its contents must be deleted and that includes its subfolders and contents.  Downloading a directory suffers from the same issues as sending and deleting.  Using recursion, it is easy to do both methods.  The code for each method, deleting and sending, is very similar to send_it and can be found in the link at the bottom of this page.</p>
<p>Of course, what would a program be without the use of classes.  Wrapping these methods in classes allows me to run these operations over again easily and possibly build a GUI on top of it.  The current product allows me to do stuff like this:</p>
<div id="codebox" style="overflow: auto; ">
<p><em>require <span style="color: #0000ff;">&#8216;Multi_FTP&#8217;</span><br />
testme = <span style="color: #008000;">Multi_FTP</span>.new()<br />
testme.setup(&#8221;username&#8221;,&#8221;password&#8221;,&#8221;server&#8221;)<br />
testme.go_get(&#8221;/local/destination&#8221;,&#8221;/remote/goal&#8221;)<br />
testme.go_send(&#8221;/local/sendthis&#8221;,&#8221;/remote/tohere&#8221;)<br />
testme.delete_directory(&#8221;/remote/delete_test&#8221;)<br />
testme.close_ftp()</em></div>
<p>The code is pretty easy to follow.  I create a Multi-FTP class.  Then I pass in my credentials and connect to the server.  What follows is a series of send and receives and a delete command.</p>
<p>Of course it isn&#8217;t perfect.  It could use a GUI and other stuff.  Adding a method that changes permissions is pretty simple.  It would mirror the delete method, but since I didn&#8217;t need it at the time I created the class, I never wrote it.  I didn&#8217;t test all of the error handling but looks golden.  It was fun making it though <img src='http://tylershome.nfshost.com/home/public/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>I modified some of the code so that it will work on different types of FTP versions.  Some FTP servers don&#8217;t allow deleting folders, so I just delete the files in a directory and alert the user which folders could not be deleted.  I also created a function, called <em>get_files_and_directories()</em>, that addresses how to distinguish between a file and a directory on an FTP server.  This is great for checking if a directory exist on a remote server.</p>
<p>The class can be found by clicking <a title="HERE" href="http://tylershome.nfshost.com/Multi_FTP.zip" target="_blank">HERE.</a></p>
<p style="text-align: left;">
]]></content:encoded>
			<wfw:commentRss>http://www.tylerclemons.com/ftp-fun-with-ruby/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>

