htaccess URL rewriting PHP for posts and offers - apache

i've searched for a long time an answer for my issue, I found a lot of ideas, but I can't figure it out and make it work as I expect..
So, I've a website with
"/index.php"
"/posts.php"
What I want is to rewrite the url in order to :
redirect "/index.php", "/index.php/" and "/index/" to "/"
and also :
redirect "/posts/slug-post-1/" to "offers.php" but still display "/posts/slug-post-1/" in which I would split the url to get the slug of the post.
Thanks
What I've tried is :
## To internally redirect /dir/foo to /dir/foo.php
RewriteCond %{REQUEST_FILENAME}.php -f [NC]
RewriteRule ^ %{REQUEST_URI}.php [L]
It actually display "/offers/" and redirect to "/offers.php"
but when i add a post slug, it doesn't work.
So I've also tried :
RewriteRule ^posts/([^/]*)$ /posts.php?slug=$1 [L]
It works only with ctrl+F5 and not a simple refresh.. I don't understand why. This is the same with different brwoser and computer.

I'll give it a shot :-)
To redirect "/index.php", "/index.php/" and "/index/" to "/".
RewriteRule index(.*)$ / [NC, L]
Edit: I really urge you not to change the default behaviour of a crucial file like index.php in main folder. There will be unforeseen consequences.
And the other one:
RewriteRule posts/slug-post-1(.*)$ offers.php [QSA, NC, L]
In your example:
Your RewriteCond %{REQUEST_FILENAME}.php -f [NC] checks if "requests filename" with .php added is a real existing file.
Use RewriteCond ${REQUEST_FILENAME} !-f to make sure the targeted file is not skipped, although it is existing. !-d would check for directories.
If you want slugs to be added dynamically to the new target, use flag QSA, so [QSA, NC, L] instead of [NC, L], for example. Use the condition before the rule.

This is really a comment - but space is limited.
It looks as if you haven't thought through what you are trying to achieve before trying to implement it.
What I want is to rewrite the url in order to : redirect "/index.php", "/index.php/" and "/index/" to "/"
I think you need to do a lot more searching. Webservers don't serve up directories, they typically have a lot of machinery in place to service up content when presented with a request where the path maps to a directory to change that to a file, a script, or a special handler.
I suspect you want to rewrite /, /index.php/ and /index/ to /index.php
But I suspect there's more to what you are trying to achieve here - that you also want to deal with any string after the pattern you are seeking to match which is implied in your attempts to deal with /posts.
So it looks as if you are trying to implement 2 front controller patterns. Implementing a single front controller pattern appears to be a bit of a stretch for you. Implementing 2 at the same time is unlikely to turn out well and whatever you do finally implement will likely be very fragile. You're going to need a router in /index.php so that is the right place to handle the /posts/ requests.
But this is only PART of the problem you need to solve. Having your PHP code intercepting all requests is rather expensive in terms of CPU and memory (unless you have a really good caching policy implemented on your server and it is sitting behind a caching reverse proxy).

Related

Block direct access to .php files, less the index.php file and ajax.php file

been looking for your help, i found a method, but it is not as i wish. if someone can help me.
What I want is that nobody can enter a direct URL with .php
example when I enter my domain.com/buy/product.php, I want it to be forbidden,
I was looking for information here, I found this code that worked for me but in .htaccess
RewriteEngine On
RewriteCond %{THE_REQUEST} "^.+? [^?]+\.php(?:[?/# ]|$)" [NC]
RewriteRule !^index\.php$ - [F,L,NC]
it worked fine for me, but the problem that I in a directory /include/ajax.php , I use an ajax. and it gives me error to execute the ajax by browsing.
Now what I'm thinking how to make it work with that htaccess code that you can enter the index.php and /include/ajax.php, I tried all means but it does not work for me.
In another case if you know any code to add to my php or how to do for my version which is version 7.3, but without ruining my code.
Rather than giving you the answer straight out, I'm going to give you some hints so that you aren't copying code you don't understand.
Each RewriteRule has three parts:
the pattern to match against the URL sent by the browser
the URL to rewrite to
an optional set of flags for extra options
Before each rule, you can optionally have one or more RewriteCond lines which apply extra conditions to the rule; each has three parts:
a variable to match against
the pattern to match
an optional set of flags for extra options
The most important flag in this case is [F], short for [forbidden], which says "if the rule matches, instead of rewriting or redirecting, just server a 403 response.
You should very rarely need to test against %{THE_REQUEST}, which is a raw version of the request line from the browser; much more often, you want %{REQUEST_URI} and/or %{QUERY_STRING}.
The patterns in both RewriteRule and RewriteCond can be negated (i.e. "must not match this pattern") by starting them with !
So, if you wanted to return a 403 for all URLs ending ".bad", except for URLs ending "not.bad" or "only-a-little.bad", you could write this (note that $ is the way to say "must end here" in the regex patterns):
RewriteCond %{REQUEST_URI} !not.bad$
RewriteCond %{REQUEST_URI} !only-a-little.bad$
RewriteRule .bad$ - [F]
Hopefully it should be straight-forward enough to see how to adapt that to your requirements.
The full list of options and variables available is in the Apache manual.
After 2 days of looking for some code, I was able to read and understand.
study how htaccess works.
Thanks to the users who guided me, I found the solution.
Although my title is not quite correct.
My intention was always to block all .php that always the user wanted to enter directly by .PHP, I had found the code above, but it did not work with a specific file in the /include/ajax.php folder, exactly it was an ajax, I could not find solution.
exactly it was an Ajax, I could not find the solution to make it work.
Until I managed to solve this way.
RewriteEngine on
RewriteCond %{THE_REQUEST} ajax\.php [NC]
RewriteRule ^ - [NC,L]
RewriteCond %{THE_REQUEST} .+\.php [NC]
RewriteRule ^ - [F,L]
This causes all .php to be blocked, except the index.php and the /include/ajax.php file.
This is how it worked for me.
If I am right or wrong, can you give me some guidance.
I leave this in case someone might find it useful in the future.
I was always recommended to route my php, that I would forget about these problems.
I will keep it in mind as I move forward in the future, to route my php.

How to simulate directories with a htacess file (mod_rewrite)?

what I try to do is to simulate directories with the help of a htaccess file.
I have a website with a file like this:
http://www.domain.com/filename.php?t=yeah-a-title-2014
Now, I would like to rewrite the URL above to the following:
http://www.domain.com/directory1/yeah-a-title-2014/
If a visitor enters one of the two URLs, he should see the second one in his address bar but the content of the filename.php?t=yeah-a-title-2014 should be displayed.
I have no idea how to realize this.
Any ideas?
This is better known as SEO-urls (search engine optimized), SEF-urls (search engine friendly), fancy urls and a couple more of those terms. The basic problem with these kind of constructions, is that they cause an infinite loop if not implemented correctly, and therefore usually the THE_REQUEST trick is used, because %{THE_REQUEST} is always equal to the request, even if the url is rewritten, which in turn prevents the external redirect from matching if the internal rewrite matches.
#External redirect
RewriteCond %{THE_REQUEST} ^(GET|POST)\ /filename\.php\?t=(.*)\ HTTP
RewriteRule ^ /directory1/%2/ [R,L]
#Change [R,L] to [R=301,L] after ALL rules do what you want them to do, and before your site goes live
#Internal rewrite
RewriteRule ^directory1/([^/]+)/?$ /filename.php?t=$1 [L]

Proxypass from any subfolder

I'm not that great at proxypass(reverse). So any help would be great.
Here's what I'm trying to do:
I want to pass any subdirectory to the root url.
So hitting mydomain.com/xxxx would get passed to mydomain.com/
What would be the best way to achieve this.
Reasoning is currently we have 55 different variations. And I'd hate to have to create a ProxyPass(Reverse) line for each.
I'm not sure why you want to reverse proxy all of this stuff since the domain never changes. But if for whatever reason you have, you must reverse proxy, you can use ProxyPassMatch which works similar to ProxyPass except you can give it a regex pattern:
ProxyPassMatch ^/(.+)$ http://mydomain.com/
Still, seems to me what you really just want is to internally rewrite instead of sending an entirely new request on behalf of a single request:
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/index\.(php|html?)
RewriteRule ^(.+)$ / [L]
Each "sub-folder" is actually used to track where the user obtained the url (think tv, radio, etc) but we don't want to manage 50+ versions of a page. So the idea was to redirect it to the same page, capture the subdirectory value and use that info. Ideally a query string would be nice but we were told not to use them (readability I'm guessing)
If you use a reverse proxy, you lose the info from the landing page. That means if I go to, http://foo.com/bar1, and that gets reverse proxied to http://foo.com/index.php, the index.php script will not know that it was proxied from /bar1 (though I think you can pass that along as proxied headers). So that kind of defeats the purpose. If you internally rewrite, like above, the browser is hidden from it all, and won't know that any internal routing has happened. You can also pass query strings if you like, since everything is completely hidden from the browser:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ /index.php?subdir=$1 [L]
So with those rules, if someone goes to http://foo.com/tv and the /tv isn't a folder or file, it gets internally routed to /index.php and the "tv" is passed to the script as the GET parameter "subdir".

RewriteRule and php download counter

(1) I have a site that serves up MP3 files:
http://domain/files/1234567890.mp3
(2) I have a php script that tracks file download counts:
http://domain/modules/download_counter.php?file=/files/1234567890.mp3
After download_counter.php records the download, it redirects to the original file:
Header("Location: $FQDN_url");
(3) I'd like all my public links to be presented as the direct file urls from (1). I'm trying to use Apache to redirect the requests to download_counter.php:
RewriteRule ^files/(.+\.mp3)$ /modules/download_counter.php?file=/files/$1 [L]
I'm currently stuck on (3), as it results in a redirect loop, since download_counter.php simply redirects the request back to the original file (rather than streaming the file contents).
I'm also motivated to use download_counter.php as is (without modifying it's redirect behaviour). This is because the script is part of a larger CMS module, and I'd like to avoid complicating my upgrade path.
Perhaps there is no solution to my problem (other than modifying the download_counter script). WDYT?
If this is not about the strongest protection ever (as I can see, it is not), then just have your script to redirect browser not to the file, but to the
http://domain/files/1234567890.mp3/redirected
Ensure your webserver will still serve such request correctly as a file download. If it will, then just add negative RewriteCond that will ensure, that redirection is done if and only if the link is not ending with /redirected
UPDATED ANSWER
i think you are into a lot of troubles because your pseudo url are actually real urls: they lead to the file. So you should change your pseudo url to something like domain.com/downloads/file.mp3 and then just check whether the requested file does not exist, so that the redirect does not loop.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^downloads/(.+\.mp3)$ /modules/download_counter.php?file=/files/$1 [L]
I first thought something that would use the referer would work:
RewriteCond %{HTTP_REFERER} !download_conter\.php
RewriteCond %{HTTP_REFERER} !=""
RewriteRule ^files/(.+\.mp3)$ /modules/download_counter.php?file=/files/$1 [L]
However, the browser does not cooperate. Let's say you click some link in file.html to something.mp3 and then are forwarded to download_counter.php. When the php script does the forward it sets as referer not download_counter.php but file.html.
The only way I see you could do this would be using an external rewriting program that would keep some state -- the first time the user requested the file it would save that information and make the rewrite, the second time it would know it had made the rewrite in the first place and would pass through the request unmodified. See the documentation of RewriteMap.
Put in http://domain/files/ this .htaccess file...
RewriteEngine On
RewriteOptions Inherit
RewriteRule ^(.*).(mp3)$ /modules/download_counter.php?file=$1.$2 [R,L]
This should do the trick...

Why would mod_rewrite rewrite twice?

I only recently found out about URL rewriting, so I've still got a lot to learn.
While following the Easy Mod Rewrite tutorial, the results of one of their examples is really confusing me.
RewriteBase /
RewriteRule (.*) index.php?page=$1 [QSA,L]
Rewrites /home as /index.php?page=index.php&page=home.
I thought the duplicates might have had been caused by something in my host's configs, but a clean install of XAMPP does the same.
So, does anyone know why this seems to parse twice?
And, to me this seems like, if it's going to do this, it would be an infinite loop -- why does it stop at 2 cycles?
From Example 1 on this page, which is part of the tutorial linked in your question:
Assume you are using a CMS system that rewrites requests for everything to a single index.php script.
RewriteRule ^(.*)$ index.php?PAGE=$1 [L,QSA]
Yet every time you run that, regardless of which file you request, the PAGE variable always contains "index.php".
Why? You will end up doing two rewrites. Firstly, you request test.php. This gets rewritten to index.php?PAGE=test.php. A second request is now made for index.php?PAGE=test.php. This still matches your rewrite pattern, and in turn gets rewritten to index.php?PAGE=index.php.
One solution would be to add a RewriteCond that checks if the file is already "index.php". A better solution that also allows you to keep images and CSS files in the same directory is to use a RewriteCond that checks if the file exists, using -f.
1the link is to the Internet Archive, since the tutorial website appears to be offline
From the Apache Module mod_rewrite documentation:
'last|L' (last rule)
[…] if the RewriteRule generates an internal redirect […] this will reinject the request and will cause processing to be repeated starting from the first RewriteRule.
To prevent this you could either use an additional RewriteCond directive:
RewriteCond %{REQUEST_URI} !^/index\.php$
RewriteRule (.*) index.php?page=$1 [QSA,L]
Or you alter the pattern to not match index.php and use the REQUEST_URI variable, either in the redirect or later in PHP ($_SERVER['REQUEST_URI']).
RewriteRule !^index\.php$ index.php?page=%{REQUEST_URI} [QSA,L]