<?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>Archétype Informatique: the back burner</title>
	<atom:link href="http://www.archetype-it.com/thebackburner/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.archetype-it.com/thebackburner</link>
	<description>Occasional articles about our “back burner” web projects, and handy technical tips</description>
	<lastBuildDate>Tue, 03 Apr 2012 07:46:56 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>I love you PHP: more date goodness</title>
		<link>http://www.archetype-it.com/thebackburner/2012/04/03/i-love-you-php-more-date-goodness/</link>
		<comments>http://www.archetype-it.com/thebackburner/2012/04/03/i-love-you-php-more-date-goodness/#comments</comments>
		<pubDate>Tue, 03 Apr 2012 07:46:56 +0000</pubDate>
		<dc:creator>Veronica Yuill</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[date]]></category>
		<category><![CDATA[strftime]]></category>

		<guid isPermaLink="false">http://www.archetype-it.com/thebackburner/?p=98</guid>
		<description><![CDATA[Want to display a date in a language other than English, without switching your whole installation to some other language? It&#8217;s so easy &#8230; setlocale(LC_TIME, "fr_FR"); $datefacture = strftime("%e %B %Y"); echo $datefacture;]]></description>
			<content:encoded><![CDATA[<p>Want to display a date in a language other than English, without switching your whole installation to some other language? It&#8217;s so easy &#8230;<br />
<code><br />
setlocale(LC_TIME, "fr_FR");<br />
$datefacture = strftime("%e %B %Y");<br />
echo $datefacture;<br />
</code></p>
]]></content:encoded>
			<wfw:commentRss>http://www.archetype-it.com/thebackburner/2012/04/03/i-love-you-php-more-date-goodness/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP date calculations: last day of the month</title>
		<link>http://www.archetype-it.com/thebackburner/2012/03/05/php-date-calculations-last-day-of-the-month/</link>
		<comments>http://www.archetype-it.com/thebackburner/2012/03/05/php-date-calculations-last-day-of-the-month/#comments</comments>
		<pubDate>Mon, 05 Mar 2012 11:00:09 +0000</pubDate>
		<dc:creator>Veronica Yuill</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[dates]]></category>

		<guid isPermaLink="false">http://www.archetype-it.com/thebackburner/?p=92</guid>
		<description><![CDATA[PHP&#8217;s date() function must be my favourite PHP function. You need never struggle with manipulating dates in PHP &#8212; if you need to use more than one line of code for working out a date, you probably just haven&#8217;t looked &#8230; <a href="http://www.archetype-it.com/thebackburner/2012/03/05/php-date-calculations-last-day-of-the-month/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>PHP&#8217;s <tt>date()</tt> function must be my favourite PHP function. You need never struggle with manipulating dates in PHP &#8212; if you need to use more than one line of code for working out a date, you probably just haven&#8217;t looked at the date function closely enough. This one&#8217;s from <a href="http://www.omnimint.com/A4/PHP/PHP-Calculate-the-date-of-the-last-day-of-the-previous-month.html">here</a>; it works out the last day of the previous month. Yes, even when it&#8217;s a leap February.<br />
<code>echo date("t/m/Y", strtotime("last month"));</code></p>
]]></content:encoded>
			<wfw:commentRss>http://www.archetype-it.com/thebackburner/2012/03/05/php-date-calculations-last-day-of-the-month/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>jQuery validation plugin: required select elements</title>
		<link>http://www.archetype-it.com/thebackburner/2012/02/09/jquery-validation-plugin-required-select-elements/</link>
		<comments>http://www.archetype-it.com/thebackburner/2012/02/09/jquery-validation-plugin-required-select-elements/#comments</comments>
		<pubDate>Thu, 09 Feb 2012 13:24:10 +0000</pubDate>
		<dc:creator>Veronica Yuill</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[validation]]></category>

		<guid isPermaLink="false">http://www.archetype-it.com/thebackburner/?p=89</guid>
		<description><![CDATA[I&#8217;m just posting this as a reminder to myself, but it may help others! I found that when I added class=&#8221;required&#8221; to a select element in a form, it wasn&#8217;t actually treated as required by jQuery. After some fiddling about, &#8230; <a href="http://www.archetype-it.com/thebackburner/2012/02/09/jquery-validation-plugin-required-select-elements/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m just posting this as a reminder to myself, but it may help others! I found that when I added class=&#8221;required&#8221; to a select element in a form, it wasn&#8217;t actually treated as required by jQuery. After some fiddling about, I discovered that you can easily force it to be required by ensuring that you have a blank first option with a value of an empty string (zero will not do!). In other words:<br />
<code>&lt;option value="" selected="selected"&gt;&lt;/option&gt;</code><br />
Note that I forced this option to be selected if I hadn&#8217;t passed a valid default option to be preselected when the form was loaded. This means that if the empty option is still selected (or has been chosen by the user) when the form is submitted, jQuery will detect it as required and display the appropriate error.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.archetype-it.com/thebackburner/2012/02/09/jquery-validation-plugin-required-select-elements/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Automatically updating a WordPress blogroll</title>
		<link>http://www.archetype-it.com/thebackburner/2011/11/26/automatically-updating-a-wordpress-blogroll/</link>
		<comments>http://www.archetype-it.com/thebackburner/2011/11/26/automatically-updating-a-wordpress-blogroll/#comments</comments>
		<pubDate>Sat, 26 Nov 2011 07:05:27 +0000</pubDate>
		<dc:creator>Veronica Yuill</dc:creator>
				<category><![CDATA[Blogging]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web development]]></category>
		<category><![CDATA[Wordpress]]></category>
		<category><![CDATA[blogroll]]></category>
		<category><![CDATA[bookmarks]]></category>
		<category><![CDATA[rss]]></category>

		<guid isPermaLink="false">http://www.archetype-it.com/thebackburner/2011/11/26/automatically-updating-a-wordpress-blogroll/</guid>
		<description><![CDATA[Years ago, I signed up to a social bookmarking system called Spurl. I&#8217;m really not interested in social bookmarking, but it had a handy feature: by inserting a bit of Javascript in a web page, you could pull all or &#8230; <a href="http://www.archetype-it.com/thebackburner/2011/11/26/automatically-updating-a-wordpress-blogroll/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Years ago, I signed up to a social bookmarking system called Spurl. I&#8217;m really not interested in social bookmarking, but it had a handy feature: by inserting a bit of Javascript in a web page, you could pull all or a subset of the links out and display them in a list. That meant that I could add links to my blogrolls by simply bookmarking a link using Spurl, and categorising it. No need to fiddle around going to the blog admin and adding the link. It was really useful for easily sharing links and maintaining links pages.</p>
<p>Sadly, Spurl was overwhelmed by spam and disappeared. After that I bumbled around trying to find another service that provided the same functionality. It seemed obvious that lots of people would want this. But no. I managed to get something similar working with Furl.net. But then that was taken over by <a href="http://www.diigo.com/">Diigo</a> (a problem with these services is that they keep disappearing or being taken over). Diigo claimed I could do the same thing, but no matter what I did, it refused to show more than the 3 newest links in a particular category. Not very useful for a blogroll (although I do use it for recent links here &#8212; see the sidebar on the home page). Del.icio.us doesn&#8217;t seem to have any functionality like this.</p>
<p>Yesterday, while half-heartedly trying to resolve this problem, I happened across <a href="http://sitebar.org/">Sitebar</a>. Yes, another bookmark manager. But this one is open source, and you can install it on your own server. Complete control! Hastily I installed it (a 5-minute job). Added a few bookmarks and experimented with the RSS feed. Once I&#8217;d figured that out, some googling and digging in the <a href="http://codex.wordpress.org/Main_Page">WordPress codex</a> came up with a way to get WordPress to read the RSS feed and display it in the sidebar.<br />
<code><br />
&lt;div id="sitebar_linkroll" &gt;<br />
&lt;?php<br />
// Get RSS Feed(s)<br />
include_once(ABSPATH . WPINC . '/feed.php');<br />
// Get a SimplePie feed object from the specified feed source.<br />
$rss = fetch_feed('http://www.archetype-it.com/sitebar/index.php?hits=0&amp;w=rss&amp;mix=nodes&amp;root=16');<br />
if (!is_wp_error( $rss ) ) : // Checks that the object is created correctly<br />
    // Figure out how many total items there are, but limit it to 20.<br />
    $maxitems = $rss-&gt;get_item_quantity(20);<br />
    // Build an array of all the items, starting with element 0 (first element).<br />
    $rss_items = $rss-&gt;get_items(0, $maxitems);<br />
endif;<br />
?&gt;</p>
<p>&lt;ul&gt;<br />
    &lt;?php if ($maxitems == 0) echo '&lt;li&gt;No items.&lt;/li&gt;';<br />
    else<br />
    // Loop through each feed item and display each item as a hyperlink.<br />
    foreach ( $rss_items as $item ) : ?&gt;<br />
    &lt;li&gt;<br />
        &lt;a href='&lt;?php echo esc_url( $item-&gt;get_permalink() ); ?&gt;'<br />
        title='&lt;?php echo 'Posted '.$item-&gt;get_date('j F Y | g:i a'); ?&gt;'&gt;<br />
        &lt;?php echo esc_html( $item-&gt;get_title() ); ?&gt;&lt;/a&gt;<br />
    &lt;/li&gt;<br />
    &lt;?php endforeach; ?&gt;<br />
&lt;/ul&gt;<br />
&lt;/div&gt;<br />
</code></p>
<p><a href="http://www.larecettedujour.org/">Ta-dah</a>! This may seem a bit overkill for a blogroll, but it solves a problem for me. And Sitebar is a nice links manager in itself, even if it looks a little old-fashioned (no trendy tags, just folders!) and hasn&#8217;t been updated since 2007. There is a <a href="http://my.sitebar.org/">hosted version</a> with free and paid options, but hosting it myself means I don&#8217;t need to worry about the service disappearing or changing its terms, and if it does what I want it doesn&#8217;t really matter if it&#8217;s not being actively maintained. It&#8217;s designed to be used in the panel/sidebar area of a browser, hence the name. So I&#8217;ve added it to Opera as a panel, where it&#8217;s easily accessible for adding links (there&#8217;s a Javascript bookmarklet too, for one-click adding, though I haven&#8217;t got that working in Opera yet).</p>
<p>Note, of course, that you can use this same PHP code for any RSS feed that you want to incorporate into a WordPress site &#8212; just edit the feed URL.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.archetype-it.com/thebackburner/2011/11/26/automatically-updating-a-wordpress-blogroll/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Book review: PHP and MySQL for Dynamic Web Sites: Visual QuickPro Guide, 4th Edition by Larry Ullman</title>
		<link>http://www.archetype-it.com/thebackburner/2011/09/30/book-review-php-and-mysql-for-dynamic-web-sites-visual-quickpro-guide-4th-edition-by-larry-ullman/</link>
		<comments>http://www.archetype-it.com/thebackburner/2011/09/30/book-review-php-and-mysql-for-dynamic-web-sites-visual-quickpro-guide-4th-edition-by-larry-ullman/#comments</comments>
		<pubDate>Fri, 30 Sep 2011 11:17:01 +0000</pubDate>
		<dc:creator>Veronica Yuill</dc:creator>
				<category><![CDATA[Databases]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web development]]></category>
		<category><![CDATA[book review]]></category>

		<guid isPermaLink="false">http://www.archetype-it.com/thebackburner/2011/09/30/book-review-php-and-mysql-for-dynamic-web-sites-visual-quickpro-guide-4th-edition-by-larry-ullman/</guid>
		<description><![CDATA[I bought PHP and MySQL for Dynamic Web Sites: Visual QuickPro Guide (4th Edition) to use as a set book for an online intermediate PHP class that I teach. I previously used Web Database Applications with PHP &#38; MySQL by &#8230; <a href="http://www.archetype-it.com/thebackburner/2011/09/30/book-review-php-and-mysql-for-dynamic-web-sites-visual-quickpro-guide-4th-edition-by-larry-ullman/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I bought <a href="http://www.amazon.com/gp/product/0321784073/ref=as_li_ss_tl?ie=UTF8&amp;tag=corbieresweb-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399373&amp;creativeASIN=0321784073">PHP and MySQL for Dynamic Web Sites: Visual QuickPro Guide (4th Edition)</a><img src="http://www.assoc-amazon.com/e/ir?t=corbieresweb-20&amp;l=as2&amp;o=1&amp;a=0321784073&amp;camp=217145&amp;creative=399373" width="1" height="1" border="0" alt="" /> to use as a set book for an <a href="http://www.eclasses.org/P104/">online intermediate PHP class</a> that I teach. I previously used <a href="http://www.amazon.com/gp/product/0596005431/ref=as_li_ss_tl?ie=UTF8&amp;tag=corbieresweb-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0596005431">Web Database Applications with PHP &amp; MySQL</a><img src="http://www.assoc-amazon.com/e/ir?t=corbieresweb-20&amp;l=as2&amp;o=1&amp;a=0596005431&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" /> by Williams and Lane, but it was very old (published 2004), covering only PHP 4, and no new edition seemed to be forthcoming. I chose Larry Ullman&#8217;s book pre-publication on the strength of the coverage described in the pre-release table of contents, reviews of earlier editions, and other books by Ullman which do a good job of explaining concepts &#8212; I also corresponded with the author about some of the details, and he was helpful and forthcoming.</p>
<p>I think this book will be much more accessible than the Williams and Lane one, which had great detailed coverage of PHP and MySQL, but was over-complicated in places. But I&#8217;m a little disappointed with several aspects.</p>
<p>By far the biggest disappointment: no coverage of exceptions, a key feature of PHP5. Second biggest: the whole chapter on OOP is pretty inadequate. I don&#8217;t teach OOP on my course, but I do encourage students to use pre-built classes for some tasks, such as data validation or sending mail. This chapter takes that approach, but doesn&#8217;t explain why using the MySQLi class is any better than just using the non-OOP mysqli_ functions. He could at least have covered PDO here, as it&#8217;s more versatile than MySQLi. But again, PDO isn&#8217;t mentioned at all &#8212; a very surprising omission.</p>
<p>I was also disappointed that while he briefly discusses user-defined functions in the early chapters, he makes no effort to encourage the reader to actually use them in the exercises and case-studies later in the book. All the code is inline, including in places that are crying out for use of functions, such as the shopping cart, user registration, and forum examples. This book is not intended for complete beginners, so it really should do more to encourage good practice and maintainable code. It is nice to include a chapter on using jQuery and AJAX with PHP, but frankly I&#8217;d have rather seen this chapter omitted in favour of more coverage of the above topics. I know there&#8217;s only so much you can cover in 600 pages (especially when the layout is so inefficient), and different readers&#8217; needs will vary, but some of the priorities here seem wrong to me.</p>
<p>Good points: the coverage of MySQL queries is pretty good, but for my purposes I&#8217;d have liked to see better discussion and explanation of database design and ERDs.  The Williams and Lane book had a very good appendix covering this. There&#8217;s a whole chapter on security, with useful and realistic examples, and Ullman addresses security aspects such as input filtering and escaping throughout the book (often a weak point in introductory PHP books, happily littered with examples using unfiltered POST and GET input &#8220;for clarity&#8221; &#8212; the ever-popular <a href="http://www.amazon.com/gp/product/0672329166/ref=as_li_ss_tl?ie=UTF8&amp;tag=corbieresweb-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0672329166">PHP and MySQL Web Development</a><img src="http://www.assoc-amazon.com/e/ir?t=corbieresweb-20&amp;l=as2&amp;o=1&amp;a=0672329166&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" /> by Welling and Thompson is an egregious example). Finally, he does a good job of building up examples and leading the reader through them. The chapter on form handling is particularly good, and there&#8217;s also a whole chapter on regular expressions which does a better job than most of demystifying them. If you are an intermediate PHP coder, you&#8217;ll probably find this book useful to improve your skills, and I&#8217;m glad to find an up-to-date PHP book I can use for my course. But I&#8217;m still looking for the perfect intermediate PHP book!</p>
<p>One last black mark for Peachpit: the 2-column layout really doesn&#8217;t work for this material. Code listings drag on for pages because they are squashed into a narrow column, and the whole thibg looks untidy. Why they didn&#8217;t use a single-column design is beyond me.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.archetype-it.com/thebackburner/2011/09/30/book-review-php-and-mysql-for-dynamic-web-sites-visual-quickpro-guide-4th-edition-by-larry-ullman/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Accessing virtual hosts across a LAN</title>
		<link>http://www.archetype-it.com/thebackburner/2011/09/05/accessing-virtual-hosts-across-a-lan/</link>
		<comments>http://www.archetype-it.com/thebackburner/2011/09/05/accessing-virtual-hosts-across-a-lan/#comments</comments>
		<pubDate>Mon, 05 Sep 2011 12:43:53 +0000</pubDate>
		<dc:creator>Veronica Yuill</dc:creator>
				<category><![CDATA[Web development]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[htaccess]]></category>
		<category><![CDATA[virtual hosts]]></category>

		<guid isPermaLink="false">http://www.archetype-it.com/thebackburner/2011/09/05/accessing-virtual-hosts-across-a-lan/</guid>
		<description><![CDATA[Like many web developers, I have a local Apache/MySQL/PHP setup for developing sites. To ensure maximum compatibility with live servers, I set up a virtual host for each site. That way I know all paths will work. For example, on &#8230; <a href="http://www.archetype-it.com/thebackburner/2011/09/05/accessing-virtual-hosts-across-a-lan/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Like many web developers, I have a local Apache/MySQL/PHP setup for developing sites. To ensure maximum compatibility with live servers, I set up a virtual host for each site. That way I know all paths will work. For example, on my MacBook, all my sites live in subdirectories of /Users/myusername/Sites. It&#8217;s easy enough to set up a virtual host for each site; in Apache&#8217;s config file (normally httpd-vhosts.conf, but your set up may vary) I have the line:<br />
<code>NameVirtualHost *:80</code></p>
<p>and then a virtual host section for each site, for example:<br />
<code><br />
 &lt;virtualhost *:80&gt;<br />
    DocumentRoot /Users/myusername/Sites/site1<br />
    ServerName site1<br />
 &lt;/virtualhost *:80&gt;<br />
</code></p>
<p>That sets up the Apache side of things. In order for my computer to know what address to map the site names to, I now need to edit my hosts file. On the Mac it&#8217;s in /etc/hosts; on Windows it&#8217;s more deeply buried in C:\Windows\System32\drivers\etc. In both cases you need administrator privileges to edit it. Easy enough on the Mac; in Windows you&#8217;ll need to run Notepad or another text editor of your choice as administrator (right-click on it in the Start menu as choose &#8220;run as administrator&#8221;).</p>
<p>For each virtual host that I set up in the Apache config file, I add a line to my hosts file:<br />
<code>127.0.0.1 site1</code><br />
and that provides the mapping I need so that I can use my browser to go to http://site1 and Apache will serve up the correct site. The address 127.0.0.1 always maps to the local computer (i.e. localhost). But what if I want to access site1 from another computer on the LAN? How will it know where site1 is? That turns out to be easy-peasy.</p>
<p>First, find out the IP address of the computer hosting site1. For example 192.168.1.10. On the second computer, edit the hosts file. Add the line:<br />
<code>192.168.1.10 site1</code><br />
Et voilà! Now, when I enter http://site1 on the second computer, it will find it on the first computer, even if it&#8217;s not the default served up by Apache.</p>
<p>Note, you may hit snags with this system if you use DHCP on your LAN, because the IP addresses of the host computers may change from time to time (e.g. if you reboot them). I recommend using static IPs on your local network for this reason, at least for those computers you are using to host websites.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.archetype-it.com/thebackburner/2011/09/05/accessing-virtual-hosts-across-a-lan/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>More nifty SQL: insert if not exists</title>
		<link>http://www.archetype-it.com/thebackburner/2011/06/21/more-nifty-sql-insert-if-not-exists/</link>
		<comments>http://www.archetype-it.com/thebackburner/2011/06/21/more-nifty-sql-insert-if-not-exists/#comments</comments>
		<pubDate>Tue, 21 Jun 2011 13:57:52 +0000</pubDate>
		<dc:creator>Veronica Yuill</dc:creator>
				<category><![CDATA[Databases]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://www.archetype-it.com/thebackburner/2011/06/21/more-nifty-sql-insert-if-not-exists/</guid>
		<description><![CDATA[Quite often you want to insert a record into a table, but only if it doesn&#8217;t already exist. OK, you could first do a SELECT query to check for existence, and then do the insert, but it&#8217;s clumsy and raises &#8230; <a href="http://www.archetype-it.com/thebackburner/2011/06/21/more-nifty-sql-insert-if-not-exists/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Quite often you want to insert a record into a table, but only if it doesn&#8217;t already exist. OK, you could first do a SELECT query to check for existence, and then do the insert, but it&#8217;s clumsy and raises the slim possibility of a race condition (what if someone inserted or deleted that record between the check and the insert?). Every RDBMS seems to handle this differently (and some not at all). In SQL Server, you can do this:<br />
<code>IF NOT EXISTS (SELECT acolumn from atable where column1 = 1 and column2 = 'text') INSERT INTO atable(column1,scolumn2) VALUES(1,'text')</code></p>
<p>And in MySQL:<br />
<code>INSERT INTO atable(column1,column2) SELECT 1, 'text' FROM DUAL WHERE NOT EXISTS (SELECT column1 FROM atable WHERE column1=1 AND column2='text' LIMIT 1)</code></p>
<p>Notice that in MySQL you have to use the dummy DUAL table (which suggests to me that this syntax might work in Oracle too; I haven&#8217;t tried it).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.archetype-it.com/thebackburner/2011/06/21/more-nifty-sql-insert-if-not-exists/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ADODB database abstraction library for PHP</title>
		<link>http://www.archetype-it.com/thebackburner/2010/03/30/adodb-database-abstraction-library-for-php/</link>
		<comments>http://www.archetype-it.com/thebackburner/2010/03/30/adodb-database-abstraction-library-for-php/#comments</comments>
		<pubDate>Tue, 30 Mar 2010 13:57:49 +0000</pubDate>
		<dc:creator>Veronica Yuill</dc:creator>
				<category><![CDATA[Databases]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web development]]></category>
		<category><![CDATA[adodb]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://www.archetype-it.com/thebackburner/2010/03/30/adodb-database-abstraction-library-for-php/</guid>
		<description><![CDATA[I&#8217;ve been using this library for years to make my database interface code database-independent, but I am still discovering new useful functions. Case in point: today I was using the handy rs2csv function, which outputs a recordset to a CSV &#8230; <a href="http://www.archetype-it.com/thebackburner/2010/03/30/adodb-database-abstraction-library-for-php/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been using this library for years to make my database interface code database-independent, but I am still discovering new useful functions. Case in point: today I was using the handy rs2csv function, which outputs a recordset to a CSV file with a few lines of code &#8230;<br />
<code><br />
$fp = fopen($file, "w");<br />
if ($fp) {<br />
   rs2csvfile($rs, $fp);<br />
   fclose($fp);<br />
}<br />
</code></p>
<p>But I needed to massage some of the rows in the recordset before writing them to the file. I struggled for a while before finding <a href="http://www.itevo.de/docs/adodb/docs-adodb.htm#ex10">RSFilter</a>:<br />
<code>$rs2 = RSFilter($rs, 'callbackfunction');</code></p>
<p>The callback function takes two arguments: the recordset and an array (passed by reference) representing a single row of the recordset (see the example in the link to the documentation above). RSFilter deals with running the function on each row, and returns the duly massaged recordset ready for output to the file.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.archetype-it.com/thebackburner/2010/03/30/adodb-database-abstraction-library-for-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Preventing hotlinking of images</title>
		<link>http://www.archetype-it.com/thebackburner/2009/09/29/preventing-hotlinking-of-images/</link>
		<comments>http://www.archetype-it.com/thebackburner/2009/09/29/preventing-hotlinking-of-images/#comments</comments>
		<pubDate>Tue, 29 Sep 2009 08:53:27 +0000</pubDate>
		<dc:creator>Veronica Yuill</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web development]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[hotlinking]]></category>
		<category><![CDATA[htaccess]]></category>

		<guid isPermaLink="false">http://www.archetype-it.com/thebackburner/2009/09/29/preventing-hotlinking-of-images/</guid>
		<description><![CDATA[Using an .htaccess file to prevent people stealing bandwidth by linking directly to your images from another website is a popular and well-known technique. I needed to do this, but decided to take it a step further with a little &#8230; <a href="http://www.archetype-it.com/thebackburner/2009/09/29/preventing-hotlinking-of-images/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Using an .htaccess file to prevent people stealing bandwidth by linking directly to your images from another website is a <a href="http://altlab.com/htaccess_tutorial.html">popular</a> and <a href="http://underscorebleach.net/jotsheet/2004/11/stop-image-hotlinking-tutorial-htaccess-apache">well-known</a> <a href="http://www.htaccesstools.com/hotlink-protection/">technique</a>. I needed to do this, but decided to take it a step further with a little added PHP.</p>
<p>Most solutions simply display another image (as polite or as rude as you like) in place of the hotlinked image. But I was curious to know <em>who</em> was linking to <em>which</em> images. Some of them might be legitimate users, in which case I could unblock them. Others might need to get a stiff warning about copyright.</p>
<p>For the .htaccess file, I used the technique <a href="http://underscorebleach.net/jotsheet/2004/11/stop-image-hotlinking-tutorial-htaccess-apache">here</a>. But the author was actually redirecting to another page with the requested image embedded in it. Hey, I&#8217;m trying to save bandwidth here! So I wrote a PHP script that would log the access and then display a small generic image advertising the website from which the image had been, er, &#8220;borrowed&#8221;. Here&#8217;s the .htaccess file:<br />
<code><br />
RewriteEngine On<br />
# hotlinked images<br />
RewriteCond %{REQUEST_FILENAME} \.(gif|jpe?g|png)$ [NC]<br />
RewriteCond %{HTTP_REFERER} !^$<br />
RewriteCond %{HTTP_REFERER} !mydomain\.com [NC]<br />
RewriteCond %{HTTP_REFERER} !myotherdomain\.com [NC]<br />
RewriteCond %{HTTP_REFERER} !alegitimatedomain\.com [NC]<br />
RewriteRule (.*) /blockimage.php?imagename=$1 [NC,L]<br />
# end hotlinked images<br />
</code><br />
This file, placed in the images directory, blocks all but the authorised domains and any blank referrers from accessing images. Notice that the image requested is passed to my blockimage.php script in the query string (that&#8217;s what the $1 does), because I&#8217;m going to use it later.</p>
<p>I could have logged accesses to a text file, but I have a MySQL database so I might as well use it; it will let me do further statistical analysis of the accesses too. I created the following table:<br />
<code><br />
CREATE TABLE Hotlinks (<br />
  hotlinkid int(10) unsigned NOT NULL auto_increment,<br />
  referrer varchar(255) NOT NULL default '',<br />
  imagename varchar(255) NOT NULL default '',<br />
  linktime timestamp NOT NULL default CURRENT_TIMESTAMP,<br />
  PRIMARY KEY  (hotlinkid)<br />
) ENGINE=InnoDB;<br />
</code><br />
I used INNODB for the table type because I reckoned it would be quicker for frequent writes and infrequent reads, but you can use MyISAM if INNODB isn&#8217;t available on your server.</p>
<p>Now the PHP code:<br />
<code><br />
&lt;?php<br />
// called when an image  is hotlinked<br />
// ... snipped code to connect to database ...<br />
// get the referrer and image name<br />
// first initialise an empty array to hold them<br />
$values = array();<br />
$values['referrer'] = mysql_real_escape_string($_SERVER['HTTP_REFERER']);<br />
// get the image name from the query string thanks to .htaccess<br />
$values['imagename'] = mysql_real_escape_string($_GET['imagename']);<br />
// write it to Hotlinks table using my own insertrow function<br />
$result = insertrow($DB, 'Hotlinks', $values);<br />
// show a nice image advertising my site<br />
$mimetype = 'image/jpeg';<br />
$filename= $_SERVER['DOCUMENT_ROOT'].'/images/sitelogo.jpg';<br />
header('content-type: '.$mimetype);<br />
header('content-length: '.filesize($filename));<br />
readfile($filename);<br />
?&gt;<br />
</code><br />
So after silently logging the access, the PHP code sets the mime type to what the calling page is expecting (an image) and then returns the specified image to the browser. Remember you can&#8217;t have any other output (including white space) before the calls to the header function.</p>
<p>Now I can check the database table to see who is accessing what, and if I see any legitimate domains there, I can add them to the &#8220;allowed&#8221; list in .htaccess.</p>
<p>Ironically I ended up not using this code on the site it was intended for, for various reasons. But I think it&#8217;s an interesting and potentially useful technique, so I&#8217;m posting it here anyway.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.archetype-it.com/thebackburner/2009/09/29/preventing-hotlinking-of-images/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Who knew Javascript could be fun?</title>
		<link>http://www.archetype-it.com/thebackburner/2009/02/02/who-knew-javascript-could-be-fun/</link>
		<comments>http://www.archetype-it.com/thebackburner/2009/02/02/who-knew-javascript-could-be-fun/#comments</comments>
		<pubDate>Mon, 02 Feb 2009 11:44:43 +0000</pubDate>
		<dc:creator>Veronica Yuill</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Web development]]></category>
		<category><![CDATA[jquery]]></category>

		<guid isPermaLink="false">http://www.archetype-it.com/thebackburner/2009/02/02/who-knew-javascript-could-be-fun/</guid>
		<description><![CDATA[It gave me migraines till I discovered jQuery. Now I can validate a form with some simple CSS and a couple of lines of jQuery code. And today I had a rather odd requirement to toggle the colour of cells &#8230; <a href="http://www.archetype-it.com/thebackburner/2009/02/02/who-knew-javascript-could-be-fun/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>It gave me migraines till I discovered <a href="http://jquery.com/">jQuery</a>. Now I can validate a form with some simple CSS and a couple of lines of jQuery code. And today I had a rather odd requirement to toggle the colour of cells in a table when you click on them. In the old days, I wouldn&#8217;t even have attempted this. In my new jQuery heaven, I did this:</p>
<p><code><br />
(document).ready(function() {<br />
$("td.standard").click(<br />
function(){<br />
var currentclass = $(this).attr("class");<br />
if (currentclass.indexOf("highlightcell") == -1) {<br />
$(this).addClass("highlightcell");<br />
}  else {<br />
$(this).removeClass("highlightcell");<br />
}<br />
}<br />
);<br />
});<br />
</code></p>
<p>Voilà!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.archetype-it.com/thebackburner/2009/02/02/who-knew-javascript-could-be-fun/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

