removing .php extension and creating dynamic url from htaccess - php

I have following code for hiding php extension and redirecting user to a non .php url if user adds a .php extension in url for example domain.com/about.php should go to domain.com/about
RewriteBase /
RewriteRule ^(.+)\.php$ /$1 [R,L]
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*?)/?$ /$1.php [NC,END]
But the problem is that I want to create dynamic url where domain.com/abc?slug=fased should be domain.com/abc/fased but its not working what to do I have used the code RewriteRule ^abc/([^.]+)$ abc?slug=$1 and RewriteRule is on

Try it like this instead in the root .htaccess file:
Options -MultiViews
RewriteEngine On
# Redirect to remove ".php" and optional "slug" query string
RewriteCond /%{QUERY_STRING} ^(?:(/)(?:slug=([^/&]+))|/.*)$
RewriteRule ^([^./]+)\.php$ /$1%1%2 [QSD,R=301,END]
# Redirect to remove "slug" query string (when ".php" is not present on URL-path)
RewriteCond %{QUERY_STRING} ^slug=([^/&]+)$
RewriteRule ^([^./]+)$ /$1/%1 [QSD,R=301,END]
# Rewrite to append ".php" extension
# Handles both "/about" (empty "slug") and "/abc/fased"
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^([^./]+)(?:/([^/]+))?$ $1.php?slug=$2 [END]
In the directives you posted the RewriteBase directive was superfluous.
This handles both scenarios. ie. Requests for /about and /abc/fased. Requests for /about are internally rewritten with an empty slug URL parameter. However, this also means that /about/foo would also be a valid request (and serve /about.php). But that is really an issue with your "generalised" URL structure not these directives.
The first two rules handle the canonical redirects for SEO (you should already be linking to the canonical URLs internally). For example:
/about.php redirects to /about
/abc?slug=fased redirects to /abc/fased
/abc.php?slug=fased redirects to /abc/fased
However, if any other URL parameters are present on the request then the condition won't match and there will be no redirect.
Clear your browser cache before testing and test first with a 302 (temporary) redirect to avoid potential caching issues.

There's a really good set of introductions to rewrite rules here: Reference: mod_rewrite, URL rewriting and "pretty links" explained
One thing that's really useful to remember is that rewrites don't "make URLs pretty". The pretty URL is the input, and the ugly URL underneath is the output.
Redirects are the other way around, but they just tell the user to go somewhere else; the somewhere else has to work first.
With that in mind, your requirements are this:
a request for abc/fased should serve abc.php?slug=fased; and so on for any "slug"
a request for def should serve def.php, and so on for anything matches a PHP file and isn't already covered by rule 1
a request directly for def.php should tell the user to go to def instead
So:
# Rule 1
RewriteRule abc/(.*) abc.php?slug=$1 [END]
# Rule 2
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*?)/?$ /$1.php [END]
# Rule 3
RewriteRule ^(.+)\.php$ /$1 [R,END]
Only one rule can match each request, because they all have the END flag, and they'll be processed in order. You could put Rule 3 first, but it will only make a difference if you have a file called "abc/something.php" or "something.php.php".

Related

htaccess infinite loop issue

I have run into an issue with my .htaccess file.
The file changes the ugly URL such as http://localhost/news.php?article_slug=example-1 to http://localhost/news/example-1
This works perfectly, but when I go to http://localhost/news i get a 404 error.
Within news.php I have a redirect; so if there is not an article slug in the URL it will redirect to latest.php.
my PHP code on news.php
$article_slug=$_GET['article_slug'];
if (empty($_GET)) {
header("Location: ../latest.php");
die();// no data passed by get
}
This is what I currently have in my .htaccsess file
Options -MultiViews
RewriteEngine On
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule ^ - [L]
RewriteRule ^news/([\w\d-]+)$ /news.php?article_slug=$1[QSA,L]
RewriteCond %{QUERY_STRING} article_slug=([\w\d-]+)
RewriteRule ^news$ /news/%1 [R,L]
RewriteRule ^category/([\w-]+)$ /category.php?category_slug=$1&page=$2 [QSA]
When I try to debug this myself (with very little knowledge) and add the following line it redirects to latest.php
RewriteRule ^([^/]*)/?$ /news.php [L,QSA]
but on the redirected page I get the following error
The page isn’t redirecting properly
Firefox has detected that the server is redirecting the request for this
address in a way that will never complete.
This problem can sometimes be caused by disabling or refusing to accept cookies
When I use the developer tools in firefox as IMSoP commented all I see is latest.php reloaded multiple times.
This is not just isolated to just latest.php but any file on the server thats not listed in the access file
when I remove the line
RewriteRule ^([^/]*)/?$ /news.php [L,QSA]
I can load the PHP file but it doesn't redirect from news.php and http://localhost/news is not found but http://localhost/news/example-1 works.
but when I go to http://localhost/news i get a 404 error.
None of your rules catch such a request, so no rewriting occurs and you get a 404.
RewriteRule ^([^/]*)/?$ /news.php [L,QSA]
This rewrites everything to /news.php, including /latest.php that you are redirecting to in your PHP script and the cycle repeats, resulting in a redirect loop to /latest.php.
However, this redirect in your PHP code would also seem to assume there is a slash on the original request. ie. should be /news/ (with trailing slash) not /news (no trailing slash) as you state in the question.
It would be better to redirect to a root-relative (or absolute URL) in your PHP script. ie. header('Location: /latest.php');
RewriteRule ^news/([\w\d-]+)$ /news.php?article_slug=$1[QSA,L]
RewriteCond %{QUERY_STRING} article_slug=([\w\d-]+)
RewriteRule ^news$ /news/%1 [R,L]
(Note you are missing a space before the "flags" argument in the first rule.)
The first rule can be modified to allow news/ and not just news/<something>. This is achieved by simply changing the quantifier from + (1 or more) to * (0 or more) on the capturing subpattern.
The second rule is not currently doing anything. You should probably be targeting news.php here. But the rules are also in the wrong order.
As noted in my answer to your earlier question, the \d shorthand character class is not necessary, since \w (word characters) already includes digits.
Try the following instead:
RewriteCond %{QUERY_STRING} (?:^|&)article_slug=([\w-]*)(?:$|&)
RewriteRule ^news\.php$ /news/%1 [R=301,L]
RewriteRule ^news/([\w-]*)$ /news.php?article_slug=$1 [QSA,L]
Note, the first rule should be a 301 (permanent) redirect, not a 302 (as it was initially). But always test first with a 302 to avoid potential cachining issues.
This allows requests to /news/, but not /news (no trailing slash). Only one of these can be canonical. If you need to handle /news as well then you should redirect to append the trailing slash (so /news/ is canonical, and the URL you should always link to.) For example, before the above two rules:
# Append trailing slash if omitted (canonical redirect)
RewriteRule ^news$ /$0/ [R=301,L]
Summary
Bringing the above points together:
Options -MultiViews
RewriteEngine On
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule ^ - [L]
# Append trailing slash if omitted (canonical redirect)
RewriteRule ^news$ /$0/ [R=301,L]
RewriteCond %{QUERY_STRING} (?:^|&)article_slug=([\w-]*)(?:$|&)
RewriteRule ^news\.php$ /news/%1 [R=301,L]
RewriteRule ^news/([\w-]*)$ /news.php?article_slug=$1 [QSA,L]
RewriteRule ^category/([\w-]+)$ /category.php?category_slug=$1 [QSA,L]
However, the same now applies to your /category URL. This was also discussed in your earlier question. (I've removed the superfluous &page=$2 part and added the missing L flag.)
If you have many such URLs that follow a similar pattern (eg. news and category etc.) you don't necessarily need a separate rule for each. (An exercise for the reader.)
UPDATE:
$article_slug=$_GET['article_slug'];
if (empty($_GET)) {
header("Location: ../latest.php");
die();// no data passed by get
}
As discussed in comments, this should read:
$article_slug = $_GET['article_slug'] ?? null;
if (empty($article_slug)) {
header("Location: /latest.php");
die(); // no data passed by get
}
Rewrite rules are at heart very simple: they match the requested URL against a pattern, and then define what to do if it matches.
RewriteRule ^([^/]*)/?$ /news.php [L,QSA]
The pattern here translates as "must match right from the start; anything other than a slash, zero or more times; optional slash; must match right to the end". The action if it matches is to act as though the request was for "/news.php", adding on any query string parameters.
That's a very broad pattern; it will match "news" and "news/" but it will also match "hello-world", and "__foo--bar..baz/". The only thing that would stop it matching is other rules higher up your config file.
Meanwhile, every time this rule matches, your PHP code in news.php will run, and if there isn't anything on the query string, will tell the browser to request "latest.php".
But the rule will also match "latest.php". So when the browser requests "latest.php", the code in "news.php" gets run, and tells the browser to request "latest.php" again ... and we have an infinite loop.
The simplest fix is just to make your rule more specific, e.g. look specifically for the word "news":
RewriteRule ^news/?$ /news.php [L,QSA]
Another common technique is to add a condition to the rule that it only matches if the URL doesn't match a real filename, like this:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^/]*)/?$ /news.php [L,QSA]

nginx and htaccess rewrite rule with optional parameters

I'm trying to make a rewrite rule in NGINX and .htaccess. Now, I have a link http://project2.local/recordings which can be accessed like that, but it has an optional parameter camera. So you can access the link also like this: http://project2.local/recordings/camera/1, now it also has another option. If you go to http://project2.local/recordings/20180118-110222 (where 20180118-110222 is a querystring), you need to "link" to another .php file, so I can run php scripts in seperated files. But I have no clue on how I should do that... I currently have this for nginx:
location /camera {
rewrite ^/camera/([^/]*)$ /camera.php?camera_id=$1 last;
}
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /camera\.php\?camera_id=([^\&\s]+)
RewriteRule ^/?camera\.php$ /camera/%1? [L,R=301]
RewriteRule ^camera/([^/]*)$ /camera.php?camera_id=$1 [L]
Now that is for another page, but how can I do this for the page recordings?
It needs to have or no parameter, or one parameter (and stay on the current file) or /camera/parameter, which links to another .php file
You can use these rules with different patterns:
RewriteRule ^recordings/?$ recordings.php [L,NC]
RewriteRule ^recordings/camera/(\d+)?$ recordings.php?camera_id=$1 [L,NC,QSA]
RewriteRule ^recordings/(\d+-\d+))?$ another.php?param=$1 [L,NC,QSA]

How do i use .htaccess to clean a url generated by php

I have following URLs:
http://www.example.com/item?title=titlename&id=5 and
http://www.example.com/page?title=titlename
I want to convert them like:
http://www.example.com/item/titlename/5
http://www.example.com/page/titlename
Note: the page and item are files (ie: item.php and page.php), I was able to remove the .php extension using the following code:
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s([^.]+)\.php [NC]
RewriteRule ^ %1 [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*?)/?$ $1.php [NC,L]
Any little help would be appreciated.
i just want to internally rewrite the url from something like http://www.example.com/item?title=titlename&id=5 and http://www.example.com/page?title=titlename to something like this: http://www.example.com/item/titlename/5 or http://www.example.com/page/titlename.
That should be the other way round... internally rewrite from http://www.example.com/item/titlename/5 to http://www.example.com/item?title=titlename&id=5. And presumably you should be including the .php extension on the target URL? (Don't rely on another directive to do append the file extension.)
Try something like the following:
Options -MultiViews
RewriteEngine On
RewriteRule ^([a-z]+)/([\w-]+)(?:/(\d+))?$ /$1.php?title=$2&id=$3 [L]
This will handle a URL both with and without the trailing ID (eg. /5). However, if you specify a URL of the form /item/titlename (ie. no numeric id), then you will naturally get an empty id URL parameter passed to your script.
Note that MultiViews must be disabled for this to work, otherwise mod_negotiation will rewrite the URL from item to item.php (for example) before mod_rewrite and you won't get the URL parameters passed.
If you specifically need to check that the target file, eg. page.php exists before rewriting then you can include an additional condition to check this. However, I wouldn't have thought this was necessary since you'll get a 404 regardless and checking that the file exists is relatively expensive.
Options -MultiViews
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^([a-z]+)/([\w-]+)(?:/(\d+))?$ /$1.php?title=$2&id=$3 [L]
This assumes that your files exist in the document root of your site.
Just to clarify, as mentioned in comments, you should already be linking to URLs of the form http://www.example.com/item/titlename/5 in your application.

Url Rewriting not working with cakephp

I have an application , stored in a sub directory of my domain v2. I have set up my .htaccess file as follows (in the directory mydomain.com)
Options +FollowSymLinks
RewriteEngine On
RewriteRule ^(.*)$ v2/$1 [L]
In my knowledge my urls should be rewritten so they don't contain the /v2 in them.
Which does not happen , when I check the value of $this->base and $this->webroot it is www.mydomain.com/v2
when it should be just www.mydomain.com, Is there any way I can change this value.
So What I want to achieve is to rewrite urls so www.mydomain.com/v2/products appears in address bar as http://mydomain.com/products
The only thing those rules do is take a request for www.mydomain.com/products and internally serve the resource at /v2/products. It doesn't do anything about "changing" the URL on the browser. To do that you must redirect:
RewriteCond %{THE_REQUEST} \ /v2/([^\?\ ]*)
RewriteRule ^ /%1 [L,R=301]
And include that along with the rules that you have.

Rewrite url which redirects to page on webserver

I am trying to get a page with a query string to redirect to a nicer looking url then get that url and transfer it back to the original query string but without redirecting (i.e. without changing the url)
At the moment I am getting a redirect loop (for obvious reasons) but I was hoping for a way to stop this.
This is my code in my htaccess file
#rewrite search querystring
#/search/'apartment'/2_bedrooms/price_0-500000/town_W4/development_18,SW5/
RewriteRule ^search/([^/]+)/([^/]+)_bedrooms/price_([^/]+)-([^/]+)/town_([^/]+)/development_([^/]+) /search.php?propertytype=$1&bedrooms=$2&minprice=$3&maxprice=$4&location=$5&development=$6 [NC]
RewriteCond %{QUERY_STRING} propertytype=([^/]+)&bedrooms=([^/]+)&minprice=([^/]+)&maxprice=([^/]+)&location=([^/]+)&development=([^/]+)
/search/$1/$2_bedrooms/price_$3-$4/town_$5/development_$6 [R,L]
RewriteRule ^(.*)$ /search/%1/%2_bedrooms/price_%3-%4/town_%5/development_%6? [R,L]
So what it is meant to do is:
user has been taken to:
http://www.domain.com/search/?propertytype=dev&bedrooms=2&minprice=0&maxprice=10000000&location=W1&development=W1
This page is the actual page on the server where the data is coming from, however I want the user to see.
http://www.domain.com/search/dev/2_bedrooms/price_0-10000000/town_W1/development_W1/
Is it possible to do this without a redirect loop.
Thanks for your help
EDIT I'm thinking it could be done with the rewrite flags but I'm not sure, I'm quite new to the Rewrite Engine
Edited:
Here is a complete (and working) solution for you:
RewriteEngine On
# User gets here:
# http://localhost/search/?propertytype=dev&bedrooms=2&minprice=0&maxprice=10000000&location=W1&development=W1
# He is explicit redirected to here:
# http://localhost/search/dev/2_bedrooms/price_0-10000000/town_W1/development_W1/
# Internally, apache calls this:
# http://localhost/search.php?propertytype=dev&bedrooms=2&minprice=0&maxprice=10000000&location=W1&development=W1
RewriteRule ^search/([^/]+)/([^/]+)_bedrooms/price_([^/]+)-([^/]+)/town_([^/]+)/development_([^/]+) search.php?propertytype=$1&bedrooms=$2&minprice=$3&maxprice=$4&location=$5&development=$6 [NC,PT]
RewriteCond %{QUERY_STRING} propertytype=([^/]+)&bedrooms=([^/]+)&minprice=([^/]+)&maxprice=([^/]+)&location=([^/]+)&development=([^/]+)
RewriteRule ^search/(.*)$ /search/%1/%2_bedrooms/price_%3-%4/town_%5/development_%6/? [R,L]
It assumes you put .htaccess in server root and that there is a file search.php in root too.
Original:
I think you can use PT and QSA Rewrite Rule flags (http://httpd.apache.org/docs/current/rewrite/flags.html) in your first rule
Use PT for server-side redirection (it will not change the URL for the user/browser, but will for your server-side scripts)
Use QSA if you wanna carry the query while doing this redirection
You can redirect all requests that don't target an existing file to a specific php-script, for example:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?url=$1 [PT,QSA]

Categories