Skip to content

Commit 484448a

Browse files
committed
Implement mysqli::quote_string method
1 parent ed88724 commit 484448a

File tree

5 files changed

+124
-1
lines changed

5 files changed

+124
-1
lines changed

ext/mysqli/mysqli.stub.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -906,6 +906,11 @@ public function real_connect(
906906
*/
907907
public function real_escape_string(string $string): string {}
908908

909+
/**
910+
* @alias mysqli_quote_string
911+
*/
912+
public function quote_string(string $string): string {}
913+
909914
/**
910915
* @tentative-return-type
911916
* @alias mysqli_reap_async_query
@@ -1547,6 +1552,8 @@ function mysqli_real_escape_string(mysqli $mysql, string $string): string {}
15471552
/** @alias mysqli_real_escape_string */
15481553
function mysqli_escape_string(mysqli $mysql, string $string): string {}
15491554

1555+
function mysqli_quote_string(mysqli $mysql, string $string): string {}
1556+
15501557
function mysqli_real_query(mysqli $mysql, string $query): bool {}
15511558

15521559
/** @refcount 1 */

ext/mysqli/mysqli_api.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1363,6 +1363,29 @@ PHP_FUNCTION(mysqli_real_escape_string) {
13631363
RETURN_NEW_STR(newstr);
13641364
}
13651365

1366+
PHP_FUNCTION(mysqli_quote_string) {
1367+
MY_MYSQL *mysql;
1368+
zval *mysql_link = NULL;
1369+
char *escapestr;
1370+
size_t escapestr_len;
1371+
zend_string *newstr;
1372+
1373+
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_link, mysqli_link_class_entry, &escapestr, &escapestr_len) == FAILURE) {
1374+
RETURN_THROWS();
1375+
}
1376+
MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1377+
1378+
newstr = zend_string_safe_alloc(2, escapestr_len+1, 0, 0);
1379+
ZSTR_VAL(newstr)[0] = '\'';
1380+
ZSTR_LEN(newstr) = 1 + mysql_real_escape_string(mysql->mysql, ZSTR_VAL(newstr) + 1, escapestr, escapestr_len);
1381+
ZSTR_VAL(newstr)[ZSTR_LEN(newstr)] = '\'';
1382+
ZSTR_LEN(newstr) += 1;
1383+
ZSTR_VAL(newstr)[ZSTR_LEN(newstr)] = '\0';
1384+
newstr = zend_string_truncate(newstr, ZSTR_LEN(newstr), 0);
1385+
1386+
RETURN_NEW_STR(newstr);
1387+
}
1388+
13661389
/* {{{ Undo actions from current transaction */
13671390
PHP_FUNCTION(mysqli_rollback)
13681391
{

ext/mysqli/mysqli_arginfo.h

Lines changed: 10 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/mysqli/tests/mysqli_class_mysqli_interface.phpt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ require_once 'skipifconnectfailure.inc';
4343
'ping' => true,
4444
'prepare' => true,
4545
'query' => true,
46+
'quote_string' => true,
4647
'real_connect' => true,
4748
'real_escape_string' => true,
4849
'real_query' => true,
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
--TEST--
2+
mysqli_quote_string()
3+
--EXTENSIONS--
4+
mysqli
5+
--SKIPIF--
6+
<?php
7+
require_once 'skipifconnectfailure.inc';
8+
?>
9+
--FILE--
10+
<?php
11+
12+
require_once 'connect.inc';
13+
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
14+
$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket);
15+
16+
echo mysqli_quote_string($link, '\\') . "\n";
17+
echo mysqli_quote_string($link, '"') . "\n";
18+
echo mysqli_quote_string($link, "'") . "\n";
19+
20+
$escaped = mysqli_quote_string($link, "\' \ \"");
21+
echo $escaped . "\n";
22+
$result = $link->query("SELECT $escaped AS test");
23+
$value = $result->fetch_column();
24+
echo $value . "\n";
25+
26+
$escaped = mysqli_quote_string($link, '" OR 1=1 -- foo');
27+
echo $escaped . "\n";
28+
$result = $link->query("SELECT $escaped AS test");
29+
$value = $result->fetch_column();
30+
echo $value . "\n";
31+
32+
$escaped = mysqli_quote_string($link, "\n");
33+
if ($escaped !== "'\\n'") {
34+
printf("[001] Expected '\\n', got %s\n", $escaped);
35+
}
36+
37+
$escaped = mysqli_quote_string($link, "\r");
38+
if ($escaped !== "'\\r'") {
39+
printf("[002] Expected '\\r', got %s\n", $escaped);
40+
}
41+
42+
$escaped = mysqli_quote_string($link, "foo" . chr(0) . "bar");
43+
if ($escaped !== "'foo\\0bar'") {
44+
printf("[003] Expected 'foo\\0bar', got %s\n", $escaped);
45+
}
46+
47+
// Test that the SQL injection is impossible with NO_BACKSLASH_ESCAPES mode
48+
$link->query('SET @@sql_mode="NO_BACKSLASH_ESCAPES"');
49+
50+
echo $link->quote_string('\\') . "\n";
51+
echo $link->quote_string('"') . "\n";
52+
echo $link->quote_string("'") . "\n";
53+
54+
$escaped = $link->quote_string("\' \ \"");
55+
echo $escaped . "\n";
56+
$result = $link->query("SELECT $escaped AS test");
57+
$value = $result->fetch_column();
58+
echo $value . "\n";
59+
60+
$escaped = $link->quote_string('" OR 1=1 -- foo');
61+
echo $escaped . "\n";
62+
$result = $link->query("SELECT $escaped AS test");
63+
$value = $result->fetch_column();
64+
echo $value . "\n";
65+
66+
echo "done!";
67+
?>
68+
--EXPECT--
69+
'\\'
70+
'\"'
71+
'\''
72+
'\\\' \\ \"'
73+
\' \ "
74+
'\" OR 1=1 -- foo'
75+
" OR 1=1 -- foo
76+
'\'
77+
'"'
78+
''''
79+
'\'' \ "'
80+
\' \ "
81+
'" OR 1=1 -- foo'
82+
" OR 1=1 -- foo
83+
done!

0 commit comments

Comments
 (0)