We've switched servers and for whatever reason, our htaccess file isn't behaving the same way as it was on the other. I'm going to be the first to admit that I'm not an htaccess superuser, and I have no doubt the answer's probably looking me in the face, but literally an entire Saturday of searches hasn't fixed this. I have this filesystem:
When the domain is /category/subcategory/product/
It should rewrite to /category/product-details.php?p=product&s=subcategory
When the domain is /category/subcategory/
It should rewrite to /category-product-list.php?slug=subcategory
This seems simple enough, here's the same code we had been using for years. Note, we've commented out the first two RewriteRules regarding slashes and there was no change in behavior.
RewriteEngine On
RewriteBase /
# if folder does not end with a slash redirect to with slash
RewriteRule ^([-a-zA-Z0-9]+)$ /$1/ [L,NC,R=301]
#if it does not end with a slash e.g. rock-jewelry/some-piece, add the slash
RewriteRule ^([-a-zA-Z0-9]+/[-a-zA-Z0-9]+)$ /$1/ [L,NC,R=301]
RewriteRule ^category/([^/]+)/([^/]+)/?$ category/product-details.php?p=$2s=$1 [L,QSA]
RewriteRule ^category/([^/]+)/?$ category-product-list.php?slug=$1 [L,QSA]
When the domain is /category/subcategory/product/
It rewrites to /category-product-list.php?slug=product-details.php&p=product&s=subcategory
When the domain is /category/subcategory/
It correctly rewrites to /category-product-list.php?slug=subcategory
/category/ is an actual folder, and the only thing in it is product-details.php, there is no index.php file, the htaccess is supposed to rewrite to category-product-list if they're trying to access the index.
If we remove the category-product-list.php rule, the product-details.php rule DOES work. But isn't the L directive supposed to stop at the first rule? Why is the second still running? And how can I write a better way to accomplish this goal? Thank you very much, I'm pretty beat down on this problem at this point.
I have the same problem as you to understand the why of this loop... But it's like that.
You can add that before the last RewriteRule:
RewriteCond %{REQUEST_FILENAME} !-f
Or if you don't use dot in subcategory, you can use final RewriteRule:
RewriteRule ^category/([^./]+)/?$ category-product-list.php?slug=$1 [L,QSA]
Related
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.
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
Sorry in advance for non technical terms; but keep in mind I really tried a lot to find a solution before posting here.
Under webroot folder i've 2 websites; these are the entry points:
/frontend/web/index.php
/backend/web/index.php
My goal is
Access /frontend/web/index.php opening http://domain.tld
Access /backend/web/index.php opening http://domain.tld/something
This is my webroot/.htaccess
RewriteCond %{REQUEST_URI} !^something
RewriteRule ^(.*)$ frontend/web/$1 [L]
RewriteRule ^(.*)/something$ backend/web/$1 [L]
In this way, domain.tld/ is opening /frontend/web (GOOD), but also domain.tld/something is pointing to frontend/web/index.php instead of backend/web/index.php
The leading slash is removed from the URI when used to match rules in an htaccess file. That means this regex:
^(.*)/something$
will never match a URI that looks like:
something/...
Try changing the regex to:
RewriteRule ^something(.*)$ backend/web$1 [L]
I am using this rule to rewrite the link
RewriteEngine On
RewriteRule ^(.*)/(.*) show_cv.php?email=$1
It is working fine like if I write this url with last slash
www.mysite.com/letschat_2008#yahoo.com/ ----> index.php?email=letschat_2008#yahoo.com
But when I remove the last slash from the link www.mysite.com/letschat_2008#yahoo.com/ it shows error 404.
I wish the URL Rewrite rule would work for both with slash and without slash (/)
www.mysite.com/letschat_2008#yahoo.com/ ----> index.php?email=letschat_2008#yahoo.com
www.mysite.com/letschat_2008#yahoo.com ----> index.php?email=letschat_2008#yahoo.com
Your rules are looping, you need to make sure you are rewriting an email address, and add some conditions so that the rule doesn't get applied if it's accessing an existing resource:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([A-Za-z0-9_\-\#\.]+)/?$ /show_cv.php?email=$1 [L]
You should then be using the following rule:
RewriteRule ^(.*)/? show_cv.php?email=$1
I assume you note these rules in a .htaccess file, not in the server configuration when looking at your description ?
Rethink if you don-t want to put this into the server configuration. Apart from the usage of .htaccess files being harder to debug using rewrite rules in those files is more complex than in the server configuration. This is documented in mod_rewrites docs.
The reason for the behaviour is the different content of REQUEST_URI in both cases. Have a try checking this directly and you will see the problem. The whole part "letschat_2008#yahoo.com" is simply missing in that variable in case 2 (no "/"). To get this working you must use an additional rewriteCondition (also documented...). Something like these untested lines:
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/(.+)&
RewriteRule - show_cv.php?email=%1
(note the '%' instead of a '$' in the last line)
I'm having issues with apaches mod_rewrite. I'm wanting to make clean urls with my php application but it doesn't seem to give the results i'm expecting.
I'm using this code in my .htaccess file:
RewriteEngine on
RewriteRule ^project/([0-9]{4})/([0-9]{2})$ /project/index.php?q=$1&r=$2 [L]
RewriteRule ^project/([0-9]{4})$ /project/index.php?q=$1 [L]
To make it so when I view, http://localhost/user/project/system, it would be the equivelant of viewing http://localhost/user/project/index.php?q=system
Instead of getting any results I just get a typical 404 error.
I've also just checked to see if mod_rewrite works by replace my .htaccess code with this:
Options +FollowSymLinks
RewriteEngine On
RewriteRule (.*) http://www.stackoverflow.com
And it properly redirects me here, so mod_rewrite is definitely working.
The root path to my project is /home/user/public_html/project
The the url used to view my project is http://localhost/user/project
If anymore information is required let me know.
Thanks
If your .htaccess file is indeed located in the project/ subdirectory already, then don't mention it in the RewriteRule again. Remove it:
RewriteRule ^([0-9]{4})/([0-9]{2})$ /project/index.php?q=$1&r=$2 [L]
# no "project/" here
Rules always pertain to the current local filename mapping.
Else experiment with a RewriteBase.
You have [0-9]{4} in your regex which will only match numbers of 4 digits. "system", however, is not a number of 4 digits, and therefore does not match.
You can use something like [^/]+ instead.
RewriteRule ([^/]+)/([0-9]{2})$ /index.php?q=$1&r=$2 [L]
RewriteRule ([^/]+)$ /index.php?q=$1 [L]
Don't know if the second parameter should be a number with 2 digits or not.
Edit: I also added "user" at the beginning now.
Edit2: Okay, I thought you were in the root htdocs with your htaccess. So remove "project" and "user" if you are in "project" with the .htaccess.
You probably mean
RewriteRule ^/project/([0-9]{4})/([0-9]{2})$ /project/index.php?q=$1&r=$2 [L]
RewriteRule ^/project/([0-9]{4})$ /project/index.php?q=$1 [L]
The '^project' means "start of line is 'project'" but the start is a '/project', so you need to include the starting slash (i.e. '^/project...').
Sorry, missed the system bit (and the user bit). Was concentrating on the slash.
RewriteRule ^/user/project/([a-zA-Z0-9]*)/([a-zA-Z0-9]*)$ /user/project/index.php?q=$1&r=$2 [L]
RewriteRule ^/user/project/([a-zA-Z0-9]*)$ /user/project/index.php?q=$1 [L]
Should have you right.