PHP Geocoding Tutorial

This is a tutorial for using the OpenCage geocoding API in PHP.

Topics covered in this tutorial

Background

The code examples below will use your geocoding API key once you log in.

Before we dive in to the tutorial

  1. Sign up for an OpenCage geocoding API key.
  2. Play with the demo page, so that you see the actual response the API returns.
  3. Browse the API reference, so you understand the optional parameters, best practices, possible response codes, and the rate limiting on free trial accounts.

PHP libraries for accessing the OpenCage Geocoding API

There are two PHP libraries you can use:

The PHP wrapper attempts to use the CURL extension to access the API. If CURL support is not available, the library falls back to using fopen wrappers.

PHP 8 is supported. For PHP 7.4 you need to use an older version of the library, e.g. version 3.1.0.

To use the wrapper you must either have the CURL extension compiled into your version of PHP or configure the use of fopen wrappers via the allow_url_fopen directive in your php.ini.

The recommended - and easiest way - to install is via Composer. Require the library in your project's composer.json file.

composer require opencage/geocode

Import the Geocoder class.

require "vendor/autoload.php";

Geocode an address (forward geocoding)

$geocoder = new \OpenCage\Geocoder\Geocoder('YOUR-API-KEY');
# no need to URI encode the query, the library does this for you
$result = $geocoder->geocode('82 Clerkenwell Road, London, UK');
print_r($result);

# set optional parameters
# see the full list: https://opencagedata.com/api#optional-params
#
$result = $geocoder->geocode('6 Rue Massillon, 30020 Nîmes, France', ['language' => 'fr', 'countrycode' => 'fr']);
if ($result && $result['total_results'] > 0) {
  $first = $result['results'][0];
  print $first['geometry']['lng'] . ';' . $first['geometry']['lat'] . ';' . $first['formatted'] . "\n";
  # 4.360081;43.8316276;6 Rue Massillon, 30020 Nîmes, Frankreich
}

Geocode coordinates (reverse geocoding)

$geocoder = new \OpenCage\Geocoder\Geocoder('YOUR-API-KEY');
$result = $geocoder->geocode('43.831,4.360'); # latitude,longitude (y,x)
print $result['results'][0]['formatted'];
# 3 Rue de Rivarol, 30020 Nîmes, France

Batch geocode addresses

$geocoder = new \OpenCage\Geocoder\Geocoder('YOUR-API-KEY');

$addresses = ['London', 'Paris, France', 'Berlin'];
$results = [];

foreach ($addresses as $address) {
  $result = $geocoder->geocode($address);
  $msg = $result['status']['message'];
  if ($msg == 'OK'){
      $results[$address] = $result;
  } else {
      error_log("failed to geocode '$addresses' : $msg");
  }
}

Set optional parameters

See the full list

$result = $geocoder->geocode('6 Rue Massillon, 30020 Nîmes, France', [
    'language' => 'fr',
    'countrycode' => 'fr'
]);
if ($result && $result['total_results'] > 0) {
  $first = $result['results'][0];
  print $first['geometry']['lng'] . ';' . $first['geometry']['lat'] . ';' . $first['formatted'] . "\n";
  // 4.360081;43.8316276;6 Rue Massillon, 30020 Nîmes, Frankreich
}

Set a proxy URL

$geocoder->setProxy('http://proxy.example.com:1234');
$result = $geocoder->geocode("Brandenburger Tor, Berlin");
print_r($result['results'][0]['formatted']);
// Brandenburger Tor, Unter den Linden, 10117 Berlin, Germany
print_r($result['results'][0]['geometry']);
// Array
// (
//    [lat] => 52.5166047
//    [lng] => 13.3809897
// )

Geocoding faster by running queries in parallel

We created an example how to geocode a file with parallel threads.

Before you start geocoding at high volume, please read our guide to geocoding large datasets where we explain various strategies and points to consider.

The recommended - and easiest way - to install is via Composer. Require the library in your project's composer.json file.

composer require willdurand/geocoder

Import the Geocoder class.

require "vendor/autoload.php";

use Http\Adapter\Guzzle6\Client as GuzzleAdapter;
use Geocoder\Query\GeocodeQuery;
use Geocoder\Query\ReverseQuery;

Geocode an address (forward geocoding)

$adapter  = new GuzzleAdapter();
$provider = new \Geocoder\Provider\OpenCage\OpenCage($adapter, 'YOUR-API-KEY');
$geocoder = new \Geocoder\StatefulGeocoder($provider, 'en');

$results = $geocoder->geocodeQuery(GeocodeQuery::create('1 Hacker Way, Menlo Park, 94025'));
# print_r($results);

$coords = $results->first()->getCoordinates();

echo json_encode([ 'lat' => $coords->getLatitude(), 'lon' => $coords->getLongitude() ]) . "\n";

Batch geocode addresses

$adapter  = new GuzzleAdapter();
$provider = new \Geocoder\Provider\OpenCage\OpenCage($adapter, 'YOUR-API-KEY');
$geocoder = new \Geocoder\StatefulGeocoder($provider, 'en');

$addresses = ['London', 'Paris', 'Berlin'];
$results = [];

foreach ($addresses as $address) {
  $result = $geocoder->geocodeQuery(GeocodeQuery::create($address));
  $msg = $result['status']['message'];
  if ($msg === 'OK') {
      $results[$address] = $result;
  } else {
      error_log("failed to geocode '$addresses' : $msg");
  }
}

Geocode coordinates (reverse geocoding)

$adapter  = new GuzzleAdapter();
$provider = new \Geocoder\Provider\OpenCage\OpenCage($adapter, 'YOUR-API-KEY');
$geocoder = new \Geocoder\StatefulGeocoder($provider, 'en');

$results = $geocoder->reverseQuery(ReverseQuery::fromCoordinates(37.4856225, -122.1468803));
# print_r($results);

echo $results->first()->getStreetName() . "\n";

Start your free trial

2,500 geocoding API requests per day.

No credit card required.