]> granicus.if.org Git - php/commitdiff
Validate string is numeric for integer PDO attribute value
authorGeorge Peter Banyard <girgias@php.net>
Fri, 12 Mar 2021 20:41:15 +0000 (20:41 +0000)
committerGeorge Peter Banyard <girgias@php.net>
Wed, 17 Mar 2021 00:58:00 +0000 (00:58 +0000)
ext/pdo/pdo_dbh.c
ext/pdo/php_pdo_driver.h
ext/pdo/tests/bug_44159.phpt
ext/pdo_mysql/tests/pdo_mysql_attr_errmode.phpt
ext/pdo_mysql/tests/pdo_mysql_attr_oracle_nulls.phpt

index 41ac1e260e878fd40d280ddad8d6369b449a81a3..60b6ebcf3ff19dec9ca03c6c161b114a35a5fdac 100644 (file)
@@ -678,12 +678,24 @@ PHP_METHOD(PDO, inTransaction)
 }
 /* }}} */
 
-/* TODO: Make distinction between numeric and non-numeric strings */
-#define PDO_LONG_PARAM_CHECK \
-       if (Z_TYPE_P(value) != IS_LONG && Z_TYPE_P(value) != IS_STRING && Z_TYPE_P(value) != IS_FALSE && Z_TYPE_P(value) != IS_TRUE) { \
-               zend_type_error("Attribute value must be of type int for selected attribute, %s given", zend_zval_type_name(value)); \
-               return false; \
-       } \
+PDO_API bool pdo_get_long_param(zend_long *lval, zval *value)
+{
+       switch (Z_TYPE_P(value)) {
+               case IS_LONG:
+               case IS_TRUE:
+               case IS_FALSE:
+                       *lval = zval_get_long(value);
+                       return true;
+               case IS_STRING:
+                       if (IS_LONG == is_numeric_str_function(Z_STR_P(value), lval, NULL)) {
+                               return true;
+                       }
+                       /* fallthrough */
+               default:
+                       zend_type_error("Attribute value must be of type int for selected attribute, %s given", zend_zval_type_name(value));
+                       return false;
+       }
+}
 
 /* Return false on failure, true otherwise */
 static bool pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) /* {{{ */
@@ -692,8 +704,9 @@ static bool pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) /
 
        switch (attr) {
                case PDO_ATTR_ERRMODE:
-                       PDO_LONG_PARAM_CHECK;
-                       lval = zval_get_long(value);
+                       if (!pdo_get_long_param(&lval, value)) {
+                               return false;
+                       }
                        switch (lval) {
                                case PDO_ERRMODE_SILENT:
                                case PDO_ERRMODE_WARNING:
@@ -707,8 +720,9 @@ static bool pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) /
                        return false;
 
                case PDO_ATTR_CASE:
-                       PDO_LONG_PARAM_CHECK;
-                       lval = zval_get_long(value);
+                       if (!pdo_get_long_param(&lval, value)) {
+                               return false;
+                       }
                        switch (lval) {
                                case PDO_CASE_NATURAL:
                                case PDO_CASE_UPPER:
@@ -722,8 +736,10 @@ static bool pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) /
                        return false;
 
                case PDO_ATTR_ORACLE_NULLS:
-                       PDO_LONG_PARAM_CHECK;
-                       dbh->oracle_nulls = zval_get_long(value);
+                       if (!pdo_get_long_param(&lval, value)) {
+                               return false;
+                       }
+                       dbh->oracle_nulls = lval;
                        return true;
 
                case PDO_ATTR_DEFAULT_FETCH_MODE:
@@ -735,10 +751,12 @@ static bool pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) /
                                                return false;
                                        }
                                }
+                               lval = zval_get_long(value);
                        } else {
-                               PDO_LONG_PARAM_CHECK;
+                               if (!pdo_get_long_param(&lval, value)) {
+                                       return false;
+                               }
                        }
-                       lval = zval_get_long(value);
                        if (lval == PDO_FETCH_USE_DEFAULT) {
                                zend_value_error("Fetch mode must be a bitmask of PDO::FETCH_* constants");
                                return false;
@@ -747,8 +765,11 @@ static bool pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) /
                        return true;
 
                case PDO_ATTR_STRINGIFY_FETCHES:
-                       PDO_LONG_PARAM_CHECK;
-                       dbh->stringify = zval_get_long(value) ? 1 : 0;
+                       if (pdo_get_long_param(&lval, value) == false) {
+                               return false;
+                       }
+                       /* TODO Check for proper boolean value? */
+                       dbh->stringify = lval ? 1 : 0;
                        return true;
 
                case PDO_ATTR_STATEMENT_CLASS: {
index 91a71bd8f58a0577cc80bc4e801e938f83124d56..cb73db86d739be6a6dd78af69aa70c499c7744d3 100644 (file)
@@ -681,5 +681,8 @@ PDO_API void php_pdo_dbh_delref(pdo_dbh_t *dbh);
 PDO_API void php_pdo_free_statement(pdo_stmt_t *stmt);
 PDO_API void php_pdo_stmt_set_column_count(pdo_stmt_t *stmt, int new_count);
 
+/* Normalization for fetching long param for driver attributes */
+PDO_API bool pdo_get_long_param(zend_long *lval, zval *value);
+
 PDO_API void pdo_throw_exception(unsigned int driver_errcode, char *driver_errmsg, pdo_error_type *pdo_error);
 #endif /* PHP_PDO_DRIVER_H */
index b5601eed41c47e56bca344c13a00b3e3984da278..4167220efdfe5018edb88636892281f3df5fb958 100644 (file)
@@ -44,4 +44,4 @@ TypeError: PDO::ATTR_STATEMENT_CLASS value must be of type array, int given
 TypeError: PDO::ATTR_STATEMENT_CLASS value must be of type array, string given
 TypeError: Attribute value must be of type int for selected attribute, null given
 bool(true)
-bool(true)
+TypeError: Attribute value must be of type int for selected attribute, string given
index d6ebd87f603275793014d8fb95b5fb99a88b8a42..fc4f2f0808c1439b97e144cda6165041d6e76441 100644 (file)
@@ -25,7 +25,6 @@ error_reporting=E_ALL
         echo get_class($e), ': ', $e->getMessage(), \PHP_EOL;
     }
     try {
-        /* This currently passes */
         $db->setAttribute(PDO::ATTR_ERRMODE, 'pdo');
     } catch (\Error $e) {
         echo get_class($e), ': ', $e->getMessage(), \PHP_EOL;
@@ -160,6 +159,7 @@ error_reporting=E_ALL
 --EXPECTF--
 TypeError: Attribute value must be of type int for selected attribute, array given
 TypeError: Attribute value must be of type int for selected attribute, stdClass given
+TypeError: Attribute value must be of type int for selected attribute, string given
 ValueError: Error mode must be one of the PDO::ERRMODE_* constants
 
 Warning: PDO::query(): SQLSTATE[42000]: Syntax error or access violation: %d You have an error in your SQL syntax; check the manual that corresponds to your %s server version for the right syntax to use near '%s' at line %d in %s on line %d
index d7f54bfdee940a110553b7b7a6ad027147dbe427..78d6ae7879544ef3a24ffa7b2b21cff1382c6f48 100644 (file)
@@ -23,7 +23,6 @@ MySQLPDOTest::skip();
         echo $e->getMessage(), \PHP_EOL;
     }
     try {
-        /* Currently passes... */
         $db->setAttribute(PDO::ATTR_ORACLE_NULLS, 'pdo');
     } catch (\TypeError $e) {
         echo $e->getMessage(), \PHP_EOL;
@@ -72,6 +71,7 @@ MySQLPDOTest::skip();
 --EXPECTF--
 Attribute value must be of type int for selected attribute, array given
 Attribute value must be of type int for selected attribute, stdClass given
+Attribute value must be of type int for selected attribute, string given
 array(1) {
   [0]=>
   array(6) {