Created
November 20, 2011 23:49
-
-
Save yohgaki/1381181 to your computer and use it in GitHub Desktop.
php-trunk pg_escape_literal patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Index: ext/pgsql/tests/08escape.phpt | |
=================================================================== | |
--- ext/pgsql/tests/08escape.phpt (リビジョン 319557) | |
+++ ext/pgsql/tests/08escape.phpt (作業コピー) | |
@@ -11,8 +11,9 @@ | |
// 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 @@ | |
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 | |
Index: ext/pgsql/php_pgsql.h | |
=================================================================== | |
--- ext/pgsql/php_pgsql.h (リビジョン 319557) | |
+++ ext/pgsql/php_pgsql.h (作業コピー) | |
@@ -172,6 +172,8 @@ | |
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 */ | |
Index: ext/pgsql/config.m4 | |
=================================================================== | |
--- ext/pgsql/config.m4 (リビジョン 319557) | |
+++ ext/pgsql/config.m4 (作業コピー) | |
@@ -94,6 +94,7 @@ | |
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 | |
Index: ext/pgsql/pgsql.c | |
=================================================================== | |
--- ext/pgsql/pgsql.c (リビジョン 318651) | |
+++ ext/pgsql/pgsql.c (作業コピー) | |
@@ -422,6 +422,17 @@ | |
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 @@ | |
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 @@ | |
TSRMLS_FETCH(); | |
if (! PGG(ignore_notices)) { | |
notice = (php_pgsql_notice *)emalloc(sizeof(php_pgsql_notice)); | |
- notice->message = _php_pgsql_trim_message(message, ¬ice->len); | |
+ notice->message = _php_pgsql_trim_message(message, (int *)¬ice->len); | |
if (PGG(log_notices)) { | |
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "%s", notice->message); | |
} | |
@@ -4196,6 +4209,130 @@ | |
/* }}} */ | |
#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) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment