@@ -914,6 +914,60 @@ static void _free_result(zend_rsrc_list_entry *rsrc TSRMLS_DC)
914
914
}
915
915
/* }}} */
916
916
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
+
917
971
/* {{{ PHP_INI
918
972
*/
919
973
PHP_INI_BEGIN ()
@@ -5015,8 +5069,9 @@ PHP_PGSQL_API int php_pgsql_meta_data(PGconn *pg_link, const char *table_name, z
5015
5069
{
5016
5070
PGresult * pg_result ;
5017
5071
char * src , * tmp_name , * tmp_name2 = NULL ;
5072
+ char * escaped ;
5018
5073
smart_str querystr = {0 };
5019
- int new_len ;
5074
+ size_t new_len ;
5020
5075
int i , num_rows ;
5021
5076
zval * elem ;
5022
5077
@@ -5038,20 +5093,29 @@ PHP_PGSQL_API int php_pgsql_meta_data(PGconn *pg_link, const char *table_name, z
5038
5093
"SELECT a.attname, a.attnum, t.typname, a.attlen, a.attnotnull, a.atthasdef, a.attndims, t.typtype = 'e' "
5039
5094
"FROM pg_class as c, pg_attribute a, pg_type t, pg_namespace n "
5040
5095
"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
+
5044
5105
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 );
5047
5114
5048
5115
smart_str_appends (& querystr , "' AND a.atttypid = t.oid ORDER BY a.attnum;" );
5049
5116
smart_str_0 (& querystr );
5050
-
5051
- efree (tmp_name2 );
5052
- efree (tmp_name );
5053
- efree (src );
5054
-
5117
+ efree (src );
5118
+
5055
5119
pg_result = PQexec (pg_link , querystr .c );
5056
5120
if (PQresultStatus (pg_result ) != PGRES_TUPLES_OK || (num_rows = PQntuples (pg_result )) == 0 ) {
5057
5121
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)
5274
5338
assert (Z_TYPE_P (src ) == IS_STRING );
5275
5339
assert (should_free == 1 || should_free == 0 );
5276
5340
5341
+ smart_str_appendc (& str , 'E' );
5277
5342
smart_str_appendc (& str , '\'' );
5278
5343
smart_str_appendl (& str , Z_STRVAL_P (src ), Z_STRLEN_P (src ));
5279
5344
smart_str_appendc (& str , '\'' );
@@ -5314,7 +5379,7 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con
5314
5379
uint field_len = -1 ;
5315
5380
ulong num_idx = -1 ;
5316
5381
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 ;
5318
5383
php_pgsql_data_type data_type ;
5319
5384
5320
5385
assert (pg_link != NULL );
@@ -5327,6 +5392,8 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con
5327
5392
}
5328
5393
MAKE_STD_ZVAL (meta );
5329
5394
array_init (meta );
5395
+
5396
+ /* table_name is escaped by php_pgsql_meta_data */
5330
5397
if (php_pgsql_meta_data (pg_link , table_name , meta TSRMLS_CC ) == FAILURE ) {
5331
5398
zval_dtor (meta );
5332
5399
FREE_ZVAL (meta );
@@ -5539,15 +5606,15 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con
5539
5606
}
5540
5607
else {
5541
5608
Z_TYPE_P (new_val ) = IS_STRING ;
5542
- #if HAVE_PQESCAPE
5609
+ #if HAVE_PQESCAPE_CONN
5543
5610
{
5544
5611
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 );
5547
5614
Z_STRVAL_P (new_val ) = tmp ;
5548
5615
}
5549
5616
#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 );
5551
5618
#endif
5552
5619
php_pgsql_add_quotes (new_val , 1 TSRMLS_CC );
5553
5620
}
@@ -5833,6 +5900,7 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con
5833
5900
else {
5834
5901
unsigned char * tmp ;
5835
5902
size_t to_len ;
5903
+ smart_str s = {0 };
5836
5904
#ifdef HAVE_PQESCAPE_BYTEA_CONN
5837
5905
tmp = PQescapeByteaConn (pg_link , Z_STRVAL_PP (val ), Z_STRLEN_PP (val ), & to_len );
5838
5906
#else
@@ -5844,7 +5912,11 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con
5844
5912
memcpy (Z_STRVAL_P (new_val ), tmp , to_len );
5845
5913
PQfreemem (tmp );
5846
5914
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 ;
5848
5920
}
5849
5921
break ;
5850
5922
@@ -5929,11 +6001,22 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con
5929
6001
FREE_ZVAL (new_val );
5930
6002
break ; /* break out for() */
5931
6003
}
6004
+ /* If field is NULL and HAS DEFAULT, should be skipped */
5932
6005
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 );
5937
6020
}
5938
6021
} /* for */
5939
6022
zval_dtor (meta );
@@ -6008,6 +6091,45 @@ static int do_exec(smart_str *querystr, int expect, PGconn *pg_link, ulong opt T
6008
6091
return -1 ;
6009
6092
}
6010
6093
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
+
6011
6133
/* {{{ php_pgsql_insert
6012
6134
*/
6013
6135
PHP_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
6027
6149
6028
6150
if (zend_hash_num_elements (Z_ARRVAL_P (var_array )) == 0 ) {
6029
6151
smart_str_appends (& querystr , "INSERT INTO " );
6030
- smart_str_appends (& querystr , table );
6152
+ build_tablename (& querystr , pg_link , table );
6031
6153
smart_str_appends (& querystr , " DEFAULT VALUES" );
6032
6154
6033
6155
goto no_values ;
@@ -6042,11 +6164,11 @@ PHP_PGSQL_API int php_pgsql_insert(PGconn *pg_link, const char *table, zval *var
6042
6164
}
6043
6165
var_array = converted ;
6044
6166
}
6045
-
6167
+
6046
6168
smart_str_appends (& querystr , "INSERT INTO " );
6047
- smart_str_appends (& querystr , table );
6169
+ build_tablename (& querystr , pg_link , table );
6048
6170
smart_str_appends (& querystr , " (" );
6049
-
6171
+
6050
6172
zend_hash_internal_pointer_reset_ex (Z_ARRVAL_P (var_array ), & pos );
6051
6173
while ((key_type = zend_hash_get_current_key_ex (Z_ARRVAL_P (var_array ), & fld ,
6052
6174
& 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
6233
6355
}
6234
6356
6235
6357
smart_str_appends (& querystr , "UPDATE " );
6236
- smart_str_appends (& querystr , table );
6358
+ build_tablename (& querystr , pg_link , table );
6237
6359
smart_str_appends (& querystr , " SET " );
6238
6360
6239
6361
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
6334
6456
}
6335
6457
6336
6458
smart_str_appends (& querystr , "DELETE FROM " );
6337
- smart_str_appends (& querystr , table );
6459
+ build_tablename (& querystr , pg_link , table );
6338
6460
smart_str_appends (& querystr , " WHERE " );
6339
6461
6340
6462
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
6470
6592
}
6471
6593
6472
6594
smart_str_appends (& querystr , "SELECT * FROM " );
6473
- smart_str_appends (& querystr , table );
6595
+ build_tablename (& querystr , pg_link , table );
6474
6596
smart_str_appends (& querystr , " WHERE " );
6475
6597
6476
6598
if (build_assignment_string (& querystr , Z_ARRVAL_P (ids_array ), 1 , " AND " , sizeof (" AND " )- 1 TSRMLS_CC ))
0 commit comments