php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #63344 pg_query_params() doesn't pass parts of strings past zero byte character
Submitted: 2012-10-24 04:39 UTC Modified: 2013-07-08 10:39 UTC
From: peter dot kehl at gmail dot com Assigned: yohgaki (profile)
Status: Wont fix Package: PostgreSQL related
PHP Version: 5.4.8 OS: CentOS 6.2; possibly irrelevant
Private report: No CVE-ID: None
Password:
Status:
Package:
Bug Type:
Summary:
From: peter dot kehl at gmail dot com
New email:
PHP Version: OS:

 

 [2012-10-24 04:39 UTC] peter dot kehl at gmail dot com
Description:
------------
This may not be a code problem, but a documentation problem.

At the top, this is similar to https://bugs.php.net/bug.php?id=45491&edit=2, but not the same. If the current behaviour is intended, then it should be documented at www.php.net/pg_query_params - because current documentation doesn't mention that it doesn't support zero bytes.

Summary
If I call pg_query_params( $connection, $sql_query_with_dollar_placeholders, $params ) with all three parameters, and $params is an array with at least 1 value which is a string, which contains 1 or more zero bye characters (in PHP it's chr(0) or "\0"), then that zero byte character(s) and anything right from it (in the same string) won't be passed to Postgres server.

I've checked Postgres server logs, and the values come truncated just before the first zero byte character.

That is probably due to Postgres using/treating strings like C language does, ended with a zero byte character. However, in PHP a string can contain one or multiple zero byte characters. This happens when e.g. using output of PHP's function serialize().

Side note
I'm curious whether there is any way to set a Postgres varchar/text column to contain one or more zero byte characters. Following fails in pgAdmin (which uses UTF-8):
INSERT INTO null_character_test(value) VALUES( E'First\0Second');

Environment:
----------
PHP server:
CentOS 6.3
Linux localhost.localdomain 2.6.32-279.el6.x86_64 #1 SMP Fri Jun 22 12:19:21 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux

Compiled PHP 5.4.8
./configure --prefix=/usr/local/php --with-pgsql  --with-apxs2=/usr/sbin/apxs --enable-mbstring 

/usr/local/php/bin/php -v
PHP 5.4.8 (cli) (built: Oct 24 2012 14:49:11) 
Copyright (c) 1997-2012 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2012 Zend Technologies
----
Postgres server (and also a PHP server, where the same problem applies)
CentOS 6.2
Linux pkehlcentos.racpnet.localhost.local 2.6.32-220.el6.x86_64 #1 SMP Tue Dec 6 19:48:22 GMT 2011 x86_64 x86_64 x86_64 GNU/Linux

PostgreSQL 8.4.11 on x86_64-redhat-linux-gnu, compiled by GCC gcc (GCC) 4.4.6 20110731 (Red Hat 4.4.6-3), 64-bit.

/usr/local/php/bin/php -v
PHP 5.4.4 (cli) (built: Aug 15 2012 14:07:53) 
Copyright (c) 1997-2012 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2012 Zend Technologies
    with Xdebug v2.2.1, Copyright (c) 2002-2012, by Derick Rethans



Test script:
---------------
CREATE TABLE null_character_test( value varchar(255) );

<?php
$params= array(
        "Only the first part (this one) gets saved to DB.\0Anything after a null character (this) gets removed."
         );
    // PHP's strlen() counts characters past the null character.
    echo "Number of characters in the problem string, as reported by PHP's strlen(): " .strlen( $params[0]);

        $con= pg_connect( "host='10.10.6.62' port='5432' dbname='moodlepkehlcentos22' user='moodlepkehlcentos22' password='pkehlcentos22moodle'", PGSQL_CONNECT_FORCE_NEW );
        $sql= 'INSERT INTO null_character_test(value) VALUES($1)';
        pg_query_params( $con, $sql, $params );


Expected result:
----------------
SELECT * FROM null_character_test WHERE value LIKE 'Only the first part (this one) gets saved to DB.%Anything after a null character (this) gets removed.'

--> that should match 1 row

Actual result:
--------------
SELECT * FROM null_character_test WHERE value='Only the first part (this one) gets saved to DB.'

--> that matches 1 row

Patches

bug63344.patch (last revision 2012-10-24 06:35 UTC) by laruence@php.net)

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2012-10-24 06:34 UTC] laruence@php.net
according to http://www.postgresql.org/docs/8.0/static/libpq-exec.html

the current PHP's wrapper of PQexecParams doesn't support binary data.

a simple fix is attached
 [2012-10-24 06:35 UTC] laruence@php.net
The following patch has been added/updated:

Patch Name: bug63344.patch
Revision:   1351060504
URL:        https://bugs.php.net/patch-display.php?bug=63344&patch=bug63344.patch&revision=1351060504
 [2012-10-24 06:35 UTC] laruence@php.net
-Assigned To: +Assigned To: yohgaki
 [2012-10-25 01:00 UTC] peter dot kehl at gmail dot com
OK, pg_query_params() works as defined by Postgres. Thank you.

However, I suggest a change of Example #1 at http://www.php.net/serialize. That example saves a result of serialize() to an ODBC database. I have no way of testing whether that works with strings containing zero byte(s). Anyway, that example may lead people to save a result of serialize() using Postgres (or MSSQL mssql_query()), which fail.

Please change that example to use base64_encode() and base64_decode(), and add a note that serialize() generates a string which may contain zero byte(s).
 [2013-04-16 19:32 UTC] yohgaki@php.net
I realized this issue years ago.
We need to add correct length parameter for string.

The reason why I didn't fix this is there might be users using pg_escate_bytea() 
for prepared queries.

I can simply fix, but there is slight BC issue.
 [2013-06-29 20:09 UTC] yohgaki@php.net
-Type: Bug +Type: Feature/Change Request
 [2013-06-29 20:09 UTC] yohgaki@php.net
This requires API change. Change bug type.
 [2013-07-08 10:39 UTC] yohgaki@php.net
-Status: Assigned +Status: Wont fix
 [2013-07-08 10:39 UTC] yohgaki@php.net
We discussed this issue and decided not to implement this feature.
You cannot insert string contains null as UTF-8. 
If you are using bytea, make sure you use pg_escape_bytea()/pg_unescape_bytea() 
even with prepared query type API.

We may implement API supports direct bytea in the future, but it requires libpq 
support which is not available now.
 
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Sun Nov 19 01:31:42 2017 UTC