Creating a simple PHP routing with parameters.

PHP is a general-purpose language that can be used to develop a range of different types of web applications. It has been traditionally used to create dynamic and interactive websites and web applications.

Routing :

Routing is a common term in web development. Its purpose is to tell your application how to handle incoming requests. It decides which function needs to process the request. Today we will see how we can make a simple routing in PHP.

PHP routing is an alternative to the default PHP mechanism for handling requests. It offers a very simple and intuitive way of defining routes and mapping them to specific functions. It is also a toolkit that helps you to make your web application more modular and maintainable.

Requirements :

  • PHP 5+,
  • Basic knowledge of PHP OOP.
  • Basic knowledge of Regex.
  • XAMPP knowledge.

Our first step for PHP routing is to create a .htaccess file that will send all the requests to our index.php file. I am assuming that you know XAMPP. Goto htdocs folder, create a new folder “routing” and create a new file “.htaccess”. Add this code into your .htacess file.

RewriteEngine On

#location of your website
RewriteBase /routing

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule ^(.+)$ index.php?uri=$1 [QSA,L]

php routing

PHP Routing Without Parameters :

Create “index.php” file then create a new “Route” class and add the public method “add”.

<?php

class Route {

    /*
    two parameters.

    route : route address
    file : location of the file to show if route address matched

    */
    public function add($route, $file){

        
    }
}


?>

Our next step is to create a “home.php” file at the same folder then go to “index.php” and create a new instance of Route and call the “add” method with the route address and file location.

<!-- home.php file -->

<h1>Home Page </h1>
<?php

//index.php file

class Route {

    /*
    two parameters.

    route : route address
    file : location of the file to show if route address matched

    */
    public function add($route, $file){

        
    }
}

//Route instance
$route = new Route();

//route address and home.php file location
$route->add("/home", "home.php")



?>

PHP has a global $_REQUEST variable, which can be used to get the URI of the request. The URI of the request is available in $_REQUEST[‘uri’]. So by using this global variable we can match if the URL address is the same as the route address or not. We also need to remove start and end slashes from the URL address. See the below code you will understand better.

Doc on $_REQUEST global variable

 public function add($route, $file){

        //replacing first and last forward slashes
        //$_REQUEST['uri'] will be empty if req uri is /

        if(!empty($_REQUEST['uri'])){
            $route = preg_replace("/(^\/)|(\/$)/","",$route);
            $reqUri =  preg_replace("/(^\/)|(\/$)/","",$_REQUEST['uri']);
        }else{
            $reqUri = "/";
        }

        if($reqUri == $route ){

            //on match include the file.
            include($file);

            //exit because route address matched.
            exit();
        }
        
    }

Now your code should look like this.

<?php

//index.php file

class Route {

    /*
    two parameters.

    route : route address
    file : location of the file to show if route address matched

    */
    public function add($route, $file){

        
        //replacing first and last forward slashes
        //$_REQUEST['uri'] will be empty if req uri is /

        if(!empty($_REQUEST['uri'])){
            $route = preg_replace("/(^\/)|(\/$)/","",$route);
            $reqUri =  preg_replace("/(^\/)|(\/$)/","",$_REQUEST['uri']);
        }else{
            $reqUri = "/";
        }

        if($reqUri == $route ){

            //on match include the file. 
            include($file);

            //exit because route address matched.
            exit();
        }
        
    }
}

//Route instance
$route = new Route();

//route address and home.php file location
$route->add("home", "home.php");



?>

I am assuming that you are using XAMPP. When you go to http://localhost/routing/home/ you will see the contents of your home.php file. In the same way, you can add more routes. You can also create functions to control post/get requests easily in the located file.

$route->add("/home", "home.php");

$route->add("/user", "user.php");

$route->add("/about-us", "about.php");

What if user goto a route which is not defined by you? I mean 404 page.

To show a 404 page when no route is matched, you need to create a new method in the “Route” class, name it “notFound”. Call this method with your 404-page file location at the end in your “index.php” file.

public function notFound($file){
        include($file);
        exit();
}
<?php

//index.php file

class Route {

    /*
    two parameters.

    route : route address
    file : location of the file to show if route address matched

    */
    public function add($route, $file){

        
        //replacing first and last forward slashes
        //$_REQUEST['uri'] will be empty if req uri is /

        if(!empty($_REQUEST['uri'])){
            $route = preg_replace("/(^\/)|(\/$)/","",$route);
            $reqUri =  preg_replace("/(^\/)|(\/$)/","",$_REQUEST['uri']);
        }else{
            $reqUri = "/";
        }

        if($reqUri == $route ){

            //on match include the file. 
            include($file);

            //exit because route address matched.
            exit();
        }
        
    }

    public function notFound($file){
        include($file);
        exit();
    }
}

//Route instance
$route = new Route();

//route address and home.php file location
$route->add("/home", "home.php");

$route->add("/user", "user.php");

$route->add("/about-us", "about.php");

//write it at the last
//arg is 404 file location
$route->notFound("404.php");

?>

PHP Routing With Parameters

We have learned basic routing in PHP, but what if we want to get a parameter from the route address? for example I want to access a user with its id so my route should be like this: “user/id”. Now the question is how can I access the id ?.

This can be achieved and now I will explain you all the things which are required to get parameters from the route address.

STEP 1 :

Remove everything from the Route “add” method.

public function add($route, $file){

      
        
}

STEP 2 :

Create a new private method “simpleRoute” in the Route class. This will be called when there is no parameter required in the route address.

private function simpleRoute($file, $route){

        
        //replacing first and last forward slashes
        //$_REQUEST['uri'] will be empty if req uri is /

        if(!empty($_REQUEST['uri'])){
            $route = preg_replace("/(^\/)|(\/$)/","",$route);
            $reqUri =  preg_replace("/(^\/)|(\/$)/","",$_REQUEST['uri']);
        }else{
            $reqUri = "/";
        }

        if($reqUri == $route){
            $params = [];
            include($file);
            exit();

        }

    }

STEP 3 :

In the Route “add” method add this code. Read the comments, I have explained each line. Basic knowledge of Regular expression is required to understand this.

function add($route,$file){

        //will store all the parameters value in this array
        $params = [];

        //will store all the parameters names in this array
        $paramKey = [];

        //finding if there is any {?} parameter in $route
        preg_match_all("/(?<={).+?(?=})/", $route, $paramMatches);

        //if the $route does not contain any param call simpleRoute();
        if(empty($paramMatches[0])){
            $this->simpleRoute($file,$route);
            return;
        }

        //setting parameters names
        foreach($paramMatches[0] as $key){
            $paramKey[] = $key;
        }

        
        //replacing first and last forward slashes
        //$_REQUEST['uri'] will be empty if req uri is /

        if(!empty($_REQUEST['uri'])){
            $route = preg_replace("/(^\/)|(\/$)/","",$route);
            $reqUri =  preg_replace("/(^\/)|(\/$)/","",$_REQUEST['uri']);
        }else{
            $reqUri = "/";
        }

        //exploding route address
        $uri = explode("/", $route);

        //will store index number where {?} parameter is required in the $route 
        $indexNum = []; 

        //storing index number, where {?} parameter is required with the help of regex
        foreach($uri as $index => $param){
            if(preg_match("/{.*}/", $param)){
                $indexNum[] = $index;
            }
        }

        //exploding request uri string to array to get
        //the exact index number value of parameter from $_REQUEST['uri']
        $reqUri = explode("/", $reqUri);

        //running for each loop to set the exact index number with reg expression
        //this will help in matching route
        foreach($indexNum as $key => $index){

            //in case if req uri with param index is empty then return
            //because url is not valid for this route
            if(empty($reqUri[$index])){
                return;
            }

            //setting params with params names
            $params[$paramKey[$key]] = $reqUri[$index];

            //this is to create a regex for comparing route address
            $reqUri[$index] = "{.*}";
        }

        //converting array to sting
        $reqUri = implode("/",$reqUri);

        //replace all / with \/ for reg expression
        //regex to match route is ready !
        $reqUri = str_replace("/", '\\/', $reqUri);

        //now matching route with regex
        if(preg_match("/$reqUri/", $route))
        {
            include($file);
            exit();

        }
    }

Now we can add routes like this to get the parameter.

$route->add("/user/{id}","user.php");

In the “user.php” file you can access id like this :

<?php

//user.php file

<h1> echo $params['id'] </h1>

?>

Similarly, you can get multiple parameters.

$route->add("/user/{id}/{username}/{country}","user.php");
<?php

//user.php file

<h1> echo $params['id'] </h1>
<h1> echo $params['username'] </h1>
<h1> echo $params['country'] </h1>

?>

This is the final code :

<?php

class Route {

    private function simpleRoute($file, $route){

        
        //replacing first and last forward slashes
        //$_REQUEST['uri'] will be empty if req uri is /

        if(!empty($_REQUEST['uri'])){
            $route = preg_replace("/(^\/)|(\/$)/","",$route);
            $reqUri =  preg_replace("/(^\/)|(\/$)/","",$_REQUEST['uri']);
        }else{
            $reqUri = "/";
        }

        if($reqUri == $route){
            $params = [];
            include($file);
            exit();

        }

    }

    function add($route,$file){

        //will store all the parameters value in this array
        $params = [];

        //will store all the parameters names in this array
        $paramKey = [];

        //finding if there is any {?} parameter in $route
        preg_match_all("/(?<={).+?(?=})/", $route, $paramMatches);

        //if the route does not contain any param call simpleRoute();
        if(empty($paramMatches[0])){
            $this->simpleRoute($file,$route);
            return;
        }

        //setting parameters names
        foreach($paramMatches[0] as $key){
            $paramKey[] = $key;
        }

       
        //replacing first and last forward slashes
        //$_REQUEST['uri'] will be empty if req uri is /

        if(!empty($_REQUEST['uri'])){
            $route = preg_replace("/(^\/)|(\/$)/","",$route);
            $reqUri =  preg_replace("/(^\/)|(\/$)/","",$_REQUEST['uri']);
        }else{
            $reqUri = "/";
        }

        //exploding route address
        $uri = explode("/", $route);

        //will store index number where {?} parameter is required in the $route 
        $indexNum = []; 

        //storing index number, where {?} parameter is required with the help of regex
        foreach($uri as $index => $param){
            if(preg_match("/{.*}/", $param)){
                $indexNum[] = $index;
            }
        }

        //exploding request uri string to array to get
        //the exact index number value of parameter from $_REQUEST['uri']
        $reqUri = explode("/", $reqUri);

        //running for each loop to set the exact index number with reg expression
        //this will help in matching route
        foreach($indexNum as $key => $index){

             //in case if req uri with param index is empty then return
            //because url is not valid for this route
            if(empty($reqUri[$index])){
                return;
            }

            //setting params with params names
            $params[$paramKey[$key]] = $reqUri[$index];

            //this is to create a regex for comparing route address
            $reqUri[$index] = "{.*}";
        }

        //converting array to sting
        $reqUri = implode("/",$reqUri);

        //replace all / with \/ for reg expression
        //regex to match route is ready !
        $reqUri = str_replace("/", '\\/', $reqUri);

        //now matching route with regex
        if(preg_match("/$reqUri/", $route))
        {
            include($file);
            exit();

        }
    }

    function notFound($file){
        include($file);
        exit();
    }
}

$route = new Route();

$route->add("/user/{id}","user.php");

//example route with multiple params
$route->add("/download/{downID}/{filename}","download.php");

$route->notFound("404.php");

?>

This is how you can create simple PHP routing and access parameters. I hope you learned something from this article, if you have any issues or questions feel free to comment below I will be happy to answer.

READ : Send emails with Laravel using PHPMailer

Github Repo: https://github.com/yousufnoor5/php-basic-routing

Related Posts

2 Comments

  1. if I use $route->add(“/user/{id}”,”user.php”) how do I can to return to download? it looks like “user” directory and I can’t return to previous files

Comments are closed.