Skip to content

Commit f8a5f2e

Browse files
committed
Fixed to generate an error when a non-scalar value is passed in
`PDO_PARAM_EVT_EXEC_PRE` of `pdo_mysql_stmt_param_hook` unless it is a `Stringable` object.
1 parent b558a18 commit f8a5f2e

File tree

2 files changed

+84
-0
lines changed

2 files changed

+84
-0
lines changed

ext/pdo_mysql/mysql_statement.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "pdo/php_pdo_driver.h"
2828
#include "php_pdo_mysql.h"
2929
#include "php_pdo_mysql_int.h"
30+
#include "zend_interfaces.h"
3031

3132
#ifdef PDO_USE_MYSQLND
3233
# define pdo_mysql_stmt_execute_prepared(stmt) pdo_mysql_stmt_execute_prepared_mysqlnd(stmt)
@@ -490,7 +491,14 @@ static int pdo_mysql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_da
490491
case IS_DOUBLE:
491492
mysqlnd_stmt_bind_one_param(S->stmt, param->paramno, parameter, MYSQL_TYPE_DOUBLE);
492493
break;
494+
case IS_OBJECT:
495+
if(zend_class_implements_interface(Z_OBJCE_P(parameter), zend_ce_stringable)) {
496+
mysqlnd_stmt_bind_one_param(S->stmt, param->paramno, parameter, MYSQL_TYPE_VAR_STRING);
497+
break;
498+
}
499+
ZEND_FALLTHROUGH;
493500
default:
501+
pdo_raise_impl_error(stmt->dbh, stmt, "HY105", "Expected a scalar value or null");
494502
PDO_DBG_RETURN(0);
495503
}
496504

@@ -530,7 +538,19 @@ static int pdo_mysql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_da
530538
b->buffer = &Z_DVAL_P(parameter);
531539
PDO_DBG_RETURN(1);
532540

541+
case IS_OBJECT:
542+
if(zend_class_implements_interface(Z_OBJCE_P(parameter), zend_ce_stringable)) {
543+
convert_to_string(parameter);
544+
b->buffer_type = MYSQL_TYPE_STRING;
545+
b->buffer = Z_STRVAL_P(parameter);
546+
b->buffer_length = Z_STRLEN_P(parameter);
547+
*b->length = Z_STRLEN_P(parameter);
548+
PDO_DBG_RETURN(1);
549+
}
550+
ZEND_FALLTHROUGH;
551+
533552
default:
553+
pdo_raise_impl_error(stmt->dbh, stmt, "HY105", "Expected a scalar value or null");
534554
PDO_DBG_RETURN(0);
535555
}
536556
#endif /* PDO_USE_MYSQLND */

ext/pdo_mysql/tests/gh13384.phpt

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
--TEST--
2+
GH-13384 Fixed GH-13167 Fixed the behavior when an inappropriate value was passed to `bindValue` and `bindParam`.
3+
--EXTENSIONS--
4+
pdo_mysql
5+
--SKIPIF--
6+
<?php
7+
require_once __DIR__ . '/inc/mysql_pdo_test.inc';
8+
MySQLPDOTest::skip();
9+
?>
10+
--FILE--
11+
<?php
12+
require_once __DIR__ . '/inc/mysql_pdo_test.inc';
13+
$db = MySQLPDOTest::factory();
14+
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
15+
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
16+
17+
$stringableObject = new class () implements Stringable {
18+
public function __toString(): string
19+
{
20+
return '555';
21+
}
22+
};
23+
24+
echo "Stringable object, bindValue:\n";
25+
$stmt = $db->prepare('SELECT (?)');
26+
$stmt->bindValue(1, $stringableObject, PDO::PARAM_INT);
27+
$stmt->execute();
28+
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
29+
echo "\n";
30+
31+
echo "Normal object, bindValue:\n";
32+
try {
33+
$stmt = $db->prepare('SELECT (?)');
34+
$stmt->bindValue(1, new stdClass(), PDO::PARAM_INT);
35+
$stmt->execute();
36+
} catch (Throwable $e) {
37+
echo $e->getMessage()."\n\n";
38+
}
39+
40+
echo "Array, bindParam:\n";
41+
try {
42+
$stmt = $db->prepare('SELECT (?)');
43+
$param = ['aaa'];
44+
$stmt->bindParam(1, $param, PDO::PARAM_INT);
45+
$stmt->execute();
46+
} catch (Throwable $e) {
47+
echo $e->getMessage();
48+
}
49+
?>
50+
--EXPECT--
51+
Stringable object, bindValue:
52+
array(1) {
53+
[0]=>
54+
array(1) {
55+
["?"]=>
56+
string(3) "555"
57+
}
58+
}
59+
60+
Normal object, bindValue:
61+
SQLSTATE[HY105]: Invalid parameter type: Expected a scalar value or null
62+
63+
Array, bindParam:
64+
SQLSTATE[HY105]: Invalid parameter type: Expected a scalar value or null

0 commit comments

Comments
 (0)