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.
- More secure. There’s no risk of SQL injections, since there is no SQL!
- More robust. It’s easier to test the code, since you’ve generated every possible page.
- More reliable. It’s also not going to go down if you have server problems.
- Portable. Since all your pushing out to the webserver is a bunch of flat html files, you can easily move them around.
- 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:

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.

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.