Fatfree 路由 PHP 内置网络服务器

Fatfree routing with PHP built-in web server

我正在学习 fatfree 的路线,发现它的行为异常。

这是我在 index.php 中的代码:

$f3 = require_once(dirname(dirname(__FILE__)). '/lib/base.php');
$f3 = \Base::instance();

echo 'received uri: '.$_SERVER['REQUEST_URI'].'<br>';

$f3->route('GET /brew/@count',
    function($f3,$params) {
        echo $params['count'].' bottles of beer on the wall.';
    }
);

$f3->run();

这是我访问的 URL:http://xx.xx.xx.xx:8090/brew/12

我收到 404 错误:

received uri: /brew/12
Not Found

HTTP 404 (GET /12)

奇怪的是 F3 中的 URI 现在是“/12”而不是“/brew/12”,我想这就是问题所在。

当我检查 base.php (3.6.5) 时,$this->hive['BASE'] = "/brew" 和 $this->hive['PATH'] =“/12”。 但是如果F3只用$this->hive['PATH']去匹配预定义的路由,是匹配不到的。

如果我将路线更改为:

$f3->route('GET /brew',

并使用 URL: http://xx.xx.xx.xx:8090/brew,然后路由匹配没有问题。 在这种情况下,$this->hive['BASE'] = "" 和 $this->hive['PATH'] = "/brew"。如果 F3 将 $this->hive['PATH'] 与预定义路由进行比较,则它们相互匹配。

顺便说一句,我正在使用 PHP 的内置网络服务器,并且由于 $_SERVER['REQUEST_URI'](由 base.php 使用)returns正确的 URI,我认为我的 .htrouter.php.

中的 URL 重写没有任何问题

有什么想法吗?我在这里错过了什么?

在此处添加.htrouter.php的内容

<?php

#get the relative URL
$uri = urldecode(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH));

#if request to a real file (such as a html, image, js, css) then leave it as it is
if ($uri !== '/' && file_exists(__DIR__  . $uri)) {
    return false;
}

#if request virtual URL then pass it to the bootstrap file - index.php
$_GET['_url'] = $_SERVER['REQUEST_URI'];
require_once __DIR__ . './public/index.php';

好的,我检查了 base.php 发现 f3 计算基本 URI 时,它使用 $_SERVER['SCRIPT_NAME'].

$base='';
if (!$cli)
    $base=rtrim($this->fixslashes(
        dirname($_SERVER['SCRIPT_NAME'])),'/');

如果我们让 web 服务器直接将所有请求转发到 index.php,那么 _SERVER['SCRIPT_NAME'] = /index.php,在这种情况下,base 是 ''.

如果我们使用 URL 通过 .htrouter.php 重写为 index.php,那么 _SERVER['SCRIPT_NAME'] = /brew/12,在这种情况下,基础是导致问题的 '/brew'。

因为我要使用 URL 重写,所以我必须注释掉 if 语句并确保 base =''.

感谢 xfra35 提供线索。

您的问题与您使用 PHP 内置网络服务器的方式直接相关。

PHP docs 中所述,服务器处理请求的方式如下:

URI requests are served from the current working directory where PHP was started, unless the -t option is used to specify an explicit document root. If a URI request does not specify a file, then either index.php or index.html in the given directory are returned. If neither file exists, the lookup for index.php and index.html will be continued in the parent directory and so on until one is found or the document root has been reached. If an index.php or index.html is found, it is returned and $_SERVER['PATH_INFO'] is set to the trailing part of the URI. Otherwise a 404 response code is returned.

If a PHP file is given on the command line when the web server is started it is treated as a "router" script. The script is run at the start of each HTTP request. If this script returns FALSE, then the requested resource is returned as-is. Otherwise the script's output is returned to the browser.

这意味着,默认情况下(没有路由器脚本),Web 服务器在将不存在的 URI 路由到您的文档根目录方面做得很好 index.php文件。

换句话说,如果您的文件结构如下:

lib/
    base.php
    template.php
    etc.
public/
    index.php

以下命令足以启动您的服务器并将请求正确分派给框架:

php -S 0.0.0.0:8090 -t public/

或者如果您是 运行 直接来自 public/ 文件夹的命令:

cd public
php -S 0.0.0.0:8090

请注意,应用程序的工作目录取决于调用命令的文件夹。为了利用这个值,我强烈建议您在 public/index.php 文件的顶部添加 chdir(__DIR__);。这样,所有后续 require 调用都将与您的 public/ 文件夹相关。例如:$f3 = require('../lib/base.php');

路由文件样式 URI

内置服务器默认不会将不存在的文件 URI 传递给您的index.php,因为载于:

If a URI request does not specify a file, then either index.php or index.html in the given directory are returned

所以如果你打算用点来定义一些路由,比如:

$f3->route('GET /brew.json','Brew->json');
$f3->route('GET /brew.html','Brew->html');

那么它将无法工作,因为 PHP 不会将请求传递给 index.php

在这种情况下,您需要调用自定义路由器,例如您尝试使用的 .htrouter.php。唯一的问题是你的 .htrouter.php 显然是为不同的框架设计的(F3 不关心 $_GET['url'] 但关心 $_SERVER['SCRIPT_NAME'].

这里有一个 .htrouter.php 的例子,它应该与 F3 一起使用:

// public directory definition
$public_dir=__DIR__.'/public';

// serve existing files as-is
if (file_exists($public_dir.$_SERVER['REQUEST_URI']))
    return FALSE;

// patch SCRIPT_NAME and pass the request to index.php
$_SERVER['SCRIPT_NAME']='index.php';
require($public_dir.'/index.php');

注意:$public_dir 变量应相应地设置为 .htrouter.php 文件的位置。

例如,如果您调用:

php -S 0.0.0.0:8090 -t public/ .htrouter.php

应该是$public_dir=__DIR__.'/public'.

但是如果你调用:

cd public
php -S 0.0.0.0:8090 .htrouter.php

应该是$public_dir=__DIR__.