codeigniter4 / CodeIgniter4

Open Source PHP Framework (originally from EllisLab)
https://codeigniter.com/
MIT License
5.35k stars 1.9k forks source link

Bug: Invalid handle of PUT data #5364

Closed pawelkg closed 2 years ago

pawelkg commented 2 years ago

PHP Version

8.0

CodeIgniter4 Version

4.1.5

CodeIgniter4 Installation Method

Composer (as dependency to an existing project)

Which operating systems have you tested for this bug?

Linux

Which server did you use?

apache

Database

No response

What happened?

I get my HTML forms and send it with proper HTTP Method by JavaScript code, that looks something like this:

formData = new FormData(form);
let xmlHttpRequest = new XMLHttpRequest();
xmlHttpRequest.open(form.dataset.method, url);
xmlHttpRequest.setRequestHeader('X-Requested-With', 'xmlhttprequest');
xmlHttpRequest.responseType = 'json';
xmlHttpRequest.send(formData);

My example PUT request look something like that: Header (that count here): Content-Type: multipart/form-data; boundary=---------------------------293903230717728861911868140501 Data (in this example email is empty):

-----------------------------293903230717728861911868140501
Content-Disposition: form-data; name="name"

asdf
-----------------------------293903230717728861911868140501
Content-Disposition: form-data; name="email"

-----------------------------293903230717728861911868140501
Content-Disposition: form-data; name="password"

asdf
-----------------------------293903230717728861911868140501
Content-Disposition: form-data; name="active"

1
-----------------------------293903230717728861911868140501--

While getting data via $request->getRawInput() (IncomingRequest Class) I get:

array(2) {
  ["-----------------------------293903230717728861911868140501
Content-Disposition:_form-data"]=>
  string(0) ""
  ["name"]=>
  string(78) ""active"

1
-----------------------------293903230717728861911868140501--
"
}

which is definitely not correct. Adding <input type="hidden" name="_method" value="PUT" /> do not change anything. When subbmiting same form, same code via JavaScript but by POST method, POST data are correct:

array(4) {
  ["name"]=>
  string(4) "asdf"
  ["email"]=>
  string(0) ""
  ["password"]=>
  string(4) "asdf"
  ["active"]=>
  string(1) "1"
}

If I send via POST but add in JavaScript: formData.append('_method', 'PUT'); before send I got proper result (with _method field) from getPost() method and empty array from getRawInput() method.

Steps to Reproduce

Send PUT request base on HTML Form data by ajax like:

formData = new FormData(form);
let xmlHttpRequest = new XMLHttpRequest();
xmlHttpRequest.open('PUT', url);
xmlHttpRequest.setRequestHeader('X-Requested-With', 'xmlhttprequest');
xmlHttpRequest.responseType = 'json';
xmlHttpRequest.send(formData);

Try to read requested data like that in controller:

$data = $this->request->getPost();
$data2 = $this->request->getRawInput();
var_dump($data, $data2);

Expected Output

Array with proper data from getRawInput() or just untouched raw input.

Anything else?

Controller method that handle that request is declared in Config Routes by add method.

kenjis commented 2 years ago

Can't reproduce on develop.

<?php

namespace App\Controllers;

class Home extends BaseController
{
    public function index()
    {
        $data2 = $this->request->getRawInput();
        var_dump($data2);
    }
}
Screenshot 2021-11-21 9 24 22
pawelkg commented 2 years ago

I try to reproduce it on local server also and don't succeed. Then I upload test script to server and then I've got error. On fresh install (I download CI4 from page). My routes config:

$routes->get('/', 'Home::index');
$routes->add('/test', 'Home::test');

My Controller (replace example.com with Yours domain):

<?php

namespace App\Controllers;

class Home extends BaseController
{
    public function index()
    {
        $body = <<<EXAMPLE
<html lang="en">
<body>
<pre id="response"></pre><form><input type="text" name="name"><input type="email" name="email"><input type="password" name="password"><input name="active" value="1" type="checkbox"><button type="submit">Save</button></form>
<script>
document.addEventListener('submit', (e) => {
e.preventDefault();
formData = new FormData(e.target);
let xmlHttpRequest = new XMLHttpRequest();
xmlHttpRequest.open('PUT', 'https://example.com/test');
xmlHttpRequest.send(formData);
xmlHttpRequest.onload = () => {
    document.getElementById('response').innerHTML = xmlHttpRequest.response.replace('\\n', '<br>');
};
});
</script>
</body>
</html>
EXAMPLE;
        $this->response->setBody($body);
        $this->response->send();
    }

    public function test()
    {
        $data = $this->request->getRawInput();
        var_dump($data);
    }
}

My request data:

-----------------------------140165576325122211682143310948
Content-Disposition: form-data; name="name"

Test
-----------------------------140165576325122211682143310948
Content-Disposition: form-data; name="email"

test@example.com
-----------------------------140165576325122211682143310948
Content-Disposition: form-data; name="password"

123
-----------------------------140165576325122211682143310948
Content-Disposition: form-data; name="active"

1
-----------------------------140165576325122211682143310948--

And response:

array(2) {
  ["-----------------------------140165576325122211682143310948
Content-Disposition:_form-data"]=>
  string(0) ""
  ["name"]=>
  string(78) ""active"

1
-----------------------------140165576325122211682143310948--
"
}

My PHP version is 8.0.10.

pawelkg commented 2 years ago

@kenjis Any idea what's happened here?

kenjis commented 2 years ago

@pawelkg I can't reproduce the error.

Screenshot 2021-11-27 8 34 36

kenjis commented 2 years ago

I tried with Nginx server. But can't reproduce it.

Screenshot 2021-11-27 10 25 28

kenjis commented 2 years ago

@pawelkg Can't reproduce the error, so it is not a bug of the framework. It seems depending on your environment.

Please ask your support questions in the forums. Thanks! https://forum.codeigniter.com/forum-30.html