Laravel: Get Latitude/Longitude from Address with Geocoder

Laravel Google Maps API Geocoder

While working on a demo project, I needed to get the geographical coordinates of a real estate object, by its address: street, postcode, city, and country. In this tutorial, I will show you how to use a package called GeocoderLaravel, to achieve this.

GeocoderLaravel package is a Laravel wrapper around another package called Geocoder PHP, created for easier use within Laravel framework specifically.

Both packages have a lot of features, but we're interested in this scenario.

  • Example Input: "16-18, Argyle Street, Camden, London, WC1H 8EG, United Kingdom"
  • Example Output: [51.5291450, -0.1239401]

To do that, we need to use one of the 3rd party Geolocation services. There are a lot of them, including the ones that have API, but probably the most simple one is Google Maps API.

Important notice: using Google Maps API (and the majority of the other similar services) is not free. They may have some limited free usage, so check their pricing docs. Keep in mind that you need to watch the usage cause they often charge per API call.

Now, step by step.

Step 1. Install GeocoderLaravel Package

composer require toin0u/geocoder-laravel
php artisan vendor:publish --provider="Geocoder\Laravel\Providers\GeocoderService"

Simple, right?


Step 2. Add Google Maps API Key

Google Maps API Key looks something like this: AIzaSyAWRsRGOFbTXRlLHDOSudkerLjUtBfElUt. You can read here how to register and get that key.

After you do that, you can put it into the Laravel config.

GeocoderLaravel package comes with its config, supporting various providers of Geolocation.

config/geocoder.php:

return [
// ...
 
'providers' => [
Chain::class => [
GoogleMaps::class => [
env('GOOGLE_MAPS_LOCALE', 'us'),
env('GOOGLE_MAPS_API_KEY'), // <- THIS IS WHAT WE NEED
],
GeoPlugin::class => [],
],
],
 
// ...
];

As you can see, GoogleMaps is the provider enabled by default, so all you need to do is provide the API key in the .env file.

.env:

APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:wgvwuEojBNlCrmg7Pmn3x...
APP_DEBUG=true
 
## ...
 
GOOGLE_MAPS_API_KEY=AIzaSyAWRsRGOFbTXRlLHDOSudkerLjUtBfElUt

Notice: protect your .env file and this API key, cause, as I stated above, you are charged for API calls, so someone with that API key may directly damage you financially. Also, you can protect that API key from Google Maps API settings, restricting it by domain or other parameters.


Step 3. Call Geocoder For Coordinates

Here's a snippet that will get you the data:

$address = "16-18, Argyle Street, Camden, London, WC1H 8EG, United Kingdom";
$result = app('geocoder')->geocode($address)->get();
$coordinates = $result[0]->getCoordinates();
$lat = $coordinates->getLatitude();
$long = $coordinates->getLongitude();

Since we're using the global helper app('geocoder'), you can call it wherever you want: in Controller, Queued Job, Service class, etc.

Obviously, you are not guaranteed to get the results, especially if your address is inputted by your users. So, you should check if there are results returned.

Also, you may want to put this logic somewhere in the Job that would be fired and put into the queue, to avoid users waiting for a few seconds to get the API results.

So, simple piece of code, but a lot of caveats and potential things to go wrong. That said, when it does go well, it feels like simple magic!

avatar

Hello,

I work on Windows 11 in a local environment with php artisan serve and use the Mapbox provider instead of Google. I have followed the above steps with some slight changes because of the different provider, but I don't get any results back.

After some debugging I found out it must have somthing to do with the lack of ssl encryption in my local environment. A fix was to change a package file, to use the http adapter without verifcation.

Because I don't want to edit the package files I tried Symfony's webserver with ssl, which didn't solve the problem.

Do you had the same problem? If not not, how does your local environment look like?

Thanks in advance.

avatar

Need more details here.

  1. What do you mean "don't get any results back", what is the actual error message?
  2. "change a package file" - which file, what change?

Personally I don't use Windows, but maybe from your error messages, I can help you in googling the solution.

avatar

Thanks for your reply.

  1. As a response to my request I'm just getting an empty collection back.
[2023-04-11 07:38:46] local.ALERT: Provider "{providerName}" could not geocode address: "{address}". {"exception":"[object] (GuzzleHttp\\Exception\\RequestException(code: 0): cURL error 60: SSL certificate problem: unable to get local issuer certificate (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) for https://api.mapbox.com/geocoding/v5/mapbox.places/16-18%2C%20Argyle%20Street%2C%20Camden%2C%20London%2C%20WC1H%208EG%2C%20United%20Kingdom.json?types=address&limit=5&access_token=/*ACCESS TOKEN*/ at C:\\...\\vendor\\guzzlehttp\\guzzle\\src\\Handler\\CurlFactory.php:211)
  1. To solve this error I edited these files individually and both fixes worked: .\vendor\geocoder-php\mapbox-provider\Mapbox.php L:33
(-) const GEOCODE_ENDPOINT_URL_SSL = 'https://api.mapbox.com/geocoding/v5/%s/%s.json';
(+) const GEOCODE_ENDPOINT_URL_SSL = 'http://api.mapbox.com/geocoding/v5/%s/%s.json';

.vendor\toin0u\geocoder-laravel\src\ProviderAndDumperAggregator.php L:268

(-) $adapter = new $adapter;
(+) $adapter = new $adapter([
	'verify' => false
]);

Both the error and my temporary fixes lead to an missing ssl certificate, which the use the symfony server should have solved. Do you have any other ideas what I can try or maybe a suggestion for another local development environment?

avatar

It actually had to do with my local environment. The Symfony server was not sufficient because PHP still did not have an SSL certificate set up.

This helped me: https://docs.boltcms.io/5.0/howto/curl-ca-certificates

Anyway, thanks for your time, Povilas and for the great content both here and on Youtube. I really appreciate your work.

avatar

This looks like a fantastic and robust package, but I am having a hard time figuring out how to get local filesystem or database based caching to run with. The docs provide a Redis example but I can't use that in my environment. Can't seem to find Laravel-specific examples on the web. Does anyone have a link or a hint?

avatar

I did some digging on this to find a PSR-6 compatible filesystem caching adapter. I found two, duncan3dc/cache and cache/filesystem-adapter, but both have versioning problems with Laravel 10. THe former package doesn't seem to be maintained at all, the latter requires Flysystem ^1.0 while Laravel 10 comes with 3.8 and the maintainer isn't processing pull requests to get this updated.

Any ideas would be welcome!

Like our articles?

Become a Premium Member for $129/year or $29/month
What else you will get:
  • 59 courses (1056 lessons, total 44 h 09 min)
  • 78 long-form tutorials (one new every week)
  • access to project repositories
  • access to private Discord

Recent Premium Tutorials