使用lat lng进行CakePHP半径搜索

时间:2015-03-27 08:13:22

标签: cakephp cakephp-2.0 cakephp-2.3

我有一个名为'cities'的表,其中有两个名为lat,lng的字段。现在我想使用用户提供的lat,lng搜索100英里内的城市。我的代码ID如下..

            $lat = $latLng['lat']; // user provide lat 
            $lng = $latLng['lng']; // user provide lat
             $facilities = $this->City->find('all', array(
                'fields' => array('(((acos(sin((".$lat."*pi()/180)) * 
                    sin((`City.lat`*pi()/180))+cos((".$lat."*pi()/180)) * 
                    cos((`City.lat`*pi()/180)) * cos(((".$lng."- `City.lng`)* 
                    pi()/180))))*180/pi())*60*1.1515
                ) as distance', 'City.name', 'City.description' ), 
                'conditions' => array('City.distance' < 20)
            ));

它给出错误“错误:SQLSTATE [42S22]:未找到列:1054'字段列表'中的未知列'City.lat'”

1 个答案:

答案 0 :(得分:1)

SQL注入

首先,如果你没有使用casted / sanitized /转义用户输入,那么你所拥有的是一个很好的SQL注入漏洞,字段不会像例如条件那样被转义。 请记住,永远不要直接将用户数据插入查询中!

引用列名称

该列未知,因为它实际上并不存在,您将City.lng作为列名,而不只是lng和表名City,为了做到这一点,你必须分别正确引用这两个,即

`City`.`lng`

无法在WHERE子句中引用聚合列

我不知道您使用的是哪个DBMS,但对于MySQL,Postgre以及SQL Server都是如此。您无法在distance条件中使用汇总的WHERE列,您必须使用HAVING,或者再次在WHERE子句中重新引入相同的计算(这是virtual fields会做的事情。

HAVING子句可以像这样插入:

'conditions' => [
    // ...
    '1=1 HAVING distance < 20'
]

另请注意,您必须使用完全别名,即仅distance,而不是City.distance,就像条件一样(语法无效,'City.distance' < 20是一个表达式评估为true)。