Streaming the images allows us to hide the true name and source of the images from any robot attempting to automatically pass our CAPTCHA test. I'm using files, you could use a database or another method.
This example simply demonstrates that classic ASP is quite capable of streaming images. I have also improved on his version by increasing the number of available image choices, making the images easier to see, and ensuring that no image is used twice on a page.
For a character based CAPTCHA example in classic ASP (not using streaming) see this example. For an example of reading files as an include with pure JavaScript without using an <IFRAME> or a .js extension, (another thing you supposedly can not do, see
this article.)
Click the three pictures of "cats" to verify.
NOTE: All images are freely available content available from Wikimedia Commons. [Images for Captcha]
<% Option Explicit Session.CodePage=65001 Response.Charset="UTF-8" ' no browser caching of this page Response.Expires=-1 Response.ExpiresAbsolute = Now() - 1
' do not allow proxy servers to cache this page !! to be used on all pages Response.CacheControl="private" Response.CacheControl="no-cache" Response.CacheControl="no-store"
' A temporary array used to get unique random values. ' i.e. we pick a random value, remove it from the array, and on ' subsequent random picks, we reject the value if already removed ' from the array.
Dim Unique(9) Unique(1)=1 Unique(2)=2 Unique(3)=3 Unique(4)=4 Unique(5)=5 Unique(6)=6 Unique(7)=7 Unique(8)=8 Unique(9)=9
function getRndUnique Dim idx idx=0 While (idx=0) idx = Int(8 * Rnd)+1 if Unique(idx)>0 then idx = Unique(idx) Unique(idx)=0 else idx=0 end if Wend
getRndUnique = idx end function
function getCorrect ' choose three unique values for the image CAPTCHA ' the values will be comma separated in ascending order. Dim tmp, idx, out tmp = getRndUnique & "," & getRndUnique & "," & getRndUnique for idx=1 to 9 if Unique(idx)=0 then out = out & idx & "," end if next getCorrect = Left(out, Len(out)-1) end function
' another temporary array for getting unique images on each page
' with no repeated images
Dim UniqueImg(18)
UniqueImg(1)=1
UniqueImg(2)=2
UniqueImg(3)=3
UniqueImg(4)=4
UniqueImg(5)=5
UniqueImg(6)=6
UniqueImg(7)=7
UniqueImg(8)=8
UniqueImg(9)=9
UniqueImg(10)=10
UniqueImg(11)=11
UniqueImg(12)=12
UniqueImg(13)=13
UniqueImg(14)=14
UniqueImg(15)=15
UniqueImg(16)=16
UniqueImg(17)=17
UniqueImg(18)=18
function notUsed
Dim idx for idx=1 to 18 if UniqueImg(idx)>0 then notUsed = idx UniqueImg(idx)=0 Exit For end if next end function
function getRndUniqueImg Dim idx idx=0 While (idx=0) idx = Int(18 * Rnd)+1 if UniqueImg(idx)>0 then idx = UniqueImg(idx) UniqueImg(idx)=0 else idx=notUsed end if Wend getRndUniqueImg = idx end function
Randomize
' we use session variables so the image streaming page
' will know what image to return
Session("img1") = getRndUniqueImg
Session("img2") = getRndUniqueImg
Session("img3") = getRndUniqueImg
Session("img4") = getRndUniqueImg
Session("img5") = getRndUniqueImg
Session("img6") = getRndUniqueImg
Session("img7") = getRndUniqueImg
Session("img8") = getRndUniqueImg
Session("img9") = getRndUniqueImg
' The correct image choices will be the three numbers we put in correct.
Session("correct") = getCorrect
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="author" content="Roderick Divilbiss">
<meta name="copyright" content="© 2005-2010 Roderick Divilbiss">
<meta name="MSSmartTagsPreventParsing" content="TRUE">
<title>Image Captcha :: Classic ASP Image Streaming</title>
<script type="text/javascript">
// to keep track of the image clicks
var clicked=new Array();
clicked[1]=false;
clicked[2]=false;
clicked[3]=false;
clicked[4]=false;
clicked[5]=false;
clicked[6]=false;
clicked[7]=false;
clicked[8]=false;
clicked[9]=false;
function updateClick() {
// put the values which are clicked into our form
var tmp='';
for (var idx=1;idx<=9;idx++) {
if (clicked[idx]) {
tmp+=idx+',';
} }
if (tmp.substr(tmp.length-1,1)==',') { tmp = tmp.substr(0,tmp.length-1); }
document.getElementById('value1').value=tmp;
}
function cMe(objI) {
var idx=parseInt(objI.id.substr(3,1)); if (objI.style.borderColor=='') { // never clicked objI.style.borderColor='red'; clicked[idx]=true; updateClick(); }else if (objI.style.borderColor=='black') { // clicked after being unclicked objI.style.borderColor='red'; clicked[idx]=true; updateClick(); } else { // unclicked
objI.style.borderColor='black';
clicked[idx]=false;
updateClick();
}
// auto submit on three clicks
// you could remove this and add a submit button
if (document.getElementById('value1').value.length==5) { var myForm = document.getElementById('theForm'); myForm.submit(); } }
</script>
<style type="text/css">
#container {
width: 350px;
height: 300px;
}
#iarray li {
float:left;
margin-right:10px;
margin-bottom: 10px;
list-style-type:none
}
.dynamicImg {
border:solid 2px;
border-color:black;
border-style:solid;
}
</style>
</head>
<body>
<!-- the container division allows us to set a width-->
<div id="container">
<form id="theForm" name="theForm" method="post" action="Image-CAPTCHA-verify.asp">
<ul id="iarray">
<li><img class="dynamicImg" id="img1"
src="streamImage.asp?c=1"
alt="verification image"
onclick="cMe(this);" width="75" height="75"></li>
<li><img class="dynamicImg" id="img2"
src="streamImage.asp?c=2"
alt="verification image"
onclick="cMe(this);" width="75" height="75"></li>
<li><img class="dynamicImg" id="img3"
src="streamImage.asp?c=3"
alt="verification image"
onclick="cMe(this);" width="75" height="75"></li>
<li><img class="dynamicImg" id="img4"
src="streamImage.asp?c=4"
alt="verification image"
onclick="cMe(this);" width="75" height="75"></li>
<li><img class="dynamicImg" id="img5"
src="streamImage.asp?c=5"
alt="verification image"
onclick="cMe(this);" width="75" height="75"></li>
<li><img class="dynamicImg" id="img6"
src="streamImage.asp?c=6"
alt="verification image"
onclick="cMe(this);" width="75" height="75"></li>
<li><img class="dynamicImg" id="img7"
src="streamImage.asp?c=7"
alt="verification image"
onclick="cMe(this);" width="75" height="75"></li>
<li><img class="dynamicImg" id="img8"
src="streamImage.asp?c=8"
alt="verification image"
onclick="cMe(this);" width="75" height="75"></li>
<li><img class="dynamicImg" id="img9"
src="streamImage.asp?c=9"
alt="verification image"
onclick="cMe(this);" width="75" height="75"></li>
</ul>
<p><input type="hidden" id="value1" name="value1" size="20"></p>
</form>
</div>
</body>
</html>
<%
Option Explicit
Dim img, idx, param, correct
correct = Session("correct")
param = Request.QueryString("c")
' note the image URL on the form has a parameter
' which has no association with which image is streamed
' and the parameter is only valid for a particular session.
' I am choosing three of eighteen possible cats. You could
' make this exceedingly large if you were worried about
' harvesting...which I am not. A Blog is not Fort Knox.
Dim validImage(18)
validImage(0) = "NotAvailable.jpg"
validImage(1) = "cat1.jpg"
validImage(2) = "cat2.jpg"
validImage(3) = "cat3.jpg"
validImage(4) = "cat4.jpg"
validImage(5) = "cat5.jpg"
validImage(6) = "cat6.jpg"
validImage(7) = "cat7.jpg"
validImage(8) = "cat8.jpg"
validImage(9) = "cat9.jpg"
validImage(10) = "cat10.jpg"
validImage(11) = "cat11.jpg"
validImage(12) = "cat12.jpg"
validImage(13) = "cat13.jpg"
validImage(14) = "cat14.jpg"
validImage(15) = "cat15.jpg"
validImage(16) = "cat16.jpg"
validImage(17) = "cat17.jpg"
validImage(18) = "cat18.jpg"
Dim otherImage(18)
otherImage(0) = "NotAvailable.jpg"
otherImage(1) = "not18.jpg"
otherImage(2) = "not2.jpg"
otherImage(3) = "not16.jpg"
otherImage(4) = "not4.jpg"
otherImage(5) = "not14.jpg"
otherImage(6) = "not6.jpg"
otherImage(7) = "not7.jpg"
otherImage(8) = "not8.jpg"
otherImage(9) = "not9.jpg"
otherImage(10) = "not10.jpg"
otherImage(11) = "not11.jpg"
otherImage(12) = "not12.jpg"
otherImage(13) = "not13.jpg"
otherImage(14) = "not5.jpg"
otherImage(15) = "not15.jpg"
otherImage(16) = "not3.jpg"
otherImage(17) = "not17.jpg"
otherImage(18) = "not1.jpg"
function inCorrect(num)
Dim tmp, out
out = false
tmp = Split(Session("correct"),",")
for idx = 0 to UBound(tmp)
if CInt(tmp(idx))=CInt(num) then
out = true
end if
next
inCorrect = out
end function
' A little protection against calling the page without
' coming from the correct image CAPTCHA page.
' e.g. attempt to stop harvesting of images or
' associating any image with a URL.
if param & "x" = "x" then
img = "NotAvailable.jpg"
else
idx = Session("img" & param) if (idx < 1) or (idx="") or (idx & "x"="x") then img = "NotAvailable.jpg"
else if InStr(correct, param)>0 then img = validImage(idx) validImage(idx)="NotAvailable.jpg" Session("img" & param)=0 else img = otherImage(idx) end if end if end if
Dim objStream
Set objStream = Server.CreateObject("ADODB.Stream")
'Open a image file
objStream.Type = 1 ' adTypeBinary
objStream.Open
objStream.LoadFromFile Server.MapPath(img)
'Output the contents of the stream object
Response.ContentType = "image/jpeg"
Response.BinaryWrite objStream.Read
objStream.close
Set objStream=nothing
%>
Date Validation Using JavaScript .
Cross-Browser Clipboard Copy .
Loading Images With Remote Scripting .
Why JavaScript In Hyperlinks Is Bad .
Change The Submit Button To Show Waiting For AJAX Response .
European Date Validation Using JavaScript .
Database Results To Client Side Array .
Reading Files With JavaScript .
AJAX For Plain Text And HTML .