PHP内置web服务器的无肥路由

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,所以我认为我的.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';

在路由定义中,您始终需要使用前导斜杠/。它是$f3->route('GET /brew/@count',...),这也在示例中。 - ikkez
我刚刚使用 PHP 5.6 内置的 Web 服务器尝试了完全相同的代码,它可以正常工作。我怀疑你的错误来自于 $_SERVER['SCRIPT_NAME'],在我的情况下是 /index.php。注意:我正在使用框架 edge version,没有任何 .htrouter.php。你的 .htrouter.php 的内容是什么?你尝试跳过它了吗? - xfra35
谢谢xfra35。我刚刚按照指南操作,这应该是非常简单和直接的,不确定哪里出了问题。我的.htrouter.php文件如下:<?php #获取相对URL $uri = urldecode(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)); #如果请求的是真实文件(例如html、image、js、css),则保持原样 if ($uri !== '/' && file_exists(DIR . $uri)) { return false; } #如果请求虚拟URL,则将其传递给引导文件 - index.php $_GET['_url'] = $_SERVER['REQUEST_URI']; require_once DIR . './public/index.php'; - NHG
谢谢xFra35。我在我的帖子中添加了.htrouter.php文件。顺便提一句,我正在使用PHP 7.2。我仅在index.php中包含fatfree的base.php($f3 = require_once(dirname(dirname(FILE)). '/lib/base.php');)。 - NHG
好的,我可以重现你的问题。你的公共文件夹是public/,因此你应该使用-t public/来替换-t ./。同时删掉.htrouter.php,它没有任何帮助。所以最终命令是: php -S 0.0.0.0:8090 -t public/ - xfra35
显示剩余5条评论
3个回答

4

你的问题直接和你使用的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

请注意,应用程序的工作目录取决于您调用命令的文件夹。为了利用这个值,我强烈建议您在public/index.php文件的顶部添加chdir(__DIR__);。这样,所有后续的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'] )。

以下是一个可以与F3一起使用的.htrouter.php示例:

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


xfra35,非常感谢您的努力和详细的解释。您是正确的。由于F3使用$_SERVER['SCRIPT_NAME'],我们最好将其更改为'index.php',而不是更改f3的代码。我更新了我的代码,它可以工作了。此外,在index.php中添加chdir(DIR);绝对是一个好主意,因为它解决了当我添加配置文件时出现的问题(不幸的是,如果提供给$f3->config的配置文件路径/名称无效,f3不会报告任何问题)。 - NHG

0

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

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

如果我们直接将所有请求转发到index.php的Web服务器,则_SERVER ['SCRIPT_NAME'] = / index.php,在这种情况下,基础是''。

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

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

感谢xfra35提供线索。


这不是确切的问题。我会写一个答案来详细说明。另外,我会重命名你的问题,因为该问题明显与PHP内置服务器的行为有关。 - xfra35

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接