I am trying to achieve the following redirect:
http://localhost/api/user/list?limit=10
to
http://localhost/api/index.php/user/list?limit=10
My .htaccess file works fine according to https://htaccess.madewithlove.com/, but when I test it, I get a 404 Not Found error.
What I have tried
In my .htaccess file I included a rule that sets a header. This way, I can check with postman whether or not the rule has been executed.
When I send a GET request to http://localhost/api, I see my "TEST_FOOBAR" header in the response. However, when I send a GET request to http://localhost/api/user, the header is no longer there.
However, when I send a request to http://localhost/api/inc (an existing folder), I do get to see my header.
This makes me believe that my .htaccess only listens to and rewrites requests that are being sent to http://localhost/api, and not its "virtual" subfolders.
I've been googling for a while but can't seem to figure out why it's not rewriting calls to "virtual" subdirectories?
Here is my .htaccess file:
RewriteEngine On
RewriteRule ^api(.*)$ /api/index.php$1
Header set TEST_FOOBAR "oi"
RewriteRule ^api(.*)$ /api/index.php$1
By itself, this looks like it would result in a rewrite-loop, since the target URL /api/index.php... is also matched by the RewriteRule pattern ^api(.*)$, so a request for /api/user would be rewritten as follows:
/api/user to /api/index.php/user
/api/index.php/user to /api/index.php/index.php/user
Try the following instead, to prevent the rewritten request being further rewritten:
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^api(/.*)$ /api/index.php$1 [L]
There must always be a slash after api (for the substitution to be valid), so I've included this in the capturing group.
The check against the REDIRECT_STATUS env var ensures that only the initial request is processed and not the rewritten request. I used this method, as opposed to explicitly checking for /api/index.php since it allows direct requests to /api/index.php to be handled by your API and processed accordingly (perhaps even rejecting the request).
In my .htaccess file I included a rule that sets a header. This way, I can check with postman whether or not the rule has been executed.
This doesn't necessarily tell you whether the RewriteRule directive has been successfully processed or not. Different Apache modules are processed entirely independently, and at different times during the request. If the header is not set then it just means that the Header directive was not processed successfully (perhaps due to an error).
When I send a GET request to http://localhost/api
Since /api is a physical subdirectory, if you request /api without a trailing slash then mod_dir should ultimately 301 redirect the request to /api/ (appending the trailing slash). Your test header should not be set on the redirect response (since you are not using the always condition on the Header directive).
My .htaccess file works fine according to htaccess.madewithlove.com
The MWL tester only simulates a single pass by the rewrite engine so cannot detect rewrite/redirect-loops. On a real server the rewrite engine loops until the URL passes through unchanged or encounters an END flag (Apache 2.4). (The L flag simply stops the current pass by the rewrite engine, triggering the rewrite engine to begin another pass.)
In the above rule you could use the END flag (instead of L) which would negate the need for the preceding condition.
Related
#RewriteRule #htaccess
I have a url for eg: www.example.com/path1/path2/pdfname.pdf. i need to redirect this url to another with the pdf name without pdf extension like(pdfname). Redirect Url should be www.example.com/path3/viewpdf.php?param=pdfname.
Would appreciate your help, Thanks.
Assuming that "path1", "path2" and "path3" are all fixed, literal strings that probably is what you are looking for:
RewriteEngine on
RewriteRule ^/?path1/path2/(.+)\.pdf$ /path3/viewpdf.php?param=$1 [L]
This keeps the URL visible in the browser unchanged, which usually is what is desired.
That rule will work likewise in the central http server's host configuration (which usually is preferred) or, if you do not have access to that, in a distributed configuration file (often called ".htaccess"). In the later case that file needs to be readable by the http server process and it has to be located in the DOCUMENT_ROOT folder of the processing http server's host.
If instead of an internal rewrite you really want to redirect the request (so change the URL actually visible in the browser), then that variant should do:
RewriteEngine on
RewriteRule ^/?path1/path2/(.+)\.pdf$ /path3/viewpdf.php?param=$1 [R=301,L]
Again no domain name (http host name) or protocol scheme has to be specified if they stay the same. The same hints as above apply.
I am trying to redirect an old page from a website I have redesigned, to the new one, but it's not working.
Here's my 2 lines of code in the .htaccess file regarding that domain:
Redirect 301 /deaneco http://solutionsgtr.ca/fr/deaneco/accueil.html
RewriteRule ^/deaneco/contact http://solutionsgtr.ca/fr/deaneco/contact.html [R=301,L,QSA]
If go on the solutionsgtr.ca/deaneco/contact URL, it gives me the following page:
http://solutionsgtr.ca/fr/deaneco/accueil.html/contact
The first rule works though (deaneco/ to solutionsgtr.ca/fr/deaneco/accueil.html).
I feel like both lines are being mixed together and are giving me the wrong page, that doesn't exist so I get a 404 error.
There are a couple of issues here:
The Redirect directive (part of mod_alias) is prefix-matching and everything after the match is appended on the end of the target URL. This explains the redirect you are seeing.
The RewriteRule (mod_rewrite) pattern ^/deaneco/contact will never match in a .htaccess context since the URL-path that is matched does not start with a slash. So, this rule is not doing anything currently.
You should avoid mixing redirects from both modules since they execute independently and at different times during the request (mod_rewrite executes first, despite the apparent order of the directives).
Either use mod_alias, ordering the directives most specific first:
Redirect 301 /deaneco/contact http://solutionsgtr.ca/fr/deaneco/contact.html
Redirect 301 /deaneco http://solutionsgtr.ca/fr/deaneco/accueil.html
NB: You will need to clear your browser cache, since the erroneous 301 (permanent) redirect will have been cached by the browser. Test with 302 (temporary) redirects to avoid potential caching issues.
OR, if you are already using mod_rewrite for other redirects/rewrites then consider using mod_rewrite instead (to avoid potential conflicts as mentioned above):
RewriteEngine On
RewriteRule ^deaneco/contact$ http://solutionsgtr.ca/fr/deaneco/contact.html [R=301,L]
RewriteRule ^deaneco$ http://solutionsgtr.ca/fr/deaneco/accueil.html [R=301,L]
The QSA flag is not required, since the query string is passed through to the substitution by default.
The order of the RewriteRule directives are not important in this instance, since they match just that specific URL.
If go on the solutionsgtr.ca/deaneco/contact URL
If you are redirecting to the same host then you don't need to explicitly include the scheme + hostname in the target URL, since this will default.
I try to rewrite some of my URLs with a .htaccess file but it didn't work as expected.
This is the rewrite rule in my .htaccess file :
RewriteRule ^(index|administration)/([A-Za-z0-9-]+)(\.php)?$ index.php?c=$1&t=$2 [QSA]
When I go on www.example.com/index/main, I get a 404 error code.
So I try to change my rewrite rule to
RewriteRule ^index.php$ index.php?c=index&t=main [QSA]
Then I go to www.example.com/index.php and the webpage displays perfectly with all the datas in $_GET (c = index and t = main).
So I don't know why my first rule is not working. Let me see if you have any idea.
Is it possible that my server wants to enter the index folder, then the main folder for my first rule without taking care of my .htaccess (www.example.com/index/main) ?
You need to ensure that MultiViews (part of mod_negotiation) is disabled for this to work correctly. So, add the following at top of your .htaccess file:
Options -MultiViews
If MultiViews is enabled (it's disabled by default, but some hosts do sometimes enable this in the server config) then when you request /index/main where /index.php already exists as a physical file then mod_negotiation will make an internal request for index.php before mod_rewrite is able to process the request. (If index.html also exists, then this might be found first.)
(MultiViews essentially enables extensionless URLs by mocking up type maps and searching for files in the directory - with the same basename - that would return a response with an appropriate mime-type.)
If this happens then your mod-rewrite directive is essentially ignored (the pattern does not match, since it would need to check for index.php) and index.php is called without the URL parameters that your mod_rewrite directive would otherwise append.
it perfectly works by disabling the MultiViews Option in my .htaccess
This would ordinarily imply its your script (ie. index.php) that is triggering the 404 (perhaps due to missing URL parameters?), rather than Apache itself?
However, if you were seeing an Apache generated 404 then it would suggest either:
You also have an index.html file, which is found before index.php. .html files do not ordinarily accept path-info (ie. /main) so would trigger a 404.
OR, AcceptPathInfo Off is explicitly set elsewhere in the config, which would trigger a 404 when the request is internally rewritten to /index.php/main (by mod_negotiation).
I have some old URLs that I need redirected, unfortunatelly some of them contain spaces. I redirect them to my redirect.php script, but for some reason when the URL contains space or %20, in the URL after redirection this %20 repeats unlimited times. This seems to only happen now when we switched the server to HTTPS, when running on http subdomain or on my local it works correctly.
My rule is:
RewriteRule ^/?(gallery\.php)(.*) /redirect.php$2 [R,L]
This works correctly:
gallery.php?place=name --> redirect.php?place=name
But this happens when url contains space:
gallery.php?place=long%20name -->
redirect.php?place=long%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20name
I tried adding [B] and [NE] flags but no success. Is there anything I am missing?
UPDATE 1:
To exclude other rules in htaccess, I have created a new example. I have empty directory /test/ , inside is empty file /test/index.php and /test/.htaccess file, which contains:
RewriteEngine On
RewriteRule ^/?(index\.php)(.*) /$2 [NE,R,L]
That is all. Still the behaviour is weird, eg:
/test/index.php?a=xy works as expected, but /test/index.php?a=x%20y repeats the %20 sign.
So in the end I managed to go around the problem by reordering the .htaccess rules. So I do all redirects from HTTP to my redirect script which is on HTTP as well. This script then resolves the correct new URL, that is already on SSL without spaces, and then the script redirects there. Fortunatelly all old URLs are on HTTP so it is sufficient, I don't need this parameter redirects to happen on SSL.
Also the [NE] flag is helpful when redirecting URLs with %20, as it prevents the percentage sign to be further encoded in new URL.
This is a strange one...
A while back I managed to write a .htaccess redirect that worked so that the URL was read like: www.website.com/mt?page=index - and what the real URL of this page was www.website.com/PageParser.php?file=index.php
The problem has been that the FTP system of my webhost hides .htaccess files even though they are allowed and do operate - and so I have checked back on local copies I have of my .htaccess files and none of them have the code as to how this works - and I've forgotten how I did it!!
Essentially, I am using wildcards so that anything after mt?page= will actually be showing PageParser.php?file= but without having the PageParser.php showing within the URL (and this is the important bit, because the index.php on my site root is actually sent through PageParser.php first so that anything which shouldn't be there is wiped out before the end user sees it) - so how can .htaccess redirect/rewrite the URL so that any link to /mt?page= show the file located at /PageParser.php?file= without changing the URL the user sees?
RewriteEngine On
RewriteRule ^(.*)mt?page=(.*)$ $1PageParser.php?file=$2
RewriteEngine On
RewriteBase /
RewriteCond %{QUERY_STRING} ^page=([^&]+)
RewriteRule ^mt$ /PageParser.php?file=%1.php [NC,L]
This rule will rewrite (internal redirect) request for /mt?page=hello to /PageParser.php?file=hello.php without changing URL in browser.
Your source URL example (www.website.com/mt?page=index) has index while target URL (www.website.com/PageParser.php?file=index.php) has index.php. The above rule will add .php to the page name value, so if you request /mt?page=hello.php it will be rewritten to /PageParser.php?file=hello.php.php.
If there is a typo in your URL example and page value should be passed as is, then remove .php bit from rewrite rule.
The rule will work fine even if some other parameters are present (e.g. /mt?page=hello&name=Pinky) but those extra parameters will not be passed to rewritten URL. If needed -- add QSA flag to rewrite rule.
This rule is to be placed in .htaccess in website root folder. If placed elsewhere some small tweaking may be required.
P.S.
Better write no explanation (I knew it/I did it before .. but now I forgot how I did it) than having these "excuses". While it may be 100% true, it just does not sound that great.