Skip to content

Commit 32fb9b6

Browse files
committed
Validate string is numeric for integer PDO attribute value
1 parent e0aab74 commit 32fb9b6

File tree

5 files changed

+43
-19
lines changed

5 files changed

+43
-19
lines changed

ext/pdo/pdo_dbh.c

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -678,12 +678,24 @@ PHP_METHOD(PDO, inTransaction)
678678
}
679679
/* }}} */
680680

681-
/* TODO: Make distinction between numeric and non-numeric strings */
682-
#define PDO_LONG_PARAM_CHECK \
683-
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) { \
684-
zend_type_error("Attribute value must be of type int for selected attribute, %s given", zend_zval_type_name(value)); \
685-
return false; \
686-
} \
681+
PDO_API bool pdo_get_long_param(zend_long *lval, zval *value)
682+
{
683+
switch (Z_TYPE_P(value)) {
684+
case IS_LONG:
685+
case IS_TRUE:
686+
case IS_FALSE:
687+
*lval = zval_get_long(value);
688+
return true;
689+
case IS_STRING:
690+
if (IS_LONG == is_numeric_str_function(Z_STR_P(value), lval, NULL)) {
691+
return true;
692+
}
693+
/* fallthrough */
694+
default:
695+
zend_type_error("Attribute value must be of type int for selected attribute, %s given", zend_zval_type_name(value));
696+
return false;
697+
}
698+
}
687699

688700
/* Return false on failure, true otherwise */
689701
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) /
692704

693705
switch (attr) {
694706
case PDO_ATTR_ERRMODE:
695-
PDO_LONG_PARAM_CHECK;
696-
lval = zval_get_long(value);
707+
if (!pdo_get_long_param(&lval, value)) {
708+
return false;
709+
}
697710
switch (lval) {
698711
case PDO_ERRMODE_SILENT:
699712
case PDO_ERRMODE_WARNING:
@@ -707,8 +720,9 @@ static bool pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) /
707720
return false;
708721

709722
case PDO_ATTR_CASE:
710-
PDO_LONG_PARAM_CHECK;
711-
lval = zval_get_long(value);
723+
if (!pdo_get_long_param(&lval, value)) {
724+
return false;
725+
}
712726
switch (lval) {
713727
case PDO_CASE_NATURAL:
714728
case PDO_CASE_UPPER:
@@ -722,8 +736,10 @@ static bool pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) /
722736
return false;
723737

724738
case PDO_ATTR_ORACLE_NULLS:
725-
PDO_LONG_PARAM_CHECK;
726-
dbh->oracle_nulls = zval_get_long(value);
739+
if (!pdo_get_long_param(&lval, value)) {
740+
return false;
741+
}
742+
dbh->oracle_nulls = lval;
727743
return true;
728744

729745
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) /
735751
return false;
736752
}
737753
}
754+
lval = zval_get_long(value);
738755
} else {
739-
PDO_LONG_PARAM_CHECK;
756+
if (!pdo_get_long_param(&lval, value)) {
757+
return false;
758+
}
740759
}
741-
lval = zval_get_long(value);
742760
if (lval == PDO_FETCH_USE_DEFAULT) {
743761
zend_value_error("Fetch mode must be a bitmask of PDO::FETCH_* constants");
744762
return false;
@@ -747,8 +765,11 @@ static bool pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) /
747765
return true;
748766

749767
case PDO_ATTR_STRINGIFY_FETCHES:
750-
PDO_LONG_PARAM_CHECK;
751-
dbh->stringify = zval_get_long(value) ? 1 : 0;
768+
if (pdo_get_long_param(&lval, value) == false) {
769+
return false;
770+
}
771+
/* TODO Check for proper boolean value? */
772+
dbh->stringify = lval ? 1 : 0;
752773
return true;
753774

754775
case PDO_ATTR_STATEMENT_CLASS: {

ext/pdo/php_pdo_driver.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,5 +681,8 @@ PDO_API void php_pdo_dbh_delref(pdo_dbh_t *dbh);
681681
PDO_API void php_pdo_free_statement(pdo_stmt_t *stmt);
682682
PDO_API void php_pdo_stmt_set_column_count(pdo_stmt_t *stmt, int new_count);
683683

684+
/* Normalization for fetching long param for driver attributes */
685+
PDO_API bool pdo_get_long_param(zend_long *lval, zval *value);
686+
684687
PDO_API void pdo_throw_exception(unsigned int driver_errcode, char *driver_errmsg, pdo_error_type *pdo_error);
685688
#endif /* PHP_PDO_DRIVER_H */

ext/pdo/tests/bug_44159.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,4 @@ TypeError: PDO::ATTR_STATEMENT_CLASS value must be of type array, int given
4444
TypeError: PDO::ATTR_STATEMENT_CLASS value must be of type array, string given
4545
TypeError: Attribute value must be of type int for selected attribute, null given
4646
bool(true)
47-
bool(true)
47+
TypeError: Attribute value must be of type int for selected attribute, string given

ext/pdo_mysql/tests/pdo_mysql_attr_errmode.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ error_reporting=E_ALL
2525
echo get_class($e), ': ', $e->getMessage(), \PHP_EOL;
2626
}
2727
try {
28-
/* This currently passes */
2928
$db->setAttribute(PDO::ATTR_ERRMODE, 'pdo');
3029
} catch (\Error $e) {
3130
echo get_class($e), ': ', $e->getMessage(), \PHP_EOL;
@@ -160,6 +159,7 @@ error_reporting=E_ALL
160159
--EXPECTF--
161160
TypeError: Attribute value must be of type int for selected attribute, array given
162161
TypeError: Attribute value must be of type int for selected attribute, stdClass given
162+
TypeError: Attribute value must be of type int for selected attribute, string given
163163
ValueError: Error mode must be one of the PDO::ERRMODE_* constants
164164

165165
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

ext/pdo_mysql/tests/pdo_mysql_attr_oracle_nulls.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ MySQLPDOTest::skip();
2323
echo $e->getMessage(), \PHP_EOL;
2424
}
2525
try {
26-
/* Currently passes... */
2726
$db->setAttribute(PDO::ATTR_ORACLE_NULLS, 'pdo');
2827
} catch (\TypeError $e) {
2928
echo $e->getMessage(), \PHP_EOL;
@@ -72,6 +71,7 @@ MySQLPDOTest::skip();
7271
--EXPECTF--
7372
Attribute value must be of type int for selected attribute, array given
7473
Attribute value must be of type int for selected attribute, stdClass given
74+
Attribute value must be of type int for selected attribute, string given
7575
array(1) {
7676
[0]=>
7777
array(6) {

0 commit comments

Comments
 (0)