Mapping with Geocoder PHP and Leaflet.js

Share this article

Interactive maps inside a web application have a lot of great uses. From visualizing data to highlighting points of interest, maps are expected to communicate ideas within the context of location easily.

The hardest part, however, is converting that data into coordinates that the map can understand. Luckily, Geocoder PHP allows us to connect to different geo-coding providers. Combined with Leaflet.js, a simple Javascript library, creating maps is a breeze.

Starting

With Composer, including the Geocoder PHP library is simple:

{
  "require": {
    "willdurand/geocoder": "*"
  }
}

Let’s also add some html to a simple index.php file to include Bootstrap so that we have a nice-looking environment to display our map in:

<?php
require 'vendor/autoload.php';

?>
<!DOCTYPE html>
<html>
<head>
    <title>A simple map with Geocoder PHP and Leaflet.js</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css">
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-lg-12 page-header">
            <h1 id="header">A simple map with Geocoder PHP and Leaflet.js</h1>
        </div>
        <div class="row-fluid">
            <div class="col-lg-8">

            </div>
        </div>
    </div><!-- /row -->
</div> <!-- /container -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
</body>
</html>

Setting Up Geocoder

Geocoder bills itself as the missing the geocoder library for PHP. It can be used in three simple steps:

  1. Register an adapter
  2. Register a provider
  3. Geocode!

Register an Adapter

The adapter serves as the mechanism to connect and get data to your chosen provider via their API. Some adapters use the built-in functionality within PHP 5.3+, like cURL and sockets. Others, like Buzz, Guzzle, and Zend HTTP Client, use third-party open source libraries that simply require you to add their dependency to your composer file.

The beauty of the Geocoder library is this abstraction of the adapter step. It allows you swap out your adapter if your needs change without requiring you to rewrite how your application receives the data.

For this example, we’re going to use cURL and the included CurlHTTPAdapter class inside the Geocoder PHP library.

In our index.php file, let’s add the adapter:

// Setup geocoder adapter.
$adapter = new \Geocoder\HttpAdapter\CurlHttpAdapter();

Register a provider

There are many geocoding providers that are supported out-of-the-box by the Geocoder PHP library, including Google Maps, Bing Maps, Nominatim via Openstreetmap, and TomTom.

The full list can be found on the README of the Geocoder PHP repository.

Each provider, as represented by its respective classes, has its own options. Depending on your needs, you can register multiple providers for various circumstances. This may be useful if your application needs to map specific streets in San Jose, Costa Rica using Openstreetmap and find a quick route in Beijing, China using Baidu.

For this example, I’ll simply use Google Maps, but register it in a way that if I want to add another provider in the future, I simply need to add it to an array:

// Create a chain of providers.
// Be sure to include my previously created adapter.
$chain = new \Geocoder\Provider\ChainProvider(
    array(
        new \Geocoder\Provider\GoogleMapsProvider($adapter),
    )
);

// Instantiate the geocoder.
$geocoder = new \Geocoder\Geocoder();

// Register my providers.
$geocoder->registerProvider($chain);

Geocode

We can now pass the address to the geocode() method inside your newly instantiated $geocoder object. This will return a result object that is instantiated through the provider chosen earlier. This result object has getLatitude() and getLongitude() methods we can use.

// Demo locations
$locations = array(
    array(
        'address' => '3324 N California Ave, Chicago, IL, 60618',
        'title' => 'Hot Dougs',
    ),
    array(
        'address' => '11 S White, Frankfort, IL, 60423',
        'title' => 'Museum',
    ),
    array(
        'address' => '1000 Sterling Ave, , Flossmoor, IL, 60422',
        'title' => 'Library',
    ),
    array(
        'address' => '2053 Ridge Rd, Homewood, IL, 60430',
        'title' => 'Twisted Q',
    )
);

foreach ($locations as $key => $value) {
    // Try to geocode.
    try {
        $geocode = $geocoder->geocode($value['address']);
        $longitude = $geocode->getLongitude();
        $latitude = $geocode->getLatitude();

    } catch (Exception $e) {
        echo $e->getMessage();
    }
}

Integrating with Leaflet.js

Leaflet.js is a powerful javascript library that makes mapping very easy.

Maps consist of three parts:

  1. Tiles
  2. Interaction layer (typically through Javascript and CSS)
  3. Data points

The tiles are the 256 by 256 pixel squares that show the map detail. Services like Mapbox and Cloudmade allow you to create your own tilesets. For this example, I’ve created a free account with Cloudemade and will use the API key given to show tiles from their hosting service.

The interaction layer is handled by Leaflet.js. I simply include the Leaflet Javascript and CSS library into our starter HTML template:

<link rel="stylesheet" href="//cdn.leafletjs.com/leaflet-0.6.4/leaflet.css" />
<script src="//cdn.leafletjs.com/leaflet-0.6.4/leaflet.js"></script>

The data points have been created earlier with my geocoder code. I simply have to format the array of data in a way Leaflet expects.

In this simple example, I’m simply going to create individual markers as Javascript variables that will be included in my map via strings produced by PHP.

Leaflet has the option for this data to also be passed in via the geoJSON format for larger and more dynamic datasets.

$mapdata = $marker_group = array();

foreach ($locations as $key => $value) {
    // Try to geocode.
    try {
        $geocode = $geocoder->geocode($value['address']);
        $longitude = $geocode->getLongitude();
        $latitude = $geocode->getLatitude();

        // Create map data array
        $mapdata[] = markerCreator($latitude, $longitude, $value['title'], $key);

        // Marker grouping array
        $marker_group[] = "marker{$key}";

    } catch (Exception $e) {
        echo $e->getMessage();
    }
}

function markerCreator($lat, $long, $label, $key) {
    return "var marker{$key} = L.marker([{$lat}, {$long}]).addTo(map);
    marker{$key}.bindPopup(\"{$label}\");";
}

Because Leaflet injects the map code into an existing DOM element, we first have to define that element inside our HTML. We can do this by simply creating a div with a unique id:

<div id="map"></div>

We can then target that id in Leaflet by calling the built-in map() Javascript method and pass in our id in the footer:

var map = L.map('map');

Now, we build the three parts of our map. To register the tiles, we simply call the built-in tileLayer() method, defining attributes and zoom level if desired, then appending the addTo() method:

L.tileLayer('//{s}.tile.cloudmade.com/41339be4c5064686b781a5a00678de62/998/256/{z}/{x}/{y}.png', {maxZoom: 18}).addTo(map);

Finally, we print our map data using the PHP array we defined earlier, and make sure the map centers itself on those data points by defining them together as group. All in all, the Javascript in the footer would be:

<script>
    var map = L.map('map');

    L.tileLayer('//{s}.tile.cloudmade.com/41339be4c5064686b781a5a00678de62/998/256/{z}/{x}/{y}.png', {maxZoom: 18}).addTo(map);

    <?php print implode('', $mapdata); ?>

    var group = new L.featureGroup([<?php print implode(', ', $marker_group); ?>]);
    map.fitBounds(group.getBounds());
</script>

If you’ve gotten this far, you’ll notice that nothing happens.

This is because Leaflet does not inject properties on the height or width of the map div, allowing you to style it and resize it as you please. Simply give your div a height and width, and your map should appear!

Conclusion

You can create beautiful, interactive maps with the Geocoder PHP library and Leaflet.js. Be sure to check out the respective documentation of each project as there are many more advanced customizations that are possible.

Check out the demo for this article or fork it over at Github.

Frequently Asked Questions (FAQs) about Mapping with Geocoder PHP and Leaflet JS

How Can I Integrate Leaflet JS with PHP?

Integrating Leaflet JS with PHP involves a few steps. First, you need to include the Leaflet JS library in your PHP file. This can be done by downloading the library and linking it in your PHP file or by using a CDN. Once the library is included, you can initialize a map using the L.map() function. You can then add layers, markers, and other features to the map using various Leaflet JS functions. The data for these features can be fetched from a database using PHP and then passed to the Leaflet JS functions.

What is Geocoding and How is it Used in Leaflet JS?

Geocoding is the process of converting addresses into geographic coordinates, which you can use to place markers on a map, or position the map. In Leaflet JS, you can use a geocoding service like Nominatim or Google’s Geocoding API to convert addresses into coordinates. Once you have the coordinates, you can use the L.marker() function to place a marker on the map at the specified coordinates.

How Can I Use PHP to Fetch Data from a Database for My Map?

PHP can be used to fetch data from a database by using its built-in functions for database interaction. For example, if you’re using a MySQL database, you can use the mysqli_connect() function to connect to the database, and then use the mysqli_query() function to execute a SQL query and fetch data. The fetched data can then be passed to the Leaflet JS functions to add features to the map.

How Can I Add Interactive Features to My Map?

Leaflet JS provides various functions to add interactive features to your map. For example, you can use the L.popup() function to add popups to your map, which can display additional information when a marker or other feature is clicked. You can also use the L.control.layers() function to add a layers control, which allows users to switch between different base layers and overlay layers.

How Can I Customize the Appearance of My Map?

The appearance of your map can be customized using various Leaflet JS options and functions. For example, you can use the setView() function to set the initial geographic center and zoom level of the map. You can also use the L.tileLayer() function to add a tile layer to the map, which determines the visual appearance of the map’s base layer. The options parameter of the L.map() function can be used to set various other options, such as the map’s maximum zoom level, whether to display attribution control, and so on.

How Can I Handle Errors When Using Geocoding Services?

When using geocoding services, errors can occur for various reasons, such as network issues, invalid input, or exceeding the service’s usage limits. These errors can be handled by using error handling techniques provided by the programming language you’re using. For example, in PHP, you can use the try-catch statement to catch exceptions and handle them appropriately.

How Can I Optimize the Performance of My Map?

There are several ways to optimize the performance of your map. One way is to use a tile layer that is optimized for performance, such as a vector tile layer. Another way is to limit the number of features displayed on the map at once, for example by using clustering or by only displaying features within the current map view. You can also optimize the performance of your PHP code by using efficient database queries and by caching results when appropriate.

How Can I Make My Map Responsive?

Making your map responsive involves ensuring that it displays correctly on different screen sizes and devices. This can be achieved by using CSS media queries to adjust the size and layout of the map container based on the screen size. You can also use the Leaflet JS map.invalidateSize() function to update the map’s size and position when the size of its container changes.

How Can I Add Custom Markers to My Map?

Custom markers can be added to your map by using the L.icon() function. This function allows you to specify a custom image to be used as the marker icon. You can also specify the size, anchor point, and other properties of the icon. The custom icon can then be used when creating a marker by passing it as an option to the L.marker() function.

How Can I Use Leaflet JS to Display Data from a GeoJSON File?

Leaflet JS provides the L.geoJSON() function, which can be used to display data from a GeoJSON file on your map. This function takes a GeoJSON object as input and creates a layer containing the features described by the GeoJSON data. The features can be styled and interacted with using various options and methods provided by the L.geoJSON() function. The GeoJSON data can be fetched from a file or a server using PHP or JavaScript.

Fredric MitchellFredric Mitchell
View Author

Fredric has many years of experience in the IT field, including as a consultant in healthcare IT, an an Interaction Designer, a Lead Developer on a large government project and a Web Development Manager. Since the days of the Tandy 3000, tinkering has always been a passion, and it continues with his Legos and Raspberry Pi.

geocoderleafletmappingmaps
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week