segunda-feira, 15 de outubro de 2007

Uploading files with Caché and CSP

Uploading files with Caché and CSP - or... My first CSP

As I already said here (or not), my work is almost all done with Intersystems' Ensemble (and consequently with Caché, since Ensemble is built upon it). Therefore, I am not generally involved with user interfaces and these kind of stuff, but this week I needed to do a web page to upload files to my server. So, lets learn some CSP - or Caché Server Pages. In fact, I didnt reaaaally learned them, I just got the stuff to do what I needed. And I thought it'd be nice to share the experience with you ;)

As CSP Introduction page says, you have two paths if you´re willing to work with CSPs: you can write Html pages and embed them with csp tags, much like JSP (Java Server Pages) or PHP, saving them with .csp extension; or you can write a Caché's class, where you can output the html, the same approach of Java Servlets.

Within examples (in namespace SAMPLES of Caché) there is a .csp file with an example of upload (as you can guess, it is csp/samples/upload.csp). Taking this as base, I adapted the necessary to my needs.



(Upload example page, and the resulting page after an upload)

Well, as I couldn't place the source code here at blogger, in a good way, I will put an image, and let a link to source code text.

(Image with source code)

The logic behind this csp page is very simple: when you open this page, calling from a parent window, you pass the request parameter 'campo', if not, it will show you nothing. Then, the csp code checks if a file was uploaded, if not, it renders an html form with fields for upload (the form's submit points to the same csp); if the file was already uploaded, it sets the file name to an html field from the parent window who called this csp, and shows a link to close this current window.

Lets view with more details some of this.

<CSP:CLASS INCLUDES="SOMEINCFILETOINCLUDE">

Here we point to an .INC file (without the inc extension) that we will use in the page, i.e., we are including this INC file. In Caché, INC files are used to define macros (like C/C++ macros), and are very used to both implement routines and define constants.

/***********************************

<csp:if condition='($data(%request.Data("campo",1)))'>

Here we show an specific tag from csp, which means a condition, the famous 'if'. The condition is the value of attribute 'condition', of 'csp:if' tag, and it may contain COS (Caché Object Script) code, returning true or false. In our code, we are just checking if the http request (%request object) has as one its parameters a field named 'campo'. More info about %request object can be found at %CSP.Request class doc page.

/***********************************

<csp:if condition='($data(%request.MimeData("FileStream",1)))'>

Other if, but a little different. This time we do not check the http request parameter with %request.Data, but with %request.MimeData. The reason is because this time we are checking if a file was sent, using MIME.

/***********************************


File uploaded: <b>#(%request.MimeData("FileStream",1).FileName)#</b><br>
Size: <b>#(%request.MimeData("FileStream",1).Size)#</b><br>
Type: <b>#(%request.MimeData("FileStream",1).ContentType)#</b><br>


When we sent a file, %request.MimeData("PARAMETERNAME",1) return an object %CSP.BinaryStream. The above code shows on screen some info that we can get from this stream object. Note that the values to be rendered on the screen are between '#(' and ')#'.

/***********************************

<script language="Cache" runat="server">

Here we declare a code block of COS to be executed at the server. In this block, if we want something to be shown in the resulting html, we must write at the standard output, using Write command.

/***********************************

set dname = $$$SomeDirectory

Still within the block we opened above, here we create and set a value to the variable 'dname'. This value is a macro, which is indicated by the three $ ($$$SomeDirectory). This macro should be defined in some of .INC files we imported, like commented above.

/***********************************


Set stream=##class(%FileBinaryStream).%New()
Set stream.Filename= dname _ fname

do stream.CopyFrom(%request.MimeData("FileStream",1))
do stream.Flush()
do stream.SaveStream()


Here we create an stream to a file (class %FileBinaryStream), and we set it to variable 'stream'. Then we set the file's name, and use the method CopyFrom, to copy the content of the stream sent through http, to the file.

/***********************************

<csp:else>

Here we finish the 'if' block, and start the 'else' block.

/***********************************

<form enctype="multipart/form-data" method="post" action="este_arquivo_csp.csp">
Arquivo: <input type=file size=30 name=FileStream>
<p>

<script language="Cache" runat="server">
New bytes
Set bytes="<input type=""hidden"" name=""campo"" value=""" _ %request.Data("campo",1) _ """ > "
Write bytes,!
</script>

<p> <ul><input type="submit" value="Upload file"></ul> <p>
</form>


The 'else' block has the definition of an html form, to upload the file to the server. Note that inside de html form definition, we mix some Caché code, to place a hidden field within the form, to keep the value of parameter 'campo', which was passed. This is one solution, another one (maybe more 'elegant') would be use sessions, but as this is very simple case, I didn't check how to manage sessions with CSPs (but of course, you can explore it yourself).

/***********************************

As this post got bigger than I expected, I will finish it here. Within CSP file there are other features (as some javascript, and COS directory apis), but I will not comment them now. Besides, as I simplified the csp a lot, and I removed all stylish stuff. For you to use it, you will have to change some things, like the import of .inc file.

That's all folks.

1 comentários:

Anônimo disse...

Very Interesting!
Thank You!