diff --git a/CHANGELOG.md b/CHANGELOG.md index b619440..391fc90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ ##Change Log +###2.1.5 (2015-05-13) + +####Added + +- Test for successful execution of database query with named placeholders +- Updated README + +####Fixed + +- Remove un-needed escape sequences in regular expression patterns + ###2.1.4 (2015-10-25) ####Added diff --git a/README.md b/README.md index 7f48fb2..0b2ba9c 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,10 @@ #E_PDOStatement -Drop in replacement for default PHP PDOStatement class allowing devs to view an interpolated version of a parameterized query. The result is generally suitable for logging activities, debugging and performance analysis. +Extension to the default PHP PDOStatement class providing the ability to generate a version of a parameterized query with the parameters injected into the query string. -#####Update (2015-10-24) -Full PHPUnit Test Suite in place plus re-organization of code +The result is generally suitable for logging activities, debugging and performance analysis. -#####Update (2015-07-19) -Now takes into account bound arguments' datatypes when compiling interpolated string (previously, all values were quoted when it's likely inappropriate to quote INT datatypes). This allows for viewing/using bound values in e.g. LIMIT clauses where the quotes would interfere with processing the resultant query. +View the [changelog](CHANGELOG.md) ##Usage @@ -18,14 +16,16 @@ The E_PDOStatement (Enhanced PDOStatement) project was designed ```php prepare($query); +$content = $_POST['content']; +$title = $_POST['title']; +$date = date("Y-m-d"); -$username = $_POST['username']; -$password = passwordPrep($_POST['password']); +$query = "INSERT INTO posts SET content = :content, title = :title, date = :date" +$stmt = $pdo->prepare($query); -$stmt->bindParam(":user" , $username, PDO::PARAM_STR); -$stmt->bindParam(":password", $password, PDO::PARAM_STR); +$stmt->bindParam(":content", $content, PDO::PARAM_STR); +$stmt->bindParam(":title" , $title , PDO::PARAM_STR); +$stmt->bindParam(":date" , $date , PDO::PARAM_STR); $stmt->execute(); @@ -36,29 +36,30 @@ echo $stmt->fullQuery; The result of this will be (on a MySQL database): ``` -INSERT INTO users SET username = 'admin', password = '45ab6941fed66456afe6239ab875e4fa' +INSERT INTO posts SET content = 'There are several reasons you shouldn\'t do that, including [...]', title = 'Why You Shouldn\'t Do That', date = '2016-05-13' ``` When correctly configured, the interpolated values are escaped appropriately for the database driver, allowing the generated string to be suitable for e.g. log files, backups, etc. E_PDOStatement supports pre-execution binding to both named and ? style parameter markers: ```php -$query = "INSERT INTO users SET username = ?, password = ?"; +$query = "INSERT INTO posts SET content = ?, title = ?, date = ?"; ... -$stmt->bindParam(1, $username, PDO::PARAM_STR); -$stmt->bindParam(2, $password, PDO::PARAM_STR); +$stmt->bindParam(1, $content, PDO::PARAM_STR); +$stmt->bindParam(2, $title , PDO::PARAM_STR); +$stmt->bindParam(3, $date , PDO::PARAM_STR); ``` as well as un-named parameters provided as input arguments to the `$stmt->execute()` method: ```php -$query = "INSERT INTO users SET username = ?, password = ?"; +$query = "INSERT INTO posts SET content = ?, title = ?, date = ?"; ... -$params = array($username, $password); +$params = array($content, $title, $date); $stmt->execute($params); @@ -66,13 +67,14 @@ $stmt->execute($params); Named $key => $value pairs can also be provided as input arguments to the `$stmt->execute()` method: ```php -$query = "INSERT INTO users SET username = :username, password = :password"; +$query = "INSERT INTO posts SET content = :content, title = :title, date = :date"; ... $params = array( - ":username" => $username - , ":password" => $password + ":content" => $content + , ":title" => $title + , ":date" => $date ); $stmt->execute($params); @@ -80,26 +82,33 @@ $stmt->execute($params); You can also generate the full query string without executing the query: ```php -$query = "INSERT INTO users SET username = :user, password = :password"; -$stmt = $pdo->prepare($query); +$content = $_POST['content']; +$title = $_POST['title']; +$date = date("Y-m-d"); -$username = $_POST['username']; -$password = passwordPrep($_POST['password']); +$query = "INSERT INTO posts SET content = :content, title = :title, date = :date" +$stmt = $pdo->prepare($query); -$stmt->bindParam(":user" , $username, PDO::PARAM_STR); -$stmt->bindParam(":password", $password, PDO::PARAM_STR); +$stmt->bindParam(":content", $content, PDO::PARAM_STR); +$stmt->bindParam(":title" , $title , PDO::PARAM_STR); +$stmt->bindParam(":date" , $date , PDO::PARAM_STR); $fullQuery = $stmt->interpolateQuery(); ``` or ```php -$query = "INSERT INTO users SET username = :user, password = :password"; -$stmt = $pdo->prepare($query); +$content = $_POST['content']; +$title = $_POST['title']; +$date = date("Y-m-d"); -$username = $_POST['username']; -$password = passwordPrep($_POST['password']); +$query = "INSERT INTO posts SET content = ?, title = ?, date = ?" +$stmt = $pdo->prepare($query); -$params = array($username, $password); +$params = array( + $content + , $title + , $date +); $fullQuery = $stmt->interpolateQuery($params); ``` @@ -139,9 +148,8 @@ $pdo->setAttribute(PDO::ATTR_STATEMENT_CLASS, array("EPDOStatement\EPDOStatement That's all there is to it. -The classname has been updated to allow strict conformance to PSR-0 autoloading (e.g. removed the _ from the class/filename). - -Ideally, your project would have a PDO abstraction/wrapper class allowing you to implement this modification in only one place. If you don't have this luxury, success was shown with extending the \PDO class to set the ATTR_STATEMENT_CLASS attribute in the constructor of the PDO. +Ideally, your project would have a PDO abstraction/wrapper class allowing you to implement this modification in only one place. +If you don't have this luxury, success was shown with extending the \PDO class to set the ATTR_STATEMENT_CLASS attribute in the constructor of the PDO. ##Get in Touch There are a lot of forum posts related to or requesting this type of functionality, so hopefully someone somewhere will find it helpful. If it helps you, comments are of course appreciated. diff --git a/src/EPDOStatement.php b/src/EPDOStatement.php index 0f2fdd0..b11a131 100644 --- a/src/EPDOStatement.php +++ b/src/EPDOStatement.php @@ -134,7 +134,7 @@ private function replaceMarker($queryString, $marker, $replValue) if (is_numeric($marker)) { $marker = "\?"; } else { - $marker = (preg_match("/^\:/", $marker)) ? $marker : ":" . $marker; + $marker = (preg_match("/^:/", $marker)) ? $marker : ":" . $marker; } $testParam = "/" . $marker . "(?!\w)/"; @@ -169,16 +169,15 @@ public function execute($inputParams = null) */ private function prepareValue($value) { - if ($this->_pdo) { - - if (PDO::PARAM_INT === $value['datatype']) - { - return (int) $value['value']; - } + if (!$this->_pdo) { + return "'" . addslashes($value['value']) . "'"; + } - return $this->_pdo->quote($value['value']); + if (PDO::PARAM_INT === $value['datatype']) + { + return (int) $value['value']; } - return "'" . addslashes($value['value']) . "'"; + return $this->_pdo->quote($value['value']); } } diff --git a/tests/src/EPDOStatementTest.php b/tests/src/EPDOStatementTest.php index f204f8a..10eb84c 100644 --- a/tests/src/EPDOStatementTest.php +++ b/tests/src/EPDOStatementTest.php @@ -64,8 +64,8 @@ public function testValuesGetInterpolatedIntoQueryStatementWhenBoundIndividually $this->assertTrue(false != preg_match("/123/", $result)); $this->assertTrue(false != preg_match("/active/", $result)); - $this->assertTrue(false == preg_match("/\:userId/", $result)); - $this->assertTrue(false == preg_match("/\:user_status/", $result)); + $this->assertTrue(false == preg_match("/:userId/", $result)); + $this->assertTrue(false == preg_match("/:user_status/", $result)); } public function testValuesGetInterpolatedIntoQueryStatementWhenBoundIndividuallyAsNamedParametersWithoutLeadingColons() @@ -89,8 +89,8 @@ public function testValuesGetInterpolatedIntoQueryStatementWhenBoundIndividually $this->assertTrue(false != preg_match("/123/", $result)); $this->assertTrue(false != preg_match("/active/", $result)); - $this->assertTrue(false == preg_match("/\:userId/", $result)); - $this->assertTrue(false == preg_match("/\:user_status/", $result)); + $this->assertTrue(false == preg_match("/:userId/", $result)); + $this->assertTrue(false == preg_match("/:user_status/", $result)); } public function testValuesGetInterpolatedIntoQueryStatementWhenBoundIndividuallyAsUnnamedParameters() @@ -140,8 +140,8 @@ public function testValuesGetInterpolatedIntoQueryWhenProvidedAsNamedInputParame $this->assertTrue(false != preg_match("/123/", $result)); $this->assertTrue(false != preg_match("/active/", $result)); - $this->assertTrue(false == preg_match("/\:userId/", $result)); - $this->assertTrue(false == preg_match("/\:user_status/", $result)); + $this->assertTrue(false == preg_match("/:userId/", $result)); + $this->assertTrue(false == preg_match("/:user_status/", $result)); } public function testValuesGetInterpolatedIntoQueryWhenProvidedAsUnnamedInputParameters() @@ -194,25 +194,48 @@ public function testValuesGetInterpolatedCorrectlyWhenSimilarlyNamedPlaceholders $this->assertTrue(false != preg_match("/123/", $result)); $this->assertTrue(false != preg_match("/log content/", $result)); - $this->assertTrue(false == preg_match("/\:logContent/", $result)); - $this->assertTrue(false == preg_match("/\:log/", $result)); + $this->assertTrue(false == preg_match("/:logContent/", $result)); + $this->assertTrue(false == preg_match("/:log/", $result)); } public function testInterpolationAllowsSuccessfulExecutionOfQueries() { $pdo = $this->getPdo(); - $query = "SELECT ? + ? + ?"; + $query = "SELECT ? + ? + ?, ?"; $stmt = $pdo->prepare($query); - $values = array(1, 1, 1); + $values = array(1, 1, 1, "test string"); $stmt->execute($values); - list($sum) = $stmt->fetch(); + list($sum, $testString) = $stmt->fetch(); $this->assertEquals(3, $sum); + $this->assertEquals("test string", $testString); + } + + public function tetstInterpolationAllowsSuccessfulExecutionOfQueriesWithNamedPlaceholders() + { + $num = 3; + $string = "someString"; + + $pdo = $this->getPdo(); + + $query = "SELECT :num, :string"; + + $stmt = $pdo->prepare($query); + + $stmt->bindParam(":num", $num, PDO::PARAM_INT); + $stmt->bindParam(":string", $string, PDO::PARAM_STR); + + $stmt->execute(); + + list($sum, $testString) = $stmt->fetch(); + + $this->assertEquals(3, $sum); + $this->assertEquals("test string", $testString); } public function testValuesAreSuccessfullyInterpolatedIfNoPdoProvidedToEPDOStatement() @@ -240,8 +263,8 @@ public function testValuesAreSuccessfullyInterpolatedIfNoPdoProvidedToEPDOStatem $this->assertTrue(false != preg_match("/123/", $result)); $this->assertTrue(false != preg_match("/active/", $result)); - $this->assertTrue(false == preg_match("/\:userId/", $result)); - $this->assertTrue(false == preg_match("/\:user_status/", $result)); + $this->assertTrue(false == preg_match("/:userId/", $result)); + $this->assertTrue(false == preg_match("/:user_status/", $result)); } public function testQueryIsNotChangedIfNoParametersUsedInQuery()