【问题标题】:PHP MVC - Why does my route controller give 404s when on live serverPHP MVC - 为什么我的路由控制器在实时服务器上时会给出 404
【发布时间】:2021-06-26 13:27:26
【问题描述】:

我一直在阅读一本书,它通过使用 PHP 和 MySQL 的用户控制应用程序来解释 MVC。据我所知,我的问题是我的 MVC 路由在我使用 localhost 时运行良好,但是当我将相同的代码应用到我的提供程序服务器上的相同结构根目录时 - 它加载索引页面,但随后控制器只是为其他所有内容抛出 404。我的登录表单也没有通过控制器/方法,因此可以通过 $_POST 检索它。这一切都在本地完美运行,只是似乎落在了网络服务器上。 Composer 设置正确,我的 PHP 版本在本地和 Web 服务器上是 7.4。我已经用尽了互联网上的材料,真的只是碰了壁。我会将所有相关代码sn-ps放在下面,任何帮助将不胜感激!

index.php (localhost > webroot)

<?php
//define a directory separator e.g. / or \ depending on the machine
defined('DS') || define('DS', DIRECTORY_SEPARATOR);
define('APPDIR', realpath(__DIR__.'/../app/') .DS);
define('SYSTEMDIR', realpath(__DIR__.'/../system/') .DS);
define('PUBLICDIR', realpath(__DIR__) .DS);
define('ROOTDIR', realpath(__DIR__.'/../') .DS);

//initiate config
$config = App\Config::get();

new System\Route($config);

Config.php(本地主机>应用程序)

<?php
namespace App;

use App\Helpers\Session;

class Config {
    public static function get() {

        //turn on output buffering
        ob_start();

        //turn on sessions
        Session::init();
        
        return [

            //set the namespace for routing
            'namespace' => 'App\Controllers\\',

            //set the default controller
            //set to Home for Default view
            'default_controller' => 'admin',

            //set default method
            'default_method' => 'index',

            //database credentials
            'db_type' => 'mysql',
            'db_host' => 'localhost',
            'db_name' => '***',
            'db_username' => '***',
            'db_password' => '***',
        ];
    }
}

Route.php(本地主机>系统)

<?php
namespace System;

use System\View;

class Route {

    //construct method expects parameter called $config
    public function __construct($config) {

        //hold an array from the requested route (in the form of /page/requested)
        //when explode is run it finds forward slash in the requested URI (made available by $_SERVER)
        $url = explode('/', trim($_SERVER['REQUEST_URI'], '/'));

        //controller uses a ternary operator to check if 0 index of $url exists
        //otherwise default_controller will be used (defined in the config class)
        $controller = !empty($url[0]) ? $url[0] : $config['default_controller'];// Home/Admin

        //method checks for the existence of a $url[1] - or again defaults from config class
        $method = !empty($url[1]) ? $url[1] : $config['default_method']; 

        $args = !empty($url[2]) ? array_slice($url, 2) : array();

        $class = $config['namespace'].$controller;

        //check it the class exists
        if (! class_exists($class)) {
            return $this->not_found();
        }

        //check if the method exists
        if (! method_exists($class, $method)) {
            return $this->not_found();
        }

        //create an instance of the controller
        $classInstance = new $class;

        call_user_func_array(array($classInstance, $method), $args);
    }

    //if the class or method is not found - return a 404
    public function not_found() {
        $view = new View();
        return $view->render('404');
    }
}

Admin.php(本地主机>应用程序>控制器)

<?php

namespace App\Controllers;

use System\BaseController;
use App\Helpers\Session;
use App\Helpers\Url;
use App\Models\User;

class Admin extends BaseController {

    //set class local variable
    protected $user;

    //initialise the User Model by calling new User();
    public function __construct() {
        parent::__construct();

        $this->user = new User();
    }

    //check if logged in
    public function index() {

        //if they are not logged in, redirect to the login method
        //'logged_in' comes from Session::set method
        if (! Session::get('logged_in')) {
            Url::redirect('/admin/login');
        }

        //will set the title for the browser window
        $title = 'Dashboard';

        $this->view->render('admin/auth/login', compact('title'));
    }

    public function login () {

        //check if theres a session in play
        if (Session::get('logged_in')) {
            Url::redirect('/admin');
        }

        //create empty errors array
        $errors = [];

        //check if form has been submitted by checking if $_POST array contains an object called submit
        //$_POST comes from the admin>auth>login.php form
        if (isset($_POST['submit'])) {

            echo "Submitted";
            exit();

            //htmlspec - security measure, stops script tags from being able to be executed(renders as plaintext)
            $username = htmlspecialchars($_POST['username']);
            $password = htmlspecialchars($_POST['password']);

            //call built in function password_verify
            if (password_verify($password, $this->user->get_hash($username)) == false) {
                $errors[] = "Wrong username or password";
            }

            //count the errors, if theres none you can get the data and set the session using Session Helper
            if (count($errors) == 0) {

                //logged in
                $data = $this->user->get_data($username);

                Session::set('logged_in', true);
                Session::set('user_id', $data->id);

                //redirect the user to the admin index page
                Url::redirect("/admin");

            }

        }

        //set the title
        $title = 'Login';

        $this->view->render('admin/auth/login', compact('title', 'errors'));

    }

login.php(本地主机 > 应用程序 > 视图 > 管理员 > 身份验证)

<?php
//include header
include(APPDIR.'views/layouts/header.php');

use App\Controllers\Admin;
?>

<div class="wrapper well">

    <!--wrapper class will be used to position the DIV-->

    <!--include errors to catch any errors or messages -->
    <?php include(APPDIR.'views/layouts/errors.php');?>

    <!--form will have a POST method to send contents to an ACTION URL -->
    <!-- Admin is the class, and login is the method to be called in System\Route-->
    <form action="/admin/login" method="post">

    <h1>Login</h1>

    <!--User Input -->
    <div class="control-group">
        <label class="control-label" for="username"> Username</label>
        <input class="form-control" id="username" type="text" name="username" />
    </div>

    <!--Password Input -->
    <div class="control-group">
        <label class="control-label" for="password"> Password</label>
        <input class="form-control" id="password" type="text" name="password" />
    </div>

    <br>
    <!-- Submit button -->
    <p class="pull-left"><button type="submit" class="btn btn-sm btn-success" name="submit" value="submit">Login</button></p>

    <!-- Reset option-->
    <p class="pull-right"><a href="/admin/reset">Forgot Password</a></p>

    <!-- clear floats -->
    <div class="clearfix"></div>

    </form>

</div>

<!-- footer include -->
<?php include(APPDIR.'views/layouts/footer.php');?>

.htaccess(位于 index.php 中)

# Disable directory snooping
Options -Indexes

<IfModule mod_rewrite.c>

    RewriteEngine On
    RewriteBase /

    # Uncomment the rule below to force HTTPS (SSL)
    RewriteCond %{HTTPS} !on
    #RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

    # Force to exclude the trailing slash
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} (.*)/$
    RewriteRule ^(.+)/$ $1 [R=307,L]

    # Allow any files or directories that exist to be displayed directly
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d

    RewriteRule ^(.*)$ index.php?$1 [QSA,L]


    ErrorDocument 404 /errors/not-found.html
</IfModule>

【问题讨论】:

    标签: php model-view-controller http-status-code-404


    【解决方案1】:

    您需要告诉 Web 服务器通过应用程序的主入口点 (index.php) 路由所有请求。例如,这里是 Laravel 为最常见的 Web 服务器软件(apache 和 nginx)提供的配置。

    # APACHE conf (.htaccess)
    <IfModule mod_rewrite.c>
        <IfModule mod_negotiation.c>
            Options -MultiViews -Indexes
        </IfModule>
    
        RewriteEngine On
    
        # Handle Authorization Header
        RewriteCond %{HTTP:Authorization} .
        RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
    
        # Redirect Trailing Slashes If Not A Folder...
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteCond %{REQUEST_URI} (.+)/$
        RewriteRule ^ %1 [L,R=301]
    
        # Send Requests To Front Controller...
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteRule ^ index.php [L]
    </IfModule>
    
    
    # NGINX conf (app.conf)
    server {
        listen 80;
        index index.php index.html;
        error_log  /var/log/nginx/error.log;
        access_log /var/log/nginx/access.log;
        root /var/www/public;
        location ~ \.php$ {
            try_files $uri =404;
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass coe_da_app:9000;
            fastcgi_index index.php;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_param PATH_INFO $fastcgi_path_info;
        }
        location / {
            try_files $uri $uri/ /index.php?$query_string;
            gzip_static on;
        }
    }
    

    【讨论】:

    • 我在原始帖子中添加了 .htaccess 文件。这就是我在本地服务器上使用的。我不得不承认我不完全理解这些配置中的一些字母在做什么。我已经尝试阅读有关 .htaccess 的信息,但还没有真正找到任何有形的东西。关于我的主人,我可能需要注意哪些明显的地方?此外,它肯定在主机上使用 Apache .htaccess。
    • 划掉上面的评论。今天早上我意识到这个特定的主机实际上使用的是 IIS,而不是 Apache 或 NGINX。所以我只需要弄清楚如何在 web.config 中编写它 - 希望它会一切正常。
    【解决方案2】:

    感谢 Prieber 为我指明了正确的方向。我的问题的解决方案确实是 Web 服务器问题。事实证明,我的主机使用 IIS,所以我需要配置 web.config。以下代码在我的 标签中,我走了!

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
        <system.webServer>
            <rewrite>
                <rules>
                    <rule name="Imported Rule 1" stopProcessing="true">
                        <match url="^" ignoreCase="false" />
                        <conditions logicalGrouping="MatchAll">
                            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" />
                            <add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" />
                        </conditions>
                        <action type="Rewrite" url="index.php" />
                    </rule>
                </rules>
            </rewrite>
        </system.webServer>
    </configuration>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-03-16
      • 2020-12-29
      • 2020-12-04
      • 1970-01-01
      • 2020-12-20
      • 1970-01-01
      • 2016-02-01
      • 1970-01-01
      相关资源
      最近更新 更多