使用PHP/MySQL和可选的JavaScript配置文件位置信息

使用PHP/MySQL和可选的JavaScript配置文件位置信息,php,mysql,geolocation,geocoding,Php,Mysql,Geolocation,Geocoding,我工作的其中一个网站是某种社交网站,通过使用某种定位服务,根据距离推荐“朋友”,内容会大大增强。该网站专注于美国,但潜在用户遍布全球 我曾考虑过创建一个与国家、州/省/地区、县和城市的关联数组或关系数据库,以提供一种粗略的方法来深入了解它们的相对接近程度,但这可能非常笨拙,而且非常复杂 我也考虑过IP地理定位,但结果往往不可靠(一些服务显示我公司的IP位于东北600英里左右),我至少需要某种形式的回退来查找,例如,邮政编码 您能否告诉我一种明确定义的方法,可以在不使用第三方API的情况下,在本地

我工作的其中一个网站是某种社交网站,通过使用某种定位服务,根据距离推荐“朋友”,内容会大大增强。该网站专注于美国,但潜在用户遍布全球

我曾考虑过创建一个与国家、州/省/地区、县和城市的关联数组或关系数据库,以提供一种粗略的方法来深入了解它们的相对接近程度,但这可能非常笨拙,而且非常复杂

我也考虑过IP地理定位,但结果往往不可靠(一些服务显示我公司的IP位于东北600英里左右),我至少需要某种形式的回退来查找,例如,邮政编码

您能否告诉我一种明确定义的方法,可以在不使用第三方API的情况下,在本地有效地执行此类查找,最好首先参考从何处收集基本信息?我目前运行的是PHP5.3.2和MySQL 5.1.44,如果有什么不同的话

谢谢大家!

编辑:
增加了一笔奖金,试图获得更好的想法,或其他处理问题的方法,也许更有效。事实上,由于巨大的数据库大小而导致的加载时间是疯狂的。我想我肯定需要改进我的缓存,但我正在尝试看看在改进我的定位系统方面是否有什么我应该做的。

这可能有点明显。。。但是,您能够以最佳准确度了解用户位置的唯一方法是:

询问用户他们在哪里! 一旦您询问用户他们在哪里,您就可以使用第三方应用程序计算距离。 如果您不想使用您提到的任何第三方应用程序,那么您可以下载其中一个地理数据库并将其集成到您自己的服务中

我使用的源代码是Yahoo Geo Planet

您可以下载TSV格式的整个GeoPlanet数据文件。当我下载它时,我只是使用mysqlimport将它导入mysql

它包含世界上每个不同地理位置的记录。一吨邮政编码、地区、地区、国家,几乎所有你需要的东西


除此之外,它还包含邻居,因此您可以根据邻近的地理区域进行查询

这可能有点明显。。。但是,您能够以最佳准确度了解用户位置的唯一方法是:

询问用户他们在哪里! 一旦您询问用户他们在哪里,您就可以使用第三方应用程序计算距离。 如果您不想使用您提到的任何第三方应用程序,那么您可以下载其中一个地理数据库并将其集成到您自己的服务中

我使用的源代码是Yahoo Geo Planet

您可以下载TSV格式的整个GeoPlanet数据文件。当我下载它时,我只是使用mysqlimport将它导入mysql

它包含世界上每个不同地理位置的记录。一吨邮政编码、地区、地区、国家,几乎所有你需要的东西


除此之外,它还包含邻居,因此您可以根据邻近的地理区域进行查询

不幸的是,仅仅问他们在哪里还不够好,虽然GeoPlanet是一个不错的选择,我已经决定使用它,但我觉得它不是一个完整的答案。是的,它是有效的,但是-如何-。别名不包括拼写错误,而大多数局外人称旧金山为“圣弗兰”或“弗里斯科”,当地人使用“城市”,所以别名并不总是有效。我需要某种程度的精确性

好吧,在做了一些工作之后,我使用了一种方法,这是一种有点密集的方法,可能不是每个人都可以选择,但对我来说是有效的:

首先,从(105 MB压缩)获取TSV格式的GeoPlanet db副本

为了将其导入MySQL数据库,我创建了表,其中的列根据zip中的自述文件命名。Geoplanet_places是唯一一个提供了与WOE_ID关联的主键的表。这和Geoplanet_邻接是目前我真正需要的唯一表。对于我来说,导入是通过以下方式在本地完成的:

mysqlimport --socket=/PATH/TO/SOCKET/mysql.sock --user=EXAMPLE --password=EXAMPLE DATABASE_NAME /PATH/TO/DOWNLOADED/GEOPLANET/DATA/geoplanet_places.tsv
我从.tsv中删除了版本号,并使用文件名作为表名。你的经历可能会有很大的不同,但为了清楚起见,我添加了它。导入所有需要的文件

我决定为人们输入个人资料数据提供两个选项:您必须始终选择您的国家(从选项列表中,使用ISO 3166 Alpha-2代码作为值),但我们可以使用邮政(ZIP/PIN)代码查找他们所在的位置;或者,对于像爱尔兰这样缺乏国家邮政编码系统的国家,他们可以输入他们的城市和省名

要使用国家/地区和邮政编码进行搜索,我可以执行以下操作:

SELECT Parent_ID FROM geoplanet_places WHERE ISO = "$ctry" AND Name="$zip" AND PlaceType="ZIP";
我数结果。如果为0,则我没有结果,位置未知,我假设存在问题(相应地记录了一个错误,以确认这不是侥幸)。如果有多个,则会枚举结果,并弹出下一个屏幕,要求确认结果所在的位置。理想情况下,邮政编码系统不应出现这种情况,但在基于位置进行询问时可能会出现这种情况。如果只有一个,我会将父ID存储到他们的配置文件中,以便继续查询,并将父ID作为WOE_ID的比较器传递回,如下所示:

SELECT Name, WOE_ID, Parent_ID FROM geoplanet_places WHERE WOE_ID="$pid";
其中,
$pid
是前一个父ID-我将在稍后呈现页面时使用它来确定位置,并且城镇/城市的级别低到足以在邻接表上应用邻近检查。尝试加入结果要比抛出多个查询慢得多
// Google Maps Example
$address = "$line1, $city, $state $zip, $country";
$ch = curl_init();
$query = http_build_query(array(
    'oe' => 'utf8',
    'sensor' => 'false', // set this to 'true' if you used navigation.geolocation
    'key' => YOUR GMAPS API KEY HERE,
    'address' => $address
));
curl_setopt($ch, CURLOPT_URL, 'http://maps.google.com/maps/api/geocode/json?' . $query);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$latLong = current(end(json_decode(curl_exec($ch), true))); // let's pretend nothing ever goes wrong
$myLat = 45.5;
$myLong = -73.5833;
$range = 2; // miles
$sql = "SELECT *,
    truncate((degrees(acos(
        sin(radians(latitude))
        * sin( radians({$myLat}))
        + cos(radians(latitude))
        * cos( radians({$myLat}))
        * cos( radians(longitude - {$myLong}) ) 
        ) ) * 69.09),1) as distance
    FROM users
    HAVING distance < {$range}";