PHPJunior
PHPJunior

Reputation: 75

CakePHP 3: Error while passing an array in URL

I am trying to pass datetime variables into my exportcsv method to generate .csv file with data from indicated time period.

Both variables are associative arrays that look like this:

[
 'beginning' => [
    'year' => '2016',
    'month' => '06',
    'day' => '23',
    'hour' => '11',
    'minute' => '15'
  ],
  'end' => [
    'year' => '2016',
    'month' => '06',
    'day' => '29',
    'hour' => '11',
    'minute' => '15'
   ]
]

When I try to pass variables I get an error with this message (yep, I've got the same two warnings):

Warning (2): rawurlencode() expects parameter 1 to be string, array given [CORE\src\Routing\Route\Route.php, line 574]

Warning (2): rawurlencode() expects parameter 1 to be string, array given [CORE\src\Routing\Route\Route.php, line 574]

rawurlencode() is a basic PHP function and this is the line 574:

$pass = implode('/', array_map('rawurlencode', $pass));

It looks like some problem with URL rewriting, but frankly I don't know how to fix it. Any ideas?

exportcsv method in EventsController

public function exportcsv($beginning = null, $end = null)
{
 if ($this->request->is('post')) {
  $beginning = $this->request->data['Export']['beginning']; 
  $end = $this->request->data['Export']['end'];              

  return $this->redirect([$beginning, $end]);
 }

 if (!$beginning && !$end) {
  return $this->render();
 }

 $this->response->download('export.csv');
$data = $this->Events->find('all')
                          ->select([
                            'title',
                            'created',
                            'description',
                            'ended',
                            'working_hours',
                            'price',
                            'username' => 'Users.name',
                            'statusname' => 'Statuses.name',
                            'employeename' => 'Employees.name'
                          ])
                          ->leftJoinWith('Statuses')
                          ->leftJoinWith('Users')
                          ->leftJoinWith('Employees')
                          ->where(["created BETWEEN " . $beginning . " AND " . $end])
                          ->autoFields(true)
                          ->toArray();
$_serialize = 'data';
$_delimiter = chr(9); //tab
$_extract = ['title', 'created', 'description', 'ended', 'working_hours', 'price', 'username', 'statusname', 'employeename'];
$this->set(compact('data', '_serialize','_delimiter', '_extract'));
$this->viewBuilder()->className('CsvView.Csv');
return;
}

exportcsv.ctp view:

<div class="events form large-6 medium-4 columns content">
  <?= $this->Form->create('Export'); ?>
  <?= $this->Form->input('beginning', array('type'=>'datetime', 'interval' => 15, 'label' => 'Beginning:')); ?>
  <?= $this->Form->input('end', array('type'=>'datetime',  'interval' => 15, 'label' => 'End:')); ?>
  <?= $this->Form->button(__('Add')) ?>
  <?= $this->Form->end() ?>
</div>

Upvotes: 1

Views: 1135

Answers (2)

ndm
ndm

Reputation: 60463

You cannot pass arrays in a URL array, the router doesn't support that. Also you need to additionally pass Instead, convert your single values to proper datetime strings, you could easily do that via the DateTimeType class, something like

if ($this->request->is('post')) {
    $beginning = $this->request->data('Export.beginning');
    $end = $this->request->data('Export.end');

    $type = \Cake\Database\Type::build('datetime');
    $beginning = $type->marshal($beginning)->format('Y-m-d H:i:s');
    $end = $type->marshal($end)->format('Y-m-d H:i:s');

    return $this->redirect([
        $beginning,
        $end
    ]);
}

Also, as already mentioned in the comments, you need to fix your where() call, as currently it has an SQL injection vulnerability. The keys of key => value items, as well as value only items, are not going to be bound, but inserted into the query directly!

Cakes expression builder ships with methods to safely generate BETWEEN expressions:

->where(function(\Cake\Database\Expression\QueryExpression $exp) use ($beginning, $end) {
    return $exp->between('Events.created', $beginning, $end);
});

See also

Upvotes: 1

Alex Stallen
Alex Stallen

Reputation: 2252

your redirect is wrong

return $this->redirect([
    'controller' => 'yourController', 
    'action' => 'yourAction', 
    $yourData]
);

see the Cookbook for more information on this topic

Upvotes: 0

Related Questions