<?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>Brain Handles &#187; Web Programming</title>
	<atom:link href="http://www.brainhandles.com/category/techno-thoughts/web-programming/feed" rel="self" type="application/rss+xml" />
	<link>http://www.brainhandles.com</link>
	<description>Whatever&#039;s tugging at my brain handles</description>
	<lastBuildDate>Wed, 08 Feb 2012 05:30:20 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>The Brainhandles Heatmap PHP Class</title>
		<link>http://www.brainhandles.com/techno-thoughts/the-brainhandles-heatmap-php-class</link>
		<comments>http://www.brainhandles.com/techno-thoughts/the-brainhandles-heatmap-php-class#comments</comments>
		<pubDate>Tue, 16 Aug 2011 21:45:55 +0000</pubDate>
		<dc:creator>Greg Bulmash</dc:creator>
				<category><![CDATA[Techno Thoughts]]></category>
		<category><![CDATA[Web Programming]]></category>
		<category><![CDATA[free script]]></category>
		<category><![CDATA[GD]]></category>
		<category><![CDATA[heatmap]]></category>
		<category><![CDATA[multiply]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.brainhandles.com/?p=2640</guid>
		<description><![CDATA[A PHP heatmap class that uses GD to create plasma style heatmaps to overlay on maps or photos.]]></description>
			<content:encoded><![CDATA[<p>
<h3>Current Release 0.5.0 Beta <small>(<a href="/wp-content/uploads/2011/08/mapclass_distrib1.zip">download</a> - .zip - <i>16k</i> - CC 3.0 Attribution license)</small></h3>
<p><center><br />
<h2>What Is A Heatmap?</h2>
<p>
<div id="photo" style="height:337px;width:425px;background-image:url('/wp-content/uploads/2011/08/ship.jpg')"><img src="/wp-content/uploads/2011/08/testimage.jpg" height=337 width=425 style="padding:0px;margin:0px;opacity:.55;filter:alpha(opacity=55)"></div>
<p><small>Thanks to <a href="http://www.sxc.hu/profile/siewlian">siewlian</a> for our underlying <a href="http://www.sxc.hu/browse.phtml?f=view&#038;id=997313">photo</a></small></center></p>
<p>A heatmap is a way of visually overlaying hostspots of incidence/concentration on a grid. The hotspots can represent a clickstream (I set up a little AJAX script to record every time I clicked on the photo above and then rendered the data of where I clicked as a heatmap), or it could be the incidence of robberies or concentrations of zombies on a map.</p>
<p>Long story short, I got curious about heatmaps last year, but all the solutions I'd found were not in PHP, used the ImageMagick library, had a complex API, produced a heatmap I thought sucked, or multiple elements from that list. Eventually, because it produced the kind of map I wanted and could work simply, I first ported <a href="http://blog.corunet.com/the-definitive-heatmap/">"The Definitive Heatmap"</a> from Ruby to PHP. </p>
<p>I still didn't like the fact that it used ImageMagick (because many people on shared servers might not have access to ImageMagick), plus it executed the ImageMagick commands to the shell, which is not as secure as I'd like. So I re-wrote the whole thing to use PHP's built in graphics library, GD. That came with its own set of pitfalls, most notably being that GD has no Multiply blend mode. I had to create a GD Multiply blend in PHP from scratch. For those of you who arrived here specifically because you were Googling for a PHP script to do a Multiply blend with GD, you'll find that code in the <code>overlayDot()</code> method of the class.</p>
<p>I added a few functional modifications, did about an hour of testing to make sure it worked, wrote up the README, and packed it up.</p>
<p>The <a href="/wp-content/uploads/2011/08/mapclass_distrib1.zip">download</a> package contains the class file, a README with instructions on how to use it, and a graphics folder with a color strip and dot image needed to create the overlay images. You'll need a basic knowledge of PHP and arrays to install this and make it work with the sample code.</p>
<p>Enjoy the class and if you have any questions, comments, bug reports, feature requests, or just plain praise, please post your thoughts below.</p>
<p>
<h3>Current Release 0.5.0 Beta <small>(<a href="/wp-content/uploads/2011/08/mapclass_distrib1.zip">download</a> - .zip - <i>16k</i> - CC 3.0 Attribution license)</small></h3>
<p><center><A HREF="http://www.phpclasses.org/award/innovation/"><img src="http://www.phpclasses.org/award/innovation/nominee.gif" width="89" height="89" alt="PHP Programming Innovation award nominee" title="PHP Programming Innovation award nominee" border="0" style="clear:both;float:none;"></A><br /><B>September&nbsp;2011<br />
Nominee<br />
<A HREF="http://www.phpclasses.org/vote.html">Vote</A></B></center></p>
]]></content:encoded>
			<wfw:commentRss>http://www.brainhandles.com/techno-thoughts/the-brainhandles-heatmap-php-class/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Programming: PHP, Modern Systems, and GUIDs or UUIDs</title>
		<link>http://www.brainhandles.com/techno-thoughts/web-programming/programming-php-modern-systems-and-guids-or-uuids</link>
		<comments>http://www.brainhandles.com/techno-thoughts/web-programming/programming-php-modern-systems-and-guids-or-uuids#comments</comments>
		<pubDate>Tue, 22 Sep 2009 06:46:33 +0000</pubDate>
		<dc:creator>Greg Bulmash</dc:creator>
				<category><![CDATA[Web Programming]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.brainhandles.com/?p=2310</guid>
		<description><![CDATA[So, I'm working on a project where I want to assign unique IDs to some elements in a list. I did some research on GUIDs (Globally Unique Identifiers) and UUIDs (Universally Unique Identifiers), but the whole thing seemed a bit too overwrought for me. See, my IDs only have to be unique in a list. [...]]]></description>
			<content:encoded><![CDATA[<p>So, I'm working on a project where I want to assign unique IDs to some elements in a list. I did some research on GUIDs (Globally Unique Identifiers) and UUIDs (Universally Unique Identifiers), but the whole thing seemed a bit too overwrought for me.  </p>
<p>See, my IDs only have to be unique in a list.  That list will probably have, at most, 200 members.  I have a lot less worry about collisions (generating and assigning the same ID to two separate items, thus causing confusion). There are a few GUID/UUID generator scripts out there that do all sorts of gymnastics to generate a 32-40 character ID so unique, there's supposedly no chance of it colliding with another ID of that length... ever.</p>
<p>The math bears that out to some extent. A 32-character ID using just A-Z and 0-9 (a.k.a. Base 36) has over 63 quindecillion, or 63 times a trillion times a trillion times a trillion times a trillion different IDs. Put another way, a 70 kilogram (approx 154 pounds) person has approximately 7 octillion atoms in their body, which is more atoms than there are stars in the universe at current estimates. 63.3 quindecillion is enough to give every atom in every person on Earth over a trillion unique identifiers... per atom... and that's counting the fat people too.</p>
<p>Still, there's a part of me that thinks that a 32-character code (36 with dashes) is just too dang long. I should program a function to generate a 6 character Base 36 code, because while that raises chances of collision from 1 in gazillions to one in 2 billion, it saves 30 characters worth of disk space and computational gymnastics.  Since I only need the IDs to be locally unique to one file or one database table, I should program the quick function to generate the code (pick a random number between 1 and 2 billion, then use <code>base_convert(picked_num, 10, 36)</code> to change the random number to a Base 36 code).</p>
<p>But, I do realize that some of that mindset, while good because we should always seek the most efficient way to do things, also gives some chance of collision, requiring I write and use collision check/prevention code elsewhere in the script, so it gets balanced out.  Additionally, that mindset is a bit of an old-timer mindset. I'm old enough to remember being excited when the price of hard drives dropped under $1 per megabyte, letting me get a 250 megabyte drive for $245 back in the 90s. Yesterday I saw a <a href="http://www.costco.com/Browse/Product.aspx?Prodid=11470791">1.5 terabyte external drive at Costco for $139.99</a>. At that cost, 250 megabytes of that drive costs under 2.45 cents. Put simply, I was paying 10,000 times more per megabyte 15 years ago than I'm paying today.</p>
<p>Okay, since we're using an ASCII-safe character set and storing with UTF-8 encoding, it means the 36-character code (32 letters and numbers + 4 dashes) is going to require 30 more characters of storage. To be fair, we'll triple it for overhead.  To use up $1 worth of extra disk space on that 1.5 terabyte drive, I'd need to store over 99 million IDs.  In my project, I'm figuring a seriously heavy user might generate a few thousand over the course of a year.  I don't really have to be sparing to control storage costs.</p>
<p>What about the computational cost, then?  Efficiency is important.  But, then again, how much does processing horsepower cost? Using the gigaflops (billions of floating-point operations per second) measure applied to super computers... Back in 1997, computing power cost approximately $30,000 per gigaflop in a system sporting two 16-processor Beowulf clusters with Pentium Pro microprocessors. Now, a desktop sporting a Core 2 Quad 8200 ($149.99 at Newegg when I last checked) delivers 37.28 gigaflops at a cost of $4.02 per gigaflop.  </p>
<p>I decided to try a few methods for generating unique ID's. I tried a class that generates a 32-character UUID/GUID posted by Marius Karthaus in the comments of the <a href="http://www.php.net/manual/en/function.uniqid.php">uniqid() function documentation</a> on php.net, the uniqid() function which generates a 13-character ID, then I tried picking a random number between one and a large number and converting it to base 36 using 2,000,000,000 and 9,000,000,000,000,000,000 (two billion and 9 quintillion). I topped out at 9 quintillion because when I went up to 90 quintillion, the result for the mt_rand() function was always 1.  I generated 50 sets of 5,000 IDs for each and got the following average execution times per set (running on my local development environment - a MacBook Pro):<br />
<blockquote>
UUID: 0.16870986938477 seconds<br />
Random 2 Billion: 0.021249299049377 seconds<br />
Random 9 Quintillion: 0.024264307022095 seconds<br />
UNIQID: 0.11121699333191 seconds</p></blockquote>
<p>Computationally, if you factor the time to create versus the odds of collision, the UUID costs less than twice uniqid()'s method, but gives you a few gazillion times as many possible IDs (3.7 x 10^29 times as many).  You'll cut processing time by a factor of close to 8 if you go with the one-in-two-billion method, and close to a factor of 6 if you go with the one-in-nine-quintillion method.  Of course, even with the most computationally expensive method, generating more unique IDs than I expect any user to need in a year uses less than 2/10ths of a second.</p>
<p>So, if a REALLY heavy user completes enough tasks that they need 5,000 unique IDs, those IDs (assuming that data and overhead amount to 108 bytes) will use up 1/198th of a penny worth of disk space and 1/18,000th of an hour worth of computing time.</p>
<p>I still feel compelled through years of conditioning to try to squeeze every last bit of efficiency out of my code, but the fact that I spent hours researching this, testing it, and determining the relative efficiencies of the various methods means I probably cost myself more than all the computing and disk space savings combined among everybody who ever uses the script I'm working on.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.brainhandles.com%2Ftechno-thoughts%2Fweb-programming%2Fprogramming-php-modern-systems-and-guids-or-uuids&amp;title=Programming%3A%20PHP%2C%20Modern%20Systems%2C%20and%20GUIDs%20or%20UUIDs" id="wpa2a_2"><img src="http://www.brainhandles.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.brainhandles.com/techno-thoughts/web-programming/programming-php-modern-systems-and-guids-or-uuids/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>More Fun With JavaScript - Nested Evals</title>
		<link>http://www.brainhandles.com/techno-thoughts/more-fun-with-javascript-nested-evals</link>
		<comments>http://www.brainhandles.com/techno-thoughts/more-fun-with-javascript-nested-evals#comments</comments>
		<pubDate>Tue, 11 Aug 2009 23:45:46 +0000</pubDate>
		<dc:creator>Greg Bulmash</dc:creator>
				<category><![CDATA[Techno Thoughts]]></category>
		<category><![CDATA[Web Programming]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://www.brainhandles.com/?p=2249</guid>
		<description><![CDATA[So, the way I learn a new programming skill is I get an idea for a program I need to learn the language (or improve my knowledge of it) to create. Then as I learn the things I need to know, I toy with various ideas and do little experiments just to see what happens [...]]]></description>
			<content:encoded><![CDATA[<p>So, the way I learn a new programming skill is I get an idea for a program I need to learn the language (or improve my knowledge of it) to create. Then as I learn the things I need to know, I toy with various ideas and do little experiments just to see what happens or what's possible.</p>
<p>This time I wanted to know if I could get a string name passed, then use it in some function using the eval() function to get its value. For example<br />
<style>blockquote{background: #DFDFDF;font-family:courier;font-style:normal;font-weight:500;}</style>
<blockquote><p>var steve="blue";<br />
var blue="danny";<br />
alert(eval(steve));</p></blockquote>
<p>Now, if it was just <code>alert(steve)</code>, the result would be an alert window with the message "blue".  But because eval is evaluating the content of "steve" as code... The value of "steve" is "blue" and the value of the variable "blue" is "danny", so <code>alert(eval(steve))</code> generates an alert window with the message "danny".</p>
<p>But the cool thing is that you can nest evals...<br />
<blockquote>&lt;script type="text/javascript"&gt;</p>
<p>var steve="blue";<br />
var blue="danny";</p>
<p>function gotoit(sedley){<br />
      alert(eval(eval(sedley)));<br />
}</p>
<p>&lt;/script&gt;</p>
<p>&lt;a href="javascript:gotoit('steve');"&gt;Run The Dang Script&lt;/a&gt;</p></blockquote>
<p>In this case, the value of sedley is "steve", which evaluates to "blue", which has the value of "danny".</p>
<p><script type="text/javascript">var steve="blue";var blue="danny";function gotoit(sedley){alert(eval(eval(sedley)));}</script></p>
<p><a href="javascript:gotoit('steve');">Try it for yourself.</a></p>
<p>I know, sort of pointless, but it was neat to me and I thought I'd share.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.brainhandles.com%2Ftechno-thoughts%2Fmore-fun-with-javascript-nested-evals&amp;title=More%20Fun%20With%20JavaScript%20-%20Nested%20Evals" id="wpa2a_4"><img src="http://www.brainhandles.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.brainhandles.com/techno-thoughts/more-fun-with-javascript-nested-evals/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Javascript Hack To Replicate PHP/Perl Here or Heredoc</title>
		<link>http://www.brainhandles.com/techno-thoughts/javascript-hack-to-replicate-phpperl-here-or-heredoc</link>
		<comments>http://www.brainhandles.com/techno-thoughts/javascript-hack-to-replicate-phpperl-here-or-heredoc#comments</comments>
		<pubDate>Tue, 11 Aug 2009 09:05:06 +0000</pubDate>
		<dc:creator>Greg Bulmash</dc:creator>
				<category><![CDATA[Techno Thoughts]]></category>
		<category><![CDATA[Web Programming]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://www.brainhandles.com/?p=2235</guid>
		<description><![CDATA[While working on a recent project, I found myself with a need to insert blocks of text via javascript and wishing I could do the heredoc style parsed multiline string. If you're not familiar with it, you might have a bit of code... &#60;?php $fred = $_REQUEST["fredinput"]; $ted = &#60;&#60;&#60;EOM This is a multiline&#60;br&#62; string, [...]]]></description>
			<content:encoded><![CDATA[<p>While working on a recent project, I found myself with a need to insert blocks of text via javascript and wishing I could do the <A href="http://us.php.net/manual/en/language.types.string.php#language.types.string.syntax.heredoc">heredoc</a> style parsed multiline string.  If you're not familiar with it, you might have a bit of code...<br />
<blockquote>
&lt;?php</p>
<p>$fred = $_REQUEST["fredinput"];</p>
<p>$ted = &lt;&lt;&lt;EOM<br />
This is a multiline&lt;br&gt;<br />
string, that outputs&lt;br&gt;<br />
the value of "fredinput" as&lt;br&gt;<br />
$fred.<br />
EOM;</p>
<p>echo $ted;</p>
<p>?&gt;</p></blockquote>
<p>Now, let's say that in whatever form you'd posted to this script, the value of the "fredinput" variable was "Loquacious", the output of that bit of code would be:<br />
<blockquote>
This is a multiline<br />
string, that outputs<br />
the value of "fredinput" as<br />
Loquacious.</p></blockquote>
<p>Now, let's say you had large blocks of HTML you'd want to specify in this way for a javascript application.  It gets a little painful because it all has to be a single line, or at the end of each line, you have to escape the line break, you have to make sure you escape your single or double quotes, and to put in any variables, you have to close your quotes, insert the variable surrounded by pluses, and then reopen the quotes.  It makes that HTML hard to read and easy to screw up if you need to edit it.</p>
<p>Wouldn't it be nice to just type the big old block of text as straight HTML with lots of whitespace for readability, not have to escape anything, and just prefix variable names with dollar signs to have the variable's value appear?</p>
<p>You can, and all you need is this very short function.  It's a bit of a klunky hack because the text is in a hidden div in the HTML document instead of within the script.  But otherwise it works nicely.</p>
<p>Here's a sample using the function.<br />
<style>blockquote{background: #DFDFDF;font-family:courier;font-style:normal;font-weight:500;}</style>
<blockquote><p>
&lt;script type="text/javascript"&gt;<br />
// set variables named andy and handy, which we can use as $andy and $handy in our text</p>
<p>var andy = "Fred Flintstone";<br />
var handy = "Steve Austin";</p>
<p>function hereDoc(divid){<br />
          var obj = window; <i>// gets an object containing all the variables</i><br />
          var str = document.getElementById(divid).innerHTML; <i>// gets the HTML block</i><br />
   for(var i in obj){</p>
<p><i>/* the for loop recurses through all the objects in the page - remember strings are objects in Javascript */</i> </p>
<p>           if((typeof(obj[i])=="string")||(typeof(obj[i])=="number")){</p>
<p><i>/* Type of makes sure it only executes replacement for strings and numbers. The function worked without this test in Firefox and Safari, but threw errors on Opera until it was added. */</i> </p>
<p>           myregex = new RegExp('\\$'+i,"g");</p>
<p><i>/* To replace globally, you need to use a regular expression and use the "g" option, but within the string.replace() method, the regular expression is unquoted, so you can't use a variable in it directly.  So we create it and assign it to a RegExp object that works in the string.replace() method. */</i> </p>
<p>           str = str.replace(myregex, obj[i]);</p>
<p><i>/* we replace instances of the variable name with a dollar sign before it with the variable's value */</i><br />
               }<br />
        }<br />
     return str;</p>
<p><i>/* and when the loop is done, we return the processed text to be used however needed */</i> </p>
<p>     }          </p>
<p>function gotoit(){ </p>
<p><i>/* fill the "steve" div with the processed contents of the "randy" div. */</i> </p>
<p>document.getElementById("steve").innerHTML = hereDoc("randy");<br />
}</p>
<p>&lt;/script&gt;</p>
<p>&lt;a href="javascript:gotoit();"&gt;Run the script&lt;/a&gt;<br />
&lt;div id="randy" style="display:none;"&gt;<br />
The interesting thing about $andy is that he's not nearly as popular with young kids as $handy.&lt;br&gt;&lt;br&gt;</p>
<p>What I really find 'interesting' is that this "multiline" thing works as well as $handy's bionic arm.  &lt;br&gt;&lt;br&gt;<br />
&lt;/div&gt;<br />
&lt;div id="steve"&gt;&lt;/div&gt;</p></blockquote>
<p>Note the unescaped single and double quotes on the last line.  You can do much more complex HTML like a form, but I'm just trying to keep this simple for the example. </p>
<p>In the end, this is more a proof of concept than anything else.  You can do this a bunch of ways, but I like the way it iterates through the javascript variables in the document and processes the text the same way you'd see that handled in a PHP script.  Of course, I haven't added in the handling of array variables, but it could be done.  </p>
<p>There's also the reverse option of using regular expressions to search for single words meeting string naming rules, prefixed with $, then checking to see if there's a variable with that name that's a string or number value and doing a global replace for it.  If you had a whole lot of variables in a highly complex script, it might be faster.</p>
<p>Anyway, I'm rambling.  I've tested it on Firefox, Safari, and Opera on my MacBook Pro running Tiger.  Try it out on your browser if you like...<br />
<script src="http://www.brainhandles.com/wp-content/uploads/2009/08/heredoc.js" type="text/javascript"></script><br />
<a href="javascript:gotoit();">Run the script</a></p>
<div id="randy" style="display:none;">
The interesting thing about $andy is that he's not nearly as popular with young kids as $handy.</p>
<p>What I really find 'interesting' is that this "multiline" thing works as well as $handy's bionic arm. </p>
</div>
<div id="steve"></div>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.brainhandles.com%2Ftechno-thoughts%2Fjavascript-hack-to-replicate-phpperl-here-or-heredoc&amp;title=Javascript%20Hack%20To%20Replicate%20PHP%2FPerl%20Here%20or%20Heredoc" id="wpa2a_6"><img src="http://www.brainhandles.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.brainhandles.com/techno-thoughts/javascript-hack-to-replicate-phpperl-here-or-heredoc/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Creating a &quot;Tweet This&quot; Link</title>
		<link>http://www.brainhandles.com/techno-thoughts/web-programming/creating-a-tweet-this-link</link>
		<comments>http://www.brainhandles.com/techno-thoughts/web-programming/creating-a-tweet-this-link#comments</comments>
		<pubDate>Wed, 24 Jun 2009 09:51:40 +0000</pubDate>
		<dc:creator>Greg Bulmash</dc:creator>
				<category><![CDATA[Online Marketing And SEO]]></category>
		<category><![CDATA[Web Programming]]></category>

		<guid isPermaLink="false">http://www.brainhandles.com/?p=2157</guid>
		<description><![CDATA[Been working on a new project that will go into previews for selected friends and family later this week and go into general release a few days later, once I've had a chance to fix any issues my preview users find. One part of the project was to add "Tweet This" links to certain items [...]]]></description>
			<content:encoded><![CDATA[<p>Been working on a new project that will go into previews for selected friends and family later this week and go into general release a few days later, once I've had a chance to fix any issues my preview users find.</p>
<p>One part of the project was to add "Tweet This" links to certain items on the site, where clicking on the link would send the user to Twitter and fill in the suggested text of the tweet for them.</p>
<p>It's actually a lot simpler than you think.  The format is: <b><code>http://twitter.com/?status=[URL encoded tweet text]</code></b>.  </p>
<p>Now many of you are asking how you "URL encode" the tweet text.  Well, if you're using PHP, you use <code>urlencode('text');</code> where "text" is the text of your tweet.  If you want to do it in JavaScript, the PHP.js library has a <a href="http://phpjs.org/functions/urlencode:573">javascript equivalent for PHP's urlencode</a>.</p>
<p>But here's a little trick I didn't know about until I made this mistake.  Make sure your link goes to twitter.com, not www.twitter.com.  If it goes to www.twitter.com, the text doesn't get properly decoded.  So, trying to tweet <i>Creating a "Tweet This" Link - http://www.brainhandles.com</i> would look like <i>Creating a %22Tweet This%22 link - http%3A%2F%2Fwww.brainhandles.com</i>, and nobody wants that.</p>
<p><center><script type="text/javascript"><!--
google_ad_client = "pub-6701123236803391";
google_ad_width = 336;
google_ad_height = 280;
google_ad_format = "336x280_as";
google_ad_type = "text_image";
//2006-11-23: BrainHandles336
google_ad_channel = "8118507880";
google_color_border = "FFFFFF";
google_color_bg = "FFFFFF";
google_color_link = "440084";
google_color_text = "000000";
google_color_url = "0000DD";
//--></script>
<script type="text/javascript"
  src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></center></p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.brainhandles.com%2Ftechno-thoughts%2Fweb-programming%2Fcreating-a-tweet-this-link&amp;title=Creating%20a%20%22Tweet%20This%22%20Link" id="wpa2a_8"><img src="http://www.brainhandles.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.brainhandles.com/techno-thoughts/web-programming/creating-a-tweet-this-link/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Call to undefined function json_decode() on Mac</title>
		<link>http://www.brainhandles.com/techno-thoughts/call-to-undefined-function-json_decode-on-mac</link>
		<comments>http://www.brainhandles.com/techno-thoughts/call-to-undefined-function-json_decode-on-mac#comments</comments>
		<pubDate>Sun, 08 Mar 2009 07:27:18 +0000</pubDate>
		<dc:creator>Greg Bulmash</dc:creator>
				<category><![CDATA[Techno Thoughts]]></category>
		<category><![CDATA[Web Programming]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.brainhandles.com/?p=1497</guid>
		<description><![CDATA[So, I had this problem. I have Marc Liyanage's PHP 5.2.4 package installed on my MacBook Pro and use it for local dev tasks. It's supposed to have JSON installed, phpinfo says it has JSON installed, but when I ran a bit of code that used the json_decode() function, I got the "call to undefined [...]]]></description>
			<content:encoded><![CDATA[<p>So, I had this problem.  I have Marc Liyanage's PHP 5.2.4 package installed on my MacBook Pro and use it for local dev tasks.  It's supposed to have JSON installed, phpinfo says it has JSON installed, but when I ran a bit of code that used the json_decode() function, I got the "call to undefined function" error.</p>
<p><span id="more-1497"></span><!--adsense--></p>
<p>When I tried to find something online where someone had the same problem, a Google search requiring the error message as a phrase and the word "mac" turned up ONE result, and that was a guy mentioning the error in blog comments.  </p>
<p>So, I never found out how to fix my install, but a quick kludge was found <a href="http://forums.mawhorter.net/viewtopic.php?id=8">here</a> in the second post.  I put the JSON.php file from the downloaded .gz archive in the same folder as my PHP script, added the suggested code to JSON.php, and added "import('JSON.php')" to my script.  Voila.</p>
<p>Now, the rare person with my issue will be able to search for the error message and "mac" and find, if not the answer, a workable kludge.</p>
<p><!--adsense--></p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.brainhandles.com%2Ftechno-thoughts%2Fcall-to-undefined-function-json_decode-on-mac&amp;title=Call%20to%20undefined%20function%20json_decode%28%29%20on%20Mac" id="wpa2a_10"><img src="http://www.brainhandles.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.brainhandles.com/techno-thoughts/call-to-undefined-function-json_decode-on-mac/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Simple Interactive Comic Engine</title>
		<link>http://www.brainhandles.com/techno-thoughts/simple-interactive-comic-engine</link>
		<comments>http://www.brainhandles.com/techno-thoughts/simple-interactive-comic-engine#comments</comments>
		<pubDate>Tue, 24 Feb 2009 13:26:15 +0000</pubDate>
		<dc:creator>Greg Bulmash</dc:creator>
				<category><![CDATA[Art]]></category>
		<category><![CDATA[Techno Thoughts]]></category>
		<category><![CDATA[Web Programming]]></category>

		<guid isPermaLink="false">http://www.brainhandles.com/?p=1450</guid>
		<description><![CDATA[A few days back, more than one web-comic artist I follow linked to an interactive comic as an example of a cool use of technology to enhance cartooning. The problem for me was that it was in Flash and a little complicated. I wanted to build a tool that any cartoonist could use to create [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.brainhandles.com/csdemo/"><img src="http://www.brainhandles.com/wp-content/uploads/2009/02/cs-demo.gif" alt="A frame from my ComicScript proof of concept" title="A frame from my ComicScript proof of concept" width="500" height="179" class="alignnone size-full wp-image-1451" /></a></p>
<p>A few days back, more than one web-comic artist I follow linked to <a href="http://balak01.deviantart.com/art/about-DIGITAL-COMICS-111966969">an interactive comic</a> as an example of a cool use of technology to enhance cartooning.  The problem for me was that it was in Flash and a little complicated.  I wanted to build a tool that any cartoonist could use to create something like that.</p>
<p>So I came up with a utility I call <a href="/csdemo/">ComicScript</a>.  I'm still just at the proof of concept stage, but basically when it's done, any comic artist who wants to build a grid of panels will just fill in a few details about his/her grid and get the JavaScript code and files needed to implement the grid on their site or blog.</p>
<p>Check out my test of an 8 x 2 (8 wide by 2 tall) <a href="/csdemo/">grid comic</a> (I would have posted it here, but I realized my proof of concept was too wide.  Love to hear what you think.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.brainhandles.com%2Ftechno-thoughts%2Fsimple-interactive-comic-engine&amp;title=Simple%20Interactive%20Comic%20Engine" id="wpa2a_12"><img src="http://www.brainhandles.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.brainhandles.com/techno-thoughts/simple-interactive-comic-engine/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Big Oops - Deleted The Database - It&#039;s Back Now - Sort of</title>
		<link>http://www.brainhandles.com/techno-thoughts/web-programming/big-oops-deleted-the-database-its-back-now-sort-of</link>
		<comments>http://www.brainhandles.com/techno-thoughts/web-programming/big-oops-deleted-the-database-its-back-now-sort-of#comments</comments>
		<pubDate>Sun, 11 Jan 2009 06:59:28 +0000</pubDate>
		<dc:creator>Greg Bulmash</dc:creator>
				<category><![CDATA[Hell on $5]]></category>
		<category><![CDATA[Web Programming]]></category>

		<guid isPermaLink="false">http://www.brainhandles.com/?p=1022</guid>
		<description><![CDATA[So, I was futzing around with the site today and wanted to try out a forum plug-in and a poll plug-in. Forgot to back up beforehand. Didn't like them, removed them. Then this evening went in to do my manual biweekly backup (I created the database outside of the cPanel structure long ago, so cPanel [...]]]></description>
			<content:encoded><![CDATA[<p>So, I was futzing around with the site today and wanted to try out a forum plug-in and a poll plug-in.  Forgot to back up beforehand.</p>
<p>Didn't like them, removed them.  Then this evening went in to do my manual biweekly backup (I created the database outside of the cPanel structure long ago, so cPanel doesn't include it in the nightly backup), saw some tables related to the poll plugin, marked them, then hit the "drop" command.</p>
<p>Only I hit the one to drop the whole database, not just the marked tables.  Clicked yes to the "are you sure" warning, because I thought it was just dropping those tables, then found out I'd dropped the whole database.</p>
<p>MySQL apparently doesn't have a "holy crap" button to immediately undo disastrous mistakes, and in all this time, really doesn't have a method to undo a database drop.  You might possibly reconstruct it, but in general you're stuck restoring the database from backups.</p>
<p>Luckily I back up regularly, because I'm relatively paranoid.  I lost a few edits to later chapters in the novels.  More saddening is that I lost a number of comments posted in the last few days by friends and new readers including a discussion on the use of racially charged language in the early chapters.</p>
<p>So, for those of you who manage your own server... back up, back up, back up, and pay attention to those warning messages.  We've gotten so used to them we mindlessly click.  But if I'd read the warning message, I'd have known that I was about to kill much more data than I thought and could have stopped before it was too late.</p>
<p>And to those of you who posted comments in the last few days... SOOOORRRRYYYY!  Won't happen again.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.brainhandles.com%2Ftechno-thoughts%2Fweb-programming%2Fbig-oops-deleted-the-database-its-back-now-sort-of&amp;title=Big%20Oops%20-%20Deleted%20The%20Database%20-%20It%27s%20Back%20Now%20-%20Sort%20of" id="wpa2a_14"><img src="http://www.brainhandles.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.brainhandles.com/techno-thoughts/web-programming/big-oops-deleted-the-database-its-back-now-sort-of/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Mobile Browser Detection Updated</title>
		<link>http://www.brainhandles.com/techno-thoughts/mobile-browser-detection-updated</link>
		<comments>http://www.brainhandles.com/techno-thoughts/mobile-browser-detection-updated#comments</comments>
		<pubDate>Wed, 17 Dec 2008 01:11:12 +0000</pubDate>
		<dc:creator>Greg Bulmash</dc:creator>
				<category><![CDATA[Online Marketing And SEO]]></category>
		<category><![CDATA[Techno Thoughts]]></category>
		<category><![CDATA[Web Programming]]></category>

		<guid isPermaLink="false">http://www.brainhandles.com/?p=757</guid>
		<description><![CDATA[If you use the mobile browser detection script (this is a techy script for web developers who want to know if a page's visitor is using a phone/PDA browser or a "real" one), I've recently posted an update to it to accomodate the combo of IE8 on Vista and some software from Creative with an [...]]]></description>
			<content:encoded><![CDATA[<p>If you use the <a href="http://www.brainhandles.com/2007/10/15/detecting-mobile-browsers/">mobile browser detection script</a> (this is a techy script for web developers who want to know if a page's visitor is using a phone/PDA browser or a "real" one), I've recently posted an update to it to accomodate the combo of IE8 on Vista and some software from Creative with an auto update feature.  One of the substrings it looks for in the "user agent" string is "pda".  You'll find that in the word "u<b>pda</b>te".  I've added an exception for that.  I may need to visit that script in the new year, test it against the latest WURFL, and do some overhauling.</p>
<p><!--adsense--></p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.brainhandles.com%2Ftechno-thoughts%2Fmobile-browser-detection-updated&amp;title=Mobile%20Browser%20Detection%20Updated" id="wpa2a_16"><img src="http://www.brainhandles.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.brainhandles.com/techno-thoughts/mobile-browser-detection-updated/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Yahoo Does The Time Warp</title>
		<link>http://www.brainhandles.com/techno-thoughts/yahoo-does-the-time-warp</link>
		<comments>http://www.brainhandles.com/techno-thoughts/yahoo-does-the-time-warp#comments</comments>
		<pubDate>Fri, 22 Feb 2008 04:30:10 +0000</pubDate>
		<dc:creator>Greg Bulmash</dc:creator>
				<category><![CDATA[Techno Thoughts]]></category>
		<category><![CDATA[Web Programming]]></category>

		<guid isPermaLink="false">http://www.brainhandles.com/2008/02/21/yahoo-does-the-time-warp/</guid>
		<description><![CDATA[This evening, I went to my "My Yahoo" page, a customizeable personal page you can populate with news wire feeds, RSS feeds, and other Yahoo content. And it had gone back in time. Note how all all the stories are "one week ago". Normally this feed is somewhere between a few minutes to "one day" [...]]]></description>
			<content:encoded><![CDATA[<p>This evening, I went to my "My Yahoo" page, a customizeable personal page you can populate with news wire feeds, RSS feeds, and other Yahoo content.  And it had gone back in time.</p>
<p><center><img src='http://www.brainhandles.com/wp-content/uploads/2008/02/yahoo-full.jpg' alt='yahoo-full.jpg' /></p>
<p><img src='http://www.brainhandles.com/wp-content/uploads/2008/02/yahoo-detail.jpg' alt='yahoo-detail.jpg' /></center></p>
<p>Note how all all the stories are "one week ago".  Normally this feed is somewhere between a few minutes to "one day" ago.  And the "one week ago" is inaccurate since most of the stories are dated between February 9th to February 11th.  The same went for the comics farther down the page (Feb 11th).  The segments that related to offsite RSS feeds were current, but any feeds created/licensed by Yahoo were reaching WAAAAY back.</p>
<p>Wonder how long it will take to fix.  Oh, it's fixed.  Well, at least it lasted long enough to grab a picture.</p>
<p><!--adsense--></p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.brainhandles.com%2Ftechno-thoughts%2Fyahoo-does-the-time-warp&amp;title=Yahoo%20Does%20The%20Time%20Warp" id="wpa2a_18"><img src="http://www.brainhandles.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.brainhandles.com/techno-thoughts/yahoo-does-the-time-warp/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>A PHP Weakness: The Slowness of Echo</title>
		<link>http://www.brainhandles.com/techno-thoughts/a-php-weakness-the-slowness-of-echo</link>
		<comments>http://www.brainhandles.com/techno-thoughts/a-php-weakness-the-slowness-of-echo#comments</comments>
		<pubDate>Sun, 20 Jan 2008 21:43:55 +0000</pubDate>
		<dc:creator>Greg Bulmash</dc:creator>
				<category><![CDATA[Techno Thoughts]]></category>
		<category><![CDATA[Web Programming]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.brainhandles.com/2008/01/20/a-php-weakness-the-slowness-of-echo/</guid>
		<description><![CDATA[So, I was working on a project that generates a form based on a selection of items from a database, and the form could get pretty long. For performance testing I timed the execution of the script and found some very odd results. If the number of items on the list was 16 or thereabouts, [...]]]></description>
			<content:encoded><![CDATA[<p>So, I was working on a project that generates a form based on a selection of items from a database, and the form could get pretty long.  For performance testing I timed the execution of the script and found some very odd results.  If the number of items on the list was 16 or thereabouts, the execution was about 5-7 one-thousands of a second.  If the number of the items on the list was 50 (the maximum displayed on a page), the execution time was around 100 times longer.</p>
<p><!--adsense--></p>
<p>I was stumped, how did increasing the number of items in the list by a factor of around 3 increase the execution time by a factor of 100?</p>
<p>I initially thought it was the database query.  If the list was 16 items, that was the maximum number returned for the query.  If the list was 50 items, it might have been the first 50 out of 300, which required extra sorting and organizing.  But the database queries were timing out at close to the same speed.</p>
<p>I checked the processing of the data.  Perhaps there was some bottleneck in my code that I could isolate.  But as I broke the script down into smaller and smaller pieces, I found that all the parts that created the dynamically generated page were working fine up until I echoed the string that sent the compiled page to the user...</p>
<p><code>echo $page;</code></p>
<p>It was that line that took a couple of thousandths of a second when there were 16 questions, but took two or three hundred times longer when you tripled the length of <code>$page</code>.  In fact, the tipping point was really between 19 and 20 questions.  At 19 questions, it was executing in around 0.0085 seconds.  At 20 questions, the execution time jumped to 0.27 seconds.  Adding just one question caused the script to take 30 times longer to execute.</p>
<p>I Googled the topic and found that this is a <a href="http://us2.php.net/echo">well-known weakness of PHP</a>.  And, as a matter of fact, output in general is a weakness of PHP, because even knowing about this, people have long argued about whether it's faster to use "print" or "echo".</p>
<p>There were a number of suggestions on how to compensate, such as <code>ob_start()</code> and <code>ob_flush</code> to use output buffering with more fine grained control, but that wasn't doing the trick for me.  Another suggested <a href="http://wonko.com/article/299">breaking the output string into chunks</a> and outputting them individually in sequence. That also didn't work... at least not with his value of 8192 (8 kilobytes) as a chunk size.  So I tried larger chunks (48 kilobytes, since that seemed to be the upper limit before slowing occurred) and smaller chunks (256 bytes, getting real small), but those weren't working.  I was about ready to give up when I decided on one more try.  I tried 2048 (2 kilobytes) and things finally sped up, and it seemed the best speed came from a 1-kilobyte chunk size.</p>
<p>So, if you find a PHP script is running really slow, the culprit might be something as simple as "echo $string" and the only way to fix it is to performance tune the output of that string.  Amazing, huh?</p>
<p><!--adsense--></p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.brainhandles.com%2Ftechno-thoughts%2Fa-php-weakness-the-slowness-of-echo&amp;title=A%20PHP%20Weakness%3A%20The%20Slowness%20of%20Echo" id="wpa2a_20"><img src="http://www.brainhandles.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.brainhandles.com/techno-thoughts/a-php-weakness-the-slowness-of-echo/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Regular Expressions: A Bunch of Little Ones or One Big One?</title>
		<link>http://www.brainhandles.com/techno-thoughts/regular-expressions-a-bunch-of-little-ones-or-one-big-one</link>
		<comments>http://www.brainhandles.com/techno-thoughts/regular-expressions-a-bunch-of-little-ones-or-one-big-one#comments</comments>
		<pubDate>Mon, 14 Jan 2008 08:55:04 +0000</pubDate>
		<dc:creator>Greg Bulmash</dc:creator>
				<category><![CDATA[Techno Thoughts]]></category>
		<category><![CDATA[Web Programming]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[regular expressions]]></category>

		<guid isPermaLink="false">http://www.brainhandles.com/2008/01/14/regular-expressions-a-bunch-of-little-ones-or-one-big-one/</guid>
		<description><![CDATA[This evening I got a comment on my post about how to detect when cell phones access your web site. It was a question about the way I went about the PHP code for matching a bunch of small text snippets against the User Agent string. Basically, I put all the text snippets in a [...]]]></description>
			<content:encoded><![CDATA[<p>This evening I got a comment on my post about <a href="http://www.brainhandles.com/2007/10/15/detecting-mobile-browsers/">how to detect when cell phones access your web site</a>.  It was a question about the way I went about the PHP code for matching a bunch of small text snippets against the User Agent string.</p>
<p><!--adsense--></p>
<p>Basically, I put all the text snippets in a large array and then used a foreach loop to match each one individually against the User Agent string.  A visitor to the page asked why I hadn't done a very large regular expression, essentially including all those snippets with "or" symbols between them.  So instead of "match 1, match 2, match 3," I'd get "match 1 or 2 or 3".  She asked: "Is this more efficient processing, or more organized for you, or avoids some possible error getting thrown?"</p>
<p>Well, the initial answer was: "I just didn't think of doing a giant regex.  I like arrays and my mind went in that direction."</p>
<p>But that only answers why I did it, not whether it's better.  And while this is such a small piece of code that you can execute it 10,000 times in under 1.7 seconds, so it's not going to increase your server load significantly, I realized that on a very high traffic web site, cutting execution time even on such a small piece of code could make a difference.  So I tested it.</p>
<p>I ran both methods (the foreach and the array as a giant regex) against a string of 190-195 characters in 10,000 iteration batches, and moved the bit of matching text around the string.  </p>
<p>I got approximately the same execution time for the foreach method no matter where the matching text was in the string.  But with the giant regex, the execution times varied by huge amounts.  The farther the matching text was from the beginning of the string, the slower the giant regex worked. When the matching text was in the first 10 characters, the giant regex was 6-7 times faster than the foreach method.  If it was around the 30th character, around 4 times faster.  </p>
<p>But when the matching text was somewhere around the 150th character, the giant regex took 50-60% longer than the foreach method.  When there was no match whatsoever, the giant regex took over twice as long.</p>
<p>I then tried increasing the length of the string (with no matches in it).  The performance disparity grew deeper and deeper.  At 760 characters, the giant regex was taking around 4.25 times longer than the foreach method.  At 1520 characters (around 250 words), the giant regex had slipped to 5.4 times longer than the foreach method.  Yet if there was a match in the first 10 characters of the 1520-character string, the giant regex took no longer than if they were in the first ten characters of a 190-character string.</p>
<p>Now because User Agent strings generally aren't too long and you don't have to go too deep to get a match, in this specific case, using the giant regex would <i>probably</i> be more computationally efficient.  And if you were running this snippet millions of times a day, you could see tangible gains from optimizing it.  But as a rule of thumb, the foreach method is going to be the better general purpose choice.</p>
<p>So, Jane, I hope that answered your question.</p>
<p><!--adsense--></p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.brainhandles.com%2Ftechno-thoughts%2Fregular-expressions-a-bunch-of-little-ones-or-one-big-one&amp;title=Regular%20Expressions%3A%20A%20Bunch%20of%20Little%20Ones%20or%20One%20Big%20One%3F" id="wpa2a_22"><img src="http://www.brainhandles.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.brainhandles.com/techno-thoughts/regular-expressions-a-bunch-of-little-ones-or-one-big-one/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>PHP And The Magic of preg_replace</title>
		<link>http://www.brainhandles.com/techno-thoughts/php-and-the-magic-of-preg_replace</link>
		<comments>http://www.brainhandles.com/techno-thoughts/php-and-the-magic-of-preg_replace#comments</comments>
		<pubDate>Fri, 14 Dec 2007 20:44:04 +0000</pubDate>
		<dc:creator>Greg Bulmash</dc:creator>
				<category><![CDATA[Techno Thoughts]]></category>
		<category><![CDATA[Web Programming]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[regular expressions]]></category>

		<guid isPermaLink="false">http://www.brainhandles.com/2007/12/14/php-and-the-magic-of-preg_replace/</guid>
		<description><![CDATA[Replacing a short bit of text in PHP is easy. You just use str_replace, as in $bobo = str_replace("foo","bar",$bobo). That will replace all instances of "foo" with "bar" in the string $bobo. But, on a recent contract, I had a client's site where it only worked properly in Microsoft Internet Explorer and part of my [...]]]></description>
			<content:encoded><![CDATA[<p>Replacing a short bit of text in PHP is easy.  You just use <code>str_replace</code>, as in <code>$bobo = str_replace("foo","bar",$bobo)</code>.  That will replace all instances of "foo" with "bar" in the string $bobo.</p>
<p><!--adsense--></p>
<p>But, on a recent contract, I had a client's site where it only worked properly in Microsoft Internet Explorer and part of my task was to get it to work similarly in all browsers.  One of the things they had done was use <code>ALT</code> tags, so that when you rolled your mouse over a graphic, the alt text would pop up as a tool tip.  The problem is that this is a non-standard behavior.  Only Microsoft Internet Explorer pops up alt tags.  So how to get the alt text to pop up in all browsers?  Javascript, of course.</p>
<p>I'm not going to go into the Javascript.  There are many different ways to do a pop-up tooltip.  The trick, though, was to get all those alt texts fed to the tooltip script.  Now, there may have been a way in the DOM to get the element's alt text and feed it to the script, but I wasn't sure and didn't have a whole lot of time to hunt it down.  Instead I wrote up a quickie PHP script to handle it.  This is not a CGI, but a script I ran from the command line.  And you don't need to be running from the Linux or Mac command line.  You can install PHP on Windows XP or Vista and run it from the DOS command line.</p>
<p>The first part of the program recursed the directory with all of the HTML files, and each time it found an HTML file, it fed it to a function in the script that read it, altered it, and saved it.  I'll write a post on how to do that soon.  For now, I'm just going to get into the alteration.</p>
<p>Let's assume I had a line of HTML like this...</p>
<p><code>&lt;img src="fred.jpg" alt="This is a picture of Republican presidential candidate, Fred Thompson" height=300 width=190 border=0&gt;</code></p>
<p>As I read through the file, line by line (each line being <code>$line</code>), I applied the following bit of code...</p>
<p><code>if(preg_match("/alt=\"[^\"]+\"/i",$line){<br />
&nbsp;&nbsp;&nbsp;$newline = preg_replace("/alt=\"([^\"]+)\"/i","alt=\"\\1\" onMouseOver='toolTip(\"\\1\")'",$line);<br />
} else {<br />
&nbsp;&nbsp;&nbsp;$newline = $line;<br />
}<br />
</code></p>
<p>That will turn...</p>
<p><code>&lt;img src="fred.jpg" alt="This is a picture of Republican presidential candidate, Fred Thompson" height=300 width=190 border=0&gt;</code></p>
<p>... into ...</p>
<p><code>&lt;img src="fred.jpg" alt="This is a picture of Republican presidential candidate, Fred Thompson" onMouseOver='toolTip("This is a picture of Republican presidential candidate, Fred Thompson")' height=300 width=190 border=0&gt;</code></p>
<p>Now, how did that work?  What <code>preg_replace</code> does is store all the parts of your regular expression that are within parentheses in a series of numbered strings.  So <code>alt=\"([^\"]+)\"</code> set everything inside the quotes after <code>alt=</code> as a string which could be re-used.  So we replaced <code>alt=\"([^\"]+)\"</code> with itself (<code>alt=\"\\1\"</code>) plus a call to the JavaScript tooltip function using the same text as in the <code>ALT</code> tag (<code>onMouseOver='toolTip(\"\\1\")'</code>).</p>
<p>You could also do parentheses within parentheses, capturing a larger piece of text and then capturing a smaller subset of that piece of text.  The system counts the parentheses from left to right.  For simplification, I'll demonstrate this with a sentence and how the pieces would break out.</p>
<p><code>Fred (Thompson is a (Republican candidate for (President)) of the) United (States)</code></p>
<p>That would break out as...<br />
1: Thompson is a Republican candidate for President of the<br />
2: Republican candidate for President<br />
3: President<br />
4: States</p>
<p>And that's how that works.  I'll do a post soon on how to go through a directory and use it on all files.</p>
<p><!--adsense--></p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.brainhandles.com%2Ftechno-thoughts%2Fphp-and-the-magic-of-preg_replace&amp;title=PHP%20And%20The%20Magic%20of%20preg_replace" id="wpa2a_24"><img src="http://www.brainhandles.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.brainhandles.com/techno-thoughts/php-and-the-magic-of-preg_replace/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Validating User Input: Allowing Limited HTML</title>
		<link>http://www.brainhandles.com/techno-thoughts/form-validation-php-html</link>
		<comments>http://www.brainhandles.com/techno-thoughts/form-validation-php-html#comments</comments>
		<pubDate>Fri, 07 Dec 2007 00:45:39 +0000</pubDate>
		<dc:creator>Greg Bulmash</dc:creator>
				<category><![CDATA[Techno Thoughts]]></category>
		<category><![CDATA[Web Programming]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[regular expressions]]></category>

		<guid isPermaLink="false">http://www.brainhandles.com/2007/12/06/form-validation-php-html/</guid>
		<description><![CDATA[Validation is the art of checking and modifying input from users so that it's all of what your web site needs and none of what it doesn't want. Validation can be as complex as anti-hacking and anti-spam measures or as simple as making sure someone's not putting their phone number in the box meant for [...]]]></description>
			<content:encoded><![CDATA[<p>Validation is the art of checking and modifying input from users so that it's all of what your web site needs and none of what it doesn't want.  Validation can be as complex as anti-hacking and anti-spam measures or as simple as making sure someone's not putting their phone number in the box meant for their birthday.</p>
<p><!--adsense--></p>
<p>The recent <a href="http://www.brainhandles.com/2007/11/12/how-the-myspace-hack-worked/">MySpace hack</a>, where band pages were hacked to cover them up with an invisible link that sent you to a malware infection site, showed that it can be dangerous to let users put their HTML in your pages.  To allow users to customize their pages with everything from images to new backgrounds, MySpace allowed some pretty complex user-generated HTML.  Hackers took advantage of that to use some CSS tricks to create those page overlays.</p>
<p>But let's say you're building a site where you want your users to be able to have some formatting control over content they submit.  How do you allow some HTML but not other HTML?  There are three ways to do this... exclusion, inclusion, and substitution.</p>
<p><b style="font-size:16pt">Validating Through Exclusion</b></p>
<p>Validating through exclusion may seem simple at first. You just look for the tags you don't want and kill them. You can write rules that eliminate &lt;SCRIPT&gt; tags, "onClick" and "onMouseOver", etc.  But you'll find that this list grows and grows.  It's a cat and mouse game as hackers try to discover exploits you haven't thought to guard against yet.</p>
<p>Exclusion is nice in that it allows you to allow your users a much broader range of options.  They can do everything that isn't explicitly prohibited.  But if your list of exclusions isn't spot on, you'll be playing catch-up.</p>
<p><b style="font-size:16pt">Validating Through Inclusion</b></p>
<p>An inclusion style of validation comes at the problem from the opposite direction.  Instead of trying to catch the stuff you know to be bad, you allow the stuff you believe to be good.  It's a sort of HTML guest list; the tags on the list get into the party, but the tags on the list don't.  You can even enforce a dress code.</p>
<p>To do this, you run a global search of the input to find all the HTML tags in it, then compare each one against a set of rules.  If it matches one of the rules, it's good and gets through.  If not, then it's bad and you can handle it by deleting it, showing the user an error message, banning the user from your site forever, whatever you want.</p>
<p>For example, let's say you're going to allow them to use a FONT tag and they can specify three characteristics: size, color, and the font face.  Here's a regular expression you can use that will check to see if a tag is a conforming FONT tag.</p>
<div style="font-family:courier,courier-new,courier new;font-size:12px;margin:10px;">/&lt;\/?font(( face=\"[^\"&gt;]*\")?|( size=\"\d\d?\")?|( color=\"[^\"&gt;]*\")?)* *?\/?&gt;/i</div>
<p>Now we'll break it down...</p>
<p><span style="font-family:courier,courier-new,courier new;font-size:12px;font-weight:bold;">/&lt;\/?</span>: The first forward slash opens the regular expression like a &lt; opens an HTML tag. So the expression starts by looking for the opening &lt;.  The backslash (\) tells the interpreter not to see the forward slash (/) as the end of the regular expression, but as just a normal forward slash.  Then the question mark after it means it can occur zero or one times, meaning, this first bit will match  "&lt;" or "&lt;/".</p>
<p><span style="font-family:courier,courier-new,courier new;font-size:12px;font-weight:bold;">font</span>: The simplest part, following the "&lt;" or "&lt;/", there must be "font".</p>
<p><span style="font-family:courier,courier-new,courier new;font-size:12px;font-weight:bold;">(( face=\"[^\">]*\")?|( size=\"\d\d?\")?|( color=\"[^\">]*\")?)*</span>: This is the part that looks for the font tag modifiers.  We'll break it down from the inside out.  Inside the parentheses, we have three sub-expressions in parentheses, each followed by a question mark. </p>
<p><span style="font-family:courier,courier-new,courier new;font-size:12px;font-weight:bold;">( face=\"[^\">]*\")?|</span>: This looks for a space, the word "face" followed by an equals sign, followed by a quotation mark, followed by zero or more characters that arent a quotation mark or a &gt;, followed by another quotation mark. The question mark outside those parentheses says it should occur zero or one times.  That's followed by a pipe symbol(|) which means "or".</p>
<p><b>( size=\"\d\d?\")?|</b>: This is a more specific check.  Since you only want a number in there, we have "\d\d?"  The "\d" stands for any digit from 0 to 9, so "/d/d?" means the pattern requires one digit from 0-9 followed by zero or one more digits, allowing any value from 0-99.  If you wanted the value to just be 0-9 (which is actually fairly reasonable for font size values), you'd just take out the "\d?".  Like the pattern before it, it's followed by a question mark, meaning it should occur zero or one times, and a pipe (|) which means "or".</p>
<p><span style="font-family:courier,courier-new,courier new;font-size:12px;font-weight:bold;">( color=\"[^\">]*\")?</span>: This final pattern looks for a color value which can be anything that doesn't contain a quotation mark or a &gt; and occurs zero or one times.</p>
<p><span style="font-family:courier,courier-new,courier new;font-size:12px;font-weight:bold;">(...)*</span>: All of that is enclosed in a set of parentheses followed by a star.  The parentheses makes them into a set, basically "(1 or 2 or 3)" and the star means "zero or more times".  So the whole pattern is any number of instances of those three tags any number of times, but only those three tags.  So you could specify the font face twice or not at all, but you could only specify the face, the color, or the size.</p>
<p><span style="font-family:courier,courier-new,courier new;font-size:12px;font-weight:bold;">&nbsp;*?\/?&gt;/i</span>:  The space-star-question combo is zero or more spaces occurring zero or one times, then the possibility of a closing forward slash within the tag for someone who is XHMTL crazy, the closing &gt; and then the forward slash to close the pattern.  Then it's followed by an "i" which is a modifier that tells it the matching should be case insensitive.  Without that, a tag that started with &lt;FONT instead of &lt;font would get tossed as a non-match.</p>
<p>Inclusion works very well if you know precisely what you want to allow, can write good patterns for matching it, and can communicate what's allowed to your users.  It's also good if you're using a JavaScript-based WYSIWYG text editor like <A href="http://tinymce.moxiecode.com/">Tiny MCE</a> that lets your users format their text like they were working in a word processor.  Generally, across most browsers (except Safari), you'll be able to get consistent, <i>predictable</i> HTML submitted to the form from WYSIWYG editors, making it possible to develop an inclusion list because you know exactly which tags the editor will return. </p>
<p>The advantage of using an inclusion validation method combined with a WYSIWYG editor is that you don't have to tell your users what's acceptable HTML and what isn't.  They're one step removed from the HTML, and as long as the editor's controls are pretty intuitive or self-explanatory, your users have little or no learning curve for formatting their text in guestbooks, blog comments, or bulletin boards, but you have the ability to lock down that formatting with fairly solid precision.</p>
<p><b style="font-size:16pt">Validating Through Substitution</b></p>
<p>Validating through substitiution is a form of inclusion, but it exerts even tighter control.  Instead of using HTML, users are required to use a different form of mark-up which a browser would never recognize.  Then, at some point, your scripts parse the mark-up into HTML, so the final product is formatted the way the user wanted.</p>
<p>An example of this is <a href="http://en.wikipedia.org/wiki/Bbcode">BBCode</a>, which is used by a number of bulletin board and forum systems.  Instead of &lt;b&gt; to start bolding text, you use [b].  Somewhere in the processing engine (usually during the code that retrieves your post from the database and displays it to a visitor) a &lt;b&gt; is substituted for the [b] you used.</p>
<p>The problem with a substitution method is that it requires your users to learn a new form of mark-up and is a lot harder to get working with a WYSIWYG editor, so it requires users who are a bit more savvy and either know the substitution's mark-up or are willing to spend the time to learn.</p>
<p>On the other hand, substitution can be done on a smaller scale, such as simply substituting smiley-face graphics for emoticons... <img src='http://www.brainhandles.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p><b style="font-size:16pt">Summing It All Up</b></p>
<p>Basically, the types of validation can be summed up like this...</p>
<p>Exclusion: Toss everything I know to be bad and let everything else through.<br />
Inclusion: Allow everything I know to be good through and toss everything else.<br />
Substitution: Look for special non-functional codes and make them functional, but toss all other codes.</p>
<p>What you choose should be determined by how much freedom you want to offer your users, how much of a learning curve you want them to go through, and how much time you want to spend maintaining your validation methods.</p>
<p>Best of luck!</p>
<p><!--adsense--></p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.brainhandles.com%2Ftechno-thoughts%2Fform-validation-php-html&amp;title=Validating%20User%20Input%3A%20Allowing%20Limited%20HTML" id="wpa2a_26"><img src="http://www.brainhandles.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.brainhandles.com/techno-thoughts/form-validation-php-html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Detecting Mobile Browsers Part 2</title>
		<link>http://www.brainhandles.com/techno-thoughts/detecting-mobile-browsers-part-2</link>
		<comments>http://www.brainhandles.com/techno-thoughts/detecting-mobile-browsers-part-2#comments</comments>
		<pubDate>Thu, 06 Dec 2007 04:01:36 +0000</pubDate>
		<dc:creator>Greg Bulmash</dc:creator>
				<category><![CDATA[Techno Thoughts]]></category>
		<category><![CDATA[Web Programming]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.brainhandles.com/2007/12/05/detecting-mobile-browsers-part-2/</guid>
		<description><![CDATA[While a lot of people have written in with kudos on my PHP code for detecting mobile browsers, others have written in with questions on how to use it. The code in question is a PHP function that returns a true or false value depending on whether the browser viewing the page has been identified [...]]]></description>
			<content:encoded><![CDATA[<p>While a lot of people have written in with kudos on my <a href="http://www.brainhandles.com/2007/10/15/detecting-mobile-browsers/">PHP code for detecting mobile browsers</a>, others have written in with questions on how to use it.</p>
<p><!--adsense--></p>
<p>The code in question is a PHP function that returns a true or false value depending on whether the browser viewing the page has been identified as mobile or not.  If it's identified as mobile, it returns a "true" status.  If it's not, it returns a "false" status.  So, if you use the code exactly as presented in <a href="http://www.brainhandles.com/2007/10/15/detecting-mobile-browsers/">the original article</a>, you're going to put it somewhere near the end of the PHP code block in your page.  Somewhere near the beginning of the page, you'll want a PHP code block like this...</p>
<p><code style="font-family:courier,courier-new,courier new;font-size:12px;">if(checkmobile()){<br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code>//<i>code to execute if a mobile browser is detected</i><br />
}</code></p>
<p>Now what code you'll execute is up to you.  It might be that you simply select a mobile style sheet instead of your regular one.  To do that, you'd do something like...</p>
<p><code style="font-family:courier,courier-new,courier new;font-size:12px;">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"<br />
   "http://www.w3.org/TR/html4/loose.dtd"&gt;<br />
&lt;HTML&gt;<br />
&lt;HEAD&gt;<br />
&lt;TITLE&gt;My Page Title&lt;/TITLE&gt;<br />
<b style="text-indent:20px;">&lt;?php<br />
if(checkmobile()){<br />
echo "&lt;link rel=\"stylesheet\" type=\"text/css\" href=\"/mobilestyle.css\"&gt;";<br />
} else {<br />
echo "&lt;link rel=\"stylesheet\" type=\"text/css\" href=\"/regularstyle.css\"&gt;";<br />
}<br />
?&gt;</b><br />
&lt;META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"&gt;<br />
...</code></p>
<p>Now remember, this assumes you've put the <a href="http://www.brainhandles.com/2007/10/15/detecting-mobile-browsers/">mobile browser detection code</a> somewhere in the page between &lt;?PHP ... ?&gt; tags.</p>
<p>Some of you, on the other hand, may want to send mobile browsers over to an entirely different version of your site.  The simplest way is to do...</p>
<p><code style="font-family:courier,courier-new,courier new;font-size:12px;"><b style="text-indent:20px;">&lt;?php<br />
if(checkmobile()) header("Location:http://www.whatever-url-you-want.com");<br />
?&gt;</b><br />
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"<br />
   "http://www.w3.org/TR/html4/loose.dtd"&gt;<br />
&lt;HTML&gt;<br />
...</code></p>
<p>Note that this is at the VERY VERY top of the page, before anything else.  That's because, you need to do the redirect before any other information has been sent to the user's browser.</p>
<p>You can put the <a href="http://www.brainhandles.com/2007/10/15/detecting-mobile-browsers/">code for catching mobile browsers</a> right in that PHP block, after the "if(checkmobile())" line and before the "?&gt;" line.  I haven't included it in the examples just to keep this page from being humongously long.</p>
<p>Depending on how your server is set up, any file that contains PHP may require that the file name end in .php instead of .htm or .html.  So make sure you know what your server requires.</p>
<p>Hope this helps some of you who aren't familiar with programming.  If you need further help, I suggest buying a book on PHP if you're in a DIY mood or hiring someone who knows it if you're not.</p>
<p><!--adsense--></p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.brainhandles.com%2Ftechno-thoughts%2Fdetecting-mobile-browsers-part-2&amp;title=Detecting%20Mobile%20Browsers%20Part%202" id="wpa2a_28"><img src="http://www.brainhandles.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.brainhandles.com/techno-thoughts/detecting-mobile-browsers-part-2/feed</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
	</channel>
</rss>

