root/trunk/website/org/captcha/captchaService.cfc @ 5

Revision 5, 33.7 kB (checked in by DanWilson, 17 years ago)

Initial Commit Of ModelGlue? Website (upgrade to blogcfc 511)

RevLine 
[5]1<!---
2Copyright: (c) 2007 Maestro Publishing, LLC
3Author: Peter J. Farrell (pjf@maestropublishing.com)
4License:
5Copyright 2007 Maestro Publishing, LLC
6
7Licensed under the Apache License, Version 2.0 (the "License");
8you may not use this file except in compliance with the License.
9You may obtain a copy of the License at
10
11    http://www.apache.org/licenses/LICENSE-2.0
12
13Unless required by applicable law or agreed to in writing, software
14distributed under the License is distributed on an "AS IS" BASIS,
15WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16See the License for the specific language governing permissions and
17limitations under the License.
18
19$Id: captchaService.cfc 6056 2007-05-13 20:16:22Z pfarrell $
20--->
21<cfcomponent
22        displayname="captchaService"
23        output="false"
24        hint="Performs captcha functionality.">
25       
26        <!---
27        PROPERTIES
28        --->
29        <cfset variables.instance = StructNew() />
30        <cfset variables.packageVersion = "0.1 Beta" />
31
32        <!---
33        INITIALIZATION / CONFIGURATION
34        --->
35        <cffunction name="init" access="public" returntype="captchaService" output="false"
36                hint="Initializes the service.">
37                <cfargument name="configBean" type="captchaServiceConfigBean" required="false"
38                        default="#CreateObject("component", "captchaServiceConfigBean").init()#" />
39                <cfargument name="configFile" type="string" required="false"
40                        default="" />
41               
42                <!--- Set arguments --->
43                <cfset setConfigBean(arguments.configBean) />
44                <cfif Len(arguments.configFile)>
45                        <cfset setConfigFile(arguments.configFile) />
46                </cfif>
47               
48                <cfreturn this />
49        </cffunction>
50       
51        <cffunction name="setup" access="public" returntype="void" output="false"
52                hint="Setups the service after dependencies have been injected.">
53
54                <!--- Load the XML if configFile is not NULL --->
55                <cfif Len(getConfigFile())>
56                        <cfset loadXML() />
57                </cfif>
58
59                <!--- Setup the hash reference cache --->
60                <cfset  setupHashReferenceCache() />
61        </cffunction>
62
63        <!---
64        PUBLIC FUNCTIONS - GENERAL
65        --->
66        <cffunction name="createHashReference" access="public" returntype="struct" output="false"
67                hint="Creates a hash reference in the service and returns the results.">
68                <cfargument name="text" type="string" required="false" default="#getRandString()#"
69                        hint="Text to create Captcha with. Defaults random string as defined in config file." />
70               
71                <cfset var results = StructNew() />
72
73                <!--- Create the results struct --->
74                <cfset results.type = "hash" />
75                <cfset results.text = arguments.text />
76                <cfset results.hash = createHash() />
77                <cfset results.width = getConfigBean().getWidth() />
78                <cfset results.height = getConfigBean().getHeight() />
79               
80                <!--- Set the hash reference to the cache --->
81                <cfset setHashReference(results.hash, results.text) />
82
83                <cfreturn results />           
84        </cffunction>
85
86        <cffunction name="createCaptchaFromHashReference" access="public" returntype="struct" output="false"
87                hint="Creates a captcha to the desired from a hash reference.">
88                <cfargument name="type" type="string" required="true"
89                        hint="Captcah output type. Accepts file or stream." />
90                <cfargument name="hash" type="string" required="true"
91                        hint="Hash reference to retrieve from cache." />
92                <cfreturn createCaptcha(arguments.type, getHashReference(arguments.hash), arguments.hash) />           
93        </cffunction>
94
95        <cffunction name="validateCaptcha" access="public" returntype="boolean" output="false"
96                hint="Validates a captcha by hash and user response text.">
97                <cfargument name="hash" type="string" required="true" />
98                <cfargument name="text" type="string" required="true" />
99                <cfreturn NOT CompareNoCase(getHashReference(arguments.hash, TRUE), arguments.text) />
100        </cffunction>
101               
102        <!---
103        PUBLIC FUNCTIONS - UTILS
104        --->
105        <cffunction name="getVersion" access="public" returntype="string" output="false"
106                hint="Gets the current version of LylaCAPTCHA.">
107                <cfreturn variables.packageVersion />
108        </cffunction>
109       
110        <cffunction name="getAvailableFontNames" access="public" returntype="array" output="false"
111                hint="Returns an array of all available system fonts. This is useful when deciding on fonts to use for captcha configuration.">
112               
113                <cfset var allFonts = CreateObject("java", "java.awt.GraphicsEnvironment").getLocalGraphicsEnvironment().getAllFonts() />
114                <cfset var fontArray = ArrayNew(1) />
115                <cfset var i = "" />
116                               
117                <cfloop from="1" to="#ArrayLen(allFonts)#" index="i">
118                        <cfset ArrayAppend(fontArray, allFonts[i].getName()) />
119                </cfloop>
120
121                <cfreturn fontArray />
122        </cffunction>
123       
124        <!---
125        PROTECTED FUNCTIONS - GENERAL
126        --->
127        <cffunction name="createCaptcha" access="private" returntype="struct" output="false"
128                hint="Creates a captcha to the desired stream.">
129                <cfargument name="type" type="string" required="true"
130                        hint="Captcah output type. Accepts file or stream." />
131                <cfargument name="text" type="string" required="true" />
132                <cfargument name="hash" type="string" required="true" />
133
134                <cfset var stream = "" />
135                <cfset var results = StructNew() />
136                <cfset var tempFileLocation = "" />
137
138                <!--- Create the common results --->
139                <cfset results.text = arguments.text />
140                <cfset results.hash = arguments.hash />
141                <cfset results.width = getConfigBean().getWidth() />
142                <cfset results.height = getConfigBean().getHeight() />
143
144                <!--- Create the results struct --->
145                <cfif arguments.type IS "stream">
146                        <!--- Create the stream --->
147                        <cfset stream = createObject("java", "java.io.ByteArrayOutputStream").init() />
148                       
149                        <!--- Create the type specific results --->
150                        <cfset results.type = "stream" />
151
152                        <!--- Write the captcha with the selected stream --->
153                        <cfset writeToStream(stream, arguments.text) />                 
154                        <cfset results.stream = stream.toByteArray() />
155                <cfelseif arguments.type IS "file">
156                        <!--- Create the stream --->
157                        <cfset tempFileLocation = getFileLocation() />
158                        <cftry>
159                                <cfset stream = createObject("java", "java.io.FileOutputStream").init(tempFileLocation) />
160                                <cfcatch type="any">
161                                        <cfthrow type="captchaService.invalidOutputDirectory"
162                                                message="Could not create file output stream. The output directory probably is not a valid path. Please check that it exists."
163                                                detail="Output Directory:#tempFileLocation#" />
164                                </cfcatch>
165                        </cftry>
166
167                        <!--- Create the type specific results --->
168                        <cfset results.type = "file" />
169                        <cfset results.fileLocation = tempFileLocation />
170                        <cfset results.fileDirectory = GetDirectoryFromPath(tempFileLocation) />
171                        <cfset results.fileName = GetFileFromPath(tempFileLocation) />
172
173                        <!--- Write the captcha with the selected stream --->
174                        <cfset writeToStream(stream, arguments.text) />
175                        <cfset stream.flush() />
176                        <cfset stream.close() />
177                <cfelse>
178                        <cfthrow type="captchaService.invalidType"
179                                message="The argument type must be stream or file."
180                                detail="Passed type=#arguments.type#" />
181                </cfif>
182               
183                <cfreturn results />
184        </cffunction>
185
186        <cffunction name="writeToStream" access="private" returntype="void" output="false"
187                hint="Writes a captcha to an outputStream.">
188                <cfargument name="outputStream" type="any" required="true" />
189                <cfargument name="text" type="string" required="true" />
190
191                <cfset var i = "" />
192                <cfset var characters = arguments.text.toCharArray() />
193                <cfset var charactersArrayLen = ArrayLen(characters) />
194                <cfset var top = getConfigBean().getHeight() / 3 />
195                <cfset var left = (RandRange(50, 125) / 100) * getConfigBean().getLeftOffset() />
196                <cfset var definedFonts = getConfigBean().getDefinedFonts() /> 
197                <cfset var char = "" />
198
199                <!--- Create utils --->
200                <cfset var staticCollections = createObject("java", "java.util.Collections") />
201
202                <!--- Create basic graphic objects --->
203                <cfset var dimension = CreateObject("java", "java.awt.Dimension").init(getConfigBean().getWidth(), getConfigBean().getHeight()) />
204                <cfset var imageType = CreateObject("java", "java.awt.image.BufferedImage").TYPE_INT_RGB />
205                <cfset var bufferedImage = CreateObject("java", "java.awt.image.BufferedImage").init(JavaCast("int", dimension.getWidth()), JavaCast("int", dimension.getHeight()), imageType) />
206                <cfset var renderingHints = CreateObject("java", "java.awt.RenderingHints") />
207                <cfset var graphics = bufferedImage.createGraphics() />
208
209                <!--- Set anti-alias setting --->
210                <cfif getConfigBean().getUseAntiAlias()>
211                        <cfset graphics.setRenderingHint(renderingHints.KEY_ANTIALIASING, renderingHints.VALUE_ANTIALIAS_ON) />
212                </cfif>
213
214                <!--- If text exists --->
215                <cfif charactersArrayLen>
216                        <!--- Draw background --->
217                        <cfset drawBackground(graphics, dimension) />
218       
219                        <!--- Draw background ovals --->
220                        <cfif getConfigBean().getUseOvals()>
221                                <cfloop from="1" to="#RandRange(getConfigBean().getMinOvals(), getConfigBean().getMaxOvals())#" index="i">
222                                        <cfset drawRandomOval(graphics, dimension, getConfigBean().getOvalColor()) />
223                                </cfloop>
224                        </cfif>
225       
226                        <!--- Draw background lines --->
227                        <cfif getConfigBean().getUseBackgroundLines()>
228                                <cfloop from="1" to="#RandRange(getConfigBean().getBackgroundMinLines(), getConfigBean().getBackgroundMaxLines())#" index="i">
229                                        <cfset drawRandomLine(graphics, dimension, getConfigBean().getBackgroundLineColor()) />
230                                </cfloop>
231                        </cfif>
232
233                        <!--- Draw captcha text --->
234                        <cfloop from="1" to="#charactersArrayLen#" index="i">
235                                <!--- Get text character to draw --->
236                                <cfset char = characters[i] />
237                               
238                                <cfset staticCollections.shuffle(definedFonts) />
239                               
240                                <cfset setFont(graphics, definedFonts) />
241                                <cfset graphics.setColor(getColorByType(getConfigBean().getFontColor())) />
242                       
243                                <!--- Check if font can display current character --->
244                                <cfloop condition="NOT graphics.getFont().canDisplay(char)">
245                                        <cfset setFont(graphics, definedFonts) />                       
246                                </cfloop>
247                               
248                                <!--- Compute the top character position --->
249                                <cfset top = RandRange(graphics.getFontMetrics().getAscent(), getConfigBean().getHeight() - ((getConfigBean().getHeight() - graphics.getFontMetrics().getHeight()) / 2)) />
250                               
251                                <!--- Draw character text --->
252                                <cfset graphics.drawString(JavaCast("string", char), JavaCast("int", left), JavaCast("int", top)) />
253                               
254                                <!--- Compute the next character lef tposition --->
255                                <cfset left = left + ((RandRange(150, 200) / 100) * graphics.getFontMetrics().charWidth(char)) />
256                        </cfloop>
257
258                        <!--- Draw foreground lines --->
259                        <cfif getConfigBean().getUseForegroundLines()>
260                                <cfloop from="1" to="#RandRange(getConfigBean().getForegroundMinLines(), getConfigBean().getForegroundMaxLines())#" index="i">
261                                        <cfset drawRandomLine(graphics, dimension, getConfigBean().getForegroundLineColor()) />
262                                </cfloop>
263                        </cfif>
264
265                <cfelse>
266                        <!--- If no texts exists, then write "Captcha Not Available" text --->
267                        <cfset staticCollections.shuffle(definedFonts) />
268                        <cfset graphics.setFont(definedFonts[1].deriveFont(JavaCast("float", 18))) />
269                        <cfset graphics.setColor(getColorByType(getConfigBean().getFontColor())) />
270                        <cfset graphics.drawString(JavaCast("string", "Captcha Not Available"), JavaCast("int", left), JavaCast("int", top)) >
271                </cfif>
272
273                <!---
274                *************************************************************************
275                *       Draw attribution (please do not removed or comment out this code        *
276                *       per the additional license restrictions) BELOW                                          *
277                *************************************************************************       
278                --->
279                <cfset staticCollections.shuffle(definedFonts) />
280                <cfset graphics.setFont(definedFonts[1].deriveFont(JavaCast("float", 10))) />
281                <cfset graphics.setColor(getColorByType(getConfigBean().getBackgroundColor())) />
282                <cfset top = getConfigBean().getHeight() - 4 />
283                <cfset graphics.drawString(JavaCast("string", "LylaCaptcha"), JavaCast("int", 4), JavaCast("int", top)) />
284                <!---
285                *************************************************************************
286                *       Draw attribution (please do not removed or comment out this code        *
287                *       per the additional license restrictions) ABOVE                                          *
288                *************************************************************************       
289                --->
290
291                <!--- Encode the captcha into an image based on the output stream --->
292                <cfset encodeImage(arguments.outputStream, bufferedImage) />
293        </cffunction>
294       
295        <cffunction name="encodeImage" access="private" returntype="void" output="false"
296                hint="Encodes a buffered image to the desired output stream.">
297                <cfargument name="outputStream" type="any" required="true"
298                        hint="The output stream." />
299                <cfargument name="bufferedImage" type="any" required="true"
300                        hint="The buffered image." />
301
302                <!--- Create an encoder and get the default encoder params --->
303                <cfset var encoder = createObject("java", "com.sun.image.codec.jpeg.JPEGCodec").createJPEGEncoder(arguments.outputstream) />
304                <cfset var encoderParam = encoder.getDefaultJPEGEncodeParam(arguments.bufferedImage) />
305
306                <!--- Set the quality of the jpeg --->
307                <cfset encoderParam.setQuality(JavaCast("float", getConfigBean().getJpegQuality()), getConfigBean().getJpegUseBaseline()) />
308            <cfset encoder.setJPEGEncodeParam(encoderParam) />
309           
310            <!--- Encode the bufference image --->
311            <cfset encoder.encode(arguments.bufferedImage) />
312        </cffunction>
313
314        <!---
315        PROTECTED FUNCTIONS - DRAW
316        --->
317        <cffunction name="drawBackground" access="private" returntype="void" output="false"
318                hint="Draws a background.">
319                <cfargument name="graphics" type="any" required="true"
320                        hint="The graphics." />
321                <cfargument name="dimension" type="any" required="true"
322                        hint="The dimension object." />
323
324                <cfset var startColor = getColorByType(getConfigBean().getBackgroundColor()) />
325                <cfset var endColor =  getColorByType(getConfigBean().getBackgroundColor()) />
326                <cfset var gradientPaint = "" />
327                <cfset var background = "" />
328               
329                <cfif getConfigBean().getUseGradientBackground()>
330                        <cfset gradientPaint = CreateObject("java", "java.awt.GradientPaint").init(getRandomPointOnBorder(arguments.dimension),
331                                                                                                                                                                        startColor,
332                                                                                                                                                                        getRandomPointOnBorder(arguments.dimension), 
333                                                                                                                                                                        endColor.brighter(),
334                                                                                                                                                                        getConfigBean().getBackgroundColorUseCyclic()) />
335                        <cfset arguments.graphics.setPaint(gradientPaint) />
336                <cfelse>
337                        <cfset arguments.graphics.setColor(startColor) />
338                </cfif>
339
340                <cfset background = CreateObject("java", "java.awt.Rectangle").init(dimension) />
341                <cfset arguments.graphics.fill(background) />
342        </cffunction>
343
344        <cffunction name="drawRandomLine" access="private" returntype="void" output="false"
345                hint="Draws a random line.">
346                <cfargument name="graphics" type="any" required="true"
347                        hint="The graphics." />
348                <cfargument name="dimension" type="any" required="true"
349                        hint="The dimension object." />
350                <cfargument name="lineColorType" type="any" required="true"
351                        hint="The dimension object." />
352
353                <cfset var point1 = getRandomPointOnBorder(arguments.dimension) />
354                <cfset var point2 = getRandomPointOnBorder(arguments.dimension) />
355               
356                <cfset arguments.graphics.setStroke(getRandomStroke()) />       
357                <cfset arguments.graphics.setColor(getColorByType(arguments.lineColorType, getConfigBean().getBackgroundLineUseTransparency())) />
358                       
359                <cfset arguments.graphics.drawLine(
360                                JavaCast("int", point1.getX()),
361                                JavaCast("int", point1.getY()),
362                                JavaCast("int", point2.getX()),
363                                JavaCast("int", point2.getY())) />
364        </cffunction>
365       
366        <cffunction name="drawRandomOval" access="private" returntype="void" output="false"
367                hint="Draws a random oval.">
368                <cfargument name="graphics" type="any" required="true"
369                        hint="The graphics." />
370                <cfargument name="dimension" type="any" required="true"
371                        hint="The dimension object." />
372                <cfargument name="ovalColorType" type="any" required="true"
373                        hint="The dimension object." />
374               
375                <cfset var point = getRandomPoint(arguments.dimension) />
376                <cfset var height = arguments.dimension.getHeight() />
377                <cfset var width = arguments.dimension.getWidth() />
378                <cfset var minOval =  height * .10 />
379                <cfset var maxOval =  height * .75 />
380                <cfset var choice = RandRange(1, 3) />
381               
382                <cfset arguments.graphics.setColor(getColorByType(arguments.ovalColorType, getConfigBean().getOvalUseTransparency())) />
383               
384                <cfswitch expression="#choice#">
385                        <cfcase value="1">
386                                <cfset arguments.graphics.setStroke(getRandomStroke()) />
387                                <cfset arguments.graphics.drawOval(
388                                                JavaCast("int", point.getX()),
389                                                JavaCast("int", point.getY()),
390                                                JavaCast("int", RandRange(minOval, maxOval)),
391                                                JavaCast("int", RandRange(minOval, maxOval))) />
392                        </cfcase>
393                        <cfcase value="2,3">
394                                <cfset arguments.graphics.fillOval(
395                                                JavaCast("int", point.getX()),
396                                                JavaCast("int", point.getY()),
397                                                JavaCast("int", RandRange(minOval, maxOval)),
398                                                JavaCast("int", RandRange(minOval, maxOval))) />
399                        </cfcase>
400                </cfswitch>
401        </cffunction>
402
403        <cffunction name="getRandomPointOnBorder" access="private" returntype="any" output="false"
404                hint="Gets a random java.awt.Point on the border.">
405                <cfargument name="dimension" type="any" required="true"
406                        hint="The dimension object.">
407
408                <cfset var point = CreateObject("java", "java.awt.Point") />
409                <cfset var height = Javacast("int", arguments.dimension.getHeight()) />
410                <cfset var width = JavaCast("int", arguments.dimension.getWidth()) />
411                <cfset var choice = RandRange(1, 4) />
412
413                <cfswitch expression="#choice#">
414                        <!--- left side --->
415                        <cfcase value="1">
416                                <cfset point.setLocation(JavaCast("int", 0), JavaCast("int", RandRange(0, height))) />
417                        </cfcase>
418                        <!--- right side --->
419                        <cfcase value="2">
420                                <cfset point.setLocation(width, RandRange(0, height)) />
421                        </cfcase>
422                        <!--- top side --->
423                        <cfcase value="3">
424                                <cfset point.setLocation(JavaCast("int", RandRange(0, width)), JavaCast("int", 0)) />
425                        </cfcase>
426                        <!--- bottom side --->
427                        <cfcase value="4">
428                                <cfset point.setLocation(RandRange(0, width), height) />
429                        </cfcase>
430                </cfswitch>
431                       
432                <cfreturn point />
433        </cffunction>
434
435        <cffunction name="getRandomPoint" access="private" returntype="any" output="false"
436                hint="Gets a random java.awt.Point in within the dimensions.">
437                <cfargument name="dimension" type="any" required="true"
438                        hint="The dimension object.">
439
440                <cfset var point = CreateObject("java", "java.awt.Point") />
441                <cfset var height = Javacast("int", arguments.dimension.getHeight()) />
442                <cfset var width = JavaCast("int", arguments.dimension.getWidth()) />
443
444                <cfset point.setLocation(JavaCast("int", RandRange(0, width)), JavaCast("int", RandRange(0, height))) />
445                       
446                <cfreturn point />
447        </cffunction>   
448
449        <cffunction name="getRandomTransformation" access="private" returntype="any" output="false"
450                hint="Gets a random transformation.">
451                <cfargument name="shearXRange" type="numeric" required="true"
452                        hint="The shear x range." />
453                <cfargument name="shearYRange" type="numeric" required="true"
454                        hint="The shear y range." />
455
456                <!--- create a slightly random affine transform --->
457                <cfset var transformation = CreateObject("java", "java.awt.geom.AffineTransform").init() />
458                <cfset var shearX = RandRange(-1 * (arguments.shearXRange * (RandRange(50, 150) / 100)), (arguments.shearXRange* (RandRange(50, 150) / 100))) / 100 />
459                <cfset var shearY = RandRange(-1 * (arguments.shearYRange * (RandRange(50, 150) / 100)), (arguments.shearYRange * (RandRange(50, 150) / 100))) / 100 />
460               
461                <cfset transformation.shear(shearX, shearY) />
462                       
463                <cfreturn transformation />
464        </cffunction>
465
466        <cffunction name="getRandomStroke" access="private" returntype="any" output="false"
467                hint="Gets a random stroke.">
468                <cfreturn CreateObject("java", "java.awt.BasicStroke").init(JavaCast("float", RandRange(1, 3))) />
469        </cffunction>
470
471        <cffunction name="setFont" access="private" returntype="void" output="false"
472                hint="Sets a new font in the graphics lib.">
473                <cfargument name="graphics" type="any" required="true"
474                        hint="The graphics." />
475                <cfargument name="fontCollection" type="any" required="true"
476                        hint="The current font collection." />
477               
478                <cfset var font = "" />
479                <cfset var fontSize = Fix((RandRange(80, 120) / 100) * getConfigBean().getFontSize()) />
480                <cfset var staticCollections = createObject("java", "java.util.Collections") />                                 
481                <cfset var trans1 = getRandomTransformation(getConfigBean().getShearXRange(), getConfigBean().getShearYRange()) />
482                <cfset var trans2 = getRandomTransformation(getConfigBean().getShearXRange(), getConfigBean().getShearYRange()) />
483               
484                <cfset staticCollections.rotate(arguments.fontCollection, 1) />
485               
486                <!--- apply transform , just for fun --->
487                <cfset font = arguments.fontCollection[1].deriveFont(JavaCast("float", fontSize)).deriveFont(trans1).deriveFont(trans2) />
488               
489                <cfset arguments.graphics.setFont(font) />
490        </cffunction>
491
492        <cffunction name="getColorByType" access="private" returntype="any" output="false"
493                hint="Get a color by type name.">
494                <cfargument name="colorType" type="string" required="true">
495                <cfargument name="useTransparency" type="boolean" required="false" default="false" />
496               
497                <cfset var shade1 = "" />
498                <cfset var shade2 = "" />
499                <cfset var shade3 = "" />
500                <cfset var alpha = 255 />
501               
502                <!--- Flag for transparency --->
503                <cfif arguments.UseTransparency>
504                        <cfset alpha = RandRange(25, 255) />
505                </cfif>
506
507                <!--- Used cfif-cfelseif-cfelse block for performance --->
508                <cfif arguments.colorType EQ "light">
509                        <cfset shade1 = JavaCast("int", RandRange(170, 255)) />
510                        <cfset shade2 = JavaCast("int", RandRange(170, 255)) />
511                        <cfset shade3 = JavaCast("int", RandRange(170, 255)) />
512                <cfelseif arguments.colorType EQ "medium">
513                        <cfset shade1 = JavaCast("int", RandRange(85, 170)) />
514                        <cfset shade2 = JavaCast("int", RandRange(85, 170)) />
515                        <cfset shade3 = JavaCast("int", RandRange(85, 170)) />
516                <cfelseif arguments.colorType EQ "dark">
517                        <cfset shade1 = JavaCast("int", RandRange(0, 85)) />
518                        <cfset shade2 = JavaCast("int", RandRange(0, 85)) />
519                        <cfset shade3 = JavaCast("int", RandRange(0, 85)) />
520                <cfelseif arguments.colorType EQ "lightGray">
521                        <cfset shade1 = JavaCast("int", RandRange(170, 255)) />
522                        <cfset shade2 = shade1 />
523                        <cfset shade3 = shade1 />
524                <cfelseif arguments.colorType EQ "mediumGray">
525                        <cfset shade1 = JavaCast("int", RandRange(85, 170)) />
526                        <cfset shade2 = shade1 />
527                        <cfset shade3 = shade1 />
528                <cfelseif arguments.colorType EQ "darkGray">
529                        <cfset shade1 = JavaCast("int", RandRange(0, 85)) />
530                        <cfset shade2 = shade1 />
531                        <cfset shade3 = shade1 />
532                <cfelse>
533                        <cfthrow type="captchaService.invalidColorType"
534                                message="The chosen color type is invalid. Please select from light, medium, dark, lightGray, mediumGray or darkGray."
535                                detail="Passed colorType=#arguments.colorType#" />
536                </cfif>
537                       
538                <cfreturn CreateObject("java", "java.awt.Color").init(shade1, shade2, shade3, JavaCast("int", alpha)) />
539        </cffunction>
540
541        <!---
542        PROTECTED FUNCTIONS - UTILS
543        --->
544        <cffunction name="loadXML" access="private" returntype="void" output="false"
545                hint="Loads the config file.<br/>
546                Throws: captchaService.cannotFindConfigFile if provider cannot find the config file.<br/>
547                                captchaService.notXML if the config file is not an XML file.">
548                <cfset var configFile = "" />
549                <cfset var rawXML = "" />
550                <cfset var nodes = "" />
551                <cfset var i = "" />
552                <cfset var tempName = "" />
553                <cfset var configNodes = StructNew() />
554                <cfset var fontNodes = StructNew() />
555                <cfset var fontArray = ArrayNew(1) />
556                <cfset var allFontNames = getAvailableFontNames() />
557                <cfset var allFonts = createObject("java", "java.awt.GraphicsEnvironment").getLocalGraphicsEnvironment().getAllFonts() />
558                <cfset var definedFonts = ArrayNew(1) />
559                <cfset var location = "" />
560                <cfset var memento = StructNew() />
561
562                <!--- Read the xml file --->
563                <cftry>
564                        <cffile
565                                action="READ"
566                                file="#getConfigFile()#"
567                                variable="configFile" />
568                        <cfcatch type="application">
569                                <cfthrow
570                                        type="captchaService.cannotFindConfigFile"
571                                        message="Cannot find the config file."
572                                        detail="configFile=#getConfigFile()#">
573                        </cfcatch>
574                </cftry>
575
576                <!--- Parse the xml file --->
577                <cfset rawXML = XmlParse(configFile) />
578                <cfif ListFirst(server.ColdFusion.ProductVersion) GTE 7 AND NOT IsXML(rawXML)>
579                        <cfthrow
580                                type="captchaService.notXML"
581                                message="The config file is not an XML file."/>
582                </cfif>
583               
584                <!--- Search for the configs --->
585                <cfset configNodes = XMLSearch(rawXML, "//captcha/configs/config/") />
586               
587                <cfloop from="1" to="#ArrayLen(configNodes)#" index="i">
588                        <cfset memento[Trim(configNodes[i].XmlAttributes['name'])] = configNodes[i].XmlAttributes['value'] />
589                </cfloop>
590               
591                <!--- Search for the fonts --->
592                <cfset fontNodes = XMLSearch(rawXML, "//captcha/fonts/font/") />
593               
594                <cfloop from="1" to="#ArrayLen(fontNodes)#" index="i">
595                        <cfif fontNodes[i].XmlAttributes['use']>
596                                <!--- Get the font name --->
597                                <cfset tempName = Trim(fontNodes[i].XmlAttributes['name']) />
598
599                                <!--- Get array node of desired font --->
600                                <cfset location = arrayFind(allFontNames, tempName) />
601                               
602                                <!--- Use the font if it is available on the system --->
603                                <cfif location>
604                                        <cfset ArrayAppend(definedFonts, allFonts[location]) />
605                                </cfif>
606                        </cfif>
607                </cfloop>
608
609                <!--- Set defined fonts --->
610                <cfset memento.definedFonts = definedFonts />
611               
612                <!--- Set the memento to the config bean --->
613                <cfset getConfigBean().setMemento(memento) />
614        </cffunction>
615
616        <cffunction name="getRandString" access="private" returntype="string" output="false"
617                hint="Gets a random string based on the configuration.">
618                <cfreturn randString(getConfigBean().getRandStrType(), RandRange((getConfigBean().getRandStrLen() - 1), (getConfigBean().getRandStrLen() + 1))) />
619        </cffunction>
620       
621        <cffunction name="getFileLocation" access="private" returntype="string" output="false"
622                hint="Gets a file location.">
623                <cfset var fileName = CreateUUID() & ".jpg" />
624                <cfset var fileLocation = "" />
625
626                <cfif getConfigBean().getOutputDirectoryIsRelative()>
627                        <cfset fileLocation = ExpandPath(getConfigBean().getOutputDirectory()) & fileName />
628                <cfelse>
629                        <cfset fileLocation = getConfigBean().getOutputDirectory() & fileName />
630                </cfif>
631
632                <cfreturn fileLocation />
633        </cffunction>
634
635        <cffunction name="createHash" access="private" returntype="string" output="false"
636                hint="Creates a hash.">
637                <cfreturn CreateUUID() />
638        </cffunction>
639
640        <cffunction name="setHashReference" access="private" returntype="void" output="false"
641                hint="Sets captcha text by hash reference.">
642                <cfargument name="hash" type="string" required="true" />
643                <cfargument name="text" type="string" required="true" />
644               
645                <cfset variables.instance.hashReferenceCache[1][arguments.hash] = arguments.text />
646        </cffunction>
647
648        <cffunction name="getHashReference" access="private" returntype="string" output="false"
649                hint="Gets captcha text by hash reference.">
650                <cfargument name="hash" type="string" required="true" />
651                <cfargument name="deleteFromCache" type="boolean" required="false" default="FALSE" />
652               
653                <cfset var text = "" />
654                <cfset cleanupHashReferenceCache() />
655               
656                <!--- Search through the LRU cache starting with the first (and most likely) node --->
657                <cfif StructKeyExists(variables.instance.hashReferenceCache[1], arguments.hash)>
658                        <cfset text = variables.instance.hashReferenceCache[1][arguments.hash] />                       
659                        <cfif arguments.deleteFromCache>
660                                <cfset StructDelete(variables.instance.hashReferenceCache[1], arguments.hash, FALSE) />
661                        </cfif>
662                <cfelseif StructKeyExists(variables.instance.hashReferenceCache[2], arguments.hash)>
663                        <cfset text = variables.instance.hashReferenceCache[2][arguments.hash] />
664                        <cfif arguments.deleteFromCache>
665                                <cfset StructDelete(variables.instance.hashReferenceCache[2], arguments.hash, FALSE) />
666                        </cfif>
667                <cfelse>
668                        <cfset text = "" />
669                </cfif>
670
671                <cfreturn text />
672        </cffunction>
673
674        <cffunction name="cleanupHashReferenceCache" access="private" returntype="void" output="false"
675                hint="Cleans up expired elements in the hash reference LRU cache.">
676                <cfset var tick = getTickCount() />
677               
678                <!--- Check if cleanup is required and perform double-checked locking pattern --->
679                <cfif tick - getHashReferenceCacheTimestamp() GTE (getConfigBean().getHashValidPeriod() / 2)>
680                        <!--- Obtain named lock --->
681                        <cflock name="captchaServiceHashReferenceCache" timeout="1" throwontimeout="false">
682                                <cfif tick - getHashReferenceCacheTimestamp() GTE (getConfigBean().getHashValidPeriod() / 2)>
683                                        <cfset ArrayPrepend(variables.instance.hashReferenceCache, StructNew()) />
684                                        <cfset ArrayDeleteAt(variables.instance.hashReferenceCache, 3) />
685                                        <cfset setHashReferenceCacheTimestamp(tick) />
686                                </cfif>
687                        </cflock>
688                </cfif>
689        </cffunction>
690
691        <cffunction name="setupHashReferenceCache" access="private" returntype="void" output="false"
692                hint="Setups the hash reference cache.">
693                <cfset var tempHashReferenceCache = ArrayNew(1) />
694               
695                <!--- Setup inital hash reference cache --->
696                <cfset ArrayPrepend(tempHashReferenceCache, StructNew()) />
697                <cfset ArrayPrepend(tempHashReferenceCache, StructNew()) />
698                <cfset setHashReferenceCache(tempHashReferenceCache) />
699                <cfset setHashReferenceCacheTimestamp(getTickCount()) />
700        </cffunction>
701
702        <!---
703        PROTECTED FUNCTIONS - UDFs
704        --->
705        <cffunction name="randString" access="private" returntype="string" output="false"
706                hint="Returns a random string according to the type.">
707                <cfargument name="type" type="string" required="true" />
708                <cfargument name="count" type="numeric" required="true" />
709
710                <cfset var randStr = "" />
711                <cfset var alpha_lcase = "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z" />
712                <cfset var alpha_ucase = "A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z" />
713                <cfset var num = "0,1,2,3,4,5,6,7,8,9" />
714                <cfset var secure = "!,@,$,%,&,*,-,_,=,+,?,~" />
715                <cfset var rangeMax = "" />
716                <cfset var useList = "" />
717                <cfset var i = "" />
718               
719                <!--- Used cfif-cfelseif-cfelse block for performance --->
720                <cfif arguments.type EQ "alpha">
721                        <cfset useList = alpha_lcase & "," & alpha_ucase />
722                        <cfset rangeMax = ListLen(useList) />
723                <cfelseif arguments.type EQ "alphaLCase">
724                        <cfset useList = alpha_lcase />
725                        <cfset rangeMax = ListLen(useList) />
726                <cfelseif arguments.type EQ "alphaUCase">
727                        <cfset useList = alpha_ucase />
728                        <cfset rangeMax = ListLen(useList) />
729                <cfelseif arguments.type EQ "alphaNum">
730                        <cfset useList = alpha_lcase & "," & alpha_ucase & "," & num />
731                        <cfset rangeMax = ListLen(useList) />
732                <cfelseif arguments.type EQ "alphaNumLCase">
733                        <cfset useList = alpha_lcase & "," & "," & num />
734                        <cfset rangeMax = ListLen(useList) />
735                <cfelseif arguments.type EQ "alphaNumLCase">
736                        <cfset useList = alpha_ucase & "," & "," & num />
737                        <cfset rangeMax = ListLen(useList) />
738                <cfelseif arguments.type EQ "num">
739                        <cfset useList = num />
740                        <cfset rangeMax = ListLen(useList) />
741                <cfelseif arguments.type EQ "secure">
742                        <cfset useList = alpha_lcase & "," & alpha_ucase & "," & num & "," & secure />
743                        <cfset rangeMax = ListLen(useList) />
744                <cfelse>
745                        <cfset useList = num />
746                        <cfset rangeMax = ListLen(useList) />
747                </cfif>
748
749                <cfloop from="1" to="#arguments.count#" index="i">
750                        <cfset randStr = randStr & ListGetAt(useList, RandRange(1, rangeMax)) />
751                </cfloop>
752
753                <cfreturn randStr />
754        </cffunction>
755
756        <cffunction name="arrayFind" access="private" returntype="numeric" output="false"
757                hint="Like listFind(), except with an array.">
758                <cfargument name="searchArray" type="array" required="true" />
759                <cfargument name="value" type="string" required="true" />
760                <!--- Rewritten UDF from cflib.org Author: Nathan Dintenfass (nathan@changemedia.com) --->
761                <cfset var i = "" />
762                <cfset var result = 0 />
763               
764                <cfloop from="1" to="#ArrayLen(arguments.searchArray)#" index="i">
765                        <cfif NOT compareNoCase(arguments.searchArray[i], arguments.value)>
766                                <cfset result = i />
767                                <cfbreak />
768                        </cfif>
769                </cfloop>
770               
771                <cfreturn result />
772        </cffunction>
773
774        <!---
775        ACCESSORS
776        --->
777        <cffunction name="getMemento" access="public" returntype="struct" output="false">
778                <cfreturn variables.instance />
779        </cffunction>
780
781        <cffunction name="setConfigFile" access="private" returntype="void" output="false">
782                <cfargument name="configFile" type="string" required="true" />
783                <cfset variables.instance.configFile = ExpandPath(arguments.configFile) />
784        </cffunction>
785        <cffunction name="getConfigFile" access="public" returntype="string" output="false">
786                <cfreturn variables.instance.configFile />
787        </cffunction>
788       
789        <cffunction name="setConfigBean" access="private" returntype="void" output="false">
790                <cfargument name="configBean" type="captchaServiceConfigBean" required="true" />
791                <cfset variables.instance.configBean = arguments.configBean />
792        </cffunction>
793        <cffunction name="getConfigBean" access="public" returntype="captchaServiceConfigBean" output="false">
794                <cfreturn variables.instance.configBean />
795        </cffunction>
796
797        <cffunction name="setHashReferenceCache" access="private" returntype="void" output="false">
798                <cfargument name="hashReferenceCache" type="array" required="true" />
799                <cfset variables.instance.hashReferenceCache = arguments.hashReferenceCache />
800        </cffunction>
801        <cffunction name="getHashReferenceCache" access="public" returntype="array" output="false">
802                <cfreturn variables.instance.hashReferenceCache />
803        </cffunction>
804
805        <cffunction name="setHashReferenceCacheTimestamp" access="private" returntype="void" output="false">
806                <cfargument name="hashReferenceCacheTimestamp" type="numeric" required="true" />
807                <cfset variables.instance.hashReferenceCacheTimestamp = arguments.hashReferenceCacheTimestamp />
808        </cffunction>
809        <cffunction name="getHashReferenceCacheTimestamp" access="public" returntype="numeric" output="false">
810                <cfreturn variables.instance.hashReferenceCacheTimestamp />
811        </cffunction>
812       
813</cfcomponent>
Note: See TracBrowser for help on using the browser.