How can I fix PHP AltoRouter URL character problems? - php

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/ğşçİ');.

Related

where does this URL need urlencoding?

I hosted a website i worked on on amazon web services, and for some reason some things dont work compared to when I run it locally on localhost.
of those things are the
if (array_key_exists("error", $json))
function and
the file_get_contents function.
Ive commented out the array key exists part and that solved the issue, at least for that part of logging in, until i get to the view documents page where a slim application error displays
failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found
and the issue for that lies in the viewdocspage.php file, particularly this code:
<?php
$raw = file_get_contents("http://cosoft.us-east-1.elasticbeanstalk.com/cosoft/mywiki/api.php?action=query&list=allpages&format=json");
$pages_response = json_decode($raw, true);
$pages_array = $pages_response["query"]["allpages"];
$page_titles = [];
I looked and read up on many threads that the issue lies with the file_get_contents in which the URL contains special characters, such as spaces (which mine doesnt have) and so needs to be encoded, using urlencode (or rawurlencode..?)
now ive tried encoding the whole url like this:
$raw = file_get_contents(urlencode("http://cosoft.us-east-1.elasticbeanstalk.com/cosoft/mywiki/api.php?action=query&list=allpages&format=json"));
but that resulted in this error:
slim error
Message: file_get_contents(http%3A%2F%2Fcosoft.us-east-1.elasticbeanstalk.com%2Fcosoft%2Fmywiki%2Fapi.php%3Faction%3Dquery%26list%3Dallpages%26format%3Djson): failed to open stream: No such file or directory
I figured that this may happen since I read that not all the URL should be wrapped by this encoding, but heres where Im stuck: which part of the url do i use the encoding on? the only special characters i keep coming accross regarding this error is spaces, but i dont have any spaces, so its something else which i dont know what it is...
Help is appreciated, thanks!
You would just need to url_encode the parameters. Say you had a value $value='My name is earl'
If you wanted to pass this value as a parameter in your url
http://somesite.com/?name=$value there would be spaces in the value that is url_encoded. So if you encode it as 'http://somesite.com/?name='.urlencode($value), when this is encoded the value will turn into My+name+is+earl
Reading resources from a URL may be restricted by the server's configuration.
http://php.net/manual/en/filesystem.configuration.php#ini.allow-url-fopen
You should use CURL for this.

Laravel routes with an optional sub-path

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.

Dynamic Title of page? PHP include links?

Can the Title of the page (within the head, not a random title) be dynamic?
I was thinking that PHP could return the value of the current page and then echo it into the Title tag after amending it.
I say amending it as I use camel case and I'd need a way of turning userProfile.php into User Profile
Can anyone point me in the right direction please?
I've used :
public function findCurrentPageURL(){
return substr($_SERVER["SCRIPT_NAME"], strpos($_SERVER["SCRIPT_NAME"], "/")+1);
}//end to return current page
as a function and thought that the same principle could be applied.
EDIT: I'm not sure how to word this but here goes, I'm hoping on a simple answer as I can't see this being a rare issue.
I have an init.php file that includes various classes and other files.
This gets called at the top of every page.
It works fine when all the pages that call it are in the same folder. Now I need to create a subdirectory within the main so:
coreFolder
->init.php
->classes
->->class.php
index.php
other.php
otherFolder
->otherPage.php
is an example of what I have now.
In index(and others) my call is require'core/init.php'
In init.php I have
require 'core/connect/dbConnect.php';
require 'core/classes/users.php';
etc etc
The problem I'm now having is when I try and call init from my otherPage.php I have to use include'../core/init.php'
I then get errors as it cannot locate the other includes within init.php.
Is there a solution for this please? I really would prefer to not have one uber great big long list of php files
I can then combine the two and voila
To output the return value of your function in the title tags just put it this way :
<title><?php echo findCurrentPageURL(); ?></title>
in a php page.
Also to split it as you want, see Orangepill comment to the question, linking your question to Split camelCase word into words with php preg_match (Regular Expression) .
First, obtain the filename by:
splitting the requested file path by '/' and obtaining the last item
snipping off the file extension portion
$filename = strstr(end(explode('/', $_SERVER["SCRIPT_NAME"])), '.', true);
Now that the filename is isolated:
split into an array prior to upper-case letter
translate the array into a string with spaces as delimiter
make the first letter of initial word upper-case
return ucfirst(join(' ', preg_split('/(?=[A-Z])/', $filename)));

How to rewrite URL structure for JavaScript

I have a web page with basicly the following URL structure:
www.example.com/main.php?userId=mattias.wolff
www.example.com/definitions.php?userId=mattias.wolff
www.example.com/tasks.php?userId=mattias.wolff
www.example.com/profile.php?userId=mattias.wolff
What I would like to do is to change this to get rid of the parameters:
www.example.com/mattias.wolff
www.example.com/mattias.wolff/definitions
www.example.com/mattias.wolff/tasks
www.example.com/mattias.wolff/profile
Server side this is not a problem since I can just use mod rewrite to rewrite the URLs to the "old" format (including paramters etc.)
My question is how this should be handled client side? The pages content is very much generated by JavaScript and I therefore need to get the parameters in the same way as before.
Is there some best practice that I have missed here? Writing a function on that parse the new URL in Javascript or send the "old" URL from server side in some kind of parameter?
Do not forget that essentially, the URL is a (kind of a) query, too. The main difference here is whether you are using named parameters or positional parameters.
The ? notation is essentially a standard to allow browser to construct an URL from a form query automatically.
You could as well be using URLs of the scheme:
www.example.com/name=mattias.wolff/page=definitions
if that is what you want.
My recommendation for you is to really define a URL scheme for your pages that completely suits your needs and has enough room for future extension. Ideally, you should be able to switch back to the old scheme at some point if necessary, without major name conflicts.
There is clearly nothing wrong with organizing your URLs in the scheme of /[username]/[page], and using this scheme from JavaScript (both for parsing and generating links!) as long as you don't change it all the time.
With the following simple(?) function you can transform a URL in the way you indicate:
function transform (href) {
var m = href.match (/((?:[^\/]+\/\/)?[^\/]+\/)(.*)\.php\?userId=(.*)/);
return m ? m[1] + m[3] + '/' + m[2] : href;
}
Basically the function extracts the components of the URL into an array using a regexp match then reassembles the URL in the way you want. If the match fails the original URL is returned.
Tested on Chrome with :
var test = ["www.example.com/main.php?userId=mattias.wolff",
"www.example.com/definitions.php?userId=mattias.wolff",
"http://www.example.com/tasks.php?userId=mattias.wolff",
"www.example.com/profile.php?userId=mattias.wolff"];
for (var i = test.length; i--;)
console.log ('"' + test[i] + '" --> "' + transform (test[i]) + '"');
Output :
"www.example.com/profile.php?userId=mattias.wolff" --> "www.example.com/mattias.wolff/profile"
"http://www.example.com/tasks.php?userId=mattias.wolff" --> "http://www.example.com/mattias.wolff/tasks"
"www.example.com/definitions.php?userId=mattias.wolff" --> "www.example.com/mattias.wolff/definitions"
"www.example.com/main.php?userId=mattias.wolff" --> "www.example.com/mattias.wolff/main"

How to encode a URL as a CakePHP parameter

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

Categories