skip to Main Content

I’ve been going through a book which explains MVC through a user control application using PHP and MySQL. 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. My login form also isn’t passing the controller/method so it can be retrieved by $_POST. This all works perfectly locally, just seems to fall down on web server. Composer is setup correctly, my PHP version is 7.4 on local and web server. 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)

<?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 = AppConfig::get();

new SystemRoute($config);

Config.php (localhost > app)

<?php
namespace App;

use AppHelpersSession;

class Config {
    public static function get() {

        //turn on output buffering
        ob_start();

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

            //set the namespace for routing
            'namespace' => 'AppControllers\',

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

<?php
namespace System;

use SystemView;

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)

<?php

namespace AppControllers;

use SystemBaseController;
use AppHelpersSession;
use AppHelpersUrl;
use AppModelsUser;

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)

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

use AppControllersAdmin;
?>

<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 SystemRoute-->
    <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)

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

2

Answers


  1. Chosen as BEST ANSWER

    So thanks to Prieber for pointing me in the right direction. The solution to my problem was indeed a web server issue. As it turned out, my host uses IIS, so i needed to configure web.config instead. The following code in my <system.webServer> tags, and I was away!

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

  2. You’ll need to tell the web server to route all requests through your application’s main entry point (index.php). As an example, here are the configs provided by Laravel for the most common web server software (apache and 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;
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search