February 15, 2008

Knowledgebase - File Uploading

Knowledgebase - File Uploading

On the boards, I often get questions regarding file uploads. Usually these questions display a lack of knowledge about how a file is treated, and therefore sent, to the server. I have included here a brief tutorial that I hope will help the new programmer in understanding what is happening to the file as it travels from the user's computer to your server.

First off, the form page.
Try this simple form:
<form method="post" action="getfile.cfm" enctype="multipart/form-data">
<input type="file" name="uploadfile" size="40" />
<input type="submit" name="submit" value="Send the File Off" />
</form>
As you can see, this form is extremely simple. On a real upload page you would want at minimum some instructions to the user as well as a description of what this page will be doing.

When a user fills out the form in their local browser and clicks on the submit button, the file will be sent automatically from the user's computer to your server. In the 'form' tag above, the 'method=post' tells the form to send all information in as a 'post' form (not as part of the url string). The 'action' parameter tells the form which page to load after the form is submitted. The 'enctype=multipart/form-data' tells the form that there is a file attached to the form that needs to be sent to the server (without this, the file will not be received by the server at all).

So, here are the steps so far:
  1. The user opens your 'uploadfile.html' page in their browser. (You could have called this page anything 'upload.cfm', 'uf.html', etc)
  2. The user clicks on the 'browse button' in the form and chooses which file on their local computer to send to your server.
  3. The user clicks on the 'submit' button.
  4. The file is sent with the form to your server
  5. Your web server recognizes the 'multipart/form-data' enctype and accepts the file, saving it in a temporary (temp) directory on the web server.
  6. Your web server retrieves the 'action' page (getfile.cfm, could have been called anything as long as it is a CF page) and processes it.
Next, in order to actually use the file, you will need to save it into a 'permanent' directory on your webserver.
Try this simple CF page:
<cffile action = "upload" fileField = "UPLOADFILE" destination = "#GetDirectoryFromPath(expandpath('*.*'))#">
This one command is both 'misleading' as well as very powerful. First the powerful part. This command retrieves the location of the uploaded file from the current location in the temp directory. It moves the file from the temp directory to the destination directory. and then returnes to the coldfusion file a 'cffile structure' filled with information about the file that was just uploaded.
The misleading part? The action says 'upload'. Most people (myself included) read that to mean 'upload from the users computer'. Which can lead the programmer to believe that the file stays on the user's computer until this command is run. Which can also lead the programmer to believe that they have some minute control over the user's computer. What the 'upload' really means is 'copy from temp directory' or 'upload to a permanent directory'.

So we pick up our server activity steps from where we left off above. (web server retrieves the 'action' page)
  1. Since the action page is a .cfm page the web server sends the page to the ColdFusion engine.
  2. The ColdFusion engine sees the cffile upload command and;
    • Copies the file from the temp directory to the specified destination directory
    • If the copy was successful (no 'permission' errors), then the temp directory file is deleted
  3. ColdFusion creates a structure variable called 'cffile' to contain all of the information returned by the cffile action
  4. After ColdFusion engine is done with the file, it is sent back to the webserver to be sent as a 'static' html page to the user's browser.
This is how you upload a file from the user's browser to a directory on your web server. It is important to mention that this is an example of the most simple of cases. There are other actions that you should take when uploading a file. For instance, you should determine if you want the filename to be unique. You should limit the file types to those types you are allowing to be uploaded. You probably don't want anyone to upload a .cgi, .pl, .exe, etc that may 'compromise' your web server.

Something I would like to address, that has come up a few times, is this:
A certain browser (ie) made by the same company that makes a certain popular operating system (windows) sends the user's directory information for the file along with that file to the webserver. You can view it by displaying the 'cffile.CLIENTDIRECTORY' variable, after performing the cffile tag. It is important not to rely on this information. Unless you can guarantee that all browsers in your system will be IE (or at least IE7) then this information will not be available for all browsers. The reason is due to the 'sandbox' rules. These rules are there to protect the user from web sites that might want to do too much and possibly jeopardize the user's system. 'IE' has always broken those rules where it sees fit, but other browsers such as Netscape (now dying off), Firefox, Safari, etc respect the sandbox and don't send that information.

February 12, 2008

Tips & Tricks: Beginner Database Query Cfoutput

Tips & Tricks: Beginner Database Query Cfoutput Many times on the informational boards, I come across new developers who are working with the concepts of displaying database record sets. They are interested on how to display them in a functional way. I have compiled a short list of different methods here where I will show you some simple solutions to formatting your database query results. I will offer 2 solutions for each sample. The simple record set and the ‘grouped’ record set.
  1. Block tags or break tags. This is probably the most familiar method to anyone entering ColdFusion. I have shown both of these examples using the HTML paragraph tags, but you can substitute for any line-breaking code. (<br />, <div></div>. etc)
    Regular record set:
    <cfoutput query=”[yourqueryname]”>
    <p>#[columnname]#</p>
    </cfoutput>
    Grouped record set:
    <cfoutput query=”[yourqueryname]”>
    #[sectionname]#<br>
    <cfoutput>
    <p>#[columnname]#</p>
    </cfoutput>
    </cfoutput>
  2. Tables - Horizontal. After working with HTML for a while you will recognize this code as a simple list/report layout.
    Regular record set:
    <table>
    <cfoutput query=”[yourqueryname]”>
    <tr>
    <td>#[columnname]#</td>
    </tr>
    </cfoutput>
    </table>
    Grouped record set:
    <table>
    <cfoutput query=”[yourqueryname]”>
    <tr>
    <th>#[sectionname]#</th>
    </tr>
    <cfoutput>
    <tr>
    <td>#[columnname]#</td>
    </tr>
    </cfoutput>
    </cfoutput>
    </table>
  3. Tables - Vertical. This is similar to the system above with the addition of a ‘counter’. What you do is decide how many vertical results you want to display before ‘breaking’ to the next line of results. I have used 4 results, but choose what you need. I have moved the ‘<tr>’ to the outside of the cfoutputs and have added a to determine if the code should insert a table row termination and start tag. I had previously left out the code that I am adding using this editing color. I had left it out intentionally to keep the 'concept' of the process simple and clear for the new developer. It has been brought to my attention that it can end in badly formed HTML (this was the least of my concerns).
    Regular record set:
    <table>
    <tr>
    <cfoutput query=”[yourqueryname]”>
    <td>#[columnname]#</td>
    <cfif currentrow mod 4 eq 0 and currentrow neq recordcount></tr><tr></cfif>
    </cfoutput>
    </tr>
    </table>
    In the grouped example, I have added an additional cfif to check to see if the loop ‘did not’ end on a multiple of 4 AND it is not the very first record in the query. I have also added a variable that carries the row count of every breaking <tr> in the data displays so that it can be checked against the currentrow in the 'group' and not print two recurring breaking <tr> groups together.
    Grouped record set: <table>
    <tr>
    <cfoutput query=”[yourqueryname]”>
    <cfif currentrow mod 4 neq 0 and currentrow neq 1 and currentrow neq lastbreakrow ></tr><tr></cfif>
    <th colspan=”4”>#[sectionname]#</th>
    </tr>
    <tr>
    <cfoutput>
    <td>#[columnname]#</td>
    <cfif currentrow mod 4 eq 0> </tr><tr></cfif>
    </cfoutput>
    </cfoutput>
    </tr>
    </table>
  4. Tables – Horizontal AND Vertical (Newspaper). This is similar to the system above however instead of running the records left to right, we will run them top to bottom for ½ the records and then start at the top again for the 2nd half. (you can also do this for thirds, fourths, fifths, etc).
    Regular record set: <table>
    <tr>
    <td>
    <cfoutput query=”[yourqueryname]”>
    #[columnname]#
    <cfif currentrow eq round(recordcount / 2)></td></tr><tr><td><cfelse><br /></cfif>
    </cfoutput>
    </td>
    </tr>
    </table>
    Grouped record set:
    <table>
    <tr>
    <td>
    <cfoutput query=”[yourqueryname]”>
    <p>#sectionname]#</p>
    <cfoutput>
    <p>#[columnname]#</p>
    <cfif currentrow eq round(recordcount / 2)></td></tr><tr><td></cfif>
    </cfoutput>
    </tr>
    </cfoutput>
    </table>
This is certainly not the only methods available, nor will they be the best formatted versions for your needs, but they should hopefully help you get pointed in the right direction to have your data displayed the way you wanted it.