<?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>Hacking at 0300 &#187; Web Design</title>
	<atom:link href="http://bililite.com/blog/category/web-design/feed/" rel="self" type="application/rss+xml" />
	<link>http://bililite.com/blog</link>
	<description>Thoughts on web design and programming from a very occasional volunteer webmaster</description>
	<lastBuildDate>Fri, 23 Jul 2010 09:00:56 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Hacked!</title>
		<link>http://bililite.com/blog/2009/11/17/hacked/</link>
		<comments>http://bililite.com/blog/2009/11/17/hacked/#comments</comments>
		<pubDate>Wed, 18 Nov 2009 02:27:32 +0000</pubDate>
		<dc:creator>Danny</dc:creator>
				<category><![CDATA[Web Design]]></category>

		<guid isPermaLink="false">http://bililite.com/blog/?p=1117</guid>
		<description><![CDATA[Eternal vigilance is the price of liberty. Last month, the Young Israel site was hacked and destroyed. A little talking with my ISP's tech support reminded me that I had an old version of WordPress on the site, in a folder called "wordpress," and that it contained a vulnerability that make the vandalism possible. When [...]]]></description>
			<content:encoded><![CDATA[<p><strong><a href="http://www.bartleby.com/73/1073.html">Eternal vigilance is the price of liberty</a>.</strong> Last month, the <a href="http://youngisrael-stl.org">Young Israel site</a> was hacked and destroyed. A little talking with my <a href="http://1and1.com">ISP</a>'s tech support reminded me that I had an old version of <a href="http://wordpress.org/">WordPress</a> on the site, in a folder called "wordpress," and that it contained a <a href="http://lorelle.wordpress.com/2009/09/04/old-wordpress-versions-under-attack/">vulnerability</a> that make the vandalism possible.</p>
<p>When I <a href="/blog/2009/06/05/moving-the-blog/">moved this blog</a>, I kept it updated, so I don't think it is vulnerable, but I completely forgot to remove the old one. I just changed the links to refer to the new one. Stupid! And now I've paid the price.</p>
<p>Well, we got just about everything restored from backups (missing some old announcements that I don't think anyone will miss), and I <em>think</em> I've removed any vulnerable code. I also am now the proud owner of some cool-looking hacking software that was installed on the site that I want to try to take apart and experiment with. Just more tuition paid to the school of hard knocks.</p>]]></content:encoded>
			<wfw:commentRss>http://bililite.com/blog/2009/11/17/hacked/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Things I Learned About .htaccess</title>
		<link>http://bililite.com/blog/2009/07/27/things-i-learned-about-htaccess/</link>
		<comments>http://bililite.com/blog/2009/07/27/things-i-learned-about-htaccess/#comments</comments>
		<pubDate>Mon, 27 Jul 2009 19:12:57 +0000</pubDate>
		<dc:creator>Danny</dc:creator>
				<category><![CDATA[Web Design]]></category>

		<guid isPermaLink="false">http://bililite.com/blog/?p=1045</guid>
		<description><![CDATA[All I wanted was to get a better 404 page for the bililite.com site and to use mod_rewrite to standardize my pages. Of course, nothing is ever simple and mod_rewrite is voodoo. So it took a week of experimenting, pulling my hair and staring at a lot of 500 errors, but I think I got [...]]]></description>
			<content:encoded><![CDATA[<p>All I wanted was to get a better 404 page for the <a href="/">bililite.com site</a> and to use <a href="http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html">mod_rewrite</a> to <a href="http://www.workingwith.me.uk/blog/software/open_source/apache/mod_rewriting_an_entire_site">standardize my pages</a>. Of course, nothing is ever simple and <a href="http://httpd.apache.org/docs/2.0/rewrite/#preamble">mod_rewrite is voodoo</a>. So it took a week of experimenting, pulling my hair and staring at a lot of <a href="http://www.checkupdown.com/status/E500.html">500 errors</a>, but I think I got things where I wanted them (still don't have a very elegant 404 page, though!). To make sure I didn't have to go through this again, and to help anyone else out there, here are the things I wish I had known:</p><span id="more-1045"></span>
<h3><a href="http://www.askapache.com/">askApache</a> is my new best friend</h3>
<p>There are <a href="http://www.google.com/search?q=mod_rewrite+tutorial">lots of mod_rewrite tutorials out there</a> on the web, but once you get past the simple stuff, nothing is obvious. <a href="http://www.askapache.com/">askApache</a> digs deeper and explains more of the hack-y stuff that you need to know in order to actually <em>use</em> your <code>.htaccess</code> file, especially his <a href="http://www.askapache.com/htaccess/crazy-advanced-mod_rewrite-tutorial.html">Crazy Advanced Mod_Rewrite Tutorial</a>, Highly recommended.</p>
<h3>Know the difference between <code>Redirect</code> and <code>Rewrite</code></h3>
<p>Both of these involve changing a URL to a different one. Redirecting, however, tells the browser that it changed (generally by sending a <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.2">301 status code</a>) while rewriting (or "internally redirecting") keeps it a secret. Thus if I internally use URL's like <code>//example.com/index.php?main=foo&#038;part=bar</code> but publicly I want them to look like <code>//example.com/foo/bar</code> I'll rewrite:</p>
<pre><code>RewriteRule ^([^/\.]+)/([^/\.]+)$ index.php?main=$1&#038;part=$2 [QSA,L]</code></pre>
<p>But to publicly change a URL, say from <code>//example.com/oldname.html</code> to <code>//example.com/newname.html</code> I'll redirect:</p>
<pre><code>Redirect Permanent /oldname.html /newname.html
# or
RewriteRule ^oldname.html$ newname.html [R]</code></pre>
<p>Note that it's usually easier to use <a href="http://httpd.apache.org/docs/2.0/mod/mod_alias.html#redirect"><code>Redirect</code></a> or <a href="http://httpd.apache.org/docs/2.0/mod/mod_alias.html#redirectmatch"><code>RedirectMatch</code></a> rather than <a href="http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html#rewriterule"><code>RewriteRule</code></a> with the [R] flag. Note also that the <code>Redirect</code> pattern starts with the <code>/</code> (or whatever the per-directory prefix is) while <code>RewriteRule</code> patterns strip the <code>/</code> out. I've been burned by this! (this is true for <code>.htaccess</code> only; the per-server configuration file <code>httpd.conf</code> uses the entire URL. But I'm on a cheap shared server; I can't touch <code>httpd.conf</code>).</p>
<h3>Use <code>Redirect</code> to append a slash to directories</h3>
<p>Generally, if you use a URL like <code>//example.com/foo</code> you really want <code>//example.com/foo/</code>. Apache does this <a href="http://httpd.apache.org/docs/2.2/mod/mod_dir.html#directoryslash">automatically</a> for real directories. But if you're doing the <code>/foo/bar</code> to <code>/index.php?main=foo&#038;part=bar</code> and <code>/foo</code> to <code>/index.php?main=foo</code>, you really want <code>/foo</code> to be <em>redirected</em> to <code>/foo/</code>, then /foo/ <em>rewritten</em> to <code>/index.php?main=foo</code>. If you don't, then relative URL's won't work. If the file returned by <code>/foo</code> contains a link <code>&lt;a href="bar"&gt;</code> you want the browser to interpret that href as <code>/foo/bar</code>. But it won't. It thinks the file has the URL <code>/foo</code>, so its directory is <code>/</code> and the relative URL bar refers to <code>/bar</code>. Redirecting <code>/foo</code> to <code>/foo/</code> lets the browser know that <code>foo</code> is to be treated as a directory, so <code>bar</code> refers to <code>/foo/bar</code>. Example:
<pre><code>RedirectMatch Permanent ^/([^/\.]+)$ /$1/
RewriteRule ^([^/\.]+)/$ index.php?main=$1 [QSA,L]
RewriteRule ^([^/\.]+)/([^/\.]+)$ index.php?main=$1&#038;part=$2 [QSA,L]</code></pre>
<h3><code>ErrorDocument</code> should rewrite, not redirect</h3>
<p>It's incredibly annoying to type in <code>//example.com/long/complicated/urk.html</code> (note the typo!) and have the address bar turn into //example.com/404.html. I want the address bar to stay the same so I can edit what I wrote! The <a href="http://httpd.apache.org/docs/2.0/mod/core.html#errordocument">ErrorDocument</a> directive uses redirection if a complete URL is specified. This is bad. Just start the URL with a slash and it will use internal redirection (what I'm calling rewriting) and the browser's address bar will remain untouched.
<pre><code>ErrorDocument 404 /404.php
#NOT ErrorDocument 404 http://example.com/404.php
</code></pre>
<h3>1&#038;1 gets it wrong</h3>
<p>I use the cheapest shared-server plan from <a href="http://1and1.com">1&#038;1</a> and I've been pretty happy with it: no frills, straight classic <a href="http://en.wikipedia.org/wiki/LAMP_(software_bundle)">LAMP stack</a>, reliable enough for me. But they "hijack" the <code>ErrorDocument</code> for active pages (.php, .cgi, .pl and I assume others) to their own advertising-laden page. That I can understand (again, it's a cheap plan) but they redirect so you can't correct the URL. So I need to do an end run around them by catching nonexistent files first:
<pre><code>RewriteCond %{REQUEST_FILENAME} \.php$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . /404.php [L]
</code></pre>
<h3><code>RewriteCond -f</code> is case sensitive</h3>
<p>This burned me badly before I figured it out. The <code>-f</code> test for <a href="http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html#rewritecond"><code>RewriteCond</code></a> uses the underlying operating system to find the file, which means that on a Linux system, it's case-sensitive. No way around it; the <code>[NC]</code> flag doesn't help. So when I create gif's on my Windows machine in Paint and save it, it automatically names the file <code>whatever.GIF</code> and remains that way when I copy it to the Linux server. Now Apache will do fine finding the file if I request it with <code>&lt;img src="whatever.gif"/&gt;</code>, but if my <code>.htaccess</code> has a line <code>RewriteCond %{REQUEST_FILENAME} !-f</code> it will return true since <code>whatever.gif</code> doesn't exist; <code>whatever.GIF</code> does.</p>
<p>Hope this saves someone some time (and hair).</p>]]></content:encoded>
			<wfw:commentRss>http://bililite.com/blog/2009/07/27/things-i-learned-about-htaccess/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Don&#8217;t Reinvent the Wheel</title>
		<link>http://bililite.com/blog/2009/06/29/dont-reinvent-the-wheel/</link>
		<comments>http://bililite.com/blog/2009/06/29/dont-reinvent-the-wheel/#comments</comments>
		<pubDate>Mon, 29 Jun 2009 18:38:13 +0000</pubDate>
		<dc:creator>Danny</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Web Design]]></category>

		<guid isPermaLink="false">http://bililite.com/blog/?p=986</guid>
		<description><![CDATA[See the updated version. I needed a date/time picker and spend a couple of hours making a simple one: $('#datetime').flexdate() Obviously, I didn't spend a couple of hours putting this together. I wrote it quickly, then spend the hours getting it to work even remotely correctly in Internet Explorer. Download the code and the HTML [...]]]></description>
			<content:encoded><![CDATA[<p><strong>See the <a href="/blog/2009/07/09/updating-timepickr/">updated version</a></strong>.</p>
<script src="/inc/jquery.ui.subclass.js"></script>
<script src="/inc/jquery.textpopup.js"></script>
<script src="/inc/jquery.flexcal.js"></script>
<script src="/inc/jquery.flexdate.js"></script>
<script src="/inc/jquery.timepickr.js"></script>
<script type="text/javascript"
  src="http://jqueryui.com/themeroller/themeswitchertool/">
</script>
<p>I needed a date/time picker and spend a couple of hours making a simple one:</p>
<div id="themeswitcher" ></div>
<input id="datetime"/>
<script>$('#datetime').flexdate()</script>
<p>Obviously, I didn't spend a couple of hours putting this together. I wrote it quickly, then spend the hours getting it to work even remotely correctly in <a href="http://youngisrael-stl.org/images/webdesign.png">Internet Explorer</a>.</p>
<span id="more-986"></span>
<p>Download the <a href="/inc/jquery.flexdate.js">code</a> and the <a href="/inc/jflexdate.html">HTML template</a>.</p>
<p>But I wasn't fond of the user interface (edit time by typing, then click on date) or the design, so I decided to search for something better and found, via <a href="http://ejohn.org/blog/picking-time/">John Resig</a>, Maxime Haineault's <a href="http://haineault.com/media/jquery/ui-timepickr/page/">timepickr</a>.</p>
<script>
  $('head').append('<link href="/inc/jquery.timepickr.css" rel="stylesheet" type="text/css"/>');
  $(document).ready(function(){
    $('#themeswitcher').themeswitcher();
  });
</script><input id="timepickr" />
<pre><code class="language-javascript demo">
$('#timepickr').timepickr({convention: 12, resetOnBlur: false});
</code></pre>
<p>Which I like a lot more (I'll have to separate the date from the time-picking, but I think that's the right approach anyway). This should teach me that <a href="http://lmgtfy.com/">Google Is My Friend</a>. No need to invent everything from scratch!</p>
]]></content:encoded>
			<wfw:commentRss>http://bililite.com/blog/2009/06/29/dont-reinvent-the-wheel/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Moving the Blog</title>
		<link>http://bililite.com/blog/2009/06/05/moving-the-blog/</link>
		<comments>http://bililite.com/blog/2009/06/05/moving-the-blog/#comments</comments>
		<pubDate>Fri, 05 Jun 2009 14:01:38 +0000</pubDate>
		<dc:creator>Danny</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web Design]]></category>

		<guid isPermaLink="false">http://bililite.com/blog/?p=824</guid>
		<description><![CDATA[I decided that this blog is mine, rather than Young Israel's, so I wanted to move it to a domain that I personally own. Thus, it is no longer at youngisrael-stl.org/wordpress, but at bililite.com/blog. Moving the blog intact was non-trivial, so I'm recording how I did it, based on mydigitallife's instructions: Create the new folder, [...]]]></description>
			<content:encoded><![CDATA[<p>I decided that this blog is mine, rather than Young Israel's, so I wanted to move it to a domain that I personally own. Thus, it is no longer at youngisrael-stl.org/wordpress, but at bililite.com/blog. Moving the blog intact was non-trivial, so I'm recording how I did it, based on <a href="http://www.mydigitallife.info/2007/10/01/how-to-move-wordpress-blog-to-new-domain-or-location/">mydigitallife's instructions</a>:</p>
<ol>
<li>Create the new folder, bililite.com/blog/</li>
<li>Create a new mySQL database on bililite.com
<li>Copy all of youngisrael-stl.org/wordpress/ into bililite.com/blog/</li>
<li>Edit the wp-config.php file to reflect the new database name/user/password</li>
<li>Backup the youngisrael-stl.org database into an SQL file with <a href="http://www.phpmyadmin.net/">phpMyAdmin</a> or <a href="/blog/2009/02/10/the-agony-of-unicode-and-backing-up-mysql/">some other tool</a></li>
<li>In a text editor, change all the "http://youngisrael-stl.org/wordpress" to "http://bililite.com/blog" and "/wordpress" to "/blog". note that there are both absolute and relative URL's in there, and I was changing both the domain and the subdirectory, so I had to do two replacements. I couldn't just change "http://youngisrael-stl.org" because I didn't want to change links to the actual site.</li>
<li>Run the edited SQL file on the bililite.com database</li>
<li>In the youngisrael-stl.org/.htaccess , add the line "<a href="http://httpd.apache.org/docs/2.2/mod/mod_alias.html#redirect">Redirect</a> permanent /wordpress http://bililite.com/blog" to let browsers know I've moved</li>
<li>Actually announce the change on mailing lists of <a href="http://groups.google.com/group/jquery-ui-dev/topics?hl=en">people who actually read the site</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://bililite.com/blog/2009/06/05/moving-the-blog/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>jQuery UI 1.7</title>
		<link>http://bililite.com/blog/2009/03/08/jquery-ui-17/</link>
		<comments>http://bililite.com/blog/2009/03/08/jquery-ui-17/#comments</comments>
		<pubDate>Sun, 08 Mar 2009 15:04:15 +0000</pubDate>
		<dc:creator>Danny</dc:creator>
				<category><![CDATA[Web Design]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://bililite.com/blog/?p=408</guid>
		<description><![CDATA[Finally, jQuery UI 1.6 final is out, renamed 1.7, and it's on google ajax libraries, so it's minimized (45K for the whole thing; .27 sec to download for me, which is nothing, especially if you're loading at the end of your code so the user is busy reading the content of your site). The contributors [...]]]></description>
			<content:encoded><![CDATA[Finally, <a href="http://blog.jqueryui.com/2009/03/jquery-ui-17/">jQuery UI 1.6 final is out, renamed 1.7</a>, and it's on <a href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.0/jquery-ui.min.js">google ajax libraries</a>, so it's minimized (45K for the whole thing; .27 sec to download for me, which is nothing, especially if you're loading at the end of your code so the user is busy reading the content of your site).
The contributors list doesn't include me ($.widget uses $.metadata); so much for my fame and fortune. This release still has the <a href="http://dev.jqueryui.com/ticket/4278">droppable bug</a>; looks like that's to be fixed in 1.7.1.]]></content:encoded>
			<wfw:commentRss>http://bililite.com/blog/2009/03/08/jquery-ui-17/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Agony of Unicode (and backing up mySQL)</title>
		<link>http://bililite.com/blog/2009/02/10/the-agony-of-unicode-and-backing-up-mysql/</link>
		<comments>http://bililite.com/blog/2009/02/10/the-agony-of-unicode-and-backing-up-mysql/#comments</comments>
		<pubDate>Tue, 10 Feb 2009 07:19:52 +0000</pubDate>
		<dc:creator>Danny</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web Design]]></category>

		<guid isPermaLink="false">http://bililite.com/blog/?p=359</guid>
		<description><![CDATA[All I wanted to do was back up the Young Israel databases, some way more amenable to automation than phpMyAdmin. There are lots of PHP-based solutions on the web, but all seem based on mysqldump. I implemented one and found myself faced with an eyeful of ××¨×™××œ ×ž××™×¨ ×™×¢×§×‘ ×‘×Ÿ ×“×•×“ ××‘×¨×”× where the Hebrew [...]]]></description>
			<content:encoded><![CDATA[<p>All I wanted to do was back up the Young Israel databases, some way more amenable to automation than <a href="http://www.phpmyadmin.net/home_page/index.php">phpMyAdmin</a>. There are <a href="http://www.google.com/search?q=php+mysql+backup">lots of PHP-based solutions</a> on the web, but all seem based on <a href="http://dev.mysql.com/doc/refman/5.1/en/mysqldump.html">mysqldump</a>. I implemented <a href="http://www.dagondesign.com/articles/automatic-mysql-backup-script/">one</a> and found myself faced with an eyeful of ××¨×™××œ ×ž××™×¨ ×™×¢×§×‘ ×‘×Ÿ ×“×•×“ ××‘×¨×”× where the Hebrew names should be. Turns out this a known bug; <a href="http://bugs.mysql.com/bug.php?id=28969">mysqldump can't handle Unicode</a>. There are reports of <a href="http://vandenabeele.com/mysqldump-utf8-bug">workarounds</a>, but I spent 8 hours not getting anything to work.<p>
<p>So I had to write my own backup, going through each database on a server then each table in the database, writing the appropriate <code>INSERT INTO</code> commands (thank goodness the <code>SHOW CREATE DATABASE</code> and <code>SHOW CREATE TABLE</code> commands work correctly). It wasn't terribly miserable (not nearly as miserable it was trying to use someone else's tool that doesn't work), and now I get my&nbsp;
 אריאל מאיר יעקב בן דוד אברהם  just fine, and the backup works. I import the generated file into my local copy of mySQL and it regenerates the databases.</p>
<span id="more-359"></span>
<pre><code class="language-php">
// if this file is called directly from the web, run the backup on the requested databases
if (realpath(__FILE__) == realpath($_SERVER['SCRIPT_FILENAME'])) db_backup($_REQUEST['database']);

function db_backup($databases){
	if (!is_array($databases)) $databases = array($databases);
	$dir = '/backup'; // change this as desired
	if( !is_dir( $dir ) &#038;& !mkdir( $dir )) die('&lt;h1&gt;Could not create backup directory&lt;/h1&gt;'); 
	foreach ($databases as $database){
		list($host, $name, $user, $password) = explode('/', $database);
		$now = date('Y-m-d'); // change this as desired
		@mysql_connect($host, $user, $password) or die ("&lt;h1&gt;Could not connect to $host&lt;/h1&gt;");
		file_put_contents("$dir/$name-$now.sql", dump_dbs());
	}
}

// based on http://davidwalsh.name/backup-mysql-database-php
function dump_dbs(){
	$ret = '';
	$dbs = mysql_list_dbs();
	while ($db_row = mysql_fetch_object($dbs)) {
		$db = $db_row->Database;
		if ($db == 'information_schema') continue;
		mysql_select_db ($db);
		mysql_query("SET NAMES 'utf8'");  // magic command to make mySQL output UTF8 to PHP
		$ret = "DROP DATABASE IF EXISTS `$db`;\n";
		$createdb = mysql_fetch_row(mysql_query("SHOW CREATE DATABASE `$db`"));
		$ret .= $createdb[1].";\nUSE `$db`;\n";
		$tables = mysql_query('SHOW TABLES');
		while($table = mysql_fetch_row($tables)){
			$ret .= dump_table($table[0]);
		}
	} // while
	return $ret;
}

function dump_table($table){
	$ret = "\nDROP TABLE IF EXISTS `$table`;\n";
	$createtable = mysql_fetch_row(mysql_query("SHOW CREATE TABLE `$table`"));
	$ret .= $createtable[1].";\n";
	$dbresult = mysql_query ("SELECT * FROM `$table`");
	while($row = mysql_fetch_assoc($dbresult)) {
		$keys = fixkeys(array_keys($row));
		$values = fixvalues(array_values($row));
		$ret .= "\tINSERT INTO `$table` (".join(',', $keys).') VALUES ('.join(',',$values).");\n";
	}
	return $ret;
}
function fixkeys ($arr){
	foreach ($arr as &#038;$i){
		$i = "`$i`";
	}
	return $arr;
}
function fixvalues($arr){
	foreach ($arr as &#038;$i){
		$i = is_null($i) ? 'NULL' : "'".preg_replace("/\r\n|\n|\r/",'\n',addslashes($i))."'";
	}
	return $arr;
}
</code></pre>
<p>The main function db_backup takes a string or an array of strings that describe the databases to be backed up, of the form <code>'host/name/user/password'</code>. For the databases that <a href="http://1and1.com">my host</a> provides it would look like <code>'db12345.perfora.net/descriptivename/dbo45678/password'</code>, where <code>descriptivename</code> is whatever you want prepended to the backup file, which is named 'descriptivename-2009-02-09.sql' or whatever the date is.</p>
<p>If it is called directly as a web page, the database strings are taken from the query string with key "database". If you want to pass more than one database, don't forget to use <code>database[]=</code> to make it into a PHP array. Thus,</p> <pre><code>http://example.com/db_backup.php?database=db12345.perfora.net/serverdata/dbo45678/password</code></pre>
<p>or</p>
<pre><code>http://example.com/db_backup.php?database[]=db12345.perfora.net/serverdata/dbo45678/password&#038;database[]=localhost/localdata</code></pre>
<p>I hope this saves someone a whole lot of agony!</p>]]></content:encoded>
			<wfw:commentRss>http://bililite.com/blog/2009/02/10/the-agony-of-unicode-and-backing-up-mysql/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Upgrading to jQuery UI 1.6</title>
		<link>http://bililite.com/blog/2009/01/29/upgrading-to-jquery-ui-16/</link>
		<comments>http://bililite.com/blog/2009/01/29/upgrading-to-jquery-ui-16/#comments</comments>
		<pubDate>Thu, 29 Jan 2009 19:24:03 +0000</pubDate>
		<dc:creator>Danny</dc:creator>
				<category><![CDATA[Web Design]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://bililite.com/blog/?p=316</guid>
		<description><![CDATA[I've updated my widgets tutorials to use jQuery UI 1.6, pulling the rc5 release off the svn site and turning them into pages rather than posts, since they seem to be so popular. See the widget tutorial and the extending widgets page. Now all I need is for the UI team to officially release 1.6 [...]]]></description>
			<content:encoded><![CDATA[<p>I've updated my widgets tutorials to use jQuery UI 1.6, pulling the rc5 release off the <a href="http://jquery-ui.googlecode.com/svn/tags/1.6rc5/ui/">svn site</a> and turning them into pages rather than posts, since they seem to be so popular. See the <a href="/blog/understanding-jquery-ui-widgets-a-tutorial/">widget tutorial</a> and the <a href="/blog/extending-jquery-ui-widgets/">extending widgets page</a>.</p>
<p>Now all I need is for the UI team to officially release 1.6 so I can load it from googleapis rather than the jquery svn!</p>]]></content:encoded>
			<wfw:commentRss>http://bililite.com/blog/2009/01/29/upgrading-to-jquery-ui-16/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>jQuery CSS parser</title>
		<link>http://bililite.com/blog/2009/01/16/jquery-css-parser/</link>
		<comments>http://bililite.com/blog/2009/01/16/jquery-css-parser/#comments</comments>
		<pubDate>Fri, 16 Jan 2009 06:21:06 +0000</pubDate>
		<dc:creator>Danny</dc:creator>
				<category><![CDATA[Web Design]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://bililite.com/blog/?p=251</guid>
		<description><![CDATA[Updated 2009-05-03 Every time I create or use a jQuery plugin, I realize that the assigning of behaviors to elements on the page is a design decision, not a programming one, and one that should be made by the guy in charge of the CSS, not the guy in charge of the javascript. Even when [...]]]></description>
			<content:encoded><![CDATA[<p>Updated 2009-05-03</p>
<p>Every time I create or use a jQuery plugin, I realize that the assigning of behaviors to elements on the page is a design decision, not a programming one, and one that should be made by the guy in charge of the CSS, not the guy in charge of the javascript. Even when I'm the same guy, I want to wear each hat separately. But these presentational enhancements are written in javascript and applied in javascript. So my "presentational" code is in two different files:</p>
<dl>
<dt>style.css</dt><dd><pre><code class="language-css">
.gallery a { border: 1px solid green }
</code></pre></dd>
<dt>style.js</dt><dd><pre><code class="language-javascript">
$('.gallery a').<a href="http://leandrovieira.com/projects/jquery/lightbox/">lightbox</a>({overlayBgColor: '#ddd'});
</code></pre></dd>
</dl>
<p>I could put the presentational javascript in the HTML with <a href="http://docs.jquery.com/Plugins/Metadata" class="language-javascript">$.metadata</a> but while that's fine for quick-and-dirty pages, it's <a href="/blog/2008/08/29/making-metadata-extensible/">evil</a> in production since it completely violates the separation of data/structure/presentation/behavior.</p>
<p>As <a href="/blog/2007/10/19/css-parser-in-javascript/">I</a> and <a href="http://frontendbook.com/javascript-css-parser-for-custom-properties/">others</a> have noted before, the application of these plugins belongs in the stylesheet, and I finally got it to work:</p>
<dl>
<dt>style.css</dt><dd><pre><code class="language-css">
.gallery a {
  border: 1px solid green;
  -jquery-lightbox: {overlayBgColor: '#ddd'};
}
</code></pre></dd>
</dl>
<p>and a single call to start it off: <code class="language-javascript">$().parsecss($.parsecss.jquery)</code> .</p>
<p><a href="/inc/jquery.parsecss.js">Download the code</a>.</p>
<p><a href="/blog/blogfiles/cssparser/cssparsertest.php">See the demo</a>.</p>
<span id="more-251"></span>
<h4>Use</h4>
<p><code class="language-javascript">$(selector).parsecss(callback)</code> scans all <code class="language-html">&lt;style&gt;</code> and <code>&lt;link type="text/css"&gt;</code> elements in <code class="language-javascript">$(selector)</code> or its descendents, parses each one and passes an object (details <a href="#parserdetails">below</a>) to the callback function. It uses a callback because external stylesheets and <code class="language-css">@import</code> statements need to use AJAX, asynchronously. The parser is smart enough to understand <code>media</code> attributes and statements.</p>
<p>The supplied callback is the <code class="language-jquery">$.parsecss.jquery</code> function. That function finds properties that start with <code class="language-css">-jquery</code> and applies them to the matching elements. Generally, you would want to parse all the stylesheets in the document, <code class="language-javascript">$(document)</code>, which in jQuery is abbreviated <code class="language-javascript">$()</code>, so the simple call is: <code class="language-javascript">$().parsecss($.parsecss.jquery)</code>.</p>
<h4>The CSS</h4>
<p>Some jargon: in the stylesheet<p>
<pre><code class="language-css">foo {
  bar: quux;
  -bar-foo: quux-2;
}

foo > foo {
  bar: quux 2;
}
</code></pre>
<p><code class="language-css">foo { bar: quux; -bar-foo: quux-2}</code> is a statement, <code class="language-css">foo</code> is a selector, <code class="language-css">{bar: quux; -bar-foo: quux-2}</code> is its CSStext, <code class="language-css">-bar-foo: quux-2</code> is a declaration, <code class="language-css">-bar-foo</code> is its property and <code class="language-css">quux-2</code> is its value.</p>
<h4><code>$.parsecss.jquery</code></h4>
<p><code class="language-javascript">$.parsecss.jquery</code> is the callback function that implements the custom-jQuery code. It looks for properties that start with <code>-jquery</code>. If the property is <code class="language-css">-jquery</code> alone, then it executes the value as a javascript statement for each matched element, <code class="language-javascript">$(selector).each(Function(value))</code>. For example:</p>
<pre><code class="language-css">span.important {
  -jquery: $(this).append('&lt;span&gt;I am important&lt;/span&gt;')
}</code></pre>
<p>executes</p>
<pre><code class="language-javascript">$('span.important').each(function() {$(this).append('&lt;span&gt;I am important!&lt;/span&gt;')})</code></pre>
<p>If the property is <code class="language-css">-jquery-show</code> or <code class="language-css">-jquery-hide</code>, then the normal show() and hide() are overridden for the matched elements to use the value as the arguments. It will recognize plugins and <a href="http://docs.jquery.com/UI/Effects/effect">jQuery UI effects</a>. Examples (<a href="#parsearguments">see below</a> how it parses the arguments):</p>
<pre><code>
a {
  -jquery-show: fast; /* <code class="language-javascript">$('a').show()</code> does <code class="language-javascript">$('a').show('fast')</code> */
  -jquery-show: fadeIn 2000 /* <code class="language-javascript">$('a').show()</code> does <code class="language-javascript">$('a').fadeIn(2000)</code> */
  -jquery-show: fold {size: 5} slow /* <code class="language-javascript">$('a').show()</code> does <code class="language-javascript">$('a').show('fold', {size: 5}, 'slow')</code> */
  -jquery-hide: explode fast /* <code class="language-javascript">$('a').hide()</code> does <code class="language-javascript">$('a').hide('explode', {}, 'fast')</code> It's smart enough to know that jQuery UI effects need an options object inserted */
}</code></pre>
<p>Using <code>hide()</code> or <code>show()</code> with any arguments overrides the CSS-imposed functions.</p>
<p>Otherwise, if the property matches the regular expression <code class="language-javascript">/-jquery-(.*)/</code> then the (.*) is taken as a plugin name and the value is used for the arguments (<a href="#parsearguments">see below</a> how it parses the arguments):</p>
<pre><code class="language-css">.gallery a {
  -jquery-lightbox: {overlayBgColor: '#ddd'}
}</code></pre>
<p>executes</p>
<pre><code class="language-javascript">$('.gallery a').lightbox({overlayBgColor: '#ddd'});</code></pre>
<h4>Valid CSS?</h4>
<p>Does including the <code>-jquery</code> properties make the CSS invalid? Sort of. The easy answer is "Who cares?" 
The CSS syntax <a href="http://www.w3.org/TR/CSS21/syndata.html#parsing-errors">specifies</a> that <blockquote>User agents must handle unexpected tokens encountered while parsing a declaration by reading until the end of the declaration, while observing the rules for matching pairs of (), [], {}, "", and ''</blockquote>
That means that the extensions described here will never cause errors in interpreting the rest of the CSS. Also, the specification says
<blockquote>Keywords and property names beginning with -' or '_' are reserved for vendor-specific extensions.</blockquote>
So, <code>-jquery-show</code>, while not valid, is "expected" in real-life CSS, just like <code>-moz-border-radius</code>.</p>
<p>But, some people want CSS that passes the <a href="http://jigsaw.w3.org/css-validator/">validator</a>. I adopted a solution similar to <a href="http://msdn.microsoft.com/en-us/library/121hztk3(VS.71).aspx">Microsoft's conditional comments</a>. Text surrounded by <code>/*@</code> and <code>*/</code> will be parsed by the parser despite being ignored by the browser.</p>
<pre><code class="language-css">span.important {
      font-weight: bold;
/*@   -jquery-after: '&lt;span&gt;!!!&lt;/span&gt;'; */ /* "hide" the jQuery CSS in the comments */
}</code></pre>
<h4><code>$.livequery</code></h4>
<p>What makes the combination of CSS and javascript so powerful is that CSS is "live": changes in the DOM are immediately rendered on the page (this is why Microsoft, when they invented it, called it <a href="http://msdn.microsoft.com/en-us/library/ms533050.aspx">DHTML</a>&mdash;Dynamic HTML). If the stylesheet says <code class="language-css">.important { font-weight: bold; color: red }</code> then running <code class="language-javascript">$('#x').addClass('important')</code> changes the text to red and bold. In addition, <code class="language-javascript">$('#x').removeClass('important')</code> changes the text back. The browser keeps track of all the elements and the selector in the CSS, and when an element starts to match the CSS is applied, and when it no longer matches, the browser knows how to "undo" the styling.</p>
<p>jQuery plugins can't do this. The javascript is run at <code class="language-javascript">$(document).ready</code>, applied if the elements match at that moment, and that's it. This makes it much less useful, especially for AJAX-y sites that are constantly changing their elements.</p>
<p>Enter Brandon Aaron's <a href="http://plugins.jquery.com/project/livequery"><code class="language-javascript">$.livequery</code> plugin</a>. It keeps track of the selectors used and overrides all the plugins that modify the DOM, and re-applies the javascript if need be. It also allows you to specify <a href="http://docs.jquery.com/Plugins/livequery/livequery#matchedFnunmatchedFn">an "unmatched" function</a> that will be run when the element no longer matches. Obviously, you or the plugin programmer has to provide the "undo" ability; there's no way for <code class="language-javascript">$.livequery</code> to know how to do that.</p>
<p>If <code class="language-javascript">$.livequery</code> is available, <code class="language-javascript">$.parsecss</code> can use it. Separate the two parts (match code/unmatch code) with a <code class="language-javascript">!</code> (the exclamation point implies "not"):</p>
<pre><code class="language-javascript">.important {
  -jquery-css: font-weight bold ! font-weight normal ;
}
/* yes, in real life you'd do font-weight: bold;  and not rely on javascript */
</code></pre>
<p>You can leave either side of the <code class="language-javascript">!</code> blank:</p>
<pre><code class="language-javascript">.gallery a {
  -jquery-lightbox: {overlayBgColor: '#ddd'} ! ; /* the '!' means we'll use livequery */
  -jquery-unbind: ! click; /* remove the click handler when the element no longer matches
}
</code></pre>
<p>Some notes on <code class="language-javascript">$.livequery</code>:</p>
<ul>
<li>If <code class="language-javascript">$.livequery</code> is not available, the value after the <code class="language-javascript">!</code> is ignored and the code is applied only when <code class="language-javascript">$.parsecss</code> is called.</li>
<li><code class="language-javascript">$.livequery</code> checks every selector on every modification of the DOM. It can make <a href="http://news.ycombinator.com/item?id=433631">complicated pages and script very slow</a>. Be aware of the tradeoffs of using it.</li>
<li>jQuery 1.3 includes a <code class="language-javascript">$.live</code> plugin. This is not the same as <code class="language-javascript">$.livequery</code>! It uses event delegation to keep event handlers on new elements, but does not re-apply javascript to new elements. You have to use <code class="language-javascript">$.livequery</code> for that.</li>
</ul>
<h4 id="parserdetails">The parser</h4>
<p>The parser turns CSS into a javascript object in the obvious way:</p>
<pre><code class="language-css">
div div:first {
  font-weight: bold;
  -jquery: each(function() {alert(this.tagName);})
}

div > span {
  color: red;
}
</code></pre>
<p>is passed to the callback as:</p>
<pre><code class="language-javascript">
{
  'div div:first' : {
    'font-weight' : 'bold',
    '-jquery': 'each(function() {alert(this.tagName);})'
  },
  'div > span' : {
    'color': 'red'
  }
}
</code></pre>
<p>The callback is called separately for each &lt;style&gt; and &lt;link&gt; element, and for every @rule that includes CSS text (@import and @media). There is no guarantee of any particular order in calling the callback. The parser (and <code>$.parsecss.jquery</code>)does not attempt to obey the <a href="http://www.w3.org/TR/CSS21/cascade.html#cascade">priority rules of the CSS cascade</a>; it will execute all the relevant code.</p> 
<p>The parser is very simple; it uses regular expressions and <code>String.remove</code> to pull out comments, strings, brace-delimited blocks and @-rules, then parsing the grammar by using <code>String.split</code> on <code>}</code> to get each statement, splitting on <code>{</code> to get the selector and cssText, splitting the cssText on <code>;</code> to get each declaration and on <code>:</code> to get the properties and values. It's not a sophisticated <a href="http://www.amazon.com/Compilers-Principles-Techniques-Tools-2nd/dp/0321486811">finite-state automaton</a> but it serves.</p>
<h4 id="parsearguments"><code>$.parsecss.parseArguments</code></h4>
<p>CSS values use space-delimited arguments, <code>border: 1px solid black</code></p>. To use this in javascript, we use <code>apply</code> which requires an array: <code>['1px', 'solid', 'black']</code>. The function <code>$.parsecss.parseArguments({String})</code> returns that array. It tries to be sophisticated about arrays, objects and functions, using eval to see if the item is interpretable as is; if not, it is made a string. This means that global variables (this, window) or expressions will cause unexpected results (put them in quotes to be sure):</p>
<pre><code>
a b c                                       =>  ['a', 'b', 'c']
1 2 c                                       =>  [1, 2, 'c']
[1,2] {a: 'b c'}                          =>  [[1,2], {a: 'b c'} ]
{a: b, c: d}                              =>  ["{a: b, c: d}"] // inside arrays, objects and functions, you have to use real javascript syntax
{a: 'b', c: 'd'}                            =>  [{a:"b", c:"d"}] // the automagic quoting is only at the top level
1+2                                         =>  [3]
'1+2'                                        =>  ['1+2']
10 fast function() {$(this).hide}   =>  [10, "fast", (function () {$(this).hide;})]
</code></pre>
<p>
<h4><code>$.parsecss.isValidSelector</code></h4>
<p><code class="language-javascript">$.parsecss.isValidSelector(selector {String})</code> is a function I wrote for Any Kent's <a href="http://github.com/andykent/jss/tree/master">JSS</a>, which is sort of the opposite of <code class="language-javascript">$.parsecss.jquery</code>: it goes through the stylesheets and finds valid CSS selectors that the browser cannot handle, and uses jQuery to implement them. Eric Meyer recently had a <a href="http://meyerweb.com/eric/thoughts/2008/10/22/javascript-will-save-us-all/">similar idea</a>. <code class="language-javascript">$.parsecss.isValidSelector</code> takes a string and returns <code class="language-javascript">true</code> if the browser recognizes it as a CSS selector. Thus in IE6, <code class="language-javascript">$.parsecss.isValidSelector('div p')</code> returns <code class="language-javascript">true</code> and <code class="language-javascript">$.parsecss.isValidSelector('div > p')</code> returns <code class="language-javascript">false</code>. In Firefox 3, <code class="language-javascript">$.parsecss.isValidSelector('div > p')</code> returns <code class="language-javascript">true</code> and <code class="language-javascript">$.parsecss.isValidSelector('div:visible')</code> returns <code class="language-javascript">false</code>.</p>
<p>A simple (though very inefficient) version of <a href="http://github.com/andykent/jss/tree/master">JSS</a> would be:</p>
<pre><code class="language-javascript">$().parsecss(function(css){
  for (var selector in css){
    if (! $.parsecss.isValidSelector(selector)) $(selector).css(css[selector]);
  }
});</code></pre>
<p>It works by creating a new stylesheet and creating a rule with that selector and seeing if the browser recognized it.</p>
<h4><code>$.parsecss.mediumApplies</code></h4>
<p><code class="language-javascript">$.parsecss.mediumApplies(medium {String})</code> is similar to <code class="language-javascript">$.parsecss.isValidSelector</code>, but it returns true if the argument is a valid media attribute on a<code> &lt;link&gt;</code> element or <code>@media</code> rule. Thus, for a regular computer, <code class="language-javascript">$.parsecss.mediumApplies('screen')</code> returns <code class="language-javascript">true</code>, <code class="language-javascript">$.parsecss.mediumApplies('all')</code> returns <code class="language-javascript">true</code>, <code class="language-javascript">$.parsecss.mediumApplies('print')</code> returns <code class="language-javascript">false</code>, and <code class="language-javascript">$.parsecss.mediumApplies('')</code> returns <code class="language-javascript">true</code>.</p>
<h4>The second argument to <code>$.fn.parsecss</code></h4>
<p><code>parsecss</code> accepts a second argument, <code>parseAttributes {Boolean}</code>. If it is true, the parser will attempt to parse the <code>style</code> attribute of each element and pass it to the callback.</p>
<p>This is problematic on many levels. The first is how to identify the relevant element. If the element is <code class="language-html">&lt;div id="test" style="-jquery-show: fast"&gt;a div&lt;/div&gt;</code> we want the object <code class="language-javascript">{'#test' : {'-jquery-show': 'fast'} }</code>. If the element has an id attribute, then it's easy. Otherwise, it counts the tags in the page and uses <code>:eq()</code>: thus if <code class="language-html">&lt;div style="-jquery-show: fast"&gt;a div&lt;/div&gt;</code> is the fifth <code>div</code> element, the object generated includes <code class="language-javascript">{'div:eq(4)' : {'-jquery-show': 'fast'} }</code>.</p>
<p>The real problem is that there is no way to get the actual <code>style</code> attributes for elements in the DOM. The source code is parsed and interpreted by the browser and any declarations that the browser does not understand are discarded. There's no way to get the style="-jquery-show: fast" using any of the tools available. What I've done is used AJAX to get the source code back again: <code class="language-javascript">$.get(location.pathname+location.search, 'text', function(html){/*code that scans the html for style attributes*/)</code>. This assumes that getting the file again will get the same code (which might not be true if the real page was retrieved with a POST request) and that the DOM has not been changed. Otherwise 'div:eq(4)' will not refer to the correct element. You can obviate this problem by using id's which should not change. Still, the approach is problematic and you might want to use <code>$.metadata</code> to add information to the HTML itself.</p>
<p>If anyone knows how to get the actual text of the "<code>style</code>" attribute, please let me know!</p>]]></content:encoded>
			<wfw:commentRss>http://bililite.com/blog/2009/01/16/jquery-css-parser/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Changes</title>
		<link>http://bililite.com/blog/2008/10/23/changes/</link>
		<comments>http://bililite.com/blog/2008/10/23/changes/#comments</comments>
		<pubDate>Fri, 24 Oct 2008 04:25:02 +0000</pubDate>
		<dc:creator>Danny</dc:creator>
				<category><![CDATA[Web Design]]></category>

		<guid isPermaLink="false">http://bililite.com/blog/?p=155</guid>
		<description><![CDATA[Switched themes to Barthelme; very simple and elegant. Removed the Chili code highlighting line-numbering, which only worked intermittently, tended to get lost in the margins of the &#60;pre&#62; elements, and didn't add much.]]></description>
			<content:encoded><![CDATA[Switched themes to <a href="http://www.plaintxt.org/themes/barthelme/">Barthelme</a>; very simple and elegant. Removed the Chili code highlighting line-numbering, which only worked intermittently, tended to get lost in the margins of the &lt;pre&gt; elements, and didn't add much.]]></content:encoded>
			<wfw:commentRss>http://bililite.com/blog/2008/10/23/changes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Testing demo insertion</title>
		<link>http://bililite.com/blog/2008/08/14/testing-demo-insertion/</link>
		<comments>http://bililite.com/blog/2008/08/14/testing-demo-insertion/#comments</comments>
		<pubDate>Fri, 15 Aug 2008 03:00:45 +0000</pubDate>
		<dc:creator>Danny</dc:creator>
				<category><![CDATA[Web Design]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://bililite.com/blog/?p=102</guid>
		<description><![CDATA[I added some potentially dangerous code to automatically turn code examples (things in &#60;code&#62; elements with class demo into actual HTML or javascript that are added to the post. The javascript part works; I used it in the last post; here's testing the HTML insertion: &#60;div style="background: purple; margin: 2px"&#62;This is a test&#60;/div&#62; And more [...]]]></description>
			<content:encoded><![CDATA[<p>I added some potentially dangerous code to automatically turn code examples (things in <code>&lt;code&gt;</code> elements with class <code>demo</code> into actual HTML or javascript that are added to the post. The javascript part works; I used it in <a href="/blog/2008/08/13/extending-jquery-ui-widgets-revisited/">the last post</a>; here's testing the HTML insertion:</p>
<pre><code class="language-html demo">
  &lt;div style="background: purple; margin: 2px"&gt;This is a test&lt;/div&gt;
</code></pre>
<p>And more testing:</p>
<pre><code class="demo language-html">
  &lt;div style="background: #080; margin: 2px"&gt;This is a test&lt;/div&gt;
</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://bililite.com/blog/2008/08/14/testing-demo-insertion/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
