<?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>dougv.com « Doug Vanderweide &#187; file system</title>
	<atom:link href="http://www.dougv.com/tag/file-system/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.dougv.com</link>
	<description>ASP.NET, PHP, XML, JavaScript, Web geekery, Entrepreneurship</description>
	<lastBuildDate>Thu, 17 May 2012 22:33:05 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Recursively Listing Files In A Directory And Adding Their Names To A Text File In Visual Basic .NET</title>
		<link>https://www.dougv.com/2008/07/23/recursively-listing-files-in-a-directory-and-adding-their-names-to-a-text-file-in-visual-basic-net/</link>
		<comments>https://www.dougv.com/2008/07/23/recursively-listing-files-in-a-directory-and-adding-their-names-to-a-text-file-in-visual-basic-net/#comments</comments>
		<pubDate>Thu, 24 Jul 2008 02:43:58 +0000</pubDate>
		<dc:creator>Doug Vanderweide</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[file system]]></category>

		<guid isPermaLink="false">http://www.dougv.com/blog/?p=520</guid>
		<description><![CDATA[Recently asked on Yahoo! Answers: Reading file names in VB.NET? I am making a program that I will use to read files in a particular folder and put those file names into a text file. How can I do this? This is actually pretty easy to do in VB.NET, and there are several other examples [...]<div class="yarpp">
	<h5>Related Posts</h5>
		<ol>
				<li><a href="https://www.dougv.com/2007/01/11/retaining-the-lastwritetime-value-for-a-file-about-to-be-overwritten-via-ftp-fileupload-by-using-aspnets-fileinfo-class/" rel="bookmark">Retaining The LastWriteTime Value For A File About To Be Overwritten Via FTP / FileUpload By Using ASP.NET&#039;s FileInfo Class</a> (22.1)</li>
				<li><a href="https://www.dougv.com/2006/12/03/an-aspnet-20-script-to-share-files-among-users/" rel="bookmark">An ASP.NET 2.0 Script To Share Files Among Users</a> (20.7)</li>
				<li><a href="https://www.dougv.com/2007/06/27/displaying-a-random-image-from-a-directory-via-php/" rel="bookmark">Displaying A Random Image From A Directory Via PHP</a> (18)</li>
			</ol>
	<p class="note">The numbers inside parentheses are relevance scores. Scoring is based, in order of priority, on title, category, content and tags. The higher the score, the more likely that post relates to this post.
	</div>
]]></description>
			<content:encoded><![CDATA[<p>Recently asked on Yahoo! Answers:</p>
<blockquote><p><a href="http://answers.yahoo.com/question/index?qid=20080723180953AAWh8UK"><strong>Reading file names in VB.NET?</strong></a><br />
I am making a program that I will use to read files in a particular folder and put those file names into a text file. How can I do this?</p></blockquote>
<p>This is actually pretty easy to do in VB.NET, and there are several other examples on the Web. But it&#8217;s been a while since I&#8217;ve written anything on VB.NET, so I figured I would do this one.</p>
<p>I will accomplish this task with two subroutines. The first is a recursive subroutine that accepts a file path (e.g., C:pathtosomedirectory), scans all its subdirectories for files, and returns the name of each file to a second subroutine.</p>
<p>That second subroutine adds the passed file name to a text file.</p>
<p><span id="more-520"></span></p>
<h4>Step 1: The GetAllFiles() Subroutine</h4>
<p>As previously noted, our first subroutine accepts the opening file path as its argument.</p>
<ul>
<li>The subroutine ensures the directory exists.</li>
<li>If the directory exists, the subroutine gets a list of all current subdirectories, and sends each of those subdirectories to this same function via a For Each loop. If you do not want to scan subdirectories for file names, then simply comment out the first For Each loop.</li>
<li>The subroutine finally gets all the files in the directory and sends their names to the AddFileName subroutine.</li>
</ul>
<pre class="brush: vb; title: ; notranslate">Imports System.IO

Sub GetAllFiles(strPath As String)
	Dim objRoot As New DirectoryInfo(strPath)
	Dim objSubDir As DirectoryInfo()
	Dim objFile As FileInfo()

	If objRoot.Exists Then
		'if you don't want this to be recursive, remove this for loop
		For Each objSubDir In objRoot.GetDirectories
			GetAllFiles(objSubDir.FullPath)
		Next

		'keep this for loop
		For Each objFile In objRoot.GetFiles
			AddFileName(strPath &amp; &quot;\&quot; &amp; objFile.Name)
		Next
	End If
End Sub
</pre>
<h4>Step 2: The AddFileName() Subroutine</h4>
<p>The AddFileName subroutine will actually add our file name, its only argument, to the text file.</p>
<ul>
<li>It checks to see if the output file exists; if not, the file is created.</li>
<li>A StreamWriter is created and the output file is opened for appending.</li>
<li>The file name is added as a line to the text file, which is then closed.</li>
</ul>
<pre class="brush: vb; title: ; notranslate">
Sub AddFileName(strName As String)
	Dim strOutput As String = &quot;C:pathtooutput.txt&quot;
	If Not File.Exists(strOutput) Then
		File.CreateText(strOutput)
	End If

	Dim objStream As StreamWriter = File.AppendText(strOutput)
	objStream.WriteLine(strName)
	objStream.Flush()
	objStream.Close()
End Sub
</pre>
<p>That&#8217;s all there is to it.</p>
<div class="yarpp">
	<h5>Related Posts</h5>
		<ol>
				<li><a href="https://www.dougv.com/2007/01/11/retaining-the-lastwritetime-value-for-a-file-about-to-be-overwritten-via-ftp-fileupload-by-using-aspnets-fileinfo-class/" rel="bookmark">Retaining The LastWriteTime Value For A File About To Be Overwritten Via FTP / FileUpload By Using ASP.NET&#039;s FileInfo Class</a> (22.1)</li>
				<li><a href="https://www.dougv.com/2006/12/03/an-aspnet-20-script-to-share-files-among-users/" rel="bookmark">An ASP.NET 2.0 Script To Share Files Among Users</a> (20.7)</li>
				<li><a href="https://www.dougv.com/2007/06/27/displaying-a-random-image-from-a-directory-via-php/" rel="bookmark">Displaying A Random Image From A Directory Via PHP</a> (18)</li>
			</ol>
	<p class="note">The numbers inside parentheses are relevance scores. Scoring is based, in order of priority, on title, category, content and tags. The higher the score, the more likely that post relates to this post.</p>
	</div>

	Tags: <a href="https://www.dougv.com/tag/file-system/" title="file system" rel="tag">file system</a><br />
]]></content:encoded>
			<wfw:commentRss>https://www.dougv.com/2008/07/23/recursively-listing-files-in-a-directory-and-adding-their-names-to-a-text-file-in-visual-basic-net/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>A Windows Shell Script To Automatically Rename And Move Images To A New Folder</title>
		<link>https://www.dougv.com/2008/01/01/a-windows-shell-script-to-automatically-rename-and-move-images-to-a-new-folder/</link>
		<comments>https://www.dougv.com/2008/01/01/a-windows-shell-script-to-automatically-rename-and-move-images-to-a-new-folder/#comments</comments>
		<pubDate>Tue, 01 Jan 2008 05:29:49 +0000</pubDate>
		<dc:creator>Doug Vanderweide</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[file system]]></category>

		<guid isPermaLink="false">http://www.dougv.com/blog/2008/01/01/a-windows-shell-script-to-automatically-rename-and-move-images-to-a-new-folder/</guid>
		<description><![CDATA[Recently asked on Yahoo! Answers: How do I set Windows XP to rename same named files when in same directory? I&#8217;m putting thousands of images and other files in the same folder so that I can sort from that folder, I want to keep all the versions that I may have the same file name [...]<div class="yarpp">
	<h5>Related Posts</h5>
		<ol>
				<li><a href="https://www.dougv.com/2006/12/03/an-aspnet-20-script-to-share-files-among-users/" rel="bookmark">An ASP.NET 2.0 Script To Share Files Among Users</a> (15.9)</li>
				<li><a href="https://www.dougv.com/2007/04/04/displaying-static-random-html-and-images-on-a-web-page-via-ajax/" rel="bookmark">Displaying Static, Random HTML And Images On A Web Page Via AJAX</a> (14.8)</li>
				<li><a href="https://www.dougv.com/2007/10/06/a-simple-link-rewriting-script-in-php/" rel="bookmark">A Simple Link Rewriting Script In PHP</a> (13.2)</li>
			</ol>
	<p class="note">The numbers inside parentheses are relevance scores. Scoring is based, in order of priority, on title, category, content and tags. The higher the score, the more likely that post relates to this post.
	</div>
]]></description>
			<content:encoded><![CDATA[<p>Recently asked on Yahoo! Answers:</p>
<blockquote><p>
<strong><a href="http://answers.yahoo.com/question/?qid=20071229193924AAMHjnt">How do I set Windows XP to rename same named files when in same directory?</a></strong><br />
I&#8217;m putting thousands of images and other files in the same folder so that I can sort from that folder, I want to keep all the versions that I may have the same file name with different names when I put them in that folder. If I can I would also like to leave the () out of the new rename. I&#8217;ve seen other computers that do the renaming automatically, this would save me time from the current setting in which it asks with each file if I want to overwrite it and if it doesn&#8217;t overwrite it just leaves the file where it was before without putting it in!
</p></blockquote>
<p>This is simple enough to do if you have a little knowledge of VBScript; in this case, as it pertains to the Windows Scripting Host (or whatever Microsoft calls it these days).</p>
<p>Basically, a few lines of VBS can quickly get all the files in a directory, maintain their current sort order, rename them to be 100 percent unique, and move those files from whatever directory they are currently in to wherever we want them to go.</p>
<p>Let&#8217;s do it. As always, code you can download appears at the end of this listing.</p>
<p><span id="more-312"></span></p>
<p>Some important notes about this solution before we get into the code proper:</p>
<ul>
<li>This script only works for files that end in .jpg or .jpeg (case-insensitive). It won&#8217;t rename / move other image types.</li>
<li>This script is not recursive. It deals only with files in the specified source directory, not with the subdirectories or the files in any subdirectories. You need to change the source folder path and continue running this script for all subdirectories.</li>
<li>Images are moved from the source directory to the destination directory.</li>
<li>Images are permanently renamed in this format: YYYYMMDDhhmm_X (that is, today&#8217;s year, month, day, hour, minute, an underscore, and a padded image number.</li>
<li>There is no way for two images to have the same name with this system.</li>
<li>Images are sorted in this script in alphanumeric order before processing, so that sets may be renamed in their original order.
<ul>
<li>The Files collection &#8212; which is the most convenient way to go about getting all the files in a given folder &#8212; does not return file names in a specific order and there is no way to work directly with the collection to reorder it.</li>
<li>If we want an explicit sort, we must do so with an intermediary array. More on that shortly.</li>
</ul>
</li>
</ul>
<p>We&#8217;ll start by declaring the source and destination directory variables, which you need to change to match the file paths for the directories you want to use. <em>Note that all file paths must end with a trailing slash!</em></p>
<pre class="brush: vb; first-line: 22; title: ; notranslate">
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'DO NOT CHANGE THE LINE BELOW!
Dim SourcePath, DestinationPath
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

'################################################################################################
'CHANGE THE PATH VARIABLES BELOW to match your source / destination folders!
'Folder paths MUST have trailing slashes!

SourcePath = &quot;C:testinput&quot;
DestinationPath = &quot;C:testoutput&quot;
'################################################################################################
</pre>
<p>That&#8217;s all the user changes the script needs. Now, to the nuts &amp; bolts.</p>
<p>We start with some variables, including the basic pattern of the new file name:</p>
<pre class="brush: vb; first-line: 39; title: ; notranslate">
'Variables
Dim I, Y, strName, FileCount, ZeroPad, strTemp
strName = CStr(Year(Now)) &amp; CStr(Month(Now)) &amp; CStr(Day(Now)) &amp; CStr(Hour(Now)) &amp; CStr(Minute(Now)) &amp; &quot;_&quot;

'FSO variables
Dim objFSO, objInput, objOutput, objFile
</pre>
<p>With variables out of the way, we can create the FileSystemObject, then the source folder, and get a count of the files in the source folder:</p>
<pre class="brush: vb; first-line: 46; title: ; notranslate">
'create FSO
Set objFSO = CreateObject(&quot;Scripting.FileSystemObject&quot;)

'Open source folder
Set objInput = objFSO.GetFolder(SourcePath)

'Compute size of file name
FileCount = Len(CStr(objInput.Files.Count))
</pre>
<p>We need to declare an array that will contain all the image file names in the source folder, so that we can later sort the files alphanumerically:</p>
<pre class="brush: vb; first-line: 55; title: ; notranslate">
'Declare array to hold file names
Dim theFiles()
ReDim theFiles(objInput.Files.Count)
</pre>
<p>We need to initialize a short string with zeros, so that our newly named files will follow the same alphanumeric sorting rules we&#8217;re trying to preserve with the array.</p>
<p>For example, if there are 234 images in the folder, we want to name them 001 to 234. To do that, we will create a string with three zeros, and later, we&#8217;ll use that three-zero string to pad out the current image number.</p>
<pre class="brush: vb; first-line: 59; title: ; notranslate">
'Create padding for file rename
For I = 1 To FileCount
	ZeroPad = ZeroPad &amp; &quot;0&quot;
Next

'Reset I
I = 0
</pre>
<p>With the preliminaries out of the way, we can go through each file in the folder.</p>
<p>If it&#8217;s an image file &#8212; a fact we establish by looking for the file extension .jpg or .jpeg in the file name &#8212; we add it to the array we declared earlier. After we go through the entire list, we reset the array size to be the same as the number of items it contains.</p>
<pre class="brush: vb; first-line: 67; title: ; notranslate">
'Process all files in folder
For Each objFile In objInput.Files
    'if file has JPG or JPEG extension, add to files array
    If InStr(1, objFile.Name, &quot;.jpg&quot;, 1) &gt; 0 Or InStr(1, objFile.Name, &quot;.jpeg&quot;, 1) &gt; 0 Then
	    theFiles(I) = objFile.Name
	    I = I + 1
    End If
Next
ReDim Preserve theFiles(I)
</pre>
<p>Now, we bubble sort the array, to maintain alphanumeric order:</p>
<pre class="brush: vb; first-line: 77; title: ; notranslate">
'bubble sort files array
For I = (UBound(theFiles) - 1) To 0 Step -1
    For Y = 0 To I
        If UCase(theFiles(Y)) &gt; UCase(theFiles(Y + 1)) Then
            strTemp = theFiles(Y + 1)
            theFiles(Y + 1) = theFiles(Y)
            theFiles(Y) = strTemp
        End If
    Next
Next

'Reset I
I = 1
</pre>
<p>And now, we simply iterate through the array, renaming the files it contains and moving them to the destination folder:</p>
<pre class="brush: vb; first-line: 91; title: ; notranslate">
'Rename and move files
For Each strTemp In theFiles
    If objFSO.FileExists(SourcePath &amp; strTemp) Then
	    objFSO.MoveFile SourcePath &amp; strTemp, DestinationPath &amp; strName &amp; Right(ZeroPad &amp; I, FileCount) &amp; &quot;.jpg&quot;
	    I = I + 1
	End If
Next
</pre>
<p>A little cleanup, and a message telling us how many items were moved from where to where, just to let us know the script is done:</p>
<pre class="brush: vb; first-line: 100; title: ; notranslate">
'Clean up objects
Set objFile = Nothing
Set objInput = Nothing
Set objFSO = Nothing

'Report script complete
MsgBox(&quot;Processing completed for &quot; &amp; SourcePath &amp; &quot;. Renamed and moved &quot; &amp; UBound(theFiles) &amp; &quot; image files to &quot; &amp; DestinationPath &amp; &quot;.&quot;)
</pre>
<p>That&#8217;s it. I distribute all code under the GNU GPL version 3.</p>
<div class="yarpp">
	<h5>Related Posts</h5>
		<ol>
				<li><a href="https://www.dougv.com/2006/12/03/an-aspnet-20-script-to-share-files-among-users/" rel="bookmark">An ASP.NET 2.0 Script To Share Files Among Users</a> (15.9)</li>
				<li><a href="https://www.dougv.com/2007/04/04/displaying-static-random-html-and-images-on-a-web-page-via-ajax/" rel="bookmark">Displaying Static, Random HTML And Images On A Web Page Via AJAX</a> (14.8)</li>
				<li><a href="https://www.dougv.com/2007/10/06/a-simple-link-rewriting-script-in-php/" rel="bookmark">A Simple Link Rewriting Script In PHP</a> (13.2)</li>
			</ol>
	<p class="note">The numbers inside parentheses are relevance scores. Scoring is based, in order of priority, on title, category, content and tags. The higher the score, the more likely that post relates to this post.</p>
	</div>

	Tags: <a href="https://www.dougv.com/tag/file-system/" title="file system" rel="tag">file system</a><br />
]]></content:encoded>
			<wfw:commentRss>https://www.dougv.com/2008/01/01/a-windows-shell-script-to-automatically-rename-and-move-images-to-a-new-folder/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Displaying A Random Image From A Directory Via PHP, Part 2</title>
		<link>https://www.dougv.com/2007/07/03/displaying-a-random-image-from-a-directory-via-php-part-2/</link>
		<comments>https://www.dougv.com/2007/07/03/displaying-a-random-image-from-a-directory-via-php-part-2/#comments</comments>
		<pubDate>Wed, 04 Jul 2007 03:24:28 +0000</pubDate>
		<dc:creator>Doug Vanderweide</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[DOM images]]></category>
		<category><![CDATA[file system]]></category>

		<guid isPermaLink="false">http://www.dougv.com/blog/2007/07/03/displaying-a-random-image-from-a-directory-via-php-part-2/</guid>
		<description><![CDATA[In a recent blog post about randomly displaying an image from a directory via PHP and its built-in image and filesystem functions, I promised to expand upon the answer I had given to demonstrate some other cool filesystem tricks. It&#8217;s about time I made good on that promise. We&#8217;ll start by showing how to display [...]<div class="yarpp">
	<h5>Related Posts</h5>
		<ol>
				<li><a href="https://www.dougv.com/2007/06/27/displaying-a-random-image-from-a-directory-via-php/" rel="bookmark">Displaying A Random Image From A Directory Via PHP</a> (61.1)</li>
				<li><a href="https://www.dougv.com/2007/01/14/display-a-random-image-with-javascript-dom/" rel="bookmark">Display A Random Image With JavaScript / DOM</a> (27.8)</li>
				<li><a href="https://www.dougv.com/2006/12/20/displaying-a-random-yahoo-search-every-30-seconds-with-javascript-and-php/" rel="bookmark">Displaying A Random Yahoo! Search Every 30 Seconds With JavaScript And PHP</a> (25.2)</li>
			</ol>
	<p class="note">The numbers inside parentheses are relevance scores. Scoring is based, in order of priority, on title, category, content and tags. The higher the score, the more likely that post relates to this post.
	</div>
]]></description>
			<content:encoded><![CDATA[<p>In a <a href="http://www.dougv.com/2007/06/27/displaying-a-random-image-from-a-directory-via-php/">recent blog post</a> about randomly displaying an image from a directory via PHP and its built-in image and filesystem functions, I promised to expand upon the answer I had given to demonstrate some other cool filesystem tricks.</p>
<p>It&#8217;s about time I made good on that promise.</p>
<p>We&#8217;ll start by showing how to display a random image on a Web page, rather than forging the PHP to represent itself as an image; and we&#8217;ll also make a thumbnail gallery of all the images in the folder, which even shows the active image.</p>
<p><span id="more-249"></span></p>
<p><strong>Displaying The Random PHP Image On The Page</strong></p>
<p>The script to randomly select and display an image on a Web page is remarkably similar to the original script in <a href="http://www.dougv.com/2007/06/27/displaying-a-random-image-from-a-directory-via-php/">this post</a>, except that we&#8217;re going to find the image&#8217;s URL to apply as the src attribute for an IMG tag, rather than putting the image directly to the output buffer.</p>
<p>That URL we&#8217;ll store as the variable $img_src:</p>
<pre lang="php">
$img_path = "images/";
$exts = "/(.jpg)|(.jpeg)|(.gif)|(.png)$/i";

if(is_dir($img_path)) {
	$img_handle = opendir($img_path);

	while (false !== ($img_file = readdir($img_handle))) {
		if (preg_match($exts, $img_file)) {
			$img[] = $img_file;
		}
	}

	mt_srand();
	$len = count($img) - 1;
	$index = mt_rand(0, $len);
	$img_src = $img_path . $img[$index];

	closedir($img_handle);
}
else {
	die("no such directory!");
}
</pre>
<p>And now, to display the &#8220;random&#8221; image, we simply echo out $img_src inside an IMG tag:</p>
<pre lang="xml">
<img src="<?php echo $img_src; ?>" alt="<?php echo $img_src; ?>" title="<?php echo $img_src; ?>" />
</pre>
<p><strong>A Thumbnail Gallery That Shows The Current Image</strong></p>
<p>Using the same methods we employed to select a random, full-size image on the page, we can use to display a series of thumbnail images. In fact, we can even combine the scripts, to apply a background color to the thumbnail that is currently being displayed in full size.</p>
<p>We&#8217;ll sort of cheat on layout by using a table to display the thumbnails. (Technically, this can be considered tabular data, but best practices would be to not use a table here).</p>
<pre lang="php">
$i = 0;
$TN_COLS = 3;
$tn_path = "images/tn/";
</pre>
<p>Next, we&#8217;ll use the same method we did above to open the directory and begin iterating through the thumbnails, dumping them into an array as well:</p>
<pre lang="php">
if(is_dir($tn_path)) {
	$tn_handle = opendir($tn_path);

	while(false !== ($tn_file = readdir($tn_handle))) {
		if(preg_match($exts, $tn_file)) {
			$tn_img[] = $tn_file;
		}
	}
</pre>
<p>Now for the first real change: We apply a natsort on the array.</p>
<p>We do that not only because the filesystem stores icons in an unpredictable manner &#8212; that is, any old item in the directory could be listed first in any one iteration of the directory &#8212; but because we want the pictures ordered in a way that makes sense to most people.</p>
<p>Unlike a normal array sort, natsort will sort an array more like a human would. For example, if you have thumbnails named 1.jpg through 15.jpg, a normal array sort would place 11.jpg-15.jpg, after 1.jpg but before 2.jpg. Natsort will put 11.jpg-15.jpg at the end of the array, the way most humans would.</p>
<pre lang="php">
	natsort($tn_img);
</pre>
<p>With the array sorted, we can begin outputting each item in the array as a cell in our table.</p>
<p>We&#8217;re going to dynamically create rows in the table based on the $TN_COLS variable we declared earlier. For example, since we declared 3 as the value of $TN_COLS, any time we have a cell that is divisible by 3, we&#8217;re going to break for a new row.</p>
<p>We&#8217;re also going to see if the thumbnail image we are using is the same as the currently displaying large image. If it is, we apply a class to the table cell; in that class, we define the background color we want to have appear.</p>
<pre lang="php">
	foreach($tn_img as $thumb) {
		if($i % $TN_COLS == 0) {
			echo "
<tr>";
		}

		echo "
<td";
		if($thumb == $img[$index]) {
			echo " lang="active"";
		}
		echo ">";
		echo "<img src="" . $tn_path . $thumb . "" alt="$thumb" title="$thumb" />";
		echo "";
		echo $thumb;
		echo "</td>

n";

		$i++;
		if($i % $TN_COLS == 0) {
			echo "</tr>

n";
		}
	}
</pre>
<p>We have one last housekeeping item: It&#8217;s possible we don&#8217;t have enough cells to complete the last row. To fix that problem, we add another loop that &#8220;pads&#8221; the last row with enough empty cells to complete it.</p>
<pre lang="php">
	if($i % $TN_COLS != 0) {
		for($x = $i; $x % $TN_COLS > 0; $x++) {
			echo "
<td>&nbsp;</td>

n";
		}
		echo "</tr>

n";
	}

	closedir($tn_handle);
}
else {
	die("no such thumbnail image path!");
}
</pre>
<p>You can see this script in action at:</p>
<p><a href="http://www.dougv.com/demo/php_random_image/example2.php">http://www.dougv.com/demo/php_random_image/example2.php</a></p>
<p>You can download this script and its related images from here: <a href='http://www.dougv.com/wp-content/uploads/2007/06/php_random_image.zip'>Displaying A Random Image From A Directory Via PHP Source Code</a></p>
<p>I distribute all code under the GNU GPL 3.</p>
<div class="yarpp">
	<h5>Related Posts</h5>
		<ol>
				<li><a href="https://www.dougv.com/2007/06/27/displaying-a-random-image-from-a-directory-via-php/" rel="bookmark">Displaying A Random Image From A Directory Via PHP</a> (61.1)</li>
				<li><a href="https://www.dougv.com/2007/01/14/display-a-random-image-with-javascript-dom/" rel="bookmark">Display A Random Image With JavaScript / DOM</a> (27.8)</li>
				<li><a href="https://www.dougv.com/2006/12/20/displaying-a-random-yahoo-search-every-30-seconds-with-javascript-and-php/" rel="bookmark">Displaying A Random Yahoo! Search Every 30 Seconds With JavaScript And PHP</a> (25.2)</li>
			</ol>
	<p class="note">The numbers inside parentheses are relevance scores. Scoring is based, in order of priority, on title, category, content and tags. The higher the score, the more likely that post relates to this post.</p>
	</div>

	Tags: <a href="https://www.dougv.com/tag/dom-images/" title="DOM images" rel="tag">DOM images</a>, <a href="https://www.dougv.com/tag/file-system/" title="file system" rel="tag">file system</a><br />
]]></content:encoded>
			<wfw:commentRss>https://www.dougv.com/2007/07/03/displaying-a-random-image-from-a-directory-via-php-part-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Displaying A Random Image From A Directory Via PHP</title>
		<link>https://www.dougv.com/2007/06/27/displaying-a-random-image-from-a-directory-via-php/</link>
		<comments>https://www.dougv.com/2007/06/27/displaying-a-random-image-from-a-directory-via-php/#comments</comments>
		<pubDate>Thu, 28 Jun 2007 04:29:21 +0000</pubDate>
		<dc:creator>Doug Vanderweide</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[DOM images]]></category>
		<category><![CDATA[file system]]></category>

		<guid isPermaLink="false">http://www.dougv.com/blog/2007/06/27/displaying-a-random-image-from-a-directory-via-php/</guid>
		<description><![CDATA[Recently asked on Yahoo! Answers: How would one code a rotating image (using PHP) that can be hosted on Geocities Pro for, say, a forum? In the past, I&#8217;ve been able to host a rotating image using another method by naming a folder &#8216;something.png&#8217; to fool a forum into thinking the folder is a picture [...]<div class="yarpp">
	<h5>Related Posts</h5>
		<ol>
				<li><a href="https://www.dougv.com/2006/12/20/displaying-a-random-yahoo-search-every-30-seconds-with-javascript-and-php/" rel="bookmark">Displaying A Random Yahoo! Search Every 30 Seconds With JavaScript And PHP</a> (26.1)</li>
				<li><a href="https://www.dougv.com/2007/01/14/display-a-random-image-with-javascript-dom/" rel="bookmark">Display A Random Image With JavaScript / DOM</a> (25.8)</li>
				<li><a href="https://www.dougv.com/2007/01/09/displaying-a-new-image-based-on-image-choices-via-checkboxes-the-html-dom-and-javascript/" rel="bookmark">Displaying A New Image Based On Image Choices Via Checkboxes, the HTML DOM and JavaScript</a> (24.5)</li>
			</ol>
	<p class="note">The numbers inside parentheses are relevance scores. Scoring is based, in order of priority, on title, category, content and tags. The higher the score, the more likely that post relates to this post.
	</div>
]]></description>
			<content:encoded><![CDATA[<p>Recently asked on Yahoo! Answers:</p>
<blockquote><p>
<strong><a href="http://answers.yahoo.com/question/index?qid=20070627175856AASRhZe">How would one code a rotating image (using PHP) that can be hosted on Geocities Pro for, say, a forum?</a></strong></p>
<p>In the past, I&#8217;ve been able to host a rotating image using another method by naming a folder &#8216;something.png&#8217; to fool a forum into thinking the folder is a picture and it reads the index.php file, which in turn pulls up one of the images I have coded. Now that I&#8217;m on Geocities Pro, I cannot make such a folder but would like to still use my rotating image. Is there another way I can code this and still be able to use it with forum BBCode?
</p></blockquote>
<p>Basically, this questioner wants a PHP script to look through the contents of an image directory, randomly select one of the images in that directory, and pass the script itself off as the image.</p>
<p>That&#8217;s fairly simple to do in PHP, but it does require a number of steps and a few tricks to overcome some limitations of <a href="http://us2.php.net/manual/en/ref.filesystem.php">PHP&#8217;s built-in filesystem functions</a>.</p>
<p>This question also gives me a chance to explain working with the filesystem in PHP, and to demonstrate how loops and arrays can be used to produce some really neat results, so I&#8217;ll expand on that in a follow-up post.</p>
<p>As always, a working demo and source code will be available for download at the end of this article.</p>
<p><span id="more-245"></span></p>
<p><strong>Step 1: Declare Basic Variables</strong></p>
<p>We&#8217;ll start by declaring two variables:</p>
<ul>
<li>The path, relative to the script, of the folder containing the images we want.</li>
<li>A regular expression that gives us the allowed extensions for our images.</li>
</ul>
<p>For those who are new to the term, a <a href="http://en.wikipedia.org/wiki/Regular_expression">regular expression</a> is basically a text pattern you want to find. It uses special characters and syntax to indicate what you want to find; in our case, we&#8217;re going to search for file extensions.</p>
<p>Don&#8217;t worry if you don&#8217;t understand the expression; trust me that this one will allow you to use image files with the extension .jpg, .jpeg, .gif or .png; the test will also be case-insensitive, so .JPG is the same thing as .jpg.</p>
<p>More on all that later. Let&#8217;s look at the opening code.</p>
<pre lang="php">
$img_path = "images/";
$exts = "/(.jpg)|(.jpeg)|(.gif)|(.png)$/i";
</pre>
<p><strong>Step 2: Open The Directory And Iterate Through The Files</strong></p>
<p>Our next step is to make sure the image directory we declared actually exists. If it does, we want to go ahead and open the directory, then begin looking through the files.</p>
<p><strong>An aside on the difference between evaluating equivalence vs. identity:</strong> Notice, in the code below, that we use the identity operator (===), and not the equivalence operator (==), to test whether we have read all the files in the directory.</p>
<p>We do that because, as the PHP documentation notes, <a href="http://us2.php.net/manual/en/function.readdir.php">readdir()</a> may not return a Boolean &#8220;false,&#8221; but may return another value that is the same as false.</p>
<p>The identity operator allows us to compare two variables not on the basis of them having the same value (equivalence), but being the same thing.</p>
<p>If we just use the equivalence operator, and readdir() returns a value that means the same as Boolean false, that won&#8217;t be equal to Boolean false; our loop would continue and we&#8217;d get an error. If we use the identity operator, we know that whatever false value readdir() actually returns, it means the same, for all intents and purposes, as Boolean false; our loop will stop executing. (End of aside.)</p>
<pre lang="php">
if(is_dir($img_path)) {
	//open directory
	$img_handle = opendir($img_path);

	//iterate through all items in directory
	while (false !== ($img_file = readdir($img_handle))) {
</pre>
<p><strong>Step 3: Put All Image Files Into An Array</strong></p>
<p>We&#8217;re going to read the names of all image files into a dynamic array, the reasons for which will be clearer in a moment. For now, you&#8217;ll notice we use preg_match, the preferred method for running a regular expression match against a string, to make sure that the file we&#8217;re currently looking has an extension that&#8217;s in our allowable extensions list.</p>
<p>An added bonus of this approach is that it resolves problems with subdirectories in PHP.</p>
<p>Basically, in PHP, if you are iterating through a directory and it has subdirectories, the built-in functions in PHP will treat all subdirectories as files; you can&#8217;t even evaluate if the subdirectory is a directory.</p>
<p>Needless to say, that&#8217;s a major problem, and the only effective way to work around it, via the filesystem, is to read each &#8220;file,&#8221; then see if trying to enter it, as if it were a directory, works. If so, you&#8217;ve found a subdirectory, not a file.</p>
<p>That&#8217;s pretty wasteful, in my opinion, and possibly dangerous. It makes much more sense, and is far less resource-intensive, to simply look at the name of the file and see if it matches the kind of file we want.</p>
<p>Note that not all Web hosts will have compiled support for Perl-Compatible Regular Expressions (<a href="http://us2.php.net/manual/en/ref.pcre.php">PCRE</a>). Virtually all do, but yours may not have; if not, this script won&#8217;t be of much use to you.</p>
<p>Lastly, once we&#8217;re done looping through the files in the directory, we want to close the directory to free up the considerable resources PHP uses to work with the filesystem.</p>
<pre lang="php">
if (preg_match($exts, $img_file)) {
	$img[] = $img_file;
}

closedir($img_handle);
</pre>
<p><strong>Step 4: Select The Random Image Via A Random Number</strong></p>
<p>Here&#8217;s the magic: Since we&#8217;ve dumped all the file names into an array, all we need to do is randomly generate an index number, and pull out from the array the name of the file that is at that index.</p>
<p>So, our task list for this step is:</p>
<ul>
<li>Initialize our random number generator;</li>
<li>Get the total number of items in the array and subtract one, which will give us the index of the last item in the array. If there are no items in the array, we&#8217;ll die and report that fact;</li>
<li>Generate a random number between 0 and the integer we get from the step above, which gives us a random index for the array;</li>
<li>Append the file path to the array cell contents at the index we generated, which gives us a full file path to one of the images in the directory.</li>
</ul>
<pre lang="php">
mt_srand();

if(count($img) == 0) {
	die("no images in image directory");
}
else {
	$len = count($img) - 1;
}

$index = mt_rand(0, $len);
$img_src = $img_path . $img[$index];
</pre>
<p><strong>Step 5: Get The Content-Type</strong></p>
<p>The way we&#8217;re going to make this PHP script act like an image is by forging the HTTP header&#8217;s <a href="http://en.wikipedia.org/wiki/Internet_media_type">content-type</a> value. Instead of outputting &#8220;text/html&#8221;, which Web pages send, we&#8217;ll send one of the image types, depending on our file&#8217;s extension.</p>
<p>So first, we need to get the extension from our file.</p>
<ul>
<li>We set the basic part of the content-type string as a variable.</li>
<li>We split the file&#8217;s name into an array, around the periods.</li>
<li>We then remove the last item of the array, which will contain our extension. We know that because by virtue of the regular expression we used to sort files earlier, we know all files will end with one of our four image file extensions.</li>
<li>We cast the extension down to lower-case, to make sure we get a case-insensitive match.</li>
<li>We run the extension through a switch that assumes the file is a JPEG, but changes the content-type to GIF or PNG if that&#8217;s what we actually have.</li>
</ul>
<pre lang="php">
$ct = "Content-type: image/";

$temp = explode(".", $img_src);
$temp = array_pop($temp);
$temp = strtolower($temp);

switch($temp) {
	case "png":
		$ct .= "png";
		break;
	case "gif":
		$ct .= "gif";
		break;
	default:
		$ct .= "jpeg";
}
</pre>
<p><strong>Step 6: Echo Out The Forged Header And The Image</strong></p>
<p>Outputting our image is as simple as sending the forged header (via the cleverly-named header() function) and then dumping the image file&#8217;s contents directly to the output buffer via readfile().</p>
<pre lang="php">
header($ct);
readfile($img_src);
</pre>
<p>And, as a final step, we&#8217;ll add an else statement to the opening if statement; if the path we specified in Step 1 doesn&#8217;t lead to a directory, we&#8217;ll die the script and report that.</p>
<pre lang="php">
else {
	die("no such directory!");
}
</pre>
<p>And that&#8217;s all there is to it. You can see the script in action here:</p>
<p><a href="http://www.dougv.com/demo/php_random_image/index.php">http://www.dougv.com/demo/php_random_image/index.php</a></p>
<p>Just reload the page to see a different image.</p>
<p><strong>A final aside on randomness: </strong>When selecting a random number, the larger the range, the more random the number. Thus, the more images that act as a source for this script, the more random your results. I&#8217;m using 15 images. (End of aside.)</p>
<p>You can download the source code here: <a href='http://www.dougv.com/wp-content/uploads/2007/06/php_random_image.zip'>Displaying A Random Image From A Directory Via PHP Source Code</a></p>
<p>I distribute all code under the GNU GPL 3.</p>
<div class="yarpp">
	<h5>Related Posts</h5>
		<ol>
				<li><a href="https://www.dougv.com/2006/12/20/displaying-a-random-yahoo-search-every-30-seconds-with-javascript-and-php/" rel="bookmark">Displaying A Random Yahoo! Search Every 30 Seconds With JavaScript And PHP</a> (26.1)</li>
				<li><a href="https://www.dougv.com/2007/01/14/display-a-random-image-with-javascript-dom/" rel="bookmark">Display A Random Image With JavaScript / DOM</a> (25.8)</li>
				<li><a href="https://www.dougv.com/2007/01/09/displaying-a-new-image-based-on-image-choices-via-checkboxes-the-html-dom-and-javascript/" rel="bookmark">Displaying A New Image Based On Image Choices Via Checkboxes, the HTML DOM and JavaScript</a> (24.5)</li>
			</ol>
	<p class="note">The numbers inside parentheses are relevance scores. Scoring is based, in order of priority, on title, category, content and tags. The higher the score, the more likely that post relates to this post.</p>
	</div>

	Tags: <a href="https://www.dougv.com/tag/dom-images/" title="DOM images" rel="tag">DOM images</a>, <a href="https://www.dougv.com/tag/file-system/" title="file system" rel="tag">file system</a><br />
]]></content:encoded>
			<wfw:commentRss>https://www.dougv.com/2007/06/27/displaying-a-random-image-from-a-directory-via-php/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>An ASP.NET 2.0 Script To Share Files Among Users</title>
		<link>https://www.dougv.com/2006/12/03/an-aspnet-20-script-to-share-files-among-users/</link>
		<comments>https://www.dougv.com/2006/12/03/an-aspnet-20-script-to-share-files-among-users/#comments</comments>
		<pubDate>Sun, 03 Dec 2006 23:24:26 +0000</pubDate>
		<dc:creator>Doug Vanderweide</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[Web Forms]]></category>
		<category><![CDATA[file system]]></category>

		<guid isPermaLink="false">http://www.dougv.com/blog/2006/12/03/an-aspnet-20-script-to-share-files-among-users/</guid>
		<description><![CDATA[Recently asked on Yahoo! Answers: How could I enable user to upload and download file from server using asp.net 2? How could I enable a user to upload file to the server and then view link to download this file from the server to anthor user i when he enters the site using ASP.NET 2? [...]<div class="yarpp">
	<h5>Related Posts</h5>
		<ol>
				<li><a href="https://www.dougv.com/2006/11/26/a-simple-php-script-mysql-too-to-track-radio-station-song-requests-part-4/" rel="bookmark">A Simple PHP Script (MySQL, Too) To Track Radio Station Song Requests, Part 4</a> (13.3)</li>
				<li><a href="https://www.dougv.com/2006/11/26/a-simple-php-script-mysql-too-to-track-radio-station-song-requests/" rel="bookmark">A Simple PHP Script (MySQL, Too) To Track Radio Station Song Requests, Part 1</a> (12.1)</li>
				<li><a href="https://www.dougv.com/2006/11/26/a-simple-php-script-mysql-too-to-track-radio-station-song-requests-part-2/" rel="bookmark">A Simple PHP Script (MySQL, Too) To Track Radio Station Song Requests, Part 2</a> (12.1)</li>
			</ol>
	<p class="note">The numbers inside parentheses are relevance scores. Scoring is based, in order of priority, on title, category, content and tags. The higher the score, the more likely that post relates to this post.
	</div>
]]></description>
			<content:encoded><![CDATA[<p>Recently asked on Yahoo! Answers:</p>
<blockquote><p>
<strong><a href="http://answers.yahoo.com/question/index?qid=20061203084557AADsEV1">How could I enable user to upload and download file from server using asp.net 2?</a></strong></p>
<p>How could I enable a user to upload file to the server and then view link to download this file from the server to anthor user i when he enters the site using ASP.NET 2?
</p></blockquote>
<p>The problems here could be handled very easily simply by using the built-in FileUpload class and the DirectoryInfo / FileInfo classes to display the files in the targeted directory.</p>
<p>So, let&#8217;s run that simple code today.</p>
<p><span id="more-42"></span></p>
<h3>Web.config Settings</h3>
<p>We&#8217;ll set a few application variables in the web.config file to make our application very portable. We need to record:</p>
<ul>
<li>The URI (that is, the physical path) to the file</li>
<li>The URL (that is, the hyperlink) to the file</li>
<li>We&#8217;ll also add the System.IO namespace to the namespaces</li>
</ul>
<pre class="brush: xml; title: ; notranslate">
&lt;appSettings&gt;
	&lt;add key=&quot;UploadBaseURI&quot; value=&quot;c:physicalpathtoyouruploaddirectory&quot; /&gt;
	&lt;add key=&quot;UploadBaseURL&quot; value=&quot;http/path/to/your/upload/directory/&quot;/&gt;
&lt;/appSettings&gt;
</pre>
<pre class="brush: xml; title: ; notranslate">
&lt;namespaces&gt;
	&lt;add namespace=&quot;System.IO&quot;/&gt;
&lt;/namespaces&gt;
1

&lt;h3&gt;The HTML Form&lt;/h3&gt;

With the keys and namespaces added, we can move on to the HTML.

&lt;ul&gt;
	&lt;li&gt;We need the FileUpload control, as well as a RequiredFieldValidator to make sure that if someone uploads a file, they've entered something in the control.&lt;/li&gt;
	&lt;li&gt;We need a button to submit the form.&lt;/li&gt;
	&lt;li&gt;Finally, we have a div that we will programmatically update with the available file list.&lt;/li&gt;
&lt;/ul&gt;

1
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; &gt;
	&lt;head runat=&quot;server&quot;&gt;
		&lt;title&gt;Simple File Upload&lt;/title&gt;
	&lt;/head&gt;
	&lt;body&gt;
		&lt;form id=&quot;form1&quot; runat=&quot;server&quot;&gt;
			&lt;h1&gt;Uploaded Files&lt;/h1&gt;
			&lt;div runat=&quot;server&quot; id=&quot;divFiles&quot;&gt;&lt;/div&gt;
			&lt;br /&gt;
			&lt;h2&gt;Upload Your File&lt;/h2&gt;
			&lt;asp:Label runat=&quot;server&quot; ID=&quot;lblStatus&quot; /&gt;
			&lt;table&gt;
				&lt;tr&gt;
					&lt;td&gt;File To Upload:&lt;/td&gt;
					&lt;td&gt;&lt;asp:FileUpload runat=&quot;server&quot; ID=&quot;fuMain&quot; /&gt;&lt;/td&gt;
					&lt;td&gt;&lt;asp:RequiredFieldValidator runat=&quot;server&quot; ID=&quot;rfvFU&quot; ControlToValidate=&quot;fuMain&quot; ErrorMessage=&quot;Please provide a file to upload&quot; Display=&quot;Dynamic&quot; /&gt;&lt;/td&gt;
				&lt;/tr&gt;
			&lt;/table&gt;
			&lt;br /&gt;
			&lt;asp:Button runat=&quot;server&quot; ID=&quot;btnSubmit&quot; Text=&quot;Upload File&quot; OnClick=&quot;btnSubmit_onClick&quot; /&gt;
		&lt;/form&gt;
	&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>With the HTML out of the way, we need three subroutines:</p>
<ul>
<li>A Page_Load subroutine that will show all users the file list upon first visiting the page.</li>
<li>A subroutine to show us the files</li>
<li>A subroutine to upload user files, then refresh the file list</li>
</ul>
<h3>The Page_Load Subroutine</h3>
<p>It doesn&#8217;t get more rudimentary than this: Check for page postback; if the page isn&#8217;t posting back, show the list of files.</p>
<pre class="brush: vb; title: ; notranslate">
Sub Page_Load(ByVal Sender As Object, ByVal E As EventArgs)
	If Not Page.IsPostBack Then
		'as the name says, show files
		ShowAvailableFiles()
	End If
End Sub
</pre>
<h3>The ShowAvailableFiles Subroutine</h3>
<p>Showing the files is fairly straightforward.</p>
<ul>
<li>We create an HTML table</li>
<li>We open the directory up with DirectoryInfo, then get all the files from it</li>
<li>We load those files into an array of FileInfo objects</li>
<li>We check the length of the array. If it&#8217;s 0, we know there are no files. If it&#8217;s longer, we know there are files to display.</li>
<li>We iterate through the FileInfo array we created, constructing URLs for each file and showing its upload (LastWriteTime) time.</li>
<li>We finish the HTML table, and then assign the table to the display DIV&#8217;s InnerHtml</li>
</ul>
<pre class="brush: vb; title: ; notranslate">
Sub ShowAvailableFiles()
	'display all available files in a table
	Dim strOut As String, strPath As String, strBase As String = ConfigurationManager.AppSettings(&quot;UploadBaseURL&quot;).ToString()

	'start building the table
	strOut = &quot;&lt;table&gt;&quot;
	strOut += &quot;&lt;tr&gt;&lt;th&gt;File&lt;/th&gt;&lt;th&gt;Date / Time Uploaded&lt;/th&gt;&lt;/tr&gt;&quot;

	'get all the files in our upload directory
	'load into an array of FileInfo objects
	Dim objDir As New DirectoryInfo(ConfigurationManager.AppSettings(&quot;UploadBaseURI&quot;).ToString())
	Dim objFiles() As FileInfo = objDir.GetFiles()
	Dim objFile As FileInfo

	'if we have no files, put message out
	If objFiles.Length = 0 Then
		strOut += &quot;&lt;tr&gt;&lt;td colspan=&quot;&quot;2&quot;&quot;&gt;No files&lt;/td&gt;&lt;/tr&gt;&quot;
	Else
		For Each objFile In objFiles
			'provide a link to each file, as well as its upload date / time
			'(LastWriteTime is the proper use here; CreateTime may be the
			'date the file was made, not the date it was uploaded
			strPath = strBase + objFile.Name
			strOut += &quot;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;&quot;&quot; + strPath + &quot;&quot;&quot;&gt;&quot; + objFile.Name + &quot;&lt;/a&gt;&lt;/td&gt;&quot;
			strOut += &quot;&lt;td&gt;&quot; + String.Format(&quot;{0:F}&quot;, objFile.LastWriteTime) + &quot;&lt;/td&gt;&lt;/tr&gt;&quot;
		Next
	End If

	'close the table, set the HTML for the DIV to show the listing
	strOut += &quot;&lt;/table&gt;&quot;
	divFiles.InnerHtml = strOut
End Sub
</pre>
<h3>The btnSubmit_onClick Subroutine</h3>
<p>The last task is the subroutine that handles file uploading.</p>
<ul>
<li>It checks if there was a file sent via the FileUpload control</li>
<li>If so, it tries to save the uploaded file to the URI for our uploaded files</li>
<li>If the file upload was bad, an error message is output</li>
<li>The available file list is refreshed</li>
</ul>
<pre class="brush: vb; title: ; notranslate">
Sub btnSubmit_onClick(ByVal Sender As Object, ByVal E As EventArgs)
	'check for good file
	If fuMain.HasFile() Then
		'set upload path string from app key
		Dim strPath As String = ConfigurationManager.AppSettings(&quot;UploadBaseURI&quot;).ToString() + fuMain.FileName
		'if we have a good upload, tell user;
		'otherwise, tell user the problem
		Try
			fuMain.SaveAs(strPath)
		Catch ex As Exception
			lblStatus.Text = &quot;Error trying to save the file you uploaded: &quot; + ex.Message
		Finally
			'no matter what, refresh the file list
			ShowAvailableFiles()
		End Try
	Else
		'warn that no file was sent to server
		lblStatus.Text = &quot;No file was uploaded. Please try again.&quot;
	End If
</pre>
<h3>Final Notes</h3>
<p>You can download this code here:</p>
<p><a id="p43" rel="attachment" href="http://www.dougv.com/2006/12/03/an-aspnet-20-script-to-share-files-among-users/aspnet-20-simple-upload-code/" title="ASP.NET 2.0 Simple Upload Code">ASP.NET 2.0 Simple Upload Code</a></p>
<p>There are all kinds of security holes in this code. Ideally, you should never place a writable directory in your public HTML path, nor should you allow people to upload any old thing they want. If you use this as is, someone could upload a malicious page to your Web site and do all sorts of damage with it; they could distribute illegal materials via your site; the list of potential mischief is endless.</p>
<p>As the license states, this code is provided as-is with no warranty whatsoever.</p>
<div class="yarpp">
	<h5>Related Posts</h5>
		<ol>
				<li><a href="https://www.dougv.com/2006/11/26/a-simple-php-script-mysql-too-to-track-radio-station-song-requests-part-4/" rel="bookmark">A Simple PHP Script (MySQL, Too) To Track Radio Station Song Requests, Part 4</a> (13.3)</li>
				<li><a href="https://www.dougv.com/2006/11/26/a-simple-php-script-mysql-too-to-track-radio-station-song-requests/" rel="bookmark">A Simple PHP Script (MySQL, Too) To Track Radio Station Song Requests, Part 1</a> (12.1)</li>
				<li><a href="https://www.dougv.com/2006/11/26/a-simple-php-script-mysql-too-to-track-radio-station-song-requests-part-2/" rel="bookmark">A Simple PHP Script (MySQL, Too) To Track Radio Station Song Requests, Part 2</a> (12.1)</li>
			</ol>
	<p class="note">The numbers inside parentheses are relevance scores. Scoring is based, in order of priority, on title, category, content and tags. The higher the score, the more likely that post relates to this post.</p>
	</div>

	Tags: <a href="https://www.dougv.com/tag/file-system/" title="file system" rel="tag">file system</a><br />
]]></content:encoded>
			<wfw:commentRss>https://www.dougv.com/2006/12/03/an-aspnet-20-script-to-share-files-among-users/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>An ASP.NET Subroutine To Locally Store The National Weather Service Current Observations XML Feeds</title>
		<link>https://www.dougv.com/2006/11/14/an-aspnet-subroutine-to-locally-store-the-national-weather-service-current-observations-xml-feeds/</link>
		<comments>https://www.dougv.com/2006/11/14/an-aspnet-subroutine-to-locally-store-the-national-weather-service-current-observations-xml-feeds/#comments</comments>
		<pubDate>Tue, 14 Nov 2006 12:43:29 +0000</pubDate>
		<dc:creator>Doug Vanderweide</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[XML]]></category>
		<category><![CDATA[file system]]></category>

		<guid isPermaLink="false">http://www.dougv.com/blog/2006/11/14/an-aspnet-subroutine-to-locally-store-the-national-weather-service-current-observations-xml-feeds/</guid>
		<description><![CDATA[As promised in my last article, here&#8217;s some ASP.NET 2.0 / VB.NET code to locally store / cache the National Weather Service&#8217;s current observations XML feeds. The first step in this process is to create a directory on your Web server that is writeable. The second is to determine how, and when, you&#8217;ll update your [...]<div class="yarpp">
	<h5>Related Posts</h5>
		<ol>
				<li><a href="https://www.dougv.com/2006/11/11/using-national-weather-service-xml-feeds-with-aspnet-adonet-and-xsl/" rel="bookmark">Using National Weather Service XML Feeds With ASP.NET, ADO.NET And XSL</a> (69.9)</li>
				<li><a href="https://www.dougv.com/2006/11/07/national-weather-service-current-observations-php-script-project-has-first-release/" rel="bookmark">National Weather Service Current Observations PHP Script Project Has First Release</a> (69.4)</li>
				<li><a href="https://www.dougv.com/2006/10/06/free-weather-on-your-website-via-the-national-weather-services-rss-feeds/" rel="bookmark">Free Weather On Your Website Via The National Weather Service&#8217;s RSS Feeds</a> (56.4)</li>
			</ol>
	<p class="note">The numbers inside parentheses are relevance scores. Scoring is based, in order of priority, on title, category, content and tags. The higher the score, the more likely that post relates to this post.
	</div>
]]></description>
			<content:encoded><![CDATA[<p>As promised in my <a href="http://www.dougv.com/2006/11/11/using-national-weather-service-xml-feeds-with-aspnet-adonet-and-xsl/">last article</a>, here&#8217;s some ASP.NET 2.0 / VB.NET code to locally store / cache the National Weather Service&#8217;s <a href="http://www.weather.gov/current_obs">current observations</a> XML feeds.</p>
<p>The first step in this process is to create a directory on your Web server that is writeable. The second is to determine how, and when, you&#8217;ll update your feeds. Then, we can write the code.</p>
<p><span id="more-17"></span></p>
<p>In re: writeable directories on a Web server, the usual cautions:</p>
<ul>
<li>Where possible, you should grant write permissions on directories to specific user accounts you impersonate, or the ASPNET worker process for the machine you are using. Allowing &#8220;Everyone&#8221; or anonymous users to write to directories on your server is dangerous, especially if the directory is in your public HTTP path.</li>
<li>You should place writeable directories outside your HTTP path. So, for example, if your Web files go in a directory named D:Inetpubwwwroot-myserver, you might want to make your writeable directory something like D:NWSXML. Of course, this assumes that you have a Web host that gives you the ability to place files outside a publicly accessible HTTP directory. Most do, some do not, so check.</li>
<li>An alternative, if you can&#8217;t move your XML directory outside your HTTP path or easily impersonate a user on your system, is to obfuscate the writeable directory&#8217;s name. Don&#8217;t name it something obvious, such as &#8220;upload&#8221;; name it something odd and impossible to guess, such as &#8220;7zj32x5p6.&#8221; Then, don&#8217;t link to it from any of your Web pages, make mention of it in any site map or robots.txt files, etc. Treat it like Area 51: Deny its existence, even as you use it for secret purposes.</li>
</ul>
<p>Once you have a directory to which you can write, you&#8217;ll need to determine how you&#8217;re going to go about scraping the XML feeds from weather.gov. You have two options:</p>
<ol>
<li>You can check for the last update time when you have a new visitor, and grab the new file <strong>after</strong> you serve the current request. For lower-traffic sites, this is an acceptable option.</li>
<li>You can automate the retrieval of the file by firing your code off every 60 minutes. This is the better course, but requires additional resources beyond your Web site.</li>
<ol>
<li>One method to automate the XML update is to write the code as a DLL and run it as a scheduled task on your Web server &#8212; something most shared hosting providers either won&#8217;t let you do, or want good money to let you do.</li>
<li>Another option, if you also have <a href="http://en.wikipedia.org/wiki/LAMP_(software_bundle)">LAMP</a>-based hosting, is to write the code into an ASP.NET page on your Windows box, then set up a cron job on your Linux box that instructs Lynx &#8212; the built-in text-only Web browser that comes with most *nix installs &#8212; to visit the ASP.NET page, and thus execute your code. <a href="http://www.15seconds.com/Issue/010905.htm">Here&#8217;s a tutorial on how to set that up</a>.</li>
</ol>
</ol>
<p>I&#8217;m going to provide code here that works per versions 1 and 2.2 above. For both these versions, we are going to need the System.IO and System.Net namespaces; either add them to your page via the Import directive or your web.config file.</p>
<h3>Version 1: Check With Each New Visitor</h3>
<p>Again, checking with each new visitor is best for low-traffic pages; those that are going to see no more than one or two visitors per minute (60-120 visitors per hour). If you&#8217;re getting more traffic than that, you&#8217;re wasting resources, because we need to run uncached file requests on the XML file on your Web server for every visitor, and asking a Web server to pick up and parse a file is one of the most resource-intensive things we can demand.</p>
<p>We&#8217;re going to do this in two parts: A function that will check whether we have a current version of the NWS XML feed stored locally, and return a Boolean; and a subroutine that will get the appropriate XML feed if it&#8217;s time to get an update.</p>
<p>Additionally, we&#8217;re going to add two application keys to the web.config file&#8217;s <appSettings> section. One will be the base URI of the local feed; the other will be the base URL of the NWS feeds.</p>
<pre class="brush: xml; title: ; notranslate">
&lt;configuration&gt;
	&lt;appSettings&gt;
		&lt;add key=&quot;NWSBaseURI&quot; value=&quot;c:pathtolocaldirectory&quot; /&gt;
		&lt;add key=&quot;NWSBaseURL&quot; value=&quot;http://www.weather.gov/data/current_obs/&quot; /&gt;
	&lt;/appSettings&gt;
&lt;/configuration&gt;
</pre>
<p>On to the function. It takes three parameters: A DateTime, which will be the current time; an Integer, which will be the number of minutes between pickups; and a String, which will be the file name of the feed we want to check.</p>
<pre class="brush: vb; title: ; notranslate">
Function CheckLastUpdateTime(ByRef dtTime As DateTime, ByRef intPickup As Integer, ByRef strFile As String) As Boolean
	'set default value for function
	Dim blResult As Boolean = False

	'multiply pickup period by -1, &quot;add&quot; it to the check time
	Dim intUpdate As Integer = intPickup * -1
	Dim dtUpdate As DateTime = dtTime.AddMinutes(intUpdate)

	'get local file
	Dim strPath As String = ConfigurationManager.AppSettings(&quot;NWSbaseURI&quot;).ToString() &amp; strFile
	Dim objFI As New FileInfo(strPath)

	'check that file exists; return false if it does not
	If objFI.Exists() Then
		'compare last write time to update time;
		'if less than update time, return true;
		'else return false
		If objFI.LastWriteTime &lt; dtUpdate Then
			blResult = True
		End If
	End If

	Return blResult
End Function
</pre>
<p>With that function complete, we can now move on to the subroutine that does the updating. What we&#8217;ll specifically do is request the file via WebRequest, then save it via a StreamWriter.</p>
<p>Also, I know that I could use different objects to read and write these files, or work directly from the StreamReader to the StreamWriter, etc. I&#8217;m doing it this way.</p>
<pre class="brush: vb; title: ; notranslate">
Sub UpdateNWSFeed(strFile As String)
	'set path strings
	Dim strLocalPath As String = ConfigurationManager.AppSettings(&quot;NWSbaseURI&quot;).ToString() &amp; strFile
	Dim strRemotePath As String = ConfigurationManager.AppSettings(&quot;NWSbaseURL&quot;).ToString() &amp; strFile

	'Create the WebRequest object;
	'give it 3 seconds to complete
	Dim objRequest as WebRequest = WebRequest.Create(strRemotePath)
	objRequest.Timeout = 3000

	Try
		'get the data as an WebResponse object
		'only overwrite old file if we have a good response
		Dim objResponse As WebResponse = objRequest.GetResponse()

		'convert the data into a string
		Dim objReader As New StreamReader(objResponse.GetResponseStream())
		Dim strResults As String = objReader.ReadToEnd()
		objReader.Close()

		'write results to file
		Dim objWriter As New StreamWriter(strLocalPath)
		objWriter.Write(strResults)
		objWriter.Close()

	Catch wex as WebException
		'You can add your own error-catching code here
		'Response.Write(&quot;Error getting &quot; &amp; strFile &amp; &quot;: &quot; &amp; wex.Message)
	End Try
End Sub
</pre>
<p>By virtue of making a new file with the StreamWriter object, we&#8217;ll overwrite the old file in the same location. Also, I should give full thanks to 4guysfromrolla.com for the <a href="http://aspnet.4guysfromrolla.com/articles/122204-1.aspx">WebRequest code above</a>, which I pirated and fixed to avoid some strong typing issues with Option Strict.</p>
<h3>Use Page_LoadComplete To Invoke Version 1</h3>
<p>We&#8217;ll invoke the Version 1 subroutine with the Page_LoadComplete event, which occurs after all the controls &#8212; including XmlDataSource &#8212; have been loaded onto the page. We don&#8217;t want to interrupt the loading onto the page of the XmlDataSource or the DataGrid / other controls that bind to it, so we wait for them to be on the page before we go off to look for new XML.</p>
<pre class="brush: vb; title: ; notranslate">
Sub Page_LoadComplete(Sender As Object, E As EventArgs)
	If Not Page.IsPostBack Then
		If CheckLastUpdateTime(Now(), 60, &quot;KAUG.xml&quot;) Then
			UpdateNWSFeed(&quot;KAUG.xml&quot;)
		End If
	End If
End Sub
</pre>
<h3>Version 2.2: Running The Code With Crontab / Lynx</h3>
<p>This is the best solution because it requires the least resources: However often you set the job up to run, Lynx fires and updates your feeds, using about the same amount of resources 2-3 visitors to your weather page would use under Version 1, but doing it in a fell swoop and in a manner that doesn&#8217;t impede any visitor&#8217;s experiences.</p>
<p>To use it, just create an ASP.NET page that fires off the UpdateNWSFeed subroutine from Version 1, above, in a Page_Load subroutine. Then, set up your Lynx crontab job to access that page however often you want to update the feeds.</p>
<p>I distribute code under the GNU GPL version 3.</p>
<div class="yarpp">
	<h5>Related Posts</h5>
		<ol>
				<li><a href="https://www.dougv.com/2006/11/11/using-national-weather-service-xml-feeds-with-aspnet-adonet-and-xsl/" rel="bookmark">Using National Weather Service XML Feeds With ASP.NET, ADO.NET And XSL</a> (69.9)</li>
				<li><a href="https://www.dougv.com/2006/11/07/national-weather-service-current-observations-php-script-project-has-first-release/" rel="bookmark">National Weather Service Current Observations PHP Script Project Has First Release</a> (69.4)</li>
				<li><a href="https://www.dougv.com/2006/10/06/free-weather-on-your-website-via-the-national-weather-services-rss-feeds/" rel="bookmark">Free Weather On Your Website Via The National Weather Service&#8217;s RSS Feeds</a> (56.4)</li>
			</ol>
	<p class="note">The numbers inside parentheses are relevance scores. Scoring is based, in order of priority, on title, category, content and tags. The higher the score, the more likely that post relates to this post.</p>
	</div>

	Tags: <a href="https://www.dougv.com/tag/file-system/" title="file system" rel="tag">file system</a><br />
]]></content:encoded>
			<wfw:commentRss>https://www.dougv.com/2006/11/14/an-aspnet-subroutine-to-locally-store-the-national-weather-service-current-observations-xml-feeds/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

