0

So some background - I've decided to split an old PHP MVC project into a React frontend and php backend "server". For development - both are hosted locally, both are configured on different apache roots with some dummy hosts (api.loc/exp.loc) which are added in /etc/hosts. The so called "API server" uses an MVC Routing, which gets the requests /foo/bar and launches FooController->barAction().

For the API I send POST requests first through the fetch API, then through axios, both of which failed, and I discovered (using both xDebug and printing the $_POST as response), that PHP receives no $_POST. Nothing - empty array. I tried using the RESTClient addon for firefox to fire POST requests to the "server" and I get the same result.

In an attempt to fix the issue, after some research I've added the following headers on my index.php file, but to be honest I'm not 100% certain of their exact role.

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST');
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Max-Age: 86400');
header('Access-Control-Allow-Headers: Content-Type');
header('Content-Type: application/json');

Playing with these barely made any difference. This is how the routing is done (index.php):

$router = new Core\Router();

$url = $_SERVER['REQUEST_URI'];
$router->dispatch($url);

Router.php

    public function dispatch($url)
    {
        $route = $this->extractRoute($url);
        $controller = 'Application\Controllers\\' . $this->convertToStudlyCaps($route['controller']);
        $action = $this->convertToCamelCase($route['action']);
        $params = $route['params'];
        $params = count($params) > 0 ? $this->processParams($route['params']) : null;
        if (class_exists($controller)) {
            $Controller = new $controller();
            $callableAction = $action.'Action';
            if (is_callable([$Controller, $callableAction])) {
                $Controller->$callableAction($params);
            } else {
                echo json_encode("Invalid method [ {$action} ] specified");
            }
        } else {
            echo json_encode("Invalid controller specified: [ {$controller} ]");
        }
    }

    public function extractRoute($url)
    {
        $urlArray = explode('/', $url);

        $result = [];
        $result['controller'] = (array_key_exists(1, $urlArray) && $urlArray[1] !== '') ? $urlArray[1] : 'Index';
        $result['action'] = (array_key_exists(2, $urlArray) && $urlArray[2] !== '') ? $urlArray[2] : 'index';
        $result['params'] = array_slice($urlArray, 3);

        return $result;
    }

The requests reach the controller, but as stated above - with no $_POST available. $_GET receives only 'url' => '{urlpath}', regardless if I use $_GET.

I've checked php.ini post_max_size = 8M

So after some searching - I found a workaround, I can extract the $_POST data using

$data = file_get_contents('php://input');

What I really need help with is understanding why. I don't understand why there's no $_POST. I obviously lack the knowledge on what the exact problem is and I would greatly appreciate it if someone can point me in the right direction. Thank you in advance!

  • Your added headers are for _response_ and issue is with _request_ sending `Content-Type` header that is not compatible with PHP POST method, that's why it's found only in `php://input` – Justinas Sep 02 '21 at 09:24

1 Answers1

4

For the purposes of populating $_POST, PHP only supports the data formats that HTML forms support. i.e. application/x-www-form-urlencoded and multipart/form-data.

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • that was something interesting I did not know! Just tested with RESTClient sending with `application/x-www-form-urlencoded` and the data was in the $_POST. Seems I'll need to read through more about building API... Thanks for your input! – Petar Stoyanov Sep 02 '21 at 09:59