Unable to rewrite multiple URL rewrite with same paramters - apache

Need your expert help. I am trying to rewrite 2 url's in htaccess where both url's have same parameters. After rewriting url only 1st url rewrite is working. Can anybody help me on how to make both url rewrite work?
Here is my htaccess code code.
1st URL : http://www.example.com/quotaid.php?id=id/address
which i want to rewrite to
http://www.example.com/id/address
//1st URL rewrite
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/([a-zA-Z0-9]+|[0-9a-zA-Z]+)/?$
RewriteRule ^([a-zA-Z0-9]+|[0-9a-zA-Z]+)/(.*)$ quotaid.php?id=$1 [NC,L]
2nd URL : http://www.example.com/zipquota.php?zip=zip/address
which i want to rewrite to
http://www.example.com/zip/address
//2nd URL rewite in htaccess
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/([a-zA-Z0-9]+)?$
RewriteRule ^(.*)$ zipquota.php?zip=$1 [NC,L]
Only one url rewrite is working which comes first. If i move the 2nd url rewrite to top, then the 2nd url rewrite is working but the 1st url stops working. PLease help on how to manage both url rewrite working.

I assume this is what you are looking for:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/?([0-9]+)/(.+)$ /zipquota.php?zip=$1&address=$2 [NC,END]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/?([0-9a-z]+)/(.+)$ /quotaid.php?id=$1&address=$2 [NC,END]
These are the internal rewritings applied by that, as specified by you in the comments to the question, though I dare say that the address argument makes zero sense and probably will get removed in future...:
https://example.org/91007/HOMES-FOR-Arcadia-CA => /zipquota.php?zip=91007&address=HOMES-FOR-Arcadia-CA
https://example.org/CV17057071/3677-Louise-Street-Lynwood-CA-90262 => /quotaid.php?id=CV17057071&address=3677-Louise-Street-Lynwood-CA-90262
Those rules should work in the http servers host configuration and likewise in dynamic configuration files (.htaccess). To be able to use them in a dynamic configuration file some preconditions have to be matched: the interpretation of such files has to be enabled in the http servers configuration (AllowOverride ...), the file has to be readable by the http server and it has to be placed inside the DOCUMENT_ROOT folder configured for that http host.
The zip based URLs are rewritten first, since they use a more specific pattern, purely number based. Then comes the more general rule for ids with alphanumeric patterns. The condition you originally had does not really make sense, I removed it.
Note: I also took the liberty to make those target paths absolute (leading slash) to make the setup more robust. That obviously requires those scripts to be located directly inside the DOCUMENT_ROOT folder. otherwise the paths have to be adjusted.
Warning: In case you get a http status 500 (internal server error), chances are that you operate a very old version of the apache http server. In that case you have to replace the END flag with the L flag. You can see a hint on that in your http servers error log file in that case. The L flag should work too, unless you have more rewriting rules that might create a conflict.
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).

Related

.htaccess rewrite returning Error 404

RewriteEngine on
RewriteCond %{QUERY_STRING} (^|&)public_url=([^&]+)($|&)
RewriteRule ^process\.php$ /api/%2/? [L,R=301]
Where domain.tld/app/process.php?public_url=abcd1234 is the actual location of the script.
But I am trying to get .htaccess to make the URL like this: domain.tld/app/api/acbd1234.
Essentially hides the process.php script and the get query ?public_url.
However the script above is returning error 404 not found.
I think this is what you are actually looking for:
RewriteEngine on
RewriteCond %{QUERY_STRING} (?:^|&)public_url=([^&]+)(?:$|&)
RewriteRule ^/?app/process\.php$ /app/api/%1 [R=301,QSD]
RewriteRule ^/?app/api/([^/]+)/?$ /app/process.php?public_url=$1 [END]
If you receive an internal server error (http status 500) for that then check your http servers error log file. Chances are that you operate a very old version of the apache http server, you may have to replace the [END] flag with the [L] flag which probably will work just fine in this scenario.
And a general hint: you should always prefer to place such rules inside the http servers (virtual) host configuration instead of using dynamic configuration files (.htaccess style files). Those files are notoriously error prone, hard to debug and they really slow down the server. They are only supported 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).
UPDATE:
Based on your many questions in the comments below (we see again how important it is to be precise in the question itself ;-) ) I add this variant implementing a different handling of path components:
RewriteEngine on
RewriteCond %{QUERY_STRING} (?:^|&)public_url=([^&]+)(?:$|&)
RewriteRule ^/?app/process\.php$ /api/%1 [R=301,QSD]
RewriteRule ^/?api/([^/]+)/?$ /app/process.php?public_url=$1 [END]
I am trying to get .htaccess to make the URL like this: example.com/app/api/acbd1234.
You don't do this in .htaccess. You change the URL in your application and then rewrite the new URL to the actual/old URL. (You only need to redirect this, if the old URLs have been indexed by search engines - but you need to watch for redirect loops.)
So, change the URL in your application to /app/api/acbd1234 and then rewrite this in .htaccess (which I assume in in your /app subdirectory). For example:
RewriteEngine On
# Rewrite new URL back to old
RewriteRule ^api/([^/]+)$ process.php?public_url=$1 [L]
You included a trailing slash in your earlier directive, but you omitted this in your example URL, so I've omitted it here also.
If you then need to also redirect the old URL for the sake of SEO, then you can implement a redirect before the internal rewrite:
RewriteEngine On
# Redirect old URL to new (if request by search engines or external links)
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{QUERY_STRING} (?:^|&)public_url=([^&]+)(?:$|&)
RewriteRule ^process\.php$ /app/api/%1? [R=302,L]
# Rewrite new URL back to old
RewriteRule ^api/([^/]+)$ process.php?public_url=$1 [L]
The check against REDIRECT_STATUS is to avoid a rewrite loop. ?: inside the parenthesised subpattern avoids the group being captured as a backreference.
Change the 302 (temporary) to 301 (permanent) only when you are sure it's working OK, to avoid erroneous redirects being cached by the browser.

Moving from IIS ISAPI rewrite to Apache mod_rewrite

I've seen few people have asked this on here already, but none of the solutions provided worked for me so far.
We have always been developing for the IIS ISAPI rewrite (on Windows) and suddenly one of the clients decided to place the project on the Linux server running Apache. As a result some of the rules are no longer working.
Example of an ISAPI rewrite rule:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^login/?([^/]*)([^/]*)$ /login.cfm?msg=$1&$2 [L,QSA]
RewriteRule ^login.cfm$ /login/ [R=301,L,NC]
login.cfm is an actual existing page and not dynamically generated based on template.
Could someone help me how to translate this for the Apache mod_rewrite please? Currently the rule creates an infinitive loop and the output is:
login/?msg=&&msg=&&msg=&&msg=&&msg=&&msg... (till the limit of the url length)
Safe to say the page is not found either so it doesn't even check whether the file with such name exists.
The page could be /login or /login/wrong so the rule should recognize both cases.
You can use these rules in your site root .htaccess:
RewriteEngine On
# external redirect from actual URL to pretty one
RewriteCond %{THE_REQUEST} /login\.cfm\?msg=([^\s&]*)\s [NC]
RewriteRule ^ /login/%1? [R=301,L,NE]
# internal forward from pretty URL to actual one
RewriteRule ^login(?:/([\w-]+))?/?$ login.cfm?msg=$1 [L,QSA,NC]

How do I make a custom URL parser with Apache?

I heard this can be done with the web.config file. I want to make it so, for instance, my URL http://help.BHStudios.org/site might go to http://BHStudios.org/help.php?section=site, or http://i.BHStudios.org/u3Hiu might redirect to some other URL stored in a database with the hash u3Hiu as the key, or if something goes wrong and the internal file structure is exposed like http://Kyli.BHStudios.org/http/bhstudios/v2/self/index.php (something that happens with GoDaddy's servers for whatever reason) it'll change it to its intended URL http://Kyli.BHStudios.org before that's exposed tot he user.
Since I've never done this before, could you please also explain why you gave the answer you did?
A few Apache mod_rewrite rules in either your servers httpd.conf or in a .htaccess file, in your htdocs directory will do the majority of what you want e.g.
RewriteEngine On
RewriteBase /
# Default Rule - for non physical objects (not a file or directory):
# Internally rewrite (user won't see the URL) to /index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ /index.php [L]
#If the Browser request contains a .php, instruct the browser to remove it.
RewriteCond %{THE_REQUEST} \.php [NC]
RewriteRule ^/?(.*)\.php$ http://%{HTTP_HOST}/$1 [R=301,NC,L]
# Specific rule
RewriteRule ^/?site /help.php?section=site
The masking of real file system objects will not be perfect, and slightly pointless, as a user just needs to right click and view source on any served page, to obtain the actual URL's.

Redirect all to index.php using htaccess

I am writing a simple PHP-based MVC-ish framework. I want this framework to be able to be installed in any directory.
My PHP script grabs the request uri and breaks it off into segments. It makes segment 1 the controller and segment 2 the action. This goes all fine when I do this:
http://www.example.com/mvc/module/test/
It will go to the specific module controller and method. Now I have a default controller, the home controller, which is in folder home.
Now when I access this folder directly http://www.example.com/mvc/home/
It will display a 403 forbidden , because this folder does exist, instead it should also go back to http://www.example.com/mvc/index.php
If I would have installed the framework in a different folder, lets say folder framework it has to redirect back to http://www.example.com/framework/index.php
I would like to redirect every folder and php file back to the index.php, leaving everything else the way it is.
My first problem I encountered was it never redirects to the right folder, always to the domain root folder.
This is what I tried :
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . index.php [L]
Your rewrite rule looks almost ok.
First make sure that your .htaccess file is in your document root (the same place as index.php) or it'll only affect the sub-folder it's in (and any sub-folders within that - recursively).
Next make a slight change to your rule so it looks something like:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php?path=$1 [NC,L,QSA]
At the moment you're just matching on . which is one instance of any character, you need at least .* to match any number of instances of any character.
The $_GET['path'] variable will contain the fake directory structure, so /mvc/module/test for instance, which you can then use in index.php to determine the Controller and actions you want to perform.
If you want the whole shebang installed in a sub-directory, such as /mvc/ or /framework/ the least complicated way to do it is to change the rewrite rule slightly to take that into account.
RewriteRule ^(.*)$ /mvc/index.php?path=$1 [NC,L,QSA]
And ensure that your index.php is in that folder whilst the .htaccess file is in the document root.
Alternative to $_GET['path'] (updated Feb '18 and Jan '19)
It's not actually necessary (nor even common now) to set the path as a $_GET variable, many frameworks will rely on $_SERVER['REQUEST_URI'] to retrieve the same information - normally to determine which Controller to use - but the principle is exactly the same.
This does simplify the RewriteRule slightly as you don't need to create the path parameter (which means the OP's original RewriteRule will now work):
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.*$ /index.php [L,QSA]
However, the rule about installing in a sub-directory still applies, e.g.
RewriteRule ^.*$ /mvc/index.php [L,QSA]
The flags:
NC = No Case (not case sensitive, not really necessary since there are no characters in the pattern)
L = Last (it'll stop rewriting at after this Rewrite so make sure it's the last thing in your list of rewrites)
QSA = Query String Append, just in case you've got something like ?like=penguins on the end which you want to keep and pass to index.php.
To redirect everything that doesnt exist to index.php , you can also use the FallBackResource directive
FallbackResource /index.php
It works same as the ErrorDocument , when you request a non-existent path or file on the server, the directive silently forwords the request to index.php .
If you want to redirect everything (including existant files or folders ) to index.php , you can use something like the following :
RewriteEngine on
RewriteRule ^((?!index\.php).+)$ /index.php [L]
Note the pattern ^((?!index\.php).+)$ matches any uri except index.php we have excluded the destination path to prevent infinite looping error.
There is one "trick" for this problem that fits all scenarios, a so obvious solution that you will have to try it to believe it actually works... :)
Here it is...
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [L,QSA]
</IfModule>
Basically, you are asking MOD_REWRITE to forward to index.php the URI request always when a file exists AND always when the requested file doesn't exist!
When investigating the source code of MOD-REWRITE to understand how it works I realized that all its checks always happen after the verification if the referenced file exists or not. Only then the RegEx are processed. Even when your URI points to a folder, Apache will enforce the check for the index files listed in its configuration file.
Based on that simple discovery, turned obvious a simple file validation would be enough for all possible calls, as far as we double-tap the file presence check and route both results to the same end-point, covering 100% of the possibilities.
IMPORTANT: Notice there is no "/" in index.php. By default, MOD_REWRITE will use the folder it is set as "base folder" for the forwarding. The beauty of it is that it doesn't necessarily need to be the "root folder" of the site, allowing this solution work for localhost/ and/or any subfolder you apply it.
Ultimately, some other solutions I tested before (the ones that appeared to be working fine) broke the PHP ability to "require" a file via its relative path, which is a bummer. Be careful.
Some people may say this is an inelegant solution. It may be, actually, but as far as tests, in several scenarios, several servers, several different Apache versions, etc., this solution worked 100% on all cases!
You can use something like this:
RewriteEngine on
RewriteRule ^.+$ /index.php [L]
This will redirect every query to the root directory's index.php. Note that it will also redirect queries for files that exist, such as images, javascript files or style sheets.
Silly answer but if you can't figure out why its not redirecting check that the following is enabled for the web folder ..
AllowOverride All
This will enable you to run htaccess which must be running! (there are alternatives but not on will cause problems https://httpd.apache.org/docs/2.4/mod/core.html#allowoverride)
just in case you were still wondering how to redirect all request either if the directory exists (for core framework folders and files) to the framework index handler, after some error/success attempts just noticed I just needed to change the RewriteCond in the .htaccess file
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
the above condition states "not found files" and "not found directories", ok, what if just remove "not found" (!-d) line, and ended with something like the below:
RewriteEngine on
RewriteBase /framework/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /framework/index.php [L,QSA]
It worked for me like a charm
I just had to face the same kind of issue with my Laravel 7 project, in Debian 10 shared hosting. I have to add RewriteBase / to my .htaccess within /public/ directory. So the .htaccess looks a like
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.*$ /index.php [L,QSA]
After doing that don't forget to change your href in,
home
Example:
.htaccess file
RewriteEngine On
RewriteRule ^about/$ /about.php
PHP file:
about

how to make url rewrite apache whitout any rewrite condition?

sorry, but i'am less understand about url rewrite...
i want to rewrite my url from :
http://localhost/controller/index.php/user/edit
to
http://localhost/controller/user/edit
i can make it with this .htaccess :
RewriteEngine On
RewriteBase /controller/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [PT,L]
but, the rewrite works if there is no file exist at controller/user/edit.php
i want every request to under my controller/xxx is rewrited to controller/index.php/xxx whether the file is exist or not....
i have remove the RewriteCond so my current one is like this :
RewriteEngine On
RewriteBase /controller/
RewriteRule ^(.*)$ index.php/$1 [PT,L]
but, it shown internal service error..
There are a lot of things that don't make sense to me. Mainly, your question says to want to rewrite a URL having index.php in it to one that does not, but your rewrite rule, which you say works in some cases does the opposite, it pre-pends index.php to requests.
If you have access to your apache error and access log, you might see if there's more information about exactly at what point the error occurred -- was it when the .htaccess file was processed, or was it from within your php program?
I will assume that the goal here is to take "pretty" urls like /controller/user/edit and have the index.php program actually process the /user/edit part of the path.
If so, I think you may want to set the RewriteBase to /, and change your .htaccess to
RewriteEngine On
RewriteBase /
RewriteRule ^(.*)$ controller/index.php/$1 [PT,L]
The RewriteBase / directive says that all requests are relative to the server's DOCUMENT_ROOT setting. The change to the rewrite rule instructs all requests to go to the directory controller and file index.php, appending the original requested path afterwards.
(Note: I don't think you want to use the PT flag in this case, and it would be better form to escape the . which is a regex operator as index\.php, but I think neither of these are relevant to the problem here)
It is not clear if you do want the / before the $1. If your PHP program (index.php) is getting called with it present, and knows how to handle it, then it's fine, but it's a little unusual, and there may be cases where you end up with multiple /'s from within the php program.
But do you really want to do this? The typical use of the RewriteCond %{REQUEST_FILENAME} !-f is to handle cases such as image files and css or javascript files that are static and need not be handled by your controller. RewriteCond %{REQUEST_FILENAME} !-d depends on your system (but it's purpose to see that the request is not for a directory).
Anyway, the basic change as I proposed might help, but if not, perhaps you can clarify your intent and provide some actual URLs and a look inside index.php