Commit:    655245afef75613551929610873d0ba09754777f
Author:    Yasuo Ohgaki <yohg...@php.net>         Fri, 25 Nov 2011 02:21:01 
+0000
Committer: Stanislav Malyshev <s...@php.net>      Thu, 19 Apr 2012 13:40:24 
-0700
Parents:   106e0a2e688f3e5c97e49760b9c3c99eea714ae8
Branches:  PHP-5.4

Link:       
http://git.php.net/?p=php-src.git;a=commitdiff;h=655245afef75613551929610873d0ba09754777f

Log:
add pg_escape_identifier/pg_escape_literal

Changed paths:
  M  ext/pgsql/config.m4
  M  ext/pgsql/pgsql.c
  M  ext/pgsql/php_pgsql.h
  M  ext/pgsql/tests/08escape.phpt


Diff:
diff --git a/ext/pgsql/config.m4 b/ext/pgsql/config.m4
index 2710796..bddb77a 100644
--- a/ext/pgsql/config.m4
+++ b/ext/pgsql/config.m4
@@ -94,6 +94,7 @@ if test "$PHP_PGSQL" != "no"; then
   AC_CHECK_LIB(pq, 
pg_encoding_to_char,AC_DEFINE(HAVE_PGSQL_WITH_MULTIBYTE_SUPPORT,1,[Whether 
libpq is compiled with --enable-multibyte]))
   AC_CHECK_LIB(pq, lo_create, AC_DEFINE(HAVE_PG_LO_CREATE,1,[PostgreSQL 8.1 or 
later]))
   AC_CHECK_LIB(pq, lo_import_with_oid, 
AC_DEFINE(HAVE_PG_LO_IMPORT_WITH_OID,1,[PostgreSQL 8.4 or later]))
+  AC_CHECK_LIB(pq, PQescapeLiteral, 
AC_DEFINE(HAVE_PQESCAPELITERAL,1,[PostgreSQL 9.0 or later]))
   LIBS=$old_LIBS
   LDFLAGS=$old_LDFLAGS
 
diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c
index 54a86a8..ad66779 100644
--- a/ext/pgsql/pgsql.c
+++ b/ext/pgsql/pgsql.c
@@ -422,6 +422,17 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_unescape_bytea, 0, 0, 1)
 ZEND_END_ARG_INFO()
 #endif
 
+#if HAVE_PQESCAPE
+ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_escape_literal, 0, 0, 0)
+       ZEND_ARG_INFO(0, connection)
+       ZEND_ARG_INFO(0, data)
+ZEND_END_ARG_INFO()
+ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_escape_identifier, 0, 0, 0)
+       ZEND_ARG_INFO(0, connection)
+       ZEND_ARG_INFO(0, data)
+ZEND_END_ARG_INFO()
+#endif
+
 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_result_error, 0, 0, 1)
        ZEND_ARG_INFO(0, result)
 ZEND_END_ARG_INFO()
@@ -652,6 +663,8 @@ const zend_function_entry pgsql_functions[] = {
        PHP_FE(pg_escape_string,        arginfo_pg_escape_string)
        PHP_FE(pg_escape_bytea,         arginfo_pg_escape_bytea)
        PHP_FE(pg_unescape_bytea,       arginfo_pg_unescape_bytea)
+       PHP_FE(pg_escape_literal,       arginfo_pg_escape_literal)
+       PHP_FE(pg_escape_identifier,    arginfo_pg_escape_identifier)
 #endif
 #if HAVE_PQSETERRORVERBOSITY
        PHP_FE(pg_set_error_verbosity,  arginfo_pg_set_error_verbosity)
@@ -815,7 +828,7 @@ static void _php_pgsql_notice_handler(void *resource_id, 
const char *message)
        TSRMLS_FETCH();
        if (! PGG(ignore_notices)) {
                notice = (php_pgsql_notice *)emalloc(sizeof(php_pgsql_notice));
-               notice->message = _php_pgsql_trim_message(message, 
&notice->len);
+               notice->message = _php_pgsql_trim_message(message, (int 
*)&notice->len);
                if (PGG(log_notices)) {
                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "%s", 
notice->message);
                }
@@ -4206,6 +4219,130 @@ PHP_FUNCTION(pg_unescape_bytea)
 /* }}} */
 #endif
 
+#ifdef HAVE_PQESCAPE
+#if !HAVE_PQESCAPELITERAL
+/* emulate libpq's PQescapeInternal() 9.0 or later */
+static char* php_pgsql_PQescapeInternal(PGconn *conn, const char *str, size_t 
len, int escape_literal) {
+       char *result, *rp;
+       const char *s;
+       size_t tmp_len;
+       int input_len = len;
+       char quote_char = escape_literal ? '\'' : '"';
+
+       if (!conn) {
+               return NULL;
+       }
+
+       /*
+        * NOTE: multibyte strings that could cointain slashes should be 
considered.
+        * (e.g. SJIS, BIG5) However, it cannot be done without valid PGconn 
and mbstring. 
+        * Therefore, this function does not support such encodings currently.
+        * FIXME: add encoding check and skip multibyte char bytes if there is 
vaild PGconn.
+        */
+
+       /* allocate enough memory */
+       rp = result = (char *)emalloc(len*2 + 5); /* leading " E" needs extra 2 
bytes + quote_chars on both end for 2 bytes + NULL */
+
+       if (escape_literal) {
+               /* check backslashes */
+               tmp_len = strspn(str, "\\");
+               if (tmp_len != len) {
+                       /* add " E" for escaping slashes */
+                       *rp++ = ' ';
+                       *rp++ = 'E';
+               }
+       }
+       /* open quote */
+       *rp++ = quote_char;
+       for (s = str; s - str < input_len; ++s) {
+               if (*s == quote_char || (escape_literal && *s == '\\')) {
+                       *rp++ = *s;
+                       *rp++ = *s;
+               } else {
+                       *rp++ = *s;
+               }
+       }
+       *rp++ = quote_char;
+       *rp = '\0';
+       
+       return result;
+}
+#endif
+
+static void php_pgsql_escape_internal(INTERNAL_FUNCTION_PARAMETERS, int 
escape_literal) {
+       char *from = NULL, *to = NULL, *tmp = NULL;
+       zval *pgsql_link = NULL;
+       PGconn *pgsql;
+       int to_len;
+       int from_len;
+       int id = -1;
+
+       switch (ZEND_NUM_ARGS()) {
+               case 1:
+                       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, 
"s", &from, &from_len) == FAILURE) {
+                               return;
+                       }
+                       pgsql_link = NULL;
+                       id = PGG(default_link);
+                       break;
+
+               default:
+                       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, 
"rs", &pgsql_link, &from, &from_len) == FAILURE) {
+                               return;
+                       }
+                       break;
+       }
+
+       if (pgsql_link == NULL && id == -1) {
+               RETURN_FALSE;
+       }
+
+       ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL 
link", le_link, le_plink);
+       if (pgsql == NULL) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING,"Cannot get default 
pgsql link");
+               RETURN_FALSE;
+       }
+#ifdef HAVE_PQESCAPELITERAL
+       if (escape_literal) {
+               tmp = PQescapeLiteral(pgsql, from, (size_t)from_len);
+       } else {
+               tmp = PQescapeIdentifier(pgsql, from, (size_t)from_len);
+       }
+       if (!tmp) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING,"Failed to escape");
+               RETURN_FALSE;
+       }
+       to = estrdup(tmp);
+       PQfreemem(tmp);
+#else 
+       to = php_pgsql_PQescapeInternal(pgsql, from, (size_t)from_len, 
escape_literal);
+       if (!to) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING,"Failed to escape");
+               RETURN_FALSE;
+       }
+#endif
+
+       RETURN_STRING(to, 0);
+}
+
+/* {{{ proto string pg_escape_literal([resource connection,] string data)
+   Escape parameter as string literal (i.e. parameter) */
+PHP_FUNCTION(pg_escape_literal)
+{
+       php_pgsql_escape_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
+}
+/* }}} */
+
+/* {{{ proto string pg_escape_identifier([resource connection,] string data)
+   Escape identifier (i.e. table name, field name)     */
+PHP_FUNCTION(pg_escape_identifier)
+{
+       php_pgsql_escape_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
+}
+/* }}} */
+#endif
+
+
 /* {{{ proto string pg_result_error(resource result)
    Get error message associated with result */
 PHP_FUNCTION(pg_result_error)
diff --git a/ext/pgsql/php_pgsql.h b/ext/pgsql/php_pgsql.h
index b247456..8b6abbf 100644
--- a/ext/pgsql/php_pgsql.h
+++ b/ext/pgsql/php_pgsql.h
@@ -172,6 +172,8 @@ PHP_FUNCTION(pg_set_error_verbosity);
 PHP_FUNCTION(pg_escape_string);
 PHP_FUNCTION(pg_escape_bytea);
 PHP_FUNCTION(pg_unescape_bytea);
+PHP_FUNCTION(pg_escape_literal);
+PHP_FUNCTION(pg_escape_identifier);
 #endif
 
 /* misc functions */
diff --git a/ext/pgsql/tests/08escape.phpt b/ext/pgsql/tests/08escape.phpt
index cf23b50..90b4ed8 100644
--- a/ext/pgsql/tests/08escape.phpt
+++ b/ext/pgsql/tests/08escape.phpt
@@ -11,8 +11,9 @@ define('FILE_NAME', dirname(__FILE__) . '/php.gif');
 // pg_escape_string() test
 $before = "ABC\\ABC\'";
 $expect  = "ABC\\\\ABC\\'";
+$expect2  = "ABC\\\\ABC\\\\''"; //the way escape string differs from 
PostgreSQL 9.0
 $after = pg_escape_string($before);
-if ($expect === $after) {
+if ($expect === $after || $expect2 === $after) {
        echo "pg_escape_string() is Ok\n";
 }
 else {
@@ -58,11 +59,37 @@ else {
        echo "pg_escape_bytea() is broken\n";
 }
 
+// pg_escape_literal/pg_escape_identifier
+$before = "ABC\\ABC\'";
+$expect         = " E'ABC\\\\ABC\\\\'''";
+$after = pg_escape_literal($before);
+if ($expect === $after) {
+       echo "pg_escape_literal() is Ok\n";
+}
+else {
+       echo "pg_escape_literal() is NOT Ok\n";
+       var_dump($before);
+       var_dump($after);
+       var_dump($expect);
+}
+
+$before = "ABC\\ABC\'";
+$expect         = "\"ABC\ABC\'\"";
+$after = pg_escape_identifier($before);
+if ($expect === $after) {
+       echo "pg_escape_identifier() is Ok\n";
+}
+else {
+       echo "pg_escape_identifier() is NOT Ok\n";
+       var_dump($before);
+       var_dump($after);
+       var_dump($expect);
+}
+
 ?>
 --EXPECT--
-pg_escape_string() is NOT Ok
-string(9) "ABC\ABC\'"
-string(12) "ABC\\ABC\\''"
-string(10) "ABC\\ABC\'"
+pg_escape_string() is Ok
 pg_escape_bytea() is Ok
 pg_escape_bytea() actually works with database
+pg_escape_literal() is Ok
+pg_escape_identifier() is Ok
\ No newline at end of file


--
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to