PHP router only triggers on index, but not other URI's - php

I'm using the Bramus PHP router for my application, but it only seems to work on the index route which is /. Here's the piece of code that won't work:
public function handle(): Response
{
$response = null;
$request = new Request($_REQUEST);
$uri = $request->getRequestUri();
$container = $this->configureContainer();
$renderer = new RendererFactory();
$router = $this->configureRouter();
$controllerFactory = new ControllerFactory();
$controller = $controllerFactory->create($request, $container, $renderer, $uri);
$router->get($uri, function () use ($uri, $controller, &$response) {
$response = $controller->get();
});
$router->run();
return $response;
}
So when I go to the homepage, it works fine and returns the response with the correct value. However, when I go to say /about-us, the $router->get() never fires at all. It doesn't execute the anonymous function inside. Even replacing the $uri parameter with a hardcoded string like $router->get('/about-us'...) doesn't make the anonymous function execute.
I confirmed that the ControllerFactory does in fact return the right controller, so if the $router->get() fires, the get() method is in there and the $response should not be null. But now I get an error saying $response is null because the $router->get() won't fire.
What's the mistake I'm missing here? How can the index route work perfectly fine, but the router won't accept another route?
Edit Did some digging and added a var_dump to the Bramus Router
I added a var_dump() in the handle function inside the package itself, and it always says that the result of $this->getCurrentUri() is /, and not the URI in the browser.
My .htaccess is in the root directory and I redirect all requests to /public/index.php. Maybe that's the culprit? But I don't know how to fix it. My .htaccess:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /public/index.php?path=$1 [NC,L,QSA]

Forgot to add $router->setBasePath('/');, and my folder structure and .htaccess config made the router go crazy.

Related

Redirect to Controller results 404 Page Not Found

I am creating a web application in Codeignitor using Laragon as my local server. When I try to "redirect" to a Controller - I get "404 Page Not Found". If I redirect to View - it works. I can access Controllers with other methods such as "Form Open".
Here is my .htaccess file:
RewriteEngine on
RewriteCond $1 !^(index\.php|assets|images|js|css|uploads|favicon.png)
RewriteCond %(REQUEST_FILENAME) !-f
RewriteCond %(REQUEST_FILENAME) !-d
RewriteRule ^(.*)$ index.php/$1 [L]
This is my Controller - for a test I used Redirect to a View "page-login" and a Controller "Private-area". I can access the View, but the Controller sends to 404 Page Not Found.
if($this->form_validation->run()){
$result = $this->login_model->can_login($this->input->post('user_email'), $this->input->post('user_password'));
if($result == ''){
redirect('private_area');
}
else {
$this->session->set_flashdata('message', $result);
redirect('page-login');
FYI I can access Controllers (in this example "Register") using other methods such as Form Open like this:
<?php echo form_open('register/validation'); ?>
Why do I get the 404 error?
Your redirect syntax is incorrect:
the CI function redirect() is structured like this:
redirect($uri = '', $method = 'auto', $code = NULL)
keep in mind to use a relative path like '/my_controller/my_function'
as in this example:
redirect('/login/form/');
you need to autoload/load the URL helper with: $this->load->helper('url');
the form_open() syntax is correct, you need to autoload/load the Form Helper with: $this->load->helper('form');
redirect() function
Does a “header redirect” to the URI specified. If you specify the full site URL that link will be built, but for local links simply providing the URI segments to the controller you want to direct to will create the link. The function will build the URL based on your config file values. (- source)
So, the url must be
redirect("/controller/method/parameters");
Or full url
In your code, Codeigniter will look for the index() method of private_area controller.
Thanks All!
So I think #Don'tPanic nailed it. I thought "Redirect" would point to a Controller - but it points to a Route. So I created a Route in my Routes.php file where
$route['private_area'] = 'private_area';
And everything works. Is this the correct way to do this?
Ie to define Routes in the Routes.php file...then call upon them as required using "Redirect"?

PHP: route URL to static pages/resources

I am trying to figure out the best approach when linking to static pages using a loosely followed MVC design pattern.
I begin by rewriting all requests to the index.php which handles all request and break them down the url into the controller, action and parameters. However if i don't want to follow this url structure and just want to visit a static page such as 'http://example.com/home/' without having to call some action how would i achieve this without getting a php error caused by my router/dispatcher trying to request a file that does not exist?
I thought about setting up some switch statement or a if statement as shown below that checks if the url is set to something then uses a custom defined controller and action, or i wasn't sure whether to take the static resources out of the MVC directory and have it seperate and link to it that way?
<?php
class Router
{
static public function parse($url, $request)
{
$url = trim($url);
if ($url == "/")
{
$request->controller = "tasks";
$request->action = "index";
$request->params = [];
}
else
{
$explode_url = explode('/', $url);
$explode_url = array_slice($explode_url, 2);
$request->controller = $explode_url[0];
$request->action = $explode_url[1];
$request->params = array_slice($explode_url, 2);
}
}
}
?>
This works, but i'd rather not have a huge router setup for many different static resources as it feels tacky and that i am just patching together code. Would putting static pages in its own directory outside of MVC and linking to them in the views be a valid option? i'm relatively new to MVC so any guidance would be great.
Your application shouldn't receive request it is not supposed to handle, you can solve this on a webserver level:
if you are using apache for example, you can setup in the .htaccess file that the request should be directed to your front controller (ex: index.php) only if the requested resource does not exist
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.*$ /index.php [L]

Oop php front controller issue

I have a problem building a front controller for a project I have at school.
Here is the thing, i created several controllers per entities i.e. One to select, another one to delete etc... and this for posts and comments. So i have 6 controllers and then I'm being asked to build front controller above these controllers but i keep on adding layers (route all to index.php then from there I instantiate the front controller which then will send the request to the related controller with header(location:...) and it gets messy and very complicated because for some of the request i need to pass some ids in the url for the db request...
I can't use any framework so is there a cleaner way to build a front controller that can handle request with parameters in the url and some without?
Do i have to route everything to a single page (with htaccess i created a simple rule to send everything to index.php)?
And then from there again instantiate the front controller?
If you need some code I'll share this with you but it's a mess :)
Thanks guys, i need advise I'm kind of lost at this point
You will want to build a basic router, what it does.
A router will parse the path and take parts of it and locate a controller file. And then run a method in that file with arguments. We will use this format for urls
www.yoursite.com/index.php/{controller}/{method}/{args}
So for this example our url will be
www.yoursite.com/index.php/home/index/hello/world
the index.php can be hidden using some basic .htaccess ( Mod Rewrite )
So lets define some things, first we will have folders
-public_html
index.php
--app
---controller
home.php
So the main folder is public_html with the index.php and a folder named app. Inside app is a folder named controller and inside that is our home.php contoller
Now for the Code ( yea )
index.php (basic router )
<?php
//GET URI segment from server, everything after index.php ( defaults to home )
$path_info = isset( $_SERVER['PATH_INFO'] ) ? $_SERVER['PATH_INFO'] : '/home';
//explode into an array - array_filter removes empty items such as this would cause '/home//index/' leading /, trailing / and // double slashes.
$args = array_filter( explode('/', $path_info) );
$controller_class = array_shift($args); //remove first item ( contoller )
$method = count( $args ) > 0 ? array_shift($args) : 'index'; //remove second item or default to index ( method )
$basepath = __DIR__.'/app/controller/'; //base path to controllers
if(!file_exists($basepath.$controller_class.".php") ){
echo "SHOW 404";
exit();
}
//instantiate controller class
require_once $basepath.$controller_class.".php";
$Controller = new $controller_class;
//check if method exists in controller
if(!method_exists( $Controller, $method ) ){
echo "Method not found in controller / or 404";
exit();
}
//call methods with any remaining args
call_user_func_array( [$Controller, $method], $args);
home.php ( controller )
<?php
class home{
public function index( $arg1="", $arg2=""){
echo "Arg1: ".$arg1 . "\n";
echo "Arg2: ".$arg2 . "\n";
}
public function test( $arg1 = "" ){
echo "Arg1: ".$arg1 . "\n";
}
}
Now if you put in any of these urls
www.yoursite.com/index.php
www.yoursite.com/index.php/home
www.yoursite.com/index.php/home/index
It should print ( defaults )
Arg1:
Arg2:
If you do this url
www.yoursite.com/index.php/home/index/hello/world
It should print
Arg1: hello
Arg2: world
And if you do this one
www.yoursite.com/index.php/home/test/hello_world
it would print
Arg1: hello_world
The last one, running in the second method test ( no echo arg2 ), this way you can see how we can add more controllers and methods with only having to code them into a controller.
This method still allows you to use the $_GET part of the url, as well as the URI part to pass info into the controller. So this is still valid
www.yoursite.com/index.php/home/test/hello_world?a=1
and you could ( in home::test() ) output the contents of $_GET with no issues, this is useful for search forms etc. Some pretty url methods prevent this which is just ... well ... crap.
In .htaccess with mod rewrite you would do this to remove index.php from the urls
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?/$1 [L]
</IfModule>
Then you can use urls without the index.php such as this
www.yoursite.com/home/index/hello/world
This is the simplest Router I could come up with on such short notice, yes I just created it. But this is a very similar ( although simplified ) implementation used in many MVC frameworks
PS. please understand how this is all done, so you actually learn something...
Many improvements could be made, such as allowing these urls
www.yoursite.com/hello/world
www.yoursite.com/home/hello/world
www.yoursite.com/index/hello/world
Which would all fall back to the a default of home controller and index method, but that would take some additional checks (for not found files and methods ) I cant be bothered with right now...
Here's a simple demo process (won't work, just an example).
index.php
//Say you called /index.php/do/some/stuff
$route = $_SERVER["PATH_INFO"]; //This will contain /do/some/stuff
$router = new Router();
$router->handle($route);
router.php
class Router {
private static $routeTable = [
"do/some/stuff" => [ "DoingSomeController" => "stuff" ]
];
public function handle($route) {
if (isset(self::$routeTable[trim($route,"/"])) {
$controller = new self::$routeTable[trim($route,"/"][0];
call_user_func([$controller,self::$routeTable[trim($route,"/"][1]]);
}
}
}
Basic demo, what some frameworks do.

How to deal with extra "/" in phpleague route?

I am setting endpoints for my web application like this:
$router = new League\Route\RouteCollection;
function user_action (Request $request, Response $response) {
// some logic
.
.
.
return $response;
}
$router->addRoute('GET', '/user', 'user_action');
/user endpoint works well.
However when I use /user/ (extra slash in the end) I get a
League\Route\Http\Exception\NotFoundException
I want both endpoints to point to same function.
I can achieve the desired behavior by adding routes for both endpoints separately:
$router->addRoute('GET', '/user', 'user_action');
$router->addRoute('GET', '/user/', 'user_action');
What is the recommended way to resolve this?
There are two options
You can use htaccess to strip the trailing slash from the url.
Send the dispatcher the url without the trailing slash.
Solution 1: htaccess
Add the following rewrite rule to your .htacces:
RewriteRule ^(.*)/$ /$1 [L,R=301]
Solution 2: dispatcher
After you've created the router from a RouteCollection, you get the dispatcher and dispatch the routes:
$router = new RouteCollection();
$dispatcher = $router->getDispatcher();
$response = $dispatcher->dispatch($request->getMethod(), $request->getPathInfo());
The url which is send to the dispatcher can easily be adjusted:
$url = $request->getPathInfo();
// if url ends with a slash, remove it
$url = rtrim($url, '/');
$response = $dispatcher->dispatch($request->getMethod(), $url);
Two easy solutions, which one you use depends on you.

Codeigniter subdomain routing

I'm trying to setup a blog script on a website running on the CodeIgniter framework. I want do this without making any major code changes to my existing website's code. I figured that creating a sub domain pointing to another Controller would be the cleanest method of doing this.
The steps that I took to setup my new Blog controller involved:
Creating an A record pointing to my server's ip address.
Adding new rules to CodeIgniter's routes.php file.
Here is what I came up with:
switch ($_SERVER['HTTP_HOST']) {
case 'blog.notedu.mp':
$route['default_controller'] = "blog";
$route['latest'] = "blog/latest";
break;
default:
$route['default_controller'] = "main";
break;
}
This should point blog.notedu.mp and blog.notedu.mp/latest to my blog controller.
Now here is the problem...
Accessing blog.notedu.mp or blog.notedu.mp/index.php/blog/latest works fine, however accessing blog.notedu.mp/latest takes me to a 404 page for some reason...
My .htaccess file looks like this (the default for removing index.php from the url):
RewriteEngine on
RewriteCond $1 !^(index\.php|images|robots\.txt)
RewriteRule ^(.*)$ /index.php/$1 [L]
And my Blog controller contains the following code:
class Blog extends CI_Controller {
public function _remap($method){
echo "_remap function called.\n";
echo "The method called was: ".$method;
}
public function index()
{
$this->load->helper('url');
$this->load->helper('../../global/helpers/base');
$this->load->view('blog');
}
public function latest(){
echo "latest working";
}
}
What am I missing out on or doing wrong here? I've been searching for a solution to this problem for days :(
After 4 days of trial and error, I've finally fixed this issue!
Turns out it was a .htaccess problem and the following rules fixed it:
RewriteEngine on
RewriteCond $1 !^(index\.php|images|robots\.txt)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php/$1 [L]
Thanks to everyone that read or answered this question.
Does blog.domain.co/blog/latest also show a 404?
maybe you could also take a look at the _remap() function for your default controller.
http://ellislab.com/codeigniter/user-guide/general/controllers.html#default
Basically, CodeIgniter uses the second segment of the URI to determine which function in the controller gets called. You to override this behavior through the use of the _remap() function.
Straight from the user guide,
If your controller contains a function named _remap(), it will always
get called regardless of what your URI contains. It overrides the
normal behavior in which the URI determines which function is called,
allowing you to define your own function routing rules.
public function _remap($method)
{
if ($method == 'some_method')
{
$this->$method();
}
else
{
$this->default_method();
}
}
Hope this helps.
have a "AllowOverride All" in the configuration file of the subdomain in apache?
without it "blog.notedu.mp/index.php/blog/latest" work perfectly, but "blog.notedu.mp/latest" no
$route['latest'] = "index";
means that the URL http://blog.example.com/latest will look for an index() method in an index controller.
You want
$route['latest'] = "blog/latest";
Codeigniter user guide has a clear explanation about routes here

Categories