yohgaki Fri, 25 Nov 2011 02:21:01 +0000 Revision: http://svn.php.net/viewvc?view=revision&revision=319788
Log: add pg_escape_identifier/pg_escape_literal Changed paths: U php/php-src/trunk/ext/pgsql/config.m4 U php/php-src/trunk/ext/pgsql/pgsql.c U php/php-src/trunk/ext/pgsql/php_pgsql.h U php/php-src/trunk/ext/pgsql/tests/08escape.phpt Modified: php/php-src/trunk/ext/pgsql/config.m4 =================================================================== --- php/php-src/trunk/ext/pgsql/config.m4 2011-11-25 02:17:33 UTC (rev 319787) +++ php/php-src/trunk/ext/pgsql/config.m4 2011-11-25 02:21:01 UTC (rev 319788) @@ -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 Modified: php/php-src/trunk/ext/pgsql/pgsql.c =================================================================== --- php/php-src/trunk/ext/pgsql/pgsql.c 2011-11-25 02:17:33 UTC (rev 319787) +++ php/php-src/trunk/ext/pgsql/pgsql.c 2011-11-25 02:21:01 UTC (rev 319788) @@ -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); } @@ -4200,6 +4213,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) Modified: php/php-src/trunk/ext/pgsql/php_pgsql.h =================================================================== --- php/php-src/trunk/ext/pgsql/php_pgsql.h 2011-11-25 02:17:33 UTC (rev 319787) +++ php/php-src/trunk/ext/pgsql/php_pgsql.h 2011-11-25 02:21:01 UTC (rev 319788) @@ -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 */ Modified: php/php-src/trunk/ext/pgsql/tests/08escape.phpt =================================================================== --- php/php-src/trunk/ext/pgsql/tests/08escape.phpt 2011-11-25 02:17:33 UTC (rev 319787) +++ php/php-src/trunk/ext/pgsql/tests/08escape.phpt 2011-11-25 02:21:01 UTC (rev 319788) @@ -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
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php