Thank you! -- Yasuo Ohgaki yohg...@ohgaki.net
2011/11/25 Stanislav Malyshev <s...@php.net>: > 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, > ¬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); > } > @@ -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 > -- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php