From 335cd962cc4ea3fa85e7ac1a7b2587208d35a382 Mon Sep 17 00:00:00 2001 From: tpetry Date: Wed, 22 Mar 2023 18:26:30 +0100 Subject: [PATCH 1/8] grammars can escape values for safe embedding in sql queries --- src/Illuminate/Database/Connection.php | 5 +- src/Illuminate/Database/Grammar.php | 46 +++++++++++++++++++ src/Illuminate/Database/MySqlConnection.php | 10 +++- .../Database/PostgresConnection.php | 10 +++- src/Illuminate/Database/SQLiteConnection.php | 10 +++- .../Database/SqlServerConnection.php | 10 +++- 6 files changed, 82 insertions(+), 9 deletions(-) diff --git a/src/Illuminate/Database/Connection.php b/src/Illuminate/Database/Connection.php index b9c8e16710be..eb6097f0aefb 100755 --- a/src/Illuminate/Database/Connection.php +++ b/src/Illuminate/Database/Connection.php @@ -257,7 +257,10 @@ public function useDefaultQueryGrammar() */ protected function getDefaultQueryGrammar() { - return new QueryGrammar; + $grammar = new QueryGrammar(); + $grammar->setConnection($this); + + return $grammar; } /** diff --git a/src/Illuminate/Database/Grammar.php b/src/Illuminate/Database/Grammar.php index bba1e5831c6a..2586f719ec0b 100755 --- a/src/Illuminate/Database/Grammar.php +++ b/src/Illuminate/Database/Grammar.php @@ -10,6 +10,13 @@ abstract class Grammar { use Macroable; + /** + * The connection used for escaping values. + * + * @var \Illuminate\Database\Connection + */ + protected $connection = null; + /** * The grammar table prefix. * @@ -196,6 +203,32 @@ public function quoteString($value) return "'$value'"; } + /** + * Escapes a value to use it for safe SQL embedding. + * + * @param string|float|int $value + * @return string + */ + public function escape($value) + { + if (null === $this->connection) { + throw new RuntimeException('The grammar has no connection to escape any value.'); + } + + // The documentation of PDO::quote states that it should be theoretically safe to use a quoted string within + // a SQL query. While only being "theoretically" safe this behaviour is used within the PHP MySQL driver all the + // time as no real prepared statements are used because it is emulating prepares by default. All remaining known + // SQL injections are always some strange charset conversion tricks that start by using invalid UTF-8 sequences. + // But those attacks are fixed by setting the proper connection charset which is done by the standard Laravel + // configuration. To further secure the implementation we can scrub the value by checking for invalid UTF-8 + // sequences. + if (false === preg_match('//u', (string) $value)) { + throw new RuntimeException('The value contains an invalid UTF-8 byte sequence.'); + } + + return $this->connection->getReadPdo()->quote($value); + } + /** * Determine if the given value is a raw expression. * @@ -254,4 +287,17 @@ public function setTablePrefix($prefix) return $this; } + + /** + * Set the grammar's database connection. + * + * @param \Illuminate\Database\Connection $prefix + * @return $this + */ + public function setConnection($connection) + { + $this->connection = $connection; + + return $this; + } } diff --git a/src/Illuminate/Database/MySqlConnection.php b/src/Illuminate/Database/MySqlConnection.php index 54e3d473d580..5a8b9c37f139 100755 --- a/src/Illuminate/Database/MySqlConnection.php +++ b/src/Illuminate/Database/MySqlConnection.php @@ -30,7 +30,10 @@ public function isMaria() */ protected function getDefaultQueryGrammar() { - return $this->withTablePrefix(new QueryGrammar); + $grammar = new QueryGrammar(); + $grammar->setConnection($this); + + return $this->withTablePrefix($grammar); } /** @@ -54,7 +57,10 @@ public function getSchemaBuilder() */ protected function getDefaultSchemaGrammar() { - return $this->withTablePrefix(new SchemaGrammar); + $grammar = new SchemaGrammar(); + $grammar->setConnection($this); + + return $this->withTablePrefix($grammar); } /** diff --git a/src/Illuminate/Database/PostgresConnection.php b/src/Illuminate/Database/PostgresConnection.php index f750f64e6d08..6891635cc11b 100755 --- a/src/Illuminate/Database/PostgresConnection.php +++ b/src/Illuminate/Database/PostgresConnection.php @@ -19,7 +19,10 @@ class PostgresConnection extends Connection */ protected function getDefaultQueryGrammar() { - return $this->withTablePrefix(new QueryGrammar); + $grammar = new QueryGrammar(); + $grammar->setConnection($this); + + return $this->withTablePrefix($grammar); } /** @@ -43,7 +46,10 @@ public function getSchemaBuilder() */ protected function getDefaultSchemaGrammar() { - return $this->withTablePrefix(new SchemaGrammar); + $grammar = new SchemaGrammar(); + $grammar->setConnection($this); + + return $this->withTablePrefix($grammar); } /** diff --git a/src/Illuminate/Database/SQLiteConnection.php b/src/Illuminate/Database/SQLiteConnection.php index 59b5edb210b2..6088d9622a8b 100755 --- a/src/Illuminate/Database/SQLiteConnection.php +++ b/src/Illuminate/Database/SQLiteConnection.php @@ -43,7 +43,10 @@ public function __construct($pdo, $database = '', $tablePrefix = '', array $conf */ protected function getDefaultQueryGrammar() { - return $this->withTablePrefix(new QueryGrammar); + $grammar = new QueryGrammar(); + $grammar->setConnection($this); + + return $this->withTablePrefix($grammar); } /** @@ -67,7 +70,10 @@ public function getSchemaBuilder() */ protected function getDefaultSchemaGrammar() { - return $this->withTablePrefix(new SchemaGrammar); + $grammar = new SchemaGrammar(); + $grammar->setConnection($this); + + return $this->withTablePrefix($grammar); } /** diff --git a/src/Illuminate/Database/SqlServerConnection.php b/src/Illuminate/Database/SqlServerConnection.php index feb4577bc9b1..68528f856325 100755 --- a/src/Illuminate/Database/SqlServerConnection.php +++ b/src/Illuminate/Database/SqlServerConnection.php @@ -61,7 +61,10 @@ public function transaction(Closure $callback, $attempts = 1) */ protected function getDefaultQueryGrammar() { - return $this->withTablePrefix(new QueryGrammar); + $grammar = new QueryGrammar(); + $grammar->setConnection($this); + + return $this->withTablePrefix($grammar); } /** @@ -85,7 +88,10 @@ public function getSchemaBuilder() */ protected function getDefaultSchemaGrammar() { - return $this->withTablePrefix(new SchemaGrammar); + $grammar = new SchemaGrammar(); + $grammar->setConnection($this); + + return $this->withTablePrefix($grammar); } /** From b3c68e7bc64f5da5aff445caf996c3d1831e9973 Mon Sep 17 00:00:00 2001 From: tpetry Date: Tue, 4 Apr 2023 17:35:03 +0200 Subject: [PATCH 2/8] moved escaping to connection, better escapes for many types --- src/Illuminate/Database/Connection.php | 73 +++++++++++++++++++ src/Illuminate/Database/Grammar.php | 42 ++++------- src/Illuminate/Database/MySqlConnection.php | 12 +++ .../Database/PostgresConnection.php | 24 ++++++ src/Illuminate/Database/SQLiteConnection.php | 13 ++++ .../Database/SqlServerConnection.php | 13 ++++ src/Illuminate/Support/Facades/DB.php | 1 + .../Integration/Database/MySql/EscapeTest.php | 54 ++++++++++++++ .../Database/Postgres/EscapeTest.php | 54 ++++++++++++++ .../Database/SqlServer/EscapeTest.php | 50 +++++++++++++ .../Database/Sqlite/EscapeTest.php | 66 +++++++++++++++++ 11 files changed, 376 insertions(+), 26 deletions(-) create mode 100644 tests/Integration/Database/MySql/EscapeTest.php create mode 100644 tests/Integration/Database/Postgres/EscapeTest.php create mode 100644 tests/Integration/Database/SqlServer/EscapeTest.php create mode 100644 tests/Integration/Database/Sqlite/EscapeTest.php diff --git a/src/Illuminate/Database/Connection.php b/src/Illuminate/Database/Connection.php index eb6097f0aefb..5b7dd3acb157 100755 --- a/src/Illuminate/Database/Connection.php +++ b/src/Illuminate/Database/Connection.php @@ -1622,4 +1622,77 @@ public static function getResolver($driver) { return static::$resolvers[$driver] ?? null; } + + /** + * Escapes a value for safe SQL embedding. + * + * @param string|float|int|bool $value + * @param bool $binary + * @return string + */ + public function escape($value, $binary = false) + { + if ($binary) { + return $this->escapeBinary($value); + } else if (is_numeric($value)) { + return (string) $value; + } else if (is_bool($value)) { + return $this->escapeBool($value); + } else { + // As many desktop tools and other programming languages still have problems with null bytes, they are + // forbidden for textual strings to align the support of the different databases: MySQL is the only database + // supporting null bytes within a SQL string in an escaped human-readable format. While PostgreSQL doesn't + // support null bytes, all the other ones use the invisible byte that would be hard to spot when viewing or + // copying SQL queries. + if (str_contains($value, "\00")) { + throw new RuntimeException('Strings with null bytes cannot be escaped. Use the binary escape option.'); + } + + // The documentation of PDO::quote states that it should be theoretically safe to use a quoted string within + // a SQL query. While only being "theoretically" safe this behaviour is used within the PHP MySQL driver all + // the time as no real prepared statements are used because it is emulating prepares by default. All + // remaining known SQL injections are always some strange charset conversion tricks that start by using + // invalid UTF-8 sequences. But those attacks are fixed by setting the proper connection charset which is + // done by the standard Laravel configuration. To further secure the implementation we can scrub the value + // by checking for invalid UTF-8 sequences. + if (false === preg_match('//u', $value)) { + throw new RuntimeException('Strings with invalid UTF-8 byte sequences cannot be escaped.'); + } + + return $this->escapeString($value); + } + } + + /** + * Escapes a string value for safe SQL embedding. + * + * @param string $value + * @return string + */ + protected function escapeString($value) + { + return $this->getPdo()->quote($value); + } + + /** + * Escapes a bool value for safe SQL embedding. + * + * @param bool $value + * @return string + */ + protected function escapeBool($value) + { + return $value ? '1' : '0'; + } + + /** + * Escapes a binary value for safe SQL embedding. + * + * @param string $value + * @return string + */ + protected function escapeBinary($value) + { + throw new RuntimeException('The database connection has no implementation to escape binary values.'); + } } diff --git a/src/Illuminate/Database/Grammar.php b/src/Illuminate/Database/Grammar.php index 2586f719ec0b..b0d60723a5fa 100755 --- a/src/Illuminate/Database/Grammar.php +++ b/src/Illuminate/Database/Grammar.php @@ -203,32 +203,6 @@ public function quoteString($value) return "'$value'"; } - /** - * Escapes a value to use it for safe SQL embedding. - * - * @param string|float|int $value - * @return string - */ - public function escape($value) - { - if (null === $this->connection) { - throw new RuntimeException('The grammar has no connection to escape any value.'); - } - - // The documentation of PDO::quote states that it should be theoretically safe to use a quoted string within - // a SQL query. While only being "theoretically" safe this behaviour is used within the PHP MySQL driver all the - // time as no real prepared statements are used because it is emulating prepares by default. All remaining known - // SQL injections are always some strange charset conversion tricks that start by using invalid UTF-8 sequences. - // But those attacks are fixed by setting the proper connection charset which is done by the standard Laravel - // configuration. To further secure the implementation we can scrub the value by checking for invalid UTF-8 - // sequences. - if (false === preg_match('//u', (string) $value)) { - throw new RuntimeException('The value contains an invalid UTF-8 byte sequence.'); - } - - return $this->connection->getReadPdo()->quote($value); - } - /** * Determine if the given value is a raw expression. * @@ -300,4 +274,20 @@ public function setConnection($connection) return $this; } + + /** + * Escapes a value for safe SQL embedding. + * + * @param string|float|int|bool $value + * @param bool $binary + * @return string + */ + public function escape($value, $binary = false) + { + if (null === $this->connection) { + throw new RuntimeException('The grammar does not support escaping values.'); + } + + return $this->connection->escape($value, $binary); + } } diff --git a/src/Illuminate/Database/MySqlConnection.php b/src/Illuminate/Database/MySqlConnection.php index 5a8b9c37f139..4cc573806ce2 100755 --- a/src/Illuminate/Database/MySqlConnection.php +++ b/src/Illuminate/Database/MySqlConnection.php @@ -94,4 +94,16 @@ protected function getDoctrineDriver() { return new MySqlDriver; } + /** + * Escapes a binary value for safe SQL embedding. + * + * @param string $value + * @return string + */ + protected function escapeBinary($value) + { + $hex = bin2hex($value); + + return "x'{$hex}'"; + } } diff --git a/src/Illuminate/Database/PostgresConnection.php b/src/Illuminate/Database/PostgresConnection.php index 6891635cc11b..927ff4bc3e03 100755 --- a/src/Illuminate/Database/PostgresConnection.php +++ b/src/Illuminate/Database/PostgresConnection.php @@ -83,4 +83,28 @@ protected function getDoctrineDriver() { return new PostgresDriver; } + + /** + * Escapes a binary value for safe SQL embedding. + * + * @param string $value + * @return string + */ + protected function escapeBinary($value) + { + $hex = bin2hex($value); + + return "'\x{$hex}'::bytea"; + } + + /** + * Escapes a bool value for safe SQL embedding. + * + * @param bool $value + * @return string + */ + protected function escapeBool($value) + { + return $value ? 'true' : 'false'; + } } diff --git a/src/Illuminate/Database/SQLiteConnection.php b/src/Illuminate/Database/SQLiteConnection.php index 6088d9622a8b..0fc4e9f7e80a 100755 --- a/src/Illuminate/Database/SQLiteConnection.php +++ b/src/Illuminate/Database/SQLiteConnection.php @@ -118,4 +118,17 @@ protected function getForeignKeyConstraintsConfigurationValue() { return $this->getConfig('foreign_key_constraints'); } + + /** + * Escapes a binary value for safe SQL embedding. + * + * @param string $value + * @return string + */ + protected function escapeBinary($value) + { + $hex = bin2hex($value); + + return "x'{$hex}'"; + } } diff --git a/src/Illuminate/Database/SqlServerConnection.php b/src/Illuminate/Database/SqlServerConnection.php index 68528f856325..c7c826bac22d 100755 --- a/src/Illuminate/Database/SqlServerConnection.php +++ b/src/Illuminate/Database/SqlServerConnection.php @@ -126,4 +126,17 @@ protected function getDoctrineDriver() { return new SqlServerDriver; } + + /** + * Escapes a binary value for safe SQL embedding. + * + * @param string $value + * @return string + */ + protected function escapeBinary($value) + { + $hex = bin2hex($value); + + return "0x{$hex}"; + } } diff --git a/src/Illuminate/Support/Facades/DB.php b/src/Illuminate/Support/Facades/DB.php index 5053897798cd..a49caa318e0d 100755 --- a/src/Illuminate/Support/Facades/DB.php +++ b/src/Illuminate/Support/Facades/DB.php @@ -98,6 +98,7 @@ * @method static \Illuminate\Database\Grammar withTablePrefix(\Illuminate\Database\Grammar $grammar) * @method static void resolverFor(string $driver, \Closure $callback) * @method static mixed getResolver(string $driver) + * @method static string escape(string|float|int|bool $value, bool $binary = false) * @method static mixed transaction(\Closure $callback, int $attempts = 1) * @method static void beginTransaction() * @method static void commit() diff --git a/tests/Integration/Database/MySql/EscapeTest.php b/tests/Integration/Database/MySql/EscapeTest.php new file mode 100644 index 000000000000..3f8b457fdb71 --- /dev/null +++ b/tests/Integration/Database/MySql/EscapeTest.php @@ -0,0 +1,54 @@ +assertSame('42', $this->app['db']->escape(42)); + $this->assertSame('-6', $this->app['db']->escape(-6)); + } + + public function testEscapeFloat() + { + $this->assertSame('3.14159', $this->app['db']->escape(3.14159)); + $this->assertSame('-3.14159', $this->app['db']->escape(-3.14159)); + } + + public function testEscapeBool() + { + $this->assertSame('1', $this->app['db']->escape(true)); + $this->assertSame('0', $this->app['db']->escape(false)); + } + + public function testEscapeBinary() + { + $this->assertSame("x'dead00beef'", $this->app['db']->escape(hex2bin('dead00beef'), true)); + } + + public function testEscapeString() + { + $this->assertSame("'Hello\'World'", $this->app['db']->escape("Hello'World")); + } + + public function testEscapeStringInvalidUtf8() + { + $this->expectException(RuntimeException::class); + + $this->app['db']->escape("I am hiding an invalid \x80 utf-8 continuation byte"); + } + + public function testEscapeStringNullByte() + { + $this->expectException(RuntimeException::class); + + $this->app['db']->escape("I am hiding a \00 byte"); + } +} diff --git a/tests/Integration/Database/Postgres/EscapeTest.php b/tests/Integration/Database/Postgres/EscapeTest.php new file mode 100644 index 000000000000..4084654d17d2 --- /dev/null +++ b/tests/Integration/Database/Postgres/EscapeTest.php @@ -0,0 +1,54 @@ +assertSame('42', $this->app['db']->escape(42)); + $this->assertSame('-6', $this->app['db']->escape(-6)); + } + + public function testEscapeFloat() + { + $this->assertSame('3.14159', $this->app['db']->escape(3.14159)); + $this->assertSame('-3.14159', $this->app['db']->escape(-3.14159)); + } + + public function testEscapeBool() + { + $this->assertSame('true', $this->app['db']->escape(true)); + $this->assertSame('false', $this->app['db']->escape(false)); + } + + public function testEscapeBinary() + { + $this->assertSame("'\\xdead00beef'::bytea", $this->app['db']->escape(hex2bin('dead00beef'), true)); + } + + public function testEscapeString() + { + $this->assertSame("'Hello''World'", $this->app['db']->escape("Hello'World")); + } + + public function testEscapeStringInvalidUtf8() + { + $this->expectException(RuntimeException::class); + + $this->app['db']->escape("I am hiding an invalid \x80 utf-8 continuation byte"); + } + + public function testEscapeStringNullByte() + { + $this->expectException(RuntimeException::class); + + $this->app['db']->escape("I am hiding a \00 byte"); + } +} diff --git a/tests/Integration/Database/SqlServer/EscapeTest.php b/tests/Integration/Database/SqlServer/EscapeTest.php new file mode 100644 index 000000000000..afb044e80bb9 --- /dev/null +++ b/tests/Integration/Database/SqlServer/EscapeTest.php @@ -0,0 +1,50 @@ +assertSame('42', $this->app['db']->escape(42)); + $this->assertSame('-6', $this->app['db']->escape(-6)); + } + + public function testEscapeFloat() + { + $this->assertSame('3.14159', $this->app['db']->escape(3.14159)); + $this->assertSame('-3.14159', $this->app['db']->escape(-3.14159)); + } + + public function testEscapeBool() + { + $this->assertSame('1', $this->app['db']->escape(true)); + $this->assertSame('0', $this->app['db']->escape(false)); + } + + public function testEscapeBinary() + { + $this->assertSame('0xdead00beef', $this->app['db']->escape(hex2bin('dead00beef'), true)); + } + + public function testEscapeString() + { + $this->assertSame("'Hello''World'", $this->app['db']->escape("Hello'World")); + } + + public function testEscapeStringInvalidUtf8() + { + $this->expectException(RuntimeException::class); + + $this->app['db']->escape("I am hiding an invalid \x80 utf-8 continuation byte"); + } + + public function testEscapeStringNullByte() + { + $this->expectException(RuntimeException::class); + + $this->app['db']->escape("I am hiding a \00 byte"); + } +} diff --git a/tests/Integration/Database/Sqlite/EscapeTest.php b/tests/Integration/Database/Sqlite/EscapeTest.php new file mode 100644 index 000000000000..5255fa1425db --- /dev/null +++ b/tests/Integration/Database/Sqlite/EscapeTest.php @@ -0,0 +1,66 @@ +markTestSkipped('Test requires a Sqlite connection.'); + } + + $app['config']->set('database.default', 'conn1'); + + $app['config']->set('database.connections.conn1', [ + 'driver' => 'sqlite', + 'database' => ':memory:', + 'prefix' => '', + ]); + } + + public function testEscapeInt() + { + $this->assertSame('42', $this->app['db']->escape(42)); + $this->assertSame('-6', $this->app['db']->escape(-6)); + } + + public function testEscapeFloat() + { + $this->assertSame('3.14159', $this->app['db']->escape(3.14159)); + $this->assertSame('-3.14159', $this->app['db']->escape(-3.14159)); + } + + public function testEscapeBool() + { + $this->assertSame('1', $this->app['db']->escape(true)); + $this->assertSame('0', $this->app['db']->escape(false)); + } + + public function testEscapeBinary() + { + $this->assertSame("x'dead00beef'", $this->app['db']->escape(hex2bin('dead00beef'), true)); + } + + public function testEscapeString() + { + $this->assertSame("'Hello''World'", $this->app['db']->escape("Hello'World")); + } + + public function testEscapeStringInvalidUtf8() + { + $this->expectException(RuntimeException::class); + + $this->app['db']->escape("I am hiding an invalid \x80 utf-8 continuation byte"); + } + + public function testEscapeStringNullByte() + { + $this->expectException(RuntimeException::class); + + $this->app['db']->escape("I am hiding a \00 byte"); + } +} From cd7ad50dca046d465e616d08e9db430b92cf9942 Mon Sep 17 00:00:00 2001 From: tpetry Date: Tue, 4 Apr 2023 17:47:55 +0200 Subject: [PATCH 3/8] styleci --- src/Illuminate/Database/Connection.php | 10 +++++----- src/Illuminate/Database/Grammar.php | 2 +- src/Illuminate/Database/MySqlConnection.php | 2 +- src/Illuminate/Database/PostgresConnection.php | 4 ++-- src/Illuminate/Database/SQLiteConnection.php | 2 +- src/Illuminate/Database/SqlServerConnection.php | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Illuminate/Database/Connection.php b/src/Illuminate/Database/Connection.php index 5b7dd3acb157..d4b3bf41fe35 100755 --- a/src/Illuminate/Database/Connection.php +++ b/src/Illuminate/Database/Connection.php @@ -1627,7 +1627,7 @@ public static function getResolver($driver) * Escapes a value for safe SQL embedding. * * @param string|float|int|bool $value - * @param bool $binary + * @param bool $binary * @return string */ public function escape($value, $binary = false) @@ -1636,7 +1636,7 @@ public function escape($value, $binary = false) return $this->escapeBinary($value); } else if (is_numeric($value)) { return (string) $value; - } else if (is_bool($value)) { + } elseif (is_bool($value)) { return $this->escapeBool($value); } else { // As many desktop tools and other programming languages still have problems with null bytes, they are @@ -1666,7 +1666,7 @@ public function escape($value, $binary = false) /** * Escapes a string value for safe SQL embedding. * - * @param string $value + * @param string $value * @return string */ protected function escapeString($value) @@ -1677,7 +1677,7 @@ protected function escapeString($value) /** * Escapes a bool value for safe SQL embedding. * - * @param bool $value + * @param bool $value * @return string */ protected function escapeBool($value) @@ -1688,7 +1688,7 @@ protected function escapeBool($value) /** * Escapes a binary value for safe SQL embedding. * - * @param string $value + * @param string $value * @return string */ protected function escapeBinary($value) diff --git a/src/Illuminate/Database/Grammar.php b/src/Illuminate/Database/Grammar.php index b0d60723a5fa..f24892409eb7 100755 --- a/src/Illuminate/Database/Grammar.php +++ b/src/Illuminate/Database/Grammar.php @@ -279,7 +279,7 @@ public function setConnection($connection) * Escapes a value for safe SQL embedding. * * @param string|float|int|bool $value - * @param bool $binary + * @param bool $binary * @return string */ public function escape($value, $binary = false) diff --git a/src/Illuminate/Database/MySqlConnection.php b/src/Illuminate/Database/MySqlConnection.php index 4cc573806ce2..e930640f0744 100755 --- a/src/Illuminate/Database/MySqlConnection.php +++ b/src/Illuminate/Database/MySqlConnection.php @@ -97,7 +97,7 @@ protected function getDoctrineDriver() /** * Escapes a binary value for safe SQL embedding. * - * @param string $value + * @param string $value * @return string */ protected function escapeBinary($value) diff --git a/src/Illuminate/Database/PostgresConnection.php b/src/Illuminate/Database/PostgresConnection.php index 927ff4bc3e03..1d1d14310e2b 100755 --- a/src/Illuminate/Database/PostgresConnection.php +++ b/src/Illuminate/Database/PostgresConnection.php @@ -87,7 +87,7 @@ protected function getDoctrineDriver() /** * Escapes a binary value for safe SQL embedding. * - * @param string $value + * @param string $value * @return string */ protected function escapeBinary($value) @@ -100,7 +100,7 @@ protected function escapeBinary($value) /** * Escapes a bool value for safe SQL embedding. * - * @param bool $value + * @param bool $value * @return string */ protected function escapeBool($value) diff --git a/src/Illuminate/Database/SQLiteConnection.php b/src/Illuminate/Database/SQLiteConnection.php index 0fc4e9f7e80a..26583eec63d0 100755 --- a/src/Illuminate/Database/SQLiteConnection.php +++ b/src/Illuminate/Database/SQLiteConnection.php @@ -122,7 +122,7 @@ protected function getForeignKeyConstraintsConfigurationValue() /** * Escapes a binary value for safe SQL embedding. * - * @param string $value + * @param string $value * @return string */ protected function escapeBinary($value) diff --git a/src/Illuminate/Database/SqlServerConnection.php b/src/Illuminate/Database/SqlServerConnection.php index c7c826bac22d..f415aaf91130 100755 --- a/src/Illuminate/Database/SqlServerConnection.php +++ b/src/Illuminate/Database/SqlServerConnection.php @@ -130,7 +130,7 @@ protected function getDoctrineDriver() /** * Escapes a binary value for safe SQL embedding. * - * @param string $value + * @param string $value * @return string */ protected function escapeBinary($value) From 5df51bdcebfaba0d8bdb7c15c0438b679b861b8b Mon Sep 17 00:00:00 2001 From: tpetry Date: Tue, 4 Apr 2023 17:49:11 +0200 Subject: [PATCH 4/8] styleci --- src/Illuminate/Database/Connection.php | 2 +- src/Illuminate/Database/MySqlConnection.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Connection.php b/src/Illuminate/Database/Connection.php index d4b3bf41fe35..83646aa1573e 100755 --- a/src/Illuminate/Database/Connection.php +++ b/src/Illuminate/Database/Connection.php @@ -1634,7 +1634,7 @@ public function escape($value, $binary = false) { if ($binary) { return $this->escapeBinary($value); - } else if (is_numeric($value)) { + } elseif (is_numeric($value)) { return (string) $value; } elseif (is_bool($value)) { return $this->escapeBool($value); diff --git a/src/Illuminate/Database/MySqlConnection.php b/src/Illuminate/Database/MySqlConnection.php index e930640f0744..9858c3fb39ab 100755 --- a/src/Illuminate/Database/MySqlConnection.php +++ b/src/Illuminate/Database/MySqlConnection.php @@ -94,6 +94,7 @@ protected function getDoctrineDriver() { return new MySqlDriver; } + /** * Escapes a binary value for safe SQL embedding. * From 8aafee84579bb91eec345fabf8d24fdd137db613 Mon Sep 17 00:00:00 2001 From: tpetry Date: Thu, 6 Apr 2023 08:45:26 +0200 Subject: [PATCH 5/8] type and doc improvements --- src/Illuminate/Database/Connection.php | 20 +++++++++++-------- src/Illuminate/Database/Grammar.php | 2 +- src/Illuminate/Support/Facades/DB.php | 2 +- .../Integration/Database/MySql/EscapeTest.php | 10 ++++++++++ .../Database/Postgres/EscapeTest.php | 10 ++++++++++ .../Database/SqlServer/EscapeTest.php | 10 ++++++++++ .../Database/Sqlite/EscapeTest.php | 10 ++++++++++ 7 files changed, 54 insertions(+), 10 deletions(-) diff --git a/src/Illuminate/Database/Connection.php b/src/Illuminate/Database/Connection.php index 83646aa1573e..242aa0c5b2fc 100755 --- a/src/Illuminate/Database/Connection.php +++ b/src/Illuminate/Database/Connection.php @@ -1626,15 +1626,17 @@ public static function getResolver($driver) /** * Escapes a value for safe SQL embedding. * - * @param string|float|int|bool $value + * @param string|float|int|bool|null $value * @param bool $binary * @return string */ public function escape($value, $binary = false) { - if ($binary) { + if ($value === null) { + return 'null'; + } else if ($binary) { return $this->escapeBinary($value); - } elseif (is_numeric($value)) { + } elseif (is_int($value) || is_float($value)) { return (string) $value; } elseif (is_bool($value)) { return $this->escapeBool($value); @@ -1650,11 +1652,13 @@ public function escape($value, $binary = false) // The documentation of PDO::quote states that it should be theoretically safe to use a quoted string within // a SQL query. While only being "theoretically" safe this behaviour is used within the PHP MySQL driver all - // the time as no real prepared statements are used because it is emulating prepares by default. All - // remaining known SQL injections are always some strange charset conversion tricks that start by using - // invalid UTF-8 sequences. But those attacks are fixed by setting the proper connection charset which is - // done by the standard Laravel configuration. To further secure the implementation we can scrub the value - // by checking for invalid UTF-8 sequences. + // the time as no real prepared statements are used because it is emulating prepares by default. So even the + // PHP core developers believes it to be secure. However, Laravel forces the PDO driver to use real prepared + // statements so the default mode is not active for Laravel applications. + // All SQL injections remaining when quoting values are always some strange charset conversion tricks that + // start by using invalid UTF-8 sequences. But those attacks are fixed by setting the proper connection + // charset which is done by the standard Laravel configuration. To further secure the implementation we can + // scrub the value by checking for invalid UTF-8 sequences. if (false === preg_match('//u', $value)) { throw new RuntimeException('Strings with invalid UTF-8 byte sequences cannot be escaped.'); } diff --git a/src/Illuminate/Database/Grammar.php b/src/Illuminate/Database/Grammar.php index f24892409eb7..68ba93d256da 100755 --- a/src/Illuminate/Database/Grammar.php +++ b/src/Illuminate/Database/Grammar.php @@ -285,7 +285,7 @@ public function setConnection($connection) public function escape($value, $binary = false) { if (null === $this->connection) { - throw new RuntimeException('The grammar does not support escaping values.'); + throw new RuntimeException("The database driver's grammar implementation does not support escaping values."); } return $this->connection->escape($value, $binary); diff --git a/src/Illuminate/Support/Facades/DB.php b/src/Illuminate/Support/Facades/DB.php index a49caa318e0d..c71b31d29c68 100755 --- a/src/Illuminate/Support/Facades/DB.php +++ b/src/Illuminate/Support/Facades/DB.php @@ -98,7 +98,7 @@ * @method static \Illuminate\Database\Grammar withTablePrefix(\Illuminate\Database\Grammar $grammar) * @method static void resolverFor(string $driver, \Closure $callback) * @method static mixed getResolver(string $driver) - * @method static string escape(string|float|int|bool $value, bool $binary = false) + * @method static string escape(string|float|int|bool|null $value, bool $binary = false) * @method static mixed transaction(\Closure $callback, int $attempts = 1) * @method static void beginTransaction() * @method static void commit() diff --git a/tests/Integration/Database/MySql/EscapeTest.php b/tests/Integration/Database/MySql/EscapeTest.php index 3f8b457fdb71..a33080749276 100644 --- a/tests/Integration/Database/MySql/EscapeTest.php +++ b/tests/Integration/Database/MySql/EscapeTest.php @@ -28,6 +28,12 @@ public function testEscapeBool() $this->assertSame('0', $this->app['db']->escape(false)); } + public function testEscapeNull() + { + $this->assertSame('null', $this->app['db']->escape(null)); + $this->assertSame('null', $this->app['db']->escape(null, true)); + } + public function testEscapeBinary() { $this->assertSame("x'dead00beef'", $this->app['db']->escape(hex2bin('dead00beef'), true)); @@ -35,6 +41,10 @@ public function testEscapeBinary() public function testEscapeString() { + $this->assertSame("'2147483647'", $this->app['db']->escape("2147483647")); + $this->assertSame("'true'", $this->app['db']->escape("true")); + $this->assertSame("'false'", $this->app['db']->escape("false")); + $this->assertSame("'null'", $this->app['db']->escape("null")); $this->assertSame("'Hello\'World'", $this->app['db']->escape("Hello'World")); } diff --git a/tests/Integration/Database/Postgres/EscapeTest.php b/tests/Integration/Database/Postgres/EscapeTest.php index 4084654d17d2..9580e26c265b 100644 --- a/tests/Integration/Database/Postgres/EscapeTest.php +++ b/tests/Integration/Database/Postgres/EscapeTest.php @@ -28,6 +28,12 @@ public function testEscapeBool() $this->assertSame('false', $this->app['db']->escape(false)); } + public function testEscapeNull() + { + $this->assertSame('null', $this->app['db']->escape(null)); + $this->assertSame('null', $this->app['db']->escape(null, true)); + } + public function testEscapeBinary() { $this->assertSame("'\\xdead00beef'::bytea", $this->app['db']->escape(hex2bin('dead00beef'), true)); @@ -35,6 +41,10 @@ public function testEscapeBinary() public function testEscapeString() { + $this->assertSame("'2147483647'", $this->app['db']->escape("2147483647")); + $this->assertSame("'true'", $this->app['db']->escape("true")); + $this->assertSame("'false'", $this->app['db']->escape("false")); + $this->assertSame("'null'", $this->app['db']->escape("null")); $this->assertSame("'Hello''World'", $this->app['db']->escape("Hello'World")); } diff --git a/tests/Integration/Database/SqlServer/EscapeTest.php b/tests/Integration/Database/SqlServer/EscapeTest.php index afb044e80bb9..9dc4ed4d269d 100644 --- a/tests/Integration/Database/SqlServer/EscapeTest.php +++ b/tests/Integration/Database/SqlServer/EscapeTest.php @@ -24,6 +24,12 @@ public function testEscapeBool() $this->assertSame('0', $this->app['db']->escape(false)); } + public function testEscapeNull() + { + $this->assertSame('null', $this->app['db']->escape(null)); + $this->assertSame('null', $this->app['db']->escape(null, true)); + } + public function testEscapeBinary() { $this->assertSame('0xdead00beef', $this->app['db']->escape(hex2bin('dead00beef'), true)); @@ -31,6 +37,10 @@ public function testEscapeBinary() public function testEscapeString() { + $this->assertSame("'2147483647'", $this->app['db']->escape("2147483647")); + $this->assertSame("'true'", $this->app['db']->escape("true")); + $this->assertSame("'false'", $this->app['db']->escape("false")); + $this->assertSame("'null'", $this->app['db']->escape("null")); $this->assertSame("'Hello''World'", $this->app['db']->escape("Hello'World")); } diff --git a/tests/Integration/Database/Sqlite/EscapeTest.php b/tests/Integration/Database/Sqlite/EscapeTest.php index 5255fa1425db..a61c74a0caf7 100644 --- a/tests/Integration/Database/Sqlite/EscapeTest.php +++ b/tests/Integration/Database/Sqlite/EscapeTest.php @@ -40,6 +40,12 @@ public function testEscapeBool() $this->assertSame('0', $this->app['db']->escape(false)); } + public function testEscapeNull() + { + $this->assertSame('null', $this->app['db']->escape(null)); + $this->assertSame('null', $this->app['db']->escape(null, true)); + } + public function testEscapeBinary() { $this->assertSame("x'dead00beef'", $this->app['db']->escape(hex2bin('dead00beef'), true)); @@ -47,6 +53,10 @@ public function testEscapeBinary() public function testEscapeString() { + $this->assertSame("'2147483647'", $this->app['db']->escape("2147483647")); + $this->assertSame("'true'", $this->app['db']->escape("true")); + $this->assertSame("'false'", $this->app['db']->escape("false")); + $this->assertSame("'null'", $this->app['db']->escape("null")); $this->assertSame("'Hello''World'", $this->app['db']->escape("Hello'World")); } From c54339fb7a7f7230e7a796c2fa499414560c3492 Mon Sep 17 00:00:00 2001 From: tpetry Date: Thu, 6 Apr 2023 08:55:31 +0200 Subject: [PATCH 6/8] styleci --- src/Illuminate/Database/Connection.php | 2 +- tests/Integration/Database/MySql/EscapeTest.php | 8 ++++---- tests/Integration/Database/Postgres/EscapeTest.php | 8 ++++---- tests/Integration/Database/SqlServer/EscapeTest.php | 8 ++++---- tests/Integration/Database/Sqlite/EscapeTest.php | 8 ++++---- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/Illuminate/Database/Connection.php b/src/Illuminate/Database/Connection.php index 242aa0c5b2fc..37f4dc55446b 100755 --- a/src/Illuminate/Database/Connection.php +++ b/src/Illuminate/Database/Connection.php @@ -1634,7 +1634,7 @@ public function escape($value, $binary = false) { if ($value === null) { return 'null'; - } else if ($binary) { + } elseif ($binary) { return $this->escapeBinary($value); } elseif (is_int($value) || is_float($value)) { return (string) $value; diff --git a/tests/Integration/Database/MySql/EscapeTest.php b/tests/Integration/Database/MySql/EscapeTest.php index a33080749276..9ad6d6e8a41f 100644 --- a/tests/Integration/Database/MySql/EscapeTest.php +++ b/tests/Integration/Database/MySql/EscapeTest.php @@ -41,10 +41,10 @@ public function testEscapeBinary() public function testEscapeString() { - $this->assertSame("'2147483647'", $this->app['db']->escape("2147483647")); - $this->assertSame("'true'", $this->app['db']->escape("true")); - $this->assertSame("'false'", $this->app['db']->escape("false")); - $this->assertSame("'null'", $this->app['db']->escape("null")); + $this->assertSame("'2147483647'", $this->app['db']->escape('2147483647')); + $this->assertSame("'true'", $this->app['db']->escape('true')); + $this->assertSame("'false'", $this->app['db']->escape('false')); + $this->assertSame("'null'", $this->app['db']->escape('null')); $this->assertSame("'Hello\'World'", $this->app['db']->escape("Hello'World")); } diff --git a/tests/Integration/Database/Postgres/EscapeTest.php b/tests/Integration/Database/Postgres/EscapeTest.php index 9580e26c265b..dc382b4a1143 100644 --- a/tests/Integration/Database/Postgres/EscapeTest.php +++ b/tests/Integration/Database/Postgres/EscapeTest.php @@ -41,10 +41,10 @@ public function testEscapeBinary() public function testEscapeString() { - $this->assertSame("'2147483647'", $this->app['db']->escape("2147483647")); - $this->assertSame("'true'", $this->app['db']->escape("true")); - $this->assertSame("'false'", $this->app['db']->escape("false")); - $this->assertSame("'null'", $this->app['db']->escape("null")); + $this->assertSame("'2147483647'", $this->app['db']->escape('2147483647')); + $this->assertSame("'true'", $this->app['db']->escape('true')); + $this->assertSame("'false'", $this->app['db']->escape('false')); + $this->assertSame("'null'", $this->app['db']->escape('null')); $this->assertSame("'Hello''World'", $this->app['db']->escape("Hello'World")); } diff --git a/tests/Integration/Database/SqlServer/EscapeTest.php b/tests/Integration/Database/SqlServer/EscapeTest.php index 9dc4ed4d269d..77037d1cc810 100644 --- a/tests/Integration/Database/SqlServer/EscapeTest.php +++ b/tests/Integration/Database/SqlServer/EscapeTest.php @@ -37,10 +37,10 @@ public function testEscapeBinary() public function testEscapeString() { - $this->assertSame("'2147483647'", $this->app['db']->escape("2147483647")); - $this->assertSame("'true'", $this->app['db']->escape("true")); - $this->assertSame("'false'", $this->app['db']->escape("false")); - $this->assertSame("'null'", $this->app['db']->escape("null")); + $this->assertSame("'2147483647'", $this->app['db']->escape('2147483647')); + $this->assertSame("'true'", $this->app['db']->escape('true')); + $this->assertSame("'false'", $this->app['db']->escape('false')); + $this->assertSame("'null'", $this->app['db']->escape('null')); $this->assertSame("'Hello''World'", $this->app['db']->escape("Hello'World")); } diff --git a/tests/Integration/Database/Sqlite/EscapeTest.php b/tests/Integration/Database/Sqlite/EscapeTest.php index a61c74a0caf7..f642c6fe3363 100644 --- a/tests/Integration/Database/Sqlite/EscapeTest.php +++ b/tests/Integration/Database/Sqlite/EscapeTest.php @@ -53,10 +53,10 @@ public function testEscapeBinary() public function testEscapeString() { - $this->assertSame("'2147483647'", $this->app['db']->escape("2147483647")); - $this->assertSame("'true'", $this->app['db']->escape("true")); - $this->assertSame("'false'", $this->app['db']->escape("false")); - $this->assertSame("'null'", $this->app['db']->escape("null")); + $this->assertSame("'2147483647'", $this->app['db']->escape('2147483647')); + $this->assertSame("'true'", $this->app['db']->escape('true')); + $this->assertSame("'false'", $this->app['db']->escape('false')); + $this->assertSame("'null'", $this->app['db']->escape('null')); $this->assertSame("'Hello''World'", $this->app['db']->escape("Hello'World")); } From 8a489f68c5ad766f9bc6722a233f264fc43aab00 Mon Sep 17 00:00:00 2001 From: tpetry Date: Fri, 14 Apr 2023 08:51:01 +0200 Subject: [PATCH 7/8] null doctype missing --- src/Illuminate/Database/Grammar.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Grammar.php b/src/Illuminate/Database/Grammar.php index 68ba93d256da..0df0dcb60f1f 100755 --- a/src/Illuminate/Database/Grammar.php +++ b/src/Illuminate/Database/Grammar.php @@ -278,7 +278,7 @@ public function setConnection($connection) /** * Escapes a value for safe SQL embedding. * - * @param string|float|int|bool $value + * @param string|float|int|bool|null $value * @param bool $binary * @return string */ From fca8e969212dae79c3166b7acf7ba9a6c3e2972f Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 24 May 2023 16:16:10 -0500 Subject: [PATCH 8/8] formatting --- src/Illuminate/Database/Connection.php | 143 ++++++++---------- src/Illuminate/Database/Grammar.php | 34 ++--- src/Illuminate/Database/MySqlConnection.php | 32 ++-- .../Database/PostgresConnection.php | 54 ++++--- src/Illuminate/Database/SQLiteConnection.php | 32 ++-- .../Database/SqlServerConnection.php | 32 ++-- 6 files changed, 152 insertions(+), 175 deletions(-) diff --git a/src/Illuminate/Database/Connection.php b/src/Illuminate/Database/Connection.php index 37f4dc55446b..b598c95eb506 100755 --- a/src/Illuminate/Database/Connection.php +++ b/src/Illuminate/Database/Connection.php @@ -257,8 +257,7 @@ public function useDefaultQueryGrammar() */ protected function getDefaultQueryGrammar() { - $grammar = new QueryGrammar(); - $grammar->setConnection($this); + ($grammar = new QueryGrammar)->setConnection($this); return $grammar; } @@ -1043,6 +1042,69 @@ public function raw($value) return new Expression($value); } + /** + * Escape a value for safe SQL embedding. + * + * @param string|float|int|bool|null $value + * @param bool $binary + * @return string + */ + public function escape($value, $binary = false) + { + if ($value === null) { + return 'null'; + } elseif ($binary) { + return $this->escapeBinary($value); + } elseif (is_int($value) || is_float($value)) { + return (string) $value; + } elseif (is_bool($value)) { + return $this->escapeBool($value); + } else { + if (str_contains($value, "\00")) { + throw new RuntimeException('Strings with null bytes cannot be escaped. Use the binary escape option.'); + } + + if (preg_match('//u', $value) === false) { + throw new RuntimeException('Strings with invalid UTF-8 byte sequences cannot be escaped.'); + } + + return $this->escapeString($value); + } + } + + /** + * Escape a string value for safe SQL embedding. + * + * @param string $value + * @return string + */ + protected function escapeString($value) + { + return $this->getPdo()->quote($value); + } + + /** + * Escape a boolean value for safe SQL embedding. + * + * @param bool $value + * @return string + */ + protected function escapeBool($value) + { + return $value ? '1' : '0'; + } + + /** + * Escape a binary value for safe SQL embedding. + * + * @param string $value + * @return string + */ + protected function escapeBinary($value) + { + throw new RuntimeException('The database connection does not support escaping binary values.'); + } + /** * Determine if the database connection has modified any database records. * @@ -1622,81 +1684,4 @@ public static function getResolver($driver) { return static::$resolvers[$driver] ?? null; } - - /** - * Escapes a value for safe SQL embedding. - * - * @param string|float|int|bool|null $value - * @param bool $binary - * @return string - */ - public function escape($value, $binary = false) - { - if ($value === null) { - return 'null'; - } elseif ($binary) { - return $this->escapeBinary($value); - } elseif (is_int($value) || is_float($value)) { - return (string) $value; - } elseif (is_bool($value)) { - return $this->escapeBool($value); - } else { - // As many desktop tools and other programming languages still have problems with null bytes, they are - // forbidden for textual strings to align the support of the different databases: MySQL is the only database - // supporting null bytes within a SQL string in an escaped human-readable format. While PostgreSQL doesn't - // support null bytes, all the other ones use the invisible byte that would be hard to spot when viewing or - // copying SQL queries. - if (str_contains($value, "\00")) { - throw new RuntimeException('Strings with null bytes cannot be escaped. Use the binary escape option.'); - } - - // The documentation of PDO::quote states that it should be theoretically safe to use a quoted string within - // a SQL query. While only being "theoretically" safe this behaviour is used within the PHP MySQL driver all - // the time as no real prepared statements are used because it is emulating prepares by default. So even the - // PHP core developers believes it to be secure. However, Laravel forces the PDO driver to use real prepared - // statements so the default mode is not active for Laravel applications. - // All SQL injections remaining when quoting values are always some strange charset conversion tricks that - // start by using invalid UTF-8 sequences. But those attacks are fixed by setting the proper connection - // charset which is done by the standard Laravel configuration. To further secure the implementation we can - // scrub the value by checking for invalid UTF-8 sequences. - if (false === preg_match('//u', $value)) { - throw new RuntimeException('Strings with invalid UTF-8 byte sequences cannot be escaped.'); - } - - return $this->escapeString($value); - } - } - - /** - * Escapes a string value for safe SQL embedding. - * - * @param string $value - * @return string - */ - protected function escapeString($value) - { - return $this->getPdo()->quote($value); - } - - /** - * Escapes a bool value for safe SQL embedding. - * - * @param bool $value - * @return string - */ - protected function escapeBool($value) - { - return $value ? '1' : '0'; - } - - /** - * Escapes a binary value for safe SQL embedding. - * - * @param string $value - * @return string - */ - protected function escapeBinary($value) - { - throw new RuntimeException('The database connection has no implementation to escape binary values.'); - } } diff --git a/src/Illuminate/Database/Grammar.php b/src/Illuminate/Database/Grammar.php index 0df0dcb60f1f..0d2b0eff42a7 100755 --- a/src/Illuminate/Database/Grammar.php +++ b/src/Illuminate/Database/Grammar.php @@ -15,7 +15,7 @@ abstract class Grammar * * @var \Illuminate\Database\Connection */ - protected $connection = null; + protected $connection; /** * The grammar table prefix. @@ -203,6 +203,22 @@ public function quoteString($value) return "'$value'"; } + /** + * Escapes a value for safe SQL embedding. + * + * @param string|float|int|bool|null $value + * @param bool $binary + * @return string + */ + public function escape($value, $binary = false) + { + if (is_null($this->connection)) { + throw new RuntimeException("The database driver's grammar implementation does not support escaping values."); + } + + return $this->connection->escape($value, $binary); + } + /** * Determine if the given value is a raw expression. * @@ -274,20 +290,4 @@ public function setConnection($connection) return $this; } - - /** - * Escapes a value for safe SQL embedding. - * - * @param string|float|int|bool|null $value - * @param bool $binary - * @return string - */ - public function escape($value, $binary = false) - { - if (null === $this->connection) { - throw new RuntimeException("The database driver's grammar implementation does not support escaping values."); - } - - return $this->connection->escape($value, $binary); - } } diff --git a/src/Illuminate/Database/MySqlConnection.php b/src/Illuminate/Database/MySqlConnection.php index 9858c3fb39ab..2f87b16f5afe 100755 --- a/src/Illuminate/Database/MySqlConnection.php +++ b/src/Illuminate/Database/MySqlConnection.php @@ -13,6 +13,19 @@ class MySqlConnection extends Connection { + /** + * Escape a binary value for safe SQL embedding. + * + * @param string $value + * @return string + */ + protected function escapeBinary($value) + { + $hex = bin2hex($value); + + return "x'{$hex}'"; + } + /** * Determine if the connected database is a MariaDB database. * @@ -30,8 +43,7 @@ public function isMaria() */ protected function getDefaultQueryGrammar() { - $grammar = new QueryGrammar(); - $grammar->setConnection($this); + ($grammar = new QueryGrammar)->setConnection($this); return $this->withTablePrefix($grammar); } @@ -57,8 +69,7 @@ public function getSchemaBuilder() */ protected function getDefaultSchemaGrammar() { - $grammar = new SchemaGrammar(); - $grammar->setConnection($this); + ($grammar = new SchemaGrammar)->setConnection($this); return $this->withTablePrefix($grammar); } @@ -94,17 +105,4 @@ protected function getDoctrineDriver() { return new MySqlDriver; } - - /** - * Escapes a binary value for safe SQL embedding. - * - * @param string $value - * @return string - */ - protected function escapeBinary($value) - { - $hex = bin2hex($value); - - return "x'{$hex}'"; - } } diff --git a/src/Illuminate/Database/PostgresConnection.php b/src/Illuminate/Database/PostgresConnection.php index 1d1d14310e2b..a03b29e3bec2 100755 --- a/src/Illuminate/Database/PostgresConnection.php +++ b/src/Illuminate/Database/PostgresConnection.php @@ -12,6 +12,30 @@ class PostgresConnection extends Connection { + /** + * Escape a binary value for safe SQL embedding. + * + * @param string $value + * @return string + */ + protected function escapeBinary($value) + { + $hex = bin2hex($value); + + return "'\x{$hex}'::bytea"; + } + + /** + * Escape a bool value for safe SQL embedding. + * + * @param bool $value + * @return string + */ + protected function escapeBool($value) + { + return $value ? 'true' : 'false'; + } + /** * Get the default query grammar instance. * @@ -19,8 +43,7 @@ class PostgresConnection extends Connection */ protected function getDefaultQueryGrammar() { - $grammar = new QueryGrammar(); - $grammar->setConnection($this); + ($grammar = new QueryGrammar)->setConnection($this); return $this->withTablePrefix($grammar); } @@ -46,8 +69,7 @@ public function getSchemaBuilder() */ protected function getDefaultSchemaGrammar() { - $grammar = new SchemaGrammar(); - $grammar->setConnection($this); + ($grammar = new SchemaGrammar)->setConnection($this); return $this->withTablePrefix($grammar); } @@ -83,28 +105,4 @@ protected function getDoctrineDriver() { return new PostgresDriver; } - - /** - * Escapes a binary value for safe SQL embedding. - * - * @param string $value - * @return string - */ - protected function escapeBinary($value) - { - $hex = bin2hex($value); - - return "'\x{$hex}'::bytea"; - } - - /** - * Escapes a bool value for safe SQL embedding. - * - * @param bool $value - * @return string - */ - protected function escapeBool($value) - { - return $value ? 'true' : 'false'; - } } diff --git a/src/Illuminate/Database/SQLiteConnection.php b/src/Illuminate/Database/SQLiteConnection.php index 26583eec63d0..6e9df07e97ba 100755 --- a/src/Illuminate/Database/SQLiteConnection.php +++ b/src/Illuminate/Database/SQLiteConnection.php @@ -36,6 +36,19 @@ public function __construct($pdo, $database = '', $tablePrefix = '', array $conf : $this->getSchemaBuilder()->disableForeignKeyConstraints(); } + /** + * Escape a binary value for safe SQL embedding. + * + * @param string $value + * @return string + */ + protected function escapeBinary($value) + { + $hex = bin2hex($value); + + return "x'{$hex}'"; + } + /** * Get the default query grammar instance. * @@ -43,8 +56,7 @@ public function __construct($pdo, $database = '', $tablePrefix = '', array $conf */ protected function getDefaultQueryGrammar() { - $grammar = new QueryGrammar(); - $grammar->setConnection($this); + ($grammar = new QueryGrammar)->setConnection($this); return $this->withTablePrefix($grammar); } @@ -70,8 +82,7 @@ public function getSchemaBuilder() */ protected function getDefaultSchemaGrammar() { - $grammar = new SchemaGrammar(); - $grammar->setConnection($this); + ($grammar = new SchemaGrammar)->setConnection($this); return $this->withTablePrefix($grammar); } @@ -118,17 +129,4 @@ protected function getForeignKeyConstraintsConfigurationValue() { return $this->getConfig('foreign_key_constraints'); } - - /** - * Escapes a binary value for safe SQL embedding. - * - * @param string $value - * @return string - */ - protected function escapeBinary($value) - { - $hex = bin2hex($value); - - return "x'{$hex}'"; - } } diff --git a/src/Illuminate/Database/SqlServerConnection.php b/src/Illuminate/Database/SqlServerConnection.php index f415aaf91130..57d2b20402e0 100755 --- a/src/Illuminate/Database/SqlServerConnection.php +++ b/src/Illuminate/Database/SqlServerConnection.php @@ -54,6 +54,19 @@ public function transaction(Closure $callback, $attempts = 1) } } + /** + * Escape a binary value for safe SQL embedding. + * + * @param string $value + * @return string + */ + protected function escapeBinary($value) + { + $hex = bin2hex($value); + + return "0x{$hex}"; + } + /** * Get the default query grammar instance. * @@ -61,8 +74,7 @@ public function transaction(Closure $callback, $attempts = 1) */ protected function getDefaultQueryGrammar() { - $grammar = new QueryGrammar(); - $grammar->setConnection($this); + ($grammar = new QueryGrammar)->setConnection($this); return $this->withTablePrefix($grammar); } @@ -88,8 +100,7 @@ public function getSchemaBuilder() */ protected function getDefaultSchemaGrammar() { - $grammar = new SchemaGrammar(); - $grammar->setConnection($this); + ($grammar = new SchemaGrammar)->setConnection($this); return $this->withTablePrefix($grammar); } @@ -126,17 +137,4 @@ protected function getDoctrineDriver() { return new SqlServerDriver; } - - /** - * Escapes a binary value for safe SQL embedding. - * - * @param string $value - * @return string - */ - protected function escapeBinary($value) - { - $hex = bin2hex($value); - - return "0x{$hex}"; - } }