how to make a htaccess rule from id to name - php

I have a list of unique data:
Suppose I have the following data:
id name
1 Jhon
2 Peter
3 Mark
4 Scotty
5 Marry
I make a .htaccess rule for id:
RewriteRule brandlisting/(.*)/ site/brandlisting?id=$1 [L]
RewriteRule brandlisting/(.*) site/brandlisting?id=$1 [L]
my URL is:
http://localhost/mate/admin/site/brandlisting/3
this works for id.
Now I need a .htaccess rule for name, so I make a rule for it:
RewriteRule brandlisting/(.*)/ site/brandlisting?name=$1 [L]
RewriteRule brandlisting/(.*) site/brandlisting?name=$1 [L]
http://localhost/mate/admin/site/brandlisting/Mark
When I used the above URL I was faced with following error in the console:
"NetworkError: 400 Bad Request -
http://localhost/mate/admin/site/brandlisting/Mark"
and in browser it shows:
Error 400 Your request is invalid.
My current .htaccess file
RewriteEngine on
RewriteCond %{HTTP_HOST} ^localhost/mate/admin$ [NC,OR]
RewriteCond %{HTTP_HOST} ^localhost/mate/admin$
RewriteCond %{REQUEST_URI} !wordpress/
RewriteRule (.*) /wordpress/$1 [L]
Options +FollowSymLinks -MultiViews
RewriteEngine On
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* index.php/$0 [PT,L]
#RewriteRule brandlisting/(.*)/ site/brandlisting?id=$1 [L]
#RewriteRule brandlisting/(.*) site/brandlisting?id=$1 [L]
RewriteRule brandlisting/(.*)/ site/brandlisting?name=$1 [L]
RewriteRule brandlisting/(.*) site/brandlisting?name=$1 [L]

I am starting with your current .htaccess you have crunch all the available rule which meets your needs in one single .htaccess for example rule for wordpress it should be in directory where your wordpress is installed.
Your rule as per your requirement should be like this if you are trying in root directory,
RewriteEngine on
RewriteBase /mate/admin/
RewriteRule site/brandlisting/([\d]+)/?$ site/brandlisting.php?id=$1 [L]
RewriteRule site/brandlisting/([a-zA-Z]+)/?$ site/brandlisting.php?name=$1 [L]
And for wordpress you directory you can create seperate .htaccess where you can put your rule index.php.

.htaccess rules rely on order. If you anticipate using a lot of routes, keep your htaccess rules simple and put your routes into PHP instead, using one of the several already written routing frameworks.
Here's an explanation as to why your .htaccess file isn't working, line-by-line:
RewriteEngine on
This turned the RewriteEngine on. No problems so far.
RewriteCond %{HTTP_HOST} ^localhost/mate/admin$ [NC,OR]
RewriteCond %{HTTP_HOST} ^localhost/mate/admin$
RewriteCond %{REQUEST_URI} !wordpress/
Only match RewriteRule is it's WordPress. This seems to be working, so let's ignore this block of rules.
RewriteRule (.*) /wordpress/$1 [L]
Options +FollowSymLinks -MultiViews
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
Only match below if the requested filename is not a file or a directory.
RewriteRule .* index.php/$0 [PT,L]
Rewrite any path PATH to index.php/PATH. Stop processing if it matched (note the L as last). That means nothing below will be activated.
#RewriteRule brandlisting/(.*)/ site/brandlisting?id=$1 [L]
#RewriteRule brandlisting/(.*) site/brandlisting?id=$1 [L]
RewriteRule brandlisting/(.*)/ site/brandlisting?name=$1 [L]
RewriteRule brandlisting/(.*) site/brandlisting?name=$1 [L]
Assuming that it doesn't match .* (aka, never), check path for other patterns. Note also that the two lines you have commented, and the two lines you don't, both match the same pattern. If one worked, the other would not.
-- Pro Tip: Regex has a shorthand for including a rule with a trailing slash and without one: /? is equivalent to, either with one slash, or with no slashes. Another way to write this is /{0,1}.
How to Fix
.htaccess redirect rules are a pain. My rule of thumb is to make them as easy as possible to write, which makes them easy to read and to maintain. How to do this? Push the redirect logic to your PHP program, rather than forcing Apache to rely on it.
Solution 1
The htaccess-only approach here would be to ensure you understand what Apache rewrite flags are telling your server to do, and adjust accordingly. You can do this here one of two ways:
Make your more specific rules show up first. i.e., move /site/brandlisting?name=$1 rules to before .* rules.
Add a separate rewrite conditions for any followup processing. As per the Apache2 documentation linked above:
The [L] flag causes mod_rewrite to stop processing the rule set. In most contexts, this means that if the rule matches, no further rules will be processed. This corresponds to the last command in Perl, or the break command in C. Use this flag to indicate that the current rule should be applied immediately without considering further rules.
The key point here is that it is within each rule set. Building a new rule set will continue processing.
Example that should work (not tested):
RewriteEngine on
RewriteCond %{HTTP_HOST} ^localhost/mate/admin$ [NC,OR]
RewriteCond %{HTTP_HOST} ^localhost/mate/admin$
RewriteCond %{REQUEST_URI} !wordpress/
RewriteRule (.*) /wordpress/$1 [L]
Options +FollowSymLinks -MultiViews
RewriteEngine On
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* index.php/$0 [PT,L]
#New Rule Set
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Note that /? is the same as writing two separate rules,
# one with a slash at the end, and one without.
RewriteRule brandlisting/(.*)/? site/brandlisting?name=$1 [L]
There are some great pre-built routers out there, like Silex and Slim. If you don't want to use them, you can still use your own internal logic that parses various pieces. From my experience, the more that I can pull out of my .htaccess file, the happier you'll be. It winds up being far easier to debug issues, and it's easier to iterate changes without introducing unintended consequences.
Solution 2
You can use PHP routers in conjunction with the .htaccess file I provided above, like so:
// Slim example
$app = new Slim\Slim();
$app->get('/brandlisting/:key', function ($key) {
if (is_numeric($key)) {
$id = $key;
// call/run $id logic
} else {
$name = $key;
// call/run $name logic
}
});
// ...
$app->run();
If you do this, you can remove any of your brandlisting logic from .htaccess and instead put it into your index.php.
Conclusion
If you can help it, experience tells me that it's better to not write your app logic into .htaccess rules. Instead, make your .htaccess rules simple and use a routing library. If you want to use .htaccess, make sure you understand the Apache rewrite flags you're using, and that Apache reads everything from top to bottom. For example, if the [L] flag is used, Apache stops reading all other rules in the rule set. That means, you have to create a new rule set with additional rules that need to be processed, or put your more specific rules first. Keep in mind that, if those rules have an [L] flag, they will also stop execution of any subsequent rules.

You can use redirect here.
Assuming you have the following folders:
<server root>/mate/admin
place in .htaccess in mate/admin
RewriteBase /mate/admin/
RewriteRule "site/brandlisting/([^\\]+)/" "site/brandlisting?id=$1" [R,L]
RewriteRule "site/brandlisting/([^\\]+)" "site/brandlisting?id=$1" [R,L]

You may be running into an issue where a Directory or other directive is causing your rewrite rules to repeatedly fire and cause infinite redirects.
See the documentation for RewriteRule Flags: L.
Specifically, the following quoted text is relevant:
If you are using RewriteRule in either .htaccess files or in
sections, it is important to have some understanding of
how the rules are processed. The simplified form of this is that once
the rules have been processed, the rewritten request is handed back to
the URL parsing engine to do what it may with it. It is possible that
as the rewritten request is handled, the .htaccess file or
section may be encountered again, and thus the ruleset may be run
again from the start. Most commonly this will happen if one of the
rules causes a redirect - either internal or external - causing the
request process to start over.
It is therefore important, if you are using RewriteRule directives in
one of these contexts, that you take explicit steps to avoid rules
looping, and not count solely on the [L] flag to terminate execution
of a series of rules, as shown below.
You may need to add a rewrite condition or take other steps to prevent looping.

Related

Rewrite Pretty or SEO friendly URL via htaccess

I have a problem with transforming urls from dynamic to static.
I have a site where different pages are generated with a dynamic url, like:
www.example.com/?pr=project-abc123
I would like to rewrite the url of each one with htaccess making it static, like this:
www.example.com/project-abc123
// or
www.example.com/pr/project-abc123
Now, i found this htaccess code that seems to work:
RewriteEngine On
RewriteBase /
RewriteCond %{THE_REQUEST} \?
RewriteCond %{QUERY_STRING} ^p=(.*)$
RewriteRule (.*) http://example.com/%1? [L,R=301]
RewriteRule ^(.*)$ /index/?pr=$1[L]
URLs are rewritten as indicated (first type, whitout /pr/ ), but gives me a multiple choice error. What am I doing wrong?
Let's understand RewriteRule directive which is the real rewriting workhorse.
A RewriteRule consists of three arguments separated by spaces. The arguments are
Pattern: which incoming URLs should be affected by the rule;
Substitution: where should the matching requests be sent;
[flags]: options affecting the rewritten request.
Let's start with the following snippet:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
First line of code, describes RewriteEngine is turned on. Here I use RewriteCond directive which defines a rewrite rule condition. Using RewriteCond directive we defined two conditions here. This directive took a server variable called REQUEST_FILENAME. The two conditions above tell if the request is not a file or a directory, then meet the rule set by RewriteRule. See more details on this issue.
Now it's time to write some rewrite rules. Let's convert
www.example.com/?pr=project-abc123
// to
www.example.com/project-abc123
and rewrite rule will be:
RewriteRule ^(.*)$ index.php/?pr=$1 [L]
And to get the www.example.com/pr/project-abc123 we need the rule as the below:
RewriteRule ^/?([a-z]+)/(.*)$ index.php/?$1=$2 [L]
// or
RewriteRule ^/?pr/(.*)$ index.php/?pr=$1 [L]
The [L] flag tells mod_rewrite to stop processing the rule set. This means that if the rule matches, no further rules will be processed.

Exposed folders in MVC application

Well, as a start please excuse me for my beginner English..
I want to know more about security in PHP MVC applications
I've created my own MVC, I still haven't finished it.
My application directory is exposed by URL access with child elements.
How to make this hidden from visitors?
Following is what I am trying
Apache mod_rewrite ?
I still don't know to make it empty index.html in each folder like the framework Codeigniter ?
What to use for something to indicate ?
and,
... how to make ?
Edit
I know a litte something about rewrite_rules
Below is my .htaccess
Options -MultiViews
RewriteEngine On
RewriteBase /ligia
#RewriteCond %{REQUEST_FILENAME} -f [OR]
#RewriteCond %{REQUEST_FILENAME} -l [OR]
#RewriteCond %{REQUEST_FILENAME} -d
#RewriteRule .+ -
#I know, it is commented
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule "^(.+)$" "index.php?uri=$1" [QSA,L]
But I am afraid if this is the best way to hold my MVC application
security!?
I need help!
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.
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.
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 Apend, just in case you've got something like ?like=penguins on the end which you want to keep and pass to index.php.

htaccess rewrite url and check for 404

I`ve got an internet shop and want to use htaccess to shorten links
there are 3 cases of urls:
shop.com/shop/18 (number) - products.php?categoryid=$1
shop.com/shop/18/page-2 (number)/(page+number) - products.php?categoryid=$1&page=$2
shop.com/shop/18/9877 (number)/(number) - description?categoryid=$1&productid=$2
my try
RewriteRule ^shop/?$ shop.php
RewriteRule ^shop/(.*)/([0-9]+)/?$ description.php?categoryid=$1&productid=$2
RewriteRule ^shop/(.*)/page-(.*)/?$ products.php?categoryid=$1&page=$2
RewriteRule ^shop/(.*)/?$ products.php?categoryid=$1
With my try - 1 (works), 2 (works), 3 (doesn`t work)
How can I rewrite urls so?
How can I redirect to 404 page if e.g. there is no such number of
category or such product (guess check with php and mysql and then
redirect) ?
There are a number of ways that this can be dealt with;
All in htaccess (gets messy with multiple depths)
Combined htaccess and server side code
The best approach is the one that suits you based on how your store is coded. I personally feel that handling it in the server side code is better, it simplifies the htaccess file, and gives you more control with regards to validating data, and how you handle what is sent, to where, and how its processed when it gets there.
For example, in my htaccess file I have;
<IfModule mod_rewrite.c>
Options +FollowSymlinks
RewriteEngine on
#
# Do not apply rewrite rules for non required areas
RewriteCond %{REQUEST_URI} "/hidden-areas/" [OR]
RewriteCond %{REQUEST_URI} "/other-areas/"
RewriteRule (.*) $1 [L]
# Do Not apply if a specific file or folder exists
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# The rules on how to rewrite the urls
RewriteRule (.*) /index.php?url=$1 [QSA,L]
</IfModule>
Basically, to explain this in a nutshell, I DONT rewrite anything for certain folders, I forward them straight on. This is to stop calls to scripts externally, or extra added systems being able to be accessed without issue.
I then, forward the entire url as a string through to my index page, and deal with what comes through using PHP, an example is below.
// collect the passed url
$url = $_GET['url'];
// split the url into parts
$url_parts = explode('/', $url);
/*
* start sorting what is what in the url
*/
// count how many parts there are
$url_parts_count = count($url_parts);
// determine the class/module
$class = $url_parts[0]; // generally the class/method/module depending on your system, thgough could be a category so run some checks
// determine the last part in the array
$last_url_part = ($url_parts_count - 1);
// set the last part of the url to be used
$slug = $url_parts[$last_url_part]; // generally the slug and will be empty if theres a trailing slash
etc etc etc
This is just a summary, i do far more, as this is taken from a CMS I wrote, but it should give you a very good starting point should you wish to get your hands dirty. Of course, Im happy to elaborate further if necessary.
The caveat of course, is if you are using an off-the-shelf system, they should provide you with this code already ;)
I have added below something based on your updated question, this will help if you do still plan to go the way you are :)
<IfModule mod_rewrite.c>
Options +FollowSymlinks
RewriteEngine on
RewriteBase /
#
# Do not apply rewrite rules for non required areas
RewriteCond %{REQUEST_URI} "/hidden-areas/" [OR]
RewriteCond %{REQUEST_URI} "/other-areas/"
RewriteRule (.*) $1 [L]
# Do Not apply if a specific file or folder exists
# RewriteCond %{REQUEST_FILENAME} !-f
# RewriteCond %{REQUEST_FILENAME} !-d
# The rules on how to rewrite the urls
RewriteRule ^([a-zA-Z0-9_-]+)$ /index.php?slug=$1 [QSA,L]
RewriteRule ^([a-zA-Z0-9_-]+)/$ /index.php?type=$1 [QSA,L]
RewriteRule ^([a-zA-Z0-9_-]+)/([a-zA-Z0-9_-]+)$ /index.php?type=$1&slug=$2 [QSA,L]
RewriteRule ^([a-zA-Z0-9_-]+)/([a-zA-Z0-9_-]+)/$ /index.php?type=$1&cat=$2 [QSA,L]
RewriteRule ^([a-zA-Z0-9_-]+)/([a-zA-Z0-9_-]+)/([a-zA-Z0-9_-]+)$ /index.php?type=$1&cat=$2&slug=$3 [QSA,L]
</IfModule>
Thanks, ended with
RewriteRule ^shop$ shop.php [L]
RewriteRule ^shop/([0-9]+)$ products.php?categoryid=$1 [L]
RewriteRule ^shop/([0-9]+)/(page-[0-9]+)$ products.php?categoryid=$1&page=$2 [L]
RewriteRule ^shop/([0-9]+)/([0-9]+)$ description.php?categoryid=$1&productid=$2 [L]

.htaccess mod_rewrite check if querystring var is avail

Basically I want to rewrite my urls so that it is website.com/folder/ sometimes though I need it to rewrite also website.com/folder/page/
Currently I have it working with just the website.com/folder/ but can not get it to check if there is a page, if I create just another rule under the folder one it reads that one, and gives me an empty page var, which is breaking my php. I struggle with .htaccess and any help would be appreciated.
Here is what I have that works with just the folder but I can not include a page.
Options +FollowSymLinks
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/?(css|js|images|html|docs)/
RewriteRule ^([^/]*)/$ /?folder=$1 [QSA]
Here is what I tried to get it to work with either just a folder, or a folder and page
Options +FollowSymLinks
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/?(css|js|images|html|doc)/
RewriteRule ^([^/]*)/$ /?folder=$1 [QSA]
RewriteCond %{REQUEST_URI} !^/?(css|js|images|html|doc)/
RewriteRule ^([^/]*)/([^/]*)/$ /?folder=$1&page=$2 [L,QSA]
Please Help!
Accordingly to the RewriteRule docs you should reverse the rules order in your rules set. Because in your configuration both rules have the same RewriteCond, the most specific rule (folder + page) should be atop and the most general rule should be the last one. If not when the first rule is matched the URL is rewritten and the second rule never matches. Also, probably you want to remove the trailing forward slash in the pattern of your folder + page rule (assuming that the second group in the pattern matches a page not a folder). So I think the whole thing should read:
RewriteCond %{REQUEST_URI} !^/?(css|js|images|html|doc)/
RewriteRule ^([^/]*)/([^/]*)$ /?folder=$1&page=$2 [L,QSA]
RewriteCond %{REQUEST_URI} !^/?(css|js|images|html|doc)/
RewriteRule ^([^/]*)/$ /?folder=$1 [L, QSA]

Zend Framework /index/ redirect throught htaccess to avoid content duplication

I'd like to know if it is possible to add a rule to the htaccess of my ZF app to redirect all the URLs that ends with the segment /index/ (such as http://domain.ext/index/) to the same URL without the /index/ suffix.
I've tried with this simple rule:
RedirectMatch ^(.*)/(index(/)?)$ http://localhost$1
but it doesn't work as expected (with other frameworks such as FuelPHP it works like a charm).
I know that this can be done via PHP using a plugin but I'd like to make the redirect via Apache to improve the performance of the application.
I don't know why nobody jumped in here, it is not that complicated?
A config file is executed from top to bottom and certain rules cause an immediate exit. If the rule defines an external redirect the server will perform that redirect immediately and all following rules are therefore ignored. If the redirect is back to the same server and config file then it is just a new game with the rules! If the redirect rule does not apply anymore it is on to the next rule. If the rule would still apply you get a loop.
Similar thing with a RewriteRule that matches and has [L]. L means "Stop the rewriting process here and don't apply any more rewrite rules". This quote is straight from the manual
Now you simply have to define some logic in what order you want to apply certain rules. Your request about the RedirectMatch for any /index/ path is certainly something you want to have very early to the top of the config. If there is a match your config will end here and perform a redirect! The browser will send a new request and we have a new game.
The RewriteRule to an index.php is something we will add very late at the bottom. It may be our last resort like a if all fails then rule. I does not matter if this is the Zend Framework or any other application you funnel through an index.php or other script for that matter.
The following rules should cover any variation with index, including .php, .htm and .html and finally trigger the index.php file for your ZF application.
RedirectMatch ^(/.*)/(index.(php|html|htm)|index)/?$ $1
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
When testing redirect rules be careful with your browser and use one where you can totally reset all cache and history settings. All current browsers are notorious in "remembering" redirects. If they learned a redirect rule they will perform that redirect internal, i.e. they don't go to the server to see what's new!
Here is your ruleset laid out readably
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RedirectMatch ^(.*)/(index(/)?)$ http://localhost$1
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
RedirectMatch is a mod_alias directive which severs the conds as from their rule. Also it's a lot less fraught not mixing mod_alias and mod_rewrite directives, so try:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^(.*?)/index/?$ $1 [R=301,L]
RewriteRule ^.*$ index.php [NC,L]
(updated following posters comments)
More footnotes
I tried this out on my VM which mirrors my hosting service, but having root access I can see the 'production' rewrite logs. This fails because the second rules still falls through to rule (3) which dispatchs to index.php. This then returms the full content but with a 301 status and without issuing a new location. If I change the [R=301] to [R=301,L] then it works fine as the server now issues a 301 with a Location header and the browser now retries with the new location.
The documentation states:
You will almost always want to use [R] in conjunction with [L] (that is, use [R,L]) because on its own, the [R] flag prepends http://thishost[:thisport] to the URI, but then passes this on to the next rule in the ruleset, which can often result in 'Invalid URI in request' warnings.
I resolved my problem with this (horrible) workaround:
- I renamed the "index" action of IndexController to "home"
- I setup a static route for home page (source)
- I changed the htaccess to:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^(.*)home(/)?$ $1 [R=301,L]
RewriteRule ^(.*)index/(.*)$ $1$2 [R=301,L]
RewriteRule ^.*$ index.php [QSA,NC,L]
So now the home page is not duplicated because http://localhost/home/ is redirected to the base domain and for other controllers the index action, if it is called specifying the action name (/controller/index/param/value) is redirected to the desired URL (/controller/param/value/)
RewriteRule ^(.*)/index(?|$)$ $1$2 [R=301,L]
this works with urls
/index => /
/index?page=2 => /?page2
/index/index => /
/index/index?page=2 /?page2
you need remove trailing slash before, for url like /index/, index/index/
RewriteRule ^(.*)/$ /$1 [L,R=301]
url like /index/help will work without changes

Categories