pg_query_params

(PHP 5 >= 5.1.0, PHP 7, PHP 8)

pg_query_params将命令提交到服务器并等待结果,并且能够将参数与 SQL 命令文本分开传递

说明

pg_query_params(PgSql\Connection $connection = ?, string $query, array $params): PgSql\Result|false

将命令提交到服务器并等待结果,并且能够将参数与 SQL 命令文本分开传递。

pg_query_params() 类似于 pg_query(),但提供额外的功能:参数值可以与命令字符串本身分开指定。 pg_query_params() 仅在针对 PostgreSQL 7.4 或更高版本的连接时才受支持;它在使用早期版本时会失败。

如果使用参数,则在 query 字符串中将其称为 $1、$2 等。同一个参数可能在 query 中出现多次;在这种情况下将使用相同的值。 params 指定参数的实际值。此数组中的 **null** 值表示相应参数为 SQL NULL

pg_query_params() 相对于 pg_query() 的主要优势在于,参数值可以与 query 字符串分开,从而避免了对繁琐且容易出错的引用和转义的需要。与 pg_query() 不同,pg_query_params() 允许在给定字符串中最多包含一个 SQL 命令。(它可以包含分号,但不能包含多个非空命令。)

参数

connection

一个 PgSql\Connection 实例。当 connection 未指定时,将使用默认连接。默认连接是 pg_connect()pg_pconnect() 最后建立的连接。

警告

从 PHP 8.1.0 开始,使用默认连接已弃用。

query

参数化的 SQL 语句。必须只包含单个语句。(不允许用分号分隔多个语句。)如果使用任何参数,则将其称为 $1、$2 等。

用户提供的的值应该始终作为参数传递,而不是内插到查询字符串中,在查询字符串中它们会形成可能的 SQL 注入 攻击向量,并在处理包含引号的数据时引入错误。如果由于某种原因你无法使用参数,请确保内插的值是 正确转义的

params

一个参数值数组,用于替换原始准备好的查询字符串中的 $1、$2 等占位符。数组中的元素数量必须与占位符数量匹配。

旨在用于 bytea 字段的值不支持作为参数。使用 pg_escape_bytea() 代替,或使用大对象函数。

返回值

成功时为一个 PgSql\Result 实例,失败时为 **false**。

变更日志

版本 说明
8.1.0 现在返回一个 PgSql\Result 实例;以前,返回一个 资源
8.1.0 connection 参数现在期望一个 PgSql\Connection 实例;以前,期望的是一个 资源

示例

示例 #1 使用 pg_query_params()

<?php
// 连接到名为 "mary" 的数据库
$dbconn = pg_connect("dbname=mary");

// 查找所有名为 Joe's Widgets 的商店。请注意,不需要转义 "Joe's Widgets"
$result = pg_query_params($dbconn, 'SELECT * FROM shops WHERE name = $1', array("Joe's Widgets"));

// 与只使用 pg_query 进行比较
$str = pg_escape_string("Joe's Widgets");
$result = pg_query($dbconn, "SELECT * FROM shops WHERE name = '{$str}'");

?>

参见

添加注释

用户贡献的注释 15 个注释

php at richardneill dot org
10 年前
调试参数化查询可能很乏味,如果你想将查询直接粘贴到 PSQL 中。这里有一个技巧可以帮助你

<?php
$sql
= "SELECT * from table WHERE col_a = $1 and col_b=$2 and col_c=$3";
$params = array (42, "a string", NULL);

$debug = preg_replace_callback(
'/\$(\d+)\b/',
function(
$match) use ($params) {
$key=($match[1]-1); return ( is_null($params[$key])?'NULL':pg_escape_literal($params[$key]) );
},
$sql);

echo
"$debug";
//prints: SELECT * from table WHERE col_a = '42' and col_b='a string' and col_c=NULL
?>

这可以正常工作,除了在(不常见)的情况下,我们有一个文字 $N;正则表达式在不应该替换的地方替换它。例如
<?php
// 同时替换 ' ... $1 ... ' 和 $1;前者是错误的,后者是正确的。
$sql = "SELECT 'Your bill is for $1' AS invoice WHERE 7 = $1";
$params = array(7);
//$debug: SELECT 'Your bill is for $7' AS invoice WHERE 7 = '7'"
?>
victor dot engmark at terreactive dot ch
13 年前
你不能使用 pg_query_params 运行多个语句,但你仍然可以在没有回退到 pg_query 的情况下获得事务支持

<?php
$connection
= pg_connect("host=127.0.0.1 port=5432 dbname=foo user=bar password=baz");
pg_query($connection, 'DROP TABLE IF EXISTS example');
pg_query($connection, 'CREATE TABLE example (col char(1))');
pg_query($connection, 'INSERT INTO example (col) VALUES (\'a\')');
// 'SELECT col FROM example' in another session returns "a"
pg_query($connection, 'BEGIN');
pg_query_params($connection, 'UPDATE example SET col = $1', array('b'));
// 'SELECT col FROM example' in another session still returns "a"
pg_query_params($connection, 'UPDATE example SET col = $1', array('c'));
// 'SELECT col FROM example' in another session still returns "a"
pg_query($connection, 'COMMIT');
// 'SELECT col FROM example' in another session returns "c"
?>
ac at esilo dot com
14 年前
pg_query 和 pg_query_params 可以合并成一个函数。 这也消除了为 pg_query_params 构造参数数组的需要。

<?php
function my_query($conn, $query)
{
if(
func_num_args() == 2)
return
pg_query($conn, $query);

$args = func_get_args();
$params = array_splice($args, 2);
return
pg_query_params($conn, $query, $params);
}
?>

用法

<?php
/* non-parameterized example */
my_query($conn, "SELECT $val1 + $val2");

/* parameterized example */
my_query($conn, "SELECT $1 + $2", $val1, $val2);
?>
dt309 at f2s dot com
17 年前
如果您需要在选择查询中为字段提供多个可能的值,那么以下内容将有所帮助。

<?php
// Assume that $values[] is an array containing the values you are interested in.
$values = array(1, 4, 5, 8);

// To select a variable number of arguments using pg_query() you can use:
$valuelist = implode(', ', $values);
$query = "SELECT * FROM table1 WHERE col1 IN ($valuelist)";
$result = pg_query($query)
or die(
pg_last_error());

// You may therefore assume that the following will work.
$query = 'SELECT * FROM table1 WHERE col1 IN ($1)';
$result = pg_query_params($query, array($valuelist))
or die(
pg_last_error());
// Produces error message: 'ERROR: invalid input syntax for integer'
// It only works when a SINGLE value specified.

// Instead you must use the following approach:
$valuelist = '{' . implode(', ', $values . '}'
$query = 'SELECT * FROM table1 WHERE col1 = ANY ($1)';
$result = pg_query_params($query, array($valuelist));
?>

此示例中产生的错误是由 PostGreSQL 生成的。

最后一种方法通过创建包含所需值的 SQL 数组来工作。 'IN (...)' 和 ' = ANY (...)' 等效,但 ANY 用于处理数组,而 IN 用于处理简单列表。
jsnell at e-normous dot com
16 年前
将数据插入到类型为 bool 的 pg 列时,您不能提供 PHP 类型为 bool 的数据。 您必须改为使用字符串 "t" 或 "f"。 PHP 尝试将作为参数提供的布尔值更改为字符串,然后尝试使用空字符串表示 false。

失败示例
pg_query_params('insert into table1 (bool_column) values ($1)', array(false));

有效
pg_query_params('insert into lookup_permissions (system) values ($1)', array(false ? 't' : 'f'));
peter dot kehl+nospam at gmail dot com
11 年前
pg_query_params() 的第三个参数 $params 会忽略字符串值中零字节字符之后的任何部分 - PHP "\0" 或 chr(0)。 这可能是 serialize() 的结果。

参见 https://bugs.php.net/bug.php?id=63344
alec at smecher dot bc dot ca
12 年前
请注意,由于您的区域设置的数字格式设置,您可能无法将数字值作为参数传递并使其在 PostgreSQL 中仍然是数字。

如果您的系统区域设置使用 "," 作为小数点分隔符,则以下操作会导致数据库错误

pg_query_params($conn, 'SELECT $1::numeric', array(3.5));

要使此操作正常工作,需要使用 number_format 等手动将 3.5 转换为字符串。

(我将此作为错误 #46408 提交,但显然这是预期行为。)
strata_ranger at hotmail dot com
15 年前
关于布尔值,只需在将它们传递到查询中时将其类型转换为 (integer) - '0' 和 '1' 是 SQL 布尔输入的完全可接受的文字

- https://postgresql.ac.cn/docs/8.2/interactive/datatype-boolean.html

您也可以将参数化查询用双引号括起来,这样就可以在查询中混合常量值和占位符,而不必担心 PHP 是否会尝试替换参数化字符串中的任何变量。

当然,这也意味着与 PHP 的双引号字符串语法不同,您可以在 SQL 字符串中包含文字 $1、$2 等,例如

<?php
// Works ($1 is a placeholder, $2 is meant literally)
pg_query_params("INSERT INTO foo (col1, col2) VALUES ($1, 'costs $2')", Array($data1));

// Throws an E_WARNING (passing too many parameters)
pg_query_params("INSERT INTO foo (col1, col2) VALUES ($1, 'costs $2')", Array($data1, $data2));
?>
mledford
17 年前
如果您尝试复制函数 pg_query_params,您可能还想支持 NULL 值。 虽然 is_int 对 NULL 值返回 true,但 SQL 的格式。

function pg_query_params( $db, $query, $parameters ) {
// Escape parameters as required & build parameters for callback function
global $pg_query_params__parameters;
foreach( $parameters as $k=>$v ) {
if ( is_null($v) ) {
$parameters[$k] = 'NULL';
} else {
$parameters[$k] = ( is_int( $v ) ? $v : "'".pg_escape_string( $v )."'" );
}
}
$pg_query_params__parameters = $parameters;

// Call using pg_query
return pg_query( $db, preg_replace_callback( '/\$([0-9]+)/', 'pg_query_params__callback', $query));
}
cc+php at c2se dot com
17 年前
这是一个用于防止 SQL 注入攻击的有用函数,因此,对于我们中那些还无法升级到 PHP5.1 的人来说,这里有一个在 PHP 的旧版本上类似工作的替代函数...

<?php # 用于 Postgresql 和旧版本 PHP 的参数化查询实现

if( !function_exists( 'pg_query_params' ) ) {

function
pg_query_params__callback( $at ) {
global
$pg_query_params__parameters;
return
$pg_query_params__parameters[ $at[1]-1 ];
}

function
pg_query_params( $db, $query, $parameters ) {

// 根据需要转义参数并构建用于回调函数的参数
global $pg_query_params__parameters;
foreach(
$parameters as $k=>$v )
$parameters[$k] = ( is_int( $v ) ? $v : "'".pg_escape_string( $v )."'" );
$pg_query_params__parameters = $parameters;

// 使用 pg_query 调用
return pg_query( $db, preg_replace_callback( '/\$([0-9]+)/', 'pg_query_params__callback', $query ) );

}
}

// 例子:pg_query_params( $db_resource, "SELECT * FROM table WHERE col1=$1 AND col2=$2", array( 42, "It's ok" ) );
?>
匿名
7 年前
如果参数之一是数组(例如,传递给存储过程的整数数组),则必须将其表示为数组中的一个集合,而不是 PHP 数组表示法。

例如:2 个参数(一个整数和一个整数数组)的 var_dump 输出
aaa 是:数组
(
[0] => 1
[1] => {2,3}
)

您不需要

bbb 是:数组
(
[0] => 1
[1] => 数组
(
[0] => 2
[1] => 3
)

)
php at richardneill dot org
10 年前
关于布尔值类型转换的说明
pg_query_params() 及其相关函数在适当情况下,会在 PHP-NULL 和 SQL-NULL 之间进行无缝、自动的转换。
然而,其他所有内容都以字符串的形式传入(和传出)。
以下方法可能有助于处理布尔字段

<?php
$sql
= " ... ";
$params = array (1, 2, 3, true, false);

// 将布尔值转换为 'true' 和 'false'。[NULLS 已被处理]。
foreach ($params as &$value){
if (
is_bool($value)){
$value = ($value) ? 'true':'false';
}
}

// 现在执行查询:
$result = pg_query_params ($sql, $params);
$row = pg_fetch_assoc ($result,0) // 第一行

// 对于布尔值,将 't' 和 'f' 转换回 true 和 false。检查列类型,以便我们不会意外地转换错误的东西。
foreach ($row as $key => &$value){
$type = pg_field_type($result,pg_field_num($result, $key));
if (
$type == 'bool'){
$value = ($value == 't');
}
}

//$row[] 现在包含布尔值、NULLS 和字符串。
?>
php at richardneill dot org
10 年前
pg_query_params() *确实* 接受 NULLS。它们将自动正确转换为 SQL NULL。因此,例如

<?php
$sql
= "UPDATE tbl_example SET column_a = $1, column_b=$2";
$params = array(NULL, 42);
$result = pg_params ($sql, $params);

// 等同于:
$result = pg_query ("UPDATE tbl_example SET column_a = NULL column_b = '42')";

// 而不是人们可能担心的以下两种情况(不正确):
// ... column_a = '' ...
// ... column_a = 'NULL' ...
?>

请注意,您可以在 UPDATE 或 INSERT 语句中以这种方式使用 NULLS,但不能在 WHERE 子句中使用。这不是 pg_query_params() 的限制,而是 SQL 语言的结果。
因此,如果您想要以下类型的查询

<?php
// 根据数据,where-test 参数可能是也可能不是 NULL
// 以下是 $1 的错误写法。
$sql = "SELECT * from tbl_example WHERE column_a = $1 and column_b = $2";
$params = array(NULL, 42);
$result = pg_params ($sql, $params);
?>

这将失败,因为它是不合法的 SQL:因为您应该使用 "= 42",但应使用 "IS NULL"。解决方法是使用 SQL 结构 "IS [NOT] DISTINCT FROM"。

<?php
$sql
= "SELECT ... WHERE column IS NOT DISTINCT FROM $1"
$params = array (42); // 此操作有效,与 "where column = 42" 相同
$params = array (NULL); // 此操作有效,与 "where column is null" 相同
?>

(除此之外:虽然这很烦人,但这种行为是正确的。存在一个 postgresql 兼容性选项 "transform_null_equals",但它在这里帮不了您,即使您可能期望它能帮您。)
travismowens at gmail dot com
14 年前
不幸的是,参数将不会尊重 NULL 或 NOW() 的字符串表示形式。如果您的代码推送这些值,它们将被视为字符串,并按字面意义插入为 "NULL" 和 "NOW()"。

理想情况下,应该有一个额外的参数,您可以将其分配给强制将此文本作为 pgSQL 函数/保留字,而不是将其包装为字符串(假设 pgSQL 的参数化查询支持此功能)。

同样的问题也发生在 "WHERE column IN (1,2,3,4)" 中使用的逗号列表中,params 将 "1,2,3,4" 视为字符串,而不是数字列表,并使用引号运行它。

为了进行调试,我使用此函数模拟参数,请记住这并不完全准确,它只尝试模拟参数查询创建的实际 SQL。

<?php
function pg_query_params_return_sql($query, $array)
{
$query_parsed = $query;

for (
$a = 0, $b = sizeof($array); $a < $b; $a++)
{
if (
is_numeric($array[$a]) )
{
$query_parsed = str_replace(('$'.($a+1)), str_replace("'","''", $array[$a]), $query_parsed );
}
else
{
$query_parsed = str_replace(('$'.($a+1)), "'".str_replace("'","''", $array[$a])."'", $query_parsed );
}
}

return
$query_parsed;
}
?>
php at richardneill dot org
10 年前
对于参数化日期,不允许使用 NOW() 值(它将被转换为文字字符串,并使 postgres 窒息),但是 'now'
作为参数是允许的,并且具有相同的效果。
To Top