php Validate latitude/longitude strings in decimal format
Alright I have what I would call a massive list of longitude and latitude coordinates. That said I also have a handful of sources I pull these coordinates in from. Some of them come from get/post methods which can cause potential security holes in my site/service. So I am trying to figure out开发者_如何学编程 how to validate longitude and latitude via PHP. I was thinking something regex via preg_match. But I could be wrong, maybe there's an easier way someone would like to suggest. I've tried my own concepts, and I have tried various internet brew concepts of trying to find a regex pattern that will validate these for me via preg_match (or similar again if you got a better suggestion I am all ears).
My Last failed attempt prior to finally caving in and coming here was..
preg_match('^(\-?\d+(\.\d+)?),\s*(\-?\d+(\.\d+)?)$', $geoResults['latitude']))
which yields " preg_match() [function.preg-match]: No ending delimiter '^' found " as my error. Last couple attempts I have tried yielded that error so I have no idea what it is or means.
It's a bit old question, but anyway I post my solution here:
preg_match('/^[-]?(([0-8]?[0-9])\.(\d+))|(90(\.0+)?);[-]?((((1[0-7][0-9])|([0-9]?[0-9]))\.(\d+))|180(\.0+)?)$/', $geoResults['latlng']);
I assumed here that u split lat. from lng. by semicolon. If u want to check only lat. or only lng. here are regexp's;
Rgx for lat.:
/^[-]?(([0-8]?[0-9])\.(\d+))|(90(\.0+)?)$/
Rgx for lng.:
/^[-]?((((1[0-7][0-9])|([0-9]?[0-9]))\.(\d+))|180(\.0+)?)$/
Here is an improved online demo: https://regex101.com/r/bV5fA1/1
Add forward slashes to the beginning and end of the match sequence to make it valid regex syntax:
preg_match('/^(\-?\d+(\.\d+)?),\s*(\-?\d+(\.\d+)?)$/', $geoResults['latitude']);
For your question on whether to use regular expressions (regex) or not, in this case using regex (PCRE preg_match()
) is the best way to secure your site. When matching variable complex string arrangements, regex is the way to go. It's common for developers to turn to regex for matching a static string such as 'abc'. This is when strpos()
or str_replace()
are better choices.
Why not use modern and unit tested Assertion library for that?
Example Value Object class:
<?php
namespace MyApp\ValueObject;
use Assert\Assertion;
class Location
{
private $lat;
private $lon;
public function __construct($lat, $lon)
{
Assertion::greaterOrEqualThan($lat, -90.0);
Assertion::lessOrEqualThan($lat, 90.0);
Assertion::greaterOrEqualThan($lon, -180.0);
Assertion::lessOrEqualThan($lon, 180.0);
$this->lat = $lat;
$this->lon = $lon;
}
public function latitude()
{
return $this->lat;
}
public function longitude()
{
return $this->lon;
}
public function __toString()
{
return $this->lat . ' ' . $this->lon;
}
Usage:
$location = new \MyApp\ValueObject\Location(24.7, -20.4059);
echo $location->latitude() , ' ' , $location->longitude();
// or simply
echo $location;
I want to validate latitude and longitude, too, and have this result:
-90.0000 - 90.0000
^-?([0-9]|[1-8][0-9]|90)\.{1}\d{4}$
-180.0000 - 180.0000
^-?([0-9]|[1-9][0-9]|1[0-7][0-9]|180)\.{1}\d{4}$
I have tested here with pcre.
regex
/([0-9.-]+).+?([0-9.-]+)/
Function to validate Latitude
function validateLatitude($lat) {
$lat_array = explode( '.' , $lat );
if( sizeof($lat_array) !=2 ){
return '_n_';
}
if ( ! ( is_numeric($lat_array[0]) && $lat_array[0]==round($lat_array[0], 0) && is_numeric($lat_array[1]) && $lat_array[1]==round($lat_array[1], 0) ) ){
return '_n_';
}
if( $lat >= -90 && $lat <= 90 ){
return '_s_';
}
else {
return '_n_';
}
}
Function to validate Longitude
function validateLongitude($long) {
$long_array = explode( '.' , $long );
if( sizeof($long_array) !=2 ){
return '_n_';
}
if (!( is_numeric($long_array[0]) && $long_array[0]==round($long_array[0], 0) && is_numeric($long_array[1]) && $long_array[1]==round($long_array[1], 0) ) ){
return '_n_';
}
if( $long >= -180 && $long <= 180 ){
return '_s_';
}
else {
return '_n_';
}
}
It's real work unicum solution in net " -90.0000 - 90.0000
^-?([0-9]|[1-8][0-9]|90)\.{1}\d{4}$
-180.0000 - 180.0000
^-?([0-9]|[1-9][0-9]|1[0-7][0-9]|180)\.{1}\d{4}$
"
For &lat=90.000000 &lon=180.000000 :
"/^-?([0-9]|[1-8][0-9]|90)\.{1}\d{1,6}$/"
"/^-?([1]?[1-7][1-9]|[1]?[1-8][0]|[1-9]?[0-9])\.{1}\d{1,6}/"
These didn't seem very accurate being that:
latitude is between -90 and 90
longitude is between -180 and 90
and
\d
in regex matches more than [0-9]
Also a whole library just for some regex didn't seem logical...
So I built and tested:
//Latitude
if(preg_match('/^-?(90|[1-8][0-9][.][0-9]{1,20}|[0-9][.][0-9]{1,20})$/', '89.33333')) {
echo "<br>a match<br>";
} //will pass ->89.33333
//Longitude
if(preg_match('/^-?(180|1[1-7][0-9][.][0-9]{1,20}|[1-9][0-9][.][0-9]{1,20}|[0-9][.][0-9]{1,20})$/', '180.33333')) {
echo "<br>b match<br>";
} // will fail anything over 180 ->180.33333
精彩评论