【问题标题】:Using PDOStatement::prepare with PostGIS functions使用 PDOStatement::prepare 和 PostGIS 函数
【发布时间】:2013-08-24 09:23:30
【问题描述】:

我对 PDO 还很陌生,如果我误解了一些事情,请原谅。我花了很长时间阅读网上提供的材料,但找不到合适的解决方案。

我尝试编写的代码应该执行以下操作:获取两个 $_GET 变量,其中包含特定点纬度 ($lat) 和经度 ($lon),然后选择存储在 PostGIS 中的与这些坐标最近的点-启用的数据库(加上到该点的返回距离)。这是当前(和工作)代码的样子:

$courts = $pdo->query("SELECT * , ST_ASTEXT(geog) , ST_distance( ST_GeographyFromText('POINT($lon $lat)') , geog ) AS distance FROM bvbcourts WHERE ST_DWithin( ST_GeographyFromText('POINT($lon $lat)' ) , geog , 20000) ORDER BY distance LIMIT 1");

但是,我想尝试使用 prepare 语句,因为我读到这些语句是 SQL 注入证明。

$courts = $pdo->prepare("SELECT * , ST_ASTEXT(geog) , ST_distance( ST_GeographyFromText('POINT( :lon :lat )') , geog ) AS distance FROM bvbcourts WHERE ST_DWithin( ST_GeographyFromText('POINT( :lon :lat )' ) , geog , 20000) ORDER BY distance LIMIT 1" );
$courts->execute(array( ':lon' => $lon , ':lat' => $lat ) )

但上面的代码不起作用。执行errorInfo()只返回如下错误码:HY093

根据我目前了解到的情况,我认为上面的代码不起作用,因为->prepare 占位符只能用于通常插入输入参数的地方。

例如->prepare( "SELECT * FROM x WHERE field=:field" ); 会工作 而->prepare( "SELECT * FROM x WHERE field='someprefix:field'" ); 不会。我在上面尝试使用的代码有点类似于“someprefix”-example。

所以,我的问题是,如何让我尝试执行的语句生效,而无需使用 ->query 并手动阻止注入。或者我最好确保传递的参数是正确的、简单的坐标并使用->query

这只是我在这里提出的第二个问题,如果我对所提供的研究和信息不够清楚或透彻,请原谅。

【问题讨论】:

    标签: php pdo prepared-statement postgis


    【解决方案1】:

    我真的很想知道如何让新手也能获得有关该主题的基本知识。

    对于一个不断的旁观者来说,这些问题似乎非常重复。这使程序员认为网站效率低下。然而,网站政策似乎鼓励重复问题。所以,就这样吧。

    准备好的语句只能表示竞争数据文字。坦率地说 - 一个完整的 stringnumber

    查看您的代码:

    'POINT($lon $lat)'
    

    已经是一个数据文字了。因此,您不能使文字成为文字的一部分。您必须将其全部绑定:

    $courts = $pdo->prepare("SELECT * , ST_ASTEXT(geog) , ST_distance( ST_GeographyFromText(:point) , geog ) AS distance FROM bvbcourts WHERE ST_DWithin( ST_GeographyFromText(:point ) , geog , 20000) ORDER BY distance LIMIT 1" );
    $courts->execute(array( ':point' => "POINT($lon $lat)") );
    

    【讨论】:

      【解决方案2】:

      最好的方法是创建 WKT 字符串,而是将坐标浮点数直接传递给 PostGIS 几何构造函数。这是您的准备语句应该是什么样子的。

      SELECT *, ST_ASTEXT(geog), ST_Distance(poi, geog) AS distance
      FROM bvbcourts,
       (SELECT ST_MakePoint(:lon, :lat)::geography AS poi) AS f
      WHERE ST_DWithin(poi, geog, 20000)
      ORDER BY distance
      LIMIT 1;
      

      【讨论】:

      • ST_MakePoint 解决方案也很有效,根据 PostGIS 文档,它比 ST_GeographyFromText 快一点(参见此处link)。对我来说,它也更容易使用,因为我可以使用与其他查询相同的编码风格,并且不必添加检查输入参数是否准确浮动。但是,文档还指出 ST_MakePoint 不符合 OGC。这是否会成为未来的问题(例如,在迁移到不同的 dbms 时)?
      • 正确,ST_MakePoint 不符合 OGC,因此在不同的 DBMS 上不可用,但地理类型(和 ST_GeographyFromText)也不属于 OGC。我知道 MS SQL Server 有类似的类型,但不确定其他类型。
      猜你喜欢
      • 2014-09-11
      • 2015-01-22
      • 2015-09-12
      • 2012-07-08
      • 1970-01-01
      • 2016-12-18
      • 2017-08-12
      • 1970-01-01
      • 2012-12-20
      相关资源
      最近更新 更多