Search code examples
phpurl-routing

Form loads correctly the first time, but not when it has been resubmitted after rectifying the errors


I have a Controller class called class Base_controler, which redirects url with first index in the $_GET['url'] being the class name and the second being method in the class. So this is useful, let's say we have a form in the from action=""I just have to type only two things: 1. The class 2. The method to run in that class. Also it shows views from views folder. Take the following form for example, if I have to display it from the Users controller I just have to run loadView ('Users/login', $data) ($data being any data if I want to transfer to any view, if left blank it is transferred as an empty array).

<form action = "Users/login" method="POST">
<input type="text" placeholder="Enter username" name="username"><br>
<?php echo (!empty($data['username_error']) ? $data['username_error'] : '');?>
<input type="password" placeholder="Enter password" name="password"><br>
<?php echo (!empty($data['password_error']) ? $data['password_error'] : '');?>
<button type="submit" name="submit_login">Submit</button>
</form>

Refer to the Users controller, where it can be seen that, if the user enters any invalid value like username or password, the view is resent to the user with appropriate errors.

<?php
class Users extends Base_controller{
public function login(){
// This method does both display and process the form
        // Load the form if it has not been submitted yet
        if(!isset($_POST['submit_login'])){
            $this->load_view('users/login');
        }

        // Process the form if it has been submitted
        elseif(isset($_POST['submit_login'])){
*Code has been cute here*
            if($this->password == 'Invalid username'){
                // Code to execute if the entered username does not exist in the database
                $data['username_error'] = 'Invalid username.';
            }

            else{
                // Code to execute if the entered username exists in the database
                var_dump($this->password);echo br;
                echo $this->password.br;
                if(password_verify($_POST['password'], $hashed_password_retrieved_from_db)){
                    // Code to execute if the entered password is valid
                    $this->valid_password = true;
                }
                else{
                    // Code to execute if the entered password is invalid 
                    $data['password_error'] = 'Invalid password.';
                }
            }

            // Code to check if any error(s) exist(s) and proceed accordingly
            if(empty($data['username_error']) && empty($data['password_error']) && $this->valid_password==true){
                // Code to execute if no errors are present

                // Create session
                session_start();
                $_SESSION['username'] = $_POST['username'];
                // Redirect user to dashboard
                header('location: dashboard');
            }

            // Code to execute if errors are present in the entered data: Reload the form with errors
            $this->load_view('users/login', $data);

        }
    }
}
?>

Now the problem is, if the user enters any invalid field, the view is sent back to the user with appropriate errors to the change the incorrect fields, but when the user resubmits the form, only a blank page loads. Also another thing I've noticed is: when the form is loaded for the first time or when it has been resent to the user the address bar says- http://localhost/Users/login(as it should, because I use a .htaccess file to cut the remaining crap), however when the form has been resubmitted the address bar says- http:///localhost/Users/Users/login. Now this is the code which I have created based on a tutorial where the form action was http://localhost/Users/login. What is the mistake I'm doing here????


Solution

  • You are not handling your relative paths correctly.

    The first time you submit this, the current URL is http://localhost/Users/login afterwards - so we are in a fake “folder” named Users here already.

    Then when you submit this again, the browser again resolves the relative URL Users/login from the form action attribute, by combining it with the current absolute URL, http://localhost/Users/login.

    That of course lands you on http://localhost/Users/Users/login now.

    If your whole app runs directly under the domain root, then just prefix it with a slash,

    <form action="/Users/login" method="POST">
    

    (If that was not the case, and you had this running under some base path configured in the settings somewhere, then you would have to add that in as well - action="/my-base-path/Users/login", with the my-base-path part ideally coming from some variable to keep it dynamic.)