Server Side und Frameworks - Teil III
o SJS, JST oder JX?o Raccoon Extras
o Ein Captcha und was dazu gehört
o MooTools.jx in Action
o Die Template-Klasse von Raccoon
In den vorangegangenen Kapitel habe ich Windows-Setup und das Scripten mit v8cgi und dem Template-Modul behandelt. Im dritten Teil soll v8cgi um die Benefits von Mootools erweitert werden, dafür kommt das schlanke zum Einsatz. Raccon befindet sich zwar noch im Beta-Stadium, doch die modifizierte Core aus dem Bundle funktioniert und erlaubt MooTools-Vertraute Virtuosität.
SJS, JST oder JX?
Die Dateien des Frameworks sind gerade im zum Downladen. Keeto benutzt die Dateiendung JX, welche etwas schlanker als das bisherige .sjs ist, und ich im weiteren adaptieren werde. Dazu müssen einige Einstellungen im Apache .conf vorgenommen werden:
- Einmal im v8cgi Setup:
AddHandler v8cgi-script .js .sjs .ssjs .jst .jx- und
DirectoryIndex index.php index.cgi index.html index.jxRaccoon Extras
- Im Raccoon-Trunk (vendor/raccoon/Raccoon/Core) finden wir folgende Dateien:
- Cache.jx
- Controller.jx
- Extras.jx
- MooTools.jx
- Template.jx
Als erstes wollen wir etwas mit Extras.jx experimentieren. (Übrigens benötigen alle Klassen von Raccoon die MooTools.jx Erweiterung.) Extras erweitern JavaScript-String-Objekte um eine echo()-Funktion und andere nützliche trim und parse und escape Methoden.
- Folgendes ist damit nun möglich:
//PHP-Style
echo('abc');
//MooTools Style
'abc'.echo();
//Nach Mootools-Art lassen sich Aufrufe "verketten"
'<b>abc</b>'.escape().echo();
//Mootools.jx erweitert das JSON-Objekt umd encode bzw. decode
JSON.encode(request.post).echo();
//Ausgeben vom Variablen-Typ
echo(typeof(this.input));
Wie bereits gehabt starten wir unser Programm in einem Try-Catch-Block. Die Catch-Anzeige ist den Raccoon-Vorgaben entlehnt. Anstatt dem Template-Modul von v8cgi verwenden wir die etwas elegantere Templates-Klasse von Raccoon. Dazu später mehr.
- index.js
try {
include('gd');
include('session');
include('./Raccoon/Core/MooTools.jx');
include('./Raccoon/Core/Extras.jx');
include('./Raccoon/Core/Template.jx');
include('./JxCaptcha.jx');
}
catch (e) {
response.write('<html> \
<head><title>Oops!</title> \
<style>body {font-family: "Helvetica Neue", Arial, sans-serif}</style> \
</head><body> \
<h1>An Error Occurred:</h1> \
<p>'+e+'</p> \
</body></html>');
}
Wir benötigen für ein Captcha zusätzlich die das Grafik- und Session-Modul von v8cgi. Danach die Raccoon-Klassen und anschließend unser Programm.
Vor est möchte ich auf einige Eigenheiten von v8cgi eingehen. Variablen sind grundsätzlich nicht «global» also dateiübergreifend zugänglich, da implementierte Dateien wie Funktionsaufrufe behandelt werden. Dies ist eine Eigenheit von JX. Variablen können per var x = this.x, oder bei Klassen mit exports.ClassName = ClassName wie mit PHP-define als global deklariert werden.
Die andrere Sache ist das Error-Handling, die aktuelle SVN (Revision 600<) unterstützt den Config[ShowErrors] Parameter, aber leider sind die verfügbaren Windows-Builds nicht up to date… Daher der Gedanke auf Linux (und CouchDB) umzusteigen. Wobei ich nach dem Erscheinen von Chrome OS mit Linux-Kern sowieso aufspringen werde.
MooTools.jx in Action
MooTools.jx ist eine für v8cgi modifizierte MooTools-Core der sich (ebenfalls) noch in der Beta-Phase Version 2.0 befindet. Die Core ermöglicht es eleganter und leichter Klassen mit Hilfe von Json zu erstellen. Somit kommen wir zu unserer ersten Klasse:
- JxCaptcha Initialisieren:
// JxCaptcha 10 2009
this.JxCaptcha = new Class ({
Implements: Options,
options: {
words: ['bauplann','stempel','spartaner','indien','roboter','werbung'],
test_mode : false,
size: {x:340,y:70}
},
initialize: function (options) {
this.setOptions(options);
this.input = request.post;
this.msg = { success:'', warn:'', fail:'', log:'' };
this.passed = session.get('captcha_passed');
Ab hier können wir das gewohnte Framework-gestützte JavaScripting einsetzen. :)
- JxCaptcha.draw() zeichnet das Captcher mithilfe des GD-Moduls:
draw: function (word) {
var image = new Image(Image.TRUECOLOR, this.options.size.x, this.options.size.y);
image.fill(1, 1, Image.trueColor(255,255,255));
var bgimage = new Image(Image.JPEG, 'smoke.jpg');
image.copy(bgimage, 0, 0, 0, 0, this.options.size.x, this.options.size.y);
var angles = [-1.15,-1.1,1,1.1,1.15];
var r1 = angles.random();
var r2 = angles.random();
var r3 = angles.random();
image.string(
Image.trueColor(20,10,5), 'verdana',
40 + (7 * angles.random()),
0.05 * angles.random(),
35 + (10 * angles.random()),
50 + (10 * angles.random()),
word
);
image.save(Image.PNG, new File('captcha.png'));
},
Nach dem Erstellen des Image-Objekts wird das Bild 'some.jpg' als rein kopiert und dient als Hintergrund. Anschließend wird das Wort darauf gezeichnet. Abstände, Schriftgröße und Rotationsgrad variieren.
- JxCaptcha.check() für die Eingabeauswertung über Sessions:
check: function (value) {
var check = value == session.get('captcha_word') ? true : false;
session.set('captcha_passed', check);
session.set('captcha_word', null);
return check;
},
Die Session-Sache ist noch einfacher als beim PHP, zwei Variablen werden gebraucht und und können per get-set gehandhabt werden.
- Anschließend wird das Template aufgerufen.
processView: function () {
response.write(
new Template({path:'layouts/',suffix:'html'}).process('index', {
//input: this.input,
msg: this.msg,
passed: this.passed
}));
}
Der Aufruf funktioniert genau so wie in der Template-Variante von v8cgi. Noch interessanter wird es im Template:
Die Raccoon-Templates
- layouts/index.html
Keetos Template-Sprache ist recht geschickt zu gebrauchen. Der Code wird innerhalb der <# #>-Tags geparst. Variablen können direkt mit <#: var #> augegeben werden. In Kürze wird die Funktionalität um den Einsatz von Includes mit <#@ «xyz.html» #> erweitert.<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>JxCaptcha</title>
<!--[if IE]><script src="html5.js"></script><![endif]-->
<style>
section, header, dialog, article { display:block; }
section { width:350px; margin:20px; font:.8em Verdana; }
header { font-weight:bold; }
#msg_blog { padding:4px; }
article { margin-bottom:1em; padding:5px; }
input#therms { width:100%; }
a img { border:1px solid black; }
</style>
</head>
<body>
<section id="tickler">
<header>JxCaptcha</header>
<div id="msg_blog">
<dialog id="success" style="color:green;"><#: this.msg.success||"" #></dialog>
<dialog id="warning" style="color:orange;"><#: this.msg.warn||"" #></dialog>
<dialog id="fail" style="color:red;"><#: this.msg.fail||"" #></dialog>
<dialog id="log" style="color:black;"><#: this.msg.log||"" #></dialog>
</div>
<# if(!this.passed) { #>
<article>
<a href="index.jx"><img src="captcha.png" /></a>
</article>
<article>
<form id="user_form" method="POST" accept-charset="UTF-8" action="">
<label>Try</label>
<input type="text" name="therms" id="therms" value="" />
<input type="hidden" name="submit" value="true" />
<input type="submit" value="Submit">
</form>
</article>
<# } else { #>
<article>
<h1>Page Content</h1>
</article>
<form id="user_form" method="POST" accept-charset="UTF-8" action="">
<input type="hidden" name="reset" value="true" />
<input type="submit" value="Reset">
</form>
</article>
<# } #>
</section>
</body>
</html>
Wie Ihr seht habe ich im HTML einen Message-Blog eingebaut. Die msg-Variablen über erfolg/misserfolg der User-Eingaben generiere ich in der initialize-Methode von JxCaptcha.
- Hier das komplette Script:
// JxCaptcha 10 2009
this.JxCaptcha = new Class ({
Implements: Options,
options: {
words: ['bauplann','stempel','spartaner','indien','roboter','werbung'],
test_mode : false,
size: {x:340,y:70}
},
initialize: function (options) {
this.setOptions(options);
this.input = request.post;
this.msg = { success:'', warn:'', fail:'', log:'' };
this.passed = session.get('captcha_passed');
//handle inputs
if (this.input.submit) {
var userinput = this.input.therms ? this.input.therms.rtrim().escape() : '';
//echo(userinput);
if (this.passed = this.check(userinput))
this.msg.success = "Captcha korrekt eingegeben. Weiter gehts.";
else this.msg.fail = "Captcha-Text falsch eingegeben. Nochmal.";
}
//reset nachdem das captcha korrekt eingegeben wurde
else if (this.input.reset) {
session.clear();
this.passed=false;
this.msg.success = "Nochmal probieren?";
}
//create captcha
if (!this.passed) {
var new_captcha = this.options.words.random();
session.set('captcha_word', new_captcha);
this.draw(new_captcha);
}
this.processView();
},
check: functuin(value) { ... },
draw: function(word) { ... },
processView: function () { ... }
});
var captcha = new JxCaptcha();
Soviel zur objektorientierten Programmierung mit JavaScript fürs Backend! d:) Als nächstes muss CouchDB ins Tutorial. Außerdem will ich versuchen v8cgi auf meinem VServer zum laufen zu bringen.











Kommentare (4)
Sehr gute Einleitung!
BuzzEins
wildeuter
BuzzEins
wildeuter