<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Artful Code &#187; web</title>
	<atom:link href="http://www.artfulcode.net/tags/web/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.artfulcode.net</link>
	<description>Resources and tips for dynamic, interactive languages.</description>
	<lastBuildDate>Fri, 09 Sep 2011 02:15:45 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Custom session storage with newLISP Web</title>
		<link>http://www.artfulcode.net/articles/custom-session-storage-with-newlisp-web/</link>
		<comments>http://www.artfulcode.net/articles/custom-session-storage-with-newlisp-web/#comments</comments>
		<pubDate>Fri, 29 May 2009 18:35:52 +0000</pubDate>
		<dc:creator>Jeff</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[newlisp]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.artfulcode.net/?p=684</guid>
		<description><![CDATA[The Web module's default session storage engine uses serialized contexts in the /tmp directory. The advantage of this method is that, apart from the directory (which is customizable), it is reasonably platform independent and has low overhead. The disadvantages of this are numerous. Files are stored unencrypted, so anyone with access to the server may view them. It is therefor advantageous to design a custom storage module for sessions.]]></description>
			<content:encoded><![CDATA[<p><a href="http://static.artfulcode.net/newlisp/web.lsp.html">The Web module&#8217;s</a> default session storage engine uses serialized contexts in the <em>/tmp</em> directory. The advantage of this method is that, apart from the directory (which is customizable), it is reasonably platform independent and has low overhead. The disadvantages of this are numerous. Files are stored unencrypted, so anyone with access to the server may view them. It is therefor advantageous to design a custom storage module for sessions.<span id="more-684"></span></p>
<p>Storing sessions in a database is a good solution. Backups are easier; persistence and pruning orphaned sessions are simpler. Security is available through the database server&#8217;s security.  We will use MySQL, since it is the best supported in newLISP.</p>
<h2>Setting up the database</h2>
<p>First, we need a table in which to store session data. Using a MySQL <code>TIMESTAMP</code> column will provide us with an automatically updating time stamp on the last modification of the session, which we will use below to find old sessions to remove.</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> sessions <span style="color: #66cc66;">&#40;</span>
	sid VARCHAR<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">255</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span><span style="color: #66cc66;">,</span>
	<span style="color: #993333; font-weight: bold;">DATA</span> TEXT <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
	ts TIMESTAMP
<span style="color: #66cc66;">&#41;</span></pre></div></div>

<h2>Designing the storage module</h2>
<p>Several functions need to be defined to handle storing data. First, we must ensure that the <a href="http://www.newlisp.org/code/modules/mysql.lsp.html">MySQL module</a> is loaded and initialized. We will do this in a separate module that we will call <code>DBSessions</code>.</p>

<div class="wp_syntax"><div class="code"><pre class="newlisp" style="font-family:monospace;"><span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">context</span> 'DBSessions<span style="color: #AF0500;">&#41;</span>
&nbsp;
<span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">unless</span> <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">sym</span> <span style="color: #3AA43E;">&quot;MYSQL&quot;</span> 'MySQL <span style="color: #2028B8;">nil</span><span style="color: #AF0500;">&#41;</span> <span style="color: #808080; font-style: italic;">; do not reinitialize if already loaded</span>
  <span style="color: #AF0500;">&#40;</span>module <span style="color: #3AA43E;">&quot;mysql5.lsp&quot;</span><span style="color: #AF0500;">&#41;</span> <span style="color: #808080; font-style: italic;">; with newlisp 10.1, this will change to &quot;mysql.lsp&quot;</span>
  <span style="color: #AF0500;">&#40;</span>MySQL:<span style="color: #2028B8;">init</span><span style="color: #AF0500;">&#41;</span>
  <span style="color: #AF0500;">&#40;</span>MySQL:<span style="color: #2028B8;">connect</span> <span style="color: #3AA43E;">&quot;127.0.0.1&quot;</span> <span style="color: #3AA43E;">&quot;user&quot;</span> <span style="color: #3AA43E;">&quot;secret&quot;</span> <span style="color: #3AA43E;">&quot;somedb&quot;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span>
&nbsp;
<span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">context</span> '<span style="color: #2028B8;">MAIN</span><span style="color: #AF0500;">&#41;</span></pre></div></div>

<p>Next, we define a function to create or resume a session from the database. Sessions are stored in memory as contexts, making our job easier. Our function will query MySQL to see if the session id exists, and either create a new session and insert it or retrieve an existing session and load it. The function <code>Web:session-id</code> gives us the current session id from the session cookie or creates a new one and sends the client a cookie to store it. <code>Web:session-context</code> returns a symbol pointed to the context storing the current session.</p>

<div class="wp_syntax"><div class="code"><pre class="newlisp" style="font-family:monospace;"><span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">define</span> <span style="color: #AF0500;">&#40;</span>open-session<span style="color: #AF0500;">&#41;</span>
  <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">when</span> <span style="color: #AF0500;">&#40;</span>MySQL:<span style="color: #2028B8;">query</span> <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">format</span> <span style="color: #3AA43E;">&quot;SELECT data FROM sessions WHERE sid = '%s'&quot;</span> <span style="color: #AF0500;">&#40;</span>MySQL:<span style="color: #2028B8;">escape</span> <span style="color: #AF0500;">&#40;</span>Web:<span style="color: #2028B8;">session-id</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span>
    <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">let</span> <span style="color: #AF0500;">&#40;</span><span style="color: #AF0500;">&#40;</span>data <span style="color: #AF0500;">&#40;</span>MySQL:<span style="color: #2028B8;">fetch-row</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span>
      <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">if</span> data
        <span style="color: #808080; font-style: italic;">;; Evaluate the serialized context into the current session context</span>
        <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">eval-string</span> <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">first</span> data<span style="color: #AF0500;">&#41;</span> <span style="color: #AF0500;">&#40;</span>Web:<span style="color: #2028B8;">session-</span><span style="color: #2028B8;">context</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span>
        <span style="color: #808080; font-style: italic;">;; Create a new session and save it</span>
        <span style="color: #AF0500;">&#40;</span>MySQL:<span style="color: #2028B8;">query</span> <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">format</span> <span style="color: #3AA43E;">&quot;INSERT INTO sessions (sid, data) VALUES ('%s', '%s')&quot;</span>
          <span style="color: #AF0500;">&#40;</span>MySQL:<span style="color: #2028B8;">escape</span> <span style="color: #AF0500;">&#40;</span>Web:<span style="color: #2028B8;">session-id</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span>
          <span style="color: #AF0500;">&#40;</span>MySQL:<span style="color: #2028B8;">escape</span> <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">source</span> <span style="color: #AF0500;">&#40;</span>Web:<span style="color: #2028B8;">session-</span><span style="color: #2028B8;">context</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span></pre></div></div>

<p>Next, we need a function to write any changes to the session to storage. Since the session is stored as a context, this is quite simple.</p>

<div class="wp_syntax"><div class="code"><pre class="newlisp" style="font-family:monospace;"><span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">define</span> <span style="color: #AF0500;">&#40;</span>close-session<span style="color: #AF0500;">&#41;</span>
  <span style="color: #AF0500;">&#40;</span>MySQL:<span style="color: #2028B8;">query</span> <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">format</span> <span style="color: #3AA43E;">&quot;UPDATE sessions SET data = '%s' WHERE sid = '%s'&quot;</span>
    <span style="color: #AF0500;">&#40;</span>MySQL:<span style="color: #2028B8;">escape</span> <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">source</span> <span style="color: #AF0500;">&#40;</span>Web:<span style="color: #2028B8;">session-</span><span style="color: #2028B8;">context</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span>
    <span style="color: #AF0500;">&#40;</span>MySQL:<span style="color: #2028B8;">escape</span> <span style="color: #AF0500;">&#40;</span>Web:<span style="color: #2028B8;">session-id</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span></pre></div></div>

<p>We also need a function to delete entire sessions when necessary. This is also simple.</p>

<div class="wp_syntax"><div class="code"><pre class="newlisp" style="font-family:monospace;"><span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">define</span> <span style="color: #AF0500;">&#40;</span>delete-session<span style="color: #AF0500;">&#41;</span>
  <span style="color: #AF0500;">&#40;</span>MySQL:<span style="color: #2028B8;">query</span> <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">format</span> <span style="color: #3AA43E;">&quot;DELETE FROM sessions WHERE sid = '%s'&quot;</span>
    <span style="color: #AF0500;">&#40;</span>MySQL:<span style="color: #2028B8;">escape</span> <span style="color: #AF0500;">&#40;</span>Web:<span style="color: #2028B8;">session-id</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span></pre></div></div>

<p>Finally, a function to cull old sessions from the database. For this, we use the variable <code>Web:SESSION_MAX_AGE</code> to determine which sessions have expired.</p>

<div class="wp_syntax"><div class="code"><pre class="newlisp" style="font-family:monospace;"><span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">define</span> <span style="color: #AF0500;">&#40;</span>clean-sessions<span style="color: #AF0500;">&#41;</span>
  <span style="color: #AF0500;">&#40;</span>MySQL:<span style="color: #2028B8;">query</span> <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">format</span> <span style="color: #3AA43E;">&quot;DELETE FROM sessions WHERE NOW() &gt;= DATE_ADD(ts, INTERVAL %d SECOND)&quot;</span>
    Web:<span style="color: #2028B8;">SESSION_MAX_AGE</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span></pre></div></div>

<h2>Registering the handler in Web</h2>
<p>Last, the handler functions need to be registered in the <code>Web</code> module.</p>

<div class="wp_syntax"><div class="code"><pre class="newlisp" style="font-family:monospace;"><span style="color: #AF0500;">&#40;</span>Web:<span style="color: #2028B8;">define-session-handlers</span>
  open-session close-session delete-session clean-sessions<span style="color: #AF0500;">&#41;</span></pre></div></div>

<h2>Putting it all together</h2>

<div class="wp_syntax"><div class="code"><pre class="newlisp" style="font-family:monospace;"><span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">unless</span> <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">sym</span> <span style="color: #3AA43E;">&quot;MYSQL&quot;</span> 'MySQL <span style="color: #2028B8;">nil</span><span style="color: #AF0500;">&#41;</span> <span style="color: #808080; font-style: italic;">; do not reinitialize if already loaded</span>
  <span style="color: #AF0500;">&#40;</span>module <span style="color: #3AA43E;">&quot;mysql5.lsp&quot;</span><span style="color: #AF0500;">&#41;</span> <span style="color: #808080; font-style: italic;">; with newlisp 10.1, this will change to &quot;mysql.lsp&quot;</span>
  <span style="color: #AF0500;">&#40;</span>MySQL:<span style="color: #2028B8;">init</span><span style="color: #AF0500;">&#41;</span>
  <span style="color: #AF0500;">&#40;</span>MySQL:<span style="color: #2028B8;">connect</span> <span style="color: #3AA43E;">&quot;127.0.0.1&quot;</span> <span style="color: #3AA43E;">&quot;user&quot;</span> <span style="color: #3AA43E;">&quot;secret&quot;</span> <span style="color: #3AA43E;">&quot;somedb&quot;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span>
&nbsp;
<span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">context</span> 'DBSessions<span style="color: #AF0500;">&#41;</span>
&nbsp;
<span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">define</span> <span style="color: #AF0500;">&#40;</span>open-session<span style="color: #AF0500;">&#41;</span>
  <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">when</span> <span style="color: #AF0500;">&#40;</span>MySQL:<span style="color: #2028B8;">query</span> <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">format</span> <span style="color: #3AA43E;">&quot;SELECT data FROM sessions WHERE sid = '%s'&quot;</span> <span style="color: #AF0500;">&#40;</span>MySQL:<span style="color: #2028B8;">escape</span> <span style="color: #AF0500;">&#40;</span>Web:<span style="color: #2028B8;">session-id</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span>
    <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">let</span> <span style="color: #AF0500;">&#40;</span><span style="color: #AF0500;">&#40;</span>data <span style="color: #AF0500;">&#40;</span>MySQL:<span style="color: #2028B8;">fetch-row</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span>
      <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">if</span> data
        <span style="color: #808080; font-style: italic;">;; Evaluate the serialized context into the current session context</span>
        <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">eval-string</span> <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">first</span> data<span style="color: #AF0500;">&#41;</span> <span style="color: #AF0500;">&#40;</span>Web:<span style="color: #2028B8;">session-</span><span style="color: #2028B8;">context</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span>
        <span style="color: #808080; font-style: italic;">;; Create a new session and save it</span>
        <span style="color: #AF0500;">&#40;</span>MySQL:<span style="color: #2028B8;">query</span> <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">format</span> <span style="color: #3AA43E;">&quot;INSERT INTO sessions (sid, data) VALUES ('%s', '%s')&quot;</span>
          <span style="color: #AF0500;">&#40;</span>MySQL:<span style="color: #2028B8;">escape</span> <span style="color: #AF0500;">&#40;</span>Web:<span style="color: #2028B8;">session-id</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span>
          <span style="color: #AF0500;">&#40;</span>MySQL:<span style="color: #2028B8;">escape</span> <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">source</span> <span style="color: #AF0500;">&#40;</span>Web:<span style="color: #2028B8;">session-</span><span style="color: #2028B8;">context</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span>
&nbsp;
<span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">define</span> <span style="color: #AF0500;">&#40;</span>close-session<span style="color: #AF0500;">&#41;</span>
  <span style="color: #AF0500;">&#40;</span>MySQL:<span style="color: #2028B8;">query</span> <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">format</span> <span style="color: #3AA43E;">&quot;UPDATE sessions SET data = '%s' WHERE sid = '%s'&quot;</span>
    <span style="color: #AF0500;">&#40;</span>MySQL:<span style="color: #2028B8;">escape</span> <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">source</span> <span style="color: #AF0500;">&#40;</span>Web:<span style="color: #2028B8;">session-</span><span style="color: #2028B8;">context</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span>
    <span style="color: #AF0500;">&#40;</span>MySQL:<span style="color: #2028B8;">escape</span> <span style="color: #AF0500;">&#40;</span>Web:<span style="color: #2028B8;">session-id</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span>
&nbsp;
<span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">define</span> <span style="color: #AF0500;">&#40;</span>delete-session<span style="color: #AF0500;">&#41;</span>
  <span style="color: #AF0500;">&#40;</span>MySQL:<span style="color: #2028B8;">query</span> <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">format</span> <span style="color: #3AA43E;">&quot;DELETE FROM sessions WHERE sid = '%s'&quot;</span>
    <span style="color: #AF0500;">&#40;</span>MySQL:<span style="color: #2028B8;">escape</span> <span style="color: #AF0500;">&#40;</span>Web:<span style="color: #2028B8;">session-id</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span>
&nbsp;
<span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">define</span> <span style="color: #AF0500;">&#40;</span>clean-sessions<span style="color: #AF0500;">&#41;</span>
  <span style="color: #AF0500;">&#40;</span>MySQL:<span style="color: #2028B8;">query</span> <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">format</span> <span style="color: #3AA43E;">&quot;DELETE FROM sessions WHERE NOW() &gt;= DATE_ADD(ts, INTERVAL %d SECOND)&quot;</span>
    Web:<span style="color: #2028B8;">SESSION_MAX_AGE</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span>
&nbsp;
<span style="color: #AF0500;">&#40;</span>Web:<span style="color: #2028B8;">define-session-handlers</span>
  open-session close-session delete-session clean-sessions<span style="color: #AF0500;">&#41;</span>
&nbsp;
<span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">context</span> '<span style="color: #2028B8;">MAIN</span><span style="color: #AF0500;">&#41;</span></pre></div></div>

<!-- Social Bookmarks BEGIN -->
<div class="social_bookmark">
<a><strong><em>Submit article</em></strong></a>
<br />
<div class="d">
<br />
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://del.icio.us/post?url=http%3A%2F%2Fwww.artfulcode.net%2Farticles%2Fcustom-session-storage-with-newlisp-web%2F&amp;title=Custom+session+storage+with+newLISP+Web" rel="nofollow" title="Add to&nbsp;Del.icio.us"><img class="social_img" src="http://www.artfulcode.net/wp-content/plugins/social-bookmarks/images/delicious.png" title="Add to&nbsp;Del.icio.us" alt="Add to&nbsp;Del.icio.us" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fwww.artfulcode.net%2Farticles%2Fcustom-session-storage-with-newlisp-web%2F&amp;title=Custom+session+storage+with+newLISP+Web" rel="nofollow" title="Add to&nbsp;digg"><img class="social_img" src="http://www.artfulcode.net/wp-content/plugins/social-bookmarks/images/digg.png" title="Add to&nbsp;digg" alt="Add to&nbsp;digg" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.dzone.com/links/add.html?description=Custom+session+storage+with+newLISP+Web&amp;url=http%3A%2F%2Fwww.artfulcode.net%2Farticles%2Fcustom-session-storage-with-newlisp-web%2F&amp;title=Custom+session+storage+with+newLISP+Web" rel="nofollow" title="Add to&nbsp;DZone"><img class="social_img" src="http://www.artfulcode.net/wp-content/plugins/social-bookmarks/images/dzone.png" title="Add to&nbsp;DZone" alt="Add to&nbsp;DZone" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.facebook.com/sharer.php?u=http%3A%2F%2Fwww.artfulcode.net%2Farticles%2Fcustom-session-storage-with-newlisp-web%2F" rel="nofollow" title="Add to&nbsp;Facebook"><img class="social_img" src="http://www.artfulcode.net/wp-content/plugins/social-bookmarks/images/facebook.png" title="Add to&nbsp;Facebook" alt="Add to&nbsp;Facebook" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://reddit.com/submit?url=http%3A%2F%2Fwww.artfulcode.net%2Farticles%2Fcustom-session-storage-with-newlisp-web%2F&amp;title=Custom+session+storage+with+newLISP+Web" rel="nofollow" title="Add to&nbsp;reddit"><img class="social_img" src="http://www.artfulcode.net/wp-content/plugins/social-bookmarks/images/reddit.png" title="Add to&nbsp;reddit" alt="Add to&nbsp;reddit" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.stumbleupon.com/submit?url=http%3A%2F%2Fwww.artfulcode.net%2Farticles%2Fcustom-session-storage-with-newlisp-web%2F&amp;title=Custom+session+storage+with+newLISP+Web" rel="nofollow" title="Add to&nbsp;Stumble Upon"><img class="social_img" src="http://www.artfulcode.net/wp-content/plugins/social-bookmarks/images/stumbleupon.png" title="Add to&nbsp;Stumble Upon" alt="Add to&nbsp;Stumble Upon" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.technorati.com/faves?add=http%3A%2F%2Fwww.artfulcode.net%2Farticles%2Fcustom-session-storage-with-newlisp-web%2F" rel="nofollow" title="Add to&nbsp;Technorati"><img class="social_img" src="http://www.artfulcode.net/wp-content/plugins/social-bookmarks/images/technorati.png" title="Add to&nbsp;Technorati" alt="Add to&nbsp;Technorati" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://twitter.com/home/?status=Check+out+Custom+session+storage+with+newLISP+Web+@+http%3A%2F%2Fwww.artfulcode.net%2Farticles%2Fcustom-session-storage-with-newlisp-web%2F" rel="nofollow" title="Add to&nbsp;Twitter"><img class="social_img" src="http://www.artfulcode.net/wp-content/plugins/social-bookmarks/images/twitter.png" title="Add to&nbsp;Twitter" alt="Add to&nbsp;Twitter" /></a>
<br />
</div>
</div>
<!-- Social Bookmarks END -->
]]></content:encoded>
			<wfw:commentRss>http://www.artfulcode.net/articles/custom-session-storage-with-newlisp-web/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>A better newLISP web library</title>
		<link>http://www.artfulcode.net/articles/a-better-newlisp-web-library/</link>
		<comments>http://www.artfulcode.net/articles/a-better-newlisp-web-library/#comments</comments>
		<pubDate>Fri, 29 May 2009 13:32:29 +0000</pubDate>
		<dc:creator>Jeff</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[newlisp]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.artfulcode.net/?p=648</guid>
		<description><![CDATA[One problem from which newLISP suffers is the lack of a really useful library for web-based applications. The <a href="http://newlisp.nfshost.com/code/modules/cgi.lsp.html">official CGI module</a> has serious enough problems to justify an entirely new library. After some thought, I decided moreover that the <a href="http://static.artfulcode.net/newlisp/request.lsp.html">request</a> and <a href="http://static.artfulcode.net/newlisp/response.lsp.html">response</a> modules that I designed were neither practical nor sufficient. To that end, I have designed a new, monolithic library to provide the essential functionality required for web programming]]></description>
			<content:encoded><![CDATA[<p>One problem from which newLISP suffers is the lack of a really useful library for web-based applications. The <a href="http://newlisp.nfshost.com/code/modules/cgi.lsp.html">official CGI module</a> has serious enough problems to justify an entirely new library. After some thought, I decided moreover that the <a href="http://static.artfulcode.net/newlisp/request.lsp.html">request</a> and <a href="http://static.artfulcode.net/newlisp/response.lsp.html">response</a> modules that I designed were neither practical nor sufficient. To that end, I have designed a new, monolithic library to provide the essential functionality required for web programming.<span id="more-648"></span></p>
<p>The official CGI module has some real issues. First, it combines POST and GET variables into a single structure. This has two serious consequences: 1) the application has no way to determine the method by which a parameter is passed (that information is completely lost), and 2) name clashes between GET and POST result in the loss of one or the other parameter (in the case of the CGI module, GET information would be overwritten.)</p>
<p>Another issue in the CGI module is with the <code>put-page</code> function, which breaks if &#8220;%&gt;&#8221; is used inside of a code island, even legitimately, such as in a string.</p>
<p><a href="http://static.artfulcode.net/newlisp/web.lsp.html">Web</a> fixes both of these problems and provides a number of other features, including:</p>
<ul>
<li>ASP/PHP-style templates</li>
<li>Getting/setting cookies, GET, and POST parameters</li>
<li>Entity encoding and decoding</li>
<li>HTTP header control</li>
<li>Sessions</li>
<li>Custom session storage</li>
<li>URL building and parsing</li>
<li>URL encoding and decoding</li>
<li>Query string building and parsing</li>
</ul>
<p>Additionally, Web does not suffer from the GET/POST issues that the CGI module does, nor does it mishandle tags inside of code.</p>
<h2>HTTP Headers</h2>
<p>Headers are set using <a href="http://static.artfulcode.net/newlisp/web.lsp.html#Web_header"><code>Web:header</code></a>, which accepts two parameters &#8211; the header name and the header value. By default, one header is already set: <strong>Content-type: text/html</strong>. Headers are output using <a href="http://static.artfulcode.net/newlisp/web.lsp.html#Web_send-headers"><code>Web:send-headers</code></a>, which is called before any other output. The convenience function <a href="http://static.artfulcode.net/newlisp/web.lsp.html#Web_redir"><code>Web:redir</code></a> redirects the browser to the passed URL.</p>
<h2>GET and POST</h2>
<p>GET and POST variables are accessed using <a href="http://static.artfulcode.net/newlisp/web.lsp.html#Web_get"><code>Web:get</code></a> and <a href="http://static.artfulcode.net/newlisp/web.lsp.html#Web_post"><code>Web:post</code></a>, which may be called in two ways. When called with a single parameter, these functions act like <code>lookup</code> and return the GET/POST parameter with the named key. When called with no parameters, they return an association list of the corresponding query.</p>
<h2>Cookies</h2>
<p>Cookies must be set before headers are sent. They are set using the <a href="http://static.artfulcode.net/newlisp/web.lsp.html#Web_cookie"><code>Web:cookie</code></a> function, which accepts up to six parameters.</p>

<div class="wp_syntax"><div class="code"><pre class="newlisp" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">;; Set a basic cookie</span>
<span style="color: #AF0500;">&#40;</span>cookie <span style="color: #3AA43E;">&quot;foo&quot;</span> <span style="color: #3AA43E;">&quot;bar&quot;</span><span style="color: #AF0500;">&#41;</span>
<span style="color: #808080; font-style: italic;">;; Access a cookie value</span>
<span style="color: #AF0500;">&#40;</span>cookie <span style="color: #3AA43E;">&quot;foo&quot;</span><span style="color: #AF0500;">&#41;</span>
<span style="color: #808080; font-style: italic;">;; Delete a cookie by setting expires to now</span>
<span style="color: #AF0500;">&#40;</span>cookie <span style="color: #3AA43E;">&quot;foo&quot;</span> <span style="color: #2028B8;">nil</span> <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">date-value</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span>
<span style="color: #808080; font-style: italic;">;; Set a cookie that expires in an hour</span>
<span style="color: #AF0500;">&#40;</span>cookie <span style="color: #3AA43E;">&quot;foo&quot;</span> <span style="color: #3AA43E;">&quot;bar&quot;</span> <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">+</span> <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">date-value</span><span style="color: #AF0500;">&#41;</span> <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">*</span> <span style="color: #675400;">60</span> <span style="color: #675400;">60</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span></pre></div></div>

<p>See the <a href="http://static.artfulcode.net/newlisp/web.lsp.html#Web_cookie">documentation</a> for a full list of accepted parameters.</p>
<h2>Sessions</h2>
<p>By default, sessions use file-based storage (located at /tmp). They are controlled with a few simple functions. The default <code>exit</code> function is wrapped to ensure that <code>Web:close-session</code> is called at the end of a script (at least, a script that calls <code>exit</code> at its end.)</p>

<div class="wp_syntax"><div class="code"><pre class="newlisp" style="font-family:monospace;"><span style="color: #AF0500;">&#40;</span>Web:<span style="color: #2028B8;">open-session</span><span style="color: #AF0500;">&#41;</span>
<span style="color: #AF0500;">&#40;</span>Web:<span style="color: #2028B8;">session</span> <span style="color: #3AA43E;">&quot;foo&quot;</span> <span style="color: #3AA43E;">&quot;bar&quot;</span><span style="color: #AF0500;">&#41;</span> <span style="color: #808080; font-style: italic;">; store &quot;foo&quot; as &quot;bar&quot;</span>
<span style="color: #AF0500;">&#40;</span>Web:<span style="color: #2028B8;">send-headers</span><span style="color: #AF0500;">&#41;</span> <span style="color: #808080; font-style: italic;">; start output</span>
<span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">println</span> <span style="color: #3AA43E;">&quot;&lt;p&gt;&lt;strong&gt;foo is:&lt;/strong&gt; &quot;</span> <span style="color: #AF0500;">&#40;</span>Web:<span style="color: #2028B8;">session</span> <span style="color: #3AA43E;">&quot;foo&quot;</span><span style="color: #AF0500;">&#41;</span> <span style="color: #3AA43E;">&quot;&lt;/p&gt;&quot;</span><span style="color: #AF0500;">&#41;</span>
<span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">exit</span> <span style="color: #675400;">0</span><span style="color: #AF0500;">&#41;</span></pre></div></div>

<p>It is a simple matter to design and use custom storage handlers. The function <a href="http://static.artfulcode.net/newlisp/web.lsp.html#Web_define-session-handlers"><code>Web:define-session-handlers</code></a> allows customization of which functions are called to begin/load, close/write, delete a session, and clear old sessions. See the <a href="http://static.artfulcode.net/newlisp/web.lsp.html#Web_define-session-handlers">documentation</a> for a list of helpful functions and variables for custom storage handlers.</p>
<h2>Templates</h2>
<p>Templates work almost identically to the official CGI module, with a few differences. First, <a href="http://static.artfulcode.net/newlisp/web.lsp.html#Web_eval-template"><code>Web:eval-template</code></a> is called with a string, rather than a file, to permit other storage methods and programmatic building of templates. Second, &lt;%= .. %&gt; may be substituted for the default opening tag as a shortcut for &lt;% (print &#8230; ) %&gt;. Last, the opening and closing tags may be customized by setting values of <code>Web:OPEN_TAG</code> and <code>Web:CLOSE_TAG</code>. The shortcut tag will always be <code>Web:OPEN_TAG</code> appended with and equal sign.</p>
<h2>Encoding and decoding</h2>
<p>There are several functions to make encoding, decoding, and escaping strings easier for dealing with URLs, javascript, and HTML entities.</p>
<p><a href="http://static.artfulcode.net/newlisp/web.lsp.html#Web_escape"><code>Web:escape</code></a> takes a string and encodes the basic HTML character entities (apostrophe, quote, ampersand, and left and right angle brackets.) <a href="http://static.artfulcode.net/newlisp/web.lsp.html#Web_unescape"><code>Web:unescape</code></a> provides the reverse. The function <a href="http://static.artfulcode.net/newlisp/web.lsp.html#Web_escape-js"><code>Web:escape-js</code></a> does no encoding of entities, but instead ensures that a string may be safely output in javascript string without causing syntax errors.</p>
<p><a href="http://static.artfulcode.net/newlisp/web.lsp.html#Web_encode-entities"><code>Web:encode-entities</code></a> encodes all HTML entities, including a number of entities that are not fully supported by all browser. The full list of entities is derived from <a href="http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references">Wikipedia</a>. Its reverse, <a href="http://static.artfulcode.net/newlisp/web.lsp.html#Web_decode-entities"><code>Web:decode-entities</code></a>, translates entities back into their character equivalents.</p>
<p>The functions <a href="http://static.artfulcode.net/newlisp/web.lsp.html#Web_url-encode"><code>Web:url-encode</code></a> and <a href="http://static.artfulcode.net/newlisp/web.lsp.html#Web_url-decode"><code>Web:url-decode</code></a> deal with hex-encoding/decoding strings for use in URLs.</p>
<p>Query strings are easily created using <a href="http://static.artfulcode.net/newlisp/web.lsp.html#Web_build-query"><code>Web:build-query</code></a>, modeled after the PHP function  <code>http_build_query</code>.  Its counterpart, <a href="http://static.artfulcode.net/newlisp/web.lsp.html#Web_parse-query"><code>Web:parse-query</code></a>, takes a query string and turns it into an association list.</p>
<p>For URLs, it is simpler to use <a href="http://static.artfulcode.net/newlisp/web.lsp.html#Web_build-url"><code>Web:build-url</code></a>, which takes a URL and any number of association lists which it uses to build a complete URL. Each alist may overwrite parameters from the previous, including any parameters on the passed URL.</p>

<div class="wp_syntax"><div class="code"><pre class="newlisp" style="font-family:monospace;"><span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">let</span> <span style="color: #AF0500;">&#40;</span><span style="color: #AF0500;">&#40;</span>url <span style="color: #3AA43E;">&quot;http://www.artfulcode.net/?s=newlisp&quot;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span>
  <span style="color: #AF0500;">&#40;</span><span style="color: #2028B8;">println</span> <span style="color: #AF0500;">&#40;</span>Web:<span style="color: #2028B8;">build-url</span> url '<span style="color: #AF0500;">&#40;</span><span style="color: #AF0500;">&#40;</span><span style="color: #3AA43E;">&quot;s&quot;</span> <span style="color: #3AA43E;">&quot;newlisp web module&quot;</span><span style="color: #AF0500;">&#41;</span> <span style="color: #AF0500;">&#40;</span><span style="color: #3AA43E;">&quot;foo&quot;</span> <span style="color: #3AA43E;">&quot;bar&quot;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span><span style="color: #AF0500;">&#41;</span>
<span style="color: #808080; font-style: italic;">;; =&gt; http://www.artfulcode.net/?s=newlisp+web+module&amp;foo=bar</span></pre></div></div>

<p>It also has a counterpart, <a href="http://static.artfulcode.net/newlisp/web.lsp.html#Web_parse-url"><code>Web:parse-url</code></a>, which breaks a URL up into an association list of its component parts.</p>
<h2>Download</h2>
<p>You can find it in the <a href="http://static.artfulcode.net/newlisp/index.html">repository</a> or download it directly <a href="http://static.artfulcode.net/newlisp/web.lsp">here</a>.</p>
<!-- Social Bookmarks BEGIN -->
<div class="social_bookmark">
<a><strong><em>Submit article</em></strong></a>
<br />
<div class="d">
<br />
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://del.icio.us/post?url=http%3A%2F%2Fwww.artfulcode.net%2Farticles%2Fa-better-newlisp-web-library%2F&amp;title=A+better+newLISP+web+library" rel="nofollow" title="Add to&nbsp;Del.icio.us"><img class="social_img" src="http://www.artfulcode.net/wp-content/plugins/social-bookmarks/images/delicious.png" title="Add to&nbsp;Del.icio.us" alt="Add to&nbsp;Del.icio.us" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fwww.artfulcode.net%2Farticles%2Fa-better-newlisp-web-library%2F&amp;title=A+better+newLISP+web+library" rel="nofollow" title="Add to&nbsp;digg"><img class="social_img" src="http://www.artfulcode.net/wp-content/plugins/social-bookmarks/images/digg.png" title="Add to&nbsp;digg" alt="Add to&nbsp;digg" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.dzone.com/links/add.html?description=A+better+newLISP+web+library&amp;url=http%3A%2F%2Fwww.artfulcode.net%2Farticles%2Fa-better-newlisp-web-library%2F&amp;title=A+better+newLISP+web+library" rel="nofollow" title="Add to&nbsp;DZone"><img class="social_img" src="http://www.artfulcode.net/wp-content/plugins/social-bookmarks/images/dzone.png" title="Add to&nbsp;DZone" alt="Add to&nbsp;DZone" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.facebook.com/sharer.php?u=http%3A%2F%2Fwww.artfulcode.net%2Farticles%2Fa-better-newlisp-web-library%2F" rel="nofollow" title="Add to&nbsp;Facebook"><img class="social_img" src="http://www.artfulcode.net/wp-content/plugins/social-bookmarks/images/facebook.png" title="Add to&nbsp;Facebook" alt="Add to&nbsp;Facebook" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://reddit.com/submit?url=http%3A%2F%2Fwww.artfulcode.net%2Farticles%2Fa-better-newlisp-web-library%2F&amp;title=A+better+newLISP+web+library" rel="nofollow" title="Add to&nbsp;reddit"><img class="social_img" src="http://www.artfulcode.net/wp-content/plugins/social-bookmarks/images/reddit.png" title="Add to&nbsp;reddit" alt="Add to&nbsp;reddit" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.stumbleupon.com/submit?url=http%3A%2F%2Fwww.artfulcode.net%2Farticles%2Fa-better-newlisp-web-library%2F&amp;title=A+better+newLISP+web+library" rel="nofollow" title="Add to&nbsp;Stumble Upon"><img class="social_img" src="http://www.artfulcode.net/wp-content/plugins/social-bookmarks/images/stumbleupon.png" title="Add to&nbsp;Stumble Upon" alt="Add to&nbsp;Stumble Upon" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.technorati.com/faves?add=http%3A%2F%2Fwww.artfulcode.net%2Farticles%2Fa-better-newlisp-web-library%2F" rel="nofollow" title="Add to&nbsp;Technorati"><img class="social_img" src="http://www.artfulcode.net/wp-content/plugins/social-bookmarks/images/technorati.png" title="Add to&nbsp;Technorati" alt="Add to&nbsp;Technorati" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://twitter.com/home/?status=Check+out+A+better+newLISP+web+library+@+http%3A%2F%2Fwww.artfulcode.net%2Farticles%2Fa-better-newlisp-web-library%2F" rel="nofollow" title="Add to&nbsp;Twitter"><img class="social_img" src="http://www.artfulcode.net/wp-content/plugins/social-bookmarks/images/twitter.png" title="Add to&nbsp;Twitter" alt="Add to&nbsp;Twitter" /></a>
<br />
</div>
</div>
<!-- Social Bookmarks END -->
]]></content:encoded>
			<wfw:commentRss>http://www.artfulcode.net/articles/a-better-newlisp-web-library/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
	</channel>
</rss>

