Skip to content

Commit cb2ba6d

Browse files
committed
Adapt phpGH-10343 for PARAM_BINARY
Original text: >If the user is specifying a PDO::PARAM_LOB, there's a good chance >that it's a binary file (i.e. an image), that is too fragile to >survive in a string, as escaping it is insufficient. Because >PDO_DBLIB relies on PDO to fill in a parameterized query and >submits the filled string to the server, it ends up mangling the >query. > >This adds logic in the PDO_DBLIB quoter to handle binary parameters >by using the SQL Server binary literal syntax (a hex string that >begins with `0x`). This resolves the issue because PDO consults the >quoter for filling in the query string.
1 parent b0ac91c commit cb2ba6d

File tree

2 files changed

+70
-1
lines changed

2 files changed

+70
-1
lines changed

ext/pdo_dblib/dblib_driver.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ static zend_long dblib_handle_doer(pdo_dbh_t *dbh, const zend_string *sql)
145145
static zend_string* dblib_handle_quoter(pdo_dbh_t *dbh, const zend_string *unquoted, enum pdo_param_type paramtype)
146146
{
147147
pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data;
148-
bool use_national_character_set = 0;
148+
bool use_national_character_set = 0, is_binary = false;
149149
size_t i;
150150
char *q;
151151
size_t quotedlen = 0;
@@ -160,6 +160,29 @@ static zend_string* dblib_handle_quoter(pdo_dbh_t *dbh, const zend_string *unquo
160160
if ((paramtype & PDO_PARAM_STR_CHAR) == PDO_PARAM_STR_CHAR) {
161161
use_national_character_set = 0;
162162
}
163+
/*
164+
* A user could be passing a binary (i.e. an image file) in a query.
165+
* It's fragile trying to escape it as a string, so encode it as a
166+
* binary literal instead.
167+
*/
168+
if (paramtype == PDO_PARAM_BINARY) {
169+
is_binary = true;
170+
}
171+
172+
if (is_binary) {
173+
/* 1 char = 2 chars in hex, plus 0x */
174+
quotedlen = ZSTR_LEN(unquoted) * 2; /* XXX: Overflow? */
175+
quotedlen += 2;
176+
177+
quoted_str = zend_string_alloc(quotedlen, 0);
178+
q = ZSTR_VAL(quoted_str);
179+
*q++ = '0';
180+
*q++ = 'x';
181+
for (i = 0; i < ZSTR_LEN(unquoted); i++) {
182+
q += sprintf(q, "%02X", (unsigned char)ZSTR_VAL(unquoted)[i]);
183+
}
184+
return quoted_str;
185+
}
163186

164187
/* Detect quoted length, adding extra char for doubled single quotes */
165188
for (i = 0; i < ZSTR_LEN(unquoted); i++) {
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
--TEST--
2+
PDO_DBLIB: Ensure binary bound parameter is a binary literal
3+
--EXTENSIONS--
4+
pdo_dblib
5+
--SKIPIF--
6+
<?php
7+
require __DIR__ . '/config.inc';
8+
?>
9+
--FILE--
10+
<?php
11+
require __DIR__ . '/config.inc';
12+
13+
// This is a one pixel PNG of rgba(0, 0, 0, 255)
14+
$binary = base64_decode("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2NgYGD4DwABBAEAwS2OUAAAAABJRU5ErkJggg==");
15+
$query =
16+
"SELECT ?";
17+
// "create table #php_pdo(value varbinary(max));" .
18+
// "insert into #php_pdo values ?;" .
19+
// "drop table #php_pdo;";
20+
21+
$db = new PDO($dsn, $user, $pass);
22+
23+
$stmt = $db->prepare($query);
24+
// PARAM_LOB gets converted to a binary literal instead of a string literal
25+
$stmt->bindParam(1, $binary, PDO::PARAM_BINARY);
26+
$result = $stmt->execute();
27+
28+
// Verify we sent the binary literal over the wire
29+
var_dump($stmt->debugDumpParams());
30+
31+
// Verify that we get the same PNG back over the wire
32+
$rows = $stmt->fetchAll();
33+
var_dump(base64_encode($rows[0][0]));
34+
35+
?>
36+
--EXPECT--
37+
SQL: [8] SELECT ?
38+
Sent SQL: [149] SELECT 0x89504E470D0A1A0A0000000D49484452000000010000000108060000001F15C4890000000D49444154085B63606060F80F0001040100C12D8E500000000049454E44AE426082
39+
Params: 1
40+
Key: Position #0:
41+
paramno=0
42+
name=[0] ""
43+
is_param=1
44+
param_type=3
45+
NULL
46+
string(96) "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2NgYGD4DwABBAEAwS2OUAAAAABJRU5ErkJggg=="

0 commit comments

Comments
 (0)