mirror of
https://github.com/php/php-src.git
synced 2024-09-22 02:17:32 +00:00
add pg_escape_identifier/pg_escape_literal
This commit is contained in:
parent
106e0a2e68
commit
655245afef
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
@ -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
|
Loading…
Reference in New Issue
Block a user