Currently, PDO drivers behave inconsistently and unpredictably dealing with binary data. Sometimes, they require special quoting rules, or special binding behaviour, that is currently not possible to do from userland or is very unergonomic to do.
For example:
It's also worth noting that a binary column is *not* inherently a LOB, which some might consider the possible way to map binary values. For example, ODBC has a family of binary string column types, and a distinction between character vs. binary LOB columns. Some drivers (i.e. Postgres) also expect a PDO::PARAM_LOB to be a stream resource.
This RFC proposes either an additional PDO data type *or* a flag for strings and LOBs for representing binary data. This makes the intent clear for programmers, and should force consistent behaviour across drivers.
<?php $sql = "select id, my_blob from calvin.blob_stream"; $dbconn = new PDO("odbc:*LOCAL", "", ""); // Proposal 1: Separate data type $stmt = $dbconn->prepare($sql); $stmt->execute(); $data = ""; $stmt->bindColumn(2, $data, PDO::PARAM_BINARY); $stmt->fetch(PDO::FETCH_BOUND); echo bin2hex($data) . "\n"; // Proposal 2: Flag for PARAM_STRING or PARAM_LOB $stmt = $dbconn->prepare($sql); $stmt->execute(); $data = ""; $stmt->bindColumn(2, $data, PDO::PARAM_STRING | PDO::PARAM_BINARY); $stmt->fetch(PDO::FETCH_BOUND); echo bin2hex($data) . "\n"; ?>
There are two approaches:
A dedicated data type. This would use the next unassigned PDO data type in the enum (6 as of writing). The benefit here is that it simplifies implementations and maps more cleanly to how many databases represent binary data (as a separate data type).
A modifier flag. This is similar to how “national” strings are implemented already in some drivers, and uses a free high value in the enum for masking (likely 0x10000000). The benefit here is that LOBs themselves can be strings (CLOBs) or binaries (BLOBs); this would allow it to compose with existing LOB support in addition to strings (hence why it should not be called i.e. PDO::PARAM_STR_BINARY). Note that this would have to interact with things like PDO::ATTR_DEFAULT_STR_PARAM, which may complicate matters.
If discussions are unclear on what approach is better, then it should be held to a vote; if discussions are clear on what approach should be taken, the others will be dropped.
Variant with a dedicated data type:
<?php $sql = "select id, my_blob from calvin.blob_stream"; $dbconn = new PDO("odbc:*LOCAL", "", ""); $stmt = $dbconn->prepare($sql); $stmt->execute(); $data = ""; $stmt->bindColumn(2, $data, PDO::PARAM_BINARY); $stmt->fetch(PDO::FETCH_BOUND); echo bin2hex($data) . "\n"; ?>
Variant with a flag for a string:
<?php $sql = "select id, my_blob from calvin.blob_stream"; $dbconn = new PDO("odbc:*LOCAL", "", ""); $stmt = $dbconn->prepare($sql); $stmt->execute(); $data = ""; $stmt->bindColumn(2, $data, PDO::PARAM_STRING | PDO::PARAM_BINARY); $stmt->fetch(PDO::FETCH_BOUND); echo bin2hex($data) . "\n"; ?>
Variant with a flag for a LOB:
<?php $sql = "select id, my_blob from calvin.blob_stream"; $dbconn = new PDO("odbc:*LOCAL", "", ""); $stmt = $dbconn->prepare($sql); $stmt->execute(); $fp = fopen("/tmp/binary", 'wb'); $stmt->bindColumn(2, $data, PDO::PARAM_STRING | PDO::PARAM_BINARY); $stmt->fetch(PDO::FETCH_BOUND); ?>
Next PHP 8.x.
Database libraries such as ORMs may want to include support for the new binary support. For example, Illuminate in Laravel has a notion of binary data types at least in migrations.
PDO drivers will need to include support. If a driver has no distinction between binary vs. regular strings, then they can just be simply treated as a regular PDO::PARAM_STRING.
None.
Primary Vote requiring a 2/3 majority to accept the RFC:
What approach should be taken if approved:
Original issue: https://github.com/php/php-src/issues/11462
None yet.