根据坐标获取详细地址方法 For 百度地图0+

15,614 views / 2012.05.07 / 5:05 下午

先看官方给出的文档,可以很简单的根据坐标获取详细地址:

<div style="width:200px;height:200px" id="container"></div>
 
<script>  var map = new BMap.Map("container"); map.centerAndZoom(new BMap.Point(116.404, 39.915), 11);
 
// 创建地理编码实例
 
function d(){
 
var myGeo = new BMap.Geocoder();
 
// 根据坐标得到地址描述
 
myGeo.getLocation(new BMap.Point(116.364, 39.993), function(result){    if (result){      alert(result.address);   }   }); }
 
</script>
 
<input type="button" onclick="d()" value="do" />

 

但是我们在做移动终端研发的时候,往往只能通过SDK获取到用户的坐标,如何才能让服务器获取用户的详细位置呢?(大众点评有实现)。我们运行上面的代码,抓包后分析发现,浏览器请求了这个地址:
http://api.map.baidu.com/?qt=rgc&x=12953722.17&y=4837205.83&dis_poi=100&poi_num=10&ie=utf-8&oue=1&res=api&callback=BMap._rd._cbk81902

看参数,这个x y 应该是坐标啊,可为什么跟我们传入的不一样呢?NND,原来百度给转换成了MC坐标,貌似这是搜过的算法啊! 算了,在这个互相山寨的年代,也管不了这么多了。献出我的php算法:

<?php
function getRange($cF, $cE, $T) {  if ($cE != null) {   $cF = max($cF, $cE);  }  if ($T != null) {   $cF = min($cF, $T);  }  return $cF; } function getLoop($cF, $cE, $T) {  while ($cF > $T) {   $cF -= $T - $cE;  } while ($cF < $cE) {   $cF += $T - $cE;  }  return $cF; } function convertLL2MC($T) {  $LLBAND = array(75, 60, 45, 30, 15, 0);  $LL2MC = array(array(- 0.0015702102444, 111320.7020616939, 1704480524535203, -10338987376042340, 26112667856603880, -35149669176653700, 26595700718403920, -10725012454188240, 1800819912950474, 82.5), array(0.0008277824516172526, 111320.7020463578, 647795574.6671607, -4082003173.641316, 10774905663.51142, -15171875531.51559, 12053065338.62167, -5124939663.577472, 913311935.9512032, 67.5), array(0.00337398766765, 111320.7020202162, 4481351.045890365, -23393751.19931662, 79682215.47186455, -115964993.2797253, 97236711.15602145, -43661946.33752821, 8477230.501135234, 52.5), array(0.00220636496208, 111320.7020209128, 51751.86112841131, 3796837.749470245, 992013.7397791013, -1221952.21711287, 1340652.697009075, -620943.6990984312, 144416.9293806241, 37.5), array(- 0.0003441963504368392, 111320.7020576856, 278.2353980772752, 2485758.690035394, 6070.750963243378, 54821.18345352118, 9540.606633304236, -2710.55326746645, 1405.483844121726, 22.5), array(- 0.0003218135878613132, 111320.7020701615, 0.00369383431289, 823725.6402795718, 0.46104986909093, 2351.343141331292, 1.58060784298199, 8.77738589078284, 0.37238884252424, 7.45));  $T['lng'] = getLoop($T['lng'], -180, 180);  $T['lat'] = getRange($T['lat'], -74, 74);  for ($cF = 0; $cF < count($LLBAND); $cF++) {   if ($T['lat'] >= $LLBAND[$cF]) {    $cG = $LL2MC[$cF];    break;   }  }  if (!$cG) {   for ($cF = count($LLBAND) - 1; $cF >= 0; $cF--) {    if ($T['lng'] <= - $LLBAND[$cF]) {     $cG = $LL2MC[$cF];     break;    }   }  }  $cH = convertor($T, $cG);  $T = array(round($cH['lng'], 2), round($cH['lat'], 2));  return $T; } function convertor($cF, $cG) {  if (!$cF || !$cG) {   return false;  }  $T = $cG[0] + $cG[1] * abs($cF['lng']);  $cE = abs($cF['lat']) / $cG[9];  $cH = $cG[2] + $cG[3] * $cE + $cG[4] * $cE * $cE + $cG[5] * $cE * $cE * $cE + $cG[6] * $cE * $cE * $cE * $cE + $cG[7] * $cE * $cE * $cE * $cE * $cE + $cG[8] * $cE * $cE * $cE * $cE * $cE * $cE;  $T *= ($cF['lng'] < 0 ? -1: 1);  $cH *= ($cF['lat'] < 0 ? -1: 1);  return array("lng" => $T, "lat" => $cH); } $d = convertLL2MC(array("lng" => "116.364", "lat" => "39.993")); echo file_get_contents("<a href="http://api.map.baidu.com/?qt=rgc&x">http://api.map.baidu.com/?qt=rgc&x</a>=" . $d[0] . "&y=" . $d[1] . "&dis_poi=100&poi_num=10&ie=utf-8&oue=1&res=api&callback=");

?>

怎样,实现了吧?这事之所以这么麻烦,还是nodejs不够高级啊,不然直接架设个nodejs服务器,专门运行js脚本,我们就不用这么麻烦了。

杜工原创,转载注明来源,否则必究。

Categories: 感悟 Tags: ,

gd库不支持jpeg的解决方法0+

10,406 views / 2011.11.06 / 11:11 下午

杜工就不在这里啰嗦怎么遇到这个问题的了,如果你确实安装了的gd库,却发现无法支持jpeg格式的图片,可从下面找到答案。

原因是在编译gd库前,配置时未声明jpeg库路径。解决方法如下:

32位系统:

./configure –with-php-config=/usr/local/php5/bin/php-config
–with-jpeg-dir=/usr/lib

64位系统

./configure –with-php-config=/usr/local/php5/bin/php-config
–with-jpeg-dir=/usr/lib64

 

重新make&make install后,重启apache即可。

 

Categories: 感悟 Tags: ,

CentOS或者redhad下用yum或者rpm安装了 mysql 及 mysql-server , 在编译安装php时用 –with-mysql 选项出现错误

Note that the MySQL client library is not bundled anymore.

首先使用命令find / -name ‘mysql.h’ 查找路径,如果找到就给with-mysql=赋上路径,如果找不到,那就是缺少了 mysql-devel 安装包,用yum或者rpm安装上,即可解决问题

Categories: 感悟 Tags: ,

js模拟php的shuffle函数,用来打乱一维数组3+

8,050 views / 2010.12.09 / 6:06 下午
Array.prototype.shuffle = function() {
for(var j, x, i = this.length; i; j = parseInt(Math.random() * i), x = this[--i], this[i] = this[j], this[j] = x);
return this;
};
 
非原创,纯分享
Categories: 分享 Tags: ,

如何去管理php的用户名和密码(二)0+

6,867 views / 2010.06.17 / 2:02 下午

(接上文:http://71j.cn/archives/173)

操练开始

在我们做出测试代码之前,首先要创建一个用户数据表。运行如下语句:

create database myapp;
use myapp;
create table users (user varchar(60), pass varchar(60));

其中user用来储存用户名,pass用来储存密码的hash值。目前,phpass生成的密码hash值最大长度为60。

创建新用户

首先,我们从phpass项目网站把PasswordHash.php下载到网站目录中,并设置能让php加载的权限(Unix系统下一般为600或者644)。然后在网站目录中创建两个文件:user-man.html (644权限), and user-man.php (权限同asswordHash.php)。

下面,把下面的内容写在user-man.html中:

<form action="user-man.php" method="POST">
用户名:<br>
<input size="60"><br>
密码:<br>
<input size="60"><br>
<input value="创建新用户">
</form>

这个文件获取用户名和密码,然后提交到user-man.php。下面是user-man.php的代码:

header('Content-Type: text/plain');
 
// 本例只是简单的输出文本的hash值,所以开头要声明下,不让浏览器当作html解析。
 
 
 
require '../PasswordHash.php';
 
// Base-2 logarithm of the iteration count used for password stretching
$hash_cost_log2 = 8;
// Do we require the hashes to be portable to older systems (less secure)?
$hash_portable = FALSE;
 
//在实际应用中,上面两行最好写在配置文件中,比如config.inc.php
 
//下面开始获取提交的用户名和密码,实际应用中需要验证有效性,不再赘述。
 
$user = $_POST['user'];
$pass = $_POST['pass'];
 
//下面开始计算密码hash值
 
$hasher = new PasswordHash($hash_cost_log2, $hash_portable);
$hash = $hasher->HashPassword($pass);
if (strlen($hash) < 20)//这里用的CRYPT_EXT_DES方法,其它加密算法得到结果会更长。
    fail('Failed to hash new password');
unset($hasher);
 
function fail($pub, $pvt = '')
{
    $msg = $pub;
    if ($pvt !== '')
        $msg .= ": $pvt";
    exit("An error occurred ($msg).\n");
}
 
//下面开始把用户信息存入到数据库中
 
$db_host = 'localhost';
$db_port = 3306;
$db_user = ‘dbuser’;
$db_pass = 'dbpass';
$db_name = 'dbname';
 
//数据库信息也最好存储在配置文件中。下面开始连接数据库,并注意弹出失败信息。
 
$db = new mysqli($db_host, $db_user, $db_pass, $db_name, $db_port);
if (mysqli_connect_errno())
    fail('MySQL connect', mysqli_connect_error());
 
//下面用预备语句插入用户信息
 
($stmt = $db->prepare('insert into users (user, pass) values (?, ?)'))
    || fail('MySQL prepare', $db->error);
$stmt->bind_param('ss', $user, $hash)
    || fail('MySQL bind_param', $db->error);
$stmt->execute()
    || fail('MySQL execute', $db->error);
 
//最后数据库连接
 
$stmt->close();
$db->close();

好了,把左右文件保存好,放在web server下测试下。输入用户名和密码,提交后,到数据库中看下:

mysql> select * from users;
+——–+————————————————————–+
| user   |pass                                                         |
+——–+————————————————————–+
| myuser | $3b$08$Lg5XF1Tr.X5TGyfb43vBBeEFZm4GTRQhKQ6SY6emkcnhAGT8KfxFS |
+——–+————————————————————–+
1 row in set (0.00 sec)

至此,用户插入成功。

用户已经存在

下面,我们用上面的方法插入一个相同的用户,同时,用相同的密码。然后查看数据库:

mysql> select * from users;
+——–+————————————————————–+
| user   |pass                                                         |
+——–+————————————————————–+
| myuser | $3b$08$Lg5XF1Tr.X5TGyfb43vBBeEFZm4GTRQhKQ6SY6emkcnhAGT8KfxFS |
| myuser | $1a$08$7lM07FwQMm5/C8G/urT4z..MudfsS227e8oUEu6T51bNWk/RGb/qe |
+——–+————————————————————–+
2 rows in set (0.00 sec)

我们得到了用户名相同的两条记录,但是密码hash值不相同,虽然我们使用了相同的密码。

为了解决这个问题,我们可以在执行插入前先执行一个select语句,查询下该用户名是否已经存在了。但是,这对程序的效率来说不是最优化的。好的做法是让为用户名建立唯一索引,禁止用户用户名的出现:

DROP TABLE users;
CREATE TABLE users (user varchar(60), pass varchar(60), UNIQUE (user));

当我们插入相同的用户名时,程序就会报错:

An error occurred (MySQL execute: Duplicate entry ‘myuser’ for key 1).

如此,系统效率会得到提高。虽然,这是纯技术性的错误提示, 我们将稍侯予以解决。

避免泄漏过多服务器细节

上面出现的报错多是mysql服务器报错,可能会泄漏一些敏感信息,如数据库名,数据库地址,甚至数据表文件的存储地址都会被显示,这是很危险的。因此,这些信息我们并不希望被显示,除非我们就是用户,或者是在调试。如此,我们可以修改fail()函数,把错误信息显示为用户可见的内容。

// 是否为debug模式,如果是,会显示敏感信息。
$debug = TRUE;
 
function fail($pub, $pvt = '')
{
    global $debug;
    $msg = $pub;
    if ($debug && $pvt !== '')
        $msg .= ": $pvt";
/* $pvt 可能会含有敏感信息,比如需要隐藏掉,或者需要编码才能被html正确显示的内容。*/
    exit("An error occurred ($msg).\n");
}

需要注意的,不管是apache还是php,默认情况下是会显示所有调试信息的。所以,作为一个程序员,我们的职责是防止这些信息被泄漏,就跟我们设置了debug模式一样,这对程序员或者服务器运维人员来说至关重要。默认情况下,要把$debug值设置为false,但我们的例子作为测试来说,将继续使用true.

如何区分mysql报错

我们需要去辨别mysql报错,以确定用户是否已经存在于数据库中,如果已经存在,需要输出一个友好的错误提示。因为当我们插入用户的时候,不只是会有一种错误,当出现其它错误的时候,我们不能傻不愣瞪的提示相同的错误(用户已经存在)吧?

一种解决方法是在出现报错后执行一个针对该用户名的select查询,如果能够返回一行数据,说明用户确实一定存在了。实现方法如下:

if (!$stmt->execute()) {
    $save_error = $db->error;
    $stmt->close();
 
// 用户已经存在了?
    ($stmt = $db->prepare('select user from users where user=?'))
        || fail('MySQL prepare', $db->error);
    $stmt->bind_param('s', $user)
        || fail('MySQL bind_param', $db->error);
    $stmt->execute()
        || fail('MySQL execute', $db->error);
    $stmt->store_result()
        || fail('MySQL store_result', $db->error);
 
    if ($stmt->num_rows === 1)
        fail('This username is already taken');
    else
        fail('MySQL execute', $save_error);
}

这个方法确实奏效,而且也很可靠。但是,我们还有更简捷的实现方法,那就是使用mysql错误码:

if (!$stmt->execute()) {
    if ($db->errno === 1062 /* ER_DUP_ENTRY */)
        fail('额滴神,该用户已经存在了');
    else
        fail('MySQL execute', $db->error);
}

在接下来的例子中,我们将使用这种简单的方法做演示。

魔法引号的处理

Magic quotes 开启后会自动转义输入的数据。其中,所有的单引号(’)、双引号(”)、反斜线、和 NULL 字符都会被转义(增加个反斜线),其实这操作本质上调用的是 addslashes 函数。

这对程序员来说固然是一个很好的事情,省却了我们过滤的麻烦。但是,当用户输入用户名和密码中含有这些字符时,我们从$_POST中获取到的内容是不是也会被addslashes了呢?

这就需要我们去做判断,示例如下:

function get_post_var($var)
{
    $val = $_POST[$var];
    if (get_magic_quotes_gpc())
        $val = stripslashes($val);
    return $val;
}

接下来,我们将用这个函数取post过来的数据,而不是单纯的$_POST数组。 

(待续)

Categories: 感悟 Tags: , , , ,