Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: BaseConnection::escape() does not accept Stringable #8756

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions system/Database/BaseConnection.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use CodeIgniter\Database\Exceptions\DatabaseException;
use CodeIgniter\Events\Events;
use stdClass;
use Stringable;
use Throwable;

/**
Expand Down Expand Up @@ -1309,12 +1310,15 @@ public function escape($str)
return array_map($this->escape(...), $str);
}

/** @psalm-suppress NoValue I don't know why ERROR. */
if (is_string($str) || (is_object($str) && method_exists($str, '__toString'))) {
if ($str instanceof Stringable) {
if ($str instanceof RawSql) {
return $str->__toString();
}

$str = (string) $str;
}

if (is_string($str)) {
return "'" . $this->escapeString($str) . "'";
}

Expand All @@ -1328,8 +1332,8 @@ public function escape($str)
/**
* Escape String
*
* @param list<string>|string $str Input string
* @param bool $like Whether or not the string will be used in a LIKE condition
* @param list<string|Stringable>|string|Stringable $str Input string
* @param bool $like Whether the string will be used in a LIKE condition
*
* @return list<string>|string
*/
Expand All @@ -1343,6 +1347,14 @@ public function escapeString($str, bool $like = false)
return $str;
}

if ($str instanceof Stringable) {
if ($str instanceof RawSql) {
return $str->__toString();
}

$str = (string) $str;
}

$str = $this->_escapeString($str);

// escape LIKE condition wildcards
Expand Down Expand Up @@ -1371,7 +1383,7 @@ public function escapeString($str, bool $like = false)
* Calls the individual driver for platform
* specific escaping for LIKE conditions
*
* @param list<string>|string $str
* @param list<string|Stringable>|string|Stringable $str
*
* @return list<string>|string
*/
Expand Down
9 changes: 6 additions & 3 deletions system/Database/Postgre/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use PgSql\Connection as PgSqlConnection;
use PgSql\Result as PgSqlResult;
use stdClass;
use Stringable;

/**
* Connection for Postgre
Expand Down Expand Up @@ -233,20 +234,22 @@ public function escape($str)
$this->initialize();
}

/** @psalm-suppress NoValue I don't know why ERROR. */
if (is_string($str) || (is_object($str) && method_exists($str, '__toString'))) {
if ($str instanceof Stringable) {
if ($str instanceof RawSql) {
return $str->__toString();
}

$str = (string) $str;
}

if (is_string($str)) {
return pg_escape_literal($this->connID, $str);
}

if (is_bool($str)) {
return $str ? 'TRUE' : 'FALSE';
}

/** @psalm-suppress NoValue I don't know why ERROR. */
return parent::escape($str);
}

Expand Down
35 changes: 18 additions & 17 deletions system/I18n/Time.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,34 @@
namespace CodeIgniter\I18n;

use DateTimeImmutable;
use Stringable;

/**
* A localized date/time package inspired
* by Nesbot/Carbon and CakePHP/Chronos.
*
* Requires the intl PHP extension.
*
* @property int $age read-only
* @property string $day read-only
* @property string $dayOfWeek read-only
* @property string $dayOfYear read-only
* @property bool $dst read-only
* @property string $hour read-only
* @property bool $local read-only
* @property string $minute read-only
* @property string $month read-only
* @property string $quarter read-only
* @property string $second read-only
* @property int $timestamp read-only
* @property bool $utc read-only
* @property string $weekOfMonth read-only
* @property string $weekOfYear read-only
* @property string $year read-only
* @property-read int $age
* @property-read string $day
* @property-read string $dayOfWeek
* @property-read string $dayOfYear
* @property-read bool $dst
* @property-read string $hour
* @property-read bool $local
* @property-read string $minute
* @property-read string $month
* @property-read string $quarter
* @property-read string $second
* @property-read int $timestamp
* @property-read bool $utc
* @property-read string $weekOfMonth
* @property-read string $weekOfYear
* @property-read string $year
*
* @see \CodeIgniter\I18n\TimeTest
*/
class Time extends DateTimeImmutable
class Time extends DateTimeImmutable implements Stringable
{
use TimeTrait;
}
27 changes: 27 additions & 0 deletions tests/system/Database/Live/EscapeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
namespace CodeIgniter\Database\Live;

use CodeIgniter\Database\RawSql;
use CodeIgniter\I18n\Time;
use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\DatabaseTestTrait;

Expand Down Expand Up @@ -54,6 +55,14 @@ public function testEscape(): void
$this->assertSame($expected, $sql);
}

public function testEscapeStringable(): void
{
$expected = "SELECT * FROM brands WHERE name = '2024-01-01 12:00:00'";
$sql = 'SELECT * FROM brands WHERE name = ' . $this->db->escape(new Time('2024-01-01 12:00:00'));

$this->assertSame($expected, $sql);
}

public function testEscapeString(): void
{
$expected = "SELECT * FROM brands WHERE name = 'O" . $this->char . "'Doules'";
Expand All @@ -62,6 +71,15 @@ public function testEscapeString(): void
$this->assertSame($expected, $sql);
}

public function testEscapeStringStringable(): void
{
$expected = "SELECT * FROM brands WHERE name = '2024-01-01 12:00:00'";
$sql = "SELECT * FROM brands WHERE name = '"
. $this->db->escapeString(new Time('2024-01-01 12:00:00')) . "'";

$this->assertSame($expected, $sql);
}

public function testEscapeLikeString(): void
{
$expected = "SELECT * FROM brands WHERE column LIKE '%10!% more%' ESCAPE '!'";
Expand All @@ -70,6 +88,15 @@ public function testEscapeLikeString(): void
$this->assertSame($expected, $sql);
}

public function testEscapeLikeStringStringable(): void
{
$expected = "SELECT * FROM brands WHERE column LIKE '%2024-01-01 12:00:00%' ESCAPE '!'";
$sql = "SELECT * FROM brands WHERE column LIKE '%"
. $this->db->escapeLikeString(new Time('2024-01-01 12:00:00')) . "%' ESCAPE '!'";

$this->assertSame($expected, $sql);
}

public function testEscapeLikeStringDirect(): void
{
if ($this->db->DBDriver === 'MySQLi') {
Expand Down
Loading