@@ -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 ()
@@ -5016,8 +5070,9 @@ PHP_PGSQL_API int php_pgsql_meta_data(PGconn *pg_link, const char *table_name, z
5016
5070
{
5017
5071
PGresult * pg_result ;
5018
5072
char * src , * tmp_name , * tmp_name2 = NULL ;
5073
+ char * escaped ;
5019
5074
smart_str querystr = {0 };
5020
- int new_len ;
5075
+ size_t new_len ;
5021
5076
int i , num_rows ;
5022
5077
zval * elem ;
5023
5078
@@ -5039,20 +5094,29 @@ PHP_PGSQL_API int php_pgsql_meta_data(PGconn *pg_link, const char *table_name, z
5039
5094
"SELECT a.attname, a.attnum, t.typname, a.attlen, a.attnotnull, a.atthasdef, a.attndims, t.typtype = 'e' "
5040
5095
"FROM pg_class as c, pg_attribute a, pg_type t, pg_namespace n "
5041
5096
"WHERE a.attnum > 0 AND a.attrelid = c.oid AND c.relname = '" );
5042
- tmp_name2 = php_addslashes (tmp_name2 , strlen (tmp_name2 ), & new_len , 0 TSRMLS_CC );
5043
- smart_str_appendl (& querystr , tmp_name2 , new_len );
5044
-
5097
+ escaped = (char * )safe_emalloc (strlen (tmp_name2 ), 2 , 1 );
5098
+ #if HAVE_PQESCAPE_CONN
5099
+ new_len = PQescapeStringConn (pg_link , escaped , tmp_name2 , strlen (tmp_name2 ), NULL );
5100
+ #else
5101
+ new_len = PQescapeString (escaped , tmp_name2 , strlen (tmp_name2 ));
5102
+ #endif
5103
+ smart_str_appends (& querystr , escaped );
5104
+ efree (escaped );
5105
+
5045
5106
smart_str_appends (& querystr , "' AND c.relnamespace = n.oid AND n.nspname = '" );
5046
- tmp_name = php_addslashes (tmp_name , strlen (tmp_name ), & new_len , 0 TSRMLS_CC );
5047
- smart_str_appendl (& querystr , tmp_name , new_len );
5107
+ escaped = (char * )safe_emalloc (strlen (tmp_name ), 2 , 1 );
5108
+ #if HAVE_PQESCAPE_CONN
5109
+ new_len = PQescapeStringConn (pg_link , escaped , tmp_name , strlen (tmp_name ), NULL );
5110
+ #else
5111
+ new_len = PQescapeString (escaped , tmp_name , strlen (tmp_name ));
5112
+ #endif
5113
+ smart_str_appends (& querystr , escaped );
5114
+ efree (escaped );
5048
5115
5049
5116
smart_str_appends (& querystr , "' AND a.atttypid = t.oid ORDER BY a.attnum;" );
5050
5117
smart_str_0 (& querystr );
5051
-
5052
- efree (tmp_name2 );
5053
- efree (tmp_name );
5054
- efree (src );
5055
-
5118
+ efree (src );
5119
+
5056
5120
pg_result = PQexec (pg_link , querystr .c );
5057
5121
if (PQresultStatus (pg_result ) != PGRES_TUPLES_OK || (num_rows = PQntuples (pg_result )) == 0 ) {
5058
5122
php_error_docref (NULL TSRMLS_CC , E_WARNING , "Table '%s' doesn't exists" , table_name );
@@ -5275,6 +5339,7 @@ static int php_pgsql_add_quotes(zval *src, zend_bool should_free TSRMLS_DC)
5275
5339
assert (Z_TYPE_P (src ) == IS_STRING );
5276
5340
assert (should_free == 1 || should_free == 0 );
5277
5341
5342
+ smart_str_appendc (& str , 'E' );
5278
5343
smart_str_appendc (& str , '\'' );
5279
5344
smart_str_appendl (& str , Z_STRVAL_P (src ), Z_STRLEN_P (src ));
5280
5345
smart_str_appendc (& str , '\'' );
@@ -5315,7 +5380,7 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con
5315
5380
uint field_len = -1 ;
5316
5381
ulong num_idx = -1 ;
5317
5382
zval * meta , * * def , * * type , * * not_null , * * has_default , * * is_enum , * * val , * new_val ;
5318
- int new_len , key_type , err = 0 , skip_field ;
5383
+ int key_type , err = 0 , skip_field ;
5319
5384
php_pgsql_data_type data_type ;
5320
5385
5321
5386
assert (pg_link != NULL );
@@ -5328,6 +5393,8 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con
5328
5393
}
5329
5394
MAKE_STD_ZVAL (meta );
5330
5395
array_init (meta );
5396
+
5397
+ /* table_name is escaped by php_pgsql_meta_data */
5331
5398
if (php_pgsql_meta_data (pg_link , table_name , meta TSRMLS_CC ) == FAILURE ) {
5332
5399
zval_dtor (meta );
5333
5400
FREE_ZVAL (meta );
@@ -5540,15 +5607,15 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con
5540
5607
}
5541
5608
else {
5542
5609
Z_TYPE_P (new_val ) = IS_STRING ;
5543
- #if HAVE_PQESCAPE
5610
+ #if HAVE_PQESCAPE_CONN
5544
5611
{
5545
5612
char * tmp ;
5546
- tmp = (char * )safe_emalloc (Z_STRLEN_PP (val ), 2 , 1 );
5547
- Z_STRLEN_P (new_val ) = (int )PQescapeString ( tmp , Z_STRVAL_PP (val ), Z_STRLEN_PP (val ));
5613
+ tmp = (char * )safe_emalloc (Z_STRLEN_PP (val ), 2 , 1 );
5614
+ Z_STRLEN_P (new_val ) = (int )PQescapeStringConn ( pg_link , tmp , Z_STRVAL_PP (val ), Z_STRLEN_PP (val ), NULL );
5548
5615
Z_STRVAL_P (new_val ) = tmp ;
5549
5616
}
5550
5617
#else
5551
- Z_STRVAL_P (new_val ) = php_addslashes (Z_STRVAL_PP (val ), Z_STRLEN_PP (val ), & Z_STRLEN_P (new_val ), 0 TSRMLS_CC );
5618
+ Z_STRVAL_P (new_val ) = ( int ) PQescapeString (Z_STRVAL_PP (val ), Z_STRLEN_PP (val ), & Z_STRLEN_P (new_val ), 0 TSRMLS_CC );
5552
5619
#endif
5553
5620
php_pgsql_add_quotes (new_val , 1 TSRMLS_CC );
5554
5621
}
@@ -5834,6 +5901,7 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con
5834
5901
else {
5835
5902
unsigned char * tmp ;
5836
5903
size_t to_len ;
5904
+ smart_str s = {0 };
5837
5905
#ifdef HAVE_PQESCAPE_BYTEA_CONN
5838
5906
tmp = PQescapeByteaConn (pg_link , Z_STRVAL_PP (val ), Z_STRLEN_PP (val ), & to_len );
5839
5907
#else
@@ -5845,7 +5913,11 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con
5845
5913
memcpy (Z_STRVAL_P (new_val ), tmp , to_len );
5846
5914
PQfreemem (tmp );
5847
5915
php_pgsql_add_quotes (new_val , 1 TSRMLS_CC );
5848
-
5916
+ smart_str_appendl (& s , Z_STRVAL_P (new_val ), Z_STRLEN_P (new_val ));
5917
+ smart_str_0 (& s );
5918
+ efree (Z_STRVAL_P (new_val ));
5919
+ Z_STRVAL_P (new_val ) = s .c ;
5920
+ Z_STRLEN_P (new_val ) = s .len ;
5849
5921
}
5850
5922
break ;
5851
5923
@@ -5930,11 +6002,22 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con
5930
6002
FREE_ZVAL (new_val );
5931
6003
break ; /* break out for() */
5932
6004
}
6005
+ /* If field is NULL and HAS DEFAULT, should be skipped */
5933
6006
if (!skip_field ) {
5934
- /* If field is NULL and HAS DEFAULT, should be skipped */
5935
- field = php_addslashes (field , strlen (field ), & new_len , 0 TSRMLS_CC );
5936
- add_assoc_zval (result , field , new_val );
5937
- efree (field );
6007
+ char * escaped ;
6008
+ size_t new_len , field_len = strlen (field );
6009
+
6010
+ if (_php_pgsql_detect_identifier_escape (field , field_len ) == SUCCESS ) {
6011
+ escaped = strndup (field , field_len );
6012
+ } else {
6013
+ #if HAVE_PQESCAPELITERAL
6014
+ escaped = PQescapeIdentifier (pg_link , field , field_len );
6015
+ #else
6016
+ escaped = _php_pgsql_escape_identifier (field , field_len );
6017
+ #endif
6018
+ }
6019
+ add_assoc_zval (result , escaped , new_val );
6020
+ free (escaped );
5938
6021
}
5939
6022
} /* for */
5940
6023
zval_dtor (meta );
@@ -6009,6 +6092,45 @@ static int do_exec(smart_str *querystr, int expect, PGconn *pg_link, ulong opt T
6009
6092
return -1 ;
6010
6093
}
6011
6094
6095
+ static inline void build_tablename (smart_str * querystr , PGconn * pg_link , const char * table )
6096
+ {
6097
+ char * table_copy , * escaped , * token , * tmp ;
6098
+ size_t len ;
6099
+
6100
+ /* schame.table should be "schame"."table" */
6101
+ table_copy = estrdup (table );
6102
+ token = php_strtok_r (table_copy , "." , & tmp );
6103
+ len = strlen (token );
6104
+ if (_php_pgsql_detect_identifier_escape (token , len ) == SUCCESS ) {
6105
+ escaped = strndup (token , len );
6106
+ } else {
6107
+ #if HAVE_PQESCAPELITERAL
6108
+ escaped = PQescapeIdentifier (pg_link , token , len );
6109
+ #else
6110
+ escaped = _php_pgsql_escape_identifier (token , len );
6111
+ #endif
6112
+ }
6113
+ smart_str_appends (querystr , escaped );
6114
+ free (escaped );
6115
+ if (tmp && * tmp ) {
6116
+ len = strlen (tmp );
6117
+ /* "schema"."table" format */
6118
+ if (_php_pgsql_detect_identifier_escape (tmp , len ) == SUCCESS ) {
6119
+ escaped = strndup (tmp , len );
6120
+ } else {
6121
+ #if HAVE_PQESCAPELITERAL
6122
+ escaped = PQescapeIdentifier (pg_link , tmp , len );
6123
+ #else
6124
+ escaped = _php_pgsql_escape_identifier (tmp , len );
6125
+ #endif
6126
+ }
6127
+ smart_str_appendc (querystr , '.' );
6128
+ smart_str_appends (querystr , escaped );
6129
+ free (escaped );
6130
+ }
6131
+ efree (table_copy );
6132
+ }
6133
+
6012
6134
/* {{{ php_pgsql_insert
6013
6135
*/
6014
6136
PHP_PGSQL_API int php_pgsql_insert (PGconn * pg_link , const char * table , zval * var_array , ulong opt , char * * sql TSRMLS_DC )
@@ -6028,7 +6150,7 @@ PHP_PGSQL_API int php_pgsql_insert(PGconn *pg_link, const char *table, zval *var
6028
6150
6029
6151
if (zend_hash_num_elements (Z_ARRVAL_P (var_array )) == 0 ) {
6030
6152
smart_str_appends (& querystr , "INSERT INTO " );
6031
- smart_str_appends (& querystr , table );
6153
+ build_tablename (& querystr , pg_link , table );
6032
6154
smart_str_appends (& querystr , " DEFAULT VALUES" );
6033
6155
6034
6156
goto no_values ;
@@ -6043,11 +6165,11 @@ PHP_PGSQL_API int php_pgsql_insert(PGconn *pg_link, const char *table, zval *var
6043
6165
}
6044
6166
var_array = converted ;
6045
6167
}
6046
-
6168
+
6047
6169
smart_str_appends (& querystr , "INSERT INTO " );
6048
- smart_str_appends (& querystr , table );
6170
+ build_tablename (& querystr , pg_link , table );
6049
6171
smart_str_appends (& querystr , " (" );
6050
-
6172
+
6051
6173
zend_hash_internal_pointer_reset_ex (Z_ARRVAL_P (var_array ), & pos );
6052
6174
while ((key_type = zend_hash_get_current_key_ex (Z_ARRVAL_P (var_array ), & fld ,
6053
6175
& fld_len , & num_idx , 0 , & pos )) != HASH_KEY_NON_EXISTENT ) {
@@ -6234,7 +6356,7 @@ PHP_PGSQL_API int php_pgsql_update(PGconn *pg_link, const char *table, zval *var
6234
6356
}
6235
6357
6236
6358
smart_str_appends (& querystr , "UPDATE " );
6237
- smart_str_appends (& querystr , table );
6359
+ build_tablename (& querystr , pg_link , table );
6238
6360
smart_str_appends (& querystr , " SET " );
6239
6361
6240
6362
if (build_assignment_string (& querystr , Z_ARRVAL_P (var_array ), 0 , "," , 1 TSRMLS_CC ))
@@ -6335,7 +6457,7 @@ PHP_PGSQL_API int php_pgsql_delete(PGconn *pg_link, const char *table, zval *ids
6335
6457
}
6336
6458
6337
6459
smart_str_appends (& querystr , "DELETE FROM " );
6338
- smart_str_appends (& querystr , table );
6460
+ build_tablename (& querystr , pg_link , table );
6339
6461
smart_str_appends (& querystr , " WHERE " );
6340
6462
6341
6463
if (build_assignment_string (& querystr , Z_ARRVAL_P (ids_array ), 1 , " AND " , sizeof (" AND " )- 1 TSRMLS_CC ))
@@ -6471,7 +6593,7 @@ PHP_PGSQL_API int php_pgsql_select(PGconn *pg_link, const char *table, zval *ids
6471
6593
}
6472
6594
6473
6595
smart_str_appends (& querystr , "SELECT * FROM " );
6474
- smart_str_appends (& querystr , table );
6596
+ build_tablename (& querystr , pg_link , table );
6475
6597
smart_str_appends (& querystr , " WHERE " );
6476
6598
6477
6599
if (build_assignment_string (& querystr , Z_ARRVAL_P (ids_array ), 1 , " AND " , sizeof (" AND " )- 1 TSRMLS_CC ))
0 commit comments