Skip to content

Commit 1cc913b

Browse files
committed
Merge branch 'PHP-8.4'
* PHP-8.4: PDO_MYSQL: Properly quote binary strings Reproduce unexpected MySQL warnings for binary values
2 parents a8f5442 + cba92be commit 1cc913b

File tree

3 files changed

+96
-9
lines changed

3 files changed

+96
-9
lines changed

ext/pdo_mysql/mysql_driver.c

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -309,23 +309,29 @@ static zend_string* mysql_handle_quoter(pdo_dbh_t *dbh, const zend_string *unquo
309309
{
310310
pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
311311
bool use_national_character_set = 0;
312+
bool use_binary = 0;
312313
size_t quotedlen;
313314

314-
if (H->assume_national_character_set_strings) {
315-
use_national_character_set = 1;
316-
}
317-
if ((paramtype & PDO_PARAM_STR_NATL) == PDO_PARAM_STR_NATL) {
318-
use_national_character_set = 1;
319-
}
320-
if ((paramtype & PDO_PARAM_STR_CHAR) == PDO_PARAM_STR_CHAR) {
321-
use_national_character_set = 0;
315+
if ((paramtype & PDO_PARAM_LOB) == PDO_PARAM_LOB) {
316+
use_binary = 1;
317+
} else {
318+
if (H->assume_national_character_set_strings) {
319+
use_national_character_set = 1;
320+
}
321+
if ((paramtype & PDO_PARAM_STR_NATL) == PDO_PARAM_STR_NATL) {
322+
use_national_character_set = 1;
323+
}
324+
if ((paramtype & PDO_PARAM_STR_CHAR) == PDO_PARAM_STR_CHAR) {
325+
use_national_character_set = 0;
326+
}
322327
}
323328

324329
PDO_DBG_ENTER("mysql_handle_quoter");
325330
PDO_DBG_INF_FMT("dbh=%p", dbh);
326331
PDO_DBG_INF_FMT("unquoted=%.*s", (int)ZSTR_LEN(unquoted), ZSTR_VAL(unquoted));
327332

328-
zend_string *quoted_str = zend_string_safe_alloc(2, ZSTR_LEN(unquoted), 3 + (use_national_character_set ? 1 : 0), false);
333+
zend_string *quoted_str = zend_string_safe_alloc(2, ZSTR_LEN(unquoted),
334+
3 + (use_national_character_set ? 1 : 0) + (use_binary ? 7 : 0), false);
329335
char *quoted = ZSTR_VAL(quoted_str);
330336

331337
if (use_national_character_set) {
@@ -334,6 +340,11 @@ static zend_string* mysql_handle_quoter(pdo_dbh_t *dbh, const zend_string *unquo
334340
quoted[1] = '\'';
335341

336342
++quotedlen; /* N prefix */
343+
} else if (use_binary) {
344+
quotedlen = mysql_real_escape_string_quote(H->server, quoted + 8, ZSTR_VAL(unquoted), ZSTR_LEN(unquoted), '\'');
345+
memcpy(quoted, "_binary'", 8);
346+
347+
quotedlen += 7; /* _binary prefix */
337348
} else {
338349
quotedlen = mysql_real_escape_string_quote(H->server, quoted + 1, ZSTR_VAL(unquoted), ZSTR_LEN(unquoted), '\'');
339350
quoted[0] = '\'';
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
--TEST--
2+
MySQL PDO->prepare(), no warnings should be raised for binary values using emulated PS
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_EMULATE_PREPARES, true);
15+
16+
// Force the connection to utf8, which is enough to make the test fail
17+
// MySQL 5.6+ would be required for utf8mb4
18+
$db->exec("SET NAMES 'utf8'");
19+
20+
$content = '0191D886E6DC73E7AF1FEE7F99EC6235';
21+
22+
$statement = $db->prepare('SELECT HEX(?) as test');
23+
$statement->bindValue(1, hex2bin($content), PDO::PARAM_LOB);
24+
$statement->execute();
25+
26+
var_dump($statement->fetchAll(PDO::FETCH_ASSOC)[0]['test'] === $content);
27+
var_dump($db->query('SHOW WARNINGS')->fetchAll(PDO::FETCH_ASSOC));
28+
29+
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
30+
31+
$statement2 = $db->prepare('SELECT HEX(?) as test');
32+
$statement2->bindValue(1, hex2bin($content), PDO::PARAM_LOB);
33+
$statement2->execute();
34+
35+
var_dump($statement2->fetchAll(PDO::FETCH_ASSOC)[0]['test'] === $content);
36+
37+
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); // SHOW WARNINGS can only be used when PDO::ATTR_EMULATE_PREPARES=true
38+
var_dump($db->query('SHOW WARNINGS')->fetchAll(PDO::FETCH_ASSOC));
39+
print "done!";
40+
?>
41+
--EXPECTF--
42+
bool(true)
43+
array(0) {
44+
}
45+
bool(true)
46+
array(0) {
47+
}
48+
done!
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
MySQL PDO->quote(), properly handle binary data
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_EMULATE_PREPARES, true);
15+
16+
// Force the connection to utf8, which is enough to make the test fail
17+
// MySQL 5.6+ would be required for utf8mb4
18+
$db->exec("SET NAMES 'utf8'");
19+
20+
$content = "\xC3\xA1\xC3";
21+
$quoted = $db->quote($content, PDO::PARAM_LOB);
22+
23+
var_dump($quoted);
24+
var_dump($db->query("SELECT HEX({$quoted})")->fetch(PDO::FETCH_NUM)[0]);
25+
?>
26+
--EXPECTF--
27+
string(%d) "_binary'%s'"
28+
string(6) "C3A1C3"

0 commit comments

Comments
 (0)