3

我正在学习 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 的内置 Web 服务器,并且由于 $_SERVER['REQUEST_URI'] (由 base.php 使用)返回正确的 URI,我认为我的 URL 重写没有任何问题.htrouter.php。

任何想法?我在这里错过了什么?

在此处添加 .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';
4

2 回答 2

2

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

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

URI 请求是从 PHP 启动的当前工作目录提供的,除非 -t 选项用于指定显式文档根目录。如果 URI 请求未指定文件,则返回给定目录中的 index.php 或 index.html。如果两个文件都不存在,则在父目录中继续查找 index.php 和 index.html,依此类推,直到找到一个或到达文档根目录。如果找到 index.php 或 index.html,则返回它并将 $_SERVER['PATH_INFO'] 设置为 URI 的尾部。否则返回 404 响应代码。

如果在启动 Web 服务器时在命令行上给出了 PHP 文件,则将其视为“路由器”脚本。该脚本在每个 HTTP 请求开始时运行。如果此脚本返回 FALSE,则按原样返回请求的资源。否则脚本的输出将返回给浏览器。

这意味着,默认情况下(没有路由器脚本),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

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

路由文件样式的 URI

默认情况下,内置服务器不会将不存在的文件URI 传递给您的index.php,如下所述:

如果 URI 请求未指定文件,则返回给定目录中的 index.php 或 index.html

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

$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__

于 2018-09-01T18:59:17.670 回答
0

好的,我检查了 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 是 ''。

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

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

感谢 xfra35 提供线索。

于 2018-09-01T06:59:24.607 回答