<?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>Che Hodgins &#187; pecl</title>
	<atom:link href="http://www.chehodgins.com/category/pecl/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.chehodgins.com</link>
	<description>Musings on Web Development</description>
	<lastBuildDate>Wed, 15 Sep 2010 21:35:17 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Free and Fast Geolocation in PHP</title>
		<link>http://www.chehodgins.com/php/free-and-fast-geolocation-in-php/</link>
		<comments>http://www.chehodgins.com/php/free-and-fast-geolocation-in-php/#comments</comments>
		<pubDate>Thu, 21 May 2009 12:08:24 +0000</pubDate>
		<dc:creator>chehodgins</dc:creator>
				<category><![CDATA[geolocation]]></category>
		<category><![CDATA[pecl]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[geoip]]></category>

		<guid isPermaLink="false">http://www.chehodgins.com/?p=246</guid>
		<description><![CDATA[table#benchmarks { border: 1px solid black; } table#benchmarks td,th { padding: 4px; border: 1px solid black; } Geo* (as I call them) are the web technologies that provide a link between online content and Earth&#8217;s geography. Examples includes Geocoding (finding latitude/longitude based on street addresses), Geotagging (tagging media with latitude/longitude coordinates), and Geolocation (finding latitude/longitude [...]]]></description>
			<content:encoded><![CDATA[<style type="text/css">
table#benchmarks {
   border: 1px solid black;
}
table#benchmarks td,th {
   padding: 4px;
   border: 1px solid black;
}
</style>
<p>Geo* (as I call them) are the web technologies that provide a link between online content and Earth&#8217;s geography. Examples includes Geocoding (finding latitude/longitude based on street addresses), Geotagging (tagging media with latitude/longitude coordinates), and Geolocation (finding latitude/longitude of a computer).</p>
<p>Geolocation is a particularly cool technique because it allows you to estimate a person&#8217;s geographic location, thus allowing you to provide a custom tailored experience on your website, among other things. This can be <a href="http://www.google.com/latitude/intro.html">useful</a> as much as it can be <a href="http://www.hulu.com/support/geofilter">annoying</a>. There are several methods of Geolocation, some as simple as asking the user where they are located. This article focuses on adding IP based Geolocation to your PHP website for free all the while keeping it fast.</p>
<p><strong>Problems</strong></p>
<p>If IP addresses are to be used to determine a persons physical location then a few possible problems come to mind:</p>
<ul>
<li>How accurate is the mapping between an IP address and a geographical location?
<ul>
<li>From maxmind.com&#8217;s Geolocation service: &#8220;99.8% accurate on a country level, 90% accurate on a state level, and 83% accurate for the US within a 25 mile radius.&#8221;. Doing some research, the matching is done using either the address of the ISP that owns that IP [<a href="http://www.zipwise.com/geomap/geotargeting-database.php">link</a>], or by buying the data from websites that ask for users locations [<a href="http://www.maxmind.com/app/faq#accurate">link</a>].</li>
</ul>
</li>
<li>What about users behind proxies?
<ul>
<li>Some Geolocation databases <a href="http://www.maxmind.com/app/faq#anonproxy">flag</a> the IPs of potential anonymous proxy servers.</li>
<li><a href="http://en.wikipedia.org/wiki/X-Forwarded-For#Proxy_servers_and_caching_engines">Most proxy servers</a> send X-Forwarded-For and Client-IP headers that you can use.</li>
</ul>
</li>
</ul>
<p>This is <a href="http://stefan.rusek.org/Posts/Don-t-use-IP-geolocation-to-lock-out-users/9/">not perfect</a>, but in many cases the approximate geographical location of a user can be inferred.</p>
<p><strong>Demo time</strong></p>
<p>This demo will use the free Geolocation database provided by Maxmind.com. I believe this is the ideal choice for normal (i.e. not Facebook) websites for several reasons:</p>
<ul>
<li>It is free (there is a paid version with higher accuracy)</li>
<li>It is fast. <a href="http://www.maxmind.com/app/benchmark">They report</a> up to 1 million queries per second on 1 machine.</li>
<li>It is extensible. The database can be upgraded to the paid version by just replacing the binary.</li>
<li>They like developers. They provide implementations in over 10 different programming languages, with benchmarks.</li>
<li>Their website is full of valuable information. They provide benchmarks, an explanation of how they collect their data, and more. I haven&#8217;t seen this with any other IP Geolocation services.</li>
</ul>
<p>There are two options for us PHP developers. The pure PHP library or a <a href="http://pecl.php.net/package/geoip">PECL package</a> implementing the C library. For reasons that will be discussed below, the PECL package will be used. If you do not want to use a PECL package or are on a hosted server, then you can download the pure PHP classes <a href="http://geolite.maxmind.com/download/geoip/api/php/">here</a>.</p>
<p>First, the GeoIP C library must be downloaded (<a href="http://geolite.maxmind.com/download/geoip/api/c/">link</a>) and installed. Note that this can be installed on windows as well. No special options are needed to install it:<br />
<br/></p>
<div class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">mbpro:GeoIP-1.4.6 chehodgins$ <span style="color: #c20cb9; font-weight: bold;">sudo</span> .<span style="color: #000000; font-weight: bold;">/</span>configure<br />
mbpro:GeoIP-1.4.6 chehodgins$ <span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">make</span><br />
mbpro:GeoIP-1.4.6 chehodgins$ <span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">make</span> <span style="color: #c20cb9; font-weight: bold;">install</span></div></td></tr></tbody></table></div>
<p><br/><br />
Then the PECL package can be installed:</p>
<div class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">mbpro:~ chehodgins$ <span style="color: #c20cb9; font-weight: bold;">sudo</span> pecl <span style="color: #c20cb9; font-weight: bold;">install</span> geoip<br />
downloading geoip-1.0.7.tar ...<br />
...<br />
You should add <span style="color: #ff0000;">&quot;extension=geoip.so&quot;</span> to php.ini</div></td></tr></tbody></table></div>
<p><br/><br />
Next, add this extension to php.ini (i.e. extension=geoip.so), restart apache and check out phpinfo():</p>
<p><div id="attachment_253" class="wp-caption aligncenter" style="width: 628px"><a href="http://www.chehodgins.com/wp-content/uploads/2009/05/picture-2.png"><img class="size-full wp-image-253" title="GeoIP in phpinfo()" src="http://www.chehodgins.com/wp-content/uploads/2009/05/picture-2.png" alt="GeoIP in phpinfo()" width="618" height="174" /></a><p class="wp-caption-text">GeoIP in phpinfo()</p></div><br />
<br/></p>
<p>The final step before writing code is to download the actual <a href="http://www.maxmind.com/app/geolitecity">database</a>. It is updated monthly so remember to stay up to date. The directory that should contain the file is OS dependent, so create a quick php script to see where the directory is:<br />
<br/></p>
<div class="codecolorer-container php default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #990000;">ini_set</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'display_errors'</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #990000;">error_reporting</span><span style="color: #009900;">&#40;</span><span style="color: #009900; font-weight: bold;">E_ALL</span> <span style="color: #339933;">|</span> <span style="color: #009900; font-weight: bold;">E_STRICT</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$result</span> <span style="color: #339933;">=</span> geoip_record_by_name<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'72.30.81.165'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #990000;">var_dump</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$result</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
<p><br/><br />
Gives us:</p>
<p><a href="http://www.chehodgins.com/wp-content/uploads/2009/05/picture-3.png"><img class="aligncenter size-large wp-image-254" title="Determine the binary directory" src="http://www.chehodgins.com/wp-content/uploads/2009/05/picture-3-1024x99.png" alt="Determine the binary directory" width="1024" height="99" /></a><br />
<br/><br />
Now save the binary to the directory mentioned in the php warning, reload your script, and the warning should disappear. Let&#8217;s try again with some more code:</p>
<div class="codecolorer-container php default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #990000;">ini_set</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'display_errors'</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #990000;">error_reporting</span><span style="color: #009900;">&#40;</span><span style="color: #009900; font-weight: bold;">E_ALL</span> <span style="color: #339933;">|</span> <span style="color: #009900; font-weight: bold;">E_STRICT</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000088;">$functions</span> <span style="color: #339933;">=</span> <span style="color: #990000;">get_extension_funcs</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'geoip'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #990000;">var_dump</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$functions</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000088;">$result</span> <span style="color: #339933;">=</span> geoip_record_by_name<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'72.30.81.165'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #990000;">var_dump</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$result</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
<p><br/><br />
Gives:</p>
<div class="codecolorer-container php default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br /></div></td><td><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #990000;">array</span><br />
<span style="color: #cc66cc;">0</span> <span style="color: #339933;">=&gt;</span> string <span style="color: #0000ff;">'geoip_database_info'</span> <span style="color: #009900;">&#40;</span>length<span style="color: #339933;">=</span><span style="color: #cc66cc;">19</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #cc66cc;">1</span> <span style="color: #339933;">=&gt;</span> string <span style="color: #0000ff;">'geoip_country_code_by_name'</span> <span style="color: #009900;">&#40;</span>length<span style="color: #339933;">=</span><span style="color: #cc66cc;">26</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #cc66cc;">2</span> <span style="color: #339933;">=&gt;</span> string <span style="color: #0000ff;">'geoip_country_code3_by_name'</span> <span style="color: #009900;">&#40;</span>length<span style="color: #339933;">=</span><span style="color: #cc66cc;">27</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #cc66cc;">3</span> <span style="color: #339933;">=&gt;</span> string <span style="color: #0000ff;">'geoip_country_name_by_name'</span> <span style="color: #009900;">&#40;</span>length<span style="color: #339933;">=</span><span style="color: #cc66cc;">26</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #cc66cc;">4</span> <span style="color: #339933;">=&gt;</span> string <span style="color: #0000ff;">'geoip_continent_code_by_name'</span> <span style="color: #009900;">&#40;</span>length<span style="color: #339933;">=</span><span style="color: #cc66cc;">28</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #cc66cc;">5</span> <span style="color: #339933;">=&gt;</span> string <span style="color: #0000ff;">'geoip_org_by_name'</span> <span style="color: #009900;">&#40;</span>length<span style="color: #339933;">=</span><span style="color: #cc66cc;">17</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #cc66cc;">6</span> <span style="color: #339933;">=&gt;</span> string <span style="color: #0000ff;">'geoip_record_by_name'</span> <span style="color: #009900;">&#40;</span>length<span style="color: #339933;">=</span><span style="color: #cc66cc;">20</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #cc66cc;">7</span> <span style="color: #339933;">=&gt;</span> string <span style="color: #0000ff;">'geoip_id_by_name'</span> <span style="color: #009900;">&#40;</span>length<span style="color: #339933;">=</span><span style="color: #cc66cc;">16</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #cc66cc;">8</span> <span style="color: #339933;">=&gt;</span> string <span style="color: #0000ff;">'geoip_region_by_name'</span> <span style="color: #009900;">&#40;</span>length<span style="color: #339933;">=</span><span style="color: #cc66cc;">20</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #cc66cc;">9</span> <span style="color: #339933;">=&gt;</span> string <span style="color: #0000ff;">'geoip_isp_by_name'</span> <span style="color: #009900;">&#40;</span>length<span style="color: #339933;">=</span><span style="color: #cc66cc;">17</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #cc66cc;">10</span> <span style="color: #339933;">=&gt;</span> string <span style="color: #0000ff;">'geoip_db_avail'</span> <span style="color: #009900;">&#40;</span>length<span style="color: #339933;">=</span><span style="color: #cc66cc;">14</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #cc66cc;">11</span> <span style="color: #339933;">=&gt;</span> string <span style="color: #0000ff;">'geoip_db_get_all_info'</span> <span style="color: #009900;">&#40;</span>length<span style="color: #339933;">=</span><span style="color: #cc66cc;">21</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #cc66cc;">12</span> <span style="color: #339933;">=&gt;</span> string <span style="color: #0000ff;">'geoip_db_filename'</span> <span style="color: #009900;">&#40;</span>length<span style="color: #339933;">=</span><span style="color: #cc66cc;">17</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #cc66cc;">13</span> <span style="color: #339933;">=&gt;</span> string <span style="color: #0000ff;">'geoip_region_name_by_code'</span> <span style="color: #009900;">&#40;</span>length<span style="color: #339933;">=</span><span style="color: #cc66cc;">25</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #cc66cc;">14</span> <span style="color: #339933;">=&gt;</span> string <span style="color: #0000ff;">'geoip_time_zone_by_country_and_region'</span> <span style="color: #009900;">&#40;</span>length<span style="color: #339933;">=</span><span style="color: #cc66cc;">37</span><span style="color: #009900;">&#41;</span><br />
<br />
<span style="color: #990000;">array</span><br />
<span style="color: #0000ff;">'continent_code'</span> <span style="color: #339933;">=&gt;</span> string <span style="color: #0000ff;">'NA'</span> <span style="color: #009900;">&#40;</span>length<span style="color: #339933;">=</span><span style="color: #cc66cc;">2</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #0000ff;">'country_code'</span> <span style="color: #339933;">=&gt;</span> string <span style="color: #0000ff;">'US'</span> <span style="color: #009900;">&#40;</span>length<span style="color: #339933;">=</span><span style="color: #cc66cc;">2</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #0000ff;">'country_code3'</span> <span style="color: #339933;">=&gt;</span> string <span style="color: #0000ff;">'USA'</span> <span style="color: #009900;">&#40;</span>length<span style="color: #339933;">=</span><span style="color: #cc66cc;">3</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #0000ff;">'country_name'</span> <span style="color: #339933;">=&gt;</span> string <span style="color: #0000ff;">'United States'</span> <span style="color: #009900;">&#40;</span>length<span style="color: #339933;">=</span><span style="color: #cc66cc;">13</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #0000ff;">'region'</span> <span style="color: #339933;">=&gt;</span> string <span style="color: #0000ff;">'CA'</span> <span style="color: #009900;">&#40;</span>length<span style="color: #339933;">=</span><span style="color: #cc66cc;">2</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #0000ff;">'city'</span> <span style="color: #339933;">=&gt;</span> string <span style="color: #0000ff;">'Sunnyvale'</span> <span style="color: #009900;">&#40;</span>length<span style="color: #339933;">=</span><span style="color: #cc66cc;">9</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #0000ff;">'postal_code'</span> <span style="color: #339933;">=&gt;</span> string <span style="color: #0000ff;">'94089'</span> <span style="color: #009900;">&#40;</span>length<span style="color: #339933;">=</span><span style="color: #cc66cc;">5</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #0000ff;">'latitude'</span> <span style="color: #339933;">=&gt;</span> float <span style="color:#800080;">37.4249000549</span><br />
<span style="color: #0000ff;">'longitude'</span> <span style="color: #339933;">=&gt;</span> float <span style="color: #339933;">-</span><span style="color:#800080;">122.007400513</span><br />
<span style="color: #0000ff;">'dma_code'</span> <span style="color: #339933;">=&gt;</span> int <span style="color: #cc66cc;">807</span><br />
<span style="color: #0000ff;">'area_code'</span> <span style="color: #339933;">=&gt;</span> int <span style="color: #cc66cc;">408</span></div></td></tr></tbody></table></div>
<p><br/><br />
With only an IP address we can easily get the country, postal code, longitude and latitude, and even the area code of the user.</p>
<p><strong>Performance</strong></p>
<p>I initially thought that the PECL version would outperform the pure PHP version by a small percentage. I was wrong. The PECL version was much faster. Here are some informal benchmarks. <br/></p>
<table id="benchmarks">
<tbody>
<tr>
<th></th>
<th>Iterations</th>
<th>Total</th>
<th>Avg</th>
<th>Notes</th>
</tr>
<tr>
<td>PECL GeoIP</td>
<td>10,000</td>
<td>0.7s</td>
<td>.007ms per request</td>
<td></td>
</tr>
<tr>
<td>Pure PHP</td>
<td>10,000</td>
<td>49.2s</td>
<td>4.92ms per request</td>
<td></td>
</tr>
<tr>
<td>PECL GeoIP</td>
<td>1</td>
<td>0.08ms</td>
<td>0.08ms per request</td>
<td>Typical real world usage</td>
</tr>
<tr>
<td>Pure PHP</td>
<td>1</td>
<td>2.4ms</td>
<td>2.4ms per request</td>
<td>Typical real world usage</td>
</tr>
</tbody>
</table>
<p>As a validation of my results I benchmarked the pure PHP library being used in a web application and had comparable results to my benchmarks (5.9ms per IP lookup versus the 2.4ms above).</p>
<p><strong>Conclusion</strong></p>
<p>Because of the ease of implementation, the low cost, and the minimal performance losses, there is much to be gained by adding IP Geolocation to your web application. The PECL package is the ideal configuration because it provides a faster experience with less code to maintain. The pure PHP library is none the less still relatively fast and thus still worth it. This is still far from a perfect solution. False positives can occur, anonymous proxies mess everything up, and IP addresses are constantly changing. Also, what about users&#8217; who simply do not want to share their location? There are privacy issues. This is currently a hot topic, with the <a href="http://dev.w3.org/geo/api/spec-source.html">W3C geolocation API</a> being actively worked on, including the efforts of <a href="http://labs.mozilla.com/2008/10/introducing-geode/">Mozilla</a>, <a href="http://labs.opera.com/news/2009/03/26/">Opera</a> and others to improve the situation of location awareness on the web, something I am looking forward to it.</p>
<p>More reading:</p>
<p><a href="http://www.slideshare.net/rsarver/w3c-geolocation-api-making-websites-locationaware">Interesting Geolocation presentation</a><br />
<a href="http://ca3.php.net/manual/en/ref.geoip.php">GeoIP functions in the PHP manual</a><br />
<a href="http://toys.lerdorf.com/archives/49-Select-from-World.html">Cool Geo* stuff at Y!</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.chehodgins.com/php/free-and-fast-geolocation-in-php/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Sorting out your PHP includes using Inclued</title>
		<link>http://www.chehodgins.com/php/sorting-out-your-php-includes-using-inclued/</link>
		<comments>http://www.chehodgins.com/php/sorting-out-your-php-includes-using-inclued/#comments</comments>
		<pubDate>Mon, 27 Apr 2009 17:07:14 +0000</pubDate>
		<dc:creator>chehodgins</dc:creator>
				<category><![CDATA[pecl]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[inclued]]></category>

		<guid isPermaLink="false">http://www.chehodgins.com/?p=188</guid>
		<description><![CDATA[This is the third edition of my weekly PECL package series. Check out my Scream article as well as my Sphinx article to learn about these extensions. If you have ever inherited spaghetti code or worse, written spaghetti code, the following article is for you. This article is an introduction to the Inclued PECL extension. [...]]]></description>
			<content:encoded><![CDATA[<p><strong>This is the third edition of my weekly PECL package series. Check out my <a href="http://www.chehodgins.com/programming/php/weekly-pecl-package-scream/">Scream article</a> as well as my <a href="http://www.chehodgins.com/php/search-improvements-using-sphinx-mysql-and-pecl/">Sphinx article</a> to learn about these extensions.</strong></p>
<p>If you have ever inherited spaghetti code or worse, written spaghetti code, the following article is for you. This article is an introduction to the <a href="http://pecl.php.net/package/inclued">Inclued PECL extension</a>. It helps answer the common question &#8220;Where is this include coming from?&#8221;, something that I&#8217;ve asked myself before when working on some projects.</p>
<p>This extension works by <a href="http://t3.dotgnu.info/blog/php/inclued-gives-you-clue.html">overriding an opcode in Zend</a>, allowing it to log information regarding which files are being included, and from where. This information can be collected using a single function named inclued_get_data() or by setting inclued.dumpdir in php.ini to dump the data of each request.</p>
<p>The final step involves graphing this data to get a view of the include hierarchy. This can be done by converting the JSON encoded output into a <a href="http://en.wikipedia.org/wiki/DOT_language">dot</a> language file, and then converting it to an image or viewing it with an application such as <a href="http://www.graphviz.org/Gallery.php">Graphviz</a>.</p>
<p>To start, we need to install the inclued PECL extension:</p>
<div class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">mbpro:~ chehodgins$ <span style="color: #c20cb9; font-weight: bold;">sudo</span> pecl <span style="color: #c20cb9; font-weight: bold;">install</span> inclued-alpha<br />
downloading inclued-0.1.0.tar ...<br />
<span style="color: #7a0874; font-weight: bold;">&#91;</span>...<span style="color: #7a0874; font-weight: bold;">&#93;</span><br />
<span style="color: #c20cb9; font-weight: bold;">install</span> ok: channel:<span style="color: #000000; font-weight: bold;">//</span>pecl.php.net<span style="color: #000000; font-weight: bold;">/</span>inclued-0.1.0</div></td></tr></tbody></table></div>
<p>And add to php.ini and restart apache:</p>
<div class="codecolorer-container ini default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="ini codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000099;">extension</span><span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;">inclued.so</span><br />
inclued.enabled<span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;">1</span><br />
inclued.dumpdir<span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;">/tmp</span></div></td></tr></tbody></table></div>
<p>Next, in our web browser we load the page that we wish to analyze. A file named inclued.*.* will be added to /tmp. We will convert to this to a dot file using the gengraph.php script that is included in the PECL package:</p>
<div class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">mbpro:tmp chehodgins$ php <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>php<span style="color: #000000; font-weight: bold;">/</span>gengraph.php <span style="color: #660033;">-i</span> inclued.00196.2<br />
Written inclued.out.dot...<br />
To generate images: dot <span style="color: #660033;">-Tpng</span> <span style="color: #660033;">-o</span> inclued.png inclued.out.dot</div></td></tr></tbody></table></div>
<p>Now we have the choice to either create a png using the dot command or simply opening with Graphviz.</p>
<div class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">mbpro:tmp chehodgins$ dot <span style="color: #660033;">-Tpng</span> <span style="color: #660033;">-o</span> ~<span style="color: #000000; font-weight: bold;">/</span>Documents<span style="color: #000000; font-weight: bold;">/</span>inclued.png inclued.out.dot</div></td></tr></tbody></table></div>
<p>And a super nice graph of the includes is generated as an image. Here is the graph of the includes in WordPress (click to view fullscreen):</p>
<div id="attachment_191" class="wp-caption aligncenter" style="width: 1034px"><a href="http://www.chehodgins.com/wp-content/uploads/2009/04/inclued.png"><img class="size-large wp-image-191" title="inclued" src="http://www.chehodgins.com/wp-content/uploads/2009/04/inclued-1024x311.png" alt="Inclued run on WordPress" width="1024" height="311" /></a><p class="wp-caption-text">Inclued run on WordPress</p></div>
<p>Notice that there are a lot of includes, but in general there appears to be order. Now let&#8217;s check out osCommerce:</p>
<div id="attachment_194" class="wp-caption aligncenter" style="width: 1033px"><a href="http://www.chehodgins.com/wp-content/uploads/2009/04/inclued-osc.png"><img class="size-large wp-image-194" title="inclued-osc" src="http://www.chehodgins.com/wp-content/uploads/2009/04/inclued-osc-1023x723.png" alt="Inclued on osCommerce" width="1023" height="723" /></a><p class="wp-caption-text">Inclued on osCommerce</p></div>
<p>This also looks decent. What about magento?</p>
<div id="attachment_217" class="wp-caption aligncenter" style="width: 818px"><a href="http://www.chehodgins.com/wp-content/uploads/2009/04/inclued-magento-small.png"><img class="size-large wp-image-217" title="inclued-magento-small" src="http://www.chehodgins.com/wp-content/uploads/2009/04/inclued-magento-small-808x1024.png" alt="Inclued in Magento" width="808" height="1024" /></a><p class="wp-caption-text">Inclued in Magento</p></div>
<p>Holy crap, thats a lot of includes!</p>
<p>In conclusion, the inclued PECL extension can be useful in many situations, from trying to understand how and<br />
why a file is being included, to reorganizing your includes by seeing the dependencies. If anything, it can be an<br />
easy way to show off your application/framework&#8217;s include structure.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.chehodgins.com/php/sorting-out-your-php-includes-using-inclued/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Search improvements using Sphinx, MySQL and PECL</title>
		<link>http://www.chehodgins.com/php/search-improvements-using-sphinx-mysql-and-pecl/</link>
		<comments>http://www.chehodgins.com/php/search-improvements-using-sphinx-mysql-and-pecl/#comments</comments>
		<pubDate>Sat, 18 Apr 2009 13:21:42 +0000</pubDate>
		<dc:creator>chehodgins</dc:creator>
				<category><![CDATA[pecl]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[sphinx]]></category>

		<guid isPermaLink="false">http://www.chehodgins.com/?p=164</guid>
		<description><![CDATA[This is the second edition of my weekly PECL package series. See last week&#8217;s post to learn about the Scream extension. This week&#8217;s topic will be on Full-Text searching using Sphinx, specifically with the PHP client extension written by Antony Dovgal and released as a 1.0 PECL package in late January 2009. Background Sphinx is [...]]]></description>
			<content:encoded><![CDATA[<p><strong>This is the second edition of my weekly PECL package series. See <a href="http://www.chehodgins.com/programming/php/weekly-pecl-package-scream/">last week&#8217;s post</a> to learn about the Scream extension.</strong></p>
<p>This week&#8217;s topic will be on Full-Text searching using Sphinx, specifically with the <a href="http://pecl.php.net/package/sphinx">PHP client extension</a> written by Antony Dovgal and released as a 1.0 PECL package in late January 2009.</p>
<p><strong>Background</strong></p>
<p>Sphinx is an open source full-text search engine. It provides an alternative to MySQL full-text searching. Its main features include high search speed (avg query is under 0.1 sec on 2-4 GB text collections), high scalability (up to 100 GB of text, up to 100 M documents on a single CPU) and most importantly, <a href="http://www.sphinxsearch.com/docs/current.html#intro">native support for MySQL</a> (MyISAM and InnoDB) and PostgreSQL . It has also proven its worth considering that it is used on web sites such as <a href="http://jeremy.zawodny.com/blog/archives/010869.html">Craigslist</a>, <a href="http://www.slideshare.net/_jayme/scaling-optimizing-search-on-netlog-presentation">Netlog</a>, and <a href="http://www.sphinxsearch.com/powered.html">The Pirate Bay</a>.</p>
<p><strong>Sphinx Install</strong></p>
<p>There are two methods of using Sphinx in PHP: Using the PHP API or using the native libaries with the PECL package. We will of course be covering the PECL version <img src='http://www.chehodgins.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Installation a basic version of sphinx is easy:</p>
<div class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">mbpro:sphinx-0.9.8.1 chehodgins$ <span style="color: #c20cb9; font-weight: bold;">sudo</span> .<span style="color: #000000; font-weight: bold;">/</span>configure <span style="color: #660033;">--prefix</span> <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>share<span style="color: #000000; font-weight: bold;">/</span>sphinx <span style="color: #660033;">--with-mysql</span> <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>share<span style="color: #000000; font-weight: bold;">/</span>mysql<span style="color: #000000; font-weight: bold;">/</span><br />
mbpro:sphinx-0.9.8.1 chehodgins$ <span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">make</span><br />
mbpro:sphinx-0.9.8.1 chehodgins$ <span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">make</span> <span style="color: #c20cb9; font-weight: bold;">install</span></div></td></tr></tbody></table></div>
<p>Next, using the sphinx.conf configuration file a data source and index must be defined. I have added a table named `track` in my MySQL database with 7.8 million track names.</p>
<div class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">mbpro:etc chehodgins$ <span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">cp</span> sphinx.conf.dist sphinx.conf<br />
mbpro:etc chehodgins$ <span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">vi</span> sphinx.conf</div></td></tr></tbody></table></div>
<p>In sphinx.conf:</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">source track<br />
{<br />
type                                    = mysql<br />
<br />
sql_host                                = localhost<br />
sql_user                                = root<br />
sql_pass                                = root<br />
sql_db                                  = test<br />
sql_port                                = 3306<br />
<br />
sql_sock                                = /Applications/MAMP/tmp/mysql/mysql.sock<br />
sql_query_pre                 = SET NAMES utf8<br />
<br />
# the data to be indexed<br />
sql_query  = SELECT id, name, length, year FROM track;<br />
<br />
}<br />
<br />
index track_index<br />
{<br />
# document source(s) to index<br />
source                  = track<br />
<br />
# index files path and file name, without extension<br />
# mandatory, path must be writable, extensions will be auto-appended<br />
path                    = /usr/local/share/sphinx/var/data/track_index<br />
<br />
min_word_len            = 1<br />
}</div></td></tr></tbody></table></div>
<p>We can now index our data and start the sphinx server:</p>
<div class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">mbpro:sphinx chehodgins$ <span style="color: #c20cb9; font-weight: bold;">sudo</span> bin<span style="color: #000000; font-weight: bold;">/</span>indexer track_index<br />
mbpro:sphinx chehodgins$ <span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>share<span style="color: #000000; font-weight: bold;">/</span>sphinx<span style="color: #000000; font-weight: bold;">/</span>bin<span style="color: #000000; font-weight: bold;">/</span>searchd<br />
<br />
Sphinx 0.9.8.1-release <span style="color: #7a0874; font-weight: bold;">&#40;</span>r1533<span style="color: #7a0874; font-weight: bold;">&#41;</span><br />
Copyright <span style="color: #7a0874; font-weight: bold;">&#40;</span>c<span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #000000;">2001</span>-<span style="color: #000000;">2008</span>, Andrew Aksyonoff<br />
<br />
using config <span style="color: #c20cb9; font-weight: bold;">file</span> <span style="color: #ff0000;">'/usr/local/share/sphinx/etc/sphinx.conf'</span>...<br />
creating server socket on 0.0.0.0:<span style="color: #000000;">3312</span></div></td></tr></tbody></table></div>
<p>The data indexing took 1 minute on 7.8 million rows (204 MB of data) at a speed of 116655.16 docs/sec! Note that indexing should be done on regular intervals, depending on how fresh the data is required to be. </p>
<p><strong>PHP/PECL Install</strong></p>
<p>With our data indexed we must now get access to the Sphinx API. This is done using the Sphinx PECL extension. Before installating the PECL package we must install libsphinxclient, which is included in the Sphinx distribution:</p>
<div class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">mbpro:libsphinxclient chehodgins$ <span style="color: #7a0874; font-weight: bold;">cd</span> sphinx-0.9.8.1<span style="color: #000000; font-weight: bold;">/</span>api<span style="color: #000000; font-weight: bold;">/</span>libsphinxclient<span style="color: #000000; font-weight: bold;">/</span><br />
mbpro:libsphinxclient chehodgins$ <span style="color: #007800;">LIBTOOLIZE</span>=glibtoolize <span style="color: #c20cb9; font-weight: bold;">sudo</span> .<span style="color: #000000; font-weight: bold;">/</span>buildconf.sh<br />
mbpro:libsphinxclient chehodgins$ <span style="color: #c20cb9; font-weight: bold;">sudo</span> .<span style="color: #000000; font-weight: bold;">/</span>configure <span style="color: #000000; font-weight: bold;">&amp;&amp;</span> <span style="color: #c20cb9; font-weight: bold;">make</span> <span style="color: #c20cb9; font-weight: bold;">install</span></div></td></tr></tbody></table></div>
<p>Now we are ready to install the PECL package:</p>
<div class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">mbpro:~ chehodgins$ <span style="color: #c20cb9; font-weight: bold;">sudo</span> pecl <span style="color: #c20cb9; font-weight: bold;">install</span> sphinx</div></td></tr></tbody></table></div>
<p>Now it must be added to php.ini:</p>
<div class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #007800;">extension</span>=sphinx.so</div></td></tr></tbody></table></div>
<p>Restart apache and check that it is installed:</p>
<div id="attachment_165" class="wp-caption aligncenter" style="width: 645px"><a href="http://www.chehodgins.com/wp-content/uploads/2009/04/picture-2.png"><img class="size-full wp-image-165" title="sphinx in phpinfo" src="http://www.chehodgins.com/wp-content/uploads/2009/04/picture-2.png" alt="Sphinx in phpinfo" width="635" height="128" /></a><p class="wp-caption-text">Sphinx in phpinfo</p></div>
<p>Now it&#8217;s simply a matter of using the <a title="Sphinx api reference" href="http://php.net/sphinx">Sphinx function reference</a> on php.net to query your dataset.</p>
<div class="codecolorer-container php default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></div></td><td><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">&lt;?php</span><br />
<br />
<span style="color: #000088;">$sphinx</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> SphinxClient<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$sphinx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setServer</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;localhost&quot;</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">3312</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$sphinx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setMatchMode</span><span style="color: #009900;">&#40;</span>SPH_MATCH_ALL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$sphinx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setMaxQueryTime</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">500</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// Limit query to 500 milliseconds</span><br />
<span style="color: #000088;">$sphinx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setLimits</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">10</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1000</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// return first 10 results</span><br />
<br />
<span style="color: #000088;">$result</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$sphinx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">query</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Ride the Lightning'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #990000;">var_dump</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$result</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'matches'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$result</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'total_found'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">' total results found.'</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">?&gt;</span></div></td></tr></tbody></table></div>
<p>Thanks to the Sphinx log, you can see that the query executed in .042 seconds:</p>
<div class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #7a0874; font-weight: bold;">&#91;</span>Sat Apr <span style="color: #000000;">18</span> 01:<span style="color: #000000;">33</span>:<span style="color: #000000;">58.878</span> <span style="color: #000000;">2009</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> <span style="color: #000000;">0.042</span> sec <span style="color: #7a0874; font-weight: bold;">&#91;</span>all<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">0</span><span style="color: #000000; font-weight: bold;">/</span>rel <span style="color: #000000;">160</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">0</span>,<span style="color: #000000;">10</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000; font-weight: bold;">*</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> Ride the Lightning</div></td></tr></tbody></table></div>
<p><strong>Conclusion</strong></p>
<p>The example was kept simple, but queries can be refined even more using SQL-like methods of the Sphinx API. Notably, setGroupBy() will do the equivalent of GROUP BY and ORDER BY. Also, setFilter() will add extra filtering on other columns in the dataset.</p>
<p>This is the tip of the iceberg of the different ways that Sphinx can be used. The easy integration with MySQL combined with the ease of setup make it a logical next step when MySQL&#8217;s Full-Text indexing <a href="http://pooteeweet.org/blog/1359">performance degrades</a>. It also appears capable of scaling to the needs of the top-tiered websites out there. As such, I would seriously consider Sphinx when looking for solutions to your searching needs.</p>
<p>Finally, it would be worthwhile to explore alternatives such as <a href="http://lucene.apache.org/java/docs/">Lucene</a> (Java), <a title="Solr search" href="http://http://lucene.apache.org/solr/">Solr</a> (Java), and <a href="http://code.google.com/p/marjory/">Marjory</a> (PHP).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.chehodgins.com/php/search-improvements-using-sphinx-mysql-and-pecl/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Weekly PECL Package &#8211; Scream</title>
		<link>http://www.chehodgins.com/php/weekly-pecl-package-scream/</link>
		<comments>http://www.chehodgins.com/php/weekly-pecl-package-scream/#comments</comments>
		<pubDate>Thu, 09 Apr 2009 04:46:42 +0000</pubDate>
		<dc:creator>chehodgins</dc:creator>
				<category><![CDATA[pecl]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://www.chehodgins.com/?p=132</guid>
		<description><![CDATA[This is the first of what is planned to be a weekly post on a more or less random PECL package. The idea is for me to get to know some PECL packages in more detail and for you to get to know some PECL packages in more detail &#8211; without losing your precious time. [...]]]></description>
			<content:encoded><![CDATA[<p>This is the first of what is planned to be a weekly post on a more or less random PECL package. The idea is for me to get to know some PECL packages in more detail and for you to get to know some PECL packages in more detail &#8211; without losing your precious time.</p>
<p>For the first edition of this series I will cover the relatively new PECL package aptly named <a href="http://pecl.php.net/package/scream">Scream</a>. The purpose of this extension is to, well, scream. It will disable the the silence operator (@) so that any hidden errors will still be shown. After this, you may scream at whoever used the silence operator in the first place &#8211; thus the name Scream (Just kidding?).</p>
<p>Lets get started&#8230;</p>
<div class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">che-hodginss-macbook-pro:~ chehodgins$ <span style="color: #c20cb9; font-weight: bold;">sudo</span> pecl <span style="color: #c20cb9; font-weight: bold;">install</span> scream-alpha</div></td></tr></tbody></table></div>
<p>After a few minutes&#8230;</p>
<div class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Build process completed successfully<br />
Installing <span style="color: #ff0000;">'/usr/local/lib/php/extensions/no-debug-non-zts-20060613/scream.so'</span><br />
<span style="color: #c20cb9; font-weight: bold;">install</span> ok: channel:<span style="color: #000000; font-weight: bold;">//</span>pecl.php.net<span style="color: #000000; font-weight: bold;">/</span>scream-0.1.0</div></td></tr></tbody></table></div>
<p>Great, now add it to php.ini and restart apache:</p>
<div class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #007800;">extension</span>=scream.so<br />
scream.enabled=<span style="color: #000000;">1</span></div></td></tr></tbody></table></div>
<p>Check phpinfo and we are ready to go:</p>
<div id="attachment_160" class="wp-caption alignleft" style="width: 623px"><a href="http://www.chehodgins.com/wp-content/uploads/2009/04/picture-12.png"><img class="size-full wp-image-160" title="picture-12" src="http://www.chehodgins.com/wp-content/uploads/2009/04/picture-12.png" alt="I'm new to macs and just discovered taking screenshots of portions of the screen (Apple key ⌘ + Shift + 4). Very cool." width="613" height="175" /></a><p class="wp-caption-text">I&#39;m new to macs and just discovered taking screenshots of portions of the screen (Apple key ⌘ + Shift + 4). Very cool.</p></div>
<p><br/><br/><br/><br/><br/><br/><br/><br/><br/><br />
<br/><br/><br/><br/><br/><br />
Now we will borrow some code from some open source projects that use the silence operator and see what happens.<br />
<br/></p>
<div class="codecolorer-container php default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br /></div></td><td><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #990000;">ini_set</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'display_errors'</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #990000;">error_reporting</span><span style="color: #009900;">&#40;</span><span style="color: #009900; font-weight: bold;">E_ALL</span> <span style="color: #339933;">|</span> <span style="color: #009900; font-weight: bold;">E_STRICT</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'starting... '</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #666666; font-style: italic;">// Initialize</span><br />
<span style="color: #000088;">$host</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$user</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$password</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$sock</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$port</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$errno</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$errstr</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$response</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #666666; font-style: italic;">// From Joomla!</span><br />
<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$resource</span> <span style="color: #339933;">=</span> <span style="color: #339933;">@</span><span style="color: #990000;">mysql_connect</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$host</span><span style="color: #339933;">,</span> <span style="color: #000088;">$user</span><span style="color: #339933;">,</span> <span style="color: #000088;">$password</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">true</span> <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
<span style="color: #666666; font-style: italic;">// ...</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #666666; font-style: italic;">// From Wordpress</span><br />
<span style="color: #000088;">$response</span> <span style="color: #339933;">.=</span> <span style="color: #339933;">@</span> <span style="color: #990000;">fread</span> <span style="color: #009900;">&#40;</span> <span style="color: #000088;">$sock</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">8192</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #666666; font-style: italic;">// From Joomla!</span><br />
<span style="color: #339933;">@</span> <span style="color: #990000;">dl</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'bz2.so'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #666666; font-style: italic;">// From Wordpress</span><br />
<span style="color: #000088;">$sock</span> <span style="color: #339933;">=</span> <span style="color: #339933;">@</span><span style="color: #990000;">fsockopen</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$host</span><span style="color: #339933;">,</span> <span style="color: #000088;">$port</span><span style="color: #339933;">,</span> <span style="color: #000088;">$errno</span><span style="color: #339933;">,</span> <span style="color: #000088;">$errstr</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;done.<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">?&gt;</span></div></td></tr></tbody></table></div>
<p><br/><br />
With scream.enabled = 0 we get this lovely output:</p>
<div class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">che-hodginss-macbook-pro:www chehodgins$ php <span style="color: #660033;">-f</span> scream.php<br />
starting... done.<br />
che-hodginss-macbook-pro:www chehodgins$</div></td></tr></tbody></table></div>
<p>And with scream.enabled = 1:</p>
<div class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">che-hodginss-macbook-pro:www chehodgins$ php <span style="color: #660033;">-f</span> scream.php<br />
starting...<br />
Warning: fread<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>: supplied argument is not a valid stream resource <span style="color: #000000; font-weight: bold;">in</span> <span style="color: #000000; font-weight: bold;">/</span>Users<span style="color: #000000; font-weight: bold;">/</span>chehodgins<span style="color: #000000; font-weight: bold;">/</span>www<span style="color: #000000; font-weight: bold;">/</span>scream.php on line <span style="color: #000000;">17</span><br />
<br />
Warning: dl<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>: Unable to load dynamic library <span style="color: #ff0000;">'/Applications/MAMP/bin/php5/lib/php/extensions/no-debug-non-zts-20050922/bz2.so'</span> - <span style="color: #7a0874; font-weight: bold;">&#40;</span>null<span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #000000; font-weight: bold;">in</span> <span style="color: #000000; font-weight: bold;">/</span>Users<span style="color: #000000; font-weight: bold;">/</span>chehodgins<span style="color: #000000; font-weight: bold;">/</span>www<span style="color: #000000; font-weight: bold;">/</span>scream.php on line <span style="color: #000000;">20</span><br />
<br />
Warning: fsockopen<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> expects parameter <span style="color: #000000;">2</span> to be long, string given <span style="color: #000000; font-weight: bold;">in</span> <span style="color: #000000; font-weight: bold;">/</span>Users<span style="color: #000000; font-weight: bold;">/</span>chehodgins<span style="color: #000000; font-weight: bold;">/</span>www<span style="color: #000000; font-weight: bold;">/</span>scream.php on line <span style="color: #000000;">23</span><br />
done.<br />
<br />
che-hodginss-macbook-pro:www chehodgins$</div></td></tr></tbody></table></div>
<p><br/></p>
<p>It is obvious at this moment that in general it is not advisable to use the silence operator. Most PHP programmers have been burnt by this a few times and usually will be much more harsh towards those think this feature is useful. I can recall spending lots of time bug hunting before finding an @ which lead me to a simple error. Its a painful experience, don&#8217;t do it.</p>
<p>As a programmer you may already steer clear of the silence operator but much code is inherited. Because of the simplicity of the silence operator it can be hard to track down where it is used in your code. Try searching for &#8216;@&#8217; in one of your projects, how many thousands of results do you get? That is one reason to install this on your dev box and find those tough bugs before they hit production.</p>
<p>And just in case you are still not convinced, check out <a href="http://derickrethans.nl/five_reasons_why_the_shutop_operator_@_should_be_avoided.php">Five reasons the shut-up operator (@) should be avoided</a> by Derick Rethans</p>
]]></content:encoded>
			<wfw:commentRss>http://www.chehodgins.com/php/weekly-pecl-package-scream/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

