How to rewrite URLs with .htaccess (removing id?=1) - php

I've looked all over and have yet to figure out how to make this work, I'm sure it's very simple for someone who knows what they're doing. For starters, I have made sure that mod_rewrite is enabled and removing .php extensions is working so I know that isn't the issue.
Currently I'm working on a forum, and what I'm trying to do is simply remove the ?id=1 aspect of the URL, so basically making the URL look like such:
http://url.com/Forum/Topic/1
Instead of
http://url.com/Forum/Topic?id=1
/Forum is a directory with a document named Topic.php
My current .htaccess looks like this:
Options -MultiViews
RewriteEngine on
RewriteRule ^(.+)\.php$ /$1 [R,L]
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*?)/?$ /$1.php [NC,END]
Any help would be appreciated.

Assuming you've changed the URLs in your application to use http://example.com/Forum/Topic/1 then try the following:
# Remove .php file extension on requests
RewriteRule ^(.+)\.php$ /$1 [R,L]
# Specific rewrite for /Forum/Topic/N
RewriteRule ^(Forum/Topic)/(\d+)$ $1.php?id=$2 [END]
# Append .php extension for other requests
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^(.*?)/?$ /$1.php [END]
Your original condition that checked %{REQUEST_FILENAME}.php isn't necessarily checking the same "URL" that you are rewriting to - depending on the requested URL.
UPDATE: however how would I go about adding another ID variable, as in making http://example.com/Forum/Topic/1?page=1 look like http://example.com/Forum/Topic/1/1
So, in other words /Forum/Topic/1/2 goes to /Forum/Topic.php?id=1&page=2. You could just add another rule. For example:
# Specific rewrite for /Forum/Topic/N
RewriteRule ^(Forum/Topic)/(\d+)$ $1.php?id=$2 [END]
# Specific rewrite for /Forum/Topic/N/N
RewriteRule ^(Forum/Topic)/(\d+)/(\d+)$ $1.php?id=$2&page=$3 [END]
Alternatively, you can combine them into one rule. However, this will mean you'll get an empty page= URL parameter when the 2nd paramter is omitted (although that shouldn't be a problem).
# Specific rewrite for both "/Forum/Topic/N" and "/Forum/Topic/N"
RewriteRule ^(Forum/Topic)/(\d+)(?:/(\d+))?$ $1.php?id=$2&page=$3 [END]
The (?:/(\d+))? part matches the optional 2nd parameter. The ?: inside the parenthesis makes it a non-capturing group (otherwise we end up with an additional capturing subpattern that matches /2) and the trailing ? makes the whole group optional.

Related

removing .php extension and creating dynamic url from htaccess

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".

Using .htaccess to clean GET URL

Before anyone comments, I know there are a lot of posts created on this topic, but none of them seem to solve my problem, that is why I have started this thread.
So, I have a page in my website called project.php which is used in GET query like so: project.php?id=12 I want to have a .htaccess file that converts the given URL into localhost/MyWeb/project/id/12/. I've literally followed every single post regarding that topic but none of them seem to work.
Also, along with that, I want all my .php and .html files to be shown just with their names, i.e localhost/MyWeb/index.php/ becomes localhost/MyWeb/index/ and localhost/MyWeb/sub1/sub2.php becomes localhost/MyWeb/sub1/sub2/.
EDIT:
The reason why I did not add my work in first place was because I didn't think it would be any helpful. But here it is:
RewriteEngine On
RewriteRule ^([0-9]+)$ project.php?id=$1
RewriteRule ^([0-9]+)/$ project.php?page=$1
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
RewriteRule ^([^\.]+)$ $1.html [NC,L]
Firstly, you are operating out of a sub-directory (MyWeb), which means you need to set a RewriteBase. Also, you need to ensure that your .htaccess file is placed inside that sub-directory, and not in the localhost document root.
So, below RewriteEngine on, insert the folloeing line:
RewriteBase /MyWeb/
Next, you stated that you want to convert project.php?id={id} to project/id/{id}, but your code omits the /id/ segment. I also noticed that you have two rules, and that the second one contradicts your question, so I am only going to show you the change you need to make for the first rule, until such time as you clarify what the second rule is for.
To make the project URI work, change the very first rule to:
RewriteRule ^project/id/([0-9]+)/?$ project.php?id=$1 [QSA,L]
This will match the URI you want, with an optional trailing slash. I've also added the QSA flag which appends any extra query string parameters to the rewitten URI, as well as the L flag which stops processing if the rule is matched.
Next, to omit the .php or .html from your URIs, change the last three lines to the following:
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^([^\.]+)$ $1.php [L]
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^([^\.]+)$ $1.html [L]
When you make a request to localhost/MyWeb/index, Apache will check to see if localhost/MyWeb/index.php or localhost/MyWeb/index.html exist, and will then serve whichever one it finds first.
If you have both the PHP and HTML files, then the PHP one will be served, and not the HTML one. If you prefer to serve HTML files, then swap the two blocks around.
Unfortunately, I don't know of a good way to force a trailing slash for these, specifically because of the condition that checks for their existence. In other words, it won't work if you request sub2/, with the trailins slash because it would need to check if sub2/.php exists, which it does not.
Update: For added benefit, place these two blocks just below the new RewriteBase you set earlier to redirect the old URIs to the new ones whilst allowing the rewrites to the new URIs to still work:
RewriteCond %{THE_REQUEST} \/project\.php\?id=([0-9]+) [NC]
RewriteRule ^ project/id/%1/ [R=302,L,QSD]
RewriteCond %{THE_REQUEST} \/MyWeb/(.+)\.(php|html)
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ %1 [R=302,L]
For reference, here's the complete file: http://hastebin.com/gacapesoqe.rb

.htaccess Query String Rewrite

Have been going round in circles for a few hours, would really appreciate a little help.
I am trying to rewrite URLs that include a query string (preceded by company.php).
I found a few ways to get the rewrite itself to work, but it always shows a 404 :(
For example I need to rewrite (using example value):
http://test.domain.com/company.php?companynumber=05614768
to:
http://test.domain.com/company/05614768/
Here is a couple I have managed to get to do the rewrite but are 404ing:
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/company\.php$
RewriteCond %{QUERY_STRING} ^companynumber=([0-9]*)$
RewriteRule ^(.*)$ http://test.domain.com/company/%1/? [R,L]
and
RewriteEngine On
RewriteCond %{QUERY_STRING} ^companynumber=([0-9]*)$
RewriteRule ^company\.php$ http://test.domain.com/company/%1/? [R,L]
I am guessing I need to figure out how do an internal redirect as well as the external redirect? But I am really struggling...
Centos 6.6 / Apache 2.4.12
Now if that's your old-to-new redirect:
RewriteCond %{QUERY_STRING} ^companynumber=([0-9]*)$
RewriteRule ^company\.php$ http://test.domain.com/company/%1/? [R,L]
Then remap the new incoming URL via:
RewriteRule ^company/(\d+)/?$ company.php?companynumber=$1 [END]
Note that this:
Must be a rule thereafter.
Should carry the [END] flag to avoid another internal rewrite round.
Only allows numeric \d+ placeholders.
See also "Ping-Pong rewrites" on Reference: mod_rewrite, URL rewriting and “pretty links” explained. These rewrites should just be used as temporary measure. Establish the new URLs right in your HTML templates.

.htaccess redirect all extension except css and javascript

I have a .htaccess file that redirect any extension to a non-extension url and displays the requestedfilename + .php. It works great with the (.*) part of the conditions.
When I type domain.com/file.html or domain.com/file.xml it displays the file.php and the url looks like domain.com/file.
I just would like to know how to exculde extensions like .js and .css from the expression. I don't want to redirect them to any other php file.
I tried things like: (.*!.(js|css)) instead of (.*) but I can't find a working solution...
The current code is this:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
#
# to display the name.php file for any requested extension (.*)
#
RewriteRule ^(.*)\.(.*) $1\.php
#
# to hide all type of extensions (.*) of urls
#
RewriteCond %{THE_REQUEST} ^[A-Z]+\s.+\.(.*)\sHTTP/.+
RewriteRule ^(.+)\.php $1 [R=301,L]
#
# no extension url to php
#
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteCond %{REQUEST_URI} !/$
RewriteRule (.*) $1\.php [L]
</IfModule>
If your version of Apache supports it, you may be able to use "negative lookahead" and write the first RewriteRule like this:
RewriteRule ^(.*)\.(?!js|css)([^.]*)$ $1\.php
The [^.]part makes sure the (.*)\. matches everything until the last ., "positioning" the negative lookahead at the right spot.
The main idea of redirect, is to forward something, when it's not there, so redirect will work only, if the requested url is not present. If you have a http://mysite.com/js/script.js file, it will always open that file as normal one.
So in your case, you don't need a specific redirect for css and js files, if they are actually there.
What you might need to do, is to point the full path of those files. In example:
http://mysite.com/js/script.js ( works )
/js/script.js ( works )
js/script.js ( will fail if you are under a different redirected directory then root )
etc...

RewriteRule conflict with folders

In my page I have a login folder. When I enter into domain.com/login/ it takes me correctly to the folder. When I write domain.com/login it also opens the page but the url changes into domain.com/login/?cname=login
My other main link is like domain.com/company and works correctly. However if i write domain.com/company/ it sais object not found.
How can I fix these?
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/$
RewriteCond %{REQUEST_URI} !^/domain.com/index.(php|html?)
# domain.com/login
RewriteRule ^/login?$ /domain.com/login/index.php
# domain.com/abc
RewriteRule ^([a-z0-9]+)?$ /domain.com/profile/company-profile.php?cname=$1 [NC,L]
It sound like you want to have domain.com/login/ or domain.com/login take you to the login folder.
The rule below will ensure that all of your folders end with a trailing slash and thus make domain.com/login work.
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ http://domain.com/$1/ [L,R=301]
The next rule below will allow domain.com/company/ to work. In combination with the rule above, it will also ensure that domain.com/company continues to work.
RewriteRule ^company/$ profile/company-profile.php?cname=company [NC,L]
You should delete your other rules as they are incorrect.
Edit
Based on your last response modify the last rule to be
RewriteCond %{REQUEST_URI} !=/login/ [NC]
RewriteRule ^([a-z0-9]+)/$ profile/company-profile.php?cname=$1 [NC,L]
i.e. for all URI's except login do the rewrite company rule.
Make sure that you understand that any # of RewriteCond's only apply to the very next RewriteRule. I don't understand why you're matching against REQUEST_URI with a RewriteCond, rather than just matching it as part of the RewriteRule.
I also don't understand exactly what you're trying to accomplish with the ^/login?$ RewriteRule. I'm guessing the '?' needs to be escaped - otherwise, you're literally asking it to match against "/login" or "/logi".
Due to complications from the above concerns, I'm guessing your "domain.com/login" request is being handled by the 2nd RewriteRule which contains the "cname=", though I'm confused why you then don't see the "company-profile.php" as well (assuming maybe just an oversight in your question)?
After considering the above and trying to simplify this a little, I'm guessing everything should fall into place. If not, please comment back, and we'll see what we can do.

Categories