Skip to content

Commit

Permalink
Merge pull request #8756 from kenjis/fix-BaseConnection-escape-TypeError
Browse files Browse the repository at this point in the history
fix: `BaseConnection::escape()` does not accept Stringable
  • Loading branch information
kenjis authored Apr 11, 2024
2 parents 48be4ac + c1ec70f commit 59ec72d
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 25 deletions.
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

0 comments on commit 59ec72d

Please sign in to comment.