@@ -914,6 +914,60 @@ static void _free_result(zend_rsrc_list_entry *rsrc TSRMLS_DC)
914914}
915915/* }}} */
916916
917+
918+ static int _php_pgsql_detect_identifier_escape (const char * identifier , size_t len )
919+ {
920+ size_t i ;
921+
922+ /* Handle edge case. Cannot be a escaped string */
923+ if (len <= 2 ) {
924+ return FAILURE ;
925+ }
926+ /* Detect double qoutes */
927+ if (identifier [0 ] == '"' && identifier [len - 1 ] == '"' ) {
928+ /* Detect wrong format of " inside of escaped string */
929+ for (i = 1 ; i < len - 1 ; i ++ ) {
930+ if (identifier [i ] == '"' && (identifier [++ i ] != '"' || i == len - 1 )) {
931+ return FAILURE ;
932+ }
933+ }
934+ } else {
935+ return FAILURE ;
936+ }
937+ /* Escaped properly */
938+ return SUCCESS ;
939+ }
940+
941+ #if !HAVE_PQESCAPELITERAL
942+ /* {{{ _php_pgsql_escape_identifier
943+ * Since PQescapeIdentifier() is unavailable (PostgreSQL 9.0 <), idenfifers
944+ * should be escaped by pgsql module.
945+ * Note: this function does not care for encoding. Therefore users should not
946+ * use this with SJIS/BIG5 etc. (i.e. Encoding base injection may possible with
947+ * before PostgreSQL 9.0)
948+ */
949+ static char * _php_pgsql_escape_identifier (const char * field , size_t field_len )
950+ {
951+ ulong field_escaped_len = field_len * 2 + 3 ;
952+ ulong i , j = 0 ;
953+ char * field_escaped ;
954+
955+ field_escaped = (char * )malloc (field_escaped_len );
956+ field_escaped [j ++ ] = '"' ;
957+ for (i = 0 ; i < field_len ; i ++ ) {
958+ if (field [i ] == '"' ) {
959+ field_escaped [j ++ ] = '"' ;
960+ field_escaped [j ++ ] = '"' ;
961+ } else {
962+ field_escaped [j ++ ] = field [i ];
963+ }
964+ }
965+ field_escaped [j ++ ] = '"' ;
966+ field_escaped [j ] = '\0' ;
967+ return field_escaped ;
968+ }
969+ #endif
970+
917971/* {{{ PHP_INI
918972 */
919973PHP_INI_BEGIN ()
@@ -5015,8 +5069,9 @@ PHP_PGSQL_API int php_pgsql_meta_data(PGconn *pg_link, const char *table_name, z
50155069{
50165070 PGresult * pg_result ;
50175071 char * src , * tmp_name , * tmp_name2 = NULL ;
5072+ char * escaped ;
50185073 smart_str querystr = {0 };
5019- int new_len ;
5074+ size_t new_len ;
50205075 int i , num_rows ;
50215076 zval * elem ;
50225077
@@ -5038,20 +5093,29 @@ PHP_PGSQL_API int php_pgsql_meta_data(PGconn *pg_link, const char *table_name, z
50385093 "SELECT a.attname, a.attnum, t.typname, a.attlen, a.attnotnull, a.atthasdef, a.attndims, t.typtype = 'e' "
50395094 "FROM pg_class as c, pg_attribute a, pg_type t, pg_namespace n "
50405095 "WHERE a.attnum > 0 AND a.attrelid = c.oid AND c.relname = '" );
5041- tmp_name2 = php_addslashes (tmp_name2 , strlen (tmp_name2 ), & new_len , 0 TSRMLS_CC );
5042- smart_str_appendl (& querystr , tmp_name2 , new_len );
5043-
5096+ escaped = (char * )safe_emalloc (strlen (tmp_name2 ), 2 , 1 );
5097+ #if HAVE_PQESCAPE_CONN
5098+ new_len = PQescapeStringConn (pg_link , escaped , tmp_name2 , strlen (tmp_name2 ), NULL );
5099+ #else
5100+ new_len = PQescapeString (escaped , tmp_name2 , strlen (tmp_name2 ));
5101+ #endif
5102+ smart_str_appends (& querystr , escaped );
5103+ efree (escaped );
5104+
50445105 smart_str_appends (& querystr , "' AND c.relnamespace = n.oid AND n.nspname = '" );
5045- tmp_name = php_addslashes (tmp_name , strlen (tmp_name ), & new_len , 0 TSRMLS_CC );
5046- smart_str_appendl (& querystr , tmp_name , new_len );
5106+ escaped = (char * )safe_emalloc (strlen (tmp_name ), 2 , 1 );
5107+ #if HAVE_PQESCAPE_CONN
5108+ new_len = PQescapeStringConn (pg_link , escaped , tmp_name , strlen (tmp_name ), NULL );
5109+ #else
5110+ new_len = PQescapeString (escaped , tmp_name , strlen (tmp_name ));
5111+ #endif
5112+ smart_str_appends (& querystr , escaped );
5113+ efree (escaped );
50475114
50485115 smart_str_appends (& querystr , "' AND a.atttypid = t.oid ORDER BY a.attnum;" );
50495116 smart_str_0 (& querystr );
5050-
5051- efree (tmp_name2 );
5052- efree (tmp_name );
5053- efree (src );
5054-
5117+ efree (src );
5118+
50555119 pg_result = PQexec (pg_link , querystr .c );
50565120 if (PQresultStatus (pg_result ) != PGRES_TUPLES_OK || (num_rows = PQntuples (pg_result )) == 0 ) {
50575121 php_error_docref (NULL TSRMLS_CC , E_WARNING , "Table '%s' doesn't exists" , table_name );
@@ -5274,6 +5338,7 @@ static int php_pgsql_add_quotes(zval *src, zend_bool should_free TSRMLS_DC)
52745338 assert (Z_TYPE_P (src ) == IS_STRING );
52755339 assert (should_free == 1 || should_free == 0 );
52765340
5341+ smart_str_appendc (& str , 'E' );
52775342 smart_str_appendc (& str , '\'' );
52785343 smart_str_appendl (& str , Z_STRVAL_P (src ), Z_STRLEN_P (src ));
52795344 smart_str_appendc (& str , '\'' );
@@ -5314,7 +5379,7 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con
53145379 uint field_len = -1 ;
53155380 ulong num_idx = -1 ;
53165381 zval * meta , * * def , * * type , * * not_null , * * has_default , * * is_enum , * * val , * new_val ;
5317- int new_len , key_type , err = 0 , skip_field ;
5382+ int key_type , err = 0 , skip_field ;
53185383 php_pgsql_data_type data_type ;
53195384
53205385 assert (pg_link != NULL );
@@ -5327,6 +5392,8 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con
53275392 }
53285393 MAKE_STD_ZVAL (meta );
53295394 array_init (meta );
5395+
5396+ /* table_name is escaped by php_pgsql_meta_data */
53305397 if (php_pgsql_meta_data (pg_link , table_name , meta TSRMLS_CC ) == FAILURE ) {
53315398 zval_dtor (meta );
53325399 FREE_ZVAL (meta );
@@ -5539,15 +5606,15 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con
55395606 }
55405607 else {
55415608 Z_TYPE_P (new_val ) = IS_STRING ;
5542- #if HAVE_PQESCAPE
5609+ #if HAVE_PQESCAPE_CONN
55435610 {
55445611 char * tmp ;
5545- tmp = (char * )safe_emalloc (Z_STRLEN_PP (val ), 2 , 1 );
5546- Z_STRLEN_P (new_val ) = (int )PQescapeString ( tmp , Z_STRVAL_PP (val ), Z_STRLEN_PP (val ));
5612+ tmp = (char * )safe_emalloc (Z_STRLEN_PP (val ), 2 , 1 );
5613+ Z_STRLEN_P (new_val ) = (int )PQescapeStringConn ( pg_link , tmp , Z_STRVAL_PP (val ), Z_STRLEN_PP (val ), NULL );
55475614 Z_STRVAL_P (new_val ) = tmp ;
55485615 }
55495616#else
5550- Z_STRVAL_P (new_val ) = php_addslashes (Z_STRVAL_PP (val ), Z_STRLEN_PP (val ), & Z_STRLEN_P (new_val ), 0 TSRMLS_CC );
5617+ Z_STRVAL_P (new_val ) = ( int ) PQescapeString (Z_STRVAL_PP (val ), Z_STRLEN_PP (val ), & Z_STRLEN_P (new_val ), 0 TSRMLS_CC );
55515618#endif
55525619 php_pgsql_add_quotes (new_val , 1 TSRMLS_CC );
55535620 }
@@ -5833,6 +5900,7 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con
58335900 else {
58345901 unsigned char * tmp ;
58355902 size_t to_len ;
5903+ smart_str s = {0 };
58365904#ifdef HAVE_PQESCAPE_BYTEA_CONN
58375905 tmp = PQescapeByteaConn (pg_link , Z_STRVAL_PP (val ), Z_STRLEN_PP (val ), & to_len );
58385906#else
@@ -5844,7 +5912,11 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con
58445912 memcpy (Z_STRVAL_P (new_val ), tmp , to_len );
58455913 PQfreemem (tmp );
58465914 php_pgsql_add_quotes (new_val , 1 TSRMLS_CC );
5847-
5915+ smart_str_appendl (& s , Z_STRVAL_P (new_val ), Z_STRLEN_P (new_val ));
5916+ smart_str_0 (& s );
5917+ efree (Z_STRVAL_P (new_val ));
5918+ Z_STRVAL_P (new_val ) = s .c ;
5919+ Z_STRLEN_P (new_val ) = s .len ;
58485920 }
58495921 break ;
58505922
@@ -5929,11 +6001,22 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con
59296001 FREE_ZVAL (new_val );
59306002 break ; /* break out for() */
59316003 }
6004+ /* If field is NULL and HAS DEFAULT, should be skipped */
59326005 if (!skip_field ) {
5933- /* If field is NULL and HAS DEFAULT, should be skipped */
5934- field = php_addslashes (field , strlen (field ), & new_len , 0 TSRMLS_CC );
5935- add_assoc_zval (result , field , new_val );
5936- efree (field );
6006+ char * escaped ;
6007+ size_t new_len , field_len = strlen (field );
6008+
6009+ if (_php_pgsql_detect_identifier_escape (field , field_len ) == SUCCESS ) {
6010+ escaped = strndup (field , field_len );
6011+ } else {
6012+ #if HAVE_PQESCAPELITERAL
6013+ escaped = PQescapeIdentifier (pg_link , field , field_len );
6014+ #else
6015+ escaped = _php_pgsql_escape_identifier (field , field_len );
6016+ #endif
6017+ }
6018+ add_assoc_zval (result , escaped , new_val );
6019+ free (escaped );
59376020 }
59386021 } /* for */
59396022 zval_dtor (meta );
@@ -6008,6 +6091,45 @@ static int do_exec(smart_str *querystr, int expect, PGconn *pg_link, ulong opt T
60086091 return -1 ;
60096092}
60106093
6094+ static inline void build_tablename (smart_str * querystr , PGconn * pg_link , const char * table )
6095+ {
6096+ char * table_copy , * escaped , * token , * tmp ;
6097+ size_t len ;
6098+
6099+ /* schame.table should be "schame"."table" */
6100+ table_copy = estrdup (table );
6101+ token = php_strtok_r (table_copy , "." , & tmp );
6102+ len = strlen (token );
6103+ if (_php_pgsql_detect_identifier_escape (token , len ) == SUCCESS ) {
6104+ escaped = strndup (token , len );
6105+ } else {
6106+ #if HAVE_PQESCAPELITERAL
6107+ escaped = PQescapeIdentifier (pg_link , token , len );
6108+ #else
6109+ escaped = _php_pgsql_escape_identifier (token , len );
6110+ #endif
6111+ }
6112+ smart_str_appends (querystr , escaped );
6113+ free (escaped );
6114+ if (tmp && * tmp ) {
6115+ len = strlen (tmp );
6116+ /* "schema"."table" format */
6117+ if (_php_pgsql_detect_identifier_escape (tmp , len ) == SUCCESS ) {
6118+ escaped = strndup (tmp , len );
6119+ } else {
6120+ #if HAVE_PQESCAPELITERAL
6121+ escaped = PQescapeIdentifier (pg_link , tmp , len );
6122+ #else
6123+ escaped = _php_pgsql_escape_identifier (tmp , len );
6124+ #endif
6125+ }
6126+ smart_str_appendc (querystr , '.' );
6127+ smart_str_appends (querystr , escaped );
6128+ free (escaped );
6129+ }
6130+ efree (table_copy );
6131+ }
6132+
60116133/* {{{ php_pgsql_insert
60126134 */
60136135PHP_PGSQL_API int php_pgsql_insert (PGconn * pg_link , const char * table , zval * var_array , ulong opt , char * * sql TSRMLS_DC )
@@ -6027,7 +6149,7 @@ PHP_PGSQL_API int php_pgsql_insert(PGconn *pg_link, const char *table, zval *var
60276149
60286150 if (zend_hash_num_elements (Z_ARRVAL_P (var_array )) == 0 ) {
60296151 smart_str_appends (& querystr , "INSERT INTO " );
6030- smart_str_appends (& querystr , table );
6152+ build_tablename (& querystr , pg_link , table );
60316153 smart_str_appends (& querystr , " DEFAULT VALUES" );
60326154
60336155 goto no_values ;
@@ -6042,11 +6164,11 @@ PHP_PGSQL_API int php_pgsql_insert(PGconn *pg_link, const char *table, zval *var
60426164 }
60436165 var_array = converted ;
60446166 }
6045-
6167+
60466168 smart_str_appends (& querystr , "INSERT INTO " );
6047- smart_str_appends (& querystr , table );
6169+ build_tablename (& querystr , pg_link , table );
60486170 smart_str_appends (& querystr , " (" );
6049-
6171+
60506172 zend_hash_internal_pointer_reset_ex (Z_ARRVAL_P (var_array ), & pos );
60516173 while ((key_type = zend_hash_get_current_key_ex (Z_ARRVAL_P (var_array ), & fld ,
60526174 & fld_len , & num_idx , 0 , & pos )) != HASH_KEY_NON_EXISTANT ) {
@@ -6233,7 +6355,7 @@ PHP_PGSQL_API int php_pgsql_update(PGconn *pg_link, const char *table, zval *var
62336355 }
62346356
62356357 smart_str_appends (& querystr , "UPDATE " );
6236- smart_str_appends (& querystr , table );
6358+ build_tablename (& querystr , pg_link , table );
62376359 smart_str_appends (& querystr , " SET " );
62386360
62396361 if (build_assignment_string (& querystr , Z_ARRVAL_P (var_array ), 0 , "," , 1 TSRMLS_CC ))
@@ -6334,7 +6456,7 @@ PHP_PGSQL_API int php_pgsql_delete(PGconn *pg_link, const char *table, zval *ids
63346456 }
63356457
63366458 smart_str_appends (& querystr , "DELETE FROM " );
6337- smart_str_appends (& querystr , table );
6459+ build_tablename (& querystr , pg_link , table );
63386460 smart_str_appends (& querystr , " WHERE " );
63396461
63406462 if (build_assignment_string (& querystr , Z_ARRVAL_P (ids_array ), 1 , " AND " , sizeof (" AND " )- 1 TSRMLS_CC ))
@@ -6470,7 +6592,7 @@ PHP_PGSQL_API int php_pgsql_select(PGconn *pg_link, const char *table, zval *ids
64706592 }
64716593
64726594 smart_str_appends (& querystr , "SELECT * FROM " );
6473- smart_str_appends (& querystr , table );
6595+ build_tablename (& querystr , pg_link , table );
64746596 smart_str_appends (& querystr , " WHERE " );
64756597
64766598 if (build_assignment_string (& querystr , Z_ARRVAL_P (ids_array ), 1 , " AND " , sizeof (" AND " )- 1 TSRMLS_CC ))
0 commit comments