标签归档:PHP

通过IP定位经纬度

由于需要给客户端提交数据接口并且数据中包括经纬度,然而数据库中只存储了IP,于是需要通过IP定位经纬度。

一开始查找是否存在Google API直接将IP转化成经纬度,没有,只有将地址转化成经纬度,开始其它查找,得到方案一和方案二:
【方案一】
使用闭关纪要21.地图人站点的IP查询经纬度和经纬度查询行政区划的服务
地址为:
http://dituren-service.appspot.com/services/ip_lookup?c=onIpLookupLoaded&ip=24.24.24.24
其实现思路为:采用IP库实现了通过IP得到一个地址的文字描述之后,再通过Google的地址解析服务去匹配经纬度,调用代码如下:

1
2
3
4
5
6
7
8
9
10
11
<?PHP
$url = "http://dituren-service.appspot.com/services/ip_lookup?c=onIpLookupLoaded&ip=24.24.24.24";
$content = @file_get_contents($url);
$result = array();
if (!empty($content)) {
    preg_match("/\((.*)\)/i", $content, $matches);
    $result = json_decode($matches[1], true);
}
print_r($result);
 
?>

【方案二】
使用http://www.blueforge.net/map/ 提供的IP地址查询服务
取数据代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?PHP
$arr = explode(" ", microtime());
$rst = $arr[1] . substr($arr[0], strpos($arr[0], '.') + 1, 3);
 
$url = "http://www.blueforge.net/map/?rs=get_ip_info&rst=&rsrnd=" . $rst . "&rsargs[]=" . $ip;
$rs = @file_get_contents($url);
preg_match("/{(.*)}/", $rs, $matches);
 
$str = '$arr=array(' . str_replace(':', '=>', $matches[1]) . ');';
$str = str_replace('parseFloat', 'floatVal', $str);
eval($str);
print_r($arr);
 
?>

由于作者是直接给JS用的,所以源地址返回的数据是JS代码,我在这里做了一个替换,将其变为PHP代码。
以上两种方法都是基于Google API,并且在速度和稳定性方面存在极大的隐患

【方案三】
比较好的方案是在本地有一个数据库存储了相关信息,直接取出来,
http://www.maxmind.com/ 这个网站提供了这样一个数据库,在其城市级的数据中,我们可以找到经纬度信息,网站提供了各种语言的程序实现,这里就不再多说了。
数据库下载地址:
http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
PHP程序下载地址:
http://geolite.maxmind.com/download/geoip/api/php/

方案三存在两个问题:

1、一些数据不全
2、存在一些乱码,特别是城市相关信息

点号连接符与字符串内用使用变量的速度比较

一直喜欢在字符串内使用大括号包含变量,但是看到别人的程序中经常用点号连接。
难道这样快些?
于是对下面三种情况进行了测试:
1、 使用点号连接字符串和字符串变量。
2、 在字符串中使用大括号包含变量;
3、 在字符串中不使用大括号包含变量;

1、使用点号连接字符串和字符串变量

1
2
3
4
<?PHP
	$str = "abcd";
	$str2 = $str . "efg";
?>

使用VLD查看结果如下:
Branch analysis from position: 12647312
Return found
filename: D:\work\php\test.php
function name: (null)
number of ops: 8
compiled vars: !0 = $str, !1 = $str2
line # op fetch ext return operands
——————————————————————————-
2 0 EXT_STMT
1 ASSIGN !0, ‘abcd’
3 2 EXT_STMT
3 CONCAT ~1 !0, ‘efg’
4 ASSIGN !1, ~1
4 5 EXT_STMT
6 RETURN 1
7* ZEND_HANDLE_EXCEPTION

2、在字符串中使用大括号:

1
2
3
4
<?PHP
	$str = "abcd";
	$str2 = "{$st}refg";
?>

Branch analysis from position: 12647312
Return found
filename: D:\work\php\test.php
function name: (null)
number of ops: 10
compiled vars: !0 = $str, !1 = $str2
line # op fetch ext return operands
——————————————————————————-
2 0 EXT_STMT
1 ASSIGN !0, ‘abcd’
3 2 EXT_STMT
3 INIT_STRING ~1
4 ADD_VAR ~1 ~1, !0
5 ADD_STRING ~1 ~1, ‘efg’
6 ASSIGN !1, ~1
4 7 EXT_STMT
8 RETURN 1
9* ZEND_HANDLE_EXCEPTION

3、在字符串中不使用大括号包含变量

1
2
3
4
<?PHP
	$str = "abcd";
	$str2 = "$strefg";
?>

Branch analysis from position: 12647312
Return found
filename: D:\work\php\test.php
function name: (null)
number of ops: 9
compiled vars: !0 = $str, !1 = $str2, !2 = $strefg
line # op fetch ext return operands
——————————————————————————-
2 0 EXT_STMT
1 ASSIGN !0, ‘abcd’
3 2 EXT_STMT
3 INIT_STRING ~1
4 ADD_VAR ~1 ~1, !2
5 ASSIGN !1, ~1
4 6 EXT_STMT
7 RETURN 1
8* ZEND_HANDLE_EXCEPTION

另外,对于这样的两条语句执行一百万次,其结果如下:
1、使用点号连接字符串和字符串变量:平均在0.6秒
2、在字符串中使用大括号包含变量:平均在1.75左右
3、在字符串中不使用大括号包含变量: 平均在1.7秒左右
明显第一种要一些,从VLD查看的结果中可以看出后面两种与第一种的实现方式完全不同,后面两种多了INIT_STRING和ADD_VAR的操作。

使用VC6.0生成VLD扩展

使用VC6.0生成VLD扩展

最近想看看PHP生成的源码是啥样子,于是google半天,终于完成。
环境:VC6.0
源码:php5.2.9源码包(可以去http://www.php.net/下载),解压,我的是解压在D盘根目录下。
Vld源码包(可以去http://pecl.php.net/package/vld/0.9.1下载),解压

生成过程如下:
1、在Windows平台启动 VC++ 6.0, 【文件】(File)->【新建】(New), 在 【工程】(Project)中选择 【Win32 Dynamic-Link Library】, 填写上 【工程名称】(Project Name) 和 【位置】(Location),如图1所示:

图1

图1

2、点击确定后,在第二屏选中 【一个空的DLL工程】(An empty DLL project), 点 【完成】Finish, 完成创建。此时会可能会弹出一个信息框,点击确定。

3、把解压后的vld源码中的vld文件夹下面的所有文件拷贝到到工程所在的目录(D:\php-5.2.9\ext\vld);

4、选择左侧的【Source Files】,点击右键,选择【添加文件到目录】,将D:\php-5.2.9\ext\vld目录下的所有C文件添加到此目录,如图2所示;

图2

图2

5、同样选择【Header Files】,添加所有的头文件到目录。如图3所示:

图3

图3

6、修改工程设置,选择【工程】(Project)->【设置】(Settings)->【C/C++】,在【工程选项】(Project Options:)的 最后加上 /Tc,在预处理程序定义中添加如下宏定义:ZEND_DEBUG=0,COMPILE_DL_VLD,ZTS=1,ZEND_WIN32,PHP_WIN32,HAVE_VLD=1

如果你需要编译其它扩展,请将COMPILE_DL_VLD 和 HAVE_VLD=1,后面的 “VLD” 改成和你要创建的工程名一致。

如图4所示:

 

图4

图4

7、选择【连接】(Link),在【对象/库模块】(Object/library modules)添加php5ts.lib,注意要以空格格开;

8、选择【工具】(Tools)->【选项】(Options)->【目录】(Directories),

在 【目录】(Show directories for:) 下拉框中选择 “Library files”,在 【路径】(Directories) 中添加 D:\php-5.2.9 (即 php5ts.lib 所在目录);如图5所示:

在【目录】(Show directories for:) 下拉框中选择 “Include files”

在【路径】(Directories)中添加 D:\PHP-5.2.9 (即 ext、regex、win32 所在目录)

在【路径】(Directories)中添加 D:\PHP-5.2.9\MAIN

在【路径】(Directories)中添加D:\PHP-5.2.9\ZEND

在【路径】(Directories)中添加 D:\PHP-5.2.9\TSRM

如图6所示: 

 

图5

图5

 

 

图6

图6

9、选择【组建】->【编译】,此时可能会出现报错。

php_vld.h文件的59行存在三个莫名其妙的点,将他们去掉就可以了。

10、选择【组建】->【组建】。成功!

在扩展下的Debug目录D:\php-5.2.9\ext\vld\Debug下有一个生成的dll文件。这就是我们所要的东东了!