at 2006-10-24
in Editorial
by friebe
(0 comments)
If you've written web applications with the XP framework, you've probably made use of the scriptlet.xml.workflow API. It provides templating via XSL files and in general a very comfortable way of creating dynamic web pages. Feel tempted to use "standard" web scripting (see below for example) for simpler tasks like CSV export, dynamic image creation or RSS feeds?
Here's why you shouldn't...Clarification This is a scriptlet:
<?php class EchoScriptlet extends HttpScriptlet { function doGet(&$request, &$response) { $response->write('Hello '.htmlspecialchars($request->getParameter('name', 'unknown'))); } } scriptlet::run(new EchoScriptlet()); ?> This is a "standard" web script:
<?php echo 'Hello ', isset($_REQUEST['name']) ? htmlspecialchars($_REQUEST['name']) : 'unknown'; ?>
Why to use scriptlets #1: Error handling The XP framework uses a simulated exception mechanism for error handling. One of the problems with this mechanism is that it cannot simulate uncaught exceptions; that is, if an exception falls through all catch blocks and still exists at the end of the script, it won't immediately lead to an error. Your script will continue to execute, maybe causing unpredictable results, maybe bailing with some weird error, maybe even worse
If you use the scriptlet API, any exception still around before content is sent to the remote side will lead to an internal server error (HTTP statuscode 500, which is clearly distinguishable from empty content, a HTTP statuscode 200 and content containing the string "Fatal Error: ...", or even worse).
Example:
<?php class CsvExportScriptlet extends HttpScriptlet { function doGet(&$request, &$response) { $cm= &ConnectionManager::getInstance(); $conn= &$cm->getByHost('news', 0);
$response->setContentType('text/comma-separated-values'); $response->write("id,author\n"); foreach ($conn->select('id, author from news order by created_at limit 10') as $entry) { $response->write($entry['id'].','.$entry['author']."\n"); } } } ?> Now in case the SQL query fails, this scriptlet will set the HTTP statuscode to 500 ("Internal Server Error") without you having to do anything. For a "standard" web script, you'd have to add a try/catch around everything and use output buffering (ob_start(), ob_get_contents()) to capture any output, or - to make it short: Add lots of boilerplate code. If you didn't, you'd end up with the header record and an empty list (not distinguishable from "no entries found").
Why to use scriptlets #2: Parameter handling As you can see above in the example, the isset() check is necessary in standard web scripts to check whether a parameter was passed or not (and to be able to distinguish from the situation when it was passed but with an empty value). The HttpScriptletRequest's getParam() method makes this easier for you - its second (and optional) parameter lets you supply a default value for the case when the parameter was non-existant (if you just want to know whether a parameter was existant or not you may want to use hasParam()).
Why to use scriptlets #3: Portability Scriptlets will behave the same when used from within Apache's PHP module or when PHP is running as a CGI. Most noteable effect is that you'll have set the HTTP status code using Status: XXX for the CGI SAPI whereas you'll have to use HTTP/1.1 XXX for mod_php.
Why to use scriptlets #4: register_globals issues won't affect you All the security problems (see the PHP manual page for an example) that may be caused by register_globals=On will not affect you - in a scriptlet's doGet() and doPost() methods, you're outside of the global scope.
Why to use scriptlets #5: It's not really more code Comparing the "standard" web script way and using the scriptlet API you'll note that the latter consumes a bit more sourcecode - on the first glance. If you add all the necessary error handling, you'll see it comes out to the same. The CsvExportScriptlet from above - the standard way with error handling would be:
<?php $cm= &ConnectionManager::getInstance(); $conn= &$cm->getByHost('news', 0);
ob_start(); echo "id,author\n"; try(); { foreach ($conn->select('id, author from news order by created_at limit 10') as $entry) { echo $entry['id'].','.$entry['author']."\n"; } } if (catch('SQLException', $e)) { if (php_sapi_name() == 'cgi') { header('Status: 500'); } else { header('HTTP/1.1 500 Internal Server Error'); } ob_end_clean(); exit($e->toString()); }
header('Content-type: text/comma-separated-values'); ob_end_flush(); ?> That makes nineteen lines (excluding those with only whitespace), compared to eleven (plus one for scriptlet::run(new CsvExportScriptlet()); at the end) for the scriptlet approach.
|
Subscribe
You can subscribe to the XP framework's news by using RSS syndication.
CategoriesNews General PHP5 Announcements RFCs Further reading Examples Editorial EASC Experiments Unittests Databases
RelatedFind related articles by a search for «Why».
|