I have two rewrite rules for my application:
The first rule is a rule for /chef/index.php:
/chef/name -> /chef/?id=1234
The second rule is a rule for /recipes/index.php:
/r/name/nice-name-for-recipe ->
/recipes/?id=1234&nice_name=nice-name-for-recipe-name
The two rules work separately, but if I enabled both of them:
the first chef rule does not work,
the second recipes rule seems to work.
I tried to swap the order of the rules but I still cannot make both of them work.
Rules:
RewriteEngine On
RewriteRule ^([a-zA-Z0-9_-]+)/chef/$ $1 [QSA]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /chef/index.php?id=$1 [QSA]
RewriteRule ^([a-zA-Z0-9_-]+)/r/$ $1/$2 [QSA]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /recipes/index.php?id=$1&nice_name=$2 [QSA]
In the first rule, you tried to match ^([a-zA-Z0-9_-]+)/chef/$.
/chef/$ means it matches a url that ends with /chef/,
because $ means the end of string, e.g.:
http://anything.dev/chef/
So it does not match /chef/name/, it matches /chef/.
Similarly, your second rule does not match /r/name/nice-name-for-recipe,
it matches /r/$.
These rules just tell apache to fallback to static files.
It is useful if you need to serve static files,
but they are unrelated to this question.
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
So your rules are roughly just:
RewriteRule ^(.*)$ /chef/index.php?id=$1 [QSA]
RewriteRule ^(.*)$ /recipes/index.php?id=$1&nice_name=$2 [QSA]
Now it is clear that why these rules work separately but only the second one works if you put them together.
They both matches ^(.*)$, that is every url (except those urls for static files).
Thus when putting them together, only the second one wins.
So the real rule effect is:
/chef/name ->
/chef/index.php?id=/chef/name&nice_name=
/r/name/nice-name-for-recipe ->
/chef/index.php?id=/r/name/nice-name-for-recipe&nice_name=
P.S. I think the deep causes of this question are:
You try to write regular expressions without understanding them.
The regular expression syntax is hard to understand. Specifically, $ is both used as pattern and variable prefix.
The index.php code is dirty. It should not accept urls blindly. If index.php errors out, the two rules will not seem to work. Dirty code is hard for detecting and locating problems, and insecure (attackers can construct dangerous special urls).
Your IDE is not smart enough to warn you against RewriteRule ^(.*)$ /recipes/index.php?id=$1&nice_name=$2 [QSA] since $2 is unset.
You're writing that you want to transform dev.website.com/chef/name into dev.website.com/chef/?id=1234. This cannot work as the id in the target URL doesn't exist in the source URL, so you need to think about how you want to include the ID in the original URL as well.
Once you sorted that out, I'd recommend you to read up more on regular expressions to fix the mod_rewrite rules.
Here's a great resource for testing and explaining regular expressions: https://regex101.com/
Related
Before anyone comments, I know there are a lot of posts created on this topic, but none of them seem to solve my problem, that is why I have started this thread.
So, I have a page in my website called project.php which is used in GET query like so: project.php?id=12 I want to have a .htaccess file that converts the given URL into localhost/MyWeb/project/id/12/. I've literally followed every single post regarding that topic but none of them seem to work.
Also, along with that, I want all my .php and .html files to be shown just with their names, i.e localhost/MyWeb/index.php/ becomes localhost/MyWeb/index/ and localhost/MyWeb/sub1/sub2.php becomes localhost/MyWeb/sub1/sub2/.
EDIT:
The reason why I did not add my work in first place was because I didn't think it would be any helpful. But here it is:
RewriteEngine On
RewriteRule ^([0-9]+)$ project.php?id=$1
RewriteRule ^([0-9]+)/$ project.php?page=$1
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
RewriteRule ^([^\.]+)$ $1.html [NC,L]
Firstly, you are operating out of a sub-directory (MyWeb), which means you need to set a RewriteBase. Also, you need to ensure that your .htaccess file is placed inside that sub-directory, and not in the localhost document root.
So, below RewriteEngine on, insert the folloeing line:
RewriteBase /MyWeb/
Next, you stated that you want to convert project.php?id={id} to project/id/{id}, but your code omits the /id/ segment. I also noticed that you have two rules, and that the second one contradicts your question, so I am only going to show you the change you need to make for the first rule, until such time as you clarify what the second rule is for.
To make the project URI work, change the very first rule to:
RewriteRule ^project/id/([0-9]+)/?$ project.php?id=$1 [QSA,L]
This will match the URI you want, with an optional trailing slash. I've also added the QSA flag which appends any extra query string parameters to the rewitten URI, as well as the L flag which stops processing if the rule is matched.
Next, to omit the .php or .html from your URIs, change the last three lines to the following:
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^([^\.]+)$ $1.php [L]
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^([^\.]+)$ $1.html [L]
When you make a request to localhost/MyWeb/index, Apache will check to see if localhost/MyWeb/index.php or localhost/MyWeb/index.html exist, and will then serve whichever one it finds first.
If you have both the PHP and HTML files, then the PHP one will be served, and not the HTML one. If you prefer to serve HTML files, then swap the two blocks around.
Unfortunately, I don't know of a good way to force a trailing slash for these, specifically because of the condition that checks for their existence. In other words, it won't work if you request sub2/, with the trailins slash because it would need to check if sub2/.php exists, which it does not.
Update: For added benefit, place these two blocks just below the new RewriteBase you set earlier to redirect the old URIs to the new ones whilst allowing the rewrites to the new URIs to still work:
RewriteCond %{THE_REQUEST} \/project\.php\?id=([0-9]+) [NC]
RewriteRule ^ project/id/%1/ [R=302,L,QSD]
RewriteCond %{THE_REQUEST} \/MyWeb/(.+)\.(php|html)
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ %1 [R=302,L]
For reference, here's the complete file: http://hastebin.com/gacapesoqe.rb
i store uploaded files at /storage/ this way
public-adam-luki-uploads-123783.jpg
park-hanna-adel-propic-uploads-787689.jpg
the '-' count unknown because it slice the pic description
i want my users to be able to access it as
http://site.com/public/adam/luki/uploads/123783.jpg
http://site.com/park/hanna/adel/propic/uploads/787689.jpg
i think it is the same problem here
mod_rewrite with an unknown number of variables
but i can't do it because i'm new to mod_rewrite module
i hope you can help me guys with the right rewriterule
The question you link to doesn't actually do what you are trying to do (although the principle is the same) what they do is convert the url to GET variables.
If all you want to do is convert / to - then you can use a simple rewrite rule that will run in a loop:
ReWriteRule ^(.*)/(.*)$ $1-$2 [L]
There are of course a few caveats to that...
Firstly, even if you are trying to get to a real directory/file the rule will still switch out / and - and leave you with a 404. You can get around that by adding conditions; to stop it rewriting real files:
RewriteCond %{REQUEST_FILENAME} !-f
You would do better however to limit the matches to only images (jpgs):
RewriteCond %{REQUEST_FILENAME} !-f
ReWriteRule ^(.*)/(.*)\.jpg$ $1-$2.jpg [L]
Preferred Solution
ReWriteCond %{REQUEST_FILENAME} !-f
ReWriteRule ^images/(.*)/(.*)uploads[-/](\d+)\.jpg$ images/$1-$2uploads-$3.jpg [L]
RewriteCond %{REQUEST_FILENAME} !-f
ReWriteRule ^images/(.*)$ storage/$1 [L]
This solution requires you to use urls like:
http://site.com/images/park/hanna/adel/propic/uploads/787689.jpg
The pseudo directory images means you can be sure that the url is actually one that you want to redirect and it doesn't break other images/links on your site.
The above rules take a url (like the example above) and transforms it like so:
images/park/hanna/adel/propic/uploads/787689.jpg <--- Original
images/park-hanna/adel/propic/uploads-787689.jpg
images/park-hanna-adel/propic/uploads-787689.jpg
images/park-hanna-adel-propic/uploads-787689.jpg
images/park-hanna-adel-propic-uploads-787689.jpg
storage/park-hanna-adel-propic-uploads-787689.jpg <--- Final
UPDATE: This works:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{THE_REQUEST} ^[A-Z]+\ ([^\s]+)
RewriteRule (.+) /index.cfm?event=checkuri&uri=%1 [QSA]
Some background...
So we already have a catchall redirect in our .htaccess file which is this:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (.+) /index.cfm?event=checkuri&uri=$1
This ties into a database table that checks the URI for a match. so if we just moved a site that used to have this page:
/some-awesome-article.html
Onto our system, and the new address is
/awesome-article/12442
and someone tried to access the old URI, our system would check for this, find a match, and forward them to the new home: /awesome-article/12442
This system works awesome, with one exception. If the URI is something like /index.php?id=123412 then the whole system falls apart. In fact /index.php/whatever won't work either.
Everything else works except for this. We do not use PHP for our web application (although support says its in an admin console on the server somewhere).
So basically what I need is if index.php is detected anywhere it will forward the URI to our
existing system:
How can i modify this to fix it?
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (.+) /index.cfm?event=checkuri&uri=$1
Try changing your code to:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (.+) /index.cfm?event=checkuri&uri=$1 [L,QSA]
QSA is for Query String Append that will make sure to append existing query parameters with the new ones.
Rewriting with mod_rewrite does not work on the full URL. In fact, the regex in the RewriteRule does only get the path and file, but not the query string. And so the backreference $1 will only contain "index.php" and nothing else.
Additionally, the RewriteRule does change the query string because there is one in the target pattern. Because the flag [QSA] (query string append) is not present, the query string of the original request gets replaced instead of appended. So the query string is gone after this rewriting.
This would be a lot easier if you wouldn't mess with the query string. The easiest way of rewriting any url that is not an existing file would be if the second line would be simply RewriteRule (.+) /index.cfm - you could then get all info about the current request, including query string, path and file, in the script.
So now you'd have to fiddle with the query string. Adding [QSA] will pass the query string to your script and you'd have to detect what's inside. This will work only if you do not expect the query string to contain parameters named "event" and "uri" - these will be overwritten by your rewriting. If you need to add the original query string to the URL, it's a bit more complicated, because the string needs to be url-encoded.
Here's how to do that.
Based on your comments, it sounds like you need to use the Query String Append QSA flag on your rule like this:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /index.cfm?event=checkuri&uri=$1 [QSA,L]
In your example case the rewrite would look like:
/index.cfm?event=checkuri&uri=index.php&id=123412
Sven was very close so I'm giving him the check
This ended up working perfectly:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{THE_REQUEST} ^[A-Z]+\ ([^\s]+)
RewriteRule (.+) /index.cfm?event=checkuri&uri=%1 [QSA]
I need to be able to shorten my page from:
mydomain.com/mixtape.php?mixid=(WHATEVER NUMBER)
To:
mydomain.com/m/(WHATEVER NUMBER)
Now usually this wouldn't be much of an issue for me to figure out, but becasue of a few pre-existing functions in my .htaccess file, it is really hard for this function not to improperly interact with the others.
Below is the current code of my .htaccess file (AND NONE OF IT CAN CHANGE)
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/\.]+)/?$ profile.php?user=$1 [L]
Above, the .htaccess file is shorting my
mydomain.com/profile.php?username=(USERNAME)
to
mydomain.com/(USERNAME)
Is there anyone out there than can help me by being able to shorten the m/index.php?mixid and not have it conflict with the pre-existing function?
Prepend this rule to your .htaccess block rewriting the profile url (after turning the rewrite engine on) :
RewriteCond $1 ^m/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ mix.php?id=$1 [L]
That rule will now only be used for URLS like :
mydomain.com/m/(WHATEVER NUMBER)
The first line is a condition that the incoming URL must start with m/
The second and third lines are conditions that the incoming URL does not represent an actual file or folder (we wouldn't want our humble rewrite rule to block us from a real resource).
The fourth line is the actual rule itself witch uses a regular expression syntax to match and capture everything that appears after host name and passes it to the mixtape.php file as a GET parameter called id. This line also contains the [L] flag which states that no more rules or rewriting will occur on the current incoming URL.
In your mix.php file you can use the explode method to split the resulting string into an array :
http://example.com/m/foo/bar =>
`http://example.com/mixtape.php?id=/m/foo/bar
$splitArr = explode('/',$_GET['id']);
$splitArr =>
array (
0 => 'm',
1 => 'foo',
1 => 'bar',
)
and remove the initial m with
array_shift();
Then you are left with $splitArr containing all the parts of your URL, split with a / (slash) delimiter.
The URL example.com/m/foo/bar would look like :
array (
0 => 'foo',
1 => 'bar',
)
It is important to place this rule before the existing one as the existing rule will act on any incoming URL. The final two rules that you have should appear like this :
RewriteEngine on
RewriteCond $1 ^m/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ mix.php?id=$1 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/\.]+)/?$ profile.php?user=$1 [L]
Regarding your statement :
AND NONE OF IT CAN CHANGE
I would seriously recommend that you consider implementing a small change on that first rule. Making the final url something like mydomain.com/users/(USERNAME) (as they do here). In these cases it is much better to be more specific than overly general (as the current rule is). Have you considered the confusion that could be created if someone was to chose a user name such as :
about
faq
home
While perfectly valid usernames these users profiles would be :
mydomain.com/about
mydomain.com/faq
mydomain.com/home
Those usernames will block important URLs that you might want to save for other locations on your site. I think it is clear why those user names would be undesirable.
RewriteRule ^m/([0-9]+)$ /mixtape.php?mixid=$1
Put in before or after the existing rule. Should not cause any conflict.
In my page I have a login folder. When I enter into domain.com/login/ it takes me correctly to the folder. When I write domain.com/login it also opens the page but the url changes into domain.com/login/?cname=login
My other main link is like domain.com/company and works correctly. However if i write domain.com/company/ it sais object not found.
How can I fix these?
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/$
RewriteCond %{REQUEST_URI} !^/domain.com/index.(php|html?)
# domain.com/login
RewriteRule ^/login?$ /domain.com/login/index.php
# domain.com/abc
RewriteRule ^([a-z0-9]+)?$ /domain.com/profile/company-profile.php?cname=$1 [NC,L]
It sound like you want to have domain.com/login/ or domain.com/login take you to the login folder.
The rule below will ensure that all of your folders end with a trailing slash and thus make domain.com/login work.
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ http://domain.com/$1/ [L,R=301]
The next rule below will allow domain.com/company/ to work. In combination with the rule above, it will also ensure that domain.com/company continues to work.
RewriteRule ^company/$ profile/company-profile.php?cname=company [NC,L]
You should delete your other rules as they are incorrect.
Edit
Based on your last response modify the last rule to be
RewriteCond %{REQUEST_URI} !=/login/ [NC]
RewriteRule ^([a-z0-9]+)/$ profile/company-profile.php?cname=$1 [NC,L]
i.e. for all URI's except login do the rewrite company rule.
Make sure that you understand that any # of RewriteCond's only apply to the very next RewriteRule. I don't understand why you're matching against REQUEST_URI with a RewriteCond, rather than just matching it as part of the RewriteRule.
I also don't understand exactly what you're trying to accomplish with the ^/login?$ RewriteRule. I'm guessing the '?' needs to be escaped - otherwise, you're literally asking it to match against "/login" or "/logi".
Due to complications from the above concerns, I'm guessing your "domain.com/login" request is being handled by the 2nd RewriteRule which contains the "cname=", though I'm confused why you then don't see the "company-profile.php" as well (assuming maybe just an oversight in your question)?
After considering the above and trying to simplify this a little, I'm guessing everything should fall into place. If not, please comment back, and we'll see what we can do.