RewriteRule in htaccess fails, but it could be my host - php

I read that Self Sabotage is Not asking for help so here I am.
So, I have a site...it's working great using WAMP. It's working great on my current host. But I need to switch to a new host and now it's failing. I figured it's a .htaccess issue but now I'm not sure. On my current host I have no .htaccess file and it works great. On my localhost server using WAMP I had the same thing as on my new host but I just disabled the .htaccess file, renaming it to BAD.htaccess, and the site still works great. This is why I think it's a server-side problem and I need some help. On my WAMP server in vhosts I disabled +FollowSymLinks for that "domain". On my current host I had no easy way to do that so it's just whatever they gave me, but it works.
I am currently with Ionos and have switched to GreenGeeks, who use cPanel. So far I haven't found a vhosts file to edit to remove +FollowSymLinks, if that is even the problem.
Maybe it can be accomplished with .htaccess and if so here is what I need to do. First my current .htaccess:
Options +FollowSymLinks
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^poems$ poems.php [R]
#RewriteRule ^poems/$ poems.php
RewriteRule ^collections$ collections/ [R]
RewriteRule ^collections/$ collections.php
RewriteRule ^poem$ poem/ [R]
RewriteRule ^poem/$ poem.php
RewriteRule ^poem/([0-9]+)/([a-zA-Z])$ poem.php?num=$1&poem=$2 [NC,L]
RewriteRule ^collection$ collection/ [R]
RewriteRule ^collection/$ collection.php
# RewriteRule ^poem/([0=9]+)$ indpoem.php?num=$1 [NC,L]
With the first two setups I can go to example.com/poems and it will redirect or rewrite to example.com/poems.php but still look like example.com/poems. Same with collections. On the new host those rewrite rules do rewrite it but the URL or URI shows example.com/poems.php, which I don't want per current SEO standards. Still, I could live with that.
However, when I get to the next level... example.com/poem/#/poem-name it fails on my new host. I do have a file called poem.php which it should rewrite to. In that file I use the following to get the # and name...
$URL = explode("/",$_SERVER['REQUEST_URI']);
So I don't have to do a _GET.
As you can see I tried to do a RewriteRule to change it from the first to example.com/poem?111&name, but that just seems silly because on WAMP I don't have to do anything. I could try rewriting it to the same URL again, but I have a feeling that won't work. And if it does it will probably be poem.php/#/name/
Any thoughts on a server config I'm missing when using cPanel. I even tried doing
Options -FollowSymLinks
in my .htaccess file with no success.
Any help would be appreciated. My WAMP and the new host have all the most recent versions of Apache and PHP.

There are a few issues here...
For the site to work without the .htaccess file at all (on your WAMP dev server and current host) then MultiViews (part of mod_negotiation) must have been enabled. It is MultiViews that "rewrites" /foo to /foo.php.
If MultiViews is enabled then your current .htaccess file is essentially overridden since the MultiViews content-negotiation occurs before your mod_rewrite directives are processed so your RewriteRule patterns fail to match.
MultiViews is disabled by default on Apache, it needs to be "explicitly" enabled. Unfortunately, some shared hosts do enable this in the server config (which causes more problems than it fixes - if you are not expecting it.)
On the new host those rewrite rules do rewrite it but the URL or URI shows example.com/poems.php.
RewriteRule ^poems$ poems.php [R]
Because MultiViews is disabled and your directives externally "redirect" /poems to /poems.php. There is no "rewrite" here. The R (redirect) flag triggers an external redirect.
RewriteRule ^poem$ poem/ [R]
RewriteRule ^poem/$ poem.php
However, for /poem you are redirecting to /poem/ (appending the trailing slash) but you have omitted the L flag so processing continues and the request is further rewritten to /poem.php. But because you have already triggered a Redirect, the request is "redirected" (not rewritten) to /poem.php, again exposing the .php.
Redirects should nearly always include the L flag. In fact, all your rules should include the L flag for optimisation and to prevent accidental conflicts.
Why are you redirecting to append the trailing slash (as if this is the preferred canonical URL)? You make no mention of this in your question text and only one of your examples includes a trailing slash on the URL as far as I can see? So, what is the preferred/canonical URL? What URL are you linking to? Incidentally, MultiViews will not append a trailing slash - so either this redirect is not required, or your site is not actually "working great" on WAMP / current host without the .htaccess file. (?) (Personally, I would not use a trailing slash.)
RewriteRule ^poem/([0-9]+)/([a-zA-Z])$ poem.php?num=$1&poem=$2 [NC,L]
:
$URL = explode("/",$_SERVER['REQUEST_URI']);
Your PHP script parses the requested URL-path (ie. $_SERVER['REQUEST_URI']), it is not referencing the query string. However, the above RewriteRule directive is rewriting to a query string - which would seem to be entirely superfluous ("silly" - as you suggest). Because you are not using the query string in your PHP script, the request still "works" when using MultiViews.
According to your PHP script, you simply need to rewrite the request to poem.php, without a query string. (Which is what MultiViews does. Although, strictly speaking, MultiViews rewrites /poem/123/name to /poem.php/123/name - passing the additional URL-path as path-info to poem.php.)
This regex only matches a single letter in the 3rd (name) path segment so it will fail to match a requested URL of the form /poem/123/name, so the request is not rewritten to poem.php and the request fails (with a 404 I suspect).
This regex also does not match a trailing slash. (So, is the trailing slash really canonical?)
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
These conditions are entirely superfluous where you have put them. RewriteCond directives only apply to the first RewriteRule directive that follows.
Options -FollowSymLinks
You need FollowSymLinks for mod_rewrite to work. Don't try to disable this. FollowSymLinks is actually the default Apache setting, so you only need to explicitly enable it (ie. +FollowSymLinks) in .htaccess if it has been disabled in the server config.
Solution
Personally, I would not use a trailing slash on the canonical URLs. (This is in line with most of your examples and the regex used in your rule.)
So, bringing the above points together:
Options +FollowSymLinks -MultiViews
RewriteEngine on
# Canonical redirect to remove trailing slash (from non-directories)
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*)/$ /$1 [R,L]
# Internal rewrites to ".php"
RewriteRule ^poems$ poems.php [L]
RewriteRule ^collections$ collections.php [L]
RewriteRule ^poem(/\d+/[\w-]+)?$ poem.php [L]
RewriteRule ^collection$ collection.php [L]
On the other hand, if the canonical URL should include a trailing slash then change it accordingly:
Options +FollowSymLinks -MultiViews
RewriteEngine on
# Canonical redirect to append trailing slash to "all" URLs
RewriteRule !/$ ${REQUEST_URI}/ [R,L]
# Internal rewrites to ".php"
RewriteRule ^poems/$ poems.php [L]
RewriteRule ^collections/$ collections.php [L]
RewriteRule ^poem/(\d+/[\w-]+/)?$ poem.php [L]
RewriteRule ^collection/$ collection.php [L]
If you have many such URLs/pages then you can make this entirely "generic" without having to explicitly name each URL/file. ie. "poems", "collections", etc.
Alternatively, you simply enable MultiViews and let mod_negotiation rewrite the URLs. However, you will not be able to canonicalise the trailing slash or validate the request before rewriting and MultiViews applies to everything, not just your .php files, so potentially creates duplicate content. If you need to do any specific rewriting, such are rewriting the query string then MultiViews is likely to conflict.
Options +MultiViews

Related

SEO - Friendly URL redirect is not working

On my test server with Apache and php7.1 I can work with an URL like example.com/news/id/title
and it redirects me to
example.com/news.php
but the url is still the same and I can use the Parameters after the slashes.
Now I work on a live hosting and its not working anymore.
I tried to redirect with htaccess and it works for
example.com/news to redirect to example.com/news.php
but if I put anything after that i get an 404 error.
How can I redirect the requests from
/news/id/ to news.php where I want to read out the id?
And why did that work natively on my test server?
Thousand thanks for any hint.
My actual .htaccess:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^news/(.*) /news.php/$1 [R=301,NC,L]
Sounds like you may have a conflict with MultiViews (part of mod_negotiation). You need to make sure MultiViews is disabled at the top of your .htaccess file:
Options -MultiViews
If MultiViews is enabled and you make a request for /news/id/ then mod_negotiation makes an internal subrequest for /news.php (without any additional path-info) before mod_rewrite is able to rewrite the request.
why did that work natively on my testserver?
MultiViews is disabled by default on Apache, however, a number of shared web hosts do enable it for some reason. It makes extensionless URLs "magically" work without doing anything, however, this potentially creates duplicate content (bad for SEO) and causes no end of unexpected conflicts with mod_rewrite, such as this.
UPDATE: Change your directives to something like the following instead:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^news/(.*) /news.php/$1 [L]
This internally rewrites (as opposed to _externally redirects_) all requests that start /news/to/news.php/- whereis passed as _path-info_ to/news.php`. (I assume that passing the URL-path as path-info is the intention? You could instead use the query string or not pass anything in the directive and simply examine the requested URL in PHP? - but this might require marginally more processing in PHP.)
There's no need to check that the target file exists, since it's hardcoded in this example.
Removal of the R flag results in the internal rewrite.
You will need to clear your browser cache since the 301 (permanent) redirect will have been cached by the browser.
If you need a more generic solution that rewrites /<action>/<data> to /<action>.php/<data> then write it like this:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^([^/]+)/(.*) /$1.php/$1 [L]
Again, no need to check that the request does not map to a file before checking that it does map to a file when .php is appended.
Note that this is not using a TestString of the form %{REQUEST_FILENAME}.php (as you had initially), as this can result in a rewrite loop (500 error) for certain requests. See my answer to the following question on ServerFault that explains this further: https://serverfault.com/questions/989333/using-apache-rewrite-rules-in-htaccess-to-remove-html-causing-a-500-error

RewriteRule - discard trailing slash

I have a PHP project with a .htaccess file:
Options FollowSymLinks
RewriteEngine On
RewriteBase "/blog/"
RewriteRule "^([^.?/]+)/?$" "index.php?page=$1" [END,QSA]
I have a very strange problem with url localhost/blog/administration. It's definitely not caused by a PHP file, because happens even with empty source code.
My problem is: when I type localhost/blog/administration, the URL in address bar is changed to localhost/blog/administration/?page=administration. This doesn't happen after typing localhost/blog/administration/ (with trailing slash) in the address bar.
What's stranger - given problem happens only with administration URL but not with, for example, home.
What could be the cause?
DISCLAIMER: Said problem happens even when I use fresh browser (no cache) and index.php with exit; at the beggining...
Trailing slash is added at end of URI if that points to a real directory by Apache's mod_dir module for security reasons otherwise it may result in directory listing of your directory.
It is advisable to have index.php inside your /blog/administration/ directory to prevent this behavior. Otherwise you can have a separate rule to add trailing rule before final rule:
Options FollowSymLinks -Indxes
RewriteEngine On
RewriteBase /blog/
# add a trailing slash to directories
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule [^/]$ %{REQUEST_URI}/ [L,R=301]
RewriteRule ^([^./]+)/?$ index.php?page=$1 [END,QSA]
Also take note of -Indxes in options line above to disable directory listing.

.htaccess Multiple Rewrite Rules with Extensions

So, I'm not very good with Apache config or .htaccess rewrite rules.... And I'm trying to do some modifications to how my localhost server works...
What I'm trying to do is return a 404 error on any request with the extension '.php'. If the uri does not have an extension, then route the request to 'ini.php'. If the uri contains an extension that isn't of '.php', then it should just follow normal procedures in fetching the file.
What I have now:
Rewrite Engine on
DirectorySlash off
RewriteCond $1 (.php)
RewriteRule ^(.*)$ - [L,NC,R=404]
RewriteCond $1 !^(.+)
RewriteRule ^(.*)$ ini.php [L,NC]
My logic is that if it's not a .php, and it doesn't have an extension, then route it to ini.php. Otherwise it should route normally.
Right now it looks like the .php rule is working in returning 404 errors.. However, if a request for a path without an extension is received, it tries to route to ini.php and hits a 404 page. Is it maybe processing like the second rule and then hitting the first rule?
Anyways, can someone help me sort it out and give me some guidance on it? I tried google and a bunch of different solutions, but I couldn't find something that worked for this situation...
UPDATE:
I changed the code to the following and added ini.php to the DirectoryIndex settings in httpd:
RewriteEngine on
RewriteCond %{REQUEST_URI} (\.[php^\\/]+)$
RewriteRule ^(.*)$ - [L,NC,R=404]
RewriteCond %{REQUEST_URI} !(\.[^\\/]+)$
RewriteRule ^.+$ / [L,NC]
Can you check if it looks alright?
I've turned on DirectorySlash again. Thanks.
This will do it:
RewrieEngine on
# 404 any URL ending .php (ignoring any query string)
RewriteRule ^(.+)\.php$ - [R=404,L,NC]
# Rewrite any URL that does not contain a dot (.), and therefore has no extension, to ini.php
RewriteRule ^([^.]*)$ ini.php [END]
I am assuming it will go in a .htaccess file from what you said. It would need changing to go in the main config.
Don't turn DirectorySlash off. It's a security risk to do so (see the link) and it only applies to existing directories anyway so is not causing any problems for you. There is no space in RewriteEngine.

mod_rewrite into subdirectory file from folder

This could be probably duplicate due to unable to find that original even after checked the similar questions list of stackoverflow. Actually if user type myipaddress/gt then it should redirect to myipaddress/gt/gt.htm
I tried various mod_rewrites but still gets the 'gt' folder contents listed in browser. I gave the last try with below mod_rewrite.
Options +FollowSymlinks
RewriteEngine On
RewriteBase /
RewriteRule ^gt$ gt/gt.htm [NC,L]
But still the browser shows the contents of the 'gt' folder. What am I doing wrong?
You can use this rule in /gt/.htaccess:
Options +FollowSymlinks
RewriteEngine On
RewriteBase /gt/
RewriteRule ^/?$ gt.php [L]
Due to the fact that Apache sees gt as a directory, it treats it as such. However, that doesn't stop all rewriting for that particular path.
This is the basic process:
You navigate to /gt.
Apache sees that as an existing directory, and thus redirects to /gt/.
Your rule is ignored, because it doesn't contain the trailing slash.
This is why you still see the directory listing.
As such, you should change your rule to this:
RewriteRule ^gt/$ gt/gt.php [NC,L]
Alternatively, you can make use of DirectorySlash off and make the trailing slash optional, like so:
Options +FollowSymlinks
DirectorySlash off
RewriteEngine On
RewriteBase /
RewriteRule ^gt/?$ gt/gt.php [NC,L]
Doing either of the above allows you to have multiple rules of a similar nature in a single .htaccess file.

Strange Rewriting (Apache mod_rewrite)

I'm very much confused about the result of my rewrite-rules. I use WAMP to host on my local machine.
RewriteEngine on
RewriteBase /niklasrosenstein/
RewriteCond %{REQUEST_URI} !res/(.+)$
RewriteCond %{REQUEST_URI} !index.php$
RewriteRule ^(.*)$ index.php?uri=$1 [QSA]
Going to
http://localhost/niklasrosenstein/res
expands to
http://localhost/niklasrosenstein/res/?uri=res
in the browsers' address-bar. I have tested it under Firefox 14, Opera 11.62 and Internet Explorer 8.
Adding a slash at the end of the URL, which would be
http://localhost/niklasrosenstein/res/
is ok.
Does anyone know why the URL is adjusted in the browsers' address-bar? I want to use mod_rewrite in order to get rid of the fuzzy URL formatting, but that issue actually breaks it down..
Does anyone know why the URL is adjusted in the browsers' address-bar?
This looks like a mod_dir/mod_rewrite conflict. By default, mod_dir is loaded, and the directory module's defaults are to have:
DirectoryIndex index.html
DirectorySlash On
The second default makes it so anytime a request appears to access a directory, and is missing a trailing slash, 301 redirect to the same URI with the slash. This happens somewhere in the URI-file mapping pipeline and is interferring with the internal rewrite that mod_rewrite applies via your rules
Since you are routing everything through index.php, it may not be detrimental to turn off DirectorySlash, so in the htaccess file in your /niklasrosenstein/ directory, try turning it off:
DirectorySlash Off
Otherwise, you can try handling that using mod_rewrite:
RewriteCond %{REQUEST_FILENAME} -d
RewriteCond !.+[^/]$
RewriteRule ^(.+)$ $1/ [L]

Categories