PHP AltoRouter - can't get GET request - php

For some reason I am not able to start AltoRouter. I am trying the most basic call, but nothing is happening. How can I make it work?
My index.php file looks like this:
<?php
include('settings/autoload.php');
use app\AltoRouter;
$router = new AltoRouter;
$router->map('GET', '/', function(){
echo 'It is working';
});
$match = $router->match();
autoload.php:
<?php
require_once('app/Router.php');

Your Problem is that AltoRouter, according to the documentation (and in contrast to the Slim Framework, which seems to have the the same syntax), won't process the request for you, it only matches them.
So by calling $router->match() you get all the required information to process the request in any way you like.
If you just want to call the closure-function, simply modify your code:
<?php
// include AltoRouter in one of the many ways (Autoloader, composer, directly, whatever)
$router = new AltoRouter();
$router->map('GET', '/', function(){
echo 'It is working';
});
$match = $router->match();
// Here comes the new part, taken straight from the docs:
// call closure or throw 404 status
if( $match && is_callable( $match['target'] ) ) {
call_user_func_array( $match['target'], $match['params'] );
} else {
// no route was matched
header( $_SERVER["SERVER_PROTOCOL"] . ' 404 Not Found');
}
And voilĂ  - now you'll get your desired output!

Related

PHP route with Using AltoRouter Library

I need help. I am currently trying to use PHP route AltoRouter but it does not work for me. Here is my code:
require_once __DIR__ . '/vendor/autoload.php';
$router = new AltoRouter();
$router->map('GET', '/', function(){
echo 'It is working';
});
$match = $router->match();
// Here comes the new part, taken straight from the docs:
// call closure or throw 404 status
if( $match && is_callable( $match['target'] ) ) {
call_user_func_array( $match['target'], $match['params'] );
} else {
// no route was matched
header( $_SERVER["SERVER_PROTOCOL"] . ' 404 Not Found');
}
My browser output:
The existing list of answers I found are still not working for my code. I need help please. It's totally messing with my head.
THANK YOU VERY MUCH!
The current answers I found that did not solve for me:
PHP AltoRouter - can't get GET request
Routing via Php AltoRouter

Better approach to avoid recreating AltoRouter instance and map routes

I'm using AltoRouter and works pretty well. But for every request, a new instance of AltoRouter is create and so the mapping (I followed the example from their github page).
How to avoid this overhead?
I was thinking in Singleton anti pattern. You guys think is it ok?
I have no experience with PHP.
This is code:
<?php
//begin of singleton
require 'AltoRouter.php';
$router = new AltoRouter();
$router->map('GET', '/', function () {
require '../app/home/controllers/homecontroller.php';
});
//end of singleton
$match = $router->match();
if ($match && is_callable($match['target'])) {
call_user_func_array($match['target'], $match['params']);
} else {
// no route was matched
header($_SERVER["SERVER_PROTOCOL"] . ' 404 Not Found');
}
?>
My idea is to "singletonizing" the AltoRouter instance and mapping all route only once.

AltoRouter - mapping/routing home class as default

I get the part how you call your controllers here but how to set 'Home' as default controller and 'index' as default action in AltoRouter
this is wrong but something like
$router->map('GET', '/', function($controller, $action) {
$controller = 'Home';
$action = 'index';
});
Depends a little on what you mean by 'default action'.
If you mean "how do I make the '/' route go to the index() method on my HomeController class", then a simplified version of the linked github issue (and the AltoRouter website) would apply:
$router = new AltoRouter();
$router->setBasePath('/example.com');
$router->map('GET','/', 'HomeController#index');
$match = $router->match();
if ($match === false) {
header($_SERVER["SERVER_PROTOCOL"].' 404 Not Found');
} else {
list($controller, $action) = explode('#', $match['target']);
if ( is_callable([$controller, $action]) ) {
$obj = new $controller();
call_user_func_array([$obj, $action], [$match['params']]);
} else {
// here your routes are wrong.
// Throw an exception in debug, send a 500 error in production
}
}
The # here is completely arbitrary, it's just a delimiter to separate the controller name from the method being called. laravel uses an # for a similar kind of router-to-controller notation (i.e. HomeController#index).
If you meant "if in doubt, show the home page as a default action", then it would look fairly similar to the above, the only difference would be that the 404 path would be simply:
if ($match === false) {
$obj = new HomeController();
$obj->index();
} else {
// etc.
}

Altorouter cant figure out how to route correctly PHP

if you haven't used this before the link is: http://altorouter.com/
I am making a small application but do not require a framework, only the routing part. So I've decided to try altorouter out as it seemed quite simple.
I want to map certain routes to do certain things. for example:
www.example.com/products/
this should show my products.php template and pull data from the database to populate the fields. I have got this working with the following:
$router->map( 'GET', '/products', function() {
require('partials/connectdb.php'); //Require Database Connection
$pageContent = getProductsContent($conn); //prepare all the page content from database
require __DIR__ . '/products.php'; //require the template to use
});
The same for all of the other standard pages, my problem is when the route can change. For example:
www.example.com/shoes/
www.example.com/shorts/
www.example.com/shirts/
www.example.com/ties/
When a user goes to these routes I want to get the param 'shoes' and then while still using the products.php template, do the logic for only shoes.
So looking at the docs it says you can do:
www.example.com/[*] //which means anything.
However after adding this into my listed routes, it voids anything else the user trys to visit. So if they visit:
www.example.com/products // Like it worked before
It actually does the logic inside:
www.example.com/[*]
Does anyone know altorouter and can help me out please? I will paste my full page code below:
// Site Router
$router->map( 'GET', '/', function() {
require('partials/connectdb.php'); //Require Database Connection
$pageContent = getHomeContent($conn);
require __DIR__ . '/home.php';
});
$router->map( 'GET', '/products', function() {
require('partials/connectdb.php'); //Require Database Connection
$pageContent = getProductsContent($conn);
require __DIR__ . '/products.php';
});
$router->map( 'GET', '/[*]', function($id) {
require('partials/connectdb.php'); //Require Database Connection
$test = 'this was a test';
$pageContent = getProductsContent($conn);
require __DIR__ . '/products.php';
});
// match current request url
$match = $router->match();
// call closure or throw 404 status
if( $match && is_callable( $match['target'] ) ) {
call_user_func_array( $match['target'], $match['params'] );
} else {
// no route was matched
header( $_SERVER["SERVER_PROTOCOL"] . ' 404 Not Found');
}
Your url should be
www.example.com/products/
www.example.com/products/shoes
www.example.com/products/shirts
Then you can do this:
$router->map( 'GET', '/products/:type', function($type) {
require('partials/connectdb.php'); //Require Database Connection
if(!isset($type)){
$pageContent = getProductsContent($conn); //prepare all the page content from database
require __DIR__ . '/products.php'; //require the template to use
if($type == 'shoes'){
//do this
echo 'shoes';
}
if($type == 'shirts'){
//do that
echo 'shirts';
}
});

How to handle 404's with Regex-based routing?

Please consider the following very rudimentary "controllers" (functions in this case, for simplicity):
function Index() {
var_dump(__FUNCTION__); // show the "Index" page
}
function Send($n) {
var_dump(__FUNCTION__, func_get_args()); // placeholder controller
}
function Receive($n) {
var_dump(__FUNCTION__, func_get_args()); // placeholder controller
}
function Not_Found() {
var_dump(__FUNCTION__); // show a "404 - Not Found" page
}
And the following regex-based Route() function:
function Route($route, $function = null)
{
$result = rtrim(preg_replace('~/+~', '/', substr($_SERVER['PHP_SELF'], strlen($_SERVER['SCRIPT_NAME']))), '/');
if (preg_match('~' . rtrim(str_replace(array(':any', ':num'), array('[^/]+', '[0-9]+'), $route), '/') . '$~i', $result, $matches) > 0)
{
exit(call_user_func_array($function, array_slice($matches, 1)));
}
return false;
}
Now I want to map the following URLs (trailing slashes are ignored) to the corresponding "controllers":
/index.php -> Index()
/index.php/send/:NUM -> Send()
/index.php/receive/:NUM -> Receive()
/index.php/NON_EXISTENT -> Not_Found()
This is the part where things start to get tricky, I've two problems I'm not able to solve... I figure I'm not the first person to have this problem, so someone out there should have the solution.
Catching 404's (Solved!)
I can't find a way to distinguish between requests to the root (index.php) and requests that shouldn't exist like (index.php/notHere). I end up serving the default index.php route for URLs that should otherwise be served a 404 - Not Found error page. How can I solve this?
EDIT - The solution just flashed in my mind:
Route('/send/(:num)', 'Send');
Route('/receive/(:num)', 'Receive');
Route('/:any', 'Not_Found'); // use :any here, see the problem bellow
Route('/', 'Index');
Ordering of the Routes
If I set up the routes in a "logical" order, like this:
Route('/', 'Index');
Route('/send/(:num)', 'Send');
Route('/receive/(:num)', 'Receive');
Route(':any', 'Not_Found');
All URL requests are catched by the Index() controller, since the empty regex (remember: trailing slashes are ignored) matches everything. However, if I define the routes in a "hacky" order, like this:
Route('/send/(:num)', 'Send');
Route('/receive/(:num)', 'Receive');
Route('/:any', 'Not_Found');
Route('/', 'Index');
Everything seems to work like it should. Is there an elegant way of solving this problem?
The routes may not always be hard-coded (pulled from a DB or something), and I need to make sure that it won't be ignoring any routes due to the order they were defined. Any help is appreciated!
Okay, I know there's more than one way to skin a cat, but why in the world would you do it this way? Seems like some RoR approach to something that could be easily handled with mod_rewrite
That being said, I rewrote your Route function and was able to accomplish your goal. Keep in mind I added another conditional to catch the Index directly as you were stripping out all the /'s and that's why it was matching the Index when you wanted it to match the 404. I also consolidated the 4 Route() calls to use a foreach().
function Route()
{
$result = rtrim(preg_replace('~/+~', '/', substr($_SERVER['PHP_SELF'], strlen($_SERVER['SCRIPT_NAME']))), '/');
$matches = array();
$routes = array(
'Send' => '/send/(:num)',
'Receive' => '/receive/(:num)',
'Index' => '/',
'Not_Found' => null
);
foreach ($routes as $function => $route)
{
if (($route == '/' && $result == '')
|| (preg_match('~' . rtrim(str_replace(array(':any', ':num'), array('[^/]+', '[0-9]+'), $route)) . '$~i', $result, $matches) > 0))
{
exit(call_user_func_array($function, array_slice($matches, 1)));
}
}
return false;
}
Route();
Cheers!
This is a common problem with MVC webapps, that is often solved before it becomes a problem at all.
The easiest and most general way is to use exceptions. Throw a PageNotFound exception if you don't have a content for given parameters. At the top level off your application, catch all exceptions like in this simplified example:
index.php:
try {
$controller->method($arg);
} catch (PageNotFound $e) {
show404Page($e->getMessage());
} catch (Exception $e) {
logFatalError($e->getMessage());
show500Page();
}
controller.php:
function method($arg) {
$obj = findByID($arg);
if (false === $obj) {
throw new PageNotFound($arg);
} else {
...
}
}
The ordering problem can be solved by sorting the regexes so that the most specific regex is matched first, and the least specific is matched last. To do this, count the path separtors (ie. slashes) in the regex, excluding the path separator at the beginning. You'll get this:
Regex Separators
--------------------------
/send/(:num) 1
/send/8/(:num) 2
/ 0
Sort them by descending order, and process. The process order is:
/send/8/(:num)
/send/(:num)
/
OK first of all something like:
foo.com/index.php/more/info/to/follow
is perfectly valid and as per standard should load up index.php with $_SERVER[PATH_INFO] set to /more/info/to/follow. This is CGI/1.1 standard. If you want the server to NOT perform PATH_INFO expansions then turn it off in your server settings. Under apache it is done using:
AcceptPathInfo Off
If you set it to Off under Apache2 ... It will send out a 404.
I am not sure what the IIS flag is but I think you can find it.

Categories