Clamp limit values to be unsigned integers.

This solves large page numbers potentially turning into scientific
notation when being formatted into queries. It also further safeguards
against SQL manipulation.

Refs #GH-1263
This commit is contained in:
mark_story 2013-05-02 22:13:09 -04:00
parent bd3be2877d
commit 2096d3f632
4 changed files with 36 additions and 25 deletions

View file

@ -212,6 +212,9 @@ class PaginatorComponent extends Component {
$pageCount = intval(ceil($count / $limit)); $pageCount = intval(ceil($count / $limit));
$requestedPage = $page; $requestedPage = $page;
$page = max(min($page, $pageCount), 1); $page = max(min($page, $pageCount), 1);
if ($requestedPage > $page) {
throw new NotFoundException();
}
$paging = array( $paging = array(
'page' => $page, 'page' => $page,
@ -234,10 +237,6 @@ class PaginatorComponent extends Component {
array($object->alias => $paging) array($object->alias => $paging)
); );
if ($requestedPage > $page) {
throw new NotFoundException();
}
if ( if (
!in_array('Paginator', $this->Controller->helpers) && !in_array('Paginator', $this->Controller->helpers) &&
!array_key_exists('Paginator', $this->Controller->helpers) !array_key_exists('Paginator', $this->Controller->helpers)

View file

@ -2672,16 +2672,13 @@ class DboSource extends DataSource {
*/ */
public function limit($limit, $offset = null) { public function limit($limit, $offset = null) {
if ($limit) { if ($limit) {
$rt = '';
if (!strpos(strtolower($limit), 'limit')) {
$rt = ' LIMIT'; $rt = ' LIMIT';
}
if ($offset) { if ($offset) {
$rt .= ' ' . $offset . ','; $rt .= sprintf(' %u,', $offset);
} }
$rt .= ' ' . $limit; $rt .= sprintf(' %u', $limit);
return $rt; return $rt;
} }
return null; return null;

View file

@ -896,11 +896,11 @@ class PaginatorComponentTest extends CakeTestCase {
* @expectedException NotFoundException * @expectedException NotFoundException
* @return void * @return void
*/ */
public function testOutOfVeryBigRangePageNumberGetsClamped() { public function testOutOfVeryBigPageNumberGetsClamped() {
$Controller = new PaginatorTestController($this->request); $Controller = new PaginatorTestController($this->request);
$Controller->uses = array('PaginatorControllerPost'); $Controller->uses = array('PaginatorControllerPost');
$Controller->params['named'] = array( $Controller->params['named'] = array(
'page' => 3000000000000000000000000, 'page' => '3000000000000000000000000',
); );
$Controller->constructClasses(); $Controller->constructClasses();
$Controller->PaginatorControllerPost->recursive = 0; $Controller->PaginatorControllerPost->recursive = 0;
@ -910,30 +910,21 @@ class PaginatorComponentTest extends CakeTestCase {
/** /**
* testOutOfRangePageNumberAndPageCountZero * testOutOfRangePageNumberAndPageCountZero
* *
* @expectedException NotFoundException
* @return void * @return void
*/ */
public function testOutOfRangePageNumberAndPageCountZero() { public function testOutOfRangePageNumberAndPageCountZero() {
$Controller = new PaginatorTestController($this->request); $Controller = new PaginatorTestController($this->request);
$Controller->uses = array('PaginatorControllerPost'); $Controller->uses = array('PaginatorControllerPost');
$Controller->params['named'] = array( $Controller->params['named'] = array(
'page' => 3000, 'page' => '3000',
); );
$Controller->constructClasses(); $Controller->constructClasses();
$Controller->PaginatorControllerPost->recursive = 0; $Controller->PaginatorControllerPost->recursive = 0;
$Controller->paginate = array( $Controller->paginate = array(
'conditions' => array('PaginatorControllerPost.id >' => 100) 'conditions' => array('PaginatorControllerPost.id >' => 100)
); );
try {
$Controller->Paginator->paginate('PaginatorControllerPost'); $Controller->Paginator->paginate('PaginatorControllerPost');
} catch (NotFoundException $e) {
$this->assertEquals(
1,
$Controller->request->params['paging']['PaginatorControllerPost']['page'],
'Page number should not be 0'
);
return;
}
$this->fail();
} }
/** /**

View file

@ -1229,4 +1229,28 @@ class DboSourceTest extends CakeTestCase {
$this->assertEquals($expected, $result[0]); $this->assertEquals($expected, $result[0]);
} }
/**
* Test the limit function.
*
* @return void
*/
public function testLimit() {
$db = new DboTestSource;
$result = $db->limit('0');
$this->assertNull($result);
$result = $db->limit('10');
$this->assertEquals(' LIMIT 10', $result);
$result = $db->limit('FARTS', 'BOOGERS');
$this->assertEquals(' LIMIT 0, 0', $result);
$result = $db->limit(20, 10);
$this->assertEquals(' LIMIT 10, 20', $result);
$result = $db->limit(10, 300000000000000000000000000000);
$this->assertEquals(' LIMIT 0, 10', $result);
}
} }