I had a redirector, which gave everything after / in the url to the hidden index.php as a parameter (which then redirects the user with js' window.location later to an another domain, the host does not support external redirections by .htaccess), but I lost the code. Each file (index.php, .htaccess) is in the /storage folder.
The .htaccess was something like this, but I can't figure it out:
RewriteRule ^(.*) /?$1 [R,L]
This one is making an infinite loop of redirections.
It worked as entering http://storage.mysite.com/file.png would open http://storage.mysite.com/?file.png.
I tried to avoid the use of directly calling index.php in the .htaccess, as it redirected with this:
<?php
echo "
<script>
window.location='http://otherdomain.com/12345678".$_SERVER['REQUEST_URI']."'
</script>
"; // note there's no slash after the number, the REQUEST_URI had it
?>
What would be the proper way to do this?
Sounds like this is what you need:
RewriteCond %{REQUEST_URI} !^/index.php
RewriteRule ^(.*)$ index.php
In PHP, $_SERVER['REQUEST_URI'] will still be the original requested URI /file.png.
Getting rid of the R flag will fix the looping. Additionally, there is no need to add the request URI as a GET parameter as explained bellow.
The R flag means that the new address /?file.png is sent to the browser and the browser then makes a new request for that URI.
Removing the R flag will mean that Apache serves the new file index.php without telling the browser.
This means that although index.php is being parsed, the request URI is still /file.png.
RewriteCond %{REQUEST_URI} !^/index.php means if the request is for /index.php, then it is not rewritten.
I have tested this and it works. If you have any problems please comment.
* means "0 or more". If you only want to redirect if there is at least one then you should use + instead.
Related
So basically I have a website with user profiles. I want users to be able to query a profile like this:
www.example.com/john
and that would trigger another page I've written in PHP to display that profile but WITHOUT then changing the url. I've looked at other examples on SO like this:
How do I achieve a url like www.example.com/username to redirect to www.example.com/user/profile.php?uid=10?
However this uses url rewriting which means the URL would then change. For instnace if the page is called users.php, I don't want this to happen:
user queries www.examples.com/john -> page is changed to www.examples.com/users.php?name=John
I want the url to stay as www.examples.com/john but for the server to serve up the page www.examples.com/users.php?name=John
Would I still use url rewriting to achieve this even though I don't want the url to change in the url bar? Hope someone can help, thank you!
Usually who needs this kind of feature uses Routers.
Routing is the process of taking a URI endpoint (that part of the URI which comes after the base URL) and decomposing it into parameters to determine which module, controller, and action of that controller should receive the request.
Basically you can take your url and divide it in parameters. The response it's related to the input url.
There are some good libraries in php which allows you to handle routers, for example:
Dispatch: https://github.com/noodlehaus/dispatch
Phroute: https://github.com/mrjgreen/phroute
In phroute you can solve your problem just with:
$router->get(['/user/{name}', 'username'], function($name){
//retrieve $name information
return 'Hello ' . $name;
})
Just for information, every MVC framework uses router as standard.
Using .htaccess File
RewriteEngine on
RewriteRule ^/([a-zA-Z0-9])$ /users.php?name=$1
I hope this will solve your issue, now what it will do, on the front or to the public url is like http://www.example.com/john but users.php script on your server will receive a GET parameter name which will have the value john.
Just make sure apache mod_rewrite is turned on.
With Apache's rewrite module, you can do a rewrite or a redirect.
Redirect means, send a response (status code 301, 302) to the client and ask to fetch another URL. This causes the browser's URL bar to change to the new URL. This happens, when you add the R|redirect flag to a rule, e.g.
RewriteRule ^foo$ /bar.html [R,L]
or when the target is an absolute URL containing a domain, e.g.
RewriteRule ^foo$ http://www.example.com/bar.html [L]
Rewrite on the other side, means take the request and send an answer somehow, without redirecting the client to another resource.
RewriteRule ^foo$ /bar.html [L]
This time, the client asks for foo, but the server sends the contents of bar.html without telling the client.
So, as long as you don't add the R flag, or give an absolute URL, the client's URL bar won't change, e.g.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^john$ /users.php?name=john [L]
or more general
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ /users.php?name=$1 [L]
I am trying to both rewrite and redirect this URL:
https://www.domain.com/video-lessons-page.php?item=stocks
to go to this URL:
https://www.domain.com/stocks-video-lessons
Here is the code I'm currently working with:
RewriteCond %{QUERY_STRING} ^item=([^&]+)
RewriteRule ^/?video-lessons-page\.php$ https://www.domain.com/%1-video-lessons? [R=301,L]
RewriteRule ^(stocks|finance|accounting)-video-lessons$ video-lessons-page.php?item=$1 [NC,L]
Unfortunately with the above code I'm having issues. The first two lines work great by themselves in that it redirects /video-lessons-page.php?item=stocks to /stocks-video-lessons.
And the third line also works great by itself to where the /stocks-video-lessons URL functions correctly with the GET variable and the page's code.
But putting them together is problematic. Right now I'm getting errors like "www.domain.com redirected you too many times." etc. Any ideas?
Just to clarify, presumably you have already changed all your internal URLs to the form /stocks-video-lessons and the reason for the external redirect is because the "ugly" URLs have already been indexed and linked externally?
As you have found, you are getting a redirect loop because these two rules conflict and it's constantly redirecting/rewriting from one to the other.
You need to redirect when only the initial request contains the URL /video-lessons-page.php, not the rewritten URL (which is what's happening here). You can check the initial request by checking against THE_REQUEST server variable (which contains the full HTTP request as sent by the browser).
Something like the following:
RewriteCond %{THE_REQUEST} /video-lessons-page\.php?item=(\w+)
RewriteRule ^video-lessons-page\.php$ https://www.example.com/%1-video-lessons? [R=301,L]
RewriteRule ^(stocks|finance|accounting)-video-lessons$ video-lessons-page.php?item=$1 [L]
Note you must clear your browser cache before testing, since 301 (permanent) redirects will be cached by the browser. (Often easier to test with 302 redirects.) Only use the NC flag if you specifically need a case-insensitive match.
UPDATE: I've changed the regex on the query string parameter value, from ([^&]+) to the slightly more restrictive (\w+). \w being the shorthand character class for a word character (which naturally excludes & and crucially spaces). Since THE_REQUEST contains a string of the form:
GET /video-lessons-page.php?item=stocks HTTP/1.1
...we need to stop capturing before the space. The previous pattern ([^&]+) would have captured everything to the end of the string ie. "stocks HTTP/1.1". So, I would have expected a 404, since an invalid redirect would have occurred but the internal rewrite would have failed. (?)
Thanks to w3dk's guidance, I figured it out, just needed a QUERY_STRING to stay in place in addition to the THE_REQUEST.
Final code:
RewriteCond %{THE_REQUEST} video-lessons-page\.php
RewriteCond %{QUERY_STRING} ^item=([^&]+)
RewriteRule ^video-lessons-page\.php$ https://www.example.com/%1-video-lessons? [R=301,L]
RewriteRule ^(stocks|finance|accounting)-video-lessons$ video-lessons-page.php?item=$1 [L]
so I have this htaccess entry:
RedirectMatch /([a-zA-Z0-9]+).php /dirA/$1.php
The goal is that any .php that is on the root directory should be redirected to /dirA/*.php
eg. suppose I make the request
domain.com/something.php
it should instead redirect to
domain.com/dirA/something.php
However when I put that entry in my .htaccess file and then I go to domain.com/something.php
it instead returns
"The page isn't redirecting properly
Firefox has detected that the server is redirecting the request for
this address in a way that will never complete."
Any idea how I can modify my htaccess to accomplish what I want to do?
Updated Question
Also is there a way to make it so that it only redirects if the file doesn't exist in the root directory...hence if x.php exists in root, serve that x.php otherwise redirect to dirA/x.php
mod_rewrite is an overkill for this, you were on the right track with RedirectMatch. Your rule, however, is a bit faulty: the regex /([a-zA-Z0-9]+).php matches all string that contain the specified substring, so it matches "/foo/bar/baz.php", but also "dirA/foo/bar.php" (and even "/foo/bar.php/baz.php"I. Your redirection ended up in an endless loop because there was no stop condition: /dirA/foo.php was redirected to /dirA/foo.php.
You can remedy the situation by using anchors in the regex:
RedirectMatch ^/([a-zA-Z0-9]+).php$ /dirA/$1.php
As for your second question: that might indeed call for mod_rewrite. Something along these lines should do the trick:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([a-zA-Z0-9]+).php$ /dirA/$1.php [R=301]
I haven't tested it, but this should get you started. Make sure to check out the manual for details, or just search around on SO, there are tons of questions about this.
Try this
RewriteEngine On
RewriteRule ^([a-zA-Z0-9]+).php /dirA/$1.php [R=301,L]
This one should be just fine
RewriteRule ^(.*)$ /subdir/$1
When my client adds a page to the site, the new pagename should be appended to a RewiteRule regex. So with, for instance fwrite(), I would like PHP to change that RewiteRule regex with values retracted from the database. If this could be done, are there any pitfalls in the process?
Edit: handling in a PHP script would be the solution, if there would'nt be more to it...
First domain/index.php?page=pagename is 301 redirected to "domain/pagename"
to warn the visitor this page is permanently moved - (this is the old
PUBLIC location of the URL and should give this 301). Then requests
like "domain/pagename" (the new public location), would be
silently,internally rewritten to domain/index.php?page=pagename where
verification takes place and a 404 is given when not valid. But just
the key, the "page" part of ?page=pagename, is static and can be
verified and will give a 404 directly from within the .htaccess . Now,
requests like domain/index.php?page=crap will first nicely give a 301
like the valid domain/index.php?page=pagename does, and only when
arrived in the index.php can be identified as crap. So there is still
a need to get the pagenames from the database to inside the .htaccess.
This is a sample of the .htacces content to give some background to this problem:
ErrorDocument 404 http://localhost/testsite/404.php
RewriteEngine on
RewriteBase /testsite/
## block craprequests without extension like domain/crap > 404
# The requests domain/pagename that do not go to existing pages, will now be redirected with a 302 to index.php?page=pagename and only then give a 404 through the errorcheck in the code.
# This should be done here, with a RewriteCond regex with database content
RewriteCond %{REQUEST_URI} !404.php$
RewriteRule .* 404.php [R=404,L]
## block-direct-queries ##
RewriteCond %{QUERY_STRING} !marker=1$
RewriteCond %{QUERY_STRING} page=(.*)
RewriteRule ^.*$ %1? [R=301,L]
## strip-extensions ##
RewriteCond %{QUERY_STRING} !.
RewriteCond %{REQUEST_URI} !404.php$
RewriteRule ^([\w+%*\d*\+*\-*]+)\.(php[\s]{0,3}|htm[\s]{0,3}|html[\s]{0,3})$ $1 [R=301,L]
## put-querystring
RewriteRule ^([\w\-_]+)\/?$ index.php?page=$1&marker=1 [L]
I'm sorry to keep repeating this back to you, but there just isn't a need for storing the page name in the .htaccess. This can all be done much more simply in PHP.
The only rewrite rule you need is this:
RewriteCond %{REQUEST_URI} !^/?index\.php$
RewriteRule .* /index.php [L,QSA]
Now, in PHP, you can do something like this:
// The important point here is that $_SERVER['REQUEST_URI'] contains the actual
// path the user typed into their browser, which is what you are interested in
if (strtolower(basename(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH))) === 'index.php') {
// The user directly requested index.php
if (!empty($_GET['page']) || value_of_page_is_crap()) {
// The user requested a bad page
header("{$_SERVER['SERVER_PROTOCOL']} 404 Not Found");
} else {
// Redirect to correct URL
header("{$_SERVER['SERVER_PROTOCOL']} 301 Moved Permanently");
header("Location: http://{$_SERVER['HTTP_HOST']}/{$_GET['page']}");
}
exit;
}
// The request is allowed to continue
$requestedPage = pathinfo($_SERVER['REQUEST_URI'], PATHINFO_FILENAME);
The .htaccess will route every single request blindly through PHP, where much more precise logic than mod_rewrite's clunky PCRE-based rules can be used.
The PHP script examines the URI the user typed into their address bar in the browser. If they directly requested index.php, it will check whether $_GET['page'] contains a sensible value and if it does, redirect them to the correct URL, if not respond with a 404. If the user did not request index.php directly, the script can continue. I have added an example line to show how you could extract the value of the page they requested, but how you continue on from here is up to you.
This will most likely be possible (although writing permissions may be an issue). However wouldn't it be a better way to route all requests from the client through the index.php file and let PHP handle the routing.
This way you will be maximum flexible and you don't have to do "hacky" stuff.
EDIT
All forms of redirect can be done from PHP. E.g. an example of a 301 redirect:
header ('HTTP/1.1 301 Moved Permanently');
header ('Location: http://example.com/new/path'); // note the full address
exit();
Please see the manual for more information about the use of header().
In my .htaccess file I have defined the following rule to make my register page URL as http://example.com/register/
RewriteRule register/ /register.php
The above rule is perfectly fine but I can access my register page from http://example.com/register/ as well as from http://example.com/register.php.
I don't want that user will be able to access the URL from http://example.com/register.php URL, is there any RULE which I can define in .htaccess to stop execution of register.php URL or simply redirect any direct register.php request to /register/
If you are doing this to avoid getting multiple links to the same content, you can simply don't use "register.php" anywhere on your page. I think no search engine will "guess" for a certain file type and if there are no security concerns you are on the safe side, because in my opinion no user will link to this file either. However if you want to be certain just reroute all your functionality through an index.php via one line in your .htaccess which should be placed inside your www-root directory:
RewriteEngine on
RewriteRule ^(.*?)$ index.php?file=$1
In your index.php you can then simply choose which function/file to invoke by breaking down and checking the $_GET["file"] parameter. To make 100% certain no one can access your register.php file directly just move it (and all your others) to a separate directory and include a .htaccess file with the following line:
DENY from all
There are a couple of other options to prevent direct access. Just define() a variable somewhere in your index.php and at the top of your register.php just put
defined('access') or die('Intruder alert!');
at the top. Another way could be to be honest and simply tell search engines that your content has been moved and that they no longer should use the old link:
header("Status: 301"); /* Content moved permanently */
header("Location: http://yourserver/Register/");
exit;
Update
Just one more thing that crossed my mind, you can also check $_SERVER["REQUEST_URI"], whether the user attached any ".php" and act accordingly by either denying access completely or just redirecting to the new location.
It is true that you cannot use location directive, but you can actually paste .htaccess file into any directory.
Just if you put this into it, say:
Options -Indexes
order allow,deny
deny from all
you can copy paste this file into any (root) directory you want to protect from external execution.
To check the initial requested URL path, you need to use the request line. So try this rule:
RewriteCond %{THE_REQUEST} ^GET\ /[^?\s]+\.php[/?\s]
RewriteRule (.+)\.php$ /$1 [L,R=301]
And then again your rule (in a slightly modified way):
RewriteRule ^register/$ register.php
If you want to completely block /register.php by using mod_rewrite, use a variant of SleepyCod's answer:
RewriteCond %{REQUEST_FILENAME} register\.php [NC]
RewriteCond %{IS_SUBREQ} false
RewriteRule .* - [F,L]
Explanation:
[NC]: Makes the condition case-insensitive, just in case you're on a windows box.
Condition 1: The requested filename is 'register.php', and
Condition 2: The request is no subrequest (this is important, since every new round through RewriteRules actually creates subrequests).
Rule: essentially do nothing
Flags: [F]: Send an 403 Forbidden header, [L]: This is the last rule to apply, skip all following rewrite rules
Rewriting correctly is an art by itself. I suggest you carefully read http://httpd.apache.org/docs/2.2/rewrite/.
Cheers,
Try this.
RewriteCond %{REQUEST_FILENAME} ^register\.php$ [NC]
RewriteRule ^/register register.php
Or this
Redirect register.php /register
Ignoring the user-experience part, you can implement the new rel=canonical link to sort out the search engines.
Although, for this case you should probably just use a 301 redirect from /register.php to /register/
In register.php
if ( stristr( $_SERVER['REQUEST_URI'], '.php' ) )
{
header ('HTTP/1.1 301 Moved Permanently');
header ('Location: /register');
}