Using .htaccess to clean GET URL - php

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

Related

htaccess not passing parameter to get in php

I have a simple .htaccess file which is supposed to redirect users from /listing/$id to /listing?id=$id. I've tried and tested this script on another domain and it works, yet for some reason it does not work here. I had to alter a couple of things in the scripts, but the logic is almost exactly the same to the original. Maybe I've missed something, but here is the final .htaccess file:
Options +FollowSymLinks -Indexes -MultiViews
RewriteEngine On
# remove php extension
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule !.*\.php$ %{REQUEST_FILENAME}.php [QSA,L]
# only allow rewriting to paths that don't exist
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^(.+) - [PT,L]
# /listing/$id
RewriteRule ^listing/([\w-]+)/?$ listing.php?id=$1 [L,QSA,NC]
And then when I go ahead and try and retrieve the data on my server side, an empty array is returned. listing.php:
// will return array(0){ }
die(var_dump($_GET));
All help is appreciated, cheers.
I am able to replicate the problem and found it is because of the # remove php extension condition and rule. If I delete those 2 lines then it works as expected. It seems to me as though that rule is counter to the comment above it, i.e. it looks like the rule is adding the php extension not removing it as the comment suggests.
It seems as though REQUEST_FILENAME is being set to "listing" from the url, so if the php file is called listing.php then it will match the first condition but the rule can't be applied because the pattern doesn't then match.
If I keep all your conditions and rules as they are except change the php filename to "listingTEST.php" and the last rule points to that file then it also works because in this case the first condition is no longer met. e.g.
RewriteRule ^listing/([\w-]+)/?$ listingTEST.php?id=$1 [L,QSA,NC]

.htaccess - rewrite a URL and also display content from another source

I'm trying to figure out how to combine rewriting and redirecting URLs with .htaccess. My specific example is: initially I wanted to remove file extensions from page URLs, so I set this up to make /page display the content of /page.php:
# URLs without file extension lead to the file
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php [NC,L]
But then I found that if a trailing slash is mistakenly added, it will still cause an error - i.e. /page/ doesn't work. I'd like someone to be able to navigate to /page/ (because if it gives a 404, that really suggests that /page doesn't exist, even though it does) - but I also want to rewrite their URL to remove the slash so the mistake doesn't happen again.
So, I want two things to happen when someone navigates to /page/.
The URL is rewritten to /page.
The page loads content from /page.php.
While also keeping the rule that navigating to /page itself will load /page.php.
Is there a way to combine this behaviour into one rewrite rule? If not, how do I make it happen with two separate rules and prevent feedback loops?
The “problem” here is this check,
RewriteCond %{REQUEST_FILENAME}\.php -f
If page/ was requested, you will have to cut off that trailing slash here, before you append .php and check if that’s an existing file. But that’s not that easy to do when you only have %{REQUEST_FILENAME} available, and not much in terms of “string functions” …
But, the RewriteRule is evaluated first anyway, so you can achieve this by matching what comes before an (optional) trailing slash inside the rule first, and then use the back reference this creates inside the condition to perform this check:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond $1.php -f
RewriteRule ^(.*)/?$ $1.php [NC,L]
So far for the theory, not tested in practice ;-) Not too sure whether checking for an existing file works with a relative path only - otherwise, you might have to prefix that with a different variable such as maybe the DOCUMENT_ROOT.
Might be that you need to be a bit more specific in what your rule is allowed to match also, because right now it would allow for something like folder/page as well, not sure whether you want to handle that the same way or not.
Solved! I added this rule to remove the trailing slash from URLs which aren't directories, before the file extension rule.
# Non-directory URLs with trailing slash change to without
RewriteCond %{REQUEST_URI} ^(.*)/$
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ https://%{HTTP_HOST}%1 [R,L]
The line in Dusan Bajic's comment didn't work on its own - it rewrote the address with the absolute file path instead of the original URL path. But it did find the slash correctly, so I rewrote the substitution to explicitly give the correct address minus the slash.

.htaccess mod_rewrite: enabling caching via checking if file exists

I am implementing a caching system for dynamically generated images. The script is called via /img/type/param1/param2.png, where multiple types are possible and the number of parameters are variable. The script generates the image and dumps it to disk.
I would like .htaccess rules, which when requesting the image generation script:
checks to see if a cached file exists
if so, mod_rewrite to the cached file
if not, don't do anything so that the script runs
What I have so far is a slightly modified logic:
mod_rewrite to where the cached file would be
check to see if the file exists
if not, mod_rewrite the request back again
If there's a better way to do this, I'd love to hear it. In any case, the relevant part of my .htaccess file:
RewriteRule ^img/(type1|type2)/(.*)$ /images/cache/$1/$2
RewriteCond /^(.*)$ !-f
RewriteRule images/cache/(.*) /img/$1
This doesn't seem to work quite right. To debug it, I inserted the following after the first RewriteRule (the target page just dumps its input):
RewriteRule ^(.*)$ /htaccess.php?url=$1 [END]
As a result, I get:
Array
(
[url] => /images/cache/a/l/300.png/a/l/300.png
)
I don't understand why $2 contains l/300.png/a/l/300.png instead of just l/300.png.
If I change first RewriteRule to include an [L], I get the expected result. However, I experience the exact same "double-matching" issue on the second RewriteRule which reverts the request back into the non-cache version. However, adding [L] to this second RewriteRule:
RewriteRule ^img/(type1|type2)/(.*)$ /images/cache/$1/$2 [L]
RewriteCond /^(.*)$ !-f
RewriteRule images/cache/(.*) /img/$1 [L]
yields an Internal Server Error.
What am I doing wrong, and how do I fix this issue?
The first logic that you have is what you want to be doing, that bypasses the possible looping issues. You just need to extract the relevant bits from the %{REQUEST_URI} then backreference them using % references. So for example:
RewriteCond %{REQUEST_URI} ^/img/(.*)$
RewriteCond %{DOCUMENT_ROOT}/images/cache/%1 -f
RewriteRule ^img/(.*)$ /images/cache/$1 [L]
or using the regex patterns that you had:
RewriteCond %{REQUEST_URI} ^/img/(type1|type2)/(.*)$
RewriteCond %{DOCUMENT_ROOT}/images/cache/%1/%2 -f
RewriteRule ^img/(.*)$ /images/cache/$1 [L]

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.

.htacces to capture the page name and send it as a get method

I am trying to capture a url such as
http://www.mysite.com/somepage.php?sometext=somevalue
and redirect it to.
http://www.mysite.com/index.php?page=somepage.php&sometext=somevalue
I tried searching for such .htaccess online, but couldn't find it.
Can you please help me?
I'm quite sure this is a duplicate, but I'm having a bit of an issue finding it/them [Edit: I found one, though possibly not the best example].
Anyway, this is a fairly standard problem resolved with fairly standard code:
RewriteRule ^(.*)$ index.php?get=$1 [L,QSA]
The RewriteRule captures the entire request as $1, and passes it to index.php as the page GET parameter.
The [QSA] flag on the end says to take any existing GET parameters (sometext=somevalue in your example), and add them as additional GET parameters on the new request. (The [L] flag just says that this should be the last rule executed.)
Note that this will also redirect requests for things like images or CSS files, so it's good to add the following lines directly before this rule:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
These lines say "if the request is for a file or directory that actually exists, don't process the rule." That way, requests for real files will be served directly by Apache, rather than being handled (or more likely, mishandled) by your PHP script.
RewriteRule ^(.*).php?sometext=(.*)$ index.php?page=$1.php&sometext=$2 [QSA,L] #rewrite
RewriteRule ^(.*).php?sometext=(.*)$ http://www.mysite.com/index.php?page=$1.php&sometext=$2 [R=301,L] #redirect

Categories