Built-in PHP and htaccess – Route System / Friendly URL

Question:

I have a .htaccess file for route diversion on the server (production) and a router.php file for route diversion using PHP 7's Built-in server.

php -S 0.0.0.0:8000 router.php

However, I would like to use router.php in production as well, with the same effect.

My server is managed with WHM and domains with CPanel (also with PHP 7, with the same settings as the location).

Note that it is not just a matter of placing the content in index.php , nor of transferring the responsibility via .htaccess, since the routes file has specific commands, like the famous one…

return false;

…to indicate that router.php should be ignored and go straight to the URI folder.

And that doesn't work in a common access.

Practical example (merely didactic):

Project Folders/Files

1 - /api/execute.php
2 - /admin/
3 - /index.php

Routes (Source URI):

1 - /api/{servico}/{detalhe}
2 - /admin/
3 - /{caminho}/{qualquer}

How is .htaccess (production):

RewriteEngine On
RewriteRule ^api/?.*$ api/execute.php [NC,L]
RewriteRule ^admin/?(.*)$ admin/$1 [NC,L]
RewriteRule ^/?.*$ index.php

How is router.php (local/Built-in):

<?php
if (php_sapi_name() === 'cli-server' && is_file(__DIR__ . parse_url($_SERVER[ 'REQUEST_URI' ], PHP_URL_PATH))) {
    return false;
}

// Inicializa serviço de controle de URI
$uri = new \Config\Uri();

// API
if (preg_match('/^api\/?.*$/', $uri->getUri())) {
    require_once 'api/execute.php';
    exit;
}

// ADMIN
if (preg_match('/^admin\/.*$/', $uri->getUri())) {
    return false;
}

// Site
require_once "index.php";

This is just an example, but notice the use of return false; . All other lines in router.php work both locally and in production.

But the return false; which aims to bypass the router and follow the uri path naturally, doesn't work online obviously.

How to proceed?

Note : This is an old system that still needs support. It's not worth changing his entire route system, since a new system is being created. So I just wanted to use the same router.php tb in production so I don't have to use the custom .htaccess for every domain that uses the system.

Answer:

Let's see if I can help, and if I understand the question correctly.

Here's an excerpt of the code that I use in a framework that I've developed over the years, and that I use in several PHP projects.

First of all, what we want is a single point in PHP that is responsible for all the routing logic, and for that we need to have something like this in the .htaccess file:

RewriteRule ^/?.*$ /pageHandler.php?CUSTOM_HTACCESS_VAR=$1 [QSA,NC,L]

This will redirect all requests to the pageHandler, and all URL data will be accessible in $_GET['CUSTOM_HTACCESS_VAR'] (alternatively This can also be done and accessed through internal PHP variables like $_SERVER['REQUEST_URI'] )

In pageHandler, we create an instance of my parsing class, and call the processPage method.

The content of the Parser class is here (only the relevant part):

<?php
class Parser {
    var $URL;
    var $file; // the current PHP file being used
    var $vars;
    var $path;
    var $timer;
    var $fullPathExists = true;

    function __construct() {
        $this->requestID = uniqid(md5(rand()), true);

        $varName = "CUSTOM_HTACCESS_VAR";
        $this->URL = array();
        if (isset($_GET[$varName])) {
            if (substr($_GET[$varName], 0, 1) == "/") $_GET[$varName] = substr($_GET[$varName], 1);
            $url = explode("/", $_GET[$varName]);
            $this->URL = $url;
        }

        unset($_GET[$varName]);
        $this->vars = array();
        $this->path = array();

        $dir = "{$_SERVER['DOCUMENT_ROOT']}/Pages/";
        $tamanhoURL = count($this->URL);
        for($i = 0; $i < $tamanhoURL; $i++) {
            $tempDir = "{$dir}{$this->URL[$i]}/";
            if (!is_dir($tempDir)) {
                break;
            }
            $dir = $tempDir;
            $this->path[] = $this->URL[$i];
        }

        # verifica se existe dentro da ultima pasta um ficheiro com o nome que nao é o index
        if (($i < $tamanhoURL) && file_exists("{$dir}{$this->URL[$i]}.php")) {
            $file = "{$dir}{$this->URL[$i]}.php";
            $script = $this->URL[$i];
            $this->path[] = $this->URL[$i];
            $i++;
        }
        else {
            $file = "{$dir}index.php";
            $script = "index";
        }

        $this->file = $file;

        for (;$i < $tamanhoURL - 1; $i++) {
            $this->vars[$this->URL[$i]] = $this->URL[++$i];
            $this->fullPathExists = false;
        }
        if ($i < $tamanhoURL) {
            $this->vars['SINGLE'] = $this->URL[$i];
            $this->fullPathExists = false;
        }

    }


    function processPage() {
        if (file_exists($this->file)) {
            require($this->file);
        }
        else {
            header("HTTP/1.0 404 Not Found");
            header("Status: 404 Not Found");
        }
    }
}
?>

I hope it helps. You may have to adapt the code to work on those sites that already have their own structure, which may differ from the one I use.

It should also be noted that this class stores in a variable named vars all parts of the URL that do not correspond to a file, and that can be used in an MVC framework perspective.

For example, the URL /test/foo/do/action can be used to load the file /test/foo.php, and in the variable vars there is an element, named 'do' with the value 'action'.

Scroll to Top