bramus / router

A lightweight and simple object oriented PHP Router

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Broken subroute pattern

latdev opened this issue · comments

Looks like getBasePath bug.

With router definition.
$router->get("/backend/io\.js", 'IoController@actionIndex');

Inside Router.class
private function patternMatches($pattern, $uri, &$matches, $flags)

After executing with

      var_dump($uri);
      // we may have a match!
      return boolval(preg_match_all('#^' . $pattern . '$#', $uri, $matches, PREG_OFFSET_CAPTURE));

Pattern fails with $uri.

string(15) "io.js"

Please do not send JavaScript files via the router! Configure a public folder on your server where you can store static files. If the request fails or the index file gets executed specifically, execute the router 🙂

/js/file.js -> no router
/user/bla -> router
/index.php/user/bla -> router

@uvulpos the backend/io.js might be a server-side generated JS content from PHP, and not a static file.

@kktsvetkov

Normally you do not generate Javascript via PHP and even if you would because you create a Javascript generator website, than it would be possible to name it just something e.x. /download and change the output name by PHP header to e.x. something.js. PHPSpreadsheet does this for example if you want to stream your output.

Example:
https://stackoverflow.com/a/2016016
https://stackoverflow.com/q/58971049

Anyway, if this is such a big deal for you, I can try to fix that by pull request but feel free to do it youself and reference this issue by commit ;)

@latdev you've probably thought of this already but anyway: as a workaround you can use setBasePath to explicitly set the base path and not rely on getBasePath.

@uvulpos The issue is not related directly to JS though, is it? It's about that getBasePath strips the filename from $_SERVER['SCRIPT_NAME']

// Check if server base path is defined, if not define it.
if ($this->serverBasePath === null) {
    $this->serverBasePath = implode('/', array_slice(explode('/', $_SERVER['SCRIPT_NAME']), 0, -1)) . '/';
}

BTW Have you considered using dirname instead of this combination of implode, explode and array_slice here? One function call instead of 3, it is surely going to be faster. I did a quick phpbench test like this:

/**
* @Revs(8000)
* @Iterations(5)
*/
class benchmark_dirname
{
	public $uri = '/bramus/router/issues/172';

	function benchDirname()
	{
		$basePath = dirname($this->uri) . '/';
	}

	function benchImplodeSlideExplode()
	{
		$basePath = implode('/', array_slice(explode('/', $this->uri), 0, -1)) . '/';
	}
}

The dirname approach is 2.3x faster

$ php vendor/bin/phpbench run lab/dirname.php --report=short
PHPBench (1.2.3) running benchmarks...
with configuration file: phpbench.json
with PHP version 7.4.27, xdebug ✔, opcache ❌

\Benchmark_dirname

    benchDirname............................I4 - Mo0.580μs (±4.34%)
    benchImplodeSlideExplode................I4 - Mo1.296μs (±3.58%)

Subjects: 2, Assertions: 0, Failures: 0, Errors: 0
Benchmark_dirname
+--------------------------+---------+---------+---------+---------+---------+--------+
| subject                  | best    | mean    | mode    | worst   | stdev   | rstdev |
+--------------------------+---------+---------+---------+---------+---------+--------+
| benchDirname             | 0.535μs | 0.569μs | 0.580μs | 0.597μs | 0.025μs | ±4.34% |
| benchImplodeSlideExplode | 1.274μs | 1.318μs | 1.296μs | 1.404μs | 0.047μs | ±3.58% |
+--------------------------+---------+---------+---------+---------+---------+--------+