<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
    <channel>
      <title>Steven York.com RSS Feed</title>
      <link>http://www.stevenyork.com</link>
      <description>Web development tutorials by Steven York</description>
      <language>en-en</language>
    <image>
<url>http://www.stevenyork.com/images/rss.gif</url>
<title>stevenyork.com</title>
<link>http://www.stevenyork.com</link>
</image>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/StevenYorkcomRssFeed" type="application/rss+xml" /><feedburner:browserFriendly></feedburner:browserFriendly><item>
			<title>How to configure htaccess to allow PHP files to accessed with XML extension</title>
				<link>http://www.stevenyork.com/tutorial/how_to_configure_htaccess_allow_php_access_with_xml_extension</link>
				<guid isPermaLink="true">http://www.stevenyork.com/tutorial/how_to_configure_htaccess_allow_php_access_with_xml_extension</guid>
					<description>&lt;p&gt;So supposing you've got a PHP file generating XML (as per my old tutorial on &lt;a href="http://www.seopher.com/articles/writing_a_php_google_sitemap_generator_without_using_fopen"&gt;generating an RSS feed using PHP&lt;/a&gt;), what happens if you need that file to be linked as XML?  This brief tutorial will explain how.&lt;/p&gt;
&lt;p&gt;Google Webmaster Tools specifically requests that sitemaps are added only with the .xml extension, in the same way Feedburner require RSS feeds to be linked as XML too. Irrespective of whether you've set the headers for XML, you'll need to perform some .htaccess wizardry to get things working correctly. &lt;/p&gt;

&lt;h2&gt;Setting .htaccess to allow PHP to be accessed with .xml extension&lt;/h2&gt;
&lt;p&gt;Firstly you'll need to create a .htaccess file (Google it if you're unsure what one is).  The contents of the file should be as per below:&lt;/p&gt;

&lt;textarea rows="10" cols="10" name="code" class="php"&gt;
RewriteEngine on
RewriteRule (.*)\.xml(.*) $1.php$2 [nocase]
&lt;/textarea&gt;

&lt;p&gt;The above code turns on the rewrite-engine which allows you to perform URL-rewriting.  The second line is a very broad statement, allowing any file with a .php extension to be accessed as the same filename with a .xml extension.  Of course it'd make sense to tie this down to the specific files you need, but in this example I'm matching anything and everything.&lt;/p&gt;

&lt;p&gt;With this you can generate RSS feeds and XML sitemaps using PHP (or whatever programming language you wish) and still have them recognised with the XML extension.  Just make sure you've set header to be XML on the script itself.&lt;/p&gt;

&lt;h2&gt;As a reminder, here is how to set the header to be XML in PHP&lt;/h2&gt;
&lt;textarea rows="10" cols="10" name="code" class="php"&gt;
header("Content-Type: text/xml;charset=iso-8859-1");
&lt;/textarea&gt;</description>
					<pubDate>Sat, 07 Mar 2009 16:57:25 -0800</pubDate>
		</item>
	
	
	
		<item>
			<title>Accessible, pixel perfect font sizing using both percentages and em's (cross browser, cross platform)</title>
				<link>http://www.stevenyork.com/tutorial/accessible_pixel_perfect_font_sizing_using_percentages_and_ems</link>
				<guid isPermaLink="true">http://www.stevenyork.com/tutorial/accessible_pixel_perfect_font_sizing_using_percentages_and_ems</guid>
					<description>&lt;p&gt;Whenever building a website you need to set font sizes using a dynamic metric - typically this is achieved using percentages. The reason for this is that the user can adjust the font-size within their browser and the website can accomodate their wishes. This is crucial for meeting AA accessibility and therefore crucial for all web-build projects. &lt;/p&gt;
&lt;p&gt;Recently I was leading a large build project and found myself mercy to a self-created madness; percentage font sizes are difficult to get pixel perfect cross-browser unless you put serious thought into the CSS structure before commencing the build.&lt;/p&gt;
&lt;h2&gt;The Problem with Percentages&lt;/h2&gt;

&lt;p&gt;There isn't a problem with percentage font sizes as such, but when you apply a font size to the body / overall container for the site, you need to ensure that you're consistent with the nested font sizes across the site. This of course becomes increasingly problematic with numerous devs working on a single project - using percentages on their own can become a headache if you're not clearly communicating what sizes should be applied to each container/component. Here's an example of the problem:&lt;/p&gt;

&lt;textarea rows="10" cols="15" name="code" class="css"&gt;

body
{
	font-size:75%;
}

#container-1
{
	font-size:90%;
}

#container-1 p
{
	font-size:95%;
}

#container-2
{
	font-size:100%;
}

#container-2 p
{
	/*oh, what percentage do I need here to make it the same as container-1*/
}

&lt;/textarea&gt;

&lt;p&gt;While it is possible to get the percentages correct mathematically (so that the sizes are *technically* the same), browsers won't necessarily honour your sizing. Different browsers render fonts differently, use different font-scales and generally mess with your head. That's why the percentage-em approach should always be used.&lt;/p&gt;
&lt;h2&gt;What is the Percentage-Em approach?&lt;/h2&gt;
&lt;p&gt;Obviously you want to have a percentage set somewhere to accomodate for any text-size set by the user, but (as explained above) this can become a logistic nightmare in larger builds. Therefore we can use the ;quot;em;quot; metric to specify most of the font-sizes as such:&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;Set font-size on the body to be 62.5%&lt;/li&gt;
    &lt;li&gt;All sizes here-after should be set using ;quot;em;quot;, because now 1em = 10px&lt;/li&gt;
    &lt;li&gt;This allows you to be pixel-perfect at default font-sizes, but scale up should the user require it&lt;/li&gt;
    &lt;li&gt;Just divide the px figure you need by 10 and you've got your em value (15px = 1.5em, 29px = 2.9em etc)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href="http://www.stevenyork.com/demos/font-sizing/"&gt;View the online demo to see this in operation&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Code&lt;/h2&gt;

&lt;textarea rows="10" cols="15" name="code" class="css"&gt;

body
{
	font-family:Arial, Helvetica, sans-serif;
	font-size:62.5%;
	padding:20px;
}

span.em1
{
	font-size:1em;
}

span.px1
{
	font-size:10px;
}

&lt;/textarea&gt;

&lt;p&gt;In the above code sample, the span with class of em1 will render at the exact same height as the absolutely specified px1 span.  This allows you to meet accessiblity standards while remaining pixel perfect - which is ideal for keeping both the designers and the client happy.  This works perfectly cross browser, cross platform and therefore there's no reason not to be using it for everything you do.  &lt;a href="http://www.stevenyork.com/demos/font-sizing/"&gt;View the online demo&lt;/a&gt; if you don't believe me.&lt;/p&gt;</description>
					<pubDate>Sat, 01 Nov 2008 00:55:38 -0700</pubDate>
		</item>
	
	
	
		<item>
			<title>Creating an accessible tag cloud in PHP and CSS (with MySQL) </title>
				<link>http://www.stevenyork.com/tutorial/creating_accessible_tag_cloud_in_php_css_mysql</link>
				<guid isPermaLink="true">http://www.stevenyork.com/tutorial/creating_accessible_tag_cloud_in_php_css_mysql</guid>
					<description>&lt;p&gt;Tag clouds; love them or hate them they're an unavoidable cliche that clients seem to love. Once marketing types get the smell of taxonomy in their nostrils it's hard to convince them that tag clouds are a usability nightmare.&lt;/p&gt;
&lt;p&gt;Therefore to go along with the trend (well, a trend from 12 months ago maybe) I decided to implement a tag-cloud with this website, the intention was to demonstrate how it can be done in a clean and tidy fashion using simple code. The one noted in this tutorial is accessible and standards compliant, something which seems hard to come by elsewhere...&lt;/p&gt;

&lt;img src="http://www.stevenyork.comhttp://www.stevenyork.com/images/demos/tagcloud.jpg" alt="accessible tag cloud" /&gt;

&lt;h2&gt;Why other tag clouds are rubbish&lt;/h2&gt;
&lt;p&gt;Without wanting to be too cruel to some other developers, almost every tag cloud tutorial on the Internet is awful. The PHP is either &lt;a href="http://www.lotsofcode.com/php/tag-cloud.htm"&gt;far too complicated&lt;/a&gt; for the purpose or it relies on inline styles (&lt;a href="http://prism-perfect.net/archive/php-tag-cloud-tutorial/"&gt;or both&lt;/a&gt;). The PHP doesn't need to be lengthy, after all it's a very simple calculation and the CSS needs to reflect that. Do we really need 100 different sizes that the tag-cloud could be? Unlikely.&lt;/p&gt;
&lt;h2&gt;How mine works&lt;/h2&gt;
&lt;p&gt;Here is the basic set of steps to create an accessible, valid tag cloud:&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;Count how many pieces of content there are in total [x]&lt;/li&gt;
    &lt;li&gt;Count how many pieces of content are assigned to each tag [y]&lt;/li&gt;
    &lt;li&gt;Work out what percentage of [x] that [y] constitutes&lt;/li&gt;
    &lt;li&gt;Apply a CSS class that reflects that percentage&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Therefore if you have 100 articles [x] and 19 articles [y] tagged with ;quot;kitten;quot;, then ;quot;kitten;quot; constitutes for 19% of your content. I'll show you how to apply this logic in PHP and write out valid XHTML in the process.&lt;/p&gt;
&lt;h2&gt;The code&lt;/h2&gt;
&lt;p&gt;Let's start with the PHP, I'll comment the code for ease of understanding:&lt;/p&gt;

&lt;textarea rows="10" cols="15" name="code" class="php"&gt;

/*note: this is the exact function I use on this site, just with stevenyork.com specific queries removed*/
function createTagCloud($tags)
{	
	//I pass through an array of tags
    $i=0;
    foreach($tags as $tag)
    {
        $id = $tag['id']; //the tag id, passed through
        $name = $tag['tag']; //the tag name, also passed through in the array
        
        //using the mysql count command to sum up the tutorials tagged with that id
        $sql = "SELECT COUNT(*) AS totalnum FROM tutorials WHERE tags LIKE '%".$id."%' AND published = 1";
        
        //create the resultset and return it
        $res = mysql_query($sql);
        $res = mysql_fetch_assoc($res);
		
        //check there are results ;)
        if($res)
        {
        	//build an output array, with the tag-name and the number of results
            $output[$i]['tag'] = $name; 
            $output[$i]['num'] = $res['totalnum'];
        }
        
        $i++;
    }
    
    /*this is just calling another function that does a similar SQL statement, but returns how many pieces of content I have*/
    $total_tuts = $this-&gt;getNumberOfTutorials();
    
    //ugh, XHTML in PHP?  Slap my hands - this isn't best practice, but I was obviously feeling lazy
    $html = '&lt;ul class="tagcloud"&gt;';
    
    //iterate through each item in the $output array (created above)
    foreach($output as $tag)
    {
    	//get the number-of-tag-occurances as a percentage of the overall number
        $ratio = (100 / $total_tuts) * $tag['num'];
        
        //round the number to the nearest 10
        $ratio =  round($ratio,-1);
        
        /*append that classname onto the list-item, so if the result was 20%, it comes out as cloud-20*/
        $html.= '&lt;li class="cloud-'.$ratio.'"&gt;&lt;a href="/tag/'.$tag['tag'].'"&gt;'.$tag['tag'].'&lt;/a&gt;&lt;/li&gt;';			
    }
    
    //close the UL
    $html.= '&lt;/ul&gt;';
    
    return $html; 
}

&lt;/textarea&gt;

&lt;p&gt;The above function takes an array of tags, iterates through them and gets each tag as a percentage of the total number of pieces of content.  I'm rounding to the nearest 10 because I think 10 different font-sizes in a tag-cloud is more than enough.  Now the CSS:&lt;/p&gt;

&lt;textarea rows="10" cols="15" name="code" class="css"&gt;

/*remove the list style and make it just a normal list of items*/
.home-item ul.tagcloud
{
	list-style-type:none;
    margin:0px;
    padding:0px;
}

/*this lines each of the li's up next to one another and spaces them out niecly*/
.home-item ul.tagcloud li
{
	display:inline !important;
	margin-right:15px;
	line-height:2em;
}

.home-item ul.tagcloud li a
{
	display:inline;
}

/*the following are how each of the classes generated by the PHP are presented to the user 
through CSS, just increasing the text a little each time*/
.home-item ul.tagcloud li.cloud-10 a
{
	font-size:110%;
}

.home-item ul.tagcloud li.cloud-20 a
{
	font-size:120%;
}

.home-item ul.tagcloud li.cloud-30 a
{
	font-size:130%;
}

/************************************* 
you get the idea, i'm skipping a few 
*************************************/

.home-item ul.tagcloud li.cloud-90 a
{
	font-size:190%;
}

.home-item ul.tagcloud li.cloud-100 a
{
	font-size:200%;
}

&lt;/textarea&gt;

&lt;p&gt;That will create a nice unordered list of tags, lined up next to one another and nicely weighted with 10 different font sizes depending on their proportional popularity within your entire content archive.&lt;/p&gt;

&lt;h2&gt;How to make tag-clouds usable&lt;/h2&gt;
&lt;p&gt;In the majority of cases tag-clouds are only made into a usability nightmare by the user.  Clouds are inherantly a good idea but stereotyped by poor implementation.  For a tag cloud to be usable it should:&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;Be clear and concise&lt;/li&gt;
    &lt;li&gt;Have as few tags as possible, 10 is probably best, but certainly less than 30&lt;/li&gt;
    &lt;li&gt;Use sensible, descriptive tags. Using ;quot;stuff;quot; as a tag isn't going to be helpful to anyone&lt;/li&gt;
    &lt;li&gt;Ensure that even the least popular tags are still of a readable size&lt;/li&gt;
    &lt;li&gt;Be standards compliant (no inline styles)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For an example of an automatically generated tag-cloud that was less than useful, see my article on Seopher.com about &lt;a href="http://www.seopher.com/articles/the_worlds_biggest_tagcloud"&gt;the world's biggest tagcloud&lt;/a&gt;; one created on the previous implementation of the 9Rules blogging network.  Remember, less is better.  &lt;/p&gt;</description>
					<pubDate>Tue, 28 Oct 2008 21:43:38 -0700</pubDate>
		</item>
	
	
	
		<item>
			<title>How to fix IE6 PNG hack links not being clickable</title>
				<link>http://www.stevenyork.com/tutorial/fix_ie6_png_hack_links_not_being_clickable</link>
				<guid isPermaLink="true">http://www.stevenyork.com/tutorial/fix_ie6_png_hack_links_not_being_clickable</guid>
					<description>&lt;p&gt;When you're replacing a PNG using the CSS PNG hack for IE6 you'll find that links stop being clickable; here is a tutorial to end your suffering.&lt;/p&gt;

&lt;h2&gt;What you're trying to do and the actual problem&lt;/h2&gt;

&lt;p&gt;Undeniably Internet Explorer 6 is one of the biggest thorns in the side of web development; layout oddities galore, yet the single most pressing issue with it isn't it's inability to handle correct CSS - it's the lack of PNG support. Almost every decent design these days requires some degree of transparency and IE6 only natively supports GIF's, which in turn only support binary transparency. &lt;/p&gt;
&lt;p&gt;It's pretty likely that you'll end up using a PNG hack of some description (rather than compromise on aesthetics, it's still a weighty demographic). However, if you use a PNG as a background image and use CSS to create a link around it, you'll find when the CSS PNG hack is applied the link stops being clickable in IE6. This is a royal pain in the posterior, but here is a solution that works.&lt;/p&gt;
&lt;h2&gt;What we're going to do&lt;/h2&gt;

&lt;p&gt;The problem is that the filter you apply is breaking the flow of the document in IE6's eyes, so it's unsure whether the link is above or below the PNG. Typically this would be an easy fix using z-index but don't forget IE is ;quot;special;quot;. Therefore we need to add in an extra div, change the positioning and toy with z-index. Right, let's get started...&lt;/p&gt;
&lt;h2&gt;Initial Setup and PNG hack&lt;/h2&gt;
&lt;p&gt;I'm using this actual website as an example, because it's stuff I had to overcome as part of the development.  All I've got is a container (downloadbox) with a link within it.  The link simply has a non-breaking-space in it, as it derives layout from the CSS.  Nice and simple...&lt;/p&gt;

&lt;textarea rows="10" cols="15" name="code" class="html"&gt;

&lt;div id="downloadbox"&gt;
    &lt;a href="#wherever" title="Download"&gt;
        ;amp;nbsp;
    &lt;/a&gt;
&lt;/div&gt;

&lt;/textarea&gt;

&lt;p&gt;Here is the CSS used for the above layout.  I'm just adding width and height to the container, setting the background image and forcing the dimensions of the link used.  This works in Firefox, IE7, Opera and Safari (theoretically).&lt;/p&gt;

&lt;textarea rows="10" cols="15" name="code" class="css"&gt;

#downloadbox
{
	background-image:url(http://www.stevenyork.comhttp://www.stevenyork.com/images/badge.png); 
	background-repeat:no-repeat;
	width:128px; 
	height:130px;
}


#downloadbox a
{
	display:block;
	width:128px;
	height:130px;
	outline:none;
}

&lt;/textarea&gt;

&lt;p&gt;The link is given width and height and block display.  Removing the outline just makes things a lot tidier by not having that dotted line around the link when it's clicked on.  This works in the good browsers, but because we're just using a PNG, IE6 messes up in a big way.&lt;/p&gt;

&lt;img src="http://www.stevenyork.com/images/demos/ie6-png-links/1.jpg" alt="IE6 PNG fail" /&gt;

&lt;h2&gt;Apply the CSS PNG Hack&lt;/h2&gt;
&lt;p&gt;So you apply the &lt;a href="http://www.stevenyork.com/tutorial/fix_pngs_in_ie6_css_png_hack"&gt;CSS PNG hack&lt;/a&gt; and everything works fine right?  If you're not sure how to do this you can either work it out from the demo or check out &lt;a href="http://www.stevenyork.com/tutorial/fix_pngs_in_ie6_css_png_hack"&gt;my tutorial on how to apply it&lt;/a&gt;.  However, the link that was working previously with the messed up PNG is now no longer clickable... Fail.&lt;/p&gt;

&lt;h2&gt;How to fix this in IE6&lt;/h2&gt;
&lt;p&gt;It feels a little bit like bowing down to the devil, but some poor misguided people still use this black-eye of a browser, so let me explain how to fix it.  Firstly, let's step into the XHTML and make one very simple yet signifcant change...&lt;/p&gt;

&lt;textarea rows="10" cols="15" name="code" class="html"&gt;

&lt;div id="downloadbox"&gt;
	&lt;div&gt;       
        &lt;a href="#wherever" title="Download"&gt;
            ;amp;nbsp;
        &lt;/a&gt;
	&lt;/div&gt;        
&lt;/div&gt;

&lt;/textarea&gt;

&lt;p&gt;That's right, just add in a div to wrap the link.  The significance of this can then be seen in the restructured CSS:&lt;/p&gt;

&lt;textarea rows="10" cols="15" name="code" class="css"&gt;

#downloadbox
{
	background-image:url(http://www.stevenyork.comhttp://www.stevenyork.com/images/badge.png); 
	background-repeat:no-repeat;
	width:128px; 
	height:130px;
   	_background-image:none;
}


#downloadbox div 
{
	_filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src="http://www.stevenyork.comhttp://www.stevenyork.com/images/badge.png",sizingMethod="scale");
	width:128px; 
	height:130px;
}

#downloadbox a
{
	display:block;
	width:128px;
	height:130px;
	outline:none;
    position:relative; 
	z-index:1;
}

&lt;/textarea&gt;

&lt;p&gt;Where the &lt;a href="http://www.stevenyork.com/tutorial/fix_pngs_in_ie6_css_png_hack"&gt;CSS PNG hack&lt;/a&gt; would have been applied to the downloadbox container we've now moved it to the newly created div.  This is given width and height (so the image appears properly).  Remember to set the background image to be "none" on the container too - it's part of the CSS PNG Hack.  So the PNG is moved to the new wrapper, and we've added z-index and relative positioning to the link.&lt;/p&gt;

&lt;h2&gt;BINGO - it works&lt;/h2&gt;
&lt;p&gt;That's it.  Simple a change as it is, it actually makes sense in a daft IE6 sort of a way.  Simply by making your markup ugly and restructuring you can have a nice, cross browser set of PNG links.  Check out the demo for a decent comparison.&lt;/p&gt;</description>
					<pubDate>Sun, 26 Oct 2008 22:02:16 -0700</pubDate>
		</item>
	
	
	
		<item>
			<title>How to fix PNG's under IE6 (Internet Explorer CSS PNG hack)</title>
				<link>http://www.stevenyork.com/tutorial/fix_pngs_in_ie6_css_png_hack</link>
				<guid isPermaLink="true">http://www.stevenyork.com/tutorial/fix_pngs_in_ie6_css_png_hack</guid>
					<description>&lt;p&gt;IE6 just won't die, so we as web developers have to keep supporting it - at least in some capacity. My perspective (both personally and professionally) is that it should be supported to *some* extent. Provided the site looks okay and content is accessible I'm happy. However, in my professional life it's pretty likely that the client is using IE6 so we still have to make a proper effort to get sites rendering correctly. Variable transparency PNG's are one such thorn in my side, but with this super-short tutorial I'll show you how to quickly (and easily) get PNG's to display correctly using a little bit of CSS trickery.&lt;/p&gt;
&lt;h2&gt;The Problem&lt;/h2&gt;
&lt;p&gt;When you just place a PNG with variable transparency on to the page, IE6 will firmly remind you who is boss. The outcome looks something like this:&lt;/p&gt;

&lt;img src="http://www.stevenyork.com/images/demos/ie6-png-links/1.jpg" alt="IE6 PNG fail" /&gt;

&lt;p&gt;Any pixel that requires transparency is rendered as a grey mess.  So in IE6 you need to:&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;Add a wrapper around the image with the exact dimensions of the image (and any positioning applied to it)
    &lt;li&gt;Add a class of "ie-hide" to the image&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Which will look something like this:&lt;/p&gt;

&lt;textarea rows="10" cols="15" name="code" class="html"&gt;

&lt;div id="my-png"&gt;
	&lt;img class="ie-hide" src="http://www.stevenyork.comhttp://www.stevenyork.com/images/badge.png" alt="a png" /&gt;     
&lt;/div&gt;

&lt;/textarea&gt;

&lt;p&gt;You now need some CSS to accompany this:&lt;/p&gt;

&lt;textarea rows="10" cols="15" name="code" class="css"&gt;

.ie-hide
{
	_display:none;
}

#my-png
{
	width:128px; 
	height:130px;
    _filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src="http://www.stevenyork.comhttp://www.stevenyork.com/images/badge.png",sizingMethod="scale");
}

&lt;/textarea&gt;

&lt;p&gt;You'll then find that this option works under IE6.  The underscore is there because only IE6 will read it, meaning you can target specific rules to this problematic browser.&lt;/p&gt;

&lt;p&gt;If you're having problems with links that are applied to regions using the CSS PNG hack, visit my tutorial how &lt;a href="http://www.stevenyork.com/tutorial/fix_ie6_png_hack_links_not_being_clickable"&gt;how to fix IE6 PNG hack links not being clickable&lt;/a&gt;.&lt;/p&gt;</description>
					<pubDate>Sun, 26 Oct 2008 22:34:34 -0700</pubDate>
		</item>
	
	
	
		<item>
			<title>How to get search engine (Google, Yahoo, MSN) referal keywords using PHP</title>
				<link>http://www.stevenyork.com/tutorial/how_to_get_search_engine_referal_keywords_using_php</link>
				<guid isPermaLink="true">http://www.stevenyork.com/tutorial/how_to_get_search_engine_referal_keywords_using_php</guid>
					<description>&lt;p&gt;There are many reasons why you'd want to know what keywords your current visitor entered your website on; whether you want to show them similar content, gather opinion or maybe show a targetted piece of advertising, the bigger question is "how?".  I recently (through boredom more than necessity) gave this a go, so I'll show you how I did it.&lt;/p&gt;

&lt;h2&gt;What I wanted to achieve&lt;/h2&gt;
&lt;p&gt;On Seopher.com I receive quite a lot of traffic from Google - a good 60-70% of my traffic is natural search oriented.  I wanted a way to offer a richer experience to these users and try to increase the number of pages they view.  So the objective was to take the keywords they entered in on and provide a list of similar articles.&lt;/p&gt;

&lt;h2&gt;PHP Functions&lt;/h2&gt;
&lt;p&gt;First off let's look at the functions I've written to get the job done.&lt;/p&gt;
&lt;p&gt;This first function (getReferalHost) simply obtains the referal URL and uses the PHP function parse_url() to break things down.  Then it's a simple set of 'if' statements to return a user-friendly hostname.  So whereas the hostname might be images.google.com, I'm using "strstr" to check whether the string 'google' is in the URL, and so on.  It's not foolproof but it's okay.&lt;/p&gt;
&lt;textarea rows="10" cols="15" name="code" class="php"&gt;

function getReferalHost()
{
    $refer = parse_url($_SERVER['HTTP_REFERER']);
    $host = $refer['host'];
    
    if(strstr($host,'google'))
    {
        return 'Google';
    }
    elseif(strstr($host,'yahoo'))
    {
        return 'Yahoo';
    }
    elseif(strstr($host,'msn'))
    {
        return 'MSN';
    }
}

&lt;/textarea&gt;


&lt;p&gt;This next function (getKeywords) parses the referal URL again (not best practice is it?  Shame on me).  Then I've got a specific preg_match for each of the different vendors (based on the URLs that each of them uses.  Google will format their query as such: 
http://www.google.com/search?;rls=en&lt;strong&gt;;q=seopher+another+keyword&lt;/strong&gt; so I know that what I'm after starts with ';amp;q=' with the keywords separated by '+'.  So the regex used matches that.  Yahoo and MSN do exactly the same, just with slightly different syntax - hence the need for the 'if' statement.&lt;/p&gt;

&lt;textarea rows="10" cols="15" name="code" class="php"&gt;

function getKeywords()
{
    $refer = parse_url($_SERVER['HTTP_REFERER']);
    $host = $refer['host'];
    $refer = $refer['query'];
    
    if(strstr($host,'google'))
    {
        //do google stuff
        $match = preg_match('/;q=([a-zA-Z0-9+-]+)/',$refer, $output);
        $querystring = $output[0];
        $querystring = str_replace(';q=','',$querystring);
        $keywords = explode('+',$querystring);
        return $keywords;
    }
    elseif(strstr($host,'yahoo'))
    {
        //do yahoo stuff
        $match = preg_match('/p=([a-zA-Z0-9+-]+)/',$refer, $output);
        $querystring = $output[0];
        $querystring = str_replace('p=','',$querystring);
        $keywords = explode('+',$querystring);
        return $keywords;
        
    }
    elseif(strstr($host,'msn'))
    {
        //do msn stuff
        $match = preg_match('/q=([a-zA-Z0-9+-]+)/',$refer, $output);
        $querystring = $output[0];
        $querystring = str_replace('q=','',$querystring);
        $keywords = explode('+',$querystring);
        return $keywords;
    }
    else
    {
        //else, who cares
        return false;
    }
}

&lt;/textarea&gt;

&lt;p&gt;Really you can add as many different vendors to this function, I'm just focusing on the obvious 3 because they constitute about 98%+ of my search traffic.&lt;/p&gt;

&lt;p&gt;This final function is what I'm using to write the recommendations; it takes the keywords used as a parameter and uses MySQL scoring to deliver results...  So it takes the search terms and tries to find similar content on the website:&lt;/p&gt;

&lt;textarea rows="10" cols="15" name="code" class="php"&gt;

function getSearchHelperList($term, $limit, $currentPageID)
{
    $searchterm = $term;
    
    //a function I use to sanitise all inputs
    $searchterm = $this-&gt;cleanInput($searchterm);
    
    /*query that takes the searchterms and scores it against the articles
    it also checks that the title isn't the same as the page we're already on
    because we don't want it showing you a link to your current page*/
    $sql = "SELECT CatID, Title, Content, CleanTitle, UNIX_TIMESTAMP(TIME) AS FORMATED_TIME, MATCH (Title, Content) AGAINST ('$searchterm') AS score FROM Articles WHERE MATCH (Title, Content) AGAINST ('$searchterm') AND CleanTitle != '$currentPageID' AND Time &lt; CURRENT_TIMESTAMP ORDER BY score DESC";
    
    $result = mysql_query($sql);
    
    $num = mysql_numrows($result);
    
    if($num &lt; $limit)
    {
        $limit = $num;
    }
    
    //old school right?  for loops! 
    //build an unordered list of related content
    if($limit &gt; 0)
    {
        echo '&lt;ul&gt;';
        for($i=0; $i&lt;$limit; $i++)
        {
            echo '&lt;li&gt;&lt;a href="/articles/'.mysql_result($result,$i,'CleanTitle').'"&gt;';
            echo mysql_result($result,$i,'Title');
            echo '&lt;/a&gt;&lt;/li&gt;';
        }
        echo '&lt;/ul&gt;';
    
    }
    else
    {
       //display a message
    }
}

&lt;/textarea&gt;


&lt;h2&gt;Usage&lt;/h2&gt;
&lt;p&gt;Using these functions is really simple, I've commented my code so you can see the method behind the madness:&lt;/p&gt;

&lt;textarea rows="10" cols="15" name="code" class="php"&gt;

/*if there were keywords = it was a search engine referal 
from one of the vendors I'm scanning*/
if($s-&gt;getKeywords())
{
	//get the keywords
    $keywords = $s-&gt;getKeywords();
	
	if($id)
	{
    	//if the page has an ID set (only content pages have ID's
		$articleID = $id;
	}
	else
	{
    	//I thought I'd be nice and creative about nulling my articleID
        //this is an article title I'll never use (hopefully anyway!)
		$articleID = 'rawr-donkey-squirrel-ballsack';
	}
	
	?&gt;
    
    &lt;div class="rss-promo search-helper"&gt;
        &lt;span&gt;Can I help you &lt;strong&gt;&lt;?php echo $s-&gt;getReferalHost(); ?&gt;&lt;/strong&gt; user?&lt;/span&gt;
		You entered looking for &lt;strong&gt;
			&lt;?php
			
			$helperterms = '';
            foreach($keywords as $keyword)
            {
				$helperterms.= $keyword.' ';
                echo $keyword.' ';
            }
            
            ?&gt;
            &lt;/strong&gt; so maybe you'd also be interested in:&lt;br /&gt;
			
           &lt;?php 
           
           /*get the list of related content, using all the keywords, how many
           items I want returned and the articleID to avoid*/
           $s-&gt;getSearchHelperList($helperterms, 6, $articleID); 
           
           ?&gt;
    &lt;/div&gt;
    
    &lt;?php
}

&lt;/textarea&gt;

&lt;p&gt;Done!  This example is pretty specific to what I'm doing but it shows you how I'm getting keyword data back.  The functions should be pretty re-usable too (bar the getSearchHelperList which is bespoke to my needs).  I'm not providing a download with this one because there's not enough to download, but the demo has instructions on what to do.&lt;/p&gt;</description>
					<pubDate>Tue, 29 Jul 2008 13:48:34 -0700</pubDate>
		</item>
	
	
	 </channel>
</rss>
