[Slim 4] HttpNotFoundException -- Routes not found when moving application to live server

I have a WordPress website that I have extended with the Slim Framework to provide some custom API. Everything works fine in local, but when I move the application on a live server (SiteGround), if I try to call any of the custom endpoints I get a 404 error Slim\Exception\HttpNotFoundExceptio.

In local the root folder is C:\xampp\htdocs\example\

In remote the root folder is /home/customer/www/example.com/public_html/

This is my folder structure

root\
  api\
    vendor\
    public\
      .htaccess
      index.php
    routes\
      v1\
        autocomplete.php
    .htaccess
    composer.json
    composer.lock
  wp-admin
  wp-content
  wp-includes
  ... all others WordPress files

In local I was able to call the endpoint http://localhost/example/api/v1/autocomplete, while on remote if I call https://www.example.com/api/v1/autocomplete I get a 404 not found error

code: 404
file: "/home/customer/www/example.com/public_html/api/vendor/slim/slim/Slim/Middleware/RoutingMiddleware.php"
line: 91
message: "Not found."
type: "Slim\Exception\HttpNotFoundException"

As per Slim documentation the Apache mod_rewrite is enabled by the default WordPress .htaccess and AllowOverride All is setted by default on all SiteGround server.

Here is the content of the important Slim files

root\api\.htaccess

RewriteEngine on
RewriteRule ^$ public/ [L]
RewriteRule (.*) public/$1 [L]

root\api\public\.htaccess

# Redirect to front controller
RewriteEngine On
# RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L] 

root\api\public\index.php

<?php
use Selective\BasePath\BasePathMiddleware;
use Slim\Factory\AppFactory;

require_once __DIR__ . "/../vendor/autoload.php";

$app = AppFactory::create();

// Add Slim routing middleware
$app->addRoutingMiddleware();

// Set the base path to run the app in a subdirectory.
// This path is used in urlFor().
$app->add(new BasePathMiddleware($app));

$app->addErrorMiddleware(true, true, true);
 
// PUT ALL ROUTES HERE
require_once "../routes/v1/autocomplete.php";

// Run app
$app->run();

root\api\routes\v1\autocomplete.php

<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;

$app->get("/v1/autocomplete", function (Request $request, Response $response) {
  $params = $request->getQueryParams();
  $payload = array(
    "status" => "error",
    "message" => "missing param 'user_input'",
  );
  if (isset($params["user_input"])) {
    $payload = getSuggestions($params);
  }
  $response->getBody()->write(json_encode($payload));
  return $response
    ->withHeader("Content-Type", "application/json");
});

Thanks in advance

Hi @fasenderos

Good idea! It’s better to discuss such complex topics here in the Slim forum then on stackoverflow :wink:

The BasePathMiddleware detects the correct basePath for dev, but not for the prod server.
When you set this on your prod-server it works, but not on your dev, correct?

$app->setBasePath('/api');

Usualy the BasePathMiddleware should detect the correct basePath for both systems.

Is there any other .htaccess file on your prod server that could change the behavior of the routing?

The question is what does the BasePathMiddleware detects on your prod-server?

You can test it by putting this code into the file: public/index.php:

<?php

//(require __DIR__ . '/../config/bootstrap.php')->run();

require_once __DIR__ . '/../vendor/autoload.php';

$detector = new \Selective\BasePath\BasePathDetector($_SERVER);
echo $detector->getBasePath();