<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
  <channel>
    <title>Derick Rethans - tag: php</title>
    <link>http://derickrethans.nl/feed-php.xml</link>
    <description>This feed shows the latest 15 items with the tag php</description>
    <language>en-us</language>
    <copyright>All rights reserved - Derick Rethans</copyright>
    <managingEditor>derick@derickrethans.nl (Derick Rethans)</managingEditor>
    <pubDate>Thu, 05 Jan 2012 08:06:05 +0000</pubDate>
    <lastBuildDate>Thu, 05 Jan 2012 08:06:05 +0000</lastBuildDate>
    <generator>eZ Components Feed dev (http://ezcomponents.org/docs/tutorials/Feed)</generator>
    <docs>http://www.rssboard.org/rss-specification</docs>
    <ttl>60</ttl>
    <item>
      <title>OpenStreetMap: A Year of Edits</title>
      <link>http://derickrethans.nl/year-of-edits.html</link>
      <description>&lt;div class="article"&gt;
  &lt;div class="body"&gt;
    &lt;div class="articleListItem"&gt;
      &lt;h1&gt;&lt;a name="openstreetmap_a_year_of_edits"/&gt;OpenStreetMap: A Year of Edits&lt;/h1&gt;
      &lt;dl class="head"/&gt;
      &lt;div class="articleMetaData"&gt;
        &lt;div class="location"&gt; London, UK&lt;/div&gt;
        &lt;div class="date"&gt;Sunday, January 1st 2012, 00:00 GMT&lt;/div&gt;
      &lt;/div&gt;
      &lt;p&gt;In the past weeks I've been working on some visualisations related to additions and changes being made to OpenStreetMap. To start of the new year, I hereby present: &lt;strong&gt;OpenStreetMap: A Year of Edits (2011)&lt;/strong&gt;:&lt;/p&gt;
      &lt;div class="video"&gt;
        &lt;iframe src="http://player.vimeo.com/video/34404102?title=0&amp;byline=0&amp;portrait=0" width=" 599" height=" 337" frameborder="0"/&gt;
        &lt;p&gt;&lt;a href="http://vimeo.com/34404102"/&gt;OpenStreetMap: A Year of Edits (2011)&lt;/p&gt;
      &lt;/div&gt;
      &lt;p&gt;You can see the video in HD on &lt;a href="http://vimeo.com/derickr/osm-2011"&gt;Vimeo&lt;/a&gt;. &lt;strong&gt;Happy New Year!&lt;/strong&gt;&lt;/p&gt;
      &lt;p&gt;
        &lt;em&gt;How Did He Do That?&lt;/em&gt;
      &lt;/p&gt;
      &lt;p&gt;This animation is all made with Open Source software. I haven't had the time to clean up the code to make it releasable yet, but I am intending to do that in the near feature and add it to my &lt;a href="https://github.com/derickr/osm-tools"&gt;OpenStreetMap tools&lt;/a&gt; git repository on github.&lt;/p&gt;
      &lt;p&gt;The first thing I did, was download all the hourly replication files from &lt;a href="http://planet.openstreetmap.org/hour-replicate"&gt;http://planet.openstreetmap.org/hour-replicate&lt;/a&gt; for the year.&lt;/p&gt;
      &lt;p&gt;With a script, I scanned over all those XML files and for every three hours I created an image showing the edits of those last three hours (in white), as well as all the other edits in the background (in purple). With 4 frames per day, this gives me 1460 frames.&lt;/p&gt;
      &lt;p&gt;Each of the frames is an equirectangular projection which I then map onto a sphere with a faded background of "earthmap10k" of &lt;a href="http://planetpixelemporium.com/earth.html"&gt;http://planetpixelemporium.com/earth.html&lt;/a&gt; (I downloaded it &lt;em&gt;years&lt;/em&gt; ago when it was still free to download). For the 3D rendering of the Earth with the edits layed on top of it I used &lt;a href="http://www.povray.org/"&gt;POV-Ray&lt;/a&gt;.&lt;/p&gt;
      &lt;p&gt;I generated two different loops so that I can make two full rotations at different angles. This gives me in total 2882 frames which is about two minutes. The POV-Ray generated images I post-processed by overlaying the progress bar in the lower left and added the fading and merging effects. Then I used &lt;a href="http://www.mplayerhq.hu/"&gt;mencoder&lt;/a&gt; to create a MPEG video out of it.  Finally I added the &lt;a href="http://www.archive.org/details/TBECD005-MP3-192k-VBR"&gt;sound track&lt;/a&gt; again by using mencoder and uploaded it to &lt;a href="http://vimeo.com/derickr/osm-2011"&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;
      &lt;div class="flattr"&gt;
        &lt;a class="FlattrButton" rev="flattr;button:compact;" style="display: none" href="http://derickrethans.nl"/&gt;
        &lt;noscript&gt;
          &lt;a href="http://flattr.com/thing/429095/Derick-Rethans-website"&gt;
            &lt;img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this"/&gt;
          &lt;/a&gt;
        &lt;/noscript&gt;
      &lt;/div&gt;
      
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>201201010000</guid>
      <pubDate>Sun, 01 Jan 2012 00:00:00 +0000</pubDate>
    </item>
    <item>
      <title>Twig extension</title>
      <link>http://derickrethans.nl/twig-extension.html</link>
      <description>&lt;div class="article"&gt;
  &lt;div class="body"&gt;
    &lt;div class="articleListItem"&gt;
      &lt;h1&gt;&lt;a name="twig_extension"/&gt;Twig extension&lt;/h1&gt;
      &lt;dl class="head"/&gt;
      &lt;div class="articleMetaData"&gt;
        &lt;div class="location"&gt; London, UK&lt;/div&gt;
        &lt;div class="date"&gt;Monday, November 21st 2011, 09:20 GMT&lt;/div&gt;
      &lt;/div&gt;
      &lt;p&gt;A while ago, &lt;a href="http://github.com/fabpot"&gt;Fabien&lt;/a&gt; asked me to have a look at porting one of &lt;a href="http://twig.sensiolabs.org/"&gt;Twig's&lt;/a&gt; slowest methods, &lt;code&gt;TwigTemplate::getAttribute()&lt;/code&gt;, into a PHP extension. It is a complex method that does a lot of different checks and look-ups. Fabien's benchmarks showed that this method was responsible for quite a large amount of time. On top of that, it didn't seem that it could be optimised any further as PHP code itself. Seeing that it was very likely that this method would be a lot faster when written in C, &lt;a href="http://sensiolabs.com/"&gt;SensioLabs&lt;/a&gt; decided to sponser me for the development of a port of this method into a PHP extension.&lt;/p&gt;
      &lt;p&gt;Over the next few months I've worked on re-implementing just this method as a C-function in &lt;a href="https://github.com/derickr/twig-ext"&gt;twig-ext&lt;/a&gt;: &lt;code&gt;twig_template_get_attributes()&lt;/code&gt;. From initial benchmarks it looks like this function as implemented in the extension gives about a 15% speed increase while rendering templates. Twig's compiled templates directly contain a call to this function (as opposed to marshal it through the original &lt;code&gt;TwigTemplate::getAttribute()&lt;/code&gt; method) for additional performance. This probably means that you'll have to remove your compiled templates cache while upgrading.&lt;/p&gt;
      &lt;p&gt;The extension at &lt;a href="http://github.com/derickr/twig-ext"&gt;http://github.com/derickr/twig-ext&lt;/a&gt; has now been merged, via &lt;a href="http://github.com/derickr/Twig"&gt;http://github.com/derickr/Twig&lt;/a&gt;, into &lt;a href="http://github.com/fabpot/Twig"&gt;http://github.com/fabpot/Twig&lt;/a&gt;. The plan is that this new improvement is going to be part of Twig 1.4.&lt;/p&gt;
      &lt;p&gt;If you are also interested in having some of your PHP code ported into a PHP extension in C, please feel free to &lt;a href="http://derickrethans.nl/who.html"&gt;contact&lt;/a&gt; me.&lt;/p&gt;
      &lt;div class="flattr"&gt;
        &lt;a class="FlattrButton" rev="flattr;button:compact;" style="display: none" href="http://derickrethans.nl"/&gt;
        &lt;noscript&gt;
          &lt;a href="http://flattr.com/thing/429095/Derick-Rethans-website"&gt;
            &lt;img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this"/&gt;
          &lt;/a&gt;
        &lt;/noscript&gt;
      &lt;/div&gt;
      
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>201111210920</guid>
      <pubDate>Mon, 21 Nov 2011 09:20:00 +0000</pubDate>
    </item>
    <item>
      <title>Multiple PHP versions set-up</title>
      <link>http://derickrethans.nl/multiple-php-version-setup.html</link>
      <description>&lt;div class="article"&gt;
  &lt;div class="body"&gt;
    &lt;div class="articleListItem"&gt;
      &lt;h1&gt;&lt;a name="multiple_php_versions_set-up"/&gt;Multiple PHP versions set-up&lt;/h1&gt;
      &lt;dl class="head"/&gt;
      &lt;div class="articleMetaData"&gt;
        &lt;div class="location"&gt; London, UK&lt;/div&gt;
        &lt;div class="date"&gt;Monday, November 7th 2011, 09:11 GMT&lt;/div&gt;
      &lt;/div&gt;
      &lt;p&gt;For many of my projects (both &lt;a href="http://derickrethans.nl/projects.html"&gt;hobby&lt;/a&gt; and &lt;a href="http://derickrethans.nl/who.html#derickrethansltd"&gt;commercial&lt;/a&gt;) I need to support many different PHP configurations. Not only just different PHP versions, but also debug builds, ZTS builds and 32-bit builds. In order to be able to test and build extensions against all those different PHP configurations I have adopted a simple method that I'm sharing with you here.&lt;/p&gt;
      &lt;p&gt;The major part of it is that I use a different installation prefix for every configuration of PHP that I make. Right now, &lt;code&gt;ls /usr/local/php&lt;/code&gt; shows:&lt;/p&gt;
      &lt;pre&gt;5.1dev  5.3.2  5.3.8dev  5.3dev-32bit    5.3dev-zts  5.4dev      trunk
5.2dev  5.3.7  5.3dev    5.3dev-nodebug  5.4.0beta1  5.4dev-zts

&lt;/pre&gt;
      &lt;p&gt;There are two types of PHP installs that I make: "dev" versions from SVN branches, and "release" versions build from SVN tags. From the list above you see I have the SVN versions of 5.1, 5.2, 5.3.8, 5.3 (in various forms) and 5.4 (both normal, and ZTS).&lt;/p&gt;
      &lt;p&gt;I have a &lt;a href="http://derickrethans.nl/files/php-build.sh.txt"&gt;script&lt;/a&gt; to compile PHP which whatever combination I want: version, debug (default) or non-debug, normal (default) or ZTS; and 64-bit (default) or 32-bit. The configure options are nicely hardcoded :-)&lt;/p&gt;
      &lt;p&gt;The scripts accept arguments in a specific order:&lt;/p&gt;
      &lt;pre&gt;version ["debug"|"nodebug" [, "no-zts"|"zts" [, ""|"32bit" ] ] ]

&lt;/pre&gt;
      &lt;p&gt;For a simple 5.3dev build I run:&lt;/p&gt;
      &lt;pre&gt;./build 5.3dev

&lt;/pre&gt;
      &lt;p&gt;This compiles PHP 5.3 from SVN, in debug mode, without ZTS and for the 64-bit architecture. Something more exotic variants could be:&lt;/p&gt;
      &lt;pre&gt;./build 5.3.8 debug zts
./build 5.4dev nodebug no-zts 32bit

&lt;/pre&gt;
      &lt;p&gt;Each invocation of the script will configure and build PHP, and then install into &lt;code&gt;/usr/local/php/{{variant}}&lt;/code&gt;.&lt;/p&gt;
      &lt;p&gt;The script also has a hard coded location where the PHP sources are. In my case, that's a &lt;a href="https://wiki.php.net/vcs/svnfaq#sparse_directory_checkout_instructions"&gt;sparse checkout&lt;/a&gt; into &lt;code&gt;/home/derick/dev/php/php-src&lt;/code&gt;.&lt;/p&gt;
      &lt;p&gt;With the help of a small &lt;code&gt;.bashrc&lt;/code&gt; snippet:&lt;/p&gt;
      &lt;pre&gt;function pe () {
        version=$1
        shift

        if [ "$#" == "0" ]; then
                export PATH=/usr/local/php/${version}/bin:/usr/local/bin:/usr/bin:/bin
        else
                PATH=/usr/local/php/${version}/bin:$PATH $@
        fi
}

&lt;/pre&gt;
      &lt;p&gt;I can now easily switch between PHP versions by typing on the shell:&lt;/p&gt;
      &lt;pre&gt;pe 5.3dev

&lt;/pre&gt;
      &lt;p&gt;or:&lt;/p&gt;
      &lt;pre&gt;pe 5.4dev-zts

&lt;/pre&gt;
      &lt;p&gt;And each version will have a totally separated environment for me to install PEAR packages and PECL extensions in, and do my own extension development. Of course, each separated environment also comes with its own &lt;code&gt;php.ini&lt;/code&gt; file (in &lt;code&gt;/usr/local/php/{{variant}}/lib/php.ini&lt;/code&gt;).&lt;/p&gt;
      &lt;p&gt;This set-up makes my life a whole lot easier, and I hope it is useful for you as well. Thanks for listening!&lt;/p&gt;
      &lt;div class="flattr"&gt;
        &lt;a class="FlattrButton" rev="flattr;button:compact;" style="display: none" href="http://derickrethans.nl"/&gt;
        &lt;noscript&gt;
          &lt;a href="http://flattr.com/thing/429095/Derick-Rethans-website"&gt;
            &lt;img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this"/&gt;
          &lt;/a&gt;
        &lt;/noscript&gt;
      &lt;/div&gt;
      
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>201111070911</guid>
      <pubDate>Mon, 07 Nov 2011 09:11:00 +0000</pubDate>
    </item>
    <item>
      <title>Xdebug's Code Coverage speedup</title>
      <link>http://derickrethans.nl/xdebug-codecoverage-speedup.html</link>
      <description>&lt;div class="article"&gt;
  &lt;div class="body"&gt;
    &lt;div class="articleListItem"&gt;
      &lt;h1&gt;&lt;a name="xdebug_s_code_coverage_speedup"/&gt;Xdebug's Code Coverage speedup&lt;/h1&gt;
      &lt;dl class="head"/&gt;
      &lt;div class="articleMetaData"&gt;
        &lt;div class="location"&gt; London, UK&lt;/div&gt;
        &lt;div class="date"&gt;Friday, September 23rd 2011, 09:23 BST&lt;/div&gt;
      &lt;/div&gt;
      &lt;p&gt;Besides a debugging and development aid, &lt;a href="http://xdebug.org"&gt;Xdebug&lt;/a&gt; also implements the back-end code to provide code coverage information for use with &lt;a href="http://www.phpunit.de"&gt;PHPUnit&lt;/a&gt;. Code coverage tells you how much of your code base is actually being tested by your unit tests. It's a very useful feature, but sadly, it slows down PHP's execution quite a lot. One part of this slowdown is the overhead to record the information internally, but another part is because I have to overload lots of opcodes. (Opcodes are PHP's internal execution units, similar to &lt;a href="http://en.wikipedia.org/wiki/Assembler_%28computer_programming%29#Assembly_language"&gt;assembler&lt;/a&gt; instructions) They are always overloaded even if code coverage is not used, because it's only safe to overload them for the whole request.&lt;/p&gt;
      &lt;p&gt;The upcoming Xdebug 2.2 has a few changes to improve code coverage performance. First of all, the speed with which information about code coverage is recorded has been improved by &lt;a href="https://github.com/taavi/xdebug/commits/coverage_line_array"&gt;contributions&lt;/a&gt; by &lt;a href="https://github.com/taavi"&gt;Taavi Burns&lt;/a&gt;. And secondly, Xdebug 2.2 features a new setting, &lt;code&gt;xdebug.coverage_enable&lt;/code&gt; with which it is possible to disable the overloading of code coverage specific opcodes. By default that setting will still be &lt;code&gt;on&lt;/code&gt;.&lt;/p&gt;
      &lt;p&gt;Just to show how those improvements have effect on the speed, I've run a benchmark (running &lt;a href="http://incubator.apache.org/zetacomponents/"&gt;Apache Zeta Components&lt;/a&gt; Graph's tests) to compare Xdebug 2.1.2 against Xdebug 2.2-dev.&lt;/p&gt;
      &lt;p&gt;The results are as follows:&lt;/p&gt;
      &lt;table&gt;
        &lt;thead&gt;
          &lt;tr&gt;
            &lt;td&gt;
              &lt;p&gt;Version  &lt;/p&gt;
            &lt;/td&gt;
            &lt;td&gt;
              &lt;p&gt;With CC  &lt;/p&gt;
            &lt;/td&gt;
            &lt;td&gt;
              &lt;p&gt;Without CC  &lt;/p&gt;
            &lt;/td&gt;
            &lt;td&gt;
              &lt;p&gt;With coverage_enable=0  &lt;/p&gt;
            &lt;/td&gt;
            &lt;td&gt;
              &lt;p&gt;Without Xdebug&lt;/p&gt;
            &lt;/td&gt;
          &lt;/tr&gt;
        &lt;/thead&gt;
        &lt;tbody&gt;
          &lt;tr&gt;
            &lt;td&gt;
              &lt;p&gt;2.1.2    &lt;/p&gt;
            &lt;/td&gt;
            &lt;td&gt;
              &lt;p&gt;06:44    &lt;/p&gt;
            &lt;/td&gt;
            &lt;td&gt;
              &lt;p&gt;00:49       &lt;/p&gt;
            &lt;/td&gt;
            &lt;td&gt;
              &lt;p&gt;&lt;em&gt;not available&lt;/em&gt;         &lt;/p&gt;
            &lt;/td&gt;
            &lt;td&gt;
              &lt;p&gt;00:32&lt;/p&gt;
            &lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td&gt;
              &lt;p&gt;2.2-dev  &lt;/p&gt;
            &lt;/td&gt;
            &lt;td&gt;
              &lt;p&gt;05:37    &lt;/p&gt;
            &lt;/td&gt;
            &lt;td&gt;
              &lt;p&gt;00:48       &lt;/p&gt;
            &lt;/td&gt;
            &lt;td&gt;
              &lt;p&gt;00:46                   &lt;/p&gt;
            &lt;/td&gt;
            &lt;td&gt;
              &lt;p&gt;00:32&lt;/p&gt;
            &lt;/td&gt;
          &lt;/tr&gt;
        &lt;/tbody&gt;
      &lt;/table&gt;
      &lt;p&gt;Another benchmark, run by &lt;a href="https://twitter.com/#!/rossmcf"&gt;Ross McFarlane&lt;/a&gt; gives: &lt;a href="https://twitter.com/#!/rossmcf/status/116086201391398913"&gt;@derickr Based on 3 runs each, execution of 254 tests with 1070 assertions has dropped from 19s to 12s. Nice work!&lt;/a&gt;.&lt;/p&gt;
      &lt;p&gt;In Xdebug 2.2 I would also like to introduce &lt;em&gt;modes&lt;/em&gt;. Each mode will set a default configuration for Xdebug's setting to be the most optimal for that specific tasks. Examples of tasks could be: "profiling", "debugging" or "tracing". Let me know (in the comments) whether you think that's a good idea.&lt;/p&gt;
      &lt;div class="flattr"&gt;
        &lt;a class="FlattrButton" rev="flattr;button:compact;" style="display: none" href="http://derickrethans.nl"/&gt;
        &lt;noscript&gt;
          &lt;a href="http://flattr.com/thing/429095/Derick-Rethans-website"&gt;
            &lt;img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this"/&gt;
          &lt;/a&gt;
        &lt;/noscript&gt;
      &lt;/div&gt;
      
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>201109230923</guid>
      <pubDate>Fri, 23 Sep 2011 08:23:00 +0000</pubDate>
    </item>
    <item>
      <title>Remote Debugging PHP with a Firewall in the Way</title>
      <link>http://derickrethans.nl/debugging-with-xdebug-and-firewalls.html</link>
      <description>&lt;div class="article"&gt;
  &lt;div class="body"&gt;
    &lt;div class="articleListItem"&gt;
      &lt;h1&gt;&lt;a name="remote_debugging_php_with_a_firewall_in_the_way"/&gt;Remote Debugging PHP with a Firewall in the Way&lt;/h1&gt;
      &lt;dl class="head"/&gt;
      &lt;div class="articleMetaData"&gt;
        &lt;div class="location"&gt; London, UK&lt;/div&gt;
        &lt;div class="date"&gt;Thursday, August 25th 2011, 21:42 BST&lt;/div&gt;
      &lt;/div&gt;
      &lt;p&gt;The PHP debugging extension &lt;a href="http://xdebug.org"&gt;Xdebug&lt;/a&gt; has "remote" &lt;a href="http://xdebug.org/docs/remote"&gt;debugging&lt;/a&gt; capabilities for single-step debugging PHP applications. This works by setting your favourite IDE into listening mode and instructing Xdebug (with one of the handy browser &lt;a href="http://xdebug.org/docs/remote#browser-extensions"&gt;extensions&lt;/a&gt; for example) to initiate debugging. When Xdebug is instructed it tries to make a connection to the IP address and port number that are &lt;a href="http://xdebug.org/docs/remote#remote_host"&gt;configured&lt;/a&gt; in php.ini. On this IP &lt;a href="http://xdebug.org/docs/remote#remote_host"&gt;address&lt;/a&gt; and &lt;a href="http://xdebug.org/docs/remote#remote_port"&gt;port&lt;/a&gt; Xdebug expects to find a listening IDE. This IP address can just be &lt;code&gt;127.0.0.1&lt;/code&gt; in case your IDE and web server/CLI script run on the same machine. But as Xdebug supports remote debugging, PHP/Xdebug could also be running on a totally different machine than your IDE. In that case, you need to pick the IP address of the machine on which the IDE is running as the configuration value for &lt;code&gt;xdebug.remote_host&lt;/code&gt;. Alternatively you can set &lt;code&gt;xdebug.remote_connect_back&lt;/code&gt; to true, so that Xdebug may simply pick up your client machine's IP address from the HTTP headers.&lt;/p&gt;
      &lt;p&gt;There could however be a firewall in the way that prevents Xdebug connecting directly to your IDE's IP address. That can be because the network you are on employs &lt;a href="http://en.wikipedia.org/wiki/Network_address_translation"&gt;NAT&lt;/a&gt; in which case you could try (to convince) to get your system administrator to install a &lt;a href="https://github.com/derickr/dbgp"&gt;DBGp&lt;/a&gt; &lt;a href="http://derickrethans.nl/debugging-with-multiple-users.html"&gt;proxy&lt;/a&gt;. In some cases, he might not be willing to do so, or perhaps, there is simply a black box that doesn't allow either a proxy to be run on it, or port forwarding to be set-up on. In this case, there is no way Xdebug can connect to your IDE's IP address and port. Or is there?&lt;/p&gt;
      &lt;p&gt;
        &lt;strong&gt;Breaking the Firewall Down&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;There is another solution, at least, if you have &lt;a href="http://en.wikipedia.org/wiki/Secure_Shell"&gt;SSH&lt;/a&gt; access to the development machine where Xdebug is running on. In this case, you can simply ssh in and set-up a tunnel:&lt;/p&gt;
      &lt;pre&gt;ssh -R 9000:localhost:9000 username@dev.example.com

&lt;/pre&gt;
      &lt;p&gt;This command opens up port &lt;code&gt;9000&lt;/code&gt;, configured with the first &lt;code&gt;9000&lt;/code&gt; in the command, for listening on the machine where you ssh-ed into. Every connection that is made to this port is then forwarded to &lt;code&gt;localhost:9000&lt;/code&gt;, which in this case is port &lt;code&gt;9000&lt;/code&gt; on the machine from where you ran the &lt;code&gt;ssh&lt;/code&gt; command from. When you set Xdebug's &lt;code&gt;xdebug.remote_host&lt;/code&gt; setting to &lt;code&gt;localhost&lt;/code&gt; and &lt;code&gt;xdebug.remote_port&lt;/code&gt; to &lt;code&gt;9000&lt;/code&gt; you know have instructed Xdebug to connect to your SSH-tunneled connection which is forwarded to your local port &lt;code&gt;9000&lt;/code&gt;. And that is exactly where your IDE is listening for incoming debugging connections. Result: Firewall circumvented.&lt;/p&gt;
      &lt;p&gt;If you are so unfortunate to be using Windows on the client side then you don't have the luxury of being able to use the simple SSH client. However, you can set-up tunnels with &lt;a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/"&gt;putty&lt;/a&gt; as well. After configuring your normal session, go to the &lt;code&gt;Connection&lt;/code&gt;, &lt;code&gt;SSH&lt;/code&gt;, &lt;code&gt;Tunnels&lt;/code&gt; section of the configuration and fill in &lt;code&gt;Source port&lt;/code&gt; and &lt;code&gt;Destination&lt;/code&gt;, and select &lt;code&gt;Remote&lt;/code&gt;, just like in this screen shot:&lt;/p&gt;
      &lt;img src="http://derickrethans.nl/images/content/putty-tunnel-settings.png" class="center" alt="putty-tunnel-settings.png"/&gt;
      &lt;p&gt;Then click the &lt;code&gt;Add&lt;/code&gt; button and you will see the following on your screen:&lt;/p&gt;
      &lt;img src="http://derickrethans.nl/images/content/putty-tunnel-result.png" class="center" alt="putty-tunnel-result.png"/&gt;
      &lt;p&gt;Don't forget to go back to the &lt;code&gt;Session&lt;/code&gt; tab and press save. You're now ready to login and when you do so an SSH tunnel will be created just like in the Unix case above.&lt;/p&gt;
      &lt;p&gt;You can check whether it worked by running: &lt;code&gt;netstat -a -n | grep 9000&lt;/code&gt; on the SSH prompt after logging in. You should then see:&lt;/p&gt;
      &lt;pre&gt;derick@xdebug:~$ netstat -a -n | grep 9000
tcp        0      0 0.0.0.0:9000            0.0.0.0:*               LISTEN
tcp6       0      0 :::9000                 :::*                    LISTEN

&lt;/pre&gt;
      &lt;p&gt;The &lt;code&gt;tcp6&lt;/code&gt; portion might not be there, but that's all right. There, even with Windows: Firewall circumvented.&lt;/p&gt;
      &lt;div class="flattr"&gt;
        &lt;a class="FlattrButton" rev="flattr;button:compact;" style="display: none" href="http://derickrethans.nl"/&gt;
        &lt;noscript&gt;
          &lt;a href="http://flattr.com/thing/429095/Derick-Rethans-website"&gt;
            &lt;img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this"/&gt;
          &lt;/a&gt;
        &lt;/noscript&gt;
      &lt;/div&gt;
      
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>201108252142</guid>
      <pubDate>Thu, 25 Aug 2011 20:42:00 +0000</pubDate>
    </item>
    <item>
      <title>Valgrinding shared modules</title>
      <link>http://derickrethans.nl/valgrinding-shared-modules.html</link>
      <description>&lt;div class="article"&gt;
  &lt;div class="body"&gt;
    &lt;div class="articleListItem"&gt;
      &lt;h1&gt;&lt;a name="valgrinding_shared_modules"/&gt;Valgrinding shared modules&lt;/h1&gt;
      &lt;dl class="head"/&gt;
      &lt;div class="articleMetaData"&gt;
        &lt;div class="location"&gt; London, UK&lt;/div&gt;
        &lt;div class="date"&gt;Monday, August 8th 2011, 09:56 BST&lt;/div&gt;
      &lt;/div&gt;
      &lt;p&gt;Over the past year I've been writing various &lt;a href="http://derickrethans.nl/available-for-php-extension-writing.html"&gt;commercial&lt;/a&gt; (more about that later) and open source PHP extensions (such as &lt;a href="https://github.com/derickr/quickhash"&gt;QuickHash&lt;/a&gt;, more about that later too). Most of the time they are shared extensions that are not part of PHP. While testing whether I correctly free all memory with &lt;a href="http://valgrind.org/"&gt;Valgrind&lt;/a&gt;, I ran into the issue where I couldn't see the stack frames of where the memory leaks occurred in the extensions, and once I even ran into a &lt;a href="https://bugs.kde.org/show_bug.cgi?id=277045"&gt;Valgrind bug&lt;/a&gt;. The reason why Valgrind could not show the function names belonging to the stack frames is because PHP had already unloaded the shared extensions from memory.&lt;/p&gt;
      &lt;p&gt;I often found myself compiling the extensions into PHP statically so that there was nothing to unload for PHP, but that was becoming annoying. So instead I added a &lt;a href="http://news.php.net/php.cvs/65492"&gt;patch&lt;/a&gt; to PHP that prevents the shutdown sequence from actually unloading the modules. You can trigger this behaviour by setting the &lt;code&gt;ZEND_DONT_UNLOAD_MODULES&lt;/code&gt; environment variable before running your script:&lt;/p&gt;
      &lt;pre&gt;# export ZEND_DONT_UNLOAD_MODULES=1
# valgrind --leak-check=full --show-reachable=yes php -r 'echo "Hello World\n";'

&lt;/pre&gt;
      &lt;p&gt;Without &lt;code&gt;ZEND_DONT_UNLOAD_MODULES&lt;/code&gt; exported, my Valgrind output shows a block like:&lt;/p&gt;
      &lt;pre&gt;# unset ZEND_DONT_UNLOAD_MODULES
# valgrind --leak-check=full --show-reachable=yes php -r 'echo "Hello World\n";'
...
==25829== 8 bytes in 1 blocks are indirectly lost in loss record 2 of 21
==25829==    at 0x4C25E84: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==25829==    by 0xCE440DC: ???
==25829==    by 0xCE44316: ???
==25829==    by 0xCE44368: ???
==25829==    by 0xCBEE55F: ???
==25829==    by 0xCBD3F87: ???
==25829==    by 0x949A85: zend_activate_modules (zend_API.c:2285)
==25829==    by 0x8B5EBC: php_request_startup (main.c:1491)
==25829==    by 0xA83D60: do_cli (php_cli.c:954)
==25829==    by 0xA84F7B: main (php_cli.c:1356)
...

&lt;/pre&gt;
      &lt;p&gt;And with &lt;code&gt;ZEND_DONT_UNLOAD_MODULES&lt;/code&gt; exported, it shows instead:&lt;/p&gt;
      &lt;pre&gt;# export ZEND_DONT_UNLOAD_MODULES=1
# valgrind --leak-check=full --show-reachable=yes php -r 'echo "Hello World\n";'
...
==25824== 8 bytes in 1 blocks are still reachable in loss record 2 of 30
==25824==    at 0x4C25E84: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==25824==    by 0xCE440DC: event_base_priority_init (in /usr/lib/libevent-1.4.so.2.1.3)
==25824==    by 0xCE44316: event_base_new (in /usr/lib/libevent-1.4.so.2.1.3)
==25824==    by 0xCE44368: event_init (in /usr/lib/libevent-1.4.so.2.1.3)
==25824==    by 0xCBEE55F: zm_activate_http_request_pool (http_request_pool_api.c:58)
==25824==    by 0xCBD3F87: zm_activate_http (http.c:373)
==25824==    by 0x949A85: zend_activate_modules (zend_API.c:2285)
==25824==    by 0x8B5EBC: php_request_startup (main.c:1491)
==25824==    by 0xA83D60: do_cli (php_cli.c:954)
==25824==    by 0xA84F7B: main (php_cli.c:1356)
...

&lt;/pre&gt;
      &lt;p&gt;As you can see all the symbols are now nicely resolved. This patch is part of the upcoming PHP 5.4, but applies to &lt;a href="http://derickrethans.nl/files/php-zend-unload-modules-20110808.diff.txt"&gt;PHP 5.2 and PHP 5.3&lt;/a&gt; as well.&lt;/p&gt;
      
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>201108080956</guid>
      <pubDate>Mon, 08 Aug 2011 08:56:00 +0000</pubDate>
    </item>
    <item>
      <title>Xdebug on github</title>
      <link>http://derickrethans.nl/xdebug-git.html</link>
      <description>&lt;div class="article"&gt;
  &lt;div class="body"&gt;
    &lt;div class="articleListItem"&gt;
      &lt;h1&gt;&lt;a name="xdebug_on_github"/&gt;Xdebug on github&lt;/h1&gt;
      &lt;dl class="head"/&gt;
      &lt;div class="articleMetaData"&gt;
        &lt;div class="location"&gt; London, UK&lt;/div&gt;
        &lt;div class="date"&gt;Wednesday, June 22nd 2011, 21:47 BST&lt;/div&gt;
      &lt;/div&gt;
      &lt;p&gt;I've just opened my &lt;a href="http://xdebug.org"&gt;Xdebug&lt;/a&gt; &lt;a href="https://github.com/derickr/xdebug"&gt;repository&lt;/a&gt; on &lt;a href="https://github.com"&gt;github&lt;/a&gt;. Importing my old SVN repository was a bit of a task. With the help of Ole Marius Smestad I managed to cook up a bash script to import and fix-up the repository. In the meanwhile I've learned more about git than I ever wanted to know, but still not enough. I maintain that, although git is very powerful, it is also a lot less intuitive than SVN (or even CVS).&lt;/p&gt;
      &lt;p&gt;In any case, Xdebug is now on github, as well as the Xdebug &lt;a href="https://github.com/derickr/xdebug.org"&gt;website&lt;/a&gt; (&lt;a href="http://xdebug.org"&gt;http://xdebug.org&lt;/a&gt;), my proof-of-concept debugging client &lt;a href="https://github.com/derickr/gtkdbgp"&gt;GtkDBGp&lt;/a&gt; and the specification of the protocol that Xdebug uses: &lt;a href="https://github.com/derickr/dbgp"&gt;DBGp&lt;/a&gt;. The issue tracker is still at the old location—http://bugs.xdebug.org—and I am not intending to change that.  I will keep the SVN repository active for now.&lt;/p&gt;
      
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>201106222147</guid>
      <pubDate>Wed, 22 Jun 2011 20:47:00 +0000</pubDate>
    </item>
    <item>
      <title>Spatial Indexes: Solr</title>
      <link>http://derickrethans.nl/spatial-indexes-solr.html</link>
      <description>&lt;div class="article"&gt;
  &lt;div class="body"&gt;
    &lt;div class="articleListItem"&gt;
      &lt;h1&gt;&lt;a name="spatial_indexes_solr"/&gt;Spatial Indexes: Solr&lt;/h1&gt;
      &lt;dl class="head"/&gt;
      &lt;div class="articleMetaData"&gt;
        &lt;div class="location"&gt; London, UK&lt;/div&gt;
        &lt;div class="date"&gt;Tuesday, June 14th 2011, 09:04 BST&lt;/div&gt;
      &lt;/div&gt;
      &lt;p&gt;In two previous articles I introduced &lt;a href="http://drck.me/spat-dist-8kf"&gt;the spherical Earth model&lt;/a&gt;, using &lt;a href="http://drck.me/spat-osm-sqlite-8la"&gt;SQLite&lt;/a&gt; as a geographical data storage and using &lt;a href="http://drck.me/spat-mysql-8ls"&gt;MySQL&lt;/a&gt; as a geographical data storage.  In this article we're going to have a look at importing the data into something else than a relational database: the search platform &lt;a href="http://lucene.apache.org/solr/"&gt;Solr&lt;/a&gt;. (Yes, I know I've skipped PostgreSQL, but I'll come back to that).&lt;/p&gt;
      &lt;p&gt;
        &lt;strong&gt;Solr&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;&lt;a href="http://lucene.apache.org/solr/"&gt;Solr&lt;/a&gt; is "the popular, blazing fast open source enterprise search platform from the Apache Lucene project." Since version 3.1, Solr has support for &lt;a href="http://wiki.apache.org/solr/SpatialSearch"&gt;spatial search&lt;/a&gt;, including geospatial search. It can store coordinates in two different field types: &lt;code&gt;solr.PointType&lt;/code&gt; for n-dimensional points, and &lt;code&gt;solr.LatLonType&lt;/code&gt; for a two-dimensional point for geospatial search. The main difference is that with &lt;code&gt;solr.PointType&lt;/code&gt;, calculations are done according to the flat Earth model, and &lt;code&gt;solr.LatLonType&lt;/code&gt; does calculations for a spherical Earth model—which is just what we need.&lt;/p&gt;
      &lt;p&gt;In this example we will use the default Solr configuration, unless noted otherwise. First we download Solr 3.1 and then untar it with &lt;code&gt;tar -xvzf
apache-solr-3.1.0.tgz&lt;/code&gt;.  Then we edit &lt;code&gt;example/solr/conf/solrconfig.xml&lt;/code&gt; to comment out the section on &lt;code&gt;Query Elevation Component&lt;/code&gt; so that it looks like:&lt;/p&gt;
      &lt;pre&gt;&lt;!--
&lt;searchComponent name="elevator" class="solr.QueryElevationComponent" &gt;
  pick a fieldType to analyze queries
        &lt;str name="queryFieldType"&gt;string&lt;/str&gt;
        &lt;str name="config-file"&gt;elevate.xml&lt;/str&gt;
  &lt;/searchComponent&gt;
--&gt;

&lt;/pre&gt;
      &lt;p&gt;See &lt;a href="http://stackoverflow.com/questions/3631823/solr-queryelevationcomponent-requires-strfield-uniquekeyfield-error"&gt;here&lt;/a&gt; for the reason.&lt;/p&gt;
      &lt;p&gt;
        &lt;strong&gt;Setting Up Solr&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;Before we can start using Solr, we need to define a schema. This schema is quite analogous to a database schema, except that Solr only has one table.  By default Solr comes with a schema defining lots of fields in &lt;code&gt;example/solr/conf/schema.xml&lt;/code&gt;.  I've changed the whole &lt;code&gt;&lt;fields&gt;&lt;/code&gt; section to look like:&lt;/p&gt;
      &lt;pre&gt;&lt;fields&gt;
        &lt;field name="id" type="string" indexed="true" stored="true" /&gt;
        &lt;field name="type" type="int" indexed="true" stored="true" /&gt;
        &lt;field name="name" type="text" indexed="true" stored="true" /&gt;
        &lt;field name="amenity" type="string" indexed="true" stored="true" /&gt;
        &lt;field name="address" type="text" indexed="true" stored="true" /&gt;
        &lt;field name="postcode" type="text" indexed="true" stored="true" /&gt;
        &lt;field name="phone" type="text" indexed="true" stored="true" /&gt;
        &lt;field name="cuisine" type="string" indexed="true" stored="true" /&gt;
        &lt;field name="location" type="location" indexed="true" stored="true" /&gt;
        &lt;field name="location_0_coordinate" type="double" indexed="true" stored="true" /&gt;
        &lt;field name="location_1_coordinate" type="double" indexed="true" stored="true" /&gt;
&lt;/fields&gt;

&lt;/pre&gt;
      &lt;p&gt;I've defined specific fields for the &lt;code&gt;type&lt;/code&gt; of source (1=node, 2=way/area), the &lt;code&gt;name&lt;/code&gt; of the amenity (name of the pub, hospital, etc), what sort of &lt;code&gt;amenity&lt;/code&gt; it is (cafe, bank, etc), the &lt;code&gt;address&lt;/code&gt; and &lt;code&gt;postcode&lt;/code&gt;, the &lt;code&gt;phone&lt;/code&gt; number, the type of &lt;code&gt;cuisine&lt;/code&gt; as well as the &lt;code&gt;location&lt;/code&gt;. For the location I've also defined two subtypes: &lt;code&gt;location_0_coordinate&lt;/code&gt; and &lt;code&gt;location_1_coordinate&lt;/code&gt;. Solr requires this for multi-dimensional types such as &lt;code&gt;solr.LatLonType&lt;/code&gt;.&lt;/p&gt;
      &lt;p&gt;The types for each field are also defined in &lt;code&gt;schema.xml&lt;/code&gt;. &lt;code&gt;text&lt;/code&gt; is for a string that is analysed and tokenized (broken down in smaller parts) so that you can search in only parts of the text, &lt;code&gt;string&lt;/code&gt; is for a string of characters that is not analysed or tokenized, and &lt;code&gt;location&lt;/code&gt; contains our latitude/longitude point. Each of those types are associated with a specific Java class with an entry such as:&lt;/p&gt;
      &lt;pre&gt;&lt;fieldType name="location" class="solr.LatLonType" subFieldSuffix="_coordinate"/&gt;

&lt;/pre&gt;
      &lt;p&gt;The &lt;code&gt;subFieldSuffix&lt;/code&gt; in this line configures the suffix in the fields &lt;code&gt;location_0_coordinate&lt;/code&gt; and &lt;code&gt;location_1_coordinate&lt;/code&gt;.&lt;/p&gt;
      &lt;p&gt;Now we have changed the default schema, we can start Solr with: &lt;code&gt;cd example &amp;&amp;
java -jar start.jar&lt;/code&gt;.&lt;/p&gt;
      &lt;p&gt;On the PHP side, we need to do a bit of set-up as well. I've been using the &lt;a href="http://pecl.php.net/package/solr"&gt;Solr PECL&lt;/a&gt; extension to talk to Solr which can be installed with &lt;code&gt;pecl
install solr&lt;/code&gt;.  Please do not forget to add the extension to php.ini with &lt;code&gt;extension=solr.so&lt;/code&gt;. Check whether it is installed correctly with: &lt;code&gt;php --ri
solr&lt;/code&gt;.&lt;/p&gt;
      &lt;p&gt;
        &lt;strong&gt;Importing&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;For our import, we need to change the script we used previously quite substantially.  Instead of just using London, I've also downloaded the whole of the UK from &lt;a href="http://geofabrik.de"&gt;Geofabrik&lt;/a&gt; and extracted all amenities from the dataset with &lt;a href="http://wiki.openstreetmap.org/wiki/Osmosis"&gt;Osmosis&lt;/a&gt;:&lt;/p&gt;
      &lt;pre&gt;wget http://download.geofabrik.de/osm/europe/great_britain.osm.bz2

./osmosis-0.39/bin/osmosis -v 5 \
--read-xml file=great_britain.osm.bz2 \
--tf reject-relations \
--tf accept-nodes amenity=* \
--tf reject-ways \
outPipe.0=POI \
\
--read-xml file=great_britain.osm.bz2 \
--tf reject-relations \
--tf accept-ways amenity=* \
--used-node outPipe.0=area \
\
--merge inPipe.0=POI inPipe.1=area \
--write-xml file=great_britain_amenity.osm

&lt;/pre&gt;
      &lt;p&gt;This is going to take quite some time, and will result in a 500MB XML file.&lt;/p&gt;
      &lt;p&gt;The main logic of the importing script remains the same, but instead of adding each item to a database, we now build a Solr import document and add it to the search index.  I've also split the address and postcode into two separate fields, and added the &lt;code&gt;amenity&lt;/code&gt; field to store all the different amenities. For now, I'm filtering out post boxes, parking areas and grave yards. The script, &lt;code&gt;parsepoi-solr.php&lt;/code&gt; is available &lt;a href="http://derickrethans.nl/files/parsepoi-solr.php.txt"&gt;here&lt;/a&gt;.&lt;/p&gt;
      &lt;p&gt;After downloading, and renaming the downloaded file to &lt;code&gt;parsepoi-solr.php&lt;/code&gt; we can run the script with:&lt;/p&gt;
      &lt;pre&gt;php -dmemory_limit=1G parsepoi-solr.php great_britain_amenity.osm

&lt;/pre&gt;
      &lt;p&gt;When done, this should have imported more than 140.000 items into Solr. You can verify this, by going to &lt;a href="http://localhost:8983/solr/select/?q=*:*&amp;rows=0"&gt;http://localhost:8983/solr/select/?q=*:*&amp;rows=0&lt;/a&gt;&lt;/p&gt;
      &lt;p&gt;
        &lt;strong&gt;Querying&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;As you can see, you can query Solr through its HTTP interface quite easily. In fact, all queries to Solr are done over HTTP. The Solr extension however abstracts this away from you for at least the import. I couldn't find any functionality in the extension to do spatial queries, so we'll do it manually.&lt;/p&gt;
      &lt;p&gt;If we look at the URL above, we can divide it into different parts:&lt;/p&gt;
      &lt;ul&gt;
        &lt;li&gt;
          &lt;p&gt;&lt;code&gt;http://localhost:8983/solr/&lt;/code&gt;: The base URL for this Solr instance.&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;&lt;code&gt;select/?&lt;/code&gt;: The action for running search queries.&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;&lt;code&gt;q=*:*&lt;/code&gt;: &lt;code&gt;q&lt;/code&gt; is the search query parameter, and its value, &lt;code&gt;*:*&lt;/code&gt; means all fields (the first &lt;code&gt;*&lt;/code&gt;) and all possible values (the second &lt;code&gt;*&lt;/code&gt;). In this case that means return everything.&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;&lt;code&gt;rows=0&lt;/code&gt;: Do not return any rows, so that we just get a count.&lt;/p&gt;
        &lt;/li&gt;
      &lt;/ul&gt;
      &lt;p&gt;We get back the result as an XML file. If we want JSON instead, we can simply append &lt;code&gt;&amp;wt=json&lt;/code&gt;. In case you want a CSV file, append &lt;code&gt;&amp;wt=csv&lt;/code&gt;.&lt;/p&gt;
      &lt;p&gt;In a first example, all we want to do is to return all cafes within 100 meter. We construct the search query as follows:&lt;/p&gt;
      &lt;ul&gt;
        &lt;li&gt;
          &lt;p&gt;&lt;code&gt;http://localhost:8983/solr/select/?&lt;/code&gt;: The base URL with search action.&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;&lt;code&gt;q=amenity:cafe&lt;/code&gt;: We search in the field &lt;code&gt;amenity&lt;/code&gt; and look for the value &lt;code&gt;cafe&lt;/code&gt;.&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;&lt;code&gt;fq={!geofilt}&lt;/code&gt;: We set a query filter to &lt;code&gt;geofilt_&lt;/code&gt;. This filter restricts the result set according to the location (&lt;code&gt;pt&lt;/code&gt;) and the maximum distance from this location (&lt;code&gt;d&lt;/code&gt;) in km.&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;&lt;code&gt;sfield=location&lt;/code&gt;: The field to use for location information.&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;&lt;code&gt;pt=51.5375,-0.1934&lt;/code&gt;: The point that we center our search around.&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;&lt;code&gt;d=0.1&lt;/code&gt;: The maximum distance in kilometers.&lt;/p&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;p&gt;&lt;code&gt;wt=csv&lt;/code&gt;: The format to return, in our case, CSV.&lt;/p&gt;
        &lt;/li&gt;
      &lt;/ul&gt;
      &lt;p&gt;Together this makes the full GET request: &lt;a href="http://localhost:8983/solr/select/?q=amenity:cafe&amp;fq={!geofilt}&amp;sfield=location&amp;pt=51.5375,-0.1934&amp;d=0.1&amp;wt=csv"&gt;http://localhost:8983/solr/select/?q=amenity:cafe&amp;fq={!geofilt}&amp;sfield=location&amp;pt=51.5375,-0.1934&amp;d=0.1&amp;wt=csv&lt;/a&gt;&lt;/p&gt;
      &lt;p&gt;And the result is:&lt;/p&gt;
      &lt;pre&gt;id,phone,cuisine,location,address,location_1_coordinate,name,amenity,type,location_0_coordinate,postcode
w62088838,,,51.53750834,-0.19329616,75 Kilburn High Road,-0.19329616,Costa,cafe,2,51.53750834,
w78337118,,,51.53828298,-0.19410346,101 Kilburn High Road,-0.19410346,Caffè Nero,cafe,2,51.53828298,NW6 6JE
w105467205,,,51.537555925,-0.192445525,274 Belsize Road,-0.192445525,Belsize Cafe,cafe,2,51.537555925,NW6 4BT
w105467209,+44 207 3724002,,51.537624071429,-0.19228221428571,270 Belsize Road,-0.19228221428571,Lord Jim,cafe,2,51.537624071429,NW6 4BT
w107710475,+44 20 76245736,,51.53695276,-0.19263662,2 Kilburn Bridge,-0.19263662,Famished Cafe,cafe,2,51.53695276,NW6 6HT
w107710482,,,51.53717868,-0.19288912,Kilburn Bridge,-0.19288912,Mike's,cafe,2,51.53717868,NW6 6HT
w107710490,+44 20 76246942,,51.53732946,-0.1930577,12 Kilburn Bridge,-0.1930577,La Dolce Vita,cafe,2,51.53732946,NW6 6HT

&lt;/pre&gt;
      &lt;p&gt;Which fields are returned can be configured. In this case, we are only interested in the location and name of each amenity, so we restrict the number of returned fields with: &lt;code&gt;fl=id,location,name&lt;/code&gt;. The result now becomes:&lt;/p&gt;
      &lt;pre&gt;id,location,name
w62088838,51.53750834,-0.19329616,Costa
w78337118,51.53828298,-0.19410346,Caffè Nero
w105467205,51.537555925,-0.192445525,Belsize Cafe
w105467209,51.537624071429,-0.19228221428571,Lord Jim
w107710475,51.53695276,-0.19263662,Famished Cafe
w107710482,51.53717868,-0.19288912,Mike's
w107710490,51.53732946,-0.1930577,La Dolce Vita

&lt;/pre&gt;
      &lt;p&gt;Sadly, the results do not come back ordered by distance from our starting point. In order to do that, we need to add one more query parameter: &lt;code&gt;sort=geodist() asc&lt;/code&gt;.  The full query is now: &lt;a href="http://localhost:8983/solr/select/?q=amenity:cafe&amp;fq={!geofilt}&amp;sfield=location&amp;pt=51.5375,-0.1934&amp;d=0.10&amp;wt=csv&amp;fl=id,location,name&amp;sort=geodist()+asc"&gt;http://localhost:8983/solr/select/?q=amenity:cafe&amp;fq={!geofilt}&amp;sfield=location&amp;pt=51.5375,-0.1934&amp;d=0.10&amp;wt=csv&amp;fl=id,location,name&amp;sort=geodist()+asc&lt;/a&gt;&lt;/p&gt;
      &lt;p&gt;And the result:&lt;/p&gt;
      &lt;pre&gt;id,location,name
w62088838,51.53750834,-0.19329616,Costa
w107710490,51.53732946,-0.1930577,La Dolce Vita
w107710482,51.53717868,-0.19288912,Mike's
w105467205,51.537555925,-0.192445525,Belsize Cafe
w105467209,51.537624071429,-0.19228221428571,Lord Jim
w107710475,51.53695276,-0.19263662,Famished Cafe
w78337118,51.53828298,-0.19410346,Caffè Nero

&lt;/pre&gt;
      &lt;p&gt;It is however not possible to return the distance from our starting point directly with Solr. With the exception being that if you use only the &lt;code&gt;geodist()&lt;/code&gt; function as query argument. In this case, make sure to include the special field &lt;code&gt;score&lt;/code&gt; in the &lt;code&gt;fl=&lt;/code&gt; argument as well. An URL showing this is: &lt;a href="http://localhost:8983/solr/select/?q={!func}geodist()&amp;fq={!geofilt}&amp;sfield=location&amp;pt=51.5375,-0.1934&amp;d=0.10&amp;wt=csv&amp;fl=id,location,name,score&amp;sort=geodist()+asc"&gt;http://localhost:8983/solr/select/?q={!func}geodist()&amp;fq={!geofilt}&amp;sfield=location&amp;pt=51.5375,-0.1934&amp;d=0.10&amp;wt=csv&amp;fl=id,location,name,score&amp;sort=geodist()+asc&lt;/a&gt; Of course, in this case you can not filter for specific amenities.&lt;/p&gt;
      &lt;p&gt;
        &lt;strong&gt;Conclusion&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;In currently released versions of Solr (3.1 at the time of writing), it is not possible to return the distance to the starting point for the search as part of the result set. The Solr developers have already &lt;a href="https://issues.apache.org/jira/browse/SOLR-1298"&gt;implemented&lt;/a&gt; the capabilities to add the results of function queries to result documents for version 4.0. You can verify this by downloading a &lt;a href="https://builds.apache.org//job/Solr-trunk/lastSuccessfulBuild/artifact/artifacts/"&gt;nightly build&lt;/a&gt; and running the query: &lt;a href="http://localhost:8983/solr/select/?q=amenity:cafe&amp;fq={!geofilt}&amp;sfield=location&amp;pt=51.5375,-0.1934&amp;d=0.10&amp;fl=id,location,name,score,geodist()&amp;sort=geodist()+asc"&gt;http://localhost:8983/solr/select/?q=amenity:cafe&amp;fq={!geofilt}&amp;sfield=location&amp;pt=51.5375,-0.1934&amp;d=0.10&amp;fl=id,location,name,score,geodist()&amp;sort=geodist()+asc&lt;/a&gt; In this query I've added &lt;code&gt;geodist()&lt;/code&gt; to the &lt;code&gt;fl=&lt;/code&gt; parameter. The result now includes an extra field called &lt;code&gt;geodist()&lt;/code&gt;:&lt;/p&gt;
      &lt;pre&gt;&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;response&gt;
  &lt;!-- missing header --&gt;
  &lt;result name="response" numFound="7" start="0" maxScore="4.352648"&gt;
        &lt;doc&gt;
          &lt;str name="id"&gt;w62088838&lt;/str&gt;
          &lt;str name="name"&gt;Costa&lt;/str&gt;
          &lt;str name="location"&gt;51.53750834,-0.19329616&lt;/str&gt;
          &lt;float name="score"&gt;4.352648&lt;/float&gt;
          &lt;double name="geodist()"&gt;0.0072415726934058865&lt;/double&gt;
        &lt;/doc&gt;
        &lt;doc&gt;
          &lt;str name="id"&gt;w107710490&lt;/str&gt;
          &lt;str name="name"&gt;La Dolce Vita&lt;/str&gt;
          &lt;str name="location"&gt;51.53732946,-0.1930577&lt;/str&gt;
          &lt;float name="score"&gt;4.352648&lt;/float&gt;
          &lt;double name="geodist()"&gt;0.030333097323281075&lt;/double&gt;
        &lt;/doc&gt;

&lt;/pre&gt;
      &lt;p&gt;I could not manage to alias it to a different field, or get it to work with the CSV format (&lt;code&gt;wt=csv&lt;/code&gt;).&lt;/p&gt;
      &lt;p&gt;If the return format is &lt;code&gt;xml&lt;/code&gt; (the default) or &lt;code&gt;json&lt;/code&gt;, then the result includes, besides the number of found items, the total search time for this query.  Look for this information in the &lt;code&gt;QTime&lt;/code&gt; field. In all of the examples here, the &lt;code&gt;QTime&lt;/code&gt; has been less than 5, meaning 5 milliseconds. Solr is extremely fast, even with huge amounts of data. I will try to import the amenities of the whole "planet" at some point, and report back with some benchmarking information.&lt;/p&gt;
      &lt;p&gt;In the next installment of this series on storing geospatial data, I will be looking at using &lt;a href="http://www.mongodb.org"&gt;MongoDB&lt;/a&gt; as data store for geographical information.&lt;/p&gt;
      
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>201106140904</guid>
      <pubDate>Tue, 14 Jun 2011 08:04:00 +0000</pubDate>
    </item>
    <item>
      <title>Translating Twitter, part 2</title>
      <link>http://derickrethans.nl/translating-twitter-part2.html</link>
      <description>&lt;div class="article"&gt;
  &lt;div class="body"&gt;
    &lt;div class="articleListItem"&gt;
      &lt;h1&gt;&lt;a name="translating_twitter_part_2"/&gt;Translating Twitter, part 2&lt;/h1&gt;
      &lt;dl class="head"/&gt;
      &lt;div class="articleMetaData"&gt;
        &lt;div class="location"&gt; London, UK&lt;/div&gt;
        &lt;div class="date"&gt;Tuesday, May 31st 2011, 09:04 BST&lt;/div&gt;
      &lt;/div&gt;
      &lt;p&gt;A while ago I wrote in &lt;a href="http://derickrethans.nl/translating-twitter.html"&gt;an article&lt;/a&gt; about translating tweets in my client &lt;a href="http://derickrethans.nl/projects.html#haunt"&gt;Haunt&lt;/a&gt;. For the translating itself I was using the Google Translate API, which has sadly be &lt;a href="http://googlecode.blogspot.com/2011/05/spring-cleaning-for-some-of-our-apis.html"&gt;deprecated&lt;/a&gt;. Evil after all I suppose.&lt;/p&gt;
      &lt;p&gt;I've now rewritten my translation code to use the &lt;a href="http://www.microsoft.com/web/post/using-the-free-bing-translation-apis"&gt;Bing Translation APIs&lt;/a&gt; instead. You need to register an API key (see &lt;a href="http://www.bing.com/developers/appids.aspx%29"&gt;http://www.bing.com/developers/appids.aspx)&lt;/a&gt; to be able to use the APIs. The APIs that I am using are fairly simple though.&lt;/p&gt;
      &lt;p&gt;For a simple translation, requesting &lt;a href="http://api.microsofttranslator.com/V2/Http.svc/Translate?appId=%5Byourappid%5D&amp;to=en&amp;text=%5Byourtext%5D"&gt;http://api.microsofttranslator.com/V2/Http.svc/Translate?appId=[yourappid]&amp;to=en&amp;text=[yourtext]&lt;/a&gt; is all you need to do. It will auto-detect the language for you as well.&lt;/p&gt;
      &lt;p&gt;However, it does not return the detected language, so I had to resort to using two requests in order to reimplement the same functionality that I had before with the Google APIs. I also found that it was easier to use the Http and not the Ajax variant of the API. It requires using SimpleXML to get to the data, but at least you do not have to fight with the &lt;a href="http://en.wikipedia.org/wiki/Byte-order_mark"&gt;BOM&lt;/a&gt; (Byte-order mark) and quoting.&lt;/p&gt;
      &lt;p&gt;The full code looks like:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
$apiBase = 'http://api.microsofttranslator.com/V2/Http.svc/';
$appId = 'yourappid';
$text = urlencode( 'Een hoge boom vangt veel wind' );

$language = (string) simplexml_load_string(
        file_get_contents(
                "{$apiBase}/Detect?appId={$appId}&amp;text={$text}"
        )
);

$inEnglish = (string) simplexml_load_string(
        file_get_contents(
                "{$apiBase}/Translate?appId={$appId}&amp;text={$text}&amp;to=en"
        )
);

var_dump( $language, $inEnglish );
?&gt;

&lt;/pre&gt;
      &lt;p&gt;with as output:&lt;/p&gt;
      &lt;pre&gt;string(2) "nl"
string(34) "A high tree catches a lot of wind."


&lt;/pre&gt;
      
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>201105310904</guid>
      <pubDate>Tue, 31 May 2011 08:04:00 +0000</pubDate>
    </item>
    <item>
      <title>What is OpenStreetMap?</title>
      <link>http://derickrethans.nl/what-is-openstreetmap.html</link>
      <description>&lt;div class="article"&gt;
  &lt;div class="body"&gt;
    &lt;div class="articleListItem"&gt;
      &lt;h1&gt;&lt;a name="what_is_openstreetmap"/&gt;What is OpenStreetMap?&lt;/h1&gt;
      &lt;dl class="head"/&gt;
      &lt;div class="articleMetaData"&gt;
        &lt;div class="location"&gt; London, UK&lt;/div&gt;
        &lt;div class="date"&gt;Thursday, May 12th 2011, 09:04 BST&lt;/div&gt;
      &lt;/div&gt;
      &lt;p&gt;With people more and more complaining that Google Maps &lt;a href="http://www.flickr.com/photos/harrywood/5702396769/"&gt;gets it wrong&lt;/a&gt;, I often reply that the complainers have a look at &lt;a href="http://openstreetmap.org"&gt;OpenStreetMap&lt;/a&gt; instead.  But there are a few misunderstandings on what OpenStreetMap actually is.&lt;/p&gt;
      &lt;img src="http://c.tile.openstreetmap.org/18/130974/87188.png" class="right" alt="87188.png"/&gt;
      &lt;p&gt;OpenStreetMap has its main site at &lt;a href="http://openstreetmap.org"&gt;http://openstreetmap.org&lt;/a&gt;. This shows a rendering of the map that we like to call a "&lt;a href="http://wiki.openstreetmap.org/wiki/Slippy_Map"&gt;slippy map&lt;/a&gt;". This is an online map, that can interactively be zoomed and paned. The slippy map on the site is nothing more than a display of map tiles, static images rendered from OpenStreetMap data as an example of what you can do with it. The real power of OpenStreetMap is not this default rendering, but the possibility to actually access the data behind this map rendering.  And this is where it differs from &lt;a href="http://maps.google.co.uk/"&gt;Google maps&lt;/a&gt;, &lt;a href="http://www.bing.com/maps/"&gt;Bing Maps&lt;/a&gt; and &lt;a href="http://uk.maps.yahoo.com/"&gt;Yahoo! Maps&lt;/a&gt; and various others. OpenStreetMap is the only mapping service that allows you to do something more than just look at pretty map tiles. OpenStreetMap is a database project, with as its main purpose to have an exhaustive database of every street, city, road, building etc on the planet, and not a map display project.&lt;/p&gt;
      &lt;p&gt;Now what does that actually mean? For one thing, it means that the sample map tiles (that are displayed in the slippy map) are not meant to be used heavily from applications.  It's all right to show a map tile of your neighbourhood on your web site, but it's not okay to write a mobile application that allows you to scrape map tiles of large areas. Have a look at the general &lt;a href="http://wiki.openstreetmap.org/wiki/Tile_usage_policy"&gt;tile usage policy&lt;/a&gt; for some background.  The only reason why there is a sample rendering is to aid mappers with improving the data that is the core of OpenStreetMap.&lt;/p&gt;
      &lt;p&gt;Obviously, the OpenStreetMap project wants its data to be used. But if you're not allowed to use the map tiles en-masse, then how can you use the data?&lt;/p&gt;
      &lt;p&gt;First of all, you can query the OpenStreetMap database in various ways. In most cases, you're going to get an XML file with descriptions of nodes (points of interest, facilities such as toilets, benches, addresses), ways (roads, water ways, transport routes) and areas (buildings, lakes). There is some more info on the (very simple schema) &lt;a href="http://wiki.openstreetmap.org/wiki/Xml_schema"&gt;here&lt;/a&gt;. This data you can parse and import (as I've shown in a previous &lt;a href="http://drck.me/spat-osm-sqlite-8la"&gt;article&lt;/a&gt;) and do all kinds of cool tricks with, such as finding out the closest pub. This functionality is not available on the main OpenStreetMap site, because "OpenStreetMap does not aim to create and host every webservice possible, but to provide the data so that others can"  make awesome map-related applications.&lt;/p&gt;
      &lt;p&gt;Secondly there is a growing number of web sites that uses the OpenStreetMap data to render specialized maps.  There is &lt;a href="http://opencyclemap.org/?zoom=13&amp;lat=51.50806&amp;lon=-0.14025&amp;layers=B0"&gt;OpenCycleMap&lt;/a&gt; that renders information related to using your bicycle and &lt;a href="http://www.openbusmap.org/?zoom=13&amp;lat=51.50526&amp;lon=-0.13869&amp;layers=BT"&gt;Öpvnkarte&lt;/a&gt; for public transport. There is even a tool that uses the &lt;a href="http://milliams.dev.openstreetmap.org/postcodefinder/NW6%25206TB/"&gt;postcode data&lt;/a&gt; in OpenStreetMap.  It's quite possible to render your own maps as well, but that I will get back to in a later article.&lt;/p&gt;
      &lt;img src="http://open.mapquestapi.com/staticmap/v3/getmap?size=320,260&amp;zoom=12&amp;center=51.51,-0.15" class="left" alt="getmap?size=320,260&amp;zoom=12&amp;center=51.51,-0.15"/&gt;
      &lt;p&gt;&lt;a href="http://open.mapquest.co.uk/link/2-Yq2eUVEO"&gt;MapQuest&lt;/a&gt; is a good example of a company that uses OpenStreetMap data. They have made their own rendering with its own styles for a visually different map. Their site implements &lt;a href="http://open.mapquest.co.uk/link/6-eU7PhaC7"&gt;searching&lt;/a&gt; for pubs/bars and restaurants for example and MapQuest are also &lt;a href="http://wiki.openstreetmap.org/wiki/MapQuest#Access_.2F_Downloads"&gt;happy with you using their map tiles&lt;/a&gt; for your applications. Recently, they have also announced &lt;a href="http://devblog.mapquest.com/2011/05/11/get-creative-with-the-open-static-maps-api/"&gt;a simple API&lt;/a&gt; to generate a static map based on OpenStreetMap with their rendering style.&lt;/p&gt;
      &lt;p&gt;The map above is generated by just requesting &lt;a href="http://open.mapquestapi.com/staticmap/v3/getmap?size=320%2C260&amp;zoom=12&amp;center=51.51%2C-0.15"&gt;http://open.mapquestapi.com/staticmap/v3/getmap?size=320,260&amp;zoom=12&amp;center=51.51,-0.15&lt;/a&gt;&lt;/p&gt;
      &lt;p&gt;Another major difference with established mapping providers is the ability to edit the map yourself. You can add your own business, houses, addresses, postcodes, your favourite restaurants with either &lt;a href="http://wiki.openstreetmap.org/wiki/Potlatch_2"&gt;on-line&lt;/a&gt; or &lt;a href="http://wiki.openstreetmap.org/wiki/Josm"&gt;off-line&lt;/a&gt; editors. My list of recent edits is &lt;a href="http://tinyurl.com/34l8wqu"&gt;here&lt;/a&gt;.&lt;/p&gt;
      &lt;p&gt;There is also a whole plethora of special renderings of the map data to assist with debugging issues with the map.  There is the "&lt;a href="http://osm.org/go/cIrZqd@A?layers=N"&gt;no name&lt;/a&gt;" rendering which shows roads without name, &lt;a href="http://www.itoworld.com/static/index.html"&gt;ITO World's&lt;/a&gt; &lt;a href="http://www.itoworld.com/static/osm_analysis.html"&gt;osm analysis&lt;/a&gt; that shows deviations of road names from another source in the UK, &lt;a href="http://keepright.ipax.at/report_map.php?zoom=15&amp;lat=51.49309&amp;lon=-0.13344"&gt;keepright&lt;/a&gt; and &lt;a href="http://tools.geofabrik.de/osmi/?zoom=15&amp;lat=51.49309&amp;lon=-0.13344&amp;view=tagging"&gt;OSM Inspector&lt;/a&gt; that have some automated checks and a tool to &lt;a href="http://oscompare.raggedred.net/?layers=0B00FFT&amp;zoom=17&amp;lat=51.53719&amp;lon=-0.19543"&gt;overlay postcodes&lt;/a&gt; for checking.&lt;/p&gt;
      &lt;p&gt;Obviously, there are a few things missing that would make OpenStreetMap an even better resource for mapping related applications and web-applications. Feel free to suggest things that you find missing or lacking in the comments of this article. I'd be happy to hear why you would think that OpenStreetMap is not a good fit for your applications and usage.&lt;/p&gt;
      
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>201105120904</guid>
      <pubDate>Thu, 12 May 2011 08:04:00 +0000</pubDate>
    </item>
    <item>
      <title>Spatial Indexes: MySQL</title>
      <link>http://derickrethans.nl/spatial-indexes-mysql.html</link>
      <description>&lt;div class="article"&gt;
  &lt;div class="body"&gt;
    &lt;div class="articleListItem"&gt;
      &lt;h1&gt;&lt;a name="spatial_indexes_mysql"/&gt;Spatial Indexes: MySQL&lt;/h1&gt;
      &lt;dl class="head"/&gt;
      &lt;div class="articleMetaData"&gt;
        &lt;div class="location"&gt; London, UK&lt;/div&gt;
        &lt;div class="date"&gt;Tuesday, April 12th 2011, 09:04 BST&lt;/div&gt;
      &lt;/div&gt;
      &lt;p&gt;In two previous articles I introduced &lt;a href="http://drck.me/spat-dist-8kf"&gt;The spherical Earth model&lt;/a&gt; and &lt;a href="http://drck.me/spat-osm-sqlite-8la"&gt;importing data&lt;/a&gt; into SQLite for querying geographical data. In this article we're going to have a look at importing the data into &lt;a href="http://dev.mysql.com/"&gt;MySQL&lt;/a&gt; and finding out how to best store and query spatial data in the databases.&lt;/p&gt;
      &lt;p&gt;
        &lt;strong&gt;MySQL&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;MySQL has some support for &lt;a href="http://dev.mysql.com/doc/refman/5.1/en/spatial-extensions.html"&gt;Spatial Extensions&lt;/a&gt;, but it's not particularly useful. For example, there is no way to query anything within the radius around a specific point. Their community pages list a &lt;a href="http://forge.mysql.com/tools/tool.php?id=41"&gt;method&lt;/a&gt; of implementing it, but it only calculates for a flat Earth model.&lt;/p&gt;
      &lt;p&gt;Instead, we'll have to implement our own algorithms again. But first of all, let us import the data into MySQL. First we create the MySQL database:&lt;/p&gt;
      &lt;pre&gt;derick@whisky:~$ mysqladmin -u root -p create poi
mysql&gt; CREATE TABLE poi(id int, type int, lat float, lon float, name char(255), address char(255), cuisine char(64), phone char(18));

&lt;/pre&gt;
      &lt;p&gt;And then we take the &lt;a href="http://derickrethans.nl/files/parsepoi.php.txt"&gt;script&lt;/a&gt; from the previous article on &lt;a href="http://drck.me/spat-osm-sqlite-8la"&gt;importing data&lt;/a&gt;, and change the third line from:&lt;/p&gt;
      &lt;pre&gt;$d = ezcDbFactory::create( 'sqlite://' . dirname( __FILE__ ) . '/pois.sqlite' );

&lt;/pre&gt;
      &lt;p&gt;to:&lt;/p&gt;
      &lt;pre&gt;$d = ezcDbFactory::create( 'mysql://root:root@localhost/poi' );

&lt;/pre&gt;
      &lt;p&gt;Of course, substitute the username and password (&lt;code&gt;root&lt;/code&gt;, &lt;code&gt;root&lt;/code&gt;) and the database name (&lt;code&gt;poi&lt;/code&gt;) to one that suits yourself. We then run again:&lt;/p&gt;
      &lt;pre&gt;php parseoi.php.txt great_britain_pubs.osm

&lt;/pre&gt;
      &lt;p&gt;And check that our import is complete:&lt;/p&gt;
      &lt;pre&gt;mysql&gt; SELECT count(*) from poi\G
*************************** 1. row ***************************
count(*): 28147

&lt;/pre&gt;
      &lt;p&gt;Now that we have all the POIs imported, we can query the database. Because MySQL doesn't have working spatial extensions, nor the register-function capabilities from SQLite such as we saw in the previous article, we have to come up with a new solution. The most obvious one is writing a stored procedure for the task, another (non-explored option) would be to write a &lt;a href="http://dev.mysql.com/doc/refman/5.1/en/adding-udf.html"&gt;user defined function&lt;/a&gt;. Writing the stored procedure is simple enough; we just have to convert the &lt;code&gt;distance()&lt;/code&gt; function to SQL. On the MySQL command line you can enter:&lt;/p&gt;
      &lt;pre&gt;delimiter //

CREATE FUNCTION distance (latA double, lonA double, latB double, LonB double)
    RETURNS double DETERMINISTIC
BEGIN
    SET @RlatA = radians(latA);
    SET @RlonA = radians(lonA);
    SET @RlatB = radians(latB);
    SET @RlonB = radians(LonB);
    SET @deltaLat = @RlatA - @RlatB;
    SET @deltaLon = @RlonA - @RlonB;
    SET @d = SIN(@deltaLat/2) * SIN(@deltaLat/2) +
        COS(@RlatA) * COS(@RlatB) * SIN(@deltaLon/2)*SIN(@deltaLon/2);
    RETURN 2 * ASIN(SQRT(@d)) * 6371.01;
END//

&lt;/pre&gt;
      &lt;p&gt;Fetching all the pubs within a 250 meter radius around 51.5375°N, 0.1933°W is than as easy as running:&lt;/p&gt;
      &lt;pre&gt;mysql&gt; SELECT name, address, phone
       FROM poi
       WHERE DISTANCE(lat, lon, 51.5375, -0.1933) &lt; 0.25;

&lt;/pre&gt;
      &lt;p&gt;With the result being:&lt;/p&gt;
      &lt;pre&gt;| name            | address                        | phone           |
+-----------------+--------------------------------+-----------------+
| Mrs Betsy Smith | Kilburn High Road 77 , NW6 6HY | +44 20 76245793 |
| The Cock Tavern | Kilburn High Road 125          | NULL            |
| The Old Bell    | NULL                           | NULL            |
| The Westbury    | Kilburn High Road 34 , NW6 5UA | +44 20 76257500 |
+-----------------+--------------------------------+-----------------+
4 rows in set (0.72 sec)

&lt;/pre&gt;
      &lt;p&gt;If we want to also include the distance from the centre point in the result, we need to modify the query to:&lt;/p&gt;
      &lt;pre&gt;mysql&gt; SELECT name, DISTANCE(lat, lon, 51.5375, -0.1933) AS dist
       FROM poi
       HAVING dist &lt; 0.25
       ORDER BY dist;

&lt;/pre&gt;
      &lt;p&gt;with as result:&lt;/p&gt;
      &lt;pre&gt;| name            | dist                |
+-----------------+---------------------+
| Mrs Betsy Smith | 0.00825473345748987 |
| The Cock Tavern |     0.2420193460511 |
| The Old Bell    |   0.103123484090313 |
| The Westbury    |   0.150294300836645 |
+-----------------+---------------------+
4 rows in set (0.72 sec)

&lt;/pre&gt;
      &lt;p&gt;In both cases, the query takes 0.72 seconds. This is not overly fast, and the main reason for this is that the &lt;code&gt;distance()&lt;/code&gt; function has to be called for every row in the table. An index can not be created on this either. However, what we can do is to filter out the results roughly first, by calculating a bounding box of latitude/longitude pairs around the centre point. Calculating the latitude boundaries can be done by:&lt;/p&gt;
      &lt;pre&gt;d = (distInKm / 6371.01 * 2π) * 360
lat1 = centreLat - d
lat2 = centreLat + d

&lt;/pre&gt;
      &lt;p&gt;In our example that becomes:&lt;/p&gt;
      &lt;pre&gt;d = (0.250 / 6371.01 * 2π) * 360 = 0.0022483
lat1 = 51.5375 - 0.0022483 = 51.5352.. -&gt; 51.5351
lat2 = 51.5375 + 0.0022483 = 51.5397.. -&gt; 51.5398

&lt;/pre&gt;
      &lt;p&gt;Or in PHP:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
function findLatBoundary($dist, $lat, &amp;$lat1, &amp;$lat2)
{
    $d = ($dist / 6371.01 * 2 * M_PI) * 360;
    $lat1 = $lat - $d;
    $lat2 = $lat + $d;
}
?&gt;

&lt;/pre&gt;
      &lt;p&gt;We round slightly up and down to combat inaccuracies in the calculations—it is a rough estimate after all.  After adding the index on the &lt;code&gt;lat&lt;/code&gt; column, and the index on the &lt;code&gt;lon&lt;/code&gt; column, we reissue the query:&lt;/p&gt;
      &lt;pre&gt;mysql&gt; CREATE index poi_lat ON poi(lat);
mysql&gt; CREATE index poi_lon ON poi(lon);

mysql&gt; SELECT name, DISTANCE(lat, lon, 51.5375, -0.1933) AS dist
       FROM poi
       WHERE lat BETWEEN 51.5351 AND 51.5398
       HAVING dist &lt; 0.25;

&lt;/pre&gt;
      &lt;p&gt;Which returns the same result as before, but faster:&lt;/p&gt;
      &lt;pre&gt;| name            | dist                |
+-----------------+---------------------+
| The Westbury    |   0.150294300836645 |
| The Old Bell    |   0.103123484090313 |
| Mrs Betsy Smith | 0.00825473345748987 |
| The Cock Tavern |     0.2420193460511 |
+-----------------+---------------------+
4 rows in set (0.01 sec)

&lt;/pre&gt;
      &lt;p&gt;We can pre-filter the result set even more, by also limiting on the longitude boundary. This involves a few more calculations than for the latitude boundaries. The distance in degrees longitude that belongs to a distance in km depends on the latitude of the location. So first we need to calculate the latitude boundaries as we have done above, and with that information calculate the longitude boundaries.&lt;/p&gt;
      &lt;img src="http://derickrethans.nl/images/content/sphere-distance.png" alt="sphere-distance.png"/&gt;
      &lt;p&gt;In the first step (red), we calculate the northern and southern boundaries of the circle. We then calculate the western and eastern boundaries for the northern boundary (green), and southern boundary (blue).&lt;/p&gt;
      &lt;p&gt;In PHP this algorithm becomes:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
function findLonBoundary($dist, $lat, $lon, $lat1, $lat2, &amp;$lon1, &amp;$lon2)
{
    $d = $lat - $lat1;

    $d1 = $d / cos(deg2rad($lat1));
    $d2 = $d / cos(deg2rad($lat2));

    $lon1 = min($lon - $d1, $lon - $d2);
    $lon2 = max($lon + $d1, $lon + $d2);
}
?&gt;

&lt;/pre&gt;
      &lt;p&gt;If we use both functions we calculate as boundaries:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
$dist = 0.25;
$lat = 51.5375;
$lon = -0.1933;

findLatBoundary($dist, $lat, $lat1, $lat2);
findLonBoundary($dist, $lat, $lon, $lat1, $lat2, $lon1, $lon2);

echo "SELECT name, DISTANCE(lat, lon, $lat, $lon) AS dist
      FROM poi
      WHERE lat BETWEEN $lat1 AND $lat2
        AND lon BETWEEN $lon1 AND $lon2
      HAVING dist &lt; $dist
      ORDER BY dist;\n";
?&gt;

&lt;/pre&gt;
      &lt;p&gt;Which returns the query to execute:&lt;/p&gt;
      &lt;pre&gt;SELECT name, DISTANCE(lat, lon, 51.5375, -0.1933) AS dist
FROM poi
WHERE lat BETWEEN 51.535251699514 AND 51.539748300486
  AND lon BETWEEN -0.19691479627963 AND -0.18968520372037
  HAVING dist &lt; 0.25
  ORDER BY dist;

&lt;/pre&gt;
      &lt;p&gt;If we run this query, we get as result:&lt;/p&gt;
      &lt;pre&gt;| name            | dist                |
+-----------------+---------------------+
| Mrs Betsy Smith | 0.00825473345748987 |
| The Old Bell    |   0.103123484090313 |
| The Westbury    |   0.150294300836645 |
| The Cock Tavern |     0.2420193460511 |
+-----------------+---------------------+
4 rows in set (0.00 sec)

&lt;/pre&gt;
      &lt;p&gt;As you can see, we are getting the result a lot faster now—0.00 sec vs 0.72 sec.  Please do note, that if we would just have used the boundaries without using the &lt;code&gt;HAVING dist &lt; 0.25&lt;/code&gt; clause, we would have gotten one extra result that is slightly too far away (0.281 km):&lt;/p&gt;
      &lt;pre&gt;| name            | dist                |
+-----------------+---------------------+
| Mrs Betsy Smith | 0.00825473345748987 |
| The Old Bell    |   0.103123484090313 |
| The Westbury    |   0.150294300836645 |
| The Cock Tavern |     0.2420193460511 |
| Bar Hemia       |   0.281138534935208 |
+-----------------+---------------------+

&lt;/pre&gt;
      &lt;p&gt;
        &lt;strong&gt;Conclusion&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;In this article we saw how we can use a MySQL stored procedure to find our pubs and bars within a certain distance from a central location.  In the next part, we will be looking on how to solve the same problem with &lt;a href="http://www.postgresql.org/"&gt;PostgreSQL&lt;/a&gt;.&lt;/p&gt;
      
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>201104120904</guid>
      <pubDate>Tue, 12 Apr 2011 08:04:00 +0000</pubDate>
    </item>
    <item>
      <title>Spatial Indexes: Fetching Data/SQLite</title>
      <link>http://derickrethans.nl/spatial-indexes-data-sqlite.html</link>
      <description>&lt;div class="article"&gt;
  &lt;div class="body"&gt;
    &lt;div class="articleListItem"&gt;
      &lt;h1&gt;&lt;a name="spatial_indexes_fetching_data_sqlite"/&gt;Spatial Indexes: Fetching Data/SQLite&lt;/h1&gt;
      &lt;dl class="head"/&gt;
      &lt;div class="articleMetaData"&gt;
        &lt;div class="location"&gt; London, UK&lt;/div&gt;
        &lt;div class="date"&gt;Thursday, March 31st 2011, 09:17 BST&lt;/div&gt;
      &lt;/div&gt;
      &lt;p&gt;In a previous &lt;a href="http://drck.me/spat-dist-8kf"&gt;article&lt;/a&gt; I introduced 'The Flat Earth Model' and the 'The spherical Earth model'. In this article we're going to have a look at fetching a data set and importing them into a SQLite database to query from PHP. What better data set is there to import than all of the UK's pubs?&lt;/p&gt;
      &lt;p&gt;
        &lt;strong&gt;Getting the Data&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;In order to get a suitable data set we are going to use the data from the &lt;a href="http://openstreetmap.org"&gt;OpenStreetMap&lt;/a&gt; project. This project is mainly concerned with making an open map of the entire globe, but it also contains a vast database of points-of-interest (POI). OpenStreetMap contributes seems to be a big fan of pubs, and hence they are mapped really well. POIs can either be stored as a node (a single point with a geographical location) such as &lt;a href="http://www.openstreetmap.org/browse/node/603112458"&gt;The Long Acre&lt;/a&gt; or as a closed way (an ordered collection of nodes where the first and last node are the same), such as &lt;a href="http://www.openstreetmap.org/browse/way/72773168"&gt;Brondes Age&lt;/a&gt;.&lt;/p&gt;
      &lt;p&gt;I will demonstrate two methods to fetch the pubs in an XML format containing nodes and ways.  The first method is with &lt;a href="http://wiki.openstreetmap.org/wiki/Xapi"&gt;XAPI&lt;/a&gt;. XAPI is an interface to the OpenStreetMap database to allow users to query and filter items. In order to fetch data through it, you specify a bounding box and a predicate. A bounding box specifies the most Eastern, Southern, Western and Northern coordinates. The UK has roughly as bounding box &lt;em&gt;9.05°W, 48.77°N, 2.19°E, 58.88°N&lt;/em&gt;, or short: &lt;em&gt;-9.05, 48.77, 2.19, 58.88&lt;/em&gt;. Fetching the data can simply be done by querying the server with wget:&lt;/p&gt;
      &lt;pre&gt;wget -O pubs.xml 'http://xapi.openstreetmap.org/api/0.6/*[amenity=pub][bbox=-9.05,48.77,2.19,58.88]'

&lt;/pre&gt;
      &lt;p&gt;This is going to take a long time; and will most likely just not work or time-out. The current XAPI server, written in an obscure programming language called &lt;a href="http://en.wikipedia.org/wiki/MUMPS"&gt;MUMPS&lt;/a&gt;, is extremely unreliable and is really slow. A new version of XAPI build in Java is on the way, but right now it's limited to 10 square degrees.&lt;/p&gt;
      &lt;p&gt;Luckily, there is an alternative in the form of parsing (an extract of) the planet file. The planet file is an enormous database dump of OpenStreetMap's data. The people at &lt;a href="http://geofabrik.de"&gt;Geofabrik&lt;/a&gt; have extracts for specific parts of the world at &lt;a href="http://download.geofabrik.de/osm/"&gt;http://download.geofabrik.de/osm/&lt;/a&gt;. From them I downloaded the &lt;code&gt;europe/great_britain.osm.pbf&lt;/code&gt; file (274 MB) for my example. With a tool called &lt;a href="http://wiki.openstreetmap.org/wiki/Osmosis"&gt;Osmosis&lt;/a&gt; we can then filter out all pubs into a similar formatted XML file. I am only giving the command to do our task at hand, but a detailed usage guide for Osmosis is &lt;a href="http://wiki.openstreetmap.org/wiki/Osmosis/Detailed_Usage"&gt;available&lt;/a&gt; too. The command runs in about four minutes and looks like:&lt;/p&gt;
      &lt;pre&gt;./osmosis-0.38/bin/osmosis -v 5 \
\
--read-pbf file=great_britain.osm.pbf \
--tf reject-relations \
--tf accept-nodes amenity=pub,bar \
--tf reject-ways \
outPipe.0=POI \
\
--read-pbf file=great_britain.osm.pbf \
--tf reject-relations \
--tf accept-ways amenity=pub,bar \
--used-node \
outPipe.0=area \
\
--merge inPipe.0=POI inPipe.1=area \
--write-xml file=great_britain_pubs.osm

&lt;/pre&gt;
      &lt;p&gt;
        &lt;strong&gt;Importing the Data&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;The resulting XML file has two important elements: nodes and ways. The XML for The Long Acre looks like:&lt;/p&gt;
      &lt;pre&gt;&lt;node id="603112458"
  version="1" timestamp="2010-01-02T16:12:57Z"
  uid="1185" user="dankarran" changeset="3519803"
  lat="51.511831" lon="-0.126789"&gt;

  &lt;tag k="amenity" v="pub"/&gt;
  &lt;tag k="name" v="The Long Acre"/&gt;
&lt;/node&gt;

&lt;/pre&gt;
      &lt;p&gt;Important here are the latitude (51.51°N) and longitude (0.12°W) and of course, the name of the pub in the &lt;em&gt;tag&lt;/em&gt; element.&lt;/p&gt;
      &lt;p&gt;And the XML for Brondes Age (a way) is a bit more complex, and looks like:&lt;/p&gt;
      &lt;pre&gt;&lt;way id="72773168"
  version="2" timestamp="2011-01-31T10:07:45Z"
  uid="346" user="Tom Chance" changeset="7143502"&gt;

  &lt;nd ref="863936779"/&gt;
  &lt;nd ref="863936774"/&gt;
  &lt;nd ref="863936777"/&gt;
  &lt;nd ref="863936796"/&gt;
  &lt;nd ref="863936791"/&gt;
  &lt;nd ref="863936768"/&gt;
  &lt;nd ref="863936779"/&gt;
  &lt;tag k="addr:housenumber" v="328"/&gt;
  &lt;tag k="addr:postcode" v="NW6 2QN"/&gt;
  &lt;tag k="addr:street" v="Kilburn High Road"/&gt;
  &lt;tag k="amenity" v="pub"/&gt;
  &lt;tag k="building" v="yes"/&gt;
  &lt;tag k="contact:email" v="brondesage@aol.com"/&gt;
  &lt;tag k="contact:phone" v="+44 20 76249010"/&gt;
  &lt;tag k="contact:website" v="http://www.brondesage.com/"/&gt;
  &lt;tag k="name" v="Brondes Age"/&gt;
  &lt;tag k="toilets" v="yes"/&gt;
  &lt;tag k="toilets:access" v="customers"/&gt;
&lt;/way&gt;

&lt;/pre&gt;
      &lt;p&gt;There is no latitude and longitude, but instead there are references to nodes (the &lt;em&gt;nd&lt;/em&gt; elements). There is also a large collection of descriptive tags, such as &lt;em&gt;addr:housenumber&lt;/em&gt; and &lt;em&gt;contact:phone&lt;/em&gt;. In order to calculate the latitude and longitude of Brondes Age we can either take the &lt;em&gt;correct&lt;/em&gt; approach by calculating the &lt;a href="http://paulbourke.net/geometry/polyarea/"&gt;centroid&lt;/a&gt; or we can simply take the average latitude and longitude of all the nodes. To make things simple, I will take the simple approach.&lt;/p&gt;
      &lt;p&gt;In order to find the latitude and longitude of all the nodes, we simply scan through the file again and find all the nodes that correspond to the &lt;em&gt;ref&lt;/em&gt; attribute of each &lt;em&gt;nd&lt;/em&gt; element. We should disregard the last one of each &lt;em&gt;way&lt;/em&gt; though, as it is the same as the first one.&lt;/p&gt;
      &lt;p&gt;
        &lt;strong&gt;SQLite&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;To start, we will use a very simple RDBMS: &lt;a href="http://www.sqlite.org/"&gt;SQLite&lt;/a&gt;. We will still have to define a database schema. We can simply do that with:&lt;/p&gt;
      &lt;pre&gt;derick@whisky:~$ sqlite pois.sqlite
sqlite&gt; CREATE TABLE poi(id int, type int, lat float, lon float, name char, address char, cuisine char, phone char);

&lt;/pre&gt;
      &lt;p&gt;The importing of data then can be done by this "simple" &lt;a href="http://derickrethans.nl/files/parsepoi.php.txt"&gt;script&lt;/a&gt; (after adjusting the path to eZ Components/ &lt;a href="http://incubator.apache.org/zetacomponents/"&gt;Zeta Components&lt;/a&gt;) with:&lt;/p&gt;
      &lt;pre&gt;php parsepoi.php.txt great_britain_pubs.osm

&lt;/pre&gt;
      &lt;p&gt;After running the import script, there should be about 28000 POIs in the database.&lt;/p&gt;
      &lt;p&gt;
        &lt;strong&gt;Querying the Data&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;Once we have imported the POIs into our SQLite database, we are ready to query them. SQLite does not have a very extensive set of &lt;a href="http://www.sqlite.org/lang_corefunc.html"&gt;functions&lt;/a&gt; so we can not do the calculation in the query directly. Just to iterate from the &lt;a href="http://drck.me/spat-dist-8kf"&gt;previous&lt;/a&gt; article in this series, the formula for calculating the distance in a spherical Earth model is:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
function distance($latA, $lonA, $latB, $lonB)
{
  // convert from degrees to radians
  $latA = deg2rad($latA); $lonA = deg2rad($lonA);
  $latB = deg2rad($latB); $lonB = deg2rad($lonB);

  // calculate absolute difference for latitude and longitude
  $dLat = ($latA - $latB);
  $dLon = ($lonA - $lonB);

  // do trigonometry magic
  $d =
    sin($dLat/2) * sin($dLat/2) +
    cos($latA) * cos($latB) * sin($dLon/2) *sin($dLon/2);
  $d = 2 * asin(sqrt($d));
  return $d * 6371;
}
?&gt;

&lt;/pre&gt;
      &lt;p&gt;One solution would be to query the database, and then use the &lt;code&gt;distance()&lt;/code&gt; function to filter out unwanted elements, like:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
include 'distance.php';
require '/home/derick/dev/zetacomponents/trunk/Base/src/ezc_bootstrap.php';
$d = ezcDbFactory::create( 'sqlite://' . dirname( __FILE__ ) . '/pois.sqlite' );

// Centre point
$lat = 51.5375;
$lon = -0.1933;

// Distance (in km)
$wantedD = 0.25;

$q = $d-&gt;createSelectQuery();
$q-&gt;select( '*' )-&gt;from( 'poi' );
$s = $q-&gt;prepare();
$s-&gt;execute();

foreach ( $s as $res )
{
  $e = distance( $lat, $lon, $res['lat'], $res['lon'] );
  if ( $e &lt; $wantedD )
  {
    echo sprintf( '%.3f,%.3f %-40s %.2f km away',
      $res['lat'], $res['lon'], $res['name'],
      $e ), "\n";
  }
}
?&gt;

&lt;/pre&gt;
      &lt;p&gt;This will show all pubs in a 250 meter radius around 51.53°N, 0.19°W:&lt;/p&gt;
      &lt;pre&gt;derick@whisky:/home/httpd/html/test/maps$ php fetch-sqlite-simple.php
51.538,-0.193 Mrs Betsy Smith                          0.01 km away
51.539,-0.195 The Cock Tavern                          0.24 km away
51.537,-0.192 The Old Bell                             0.10 km away
51.537,-0.192 The Westbury                             0.15 km away

&lt;/pre&gt;
      &lt;p&gt;Of course, this is not very efficient as &lt;strong&gt;all&lt;/strong&gt; items are selected from the database, and then filtered out depending on their calculated distance. Luckily, SQLite supports user defined functions written in PHP. This would mean that we can increase performance a bit by letting PHP's internals call the distance function for every row:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
include 'distance.php';
require '/home/derick/dev/zetacomponents/trunk/Base/src/ezc_bootstrap.php';
$d = ezcDbFactory::create( 'sqlite://' . dirname( __FILE__ ) . '/pois.sqlite' );

// Register SQLite function "dist" to our PHP function "distance".
$d-&gt;sqliteCreateFunction( 'dist', 'distance' );

// Centre point
$lat = 51.5375;
$lon = -0.1933;

// Distance (in km)
$wantedD = 0.25;

$q = $d-&gt;createSelectQuery();

// Use the user defined dist() function as additional column
$q-&gt;select( "*, dist($lat, $lon, lat, lon) as e" )
  -&gt;from( 'poi' )
  -&gt;where( "e &lt; $wantedD" );

$s = $q-&gt;prepare();
$s-&gt;execute();

foreach ( $s as $res )
{
  echo sprintf( '%.3f,%.3f %-40s %.2f km away',
    $res['lat'], $res['lon'], $res['name'],
    $res['e'] ), "\n";
}
?&gt;

&lt;/pre&gt;
      &lt;p&gt;The result is naturally the same as before.&lt;/p&gt;
      &lt;p&gt;
        &lt;strong&gt;Conclusion&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;In this installment we have seen how to retrieve information from &lt;a href="http://openstreetmap.org"&gt;OpenStreetMap&lt;/a&gt;'s database and import them into SQLite for querying. In the next installment we will have a look at how to import and query with MySQL and PostgreSQL.&lt;/p&gt;
      
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>201103310917</guid>
      <pubDate>Thu, 31 Mar 2011 08:17:00 +0000</pubDate>
    </item>
    <item>
      <title>Xdebug 2.1.1</title>
      <link>http://derickrethans.nl/xdebug-2.1.1.html</link>
      <description>&lt;div class="article"&gt;
  &lt;div class="body"&gt;
    &lt;div class="articleListItem"&gt;
      &lt;h1&gt;&lt;a name="xdebug_2_1_1"/&gt;Xdebug 2.1.1&lt;/h1&gt;
      &lt;dl class="head"/&gt;
      &lt;div class="articleMetaData"&gt;
        &lt;div class="location"&gt; London, UK&lt;/div&gt;
        &lt;div class="date"&gt;Monday, March 28th 2011, 09:40 BST&lt;/div&gt;
      &lt;/div&gt;
      &lt;p&gt;I've just &lt;a href="http://xdebug.org/"&gt;released&lt;/a&gt; Xdebug 2.1.1. It is a bug fix release that primarily addresses issues in the debugging and profiling functionality of &lt;a href="http://xdebug.org/"&gt;Xdebug&lt;/a&gt;.&lt;/p&gt;
      &lt;p&gt;Among the bug fixes is a fix that solves an &lt;a href="https://bugs.kde.org/show_bug.cgi?id=256425#c10"&gt;issue&lt;/a&gt; with newer versions of the &lt;a href="http://kcachegrind.sourceforge.net/html/Home.html"&gt;KCacheGrind&lt;/a&gt; profiling GUI. The newer versions are more strict with input which causes an issue with Xdebug &lt;a href="http://xdebug.org/docs/profiler"&gt;profiler&lt;/a&gt;'s files. Xdebug 2.1.1 solves &lt;a href="http://bugs.xdebug.org/bug_view_page.php?bug_id=00000639"&gt;this&lt;/a&gt;.&lt;/p&gt;
      &lt;p&gt;As an &lt;a href="http://drck.me/sponsor-xdebug-8ky"&gt;experiment&lt;/a&gt; I set up a pledge system to allow myself to work on this (and related issues) during my "work time".  Twenty-four pledges were made, in about two weeks; matching the goal. Sebastian, Jan, Michael, &lt;a href="http://www.palepurple.co.uk/"&gt;Pale Purple&lt;/a&gt;, Jeff, Christoph, Karel, Yannick, Jake, Venakis, Brian, Simon, Kenneth, DM Baker, "gizmola", Ladislav, Volker, &lt;a href="http://www.react.nl/"&gt;React&lt;/a&gt;, Michal and three anonymous supporters—thanks for your support!&lt;/p&gt;
      &lt;p&gt;&lt;a href="http://bugs.xdebug.org/bug_view_page.php?bug_id=00000642"&gt;Another&lt;/a&gt; main issue that was fixed was that line numbers (in function traces, profile files and while debugging) for "magic" function calls (such as __get(), __call() etc) were always recorded as 0. This made it impossible to set breakpoints for example.&lt;/p&gt;
      &lt;p&gt;You can find Xdebug 2.1.1's source and Windows binaries at the &lt;a href="http://xdebug.org/download.php#releases"&gt;download&lt;/a&gt; page. A full &lt;a href="http://xdebug.org/updates.php#x_2_1_1"&gt;ChangeLog&lt;/a&gt; is available as well.  Through &lt;a href="https://twitter.com/xdebug"&gt;twitter&lt;/a&gt; you can kept up-to-date about Xdebug's development efforts and support is available through the &lt;a href="http://xdebug.org/support.php#list"&gt;mailinglist&lt;/a&gt;. If you think that Xdebug is a valuable tool, you can &lt;a href="http://xdebug.org/donate.php"&gt;donate&lt;/a&gt; via PayPal.&lt;/p&gt;
      
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>201103280940</guid>
      <pubDate>Mon, 28 Mar 2011 08:40:00 +0000</pubDate>
    </item>
    <item>
      <title>Sponsoring Xdebug</title>
      <link>http://derickrethans.nl/sponsoring-xdebug.html</link>
      <description>&lt;div class="article"&gt;
  &lt;div class="body"&gt;
    &lt;div class="articleListItem"&gt;
      &lt;h1&gt;&lt;a name="sponsoring_xdebug"/&gt;Sponsoring Xdebug&lt;/h1&gt;
      &lt;dl class="head"/&gt;
      &lt;div class="articleMetaData"&gt;
        &lt;div class="location"&gt; London, UK&lt;/div&gt;
        &lt;div class="date"&gt;Tuesday, March 22nd 2011, 18:30 GMT&lt;/div&gt;
      &lt;/div&gt;
      &lt;p&gt;Over the past 7 years I've spend countless hours making &lt;a href="http://xdebug.org"&gt;Xdebug&lt;/a&gt; an awesome development and debugging tool. I love working on it; it is a good way to get familiar with PHP's "interesting" internals, and it also helps PHP developers finding (potential) issues within their code base faster.&lt;/p&gt;
      &lt;p&gt;With the 2.0 release announcement I &lt;a href="http://derickrethans.nl/xdebug-2-released.html"&gt;asked&lt;/a&gt; users of Xdebug to send me a postcard if they liked it; and since the 2.1 announcement I &lt;a href="http://drck.me/xdebug-2.1-7x2"&gt;mention&lt;/a&gt; that it is possible to give &lt;a href="http://xdebug.org/donate.php"&gt;donations&lt;/a&gt; through PayPal. I have received quite few postcards and donations.&lt;/p&gt;
      &lt;p&gt;Recently, an &lt;a href="https://bugs.kde.org/show_bug.cgi?id=256425#c10"&gt;issue&lt;/a&gt; with &lt;a href="http://kcachegrind.sourceforge.net/html/Home.html"&gt;KCacheGrind&lt;/a&gt; and Xdebug's &lt;a href="http://xdebug.org/docs/profiler"&gt;profiler&lt;/a&gt; functionality became known. As an &lt;a href="http://sebastian-bergmann.de/archives/909-On-Sponsored-Open-Source-Development.html"&gt;experiment&lt;/a&gt; Sebastian suggested to see whether it would be a good idea to set-up a pledge-like system to arrange some funding so that I can dedicate my "work time" to working on Xdebug issues and features.  I set-up a &lt;a href="http://pledgie.com/campaigns/14641"&gt;campaign&lt;/a&gt; on &lt;a href="http://pledgie.com"&gt;Pledgie&lt;/a&gt; for this purpose. Both Sebastian and I expected Pledgie to work a bit different than it actually did. Instead of holding on to the pledged money until the issue was implemented, it transfered the pledges directly to my PayPal account.&lt;/p&gt;
      &lt;p&gt;Twenty-four pledges were made, in about two weeks; matching the goal. Thanks Sebastian, Jan, Michael, &lt;a href="http://www.palepurple.co.uk/"&gt;Pale Purple&lt;/a&gt;, Jeff, Christoph, Karel, Yannick, Jake, Venakis, Brian, Simon, Kenneth, DM Baker, "gizmola", Ladislav, Volker, &lt;a href="http://www.react.nl/"&gt;React&lt;/a&gt;, Michal and three anonymous supporters!&lt;/p&gt;
      &lt;p&gt;Last night I &lt;a href="http://xdebug.org/archives/xdebug-dev/1740.html"&gt;committed&lt;/a&gt; several patches to the Xdebug &lt;a href="http://svn.xdebug.org/cgi-bin/viewvc.cgi/xdebug/?root=xdebug"&gt;repository&lt;/a&gt;, including the one that sparked the idea to set-up a pledge to fund Xdebug's profiler files. These patches, and a few others, now form part of the upcoming Xdebug 2.1.1 release. I've published the &lt;a href="http://xdebug.org/download.php#releases"&gt;source&lt;/a&gt; package for the first (and most likely only) release candidate: &lt;a href="http://xdebug.org/updates.php#x_2_1_0rc1"&gt;Xdebug 2.1.1RC1&lt;/a&gt;. Windows binaries will follow shortly. You can also install/upgrade the release candidate through PECL: &lt;code&gt;pecl install xdebug-beta&lt;/code&gt; or &lt;code&gt;pecl upgrade xdebug-beta&lt;/code&gt;.&lt;/p&gt;
      &lt;p&gt;The Pledgie campaign has now been closed, but I am intending to set-up new ones for more of the elaborate features—most likely starting with one related to Xdebug's &lt;a href="http://xdebug.org/docs/code_coverage"&gt;code coverage&lt;/a&gt; functionality. In the meanwhile, please test &lt;a href="http://xdebug.org/updates.php#x_2_1_0rc1"&gt;Xdebug 2.1.1RC1&lt;/a&gt;, and let me know your comments about sponsoring specific Xdebug features. I plan on releasing to write up some more thoughts about that soon. I expect Xdebug 2.1.1 to come out before the end of the month. If you think Xdebug is useful, feel free to &lt;a href="http://xdebug.org/donate.php"&gt;donate&lt;/a&gt; as well!&lt;/p&gt;
      
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>201103221830</guid>
      <pubDate>Tue, 22 Mar 2011 18:30:00 +0000</pubDate>
    </item>
    <item>
      <title>Spatial Indexes: Calculating Distance</title>
      <link>http://derickrethans.nl/spatial-indexes-calculating-distance.html</link>
      <description>&lt;div class="article"&gt;
  &lt;div class="body"&gt;
    &lt;div class="articleListItem"&gt;
      &lt;h1&gt;&lt;a name="spatial_indexes_calculating_distance"/&gt;Spatial Indexes: Calculating Distance&lt;/h1&gt;
      &lt;dl class="head"/&gt;
      &lt;div class="articleMetaData"&gt;
        &lt;div class="location"&gt; Montréal, Canada&lt;/div&gt;
        &lt;div class="date"&gt;Wednesday, March 9th 2011, 07:17 EST&lt;/div&gt;
      &lt;/div&gt;
      &lt;p&gt;During my "Geolocation and Mapping with PHP" talk that I've given a few times I briefly touch on the subject of indexes on data-sets of spatial data. This isn't as simple as just solving &lt;a href="http://en.wikipedia.org/wiki/Pythagorean_theorem"&gt;Pythagoras theorem&lt;/a&gt; and this article is meant to clarify this.&lt;/p&gt;
      &lt;p&gt;
        &lt;strong&gt;The flat Earth model&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;Pythagoras theorem can be used to calculate the distance between two points quite easily; you take the square root of the square of the absolute vertical distance plus the square of the absolute horizontal distance; in short:&lt;/p&gt;
      &lt;pre&gt;d = √(|x1 - x2|² + |y1 - y2|²)

&lt;/pre&gt;
      &lt;p&gt;or in PHP:&lt;/p&gt;
      &lt;pre&gt;$d = sqrt(pow(abs($x1 - $x2), 2) + pow(abs($y1 - $y2), 2));

&lt;/pre&gt;
      &lt;p&gt;If you take for example London's coordinates (51.50°N, 0.13°W) and Amsterdam's coordinates (52.37°N, 4.90°E) we can calculate the distance with:&lt;/p&gt;
      &lt;pre&gt;d = √(|-0.13 - 4.90|² + |51.50 - 52.37|²)
d = √(5.03² + 0.87²)
d = √(26.0578)
d ≅ 5.10

&lt;/pre&gt;
      &lt;p&gt;And on a map:&lt;/p&gt;
      &lt;img src="http://derickrethans.nl/images/content/distance-amsterdam-london.png" alt="distance-amsterdam-london.png"/&gt;
      &lt;p&gt;But what does a difference of "5.10°" actually mean? How far is this in useful units, such as meters?&lt;/p&gt;
      &lt;p&gt;If we show the whole map of which the above is an extract, we come to:&lt;/p&gt;
      &lt;img src="http://derickrethans.nl/images/content/map-flat.png" alt="map-flat.png"/&gt;
      &lt;p&gt;The distance around the equator, and through the poles is roughly the same, 40.000km (please be aware that the blue line only shows half of it, the other half is going through the anti-meridian at 180°W/E). 5.03° in East-West difference is then about &lt;code&gt;40 000 ✕ (5.03/360) = 559 km&lt;/code&gt; and the North-South difference about &lt;code&gt;20 000 ✕ (0.87/180) = 97 km&lt;/code&gt;. Using those numbers within the Pythagoras theorem we end up with a distance of &lt;code&gt;√(559² + 97²) = 567 km&lt;/code&gt;. Although the calculation is correct, the answer is still wrong. The real distance is closer to 360 km.&lt;/p&gt;
      &lt;p&gt;
        &lt;strong&gt;The spherical Earth model&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;If we look at the Earth in its original (mostly) spherical &lt;a href="http://derickrethans.nl#_footnote_0_1" class="footnote"&gt;1&lt;/a&gt; shape, then it's clear that 10° longitude (East/West) at 60°N is going to be less of a distance than 10°E/W at the equator. It's actually fairly easy to calculate how much 1° longitude is at 60°N by using &lt;code&gt;cos(60) * 1/360 * 6371 * 2π&lt;/code&gt; &lt;a href="http://derickrethans.nl#_footnote_0_2" class="footnote"&gt;2&lt;/a&gt;. Or in PHP:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
$oneDeg =
        cos(deg2rad(60)) * // adjustment for latitude and radians/degrees
        1/360 * // 1 out of 360°
        6371 * 2 * M_PI, // circumference of the Earth at the equator
        "\n";
?&gt;

&lt;/pre&gt;
      &lt;p&gt;This returns &lt;code&gt;55.597 km per °&lt;/code&gt; for 60°N. The same distance in degrees on the Equator gives &lt;code&gt;6371 * 2 * M_PI / 360 = 111.195&lt;/code&gt;.&lt;/p&gt;
      &lt;p&gt;The following diagram shows ones more that latitudinal degrees always correspond with the same distance in kilometer, whereas longitudinal degrees differ.&lt;/p&gt;
      &lt;img src="http://derickrethans.nl/images/content/sphere2.png" alt="sphere2.png"/&gt;
      &lt;p&gt;In the diagram the line A is a line from 0°N, 90°W to 10°N, 90°W. It has the same length as line B, from 30°N, 90°W to 40°N, 90°W: a 36th of the circumference of the Earth through the poles. Line C, from 0°N, 30°W to 0°N, 20°W has the same length. Line D however, from 50°N, 30°W to 50°N, 20°W is shorter by a factor of &lt;code&gt;cos(50°) ≅ 0.64&lt;/code&gt;.&lt;/p&gt;
      &lt;p&gt;If we look again at the distance between London and Amsterdam, ignore the differences in latitude and instead pick the average, we see:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
$d = abs(-0.13 - 4.90);
// $d = 5.03 degrees

$e = 5.03/360 * cos(deg2rad(51.935)) * 6371 * 2 * M_PI;
$e = 5.03 * 0.617 * 6371 * 2 * M_PI;
// $e ≅ 345 km
?&gt;

&lt;/pre&gt;
      &lt;p&gt;Which is a bit shorter than the expected 360km, but that's because we conveniently forgot about the difference in latitude.&lt;/p&gt;
      &lt;p&gt;Sadly, we can't use Pythagoras's theorem to calculate the real distance with the latitude difference taken account as well. This is because the theorem is meant for &lt;a href="http://en.wikipedia.org/wiki/Euclidean_geometry"&gt;Euclidean&lt;/a&gt; geometry, and a sphere does not follow the rules of this geometry. Instead we need to use a formula that is called the &lt;a href="http://en.wikipedia.org/wiki/Great-circle_distance"&gt;great-circle distance&lt;/a&gt; formula. The main concept behind it is that a circle is drawn across the whole sphere that connects both the start (point P) as well as the end (point V). Then with that circle the distance can be calculated. The following diagram shows this:&lt;/p&gt;
      &lt;img src="http://derickrethans.nl/images/content/great-circle.jpg" alt="great-circle.jpg"/&gt;
      &lt;p&gt;I will spare you how the function is derived, but the distance calculation ends up as being:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
function distance($latA, $lonA, $latB, $lonB)
{
        // convert from degrees to radians
        $latA = deg2rad($latA); $lonA = deg2rad($lonA);
        $latB = deg2rad($latB); $lonB = deg2rad($lonB);

        // calculate absolute difference for latitude and longitude
        $dLat = ($latA - $latB);
        $dLon = ($lonA - $lonB);

        // do trigonometry magic
        $d =
                sin($dLat/2) * sin($dLat/2) +
                cos($latA) * cos($latB) * sin($dLon/2) *sin($dLon/2);
        $d = 2 * asin(sqrt($d));
        return $d * 6371;
}
?&gt;

&lt;/pre&gt;
      &lt;p&gt;If we punch in our original numbers form London (51.50°N, 0.13°W) and Amsterdam (52.37°N, 4.90°E), we calculate the following:&lt;/p&gt;
      &lt;pre&gt;&lt;?php
$d = distance(51.50, -0.13, 52.37, 4.90);
echo $d, " km\n";
?&gt;

&lt;/pre&gt;
      &lt;p&gt;Which gives us the expected result of &lt;code&gt;358.07 km&lt;/code&gt;.&lt;/p&gt;
      &lt;p&gt;
        &lt;strong&gt;Conclusion&lt;/strong&gt;
      &lt;/p&gt;
      &lt;p&gt;I hope that the above clarified the difference between 2D spatial indexing with the &lt;em&gt;flat Earth model&lt;/em&gt; and spatial indexing of geo-located data (&lt;em&gt;the spherical Earth model&lt;/em&gt;). In future articles I will go into specific implementations of spatial indexing by traditional databases such as SQLite, MySQL and PostGreSQL; NoSQL databases such as MongoDB and CouchDB; and Solr.&lt;/p&gt;
      
      
    &lt;/div&gt;
    &lt;ul class="footnotes"&gt;
      &lt;li&gt;
        &lt;a name="_footnote_0_1"&gt;1&lt;/a&gt;
        &lt;p&gt;The Earth is not really a sphere, but an approximation of it. However, doing the same calculations for an ellipsoid can (as far as I know) only be done by approximation. The difference would hardly matter for finding the closest pub.&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;a name="_footnote_0_2"&gt;2&lt;/a&gt;
        &lt;p&gt;In this article, I've used an average radius of the Earth of 6371 km.&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>201103090717</guid>
      <pubDate>Wed, 09 Mar 2011 12:17:00 +0000</pubDate>
    </item>
  </channel>
</rss>

