简体   繁体   English

PHP MVC - 为什么我的路由 controller 在实时服务器上给出 404s

[英]PHP MVC - Why does my route controller give 404s when on live server

I've been going through a book which explains MVC through a user control application using PHP and MySQL.我一直在阅读一本书,它通过使用 PHP 和 MySQL 的用户控制应用程序来解释 MVC。 So as far as I can tell, my issue is that my MVC routing works perfectly when I use localhost, but when I apply the same code to the same structure root directories on my providers server - it loads the index page, but then the controller just throws 404s for everything else.据我所知,我的问题是,当我使用 localhost 时,我的 MVC 路由工作得很好,但是当我将相同的代码应用到我的提供程序服务器上的相同结构根目录时 - 它加载了索引页面,然后是 controller只是为其他所有内容抛出 404。 My login form also isn't passing the controller/method so it can be retrieved by $_POST.我的登录表单也没有通过控制器/方法,因此可以通过 $_POST 检索它。 This all works perfectly locally, just seems to fall down on web server.这一切都在本地完美运行,似乎在 web 服务器上失败了。 Composer is setup correctly, my PHP version is 7.4 on local and web server. Composer 设置正确,我的 PHP 版本在本地和 web 服务器上为 7.4。 I've exhausted materials on the internet and really have just hit a brick wall with it.我已经用尽了互联网上的材料,真的只是碰了壁。 I'll put all the relevant code snippets below, and any help would be greatly appreciated!我将把所有相关的代码片段放在下面,任何帮助都将不胜感激!

index.php (localhost > webroot) 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 (localhost > app) 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 (localhost > system) 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 (localhost > app > Controllers) 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 (localhost > app > views > admin > auth) login.php (localhost > app > views > admin > auth)

<?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 (located with index.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>

You'll need to tell the web server to route all requests through your application's main entry point (index.php).您需要告诉 web 服务器通过应用程序的主入口点 (index.php) 路由所有请求。 As an example, here are the configs provided by Laravel for the most common web server software (apache and nginx).例如,这里是 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;
    }
}

So thanks to Prieber for pointing me in the right direction.因此,感谢 Prieber 为我指明了正确的方向。 The solution to my problem was indeed a web server issue.我的问题的解决方案确实是 web 服务器问题。 As it turned out, my host uses IIS, so i needed to configure web.config instead.事实证明,我的主机使用 IIS,所以我需要配置web.config The following code in my <system.webServer> tags, and I was away!我的 <system.webServer> 标签中的以下代码,我走了!

<?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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM