.htaccess rewrite rules behaving in a wrong way - apache

I'm building an events website, in all my websites i do the following logic:
RewriteEngine On
Options +FollowSymLinks
RewriteBase /
RewriteRule ^new/event?(/)?$ controller.php?page_name=new-event [QSA,L]
RewriteRule ^get-event/([^/]+)?(/)?$ controller.php?page_name=get-event&event_id=$1 [QSA,L]
RewriteRule ^event/([^/]+)/([^/]+)?(/)?$ controller.php?page_name=event&event_id=$1 [QSA,L]
RewriteRule ^event-edit/([^/]+)?(/)?$ controller.php?page_name=event-edit&event_id=$1 [QSA,L]
// this below line to handle all links that do not apply to the above rules, is this wrong?
RewriteRule ^([^/]+)?(/)?$ controller.php?page_name=$1 [QSA,L]
The last line is to handle all URLs that don't have anything other than the page name, like those:
www.example.com/event-submit/
www.example.com/about/
www.example.com/contact/
Because I made a controller.php file that handles all the requests depending on the page_name value.
But this is not working with this new site, here's what i get:
when I request any URL belonging to this site, the browser just hangs and takes forever, sometimes the page loads but after like 5 minutes.
I have no idea why! (It works on all my other websites!)
Am I doing anything wrong? I have searched a lot and nothing is working.
EDIT
This is controller.php: (it just checks for page_name if it's allowed and then includes it)
<?php
session_start();
define('__SITE_ROOT__', dirname(__FILE__));
define('__HELPERS__', __SITE_ROOT__ . '/' . 'helpers');
define('__APP__', __SITE_ROOT__ . '/' . 'app');
$page_name = strip_tags($_GET['page_name']);
$allowed_pages = array(
'index',
'about',
'contact',
'new-event',
'event-edit',
'get-event',,
'404'
);
class Controller{
public $page_name = 'index';
public $allowed_names = array();
}
$controller = new Controller();
$controller->allowed_names = $allowed_pages;
$controller->page_name = $page_name;
if(in_array($controller->page_name, $controller->allowed_names))
{
$page_real_name = $controller->page_name . ".php";
}else{
$page_real_name = "404.php";
}
include(__APP__ . '/' . $page_real_name);

// this below line to handle all links that do not apply to the above rules, is this wrong?
RewriteRule ^([^/]+)?(/)?$ controller.php?page_name=$1 [QSA,L]
This rule would create a rewrite-loop (500 error), since the regex ^([^/]+)?(/)?$ would also match controller.php (the URL being written to) and you don't appear to have anything that would otherwise prevent this?
You could resolve this my adding a dot to the character class, so it won't match the dot in .php. For example:
RewriteRule ^([^/.]+)?/?$ controller.php?page_name=$1 [QSA,L]
You don't need to surround the last / in parentheses.
(I'm assuming the // comment is just in your question, since that is syntactically invalid. Comments are delimited with #.)
the browser just hangs and takes forever, sometimes the page loads but after like 5 minutes.
However, the above doesn't quite explain this behaviour, unless maybe LimitInternalRecursion is set very high in your server config?! (Default is 10)

Related

Livewire WithFileUpload 401 with url's not matching so failing signature check

I have a livewire file uploader on a project. When you select a file it says The uploads failed to upload. The firefox dev toolbox says it is a 401 error. I investigated further and found via https://github.com/livewire/livewire/issues/1216 that commenting out a line in the livewire vendor src (abort_unless(request()->hasValidSignature(), 401);) actually doesn't show this message and allows the file to upload but this is obviously extremely bad practice for mulitple reasons (update of livewire will undo change, it removes csrf protection and as it's in the vendor folder it is not in my repo).
I decided instead to step into how this is working and found it is creating a malformed url. This is in the laravel framework /Illuminate/Routing/UrlGenerator: line 413 [hasCorrectSignature]
/**
* Determine if the signature from the given request matches the URL.
*
* #param \Illuminate\Http\Request $request
* #param bool $absolute
* #param array $ignoreQuery
* #return bool
*/
public function hasCorrectSignature(Request $request, $absolute = true, array $ignoreQuery = [])
{
$ignoreQuery[] = 'signature';
$url = $absolute ? $request->url() : '/'.$request->path();
$queryString = collect(explode('&', (string) $request->server->get('QUERY_STRING')))
->reject(fn ($parameter) => in_array(Str::before($parameter, '='), $ignoreQuery))
->join('&');
$original = rtrim($url.'?'.$queryString, '?');
$signature = hash_hmac('sha256', $original, call_user_func($this->keyResolver));
return hash_equals($signature, (string) $request->query('signature', ''));
}
As I step over this function with Xdebug I get the following variables
$url = "https://my-project.dev/livewire/upload-file"
$queryString = "/livewire/upload-file&expires=1674038186"
$original = "https://my-project.dev/livewire/upload-file?/livewire/upload-file&expires=1674038186" <- note this is malformed right?
signature this makes is
fc95677fc265d9ad90e0ff5413eecf5cb08df82b3971b468109e1011fc323406
And lastly the signature created from the query is
6152b1a0c51c2e7532d2665bf3f2cf3a809802689185b0c5d73e2854024de124
So these do not match and thus it fails, I suspect that the signature of the correct url will match the 2nd signature (i.e. signature for https://my-project.dev/livewire/upload-file&expires=1674038186). So how do I ensure this url is correct.
I've noticed a more than likely related issue with url's when I login the app after being auto logged out so if i was on a page https://my-project.dev/foo/bar then after logging back in it is now https://my-project.dev/foo/bar?%2Ffoo%2Fbar= This has no impact on the page that is generated.
My .htaccess in the public folder is:
Options -Indexes
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php?/$1 [L,QSA]
thanks
For anyone else that has this issue I had an overnight epithany and realised that the issue is the wildcard in the htaccess RewriteRule. Remove the ? and everything works correctly. It also fixed the odd url issue I was getting.
Options -Indexes
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php/$1 [L,QSA]

GET query string parameters from .htaccess rewrite URL in PHP

In my website, I am trying to rewrite few of my URLs as bellow:
This URL
http://example.com/news.php?newstype=newsletter&newsid=1123&newstitle=my news title
int to:
http://example.com/newsletter/1123/my news title
My rewrite rule in .htaccess looks like as shown below:
RewriteEngine On
Options +FollowSymlinks
RewriteBase /
RewriteRule ^(.*)/(.*)/(.*)/?$ news.php?newstype=$1&newsid=$2&newstitle=$3 [L,QSA,NC,B]
My <a> tag is looks this:
$seoUrl = "$urlNewsType/$newsid/$urlNewsTitle/";
$seoUrl = urldecode($seoUrl);
$seoUrl = html_escape($seoUrl, 'UTF-8');
Read More
These every things are working for me. But my question is, I need to get these query string parameters separately from URL into PHP. Problem is I can't get these prameters as I do usually.
In php, This is the output of:
echo '<pre>',print_r($_GET).'</pre>';
Array
(
[newstype] => news/1114
[newsid] => Presentation: Heath+Day+in+2018
[newstitle] =>
)
Can anybody tell me, what is the wrong which I have done in this regard?
The regex pattern (.*) is greedy. It matches the full requested path. Try ([^/]+) instead :
RewriteRule ^([^/]+)/([^/]+)/([^/]+)/?$ news.php?newstype=$1&newsid=$2&newstitle=$3 [L,QSA,NC,B]

.htaccess : Pretty URL with whatever number+names of parameters

Hello !
I know there already are a lot of topics about URL rewritting and I honestly swear I've spent a lot of time trying to apply them to my problem but I can't see any of them perfectly applying to my situation (if you find otherwise, please give the link).
-----
Here's the problem :
I'm learning MVC model and URL rewriting and I have my URL like this :
http://localhost/blahblahblah/mywebsite/index.php?param1=value1&param2=value2&param3=value3 ... etc ...
What I want (for some MVC template goals) is to have this kind of URL :
http://localhost/blahblahblah/mywebsite/value1/value2/value3 ... etc ...
-----
Whatever are the names of the parameters and whatever are the values.
This is the most essential thing I can't find a solution for.
(Also don't mind the localhost blahblahblah, this has to work even on distant websites but I trust it will work fine on online website has this part of URL may have no importance in what I want to do)
Thanks a lot for your time if you can help me seeing clearer in what I need to do.
If the .htaccess file is located in the document root (ie. effectively at http://localhost/.htaccess) then you would need to do something like the following using mod_rewrite:
RewriteEngine On
RewriteRule ^(blahblahblah/mywebsite)/(\w+)$ $1/index.php?param1=$2 [L]
RewriteRule ^(blahblahblah/mywebsite)/(\w+)/(\w+)$ $1/index.php?param1=$2&param2=$3 [L]
RewriteRule ^(blahblahblah/mywebsite)/(\w+)/(\w+)/(\w+)$ $1/index.php?param1=$2&param2=$3&param3=$4 [L]
# etc.
Where $n is a backreference to the corresponding captured group in the preceding RewriteRule pattern (1st argument).
UDPATE: \w is a shorthand character class that matches a-z, A-Z, 0-9 and _ (underscore).
A new directive is required for every number of parameters. You could combine them into a single (complex) directive but you would have lots of empty parameters when only a few parameters were passed (rather than not passing those parameters at all).
I'm assuming your URLs do not end in a trailing slash.
If, however, the .htaccess file is located in the /blahblahblah/mywebsite directory then then directives could be simplified a bit:
RewriteRule ^(\w+)$ index.php?param1=$1 [L]
RewriteRule ^(\w+)/(\w+)$ index.php?param1=$1&param2=$2 [L]
RewriteRule ^(\w+)/([\w]+)/([\w]+)$ index.php?param1=$1&param2=$2&param3=$3 [L]
# etc.
Don't use URL parameters (alternative method)
An alternative approach is to not convert the path segments into URL parameters in .htaccess and instead just pass everything to index.php and let your PHP script split the URL into parameters. This allows for any number of parameters.
For example, your .htaccess file then becomes rather more simple:
RewriteRule ^\w+(/\w+)*$ index.php [L]
(This assumes the .htaccess file is located in /blahblahblah/mywebsite directory, otherwise you need to add the necessary directory prefix as above.)
The RewriteRule pattern simply validates the request URL is of the form /value1 or /value1/value2 or /value1/value2/value3 etc. And the request is rewritten to index.php (the front-controller) to handle everything.
In index.php you then examine $_SERVER['REQUEST_URI'] and parse the requested URL.

URL rewriting and redirection

I just finished my rewriting with .htaccess and everything works just fine.
RewriteEngine on
RewriteRule blog/([a-zA-Z0-9\-]+)-([0-9]+) post.php?url=1&id=$2
The only I want to avoid is the duplicate content... I've searched a lot on the subject and sadly found anything matches my needs.
The fact is, the rewrited address "blog/my-new-post-77" is also accessible by "post.php?id=77" and I don't want it to happen. So I would like to redirect every post.php pages to the rewrited rule.
Someone have an idea for me?
Yes, add extra variable to your rewrite rule to check it:
RewriteRule blog/([a-zA-Z0-9\-]+)-([0-9]+) post.php?check=ok&url=$1&id=$2
And at the top of your post.php file, check for that check variable:
if(isset($_GET['check'])){
if($_GET['check'] == "ok"){
//it comes using rewrite rule
//cut and paste all of your codes in post.php file to here
//that is which codes are available when user view your page in desired way
//don't redirect to rewrite rule again here, since visitor came using that rewrite rule to here. doing so will result infinite redirect and will show an error
}else{
//this visit is not used rewrite rule to come here
//here you can redirect visitor to not found page or just show an empty page by putting die();
//you can't redirect to post pages here, because you don't know what post(id) that visitor need to see
}
}else{
//this visit is not used rewrite rule to come here
//here you can redirect visitor to not found page or just show an empty page by putting die();
//you can't redirect to post pages here, because you don't know what post(id) that visitor need to see
}
post.php?id=77 -> /my-new-post-77 via the browser
/my-new-post-77 -> post.php?id=77 via internal rewrite
Is it right?
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule blog/([a-zA-Z0-9\-]+)\-([0-9]+)$ post.php?url=1&id=$2 [L]
RewriteCond %{THE_REQUEST} \s\/post\.php\?id\=(\d+)\s
RewriteRule . /my-new-post-%1 [R,L]
I found a solution which matches my needs waaaay more.
if($data["url"]!=$_GET["url"]) {
header("Location:http://www.mywebsite.com/blog/".$data["url"]."-".$data["id"]);
}
This solution forces the post.php?id=XX to go to the rewrited location as we wanted and by the same time, encounter any manual url rewriting.
$result being the SELECT ALL of my databases rows.
$data = mysqli_fetch_array($result);
I tested #Janaka solution, with your great explanations, and it worked tho.
Thanks everybody; Case closed :)

convert dynamic to seo friendly url

I know there is plenty on this issue in SO and elsewhere, and I read it all by now, but I do not seem to get this to work despite sweating it out all day.
So, see if you guys can point me in the right direction.
I have a dynamically created url ( by customer selecting a form at index.php ) that looks like, as an instance:
http://www.example.com/marques.php?brand_id=39-Ford
I need it to show to the user and search engines as:
www.example.com/marques/Ford
I have set up .htaccess as follows:
...other .htaccess stuff..
RewriteEngine on
RewriteCond %{REQUEST_URI} ^\/marques #here, I believe, to apply this only when URI is /marques
RewriteRule /([A-Z][a-z]+$)/ marques/$1 [L] #here I meant to get 'Ford' in this instance.
I plan to have the destination file, marques.php handle the request with the given brand info.
This is not working at all. I continue to see the 'old' URL.
Of course, the next step would be to have the .htaccess redirect when the customer clicks on the 'friendly' link at the search engine ( hopefully soon ). But I need the first step to be resolved.
By the way, I checked with my provider and they confirm that mod_rewrite is enabled.
Thanks for your help.
You can use this your root .htaccess:
RewriteEngine On
RewriteCond %{THE_REQUEST} \s/+marques\.php\?brand_id=([^\s&]+) [NC]
RewriteRule ^ /marques/%1? [R=301,L]
RewriteRule ^marques/([^/.]+)/?$ marques.php?brand_id=$1 [L,QSA,NC]
After further investigation I realized I fell for this widespread misconception that one can use mod_rewrite to create SEO friendly URL's. Unfortunately, this misconception is reinforced throughout SO as well.
After reading this article from Matthew James Taylor and this it became clear that one has to create the SEO friendly URL elsewhere, not through mod_rewrite, as was my thinking.
Mod_rewrite is ONLY part of the process.
If one has only links with anchor tags, one has to go in each page of the website and hardcode the change to the SEO friendly URL. In my case, the URL's are created dynamically.
May be there are alternative solutions, but this did the trick.
So, first I changed my form, from this:
<form action="marques.php " method="post" class="form1" >
<select class="select_home" name="brand_id" onchange="form.submit()" >
<option value= "<?php echo $row['brand_id']; ?>">"<?php echo $row['brand']; ?>"</option>
To this new set up:
<form action=" " method="post" class="form1" >
<select class="select_home" name="brand" onchange="form.submit()" >
<option value= "<?php echo $row['brand']; ?>">"<?php echo $row['brand']; ?>"</option>
What I am doing above is submitting the form to the page itself by placing action = " " and changing name and value to 'brand' ie, the name of the brand as opposed to the brand_id. This last one is meant to have the URL 'really' friendly. One can decide to have both the name and the id in the URL.
The SEO friendly URL is 'created' in the sequence. This script is placed at the very top of the same page, before anything else, otherwise 'header' will not work.
if(isset($_POST['brand'])){
$brand = $_POST['brand'];
$brand = str_replace(" ", "-", $brand);
$url = '/marques-voiture/' . $brand;
header("Location:" .$url );
exit();
}
So, in the above the SEO friendly URL is created and will show at the browser:
www.example.com/marques/Ford or www.example.com/Land-Rover
Next, now yes, with mod_rewrite tell the browser how to make sense of that URL and fetch the right script which is:
www.example.com/marques.php?brand=Ford
I made that as follows within .htaccess:
RewriteEngine on
RewriteCond %{REQUEST_URI} ^/?marques-voiture [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ([\-A-Za-z]+$) /marques.php?brand=$1 [L]
Of course it is necessary to change the destination script to receive a GET, instead of a POST which now contains the brand and not the brand_id as before.
Hope that helps.