I'm trying to create a Route in routes.php that can handle optional unlimited sub-paths.
Route::get('/path/{url}', function($url){
echo $url;
});
The url's can be the following :
/path/part1
/path/part1/part2
/path/part1/part2/part3
etc.
But because of the / in the url's with a subpath they don't match, so nothing happens. (The echo $url is just for testing, of course).
I now use a trick to avoid this, by using ~ instead of / for the subpaths, and then replace them afterwards, but I would like to know if there's a better way so I can just use / in the URL's.
UPDATE
Found the solution, thanks to Mark :
Route::get('/path/{all}', function($url){
echo $url;
})->where('all', '.*');
There has to be an extent for the url to which you'd want to define your routes for. I suppose the number of sub-routes are/have to be predefined, say you'd want to go with 4 url parts.
If that is the case, then using optional parameters would be the best choice:
Route::get('path/{url1?}/{url2?}/{url3?}/{url4?}',
function($url1 = null, $url2 = null, $url3 = null, $url4 = null){
//check if sub-routes are defined and combine them to produce the desired url
});
Note:
It seems that (:any) parameter is not supported anymore as suggested by #Mark Davidson in the SO answer (I couldn't reproduce it in laravel 5.0).
Meanwhile, you could also use regular expressions to achieve the desired effect, as in the following (might be quite similar to your own approach):
Route::get('/{url}', function ($url) {
// other url parts can be extracted from $url
})->where('url', '.*');
But the only disadvantage in going with the second approach is that you might not know to what extent should you go nested to extract the url sub-parts.
With the former approach though, you know the extent.
Related
How many examples I have not seen, all are essentially the same, and perform the same thing. Let's take a look at one of them.
Route::current()->uri()
We have url https://example.com/test and we get test, and in all examples the same
But how to make sure that we get not just test but with a slash /test?
You can get it with this piece of code:
request()->getPathInfo();
Laravel Illuminate/Http/Request extends Symfony Request class which contains getPathInfo method.
Docs: https://symfony.com/doc/current/components/http_foundation.html#identifying-a-request
Definition of that method you can find here.
You can get url in laravel :
// Get the current URL without the query string...
echo url()->current();
// Get the current URL including the query string...
echo url()->full();
// Get the full URL for the previous request...
echo url()->previous();
You can try this:
request()->getPathInfo();
You can find the method definition here
I have problem with my router.
This page is working:
$router->map('GET', '/home', function(){
global $vt,$title,$router;
echo "Working!";
exit();
},'main.view');
but, when I using not latin characters like this;
$router->map('GET', '/ğşçİ', function(){
global $vt,$title,$router;
echo "404 Not Found!";
exit();
},'main.view');
router going to 404 page.
How can I fix this problem? I need all characters to work. ( Arabic, Cyrillic, China, Turkish .. )
This is happening because web browsers encode many non-ascii characters in URLs before they are event sent/requested. I'm going to over-simplify a lot of stuff in my answer, since encoding is complicated stuff, but in short, even though your address bar might show:
example.com/ğşçİ
...what actually gets requested ends up being:
example.com/%C4%9F%C5%9F%C3%A7%C4%B0
Since AltoRouter compares (by default) on the encoded URI, your route is not matching, since ğşçİ !== %C4%9F%C5%9F%C3%A7%C4%B0
Solution:
Rather than trying to match the encoded URI, the easiest solution here is to just tell AltoRouter to compare your routes based on the decoded URI. You will want to change this:
$match = $router->match();
to:
$match = $router->match(urldecode($_SERVER['REQUEST_URI']));
Here is a tested, working demo. You need AltoRouter.php in the same directory, and your htaccess set up correctly. Code:
<?php
include './AltoRouter.php';
$router = new AltoRouter();
$router->map('GET', '/ğşçİ', function() {
echo 'main';
},'main.view');
$match = $router->match(urldecode($_SERVER['REQUEST_URI']));
if($match){
call_user_func($match['target'], $match['params']);
}
Alternative: Encode the request matching strings
Alternatively, if you really want to leave the default matching of AltoRouter on the encoded value, you could get the match to trigger by encoding the actual match strings, like this:
$router->map('GET','/'.rawurlencode('ğşçİ'), function(){
...
},'main.view');
PS: For more details on URI encoding, this MDN page on encodeURI is a good starting spot. You can see what the actual encoded URI ends up being by checking the Chrome network requests panel, printing it in PHP with print_r($_SERVER['REQUEST_URI']);, or opening up Chrome console and run encodeURI('example.com/ğşçİ');.
I would like to create a bookmarklet for adding bookmarks. So you just click on the Bookmark this Page JavaScript Snippet in your Bookmarks and you are redirected to the page.
This is my current bookmarklet:
"javascript: location.href='http://…/bookmarks/add/'+encodeURIComponent(document.URL);"
This gives me an URL like this when I click on it on the Bookmarklet page:
http://localhost/~mu/cakemarks/bookmarks/add/http%3A%2F%2Flocalhost%2F~mu%2Fcakemarks%2Fpages%2Fbookmarklet
The server does not like that though:
The requested URL /~mu/cakemarks/bookmarks/add/http://localhost/~mu/cakemarks/pages/bookmarklet was not found on this server.
This gives the desired result, but is pretty useless for my use case:
http://localhost/~mu/cakemarks/bookmarks/add/test-string
There is the CakePHP typical mod_rewrite in progress, and it should transform the last part into a parameter for my BookmarksController::add($url = null) action.
What am I doing wrong?
I had a similar problem, and tried different solutions, only to be confused by the cooperation between CakePHP and my Apache-config.
My solution was to encode the URL in Base64 with JavaScript in browser before sending the request to server.
Your bookmarklet could then look like this:
javascript:(function(){function myb64enc(s){s=window.btoa(s);s=s.replace(/=/g, '');s=s.replace(/\+/g, '-');s=s.replace(/\//g, '_');return s;} window.open('http://…/bookmarks/add/'+myb64enc(window.location));})()
I make two replacements here to make the Base64-encoding URL-safe. Now it's only to reverse those two replacements and Base64-decode at server-side. This way you won't confuse your URL-controller with slashes...
Bases on poplitea's answer I translate troubling characters, / and : manually so that I do not any special function.
function esc(s) {
s=s.replace(/\//g, '__slash__');
s=s.replace(/:/g, '__colon__');
s=s.replace(/#/g, '__hash__');
return s;
}
In PHP I convert it back easily.
$url = str_replace("__slash__", "/", $url);
$url = str_replace("__colon__", ":", $url);
$url = str_replace("__hash__", "#", $url);
I am not sure what happens with chars like ? and so …
Not sure, but hope it helps
you should add this string to yout routs.php
Router::connect (
'/crazycontroller/crazyaction/crazyparams/*',
array('controller'=>'somecontroller', 'action'=>'someaction')
);
and after that your site will able to read url like this
http://site.com/crazycontroller/crazyaction/crazyparams/http://crazy.com
I wrote my own mvc for php, and it seems to be working fine for me. But i am having trouble with getting the controller and the action:
http://www.example.com/controller/action
this works fine but as soon as there are small changes to the url my code breaks appart. for example:
http://www.example.com/controller? thi breaks, saying the controller? doesn't exist,
http://www.example.com/controller/action? thi breaks, saying the action? doesn't exist,
i can't figure out why it takes the ? in there and if any body know a more robust to get the correct controller and action i would love to know.
here is my code:
all the request are redirected to the same index.php page using .htaccess
class Framework {
....
private function setup() {
$uri = (isset($_SERVER['REQUEST_URI']))?$_SERVER['REQUEST_URI']: false;
$query = (isset($_SERVER['QUERY_STRING']))?$_SERVER['QUERY_STRING']: '';
$url = str_replace($query,'',$uri);
$arr = explode('/',$url);
array_shift($arr);
$this->controller =!empty($arr[0])?$arr[0]:'home';
$this->action = isset($arr[1]) && !empty($arr[1])?$arr[1]:'index';
}
}
$_SERVER['QUERY_STRING'] does not include the ? so when you do $url = str_replace($query,'',$uri);, you are not replacing the ?. It's therefore looking for a controller named controller?
There are various ways around this
replace with '?'.$query
Use explode('?', $url) to separate the query string from the URI
Get the $_SERVER['REQUEST_URL'] (which doesn't include the query string), rather than getting the whole thing and then splitting out yourself
Personally I would go with the last option, because wherever the code is already written for you, it tends to be quicker and more robust than anything you can write.
You should fix the problem by using an / before the ?
I'm setting up routes in application.ini, so when I try to access /moved, it displays cont/move. It works but only if I type moved all lower letters exactly like it's setup on the first line. How can I make Moved or moVed or any other letter combination also work? Do I need to do it in Bootstrap to get finer control and how?
routes.test.route = moved
routes.test.defaults.controller = cont
routes.test.defaults.action = move
This is not a wise approach.
URLs are case sensitive for a reason. You will get duplicate content penalty from search engines. Users will be confused too.
However, you may create controller plugin to achieve this:
public function preDispatch()
{
$this->getRequest()->setControllerName(
strtolower($this->getRequest()->getControllerName());
)->setDispatched(false);
}
I've searched Google for a few minutes, and this page (http://joshribakoff.com/?p=29) covers a nice patch. This patch overrides the request object, instead of the dispatcher or the router.