They say you learn something new every day.

I spent yesterday morning working on a small web coding project. It’s for a relatively low traffic website that isn’t updated very often, but contains a gallery of pictures.

Now, the standard way to do something like this would be to use a database and a server side scripting language; the old:

$var = $_GET[q] ;

$result = mysql_query(“SELECT * FROM Database WHERE ID=’$var’”);

while($row = mysql_fetch_array($result)) { echo $row[‘Content’]; }

I was about to start doing this sort of thing, when I was reminded of something I wrote a few months ago. I had to do the same thing as this, but I didn’t have a web or database server. It was the standard situation: asked the impossible, need it now and, oh, since you ask, the budget is nothing.

The solution was to write some vbscript to render all the pages in advance, and then dump them on a shared drive.

It occurred to me that this system could probably be used elsewhere. For sites that are largely the same for most of the time, this would be much better than querying a database to get the data. It’s like compiling code before releasing.

  1. More secure. There’s no risk of SQL injections, since there is no SQL!
  2. More robust. It’s easier to test the code, since you’ve generated every possible page.
  3. More reliable. It’s also not going to go down if you have server problems.
  4. Portable. Since all your pushing out to the webserver is a bunch of flat html files, you can easily move them around.
  5. Faster. You completely cut out the server side request processing and all the database calls. All that needs to happen is to serve the pages. You can’t make a website any faster.

My old favourite, Jeff Atwood talks about performance being a feature, which is why they put the rendering time on each page of StackOverflow:

Stack Overflow Performance

Obviously, my system won’t work for every type of site: the site would need to have content that is rarely updated.

I have nothing against SQL, but I’ve read about projects like NoSQL without ever using them. It seems more effort than it’s worth given the low compatibility.

It occurs to me that you could probably write something to replace most SQL implementations that simply writes your edits out live to a flat html page. Obviously there’d be some issues about concurrency and locking, but nothing that couldn’t be easily solved. I suspect the biggest challenge would be searching.

Anyway, those are just idle thoughts, and I’m getting ahead of myself a bit. I decided to write my script in vbscript, not because I’m a big fan of it, but because it’s installed on every Windows machine. Jeff Atwood (again, if only he weren’t so right for so much of the time) made a good point about customization:

[…] if I learn to rely on a highly custom desktop, I’ve crippled my ability to work on a stock Windows XP or Win2k3 box. I can certainly bring my favorite apps with me on a USB key, but I also have to spend time setting them up on each box I touch.

Interestingly during the course of writing my script, I learnt a few unexpected things. Firstly, that pressing Ctrl + D in notepad2 duplicates the current line. Which is surprisingly useful. I’ve done this by mistake before, but now I can do it on purpose too.

Notepad2

I also put together this bit to round up a decimal to the nearest whole number:

Int(n) – CBool(CDbl(n) CLng(n))

By default, rounding rounds up or down to the nearest number, and I needed it to always round up.

The second thing was this script to sort an array:

FOR a = UBound(Array) – 1 TO 0 Step -1
FOR j= 0 TO a
IF Array(j)>Array(j+1) THEN
temp = Array(j+1)
Array(j+1) = Array(j)
Array(j) = temp
END IF
NEXT
NEXT

I have to admit, I pinched this from StackOverflow, although Googling it seems like a standard Bubble sort for Vbscript.

The final thing was this bit of script (courtesy of the scripting guys) to remove a trailing line break from a file:

  IF Right(PicList, 2) = vbCrLf THEN
PicList = Left(PicList, Len(PicList)2)
END IF

Thinking about this now, it could be a problem if there are two trailing line breaks, but since I’m providing the input I’m not too worried about this. The thing to do would probably be to remove duplicate line breaks first, and then run this.

Other than that, the code was straightforward:

‘ Code to pre-render website

‘ 02/01/2011

‘ Version 1  SET FSO           = CreateObject(“Scripting.FilesystemObject”)

‘ Open input files and templates

SET Pictures      = FSO.OpenTextFile(“titles.txt”,1)

PicList           = Pictures.ReadAll

Pictures.Close

SET Template      = FSO.OpenTextFile(“MASTER_picture.html”,1)

PicTemplate       = Template.ReadAll

Template.Close

SET Template      = FSO.OpenTextFile(“MASTER_full.html”,1)

FullPicListing    = Template.ReadAll

Template.Close

SET Template      = FSO.OpenTextFile(“MASTER_gallery.html”,1)

GalleryTemplate   = Template.ReadAll

Template.Close

‘ Check whether there’s a trailing line break and remove it

IF Right(PicList, 2) = vbCrLf THEN

PicList = Left(PicList, Len(PicList)2)

END IF

EachPicture       = Split(PicList,vbCrLf)

FinalPic          = ubound(EachPicture) + 1

FinalGallery      = Int(FinalPic/6)CBool(CDbl(FinalPic/6) <> CLng(FinalPic/6))

ArrayIndex        = 1

‘Counter to count each picture in each gallery

GalNumber         = 1

for EACH entry IN EachPicture

Parts           = split(entry,” “)

Number          = Parts(1)

FileName        = “picture” & Number & “.html”

Title           = Parts(0)

NEXTPic         = Number + 1

PreviousPic     = Number – 1

‘ Set the last picture to loop round to the first

IF NEXTPic      = FinalPic + 1 THEN NEXTPic = 1

‘Set the first picture to loop round to the last

IF PreviousPic  = 0 THEN PreviousPic = FinalPic

‘ Divide by 6 and THEN round up regardless of remainder

Gallery         = Int(ArrayIndex/6)CBool(CDbl(ArrayIndex/6) <> CLng(ArrayIndex/6))

NEXTGal         = Gallery + 1

PreviousGal     = Gallery – 1

GalleryName     = “gallery” & Gallery & “.html”

‘ Set the last gallery to loop round to the first

IF NEXTGal      = FinalGallery + 1 THEN NEXTGal = 1

‘Set the first gallery to loop round to the last

IF PreviousGal  = 0 THEN PreviousGal = FinalGallery

‘ Replace the template with information for each picture

PictureFile     = Replace(PicTemplate,“[NUMBER]”,Number)

PictureFile     = Replace(PictureFile,“[TITLE]”,Title)

PictureFile     = Replace(PictureFile,“[PREVIOUS]”,PreviousPic)

PictureFile     = Replace(PictureFile,“[NEXT]”,NEXTPic)

PictureFile     = Replace(PictureFile,“[GALLERY]”,Gallery)

‘ Output the picture file

SET OutputFile  = FSO.OpenTextFile(FileName,2,TRUE,0)

OutputFile.WriteLine PictureFile

OutputFile.close

‘ If this is a new gallery load the template and start replacing

IF GalNumber    = 1 THEN

GalleryFile   = REPLACE(GalleryTemplate,“[NUMBER]”,Gallery)

GalleryFile   = REPLACE(GalleryFile,“[PREVIOUS]”,PreviousGal)

GalleryFile   = REPLACE(GalleryFile,“[NEXT]”,NEXTGal)

END IF

‘ It needs to add the pictures regardless of which gallery file it is

GalleryFile     = REPLACE(GalleryFile,“[“ & GalNumber & “Pic]”,Number)

GalleryFile     = REPLACE(GalleryFile,“[“ & GalNumber & “PicTitle]”,Title)

SET OutputFile  = FSO.OpenTextFile(GalleryName,2,TRUE,0)

OutputFile.WriteLine GalleryFile

OutputFile.close

IF GalNumber    = 6 THEN

‘Set it to 0 so when the counter adds 1 it goes to 1 to start the loop again

GalNumber     = 0

END IF

‘Add one to Gal Number FOR NEXT loop

GalNumber       = GalNumber + 1

ArrayIndex      = ArrayIndex + 1

NEXT

‘ This is a slightly messy hack to remove the template parts from the final gallery

SET OutputFile    = FSO.OpenTextFile(“gallery” & FinalGallery & “.html”,1)

DO UNTIL OutputFile.AtEndOfStream

strLine         = OutputFile.ReadLine

‘If the line contains a [ THEN it removes it

IF InStr(strLine, “[“) = 0 THEN strNewContents = strNewContents & strLine & vbCrLf

LOOP

OutputFile.Close

‘ Writes the new final gallery file on top of the old one.

SET OutputFile    = FSO.OpenTextFile(“gallery” & FinalGallery & “.html”,2)

OutputFile.Write strNewContents

OutputFile.Close
‘ Sort the array into alphabetical order FOR the full picture listings page

FOR a = UBound(EachPicture)1 TO 0 Step –1

FOR j= 0 TO a

IF EachPicture(j)>EachPicture(j+1) THEN

temp              = EachPicture(j+1)

EachPicture(j+1)  = EachPicture(j)

EachPicture(j)    = temp

END IF

NEXT

NEXT

‘ Generate the picture listing data

for EACH entry IN EachPicture

Parts           = split(entry,” “)

PicListingData  = PicListingData & “<A href=”“picture” & Parts(1) & “.html”“>”& Parts(0) &“</a><BR><BR>”

NEXT

FullPicListing    = REPLACE(FullPicListing, “[PICTURES]”, PicListingData)

SET OutputFile    = FSO.OpenTextFile(“full.html”,2,TRUE,0)

OutputFile.WriteLine FullPicListing

OutputFile.close

‘Copy Gallery1 file into Gallery because link points to gallery.html

FSO.CopyFile “gallery1.html”, “gallery.html”

wscript.echo “Done”

 

I’ve pasted it here in full so this page can act as a bit of a code repository. I’ve been very bad at source control in the past.

While looking for a way to post this code so that it would be readable, I came across quickhighlighter.com. It’s quite a nice site that converts the code into css (inline or otherwise). Seems to work here, although obviously, I have a proper with my page being so narrow. But maybe that’ll encourage me to shorten my code lines.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Tag Cloud

%d bloggers like this: