Skip to content

Commit d0a580a

Browse files
committed
Merge branch 'develop' into magic-issets
2 parents d815ab7 + 91fde05 commit d0a580a

7 files changed

Lines changed: 211 additions & 20 deletions

File tree

system/Database/MySQLi/Connection.php

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,8 +389,49 @@ protected function _escapeString(string $str): string
389389

390390
//--------------------------------------------------------------------
391391

392+
/**
393+
* Escape Like String Direct
394+
* There are a few instances where MySQLi queries cannot take the
395+
* additional "ESCAPE x" parameter for specifying the escape character
396+
* in "LIKE" strings, and this handles those directly with a backslash.
397+
*
398+
* @param string|string[] $str Input string
399+
* @return string|string[]
400+
*/
401+
public function escapeLikeStringDirect($str)
402+
{
403+
if (is_array($str))
404+
{
405+
foreach ($str as $key => $val)
406+
{
407+
$str[$key] = $this->escapeLikeStringDirect($val);
408+
}
409+
410+
return $str;
411+
}
412+
413+
$str = $this->_escapeString($str);
414+
415+
// Escape LIKE condition wildcards
416+
return str_replace([
417+
$this->likeEscapeChar,
418+
'%',
419+
'_',
420+
], [
421+
'\\' . $this->likeEscapeChar,
422+
'\\' . '%',
423+
'\\' . '_',
424+
], $str
425+
);
426+
427+
return $str;
428+
}
429+
430+
//--------------------------------------------------------------------
431+
392432
/**
393433
* Generates the SQL for listing tables in a platform-dependent manner.
434+
* Uses escapeLikeStringDirect().
394435
*
395436
* @param boolean $prefixLimit
396437
*
@@ -402,7 +443,7 @@ protected function _listTables(bool $prefixLimit = false): string
402443

403444
if ($prefixLimit !== false && $this->DBPrefix !== '')
404445
{
405-
return $sql . " LIKE '" . $this->escapeLikeString($this->DBPrefix) . "%'";
446+
return $sql . " LIKE '" . $this->escapeLikeStringDirect($this->DBPrefix) . "%'";
406447
}
407448

408449
return $sql;

system/Database/SQLite3/Connection.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ protected function _escapeString(string $str): string
207207
protected function _listTables(bool $prefixLimit = false): string
208208
{
209209
return 'SELECT "NAME" FROM "SQLITE_MASTER" WHERE "TYPE" = \'table\''
210-
. ' AND "NAME" NOT LIKE \'sqlite_%\''
210+
. ' AND "NAME" NOT LIKE \'sqlite!_%\' ESCAPE \'!\''
211211
. (($prefixLimit !== false && $this->DBPrefix !== '')
212212
? ' AND "NAME" LIKE \'' . $this->escapeLikeString($this->DBPrefix) . '%\' ' . sprintf($this->likeEscapeStr,
213213
$this->likeEscapeChar)

system/Session/Session.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,8 @@ protected function configure()
304304
$this->sessionExpiration, $this->cookiePath, $this->cookieDomain, $this->cookieSecure, true // HTTP only; Yes, this is intentional and not configurable for security reasons.
305305
);
306306

307-
if (empty($this->sessionExpiration))
307+
//if (empty($this->sessionExpiration))
308+
if (!isset($this->sessionExpiration))
308309
{
309310
$this->sessionExpiration = (int) ini_get('session.gc_maxlifetime');
310311
}

tests/system/Database/BaseConnectionTest.php

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -128,21 +128,4 @@ public function testStoresConnectionTimings()
128128
$this->assertGreaterThan($start, $db->getConnectStart());
129129
$this->assertGreaterThan(0.0, $db->getConnectDuration());
130130
}
131-
132-
//--------------------------------------------------------------------
133-
134-
/**
135-
* Ensures we don't have escaped - values...
136-
*
137-
* @see https://github.com/codeigniter4/CodeIgniter4/issues/606
138-
*/
139-
public function testEscapeProtectsNegativeNumbers()
140-
{
141-
$db = new MockConnection($this->options);
142-
143-
$db->initialize();
144-
145-
$this->assertEquals("'-100'", $db->escape(-100));
146-
}
147-
148131
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<?php namespace CodeIgniter\Database\Live;
2+
3+
use CodeIgniter\Test\CIDatabaseTestCase;
4+
5+
/**
6+
* @group DatabaseLive
7+
*/
8+
class EscapeTest extends CIDatabaseTestCase
9+
{
10+
protected $refresh = false;
11+
12+
protected $char;
13+
14+
protected function setUp()
15+
{
16+
parent::setUp();
17+
18+
$this->char = $this->db->DBDriver === 'MySQLi' ? '\\' : "'";
19+
}
20+
21+
//--------------------------------------------------------------------
22+
23+
/**
24+
* Ensures we don't have escaped - values...
25+
*
26+
* @see https://github.com/codeigniter4/CodeIgniter4/issues/606
27+
*/
28+
public function testEscapeProtectsNegativeNumbers()
29+
{
30+
$this->assertEquals("'-100'", $this->db->escape(-100));
31+
}
32+
33+
//--------------------------------------------------------------------
34+
35+
public function testEscape()
36+
{
37+
$expected = "SELECT * FROM brands WHERE name = 'O" . $this->char . "'Doules'";
38+
$sql = "SELECT * FROM brands WHERE name = " . $this->db->escape("O'Doules");
39+
40+
$this->assertEquals($expected, $sql);
41+
}
42+
43+
//--------------------------------------------------------------------
44+
45+
public function testEscapeString()
46+
{
47+
$expected = "SELECT * FROM brands WHERE name = 'O" . $this->char . "'Doules'";
48+
$sql = "SELECT * FROM brands WHERE name = '" . $this->db->escapeString("O'Doules") . "'";
49+
50+
$this->assertEquals($expected, $sql);
51+
}
52+
53+
//--------------------------------------------------------------------
54+
55+
public function testEscapeLikeString()
56+
{
57+
$expected = "SELECT * FROM brands WHERE column LIKE '%10!% more%' ESCAPE '!'";
58+
$sql = "SELECT * FROM brands WHERE column LIKE '%" . $this->db->escapeLikeString("10% more") . "%' ESCAPE '!'";
59+
60+
$this->assertEquals($expected, $sql);
61+
}
62+
63+
//--------------------------------------------------------------------
64+
65+
public function testEscapeLikeStringDirect()
66+
{
67+
if ($this->db->DBDriver === 'MySQLi')
68+
{
69+
$expected = "SHOW COLUMNS FROM brands WHERE column LIKE 'wild\_chars%'";
70+
$sql = "SHOW COLUMNS FROM brands WHERE column LIKE '". $this->db->escapeLikeStringDirect("wild_chars") . "%'";
71+
72+
$this->assertEquals($expected, $sql);
73+
}
74+
else
75+
{
76+
$this->expectNotToPerformAssertions();
77+
}
78+
}
79+
}

tests/system/Database/Live/ForgeTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,8 @@ public function testCreateTableWithArrayFieldConstraints()
163163
{
164164
$this->assertEquals('enum', $fields[0]->type);
165165
}
166+
167+
$this->forge->dropTable('forge_array_constraint', true);
166168
}
167169
else
168170
{
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<?php namespace CodeIgniter\Database\Live;
2+
3+
use CodeIgniter\Test\CIDatabaseTestCase;
4+
5+
/**
6+
* @group DatabaseLive
7+
*/
8+
class MetadataTest extends CIDatabaseTestCase
9+
{
10+
protected $refresh = true;
11+
12+
protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder';
13+
14+
/**
15+
* Array of expected tables.
16+
*
17+
* @var array
18+
*/
19+
protected $expectedTables;
20+
21+
protected function setUp()
22+
{
23+
parent::setUp();
24+
25+
// Prepare the array of expected tables once
26+
$prefix = $this->db->getPrefix();
27+
$this->expectedTables = [
28+
$prefix . 'migrations',
29+
$prefix . 'user',
30+
$prefix . 'job',
31+
$prefix . 'misc',
32+
$prefix . 'empty',
33+
$prefix . 'secondary'
34+
];
35+
}
36+
37+
public function testListTables()
38+
{
39+
$result = $this->db->listTables();
40+
41+
$this->assertEquals($this->expectedTables, array_values($result));
42+
}
43+
44+
//--------------------------------------------------------------------
45+
46+
public function testListTablesConstrainPrefix()
47+
{
48+
$result = $this->db->listTables(true);
49+
50+
$this->assertEquals($this->expectedTables, array_values($result));
51+
}
52+
53+
//--------------------------------------------------------------------
54+
55+
public function testConstrainPrefixIgnoresOtherTables()
56+
{
57+
$this->forge = \Config\Database::forge($this->DBGroup);
58+
59+
// Stash the prefix and change it
60+
$DBPrefix = $this->db->getPrefix();
61+
$this->db->setPrefix('tmp_');
62+
63+
// Create a table with the new prefix
64+
$fields = [
65+
'name' => ['type' => 'varchar', 'constraint' => 31],
66+
'created_at' => ['type' => 'datetime', 'null' => true],
67+
];
68+
$this->forge->addField($fields);
69+
$this->forge->createTable('widgets');
70+
71+
// Restore the prefix and get the tables with the original prefix
72+
$this->db->setPrefix($DBPrefix);
73+
$result = $this->db->listTables(true);
74+
75+
$this->assertEquals($this->expectedTables, array_values($result));
76+
77+
// Clean up temporary table
78+
$this->db->setPrefix('tmp_');
79+
$this->forge->dropTable('widgets');
80+
$this->db->setPrefix($DBPrefix);
81+
}
82+
83+
//--------------------------------------------------------------------
84+
85+
}

0 commit comments

Comments
 (0)