Execute PHP script without Redirect - apache

I have below Rewrite rule in .htaccess:
# /m/yyy rule
RewriteRule ^m/([\w-]+)/?$ accounts/$1/index.php [L,NC]
# /m/yyy/abc rule
RewriteRule ^m/([\w-]+)/([\w-]+)$ accounts/$1/$2.php [L,NC]
# /m/yyy/abc/ rule
RewriteRule ^m/([\w-]+)/([\w-]+)/$ accounts/$1/$2/index.php [L,NC]
I want to execute the PHP script view.php if the URL is https://example.com/m/mya/view.php, I expect accounts/mya/view.php to be executed.
Please advise how I can do.

I assume your existing rules are being used for other purposes, since none of them will match the stated URL.
To internally rewrite the request /m/mya/view.php to /accounts/mya/view.php (as stated) then you would add the following before (or after) your existing rules:
RewriteRule ^m/(mya/view\.php)$ accounts/$1 [L]
To make this more generic and rewrite the request /m/<file> to /accounts/<file>, but only if /accounts/<file> exists then you can do something like the following instead before (or after) your existing rules:
RewriteCond %{DOCUMENT_ROOT}/accounts/$1 -f
RewriteRule ^m/([\w/-]+\.\w{2,5})$ accounts/$1 [L]
UPDATE: The regex part \.\w{2,5} matches, what looks-like, a file extension. ie. a dot followed by between 2 and 5 word characters. If you are only matching .php files then you can change this to \.php to hardcode the .php extension. Use a regex testing tool such as regex101.com to test this and get a detailed explanation of the regex (this is not unique to Apache - Apache uses the same regex engine as PHP and other languages, ie. PCRE).
The preceding RewriteCond (condition) directive then checks that this file exists at the intended destination before actually rewriting the request. Without this, the request is rewritten unconditionally, regardless of whether the target file exists or not. eg. /m/abc/xyz/does-not-exist.php would be internally rewritten to /accounts/abc/xyz/does-not-exist.php which then triggers a 404 later (potentially exposing the accounts subdirectory - depending on how you are handling your 404s).
The order of these rules in relation to your existing rules as posted does not matter since the regex (RewriteRule patterns) do not conflict when making a request for a file (that contains a dot before the file extension).

Related

.htaccess : Pretty URL with whatever number+names of parameters

Hello !
I know there already are a lot of topics about URL rewritting and I honestly swear I've spent a lot of time trying to apply them to my problem but I can't see any of them perfectly applying to my situation (if you find otherwise, please give the link).
-----
Here's the problem :
I'm learning MVC model and URL rewriting and I have my URL like this :
http://localhost/blahblahblah/mywebsite/index.php?param1=value1&param2=value2&param3=value3 ... etc ...
What I want (for some MVC template goals) is to have this kind of URL :
http://localhost/blahblahblah/mywebsite/value1/value2/value3 ... etc ...
-----
Whatever are the names of the parameters and whatever are the values.
This is the most essential thing I can't find a solution for.
(Also don't mind the localhost blahblahblah, this has to work even on distant websites but I trust it will work fine on online website has this part of URL may have no importance in what I want to do)
Thanks a lot for your time if you can help me seeing clearer in what I need to do.
If the .htaccess file is located in the document root (ie. effectively at http://localhost/.htaccess) then you would need to do something like the following using mod_rewrite:
RewriteEngine On
RewriteRule ^(blahblahblah/mywebsite)/(\w+)$ $1/index.php?param1=$2 [L]
RewriteRule ^(blahblahblah/mywebsite)/(\w+)/(\w+)$ $1/index.php?param1=$2&param2=$3 [L]
RewriteRule ^(blahblahblah/mywebsite)/(\w+)/(\w+)/(\w+)$ $1/index.php?param1=$2&param2=$3&param3=$4 [L]
# etc.
Where $n is a backreference to the corresponding captured group in the preceding RewriteRule pattern (1st argument).
UDPATE: \w is a shorthand character class that matches a-z, A-Z, 0-9 and _ (underscore).
A new directive is required for every number of parameters. You could combine them into a single (complex) directive but you would have lots of empty parameters when only a few parameters were passed (rather than not passing those parameters at all).
I'm assuming your URLs do not end in a trailing slash.
If, however, the .htaccess file is located in the /blahblahblah/mywebsite directory then then directives could be simplified a bit:
RewriteRule ^(\w+)$ index.php?param1=$1 [L]
RewriteRule ^(\w+)/(\w+)$ index.php?param1=$1&param2=$2 [L]
RewriteRule ^(\w+)/([\w]+)/([\w]+)$ index.php?param1=$1&param2=$2&param3=$3 [L]
# etc.
Don't use URL parameters (alternative method)
An alternative approach is to not convert the path segments into URL parameters in .htaccess and instead just pass everything to index.php and let your PHP script split the URL into parameters. This allows for any number of parameters.
For example, your .htaccess file then becomes rather more simple:
RewriteRule ^\w+(/\w+)*$ index.php [L]
(This assumes the .htaccess file is located in /blahblahblah/mywebsite directory, otherwise you need to add the necessary directory prefix as above.)
The RewriteRule pattern simply validates the request URL is of the form /value1 or /value1/value2 or /value1/value2/value3 etc. And the request is rewritten to index.php (the front-controller) to handle everything.
In index.php you then examine $_SERVER['REQUEST_URI'] and parse the requested URL.

Can htaccess "try" different extensions?

I have a folder with images uploaded by users in a few different formats. The files get numbered by my upload script with a unique ID.
When displaying them via php, I want to be able to link to them without knowing (or having to save in the database) their extension (i.e. images/42, images/69 and not images/42.png, images/69.jpeg. I have been doing some research but can't really come up with a way to write my .htaccess correctly. What I've done so far doesn't work and I had no success either trying to come up with my rewrite conditions. Any suggestions?
RewriteRule ^(.*)/?$ $1.(png|jpg|jpeg|gif) [QSA,L]
I've found this but can't really adapt to my problem: https://httpd.apache.org/docs/2.2/rewrite/flags.html#flag_s
Yes, you can manually try each extension in turn. Each extension will require a different rule. The first extension that matches will "win". If an extension matches then force the respective mime-type.
I assume your image URLs are of the form /images/<number>. This needs to be specific otherwise we will unnecessarily test the wrong URLs.
For example, near the top of your root .htaccess file:
# Check for ".webp" file (and check browser support)
# NB: If webp not supported then there needs to be a fallback (.png or .jpg)
RewriteCond %{HTTP_ACCEPT} (?:^|,)image/webp(?:,|$)
RewriteCond %{DOCUMENT_ROOT}/$0.webp -f
RewriteRule ^images/\d+$ $0.webp [T=image/webp,L]
# Check for ".png" file
RewriteCond %{DOCUMENT_ROOT}/$0.png -f
RewriteRule ^images/\d+$ $0.png [T=image/png,L]
# Check for ".jpg" file
RewriteCond %{DOCUMENT_ROOT}/$0.jpg -f
RewriteRule ^images/\d+$ $0.jpg [T=image/jpeg,L]
# Check for ".jpeg" file
RewriteCond %{DOCUMENT_ROOT}/$0.jpeg -f
RewriteRule ^images/\d+$ $0.jpeg [T=image/jpeg,L]
# Check for ".gif" file
RewriteCond %{DOCUMENT_ROOT}/$0.gif -f
RewriteRule ^images/\d+$ $0.gif [T=image/gif,L]
The $0 backreference contains the entire URL-path that is matched, eg. image/42. Each RewriteCond directive checks for the existence of the file with the respective file extension before internally rewriting the request to that file. The T flag ensures the correct Content-Type header is sent with the response.
images uploaded by users in a few different formats.
An alternative approach is to convert the image into a specific format as part of the upload process. So you always rewrite to .png (for example) - which will be more performant. And this has the added "security" benefit that malicious files (scripts that are "pretending" to be images) will get rejected since the image conversion will likely fail.
MultiViews (alternative)
Alternatively, you could simply enable MultiViews and let mod_negotiation do the work. mod_negotiation then checks various file extensions that return the appropriate mime-type and will return a resource that matches.
For example:
Options +MultiViews
No mod_rewrite directives are necessary.
HOWEVER, you don't have as much control over this, unless you manually create a type map in the server config and this might conflict and cause problems if you have other mod_rewrite directives. MultiViews will apply to everything unless you restrict it to certain paths.
RewriteRule ^(.*)/?$ $1.(png|jpg|jpeg|gif) [QSA,L]
You can't do it in a single rule like this. This directive also matches everything (ie. ^(.*)/?$) - which naturally includes every URL that does not map to an image. The substitution string is an ordinary string, not a regex, so a construct like (png|jpg|jpeg|gif) is seen as literal text. The QSA flag is irrelevant here. The query string is appended by default anyway, but do you image URLs have a query string to begin with?

Best practice for a .htaccess internal path rewrite?

We have spend a considerable amount of time looking for a solution else where. We have read and tried the recommended threads. We most likely have a core misunderstanding as to why this, or something along these lines, does not work.
We get a request for a domain:
subdomain.domain.com/embed/34acb453bc4a53abc
We want to leave the URL as it is, but need to direct this to an internal vhost:
embed.example.com/34acb453bc4a53abc
Once the request is directed to this, our system can interpret the 34acb453bc4a53abc and return the appropriate data.
We tried the following (and variations of it) we just get nothing to work.
RewriteCond ^embed\/(.*)$ [NC]
RewriteRule ^ https://embed.example.com%{REQUEST_URI} [L,NE,P]
internal path rewrite
Just to clarify, you can't internally rewrite the request across different hosts. You need to configure a reverse proxy using mod_proxy and related modules. This is what the P flag on the RewriteRule directive is doing... it's passing the request to mod_proxy (providing this is already correctly configured in the server config).
RewriteCond ^embed\/(.*)$ [NC]
RewriteRule ^ https://embed.example.com%{REQUEST_URI} [L,NE,P]
However, this will send the request to https://embed.example.com/embed/34acb453bc4a53abc, not https://embed.example.com/34acb453bc4a53abc as you require.
You need to capture the part of the URL-path after /embded/ and use that instead. You are already capturing this in the RewriteCond directive, but you are not using it. You don't actually need the RewriteCond directive here.
Try the following instead:
RewriteCond %{HTTP_HOST} =subdomain.domain.com
RewriteRule ^embed/([a-z0-9]+)$ https://embed.example.com/$1 [P]
You state that the request is for subdomain.domain.com, so I've included that in the directive.
The L and NE flags are not required here. P implies L and there is nothing that requires the substitution to not be URL encoded. Slashes do not carry any special meaning in the regex, so do not need to be escaped.
I've also made the regex that matches the "code" more restrictive, rather than matching literally anything.
The $1 backreference then matches just the "code" that follows /embed/ in the URL-path.
Note that the order of directives is important. It needs to be before any directives that are likely to result in a conflict.
If the embed and subdomain hosts point to the same place on the filesystem then you can avoid the complexities and overhead of mod_proxy and simply "rewrite" the request on the same host.

Redirect to a specific page from any dir or subdir in htaccess

Is it possible to use an universal rule to redirect to a specific page from whatever directory or subdirectory using .htaccess?
To be more precise, if I want to have an URL like example.com/login that redirects to example.com/login.php?action=login, I use the following line in my .htaccess file:
RewriteRule ^login$ /login.php?action=login [L]
But is it possible to to have a rule that lets me redirect from example.com/any_directory/login to example.com/login.php?action=login? So from anywhere down the example.com subdirectories to ``example.com/login.php?action=login`. And if yes, how can I do this
Certainly that is possible. Easiest is to use a rewrite condition since that operates on the absolute request path even inside a dynamic configuration file. Rewrite rules operate on a relative path i such location which makes matching complicated...
Take a look at this simple example:
RewriteEngine on
RewriteCond %{REQUEST_URI} /login$
RewriteRule ^ /login.php?action=login [L]
If you do the rewriting in the http servers host configuration instead you can simplify that. Reason is that it is always absolute paths the rules work on in that location:
RewriteEngine on
RewriteRule /login$ /login.php?action=login [L]
The main approach in both variants is to rely on the slash preceding the login key word. It always is present in an absolute request path and clearly left-delimits the key word. And not to insist on matching at the line start.
And a general hint: you should always prefer to place such rules inside the http servers host configuration instead of using dynamic configuration files (".htaccess"). Those files are notoriously error prone, hard to debug and they really slow down the server. They are only provided as a last option for situations where you do not have control over the host configuration (read: really cheap hosting service providers) or if you have an application that relies on writing its own rewrite rules (which is an obvious security nightmare).
You need to adjust your regex pattern .Simply remove the ^ ,so that it can match anychars before login/ in uri ie : /foobar/login .
RewriteRule /login/?$ /login.php?action=login [L]

exclude files from rewrite rule in .htaccess

I'm modifying an existing website that uses a fairly complex .htaccess file to implement a custom MVC type framework so all urls are redirected to index.php?[some parameters] or a 404 page. I'd like to add ajax support to a limited area of the site using XAJAX, and to implement that I need to place two files in the root which are ignored by the rewrite rules. How do I do that?
How about identity rewriting rule with “last” flag on the top of your rules?
For example, to exclude “/a-file-outside-of-rewriting.html” from current set of rules, the following configuration might help:
# http://~/outside-of-rewriting.html will be rewritten to itself (i.e., unmodified).
# then no more rules will be applied (because it has “last” flag.)
RewriteRule ^/a-file-outside-of-rewriting.html$ $0 [L]
RewriteRule ^/any/other/rules(/.*) $1
RewriteRule ^/already/exist(/.*) $1
# ...