<?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>blyberg.net &#187; PHP</title>
	<atom:link href="http://www.blyberg.net/tag/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.blyberg.net</link>
	<description>A library-geek blog</description>
	<lastBuildDate>Mon, 16 Nov 2009 04:10:55 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=abc</generator>
		<item>
		<title>Dynamic item recommendations</title>
		<link>http://www.blyberg.net/2007/01/31/dynamic-item-recommendations/</link>
		<comments>http://www.blyberg.net/2007/01/31/dynamic-item-recommendations/#comments</comments>
		<pubDate>Wed, 31 Jan 2007 15:54:33 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Libraries]]></category>
		<category><![CDATA[AADL]]></category>
		<category><![CDATA[OPAC]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Reccomendations]]></category>

		<guid isPermaLink="false">http://www.blyberg.net/2007/01/31/dynamic-item-recommendations/</guid>
		<description><![CDATA[So today, at AADL, we quietly rolled out dynamic item recommendations. That means that when you're looking at a catalog record, you'll be given Amazon-like recommendations ("Users who checked out this item also checked out these library items.."). This little feature uses data from our opt-in patron history system. Since we've been offering that system [...]]]></description>
			<content:encoded><![CDATA[<p>So today, at AADL, we quietly rolled out dynamic item recommendations.  That means that when you're looking at a catalog record, you'll be given Amazon-like recommendations ("Users who checked out this item also checked out these library items..").<a href="http://www.flickr.com/photos/jblyberg/375550585/"><img src="http://farm1.static.flickr.com/180/375550585_1157e702ca.jpg?v=0" border="0" height="158" width="500" /></a></p>
<p>This little feature uses data from our opt-in <a href="/2005/12/01/enhanced-patron-history/">patron history</a> system.  Since we've been offering that system for about a year now, we've been able to accumulate over 300,000 data points.  This is another great example of how to reuse your existing data to enrich use experience.  Like I've said before, you need to use the data you have to its full potential--even if it's not the data's primary purpose.</p>
<p>Ok, so let's look at the nuts and bolts of this.  I was able to cobble this together with two SQL queries.  Actually, I was able to get the same results with a single nested query, but for some reason, non-cached results took upward of ten seconds, so splitting the query seemed like the right thing to do.</p>
<p>Anyway..</p>
<div class="igBar"><span id="lphp-2"><a href="#" onclick="javascript:showPlainTxt('php-2'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">PHP:</span>
<div id="php-2">
<div class="php">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#0000FF;">$bibinfo</span> = <span style="color:#0000FF;">$xmlopac</span>-&amp;gt;get_opac_data<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#0000FF;">$bnum</span><span style="color:#006600; font-weight:bold;">&#41;</span>;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#0000FF;">$mattype</span> = <span style="color:#0000FF;">$bibinfo</span><span style="color:#006600; font-weight:bold;">&#91;</span>mattype<span style="color:#006600; font-weight:bold;">&#93;</span>;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#0000FF;">$rec_uids</span> = db_query<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#FF0000;">"SELECT DISTINCT(uid) AS uid FROM iii_hist_data WHERE bnum = '$bnum'"</span><span style="color:#006600; font-weight:bold;">&#41;</span>;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#0000FF;">$subcrit</span> = <span style="color:#FF0000;">''</span>;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#616100;">while</span> <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#0000FF;">$rec_uid</span> = db_fetch_array<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#0000FF;">$rec_uids</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&#123;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#616100;">if</span> <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#0000FF;">$rec_uid</span><span style="color:#006600; font-weight:bold;">&#91;</span>uid<span style="color:#006600; font-weight:bold;">&#93;</span> != <span style="color:#0000FF;">$user</span>-&amp;gt;uid<span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&#123;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#0000FF;">$subcrit</span> .= <span style="color:#0000FF;">$rec_uid</span><span style="color:#006600; font-weight:bold;">&#91;</span>uid<span style="color:#006600; font-weight:bold;">&#93;</span> . <span style="color:#FF0000;">', '</span>;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#006600; font-weight:bold;">&#125;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#006600; font-weight:bold;">&#125;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#0000FF;">$subcrit</span> = <a href="http://www.php.net/substr"><span style="color:#000066;">substr</span></a><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#0000FF;">$subcrit</span>, <span style="color:#CC66CC;color:#800000;">0</span>, -<span style="color:#CC66CC;color:#800000;">2</span><span style="color:#006600; font-weight:bold;">&#41;</span>;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#0000FF;">$rec_bibs</span> = db_query<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#FF0000;">"SELECT DISTINCT(bnum), COUNT(bnum) AS total FROM iii_hist_data WHERE mattype = '$mattype' AND bnum != '$bnum' AND uid IN ($subcrit) GROUP BY bnum HAVING count(bnum)&amp;gt; 2 ORDER BY RAND() DESC LIMIT 5"</span><span style="color:#006600; font-weight:bold;">&#41;</span>;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#616100;">if</span> <span style="color:#006600; font-weight:bold;">&#40;</span>!db_num_rows<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#0000FF;">$rec_bibs</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#616100;">return</span>; <span style="color:#006600; font-weight:bold;">&#125;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#616100;">while</span> <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#0000FF;">$rec</span> = db_fetch_array<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#0000FF;">$rec_bibs</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&#123;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#FF9933; font-style:italic;">// Do your business here</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#006600; font-weight:bold;">&#125;</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>So basically, you can see what's happening here.  First I get an array of all the other users who have checked out this item.  Then I get a list of items that three or more of those people have checked out and display it randomly (so it's not always the same list).  Pretty easy, of course you need to grow that data before it becomes useful.  300,000 records makes the results pertinent, 300 does not.</p>
<p>If you're curious, head on over to AADL's <a href="http://www.aadl.org/catalog/">catalog</a> and test it out.. you might stumble on something new.</p>
<p>The next step, of course, in all this SOPAC business is to try to determine how check-out patterns are changing and whether it will have an impact on collection development.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.blyberg.net/2007/01/31/dynamic-item-recommendations/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>PatREST to Include OCLC Audience Level Data</title>
		<link>http://www.blyberg.net/2006/09/15/patrest-to-include-oclc-audience-level-data/</link>
		<comments>http://www.blyberg.net/2006/09/15/patrest-to-include-oclc-audience-level-data/#comments</comments>
		<pubDate>Fri, 15 Sep 2006 13:31:17 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Libraries]]></category>
		<category><![CDATA[OPAC]]></category>
		<category><![CDATA[PatREST]]></category>
		<category><![CDATA[Patron-REST]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web Services]]></category>
		<category><![CDATA[XML]]></category>

		<guid isPermaLink="false">http://www.blyberg.net/2006/09/15/patrest-to-include-oclc-audience-level-data/</guid>
		<description><![CDATA[I've updated AADL's PatREST interface to reflect an addition I've made to the PatREST specification (now 1.3). This addition takes advantage of OCLC's Audience Level indicator. OCLC makes this information available via an XML web service. From their service page: There are a variety of ways to characterize library materials. The type of reader believed [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.flickr.com/photos/jblyberg/243854995/"><img src="http://static.flickr.com/97/243854995_cb68f16623_m.jpg" align="right" /></a>I've updated AADL's <a href="http://www.aadl.org/rest/record/1120526/">PatREST interface</a> to reflect an addition I've made to the PatREST specification (now <a href="/downloads/patrest_1.3_overview.pdf">1.3</a>).  This addition takes advantage of OCLC's <a href="http://www.oclc.org/research/projects/audience/default.htm">Audience Level indicator</a>.  OCLC makes this information available via an XML web service.  From their service page:</p>
<blockquote><p>There are a variety of ways to characterize library materials. The type of reader believed to be interested in a particular item is one. Such an indicator, generally known as the audience level, is potentially useful for a variety of activities, including the development of new ways to improve information relevance for retrieval, reference services (including readers advisory) and collection development. Audience-level filters could be implemented in existing retrieval systems to assist users in finding content based on their information needs.</p></blockquote>
<p>This is not the first OCLC service PatREST has taken advantage of.  PatREST has been incorporating data from OCLC's xISBN service for quite some time.  By pulling in the data they make available, the data PatREST is able to return becomes significantly more valuable.</p>
<p>Because AADL's PatREST implementation relies heavily upon III's XML server, I've added OCLC's Audience Level functionality to the PHP XMLOPAC class code which is freely available from my <a href="/files/">files</a> page or you can directly grab it right <a href="/downloads/iii-xmlopac-1.11.tar.gz">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.blyberg.net/2006/09/15/patrest-to-include-oclc-audience-level-data/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>AADL.org upgrades to Drupal 4.7</title>
		<link>http://www.blyberg.net/2006/09/05/aadlorg-upgrades-to-drupal-47/</link>
		<comments>http://www.blyberg.net/2006/09/05/aadlorg-upgrades-to-drupal-47/#comments</comments>
		<pubDate>Tue, 05 Sep 2006 19:08:28 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Libraries]]></category>
		<category><![CDATA[AADL]]></category>
		<category><![CDATA[aadl.org]]></category>
		<category><![CDATA[CMS]]></category>
		<category><![CDATA[Drupal]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://www.blyberg.net/2006/09/05/aadlorg-upgrades-to-drupal-47/</guid>
		<description><![CDATA[A little over a year after launch, AADL's Drupal-powered site has been upgraded to 4.7 from 4.6. Those familiar with Drupal's release schedule and changelog will know that this is a substantial upgrade that puts us in a good position to be ready for the touted and forthcoming 5.0 release (for which there is now [...]]]></description>
			<content:encoded><![CDATA[<p>A little over a year after launch, <a href="http://www.aadl.org/">AADL</a>'s <a href="http://www.drupal.org">Drupal</a>-powered <a href="http://www.aadl.org/">site</a> has been upgraded to 4.7 from 4.6.  Those familiar with Drupal's release schedule and changelog will know that this is a substantial upgrade that puts us in a good position to be ready for the touted and forthcoming 5.0 release (for which there is now a <a href="http://drupal.org/drupal-5.0.0-code-freeze">code freeze</a>).</p>
<p><a href="http://www.drupal.org"><img src="/wp-content/images/drupaqua.png" alt="" align="left" /></a>Drupal 4.7 sports a number of great new features.  I'm most excited about the new search engine which does a much better job of indexing the site and allows users to do an <a href="http://www.aadl.org/search/node">advanced search</a>.  Searches now <em>actually</em> return meaningful results.  Other features include a new Ajax-enabled content creation system with nifty improvements such as re-sizable text fields, collapsible elements, a file upload system that doesn't require authors to leave their work, and live menu updates.  On the development side, these new features are accessible via the new <a href="http://api.drupal.org/api/4.7/group/form">form-handling system</a>.  In other words, coders can easily incorporate these new Ajax elements in their own work.  Theme developers will be happy with the ability to create an infinite number of regions--nice to achieve that highly-polished CSS look.  I think a couple new block types were added as well.</p>
<p>Another great feature is the wiki-style revision system that allows editors to roll-back their work and leave editorial log messages (a very useful feature in large, collaborative environments).  Commenting benefits, as well, with the ability of site administrators to manage and moderate multiple entries at once.  Finally, Drupal 4.7 supports free tagging.  Not something we're using at this point, but, from my point of view, it means that the engine is there for future module work.  I have a feeling I'll be using those hooks for some forthcoming feature upgrades on the website itself...</p>
<p>The upgrade was fairly smooth.  Drupal ships with an update script which ran flawlessly, but that's the easy part.  A fair amount of prep-work was done ahead of time to ensure that all of our custom modules were 4.7-compatible.  Basically, this meant updating all of our form-handling code to handle the new system.  We also segregated all of our own code and theme information from Drupal's using the multi-site capability.  This means that we can easily keep track of our own work without it getting mixed up with the vanilla code-base.  This wasn't completely necessary, but it was worth the work because it'll make all future upgrades much easier to do.  Doing things this way is also in-line with my philosophy of never touching stock code unless you absolutely have to.</p>
<p>The long and the short of this whole upgrade means that our users will probably not notice a lot of difference, but we're now in a good position to work on AADL 3.2.  And <em>that</em> they will notice.</p>
<p>For more info, check out these Drupal videocasts:</p>
<ul>
<li><a href="http://drupal.org/node/63155">An overview of screencasts</a></li>
<li><a href="http://drupal.org/videocasts/whats-new-in-4.7">What's new in Drupal 4.7</a></li>
<li><a href="http://drupal.org/videocasts/installing-4.7">Installing Drupal 4.7</a></li>
<li><a href="http://drupal.org/videocasts/upgrading-to-4.7">Upgrading to Drupal 4.7</a></li>
<li><a href="http://drupal.org/node/62196">Contribute your own Drupal Videocast</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.blyberg.net/2006/09/05/aadlorg-upgrades-to-drupal-47/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>III XMLOPAC: findings, promise, and a little relief</title>
		<link>http://www.blyberg.net/2006/03/31/iii-xmlopac-findings-promise-and-a-little-relief/</link>
		<comments>http://www.blyberg.net/2006/03/31/iii-xmlopac-findings-promise-and-a-little-relief/#comments</comments>
		<pubDate>Fri, 31 Mar 2006 21:16:49 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Libraries]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Code4Lib]]></category>
		<category><![CDATA[DomDocument]]></category>
		<category><![CDATA[MARC]]></category>
		<category><![CDATA[OPAC]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[SRU]]></category>
		<category><![CDATA[Web Services]]></category>
		<category><![CDATA[XML]]></category>
		<category><![CDATA[XMLOPAC]]></category>
		<category><![CDATA[XSLT]]></category>

		<guid isPermaLink="false">http://www.blyberg.net/2006/03/31/iii-xmlopac-findings-promise-and-a-little-relief/</guid>
		<description><![CDATA[Ryan Eby has done what III seems to not be able to do: Create a resource for XMLOPAC users. He's thrown up some wiki pages with the express purpose of documenting III's XMLOPAC. All I can say is, "Thank-you Ryan!" Be sure to participate and help with the documentation--we can all benefit from it. In [...]]]></description>
			<content:encoded><![CDATA[<p><img align="left" src="/wp-content/images/xmllogo.jpeg"/><a href="http://blog.ryaneby.com/">Ryan Eby</a> has done what <a href="http://www.iii.com">III</a> seems to not be able to do:  Create a resource for XMLOPAC users.  He's thrown up some <a href="http://wiki.lib.muohio.edu/xmlopac/index.php/Main_Page">wiki pages</a> with the express purpose of documenting III's XMLOPAC.  All I can say is, "Thank-you Ryan!"  Be sure to participate and help with the documentation--we can all benefit from it.</p>
<p>In addition, Ryan has written up a couple great how-to's on getting <a href="http://blog.ryaneby.com/archives/iii-item-data-from-xmlopac/">item data</a> and <a href="http://blog.ryaneby.com/archives/iii-featured-lists-from-the-xmlopac/">featured lists</a> from the XML.  I, for one, had no idea it was possible to grab featured lists this way.  Ryan Eby has been documenting III's XMLOPAC for quite some time now and he's certainly one of only a handful of authoritative voices on the feature.</p>
<p><a href="http://public.csusm.edu/dwalker/">David Walker</a> is another, and a very industrious voice at that.  Today I had a good chat with him on the <a href="http://www.code4lib.org">Code4Lib</a> <a href="http://www.code4lib.org/irc/faq">IRC channel</a> after he showed me his <a href="http://library.csusm.edu/catalog/sru/example/">totally amazing catalog</a> based off his equally cool <a href="http://library.csusm.edu/catalog/sru/">Shrew project</a>.  What he's been doing is <i>exactly</i> what I've been looking for.  Even though the Shrew project is currently written in C#, he has plans to port it to PHP5, taking advantage of <a href="http://us2.php.net/manual/en/ref.dom.php">DomDocument</a>.  It's a project I'm completely willing to commit some time to myself, if he asks.  The shrew project is "a system that converts the Innovative XML Server into an SRU/SRW and OpenSearch server."  He's put a great deal of time into writing XSLT that will translate the III server's output into MARC-XML, Dublin Core, or MODS 3.0.  My <a href="/files">XMLOPAC class</a> for PHP5 utilizes an older version of his MARC-XML XSLT, but I think when he pulls off this port, the need for my code will go away altogether--his way is preferable.</p>
<p>We also discussed some inherent problems with III's XMLOPAC--of which there are a number, and some potential enhancements.  Chief among them would be the ability to conduct business--placing items on hold and such.  A lot of work needs to be done, but I'm feeling much more optimistic about my OPAC aspirations now and, thanks to David and Ryan, a renewed sense of enthusiasm.  Thanks guys!</p>
<p><strong>[update]</strong> Ryan reminded me that <a href="http://foam.lib.muohio.edu/blog/">Rob Casson</a> is the individual who was kind enough to provide hosting for the wiki <strong>[/update]</strong></p>
<p>[tags] OPAC, XMLOPAC, XML, XSLT, Library, Code4Lib, PHP, C#, SRU, MARC, DomDocument, Web Services [/tags]</p>
]]></content:encoded>
			<wfw:commentRss>http://www.blyberg.net/2006/03/31/iii-xmlopac-findings-promise-and-a-little-relief/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Stick &#8216;em up! Easing the holds process</title>
		<link>http://www.blyberg.net/2006/03/16/stick-em-up-easing-the-holds-process/</link>
		<comments>http://www.blyberg.net/2006/03/16/stick-em-up-easing-the-holds-process/#comments</comments>
		<pubDate>Fri, 17 Mar 2006 03:38:39 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Libraries]]></category>
		<category><![CDATA[Coding]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.blyberg.net/2006/03/16/stick-em-up-easing-the-holds-process/</guid>
		<description><![CDATA[Starting today, patrons who have items on hold at select branches will notice something new about the material they receive: a sticky note. The whole point of these new stickers is to ease the work created by an ever-increasing volume of holds being placed on AADL material. Our processors have been bearing the brunt of [...]]]></description>
			<content:encoded><![CDATA[<p>Starting today, patrons who have items on hold at select branches will notice something new about the material they receive: a sticky note.</p>
<p><a href="http://www.flickr.com/photos/jblyberg/112889186/"><img align="left" src="http://static.flickr.com/50/112889186_6643ee8307_m.jpg"/></a>The whole point of these new stickers is to ease the work created by an ever-increasing volume of holds being placed on AADL material.  Our processors have been bearing the brunt of increased loads, partly due to general growth, but also because it is so easy to place a hold online now that the number of holds we get has shot up.  Now, as far as the processors are concerned, when they scan material that has been routed to the correct pickup location, a custom label, replete with patron information and barcode will spit right out of a networked label printer.  This removes a step or two from the process and has led to some very happy circulation staff.  Though I'm quite pleased with the way the labels turned out, what pleases me the most (besides the happy processors) is what happens behind the scenes.  <a href="http://www.flickr.com/photos/jblyberg/112889411/"><img align="right" src="http://static.flickr.com/43/112889411_28c3c567d5_m.jpg"/></a>What's fun about this are the relatively simple back-end components that make this work.</p>
<p>The III circulation client can be configured to send a print job to an email address instead of a standard receipt or line printer.  In this case, I've set up an instance of Exim running on a Linux box with an address alias that pipes the email through a very simple PHP script.  The PHP script parses the email, creates a PNG on the fly, then sends it to the label printer via cupsys lp.<a href="http://www.flickr.com/photos/jblyberg/113177210/"><img align="left" src="http://static.flickr.com/50/113177210_d47a663dd4_m.jpg"/></a>  I've been having a lot of fun with PHP's GD module lately and this little project really underscores how slick it can be.  In addition to GD, I also made use of PEAR's Image::Barcode class so that the item's barcode could be included on the tag.  Because PEAR's barcode class doesn't allow you to return the image as an object, I had to instantiate it as a separate script.  That's fine because you can just point <i>imagecreatefrompng</i> to the URL. The barcode script couldn't be simpler.  Not only that, it's so generic, you can really use it for all your barcoding needs:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-inlinetags">&lt;?php</span><span class="hl-code">
</span><span class="hl-comment">//</span><span class="hl-comment"> bcode.php</span><span class="hl-comment"></span><span class="hl-code">
</span><span class="hl-reserved">if</span><span class="hl-code"> </span><span class="hl-brackets">(</span><span class="hl-code">!</span><span class="hl-var">$_GET</span><span class="hl-brackets">[</span><span class="hl-identifier">input</span><span class="hl-brackets">]</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code"> </span><span class="hl-reserved">return</span><span class="hl-code">; </span><span class="hl-brackets">}</span><span class="hl-code">
</span><span class="hl-reserved">require_once</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">Image/Barcode.php</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-code">;
</span><span class="hl-var">$bcode</span><span class="hl-code"> = </span><span class="hl-reserved">new</span><span class="hl-code"> </span><span class="hl-identifier">Image_Barcode</span><span class="hl-code">;
</span><span class="hl-var">$bcode</span><span class="hl-code">-&gt;</span><span class="hl-identifier">draw</span><span class="hl-brackets">(</span><span class="hl-var">$_GET</span><span class="hl-brackets">[</span><span class="hl-identifier">input</span><span class="hl-brackets">]</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">int25</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">png</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-code">;
</span><span class="hl-inlinetags">?&gt;</span></pre></div></div>
<p>'Eh?  What a great class!  Here's the guts of the label code--messy, I know, but it works.  As you can see, it's utilizing PHP's CLI or CGI build.  Yes, PHP makes a <i>great</i> shell scripting language too!</p>
<div class="hl-surround" style="height:560px;"><div class="hl-main"><pre><span class="hl-code">#!/usr/bin/php5 -q
</span><span class="hl-inlinetags">&lt;?php</span><span class="hl-code">
 
</span><span class="hl-identifier">putenv</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">GDFONTPATH=</span><span class="hl-quotes">'</span><span class="hl-code"> . </span><span class="hl-identifier">realpath</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">/usr/local/php/fpdf/ttf/</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-brackets">)</span><span class="hl-code">;  </span><span class="hl-comment">//</span><span class="hl-comment"> Where my TTF fonts are</span><span class="hl-comment"></span><span class="hl-code">
 
</span><span class="hl-var">$fd</span><span class="hl-code"> = </span><span class="hl-identifier">fopen</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">php://stdin</span><span class="hl-quotes">&quot;</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">r</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-code">;
</span><span class="hl-var">$email</span><span class="hl-code"> = </span><span class="hl-quotes">&quot;</span><span class="hl-quotes">&quot;</span><span class="hl-code">;
</span><span class="hl-reserved">while</span><span class="hl-code"> </span><span class="hl-brackets">(</span><span class="hl-code">!</span><span class="hl-identifier">feof</span><span class="hl-brackets">(</span><span class="hl-var">$fd</span><span class="hl-brackets">)</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code">
        </span><span class="hl-var">$email</span><span class="hl-code"> .= </span><span class="hl-identifier">fread</span><span class="hl-brackets">(</span><span class="hl-var">$fd</span><span class="hl-code">, </span><span class="hl-number">1024</span><span class="hl-brackets">)</span><span class="hl-code">;
</span><span class="hl-brackets">}</span><span class="hl-code">
</span><span class="hl-identifier">fclose</span><span class="hl-brackets">(</span><span class="hl-var">$fd</span><span class="hl-brackets">)</span><span class="hl-code">;
 
</span><span class="hl-var">$item</span><span class="hl-code"> = </span><span class="hl-identifier">hold_item_info</span><span class="hl-brackets">(</span><span class="hl-var">$email</span><span class="hl-brackets">)</span><span class="hl-code">;
 
</span><span class="hl-var">$x</span><span class="hl-code"> = </span><span class="hl-number">350</span><span class="hl-code">;
</span><span class="hl-var">$y</span><span class="hl-code"> = </span><span class="hl-number">350</span><span class="hl-code">;
</span><span class="hl-var">$daysonshelf</span><span class="hl-code"> = </span><span class="hl-number">8</span><span class="hl-code">;
</span><span class="hl-var">$unique</span><span class="hl-code"> = </span><span class="hl-identifier">time</span><span class="hl-brackets">(</span><span class="hl-brackets">)</span><span class="hl-code"> . </span><span class="hl-identifier">rand</span><span class="hl-brackets">(</span><span class="hl-number">2000000</span><span class="hl-code">, </span><span class="hl-number">6000000</span><span class="hl-brackets">)</span><span class="hl-code">;
</span><span class="hl-var">$font</span><span class="hl-code"> = </span><span class="hl-quotes">'</span><span class="hl-string">arialbd</span><span class="hl-quotes">'</span><span class="hl-code">;
</span><span class="hl-var">$logourl</span><span class="hl-code"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">http://www.aadl.org/staticimages/aadllogo.gif</span><span class="hl-quotes">&quot;</span><span class="hl-code">;
</span><span class="hl-var">$bcodeurl</span><span class="hl-code"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">http://bcodeserver.aadl.org/bcode.php?input=</span><span class="hl-var">$item</span><span class="hl-string">[barcode]</span><span class="hl-quotes">&quot;</span><span class="hl-code">;
 
</span><span class="hl-comment">//</span><span class="hl-comment"> Create the image</span><span class="hl-comment"></span><span class="hl-code">
</span><span class="hl-var">$im</span><span class="hl-code"> = </span><span class="hl-identifier">imagecreatetruecolor</span><span class="hl-brackets">(</span><span class="hl-var">$x</span><span class="hl-code">, </span><span class="hl-var">$y</span><span class="hl-brackets">)</span><span class="hl-code">;
</span><span class="hl-var">$im2</span><span class="hl-code"> = </span><span class="hl-identifier">imagecreatefrompng</span><span class="hl-brackets">(</span><span class="hl-var">$bcodeurl</span><span class="hl-brackets">)</span><span class="hl-code">;
</span><span class="hl-var">$im3</span><span class="hl-code"> = </span><span class="hl-identifier">imagecreatefromgif</span><span class="hl-brackets">(</span><span class="hl-var">$logourl</span><span class="hl-brackets">)</span><span class="hl-code">;
 
</span><span class="hl-var">$white</span><span class="hl-code"> = </span><span class="hl-identifier">imagecolorallocate</span><span class="hl-brackets">(</span><span class="hl-var">$im</span><span class="hl-code">, </span><span class="hl-number">255</span><span class="hl-code">, </span><span class="hl-number">255</span><span class="hl-code">, </span><span class="hl-number">255</span><span class="hl-brackets">)</span><span class="hl-code">;
</span><span class="hl-var">$black</span><span class="hl-code"> = </span><span class="hl-identifier">imagecolorallocate</span><span class="hl-brackets">(</span><span class="hl-var">$im</span><span class="hl-code">, </span><span class="hl-number">0</span><span class="hl-code">, </span><span class="hl-number">0</span><span class="hl-code">, </span><span class="hl-number">0</span><span class="hl-brackets">)</span><span class="hl-code">;
 
</span><span class="hl-identifier">imagefill</span><span class="hl-brackets">(</span><span class="hl-var">$im</span><span class="hl-code">, </span><span class="hl-number">0</span><span class="hl-code">, </span><span class="hl-number">0</span><span class="hl-code">, $</span><span class="hl-var">$white</span><span class="hl-brackets">)</span><span class="hl-code">;
</span><span class="hl-identifier">imagefilledrectangle</span><span class="hl-brackets">(</span><span class="hl-var">$im</span><span class="hl-code">, </span><span class="hl-number">0</span><span class="hl-code">, </span><span class="hl-number">0</span><span class="hl-code">, </span><span class="hl-var">$x</span><span class="hl-code">, </span><span class="hl-var">$y</span><span class="hl-code">, </span><span class="hl-var">$white</span><span class="hl-brackets">)</span><span class="hl-code">;
 
</span><span class="hl-var">$spine_name</span><span class="hl-code"> = </span><span class="hl-var">$item</span><span class="hl-brackets">[</span><span class="hl-identifier">plname</span><span class="hl-brackets">]</span><span class="hl-code">;
</span><span class="hl-reserved">if</span><span class="hl-code"> </span><span class="hl-brackets">(</span><span class="hl-var">$item</span><span class="hl-brackets">[</span><span class="hl-identifier">pfname</span><span class="hl-brackets">]</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code"> </span><span class="hl-var">$spine_name</span><span class="hl-code"> .= </span><span class="hl-quotes">'</span><span class="hl-string">, </span><span class="hl-quotes">'</span><span class="hl-code"> . </span><span class="hl-identifier">strtoupper</span><span class="hl-brackets">(</span><span class="hl-var">$item</span><span class="hl-brackets">[</span><span class="hl-identifier">pfname</span><span class="hl-brackets">]</span><span class="hl-brackets">{</span><span class="hl-number">1</span><span class="hl-brackets">}</span><span class="hl-brackets">)</span><span class="hl-code"> . </span><span class="hl-quotes">'</span><span class="hl-string">.</span><span class="hl-quotes">'</span><span class="hl-code">; </span><span class="hl-brackets">}</span><span class="hl-code">
 
</span><span class="hl-var">$holdtil</span><span class="hl-code"> = </span><span class="hl-brackets">(</span><span class="hl-identifier">time</span><span class="hl-brackets">(</span><span class="hl-brackets">)</span><span class="hl-code"> + </span><span class="hl-brackets">(</span><span class="hl-var">$daysonshelf</span><span class="hl-code"> * </span><span class="hl-number">86400</span><span class="hl-brackets">)</span><span class="hl-brackets">)</span><span class="hl-code">;
</span><span class="hl-var">$holdtilfmt</span><span class="hl-code"> = </span><span class="hl-identifier">date</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">n/j</span><span class="hl-quotes">&quot;</span><span class="hl-code">, </span><span class="hl-var">$holdtil</span><span class="hl-brackets">)</span><span class="hl-code">;
</span><span class="hl-var">$canceldate</span><span class="hl-code"> = </span><span class="hl-identifier">date</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">m-d-Y</span><span class="hl-quotes">&quot;</span><span class="hl-code">, </span><span class="hl-var">$holdtil</span><span class="hl-brackets">)</span><span class="hl-code">;
 
</span><span class="hl-var">$details</span><span class="hl-code"> = </span><span class="hl-quotes">'</span><span class="hl-string">Title: </span><span class="hl-quotes">'</span><span class="hl-code"> . </span><span class="hl-var">$item</span><span class="hl-brackets">[</span><span class="hl-identifier">title</span><span class="hl-brackets">]</span><span class="hl-code"> . </span><span class="hl-quotes">&quot;</span><span class="hl-special">\n</span><span class="hl-quotes">&quot;</span><span class="hl-code"> .
        </span><span class="hl-quotes">'</span><span class="hl-string">Author: </span><span class="hl-quotes">'</span><span class="hl-code"> . </span><span class="hl-var">$item</span><span class="hl-brackets">[</span><span class="hl-identifier">author</span><span class="hl-brackets">]</span><span class="hl-code"> . </span><span class="hl-quotes">&quot;</span><span class="hl-special">\n</span><span class="hl-quotes">&quot;</span><span class="hl-code"> .
        </span><span class="hl-quotes">'</span><span class="hl-string">Callnum: </span><span class="hl-quotes">'</span><span class="hl-code"> . </span><span class="hl-var">$item</span><span class="hl-brackets">[</span><span class="hl-identifier">callnum</span><span class="hl-brackets">]</span><span class="hl-code"> . </span><span class="hl-quotes">&quot;</span><span class="hl-special">\n</span><span class="hl-quotes">&quot;</span><span class="hl-code"> .
        </span><span class="hl-quotes">'</span><span class="hl-string">Barcode: </span><span class="hl-quotes">'</span><span class="hl-code"> . </span><span class="hl-var">$item</span><span class="hl-brackets">[</span><span class="hl-identifier">barcode</span><span class="hl-brackets">]</span><span class="hl-code"> . </span><span class="hl-quotes">&quot;</span><span class="hl-special">\n</span><span class="hl-quotes">&quot;</span><span class="hl-code"> .
        </span><span class="hl-quotes">'</span><span class="hl-string">Held for: </span><span class="hl-quotes">'</span><span class="hl-code"> . </span><span class="hl-var">$item</span><span class="hl-brackets">[</span><span class="hl-identifier">plname</span><span class="hl-brackets">]</span><span class="hl-code"> . </span><span class="hl-quotes">'</span><span class="hl-string">, </span><span class="hl-quotes">'</span><span class="hl-code"> . </span><span class="hl-var">$item</span><span class="hl-brackets">[</span><span class="hl-identifier">pfname</span><span class="hl-brackets">]</span><span class="hl-code"> . </span><span class="hl-quotes">&quot;</span><span class="hl-special">\n</span><span class="hl-quotes">&quot;</span><span class="hl-code"> .
        </span><span class="hl-quotes">'</span><span class="hl-string">Pickup location: </span><span class="hl-quotes">'</span><span class="hl-code"> . </span><span class="hl-var">$item</span><span class="hl-brackets">[</span><span class="hl-identifier">pickuploc</span><span class="hl-brackets">]</span><span class="hl-code"> . </span><span class="hl-quotes">&quot;</span><span class="hl-special">\n</span><span class="hl-quotes">&quot;</span><span class="hl-code"> .
        </span><span class="hl-quotes">'</span><span class="hl-string">Hold until: </span><span class="hl-quotes">'</span><span class="hl-code"> . </span><span class="hl-var">$canceldate</span><span class="hl-code">;
 
</span><span class="hl-identifier">imagettftext</span><span class="hl-brackets">(</span><span class="hl-var">$im</span><span class="hl-code">, </span><span class="hl-number">28</span><span class="hl-code">, </span><span class="hl-number">270</span><span class="hl-code">, </span><span class="hl-number">40</span><span class="hl-code">, </span><span class="hl-number">20</span><span class="hl-code">, </span><span class="hl-var">$black</span><span class="hl-code">, </span><span class="hl-var">$font</span><span class="hl-code">, </span><span class="hl-var">$spine_name</span><span class="hl-brackets">)</span><span class="hl-code">;
</span><span class="hl-identifier">imagefilledrectangle</span><span class="hl-brackets">(</span><span class="hl-var">$im</span><span class="hl-code">, </span><span class="hl-number">72</span><span class="hl-code">, </span><span class="hl-number">20</span><span class="hl-code">, </span><span class="hl-number">74</span><span class="hl-code">, </span><span class="hl-number">345</span><span class="hl-code">, </span><span class="hl-var">$black</span><span class="hl-brackets">)</span><span class="hl-code">;
</span><span class="hl-identifier">imagefilledrectangle</span><span class="hl-brackets">(</span><span class="hl-var">$im</span><span class="hl-code">, </span><span class="hl-number">15</span><span class="hl-code">, </span><span class="hl-number">300</span><span class="hl-code">, </span><span class="hl-number">70</span><span class="hl-code">, </span><span class="hl-number">335</span><span class="hl-code">, </span><span class="hl-var">$white</span><span class="hl-brackets">)</span><span class="hl-code">;
</span><span class="hl-identifier">imagettftext</span><span class="hl-brackets">(</span><span class="hl-var">$im</span><span class="hl-code">, </span><span class="hl-number">12</span><span class="hl-code">, </span><span class="hl-number">0</span><span class="hl-code">, </span><span class="hl-number">32</span><span class="hl-code">, </span><span class="hl-number">320</span><span class="hl-code">, </span><span class="hl-var">$black</span><span class="hl-code">, </span><span class="hl-var">$font</span><span class="hl-code">, </span><span class="hl-var">$holdtilfmt</span><span class="hl-brackets">)</span><span class="hl-code">;
</span><span class="hl-identifier">ImageCopyMerge</span><span class="hl-brackets">(</span><span class="hl-var">$im</span><span class="hl-code"> , </span><span class="hl-var">$im2</span><span class="hl-code">, </span><span class="hl-number">85</span><span class="hl-code">, </span><span class="hl-number">40</span><span class="hl-code">, </span><span class="hl-number">0</span><span class="hl-code">, </span><span class="hl-number">0</span><span class="hl-code">, </span><span class="hl-identifier">ImageSX</span><span class="hl-brackets">(</span><span class="hl-var">$im2</span><span class="hl-brackets">)</span><span class="hl-code">, </span><span class="hl-identifier">ImageSY</span><span class="hl-brackets">(</span><span class="hl-var">$im2</span><span class="hl-brackets">)</span><span class="hl-code">, </span><span class="hl-number">100</span><span class="hl-brackets">)</span><span class="hl-code">;
</span><span class="hl-identifier">ImageCopyMerge</span><span class="hl-brackets">(</span><span class="hl-var">$im</span><span class="hl-code"> , </span><span class="hl-var">$im3</span><span class="hl-code">, </span><span class="hl-number">85</span><span class="hl-code">, </span><span class="hl-number">275</span><span class="hl-code">, </span><span class="hl-number">0</span><span class="hl-code">, </span><span class="hl-number">0</span><span class="hl-code">, </span><span class="hl-identifier">ImageSX</span><span class="hl-brackets">(</span><span class="hl-var">$im3</span><span class="hl-brackets">)</span><span class="hl-code">, </span><span class="hl-identifier">ImageSY</span><span class="hl-brackets">(</span><span class="hl-var">$im3</span><span class="hl-brackets">)</span><span class="hl-code">, </span><span class="hl-number">100</span><span class="hl-brackets">)</span><span class="hl-code">;
</span><span class="hl-identifier">imagettftext</span><span class="hl-brackets">(</span><span class="hl-var">$im</span><span class="hl-code">, </span><span class="hl-number">12</span><span class="hl-code">, </span><span class="hl-number">0</span><span class="hl-code">, </span><span class="hl-number">85</span><span class="hl-code">, </span><span class="hl-number">120</span><span class="hl-code">, </span><span class="hl-var">$black</span><span class="hl-code">, </span><span class="hl-var">$font</span><span class="hl-code">, </span><span class="hl-var">$details</span><span class="hl-brackets">)</span><span class="hl-code">;
 
</span><span class="hl-identifier">imagepng</span><span class="hl-brackets">(</span><span class="hl-var">$im</span><span class="hl-code">,</span><span class="hl-quotes">&quot;</span><span class="hl-string">/tmp/pic</span><span class="hl-var">$unique</span><span class="hl-string">.png</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-code">;
</span><span class="hl-identifier">imagedestroy</span><span class="hl-brackets">(</span><span class="hl-var">$im</span><span class="hl-brackets">)</span><span class="hl-code">;
 
</span><span class="hl-reserved">if</span><span class="hl-code"> </span><span class="hl-brackets">(</span><span class="hl-var">$item</span><span class="hl-brackets">[</span><span class="hl-identifier">printer</span><span class="hl-brackets">]</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code">
        </span><span class="hl-var">$printer</span><span class="hl-code"> = </span><span class="hl-var">$item</span><span class="hl-brackets">[</span><span class="hl-identifier">printer</span><span class="hl-brackets">]</span><span class="hl-code">;
        </span><span class="hl-identifier">exec</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">/usr/bin/lp -d </span><span class="hl-var">$printer</span><span class="hl-string"> /tmp/pic</span><span class="hl-var">$unique</span><span class="hl-string">.png</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-code">;
</span><span class="hl-brackets">}</span><span class="hl-code">
 
</span><span class="hl-identifier">unlink</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">/tmp/pic</span><span class="hl-var">$unique</span><span class="hl-string">.png</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-code">;
 
</span><span class="hl-comment">//</span><span class="hl-comment"> Functions Below</span><span class="hl-comment"></span><span class="hl-code">
 
</span><span class="hl-reserved">function</span><span class="hl-code"> </span><span class="hl-identifier">hold_item_info</span><span class="hl-brackets">(</span><span class="hl-var">$email</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code">
    </span><span class="hl-comment">//</span><span class="hl-comment"> This function returns the $item array -- customize it for your environment.</span><span class="hl-comment"></span><span class="hl-code">
</span><span class="hl-brackets">}</span><span class="hl-code">
</span><span class="hl-inlinetags">?&gt;</span></pre></div></div>
<p>The script creates a PNG that looks something like this:<br />
<a href="http://www.flickr.com/photos/jblyberg/113162804/"><img src="http://static.flickr.com/49/113162804_4648831110_m.jpg"/></a><br />
The PNG is sent to the <a href="http://www.zebra.com/">Zebra S4M</a> and printed on a label that has Post-It-like adhesive.  Processors then peel off the backing and fold the sticker over the spine of the book and put it on the hold shelf.</p>
<p>The hardest part of this whole project was getting the printer to work with CUPS.  I wound up bastardizing some existing postscript drivers through trial and error.  As you can see from the photos, I still don't have it right.  I'd like the image to take up the entire sticker area.  All in good time.  If anyone out there wants the driver I'll be glad to email it--maybe you can get it working better!  Just ask.</p>
<p><strong>[update]</strong><br />
This is how the labels are affixed to material:<br />
<a href="http://www.flickr.com/photos/jblyberg/113779916/"><img src="http://static.flickr.com/44/113779916_dcc6a34440_m.jpg"/></a><br />
You can overlook the fact that the label info doesn't match the book info--it's just for show!<br />
<strong>[/update]</strong></p>
<p>[tags]library, libraries, PHP, coding[/tags]</p>
]]></content:encoded>
			<wfw:commentRss>http://www.blyberg.net/2006/03/16/stick-em-up-easing-the-holds-process/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Library 2.0 websites: Where to begin?</title>
		<link>http://www.blyberg.net/2006/03/12/library-20-websites-where-to-begin/</link>
		<comments>http://www.blyberg.net/2006/03/12/library-20-websites-where-to-begin/#comments</comments>
		<pubDate>Sun, 12 Mar 2006 14:24:06 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Libraries]]></category>
		<category><![CDATA[AADL]]></category>
		<category><![CDATA[Coding]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[HTTP]]></category>
		<category><![CDATA[L2]]></category>
		<category><![CDATA[OPAC]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Web-Design]]></category>

		<guid isPermaLink="false">http://www.blyberg.net/2006/03/12/library-20-websites-where-to-begin/</guid>
		<description><![CDATA["This is my website. There are many like it, but this one is mine..." Much has changed in the last year with respect to the notion of a "library website". It's as though the clear, glassy surface of a morning bay has been turned and cast about by steel, unforgiving turbines. Many unsuspecting libraries are [...]]]></description>
			<content:encoded><![CDATA[<p><img align="left" src="/wp-content/images/oneappleout.jpg"/>"This is my website.  There are many like it, but this one is mine..."</p>
<p>Much has changed in the last year with respect to the notion of a "library website".  It's as though the clear, glassy surface of a morning bay has been turned and cast about by steel, unforgiving turbines.  Many unsuspecting libraries are now caught in that turbulent wash, casting about for something, anything to hold on to as they begin the daunting task of "the redesign".  The problem is, where do we even begin? If there was no gold standard before, there still is none, but we now acknowledge two things:  Traditional library websites drain the life-force from patrons.  Our OPACs finish the job.</p>
<p>So where do we go from here?  Is there anything, anything at all we can use as a <i>modus operandi</i> as we, once again, begin the process of re-provisioning the obligatory library website?</p>
<p><img align="right" src="/wp-content/images/web5points.png"/>Let me suggest five directives that may help get your creative minds turning.  I want to talk about these not only because they represent common sense, good design, and patron convenience, but also because by using these directives as a kernel in your new project, you are sure to come out the other side feeling highly rewarded and sporting a new website that will invigorate your inner-geek for years to come.</p>
<p><strong>Social software</strong>, as you are probably aware, was born of the read/write web.  Partially due to persistent connections, newer software, higher bandwidth, and plain old human acceptance of the machine, the social web is a beautiful lace spun with minds, machines, and information.  It is who we are as humans--it is community. just like the public library is community.  So to ignore social software in the context of our library websites, is to ignore our communities.  We need to find a prominent place on our mantle for it and ensure that our websites invite humanity in and give it right back.  The point here is to extend the boundaries of the library, perhaps blurring the edges like watercolor so we're not quite sure where the library ends.</p>
<p>There are many ways to incorporate social software into your sites, not the least of which is the use of mash-ups, or the judicious use of an <strong>open source</strong> database like MySQL in conjunction with a little PHP, running on Linux, served up by Apache. <img align="left" src="/wp-content/images/opensource-110x95.png"/>Adopting open-source platforms and technologies in a library is not just financially beneficial.  Philosophically, it's the right thing to do.  We ought to be developing on open-source then turning around and making our work freely available to one another.  We <i>are</i> libraries after all, we ought to act like it, not just in the stacks and at the circulation desks, but in the server rooms and IT departments as well.  Don't forget the intrinsic benefits of supporting and pursuing an open sourced development program. Eric Raymond writes in The Cathedral and the Bazaar:</p>
<blockquote><p>...we have fun doing what we do. Our creative play has been racking up technical, market-share, and mind-share successes at an astounding rate. We're proving not only that we can do better software, but that joy is an asset.</p></blockquote>
<p>Joy truly should be an asset as you continue to plug away at your web project.  If it is, the final product will reflect it.  Open source allows success to be contagious as code is reused, changed, improved, forked, spawned into radical new ideas.  That sounds like something a public library ought to be involved with, doesn't it?</p>
<p>I think it's time libraries took the notion of <strong>single sign-on</strong> seriously.  We need to get away from the model where patrons are required to have their library cards handy every time they reserve an item. Who wants to have one set of credentials to access the OPAC and yet another to make a blog comment, or fill out an ILL request?  Why not be like the rest of the world and simply require a username and password?  Let me take this one step further, as well, and suggest that your new websites support <i>session-based</i> single sign-on--a useful little bit of web technology that has been around since, well, almost forever.  When I create an account on a site I use frequently, I expect that I'll not have to keep re-entering my password every time I visit.  Otherwise, I won't be visiting that site very frequently.  </p>
<p>Single sign-on is not just about convenience, either.  A unified user management system is a vital ingredient in the foundation of a cohesive online experience.  Think about what your users will be doing, especially in light of the fact that you're going to implement all those great social software features.  As I've mentioned before, the library website can be so much more than just a resource--it can, and should be a destination--a community touchstone.  You can't do that if there is a functional disconnect between what you're offering and how you're offering it.  </p>
<p>Single sign-on will prove to be a more difficult implementation than you may be thinking at the moment.  As you scratch the surface, you'll see why, what will all the disparate software you'll be gluing together.  After all, it's not like our vendors are going out of their way to offer and support <strong>open standards</strong>.  We ought to, of course, for many of the same reasons I've outlined for open source.  <img align="left" src="/wp-content/images/w3c_home.png"/>Open standards, however, gives us the flexibility both internally and externally to promote vital services in a timely and easily accessible manner.  That sounds good, right?  Adopting W3C standards will ensure that we've provisioned for any eventuality.  Need to export? No problem.  Someone wants to get Greasemonkey all up in your site?  Go right ahead, Ed.  RSS feeds?  Absolutely essential.  Want to offer a web services front-end to your OPAC?  Why not use SOAP and throw in some WSDL so that potential coders can hit the ground running? Open standards, open minds, open doors.</p>
<p>Then there's the white elephant.  Your OPAC--that malignant growth that looks nothing like the rest of your site and appears to have been coded by a CS 101 student who is contemplating switching majors to say, English.  Insist on an <strong>integrated OPAC</strong>.  Again, this may be a technical challenge, but nothing is impossible.  If you find a way to tame the beast, you're going to completely transform the way your website operates.  Ideally, the OPAC should be embedded inside the framework of your site so that you have access to all the site data and functionality during page parse.  Once you've got control over what, where and when your OPAC displays, you'll find that a world of opportunity has opened up to you.  While pondering a way to achieve this, you may find yourself, again, at your vendor's doorstep, whimpering, "please sir, may I have some more?"  Unless the request is in an RFP, however, good luck.  All we can do is chip away at them, in the meantime, there are ways of getting around that technical hurdle, but they probably require a programmer--a position libraries should consider adding anyway.</p>
<p>All this is an oversimplification of an arduously complex process, I confess.  Sometimes, however, when you're not sure where to begin, it helps to consider all your options within a set of parameters.  If I were to launch into a library website project right now, these are the "must-haves" I'd start with.  For my part, these comprise an ideal that will stand a project in good stead as we continue to cast about in a 2.0 world.</p>
<p>[tags]Library, Libraries, L2, Web Design, OPAC, Development, Programming, Coding, PHP, HTML, HTTP, AADL[/tags]</p>
]]></content:encoded>
			<wfw:commentRss>http://www.blyberg.net/2006/03/12/library-20-websites-where-to-begin/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>Source code for virtual card catalog images</title>
		<link>http://www.blyberg.net/2006/02/10/source-code-for-virtual-card-catalog-images/</link>
		<comments>http://www.blyberg.net/2006/02/10/source-code-for-virtual-card-catalog-images/#comments</comments>
		<pubDate>Fri, 10 Feb 2006 22:34:30 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Libraries]]></category>
		<category><![CDATA[AADL]]></category>
		<category><![CDATA[Library 2.0]]></category>
		<category><![CDATA[Open-Source]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Virtual-Card-Catalog]]></category>
		<category><![CDATA[Web 2.0]]></category>

		<guid isPermaLink="false">http://www.blyberg.net/2006/02/10/source-code-for-virtual-card-catalog-images/</guid>
		<description><![CDATA[<a href="/downloads/iii-vcards-0.1.tar.gz">iii-vcards-0.1.tar.gz</a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.aadl.org/cat/ccimg/1258697/"><img align="right" src="http://www.aadl.org/card/cardimg.php?bnum=1258697&#038;card=1&#038;comment1=413&#038;comment2=249&#038;comment3=170&#038;c1_font=kristenscript&#038;c2_font=Efficient2&#038;c3_font=dulcesfont&#038;shrink=.6"/></a>I can't tell you how many people have emailed me about getting the source code to the virtual card catalog images I <a href="/2006/01/19/creating-a-virtual-card-catalog/">announced</a> a few weeks ago.  Anyway, I've finally gotten around to stripping out all the garbage from the script that generates the images, and I'm <a href="/downloads/iii-vcards-0.1.tar.gz">releasing it here</a> (and as always, it'll be available in the <a href="/files/">files</a> section).  There are a few things you need to keep in mind about it, however.</p>
<p>First, this code is written for use with III's XMLOPAC and requires my PHP XMLOPAC class.  That said, an astute PHP coder could easily port this app and make it usable on another system (I heartily encourage that).  Someday, I plan to make it completely generic so that all you need to do is pass it the data itself.  I'm a little busy at the moment, however.</p>
<p>I am not releasing the card stock images that AADL uses.  There was no license info associated with the original images.  Until I can contact the folks at <a href="http://www.library.upenn.edu/exhibits/pennhistory/library/cards/cards.samples.html">UPenn</a> and find out what the deal is, I'm not going to make them available.  It'd be very easy to create your own stock, however.</p>
<p>Same deal with the fonts.  I was able to freely download them--so should you.</p>
<p>At present, this code is really meant for developers, it is not a "package" that will work out of the box.  You must know what you're doing in order to get this going.</p>
<p>I'm releasing it under GPL for all the world to use freely, forever and ever.</p>
<p>Included in the tarball is a README file with some basic instructions.  Be sure to read that before emailing me your questions.</p>
<p>Enjoy.  I'm looking forward to some possible creative uses.  Please email me if you get it working as I'd love to see what you're doing with it.  If you come up with a particularly interesting use, I'll be sure to showcase it here.</p>
<p>[tags]PHP, Programming, Virtual Card Catalog, AADL, Web 2.0, Library 2.0, Open Source[/tags]</p>
]]></content:encoded>
			<wfw:commentRss>http://www.blyberg.net/2006/02/10/source-code-for-virtual-card-catalog-images/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>III XMLOPAC Class update</title>
		<link>http://www.blyberg.net/2006/02/08/iii-xmlopac-class-update-2/</link>
		<comments>http://www.blyberg.net/2006/02/08/iii-xmlopac-class-update-2/#comments</comments>
		<pubDate>Wed, 08 Feb 2006 20:47:08 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Libraries]]></category>
		<category><![CDATA[AADL]]></category>
		<category><![CDATA[III]]></category>
		<category><![CDATA[OPAC]]></category>
		<category><![CDATA[Open-Source]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[XML]]></category>
		<category><![CDATA[XMLOPAC]]></category>

		<guid isPermaLink="false">http://www.blyberg.net/2006/02/08/iii-xmlopac-class-update-2/</guid>
		<description><![CDATA[<a href="/downloads/iii-xmlopac-1.10.tar.gz">iii-xmlopac-1.10.tar.gz</a>]]></description>
			<content:encoded><![CDATA[<p><img src="/wp-content/images/xmllogo.jpeg" alt="" align="left" />After a fair amount of work, I'm releasing an update to the iii-xmlopac class.  I've been sitting on this update for awhile because it's a fairly big update and I wanted to make sure it was performing like it should.  I highly recommend that anyone using this class update because a number of fairly critical bugs have been fixed, including a messy tangle of UTF8 encoding issues.</p>
<p>In addition, I've included an XSLT file written by <a href="http://library.csusm.edu/catalog/sru/xserver/test.htm">David Walker</a> which I've modified slightly.  It allows me to easily extract subject headings from the XML, so yes, this class now will return an array of subject headings!!</p>
<p>So, be sure to <a href="/downloads/iii-xmlopac-1.10.tar.gz">download</a> the latest version.  As always, you can grab it anytime from the <a href="/files/">files</a> section.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.blyberg.net/2006/02/08/iii-xmlopac-class-update-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Major enhancements for patron-REST</title>
		<link>http://www.blyberg.net/2006/01/26/major-enhancements-for-patron-rest/</link>
		<comments>http://www.blyberg.net/2006/01/26/major-enhancements-for-patron-rest/#comments</comments>
		<pubDate>Thu, 26 Jan 2006 21:41:53 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Libraries]]></category>
		<category><![CDATA[OPAC]]></category>
		<category><![CDATA[PatREST]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[Updates]]></category>
		<category><![CDATA[XML]]></category>

		<guid isPermaLink="false">http://www.blyberg.net/2006/01/26/major-enhancements-for-patron-rest/</guid>
		<description><![CDATA[(Codenamed PatREST in my SVN) When last I wrote about this, it was little more than a working proof-of-concept, but I've been working on it a lot this week--partly driven by DaveyP's experiments and Ed's tinkering, but mostly because I've been planning to do this for a long time now. So, to cut to the [...]]]></description>
			<content:encoded><![CDATA[<p>(Codenamed PatREST in my SVN)</p>
<p>When last I wrote about this, it was little more than a working proof-of-concept, but I've been working on it a lot this week--partly driven by <a href="http://www.daveyp.com/blog/">DaveyP's experiments</a> and <a href="http://vielmetti.typepad.com/superpatron/">Ed's tinkering</a>, but mostly because I've been planning to do this for a long time now.</p>
<p>So, to cut to the chase:<br />
PatREST now provides an easy, RESTful URI to do searches on quite a few fields.  Essentially, you will plug the search key into the URI, followed by the search term.  You can also request optional paging for keyword, author searches by appending hits-per-page and page-# to the URI.  It looks like this:</p>
<p>http://www.aadl.org/rest/search/[searchkey]/[searchterm]/[hits-per-page]/[page-#]</p>
<p>The following search keys are available:</p>
<p>title<br />
author<br />
callnum<br />
keyword<br />
subject<br />
gvtdocnum<br />
stdnum (ISBN/ISSN)<br />
titlekey<br />
controlnum<br />
barcode<br />
record (Bib #)<br />
bibnum (Bib # - Same as record)<br />
itemnum</p>
<p>Go ahead and try <a href="http://www.aadl.org/rest/search/keyword/japan/10/1">this keyword search</a>.  It'll look something like this:</p>
<p><a href="http://www.flickr.com/photos/jblyberg/91487868/"><img src="http://static.flickr.com/25/91487868_4ee1995bd3_m.jpg" /></a></p>
<p>You'll notice that the XSLT stylesheet presents it nicely, all the data may not be displayed, but the XML is sound.  Go ahead and view source to examine the schema.  I've departed quite a bit from my original schema in order to provide a little bit of metadata for processing purposes.  The XSLT allows you to click on a title which will take you to another RESTful record:</p>
<p><a href="http://www.flickr.com/photos/jblyberg/91487869/"><img src="http://static.flickr.com/18/91487869_f3a271d474_m.jpg" /></a></p>
<p>You'll notice that the URI for this record looks like <a href="http://www.aadl.org/rest/record/1035670/">/rest/record/1035670/</a> ... It's /rest/record/[bibnum]/.  The XSLT allows you to click on either the title or cover image to go to the regular OPAC record.  Again, view source for the XML schema.  This schema has changed little and you'll notice that I'm taking advantage of OCLC's xISBN service.</p>
<p>The real treat in all this, however, is the ability to access your personal records RESTfully.  To do this, I make use of the RSS token that is provided to every cardholder who has registered for an online account.  This is the token that authenticates RSS readers against our system.  It is a 32 character MD5 hash that looks something like "316928e0d260556eaccb6627f2ed657b".  Accessing personal data is as easy as using the following URIs:</p>
<p>For checkouts, you would use /rest/checkouts/[token] (ie http://www.aadl.org/rest/checkouts/316928e0d260556eaccb6627f2ed657b).  You'll then get output at looks something like:</p>
<p><a href="http://www.flickr.com/photos/jblyberg/91487870/"><img src="http://static.flickr.com/27/91487870_6a00d6c546_m.jpg" /></a></p>
<p>For holds, the URI is /rest/holds/[token].  Output looks like:</p>
<p><a href="http://www.flickr.com/photos/jblyberg/91487871/"><img src="http://static.flickr.com/36/91487871_90882d7159_m.jpg" /></a></p>
<p>Both of those results allow you to click on the bibnum and access the REST record for that item.  Again, check the XML schema with your browser (no point in putting it here).</p>
<p>Please hack away at this and send me your comments/suggestions.  You're absolutely correct that it doesn't adhere to any existing standard, but that's because I didn't want it to.</p>
<p>On a slightly less geek-oriented note...</p>
<p>I've gone <a href="/2005/11/24/talis-responds-to-bill-of-rights/">several rounds</a> with Talis's Richard Wallis before, so I want to call your attention to a post he <a href="http://blogs.talis.com/panlibus/archives/2006/01/just_resting.html">made the other day</a> in which he suggest that a) DaveyP and I collaborate and b) I/we consider using industry standards.  I'd like to respond by saying that Dave and I have been communicating extensively.  Ed Vielmetti has been involved as well.</p>
<p>Richard writes:</p>
<p><em>I encourage John, Dave, and those that follow them to take a look at these standards like we have</em></p>
<p>I can't speak for Dave, but I'm very familiar with these standards and so is Ed.  I think Richard is completely missing the point of this whole project which is to put a friendly, accessible, and useful development interface into the hands of <strong>patrons</strong>.  Ed offers just a small example of the type of features that existing standards don't readily make available:</p>
<p><em>Already there is a lot more useful function in it than you can get in SRU, e.g. permalinks for card records and a sensible way to get item availability.</em></p>
<p>Bear in mind, that comment was made prior to my work with RESTful holds and checkouts, which, as far as I know, don't even have a standard XML schema--I don't think it's been done before! (I'd love to be corrected on this)  This project will also evolve to the point where holds can be placed RESTfully, items renewed, fines paid.  It'll also extend to our other features like checkout history, wifi device management, personal card catalog management.  Adding this functionality is not only going to allow the public to develop highly useful applications, but it'll be a framework by which we ourselves can build new services in-house.  Vendor's obviously haven't stepped up to this, so we are--and we believe in our patrons.  They deserve this kind of access to their public library.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.blyberg.net/2006/01/26/major-enhancements-for-patron-rest/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>
