Skip to content

Conversation

@noahheck
Copy link
Contributor

I've maintained a project that performs similar behavior to what occurs in the TracedStatement (generating a string from the parameterized query with the bound arguments put in place into it), so I've seen some of the things to beware of when offering this functionality. Here's a synopsis of the issues and how I work around them:

Back reference syntax in the bound parameter value

If a value to be replaced back into the string contains a substring that looks like a regex back reference (e.g. $1), the preg_replace function looks to facilitate that:

i.e. password_hash function may produce something like this:

$2y$10$Xs/oqD0cVCb7hM1suoAD/Oqf4tlm5suTb8IsczDTnttiWUtHsb5ay

but the interpolated query value ends up like this:

y$Xs/oqD0cVCb7hM1suoAD/Oqf4tlm5suTb8IsczDTnttiWUtHsb5ay
$2y$10$Xs/oqD0cVCb7hM1suoAD/Oqf4tlm5suTb8IsczDTnttiWUtHsb5ay
  y   $Xs/oqD0cVCb7hM1suoAD/Oqf4tlm5suTb8IsczDTnttiWUtHsb5ay

I work around this by appending a % to any $ % or \ (the back reference characters) present in the bound argument value, then change them all back again afterward.

Placeholder substring presence in replaced value

If a replaced value within the query string contains the placeholder character for a future replacement, the replacement may be incorrectly performed against the value within that replacement:

$question = "What's up?";
$person = "Rasmus";

$sql = "INSERT INTO questions SET question = ?, asker = ?";

Performing the translation as it was would have resulted in this:

INSERT INTO questions SET question = <What's up<Rasmus>>, asker = ?

I work around this by ensuring the replacement doesn't occur within a set of the $quotationChar.

Optional leading colon in parameter binding

Named placeholders are required to have a leading colon, but the colon is optional when calling bindParam:

$sql = "INSERT INTO questions SET question = :question, asker = :asker";
$stmt = $pdo->prepare($sql);

// Both instructions below will execute correctly
$stmt->bindParam("question", $question);
$stmt->bindParam(":asker", $asker);

I work around this by checking for the presence of a leading colon on the bound parameter and adding it if it's not present.

I added tests for these scenarios.

If a previously replaced value in the query string contains the placeholder
for a future replacement, the string inside was being replaced
Also, PHP allows the bindParameter syntax to omit the leading ':', so we
test to make sure it's there and add it if not
@barryvdh barryvdh merged commit 3f31153 into php-debugbar:master Apr 16, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants