Mod Rewrite - Additional Query String After Already Rewriting One Query String - regex

Appreciate the help in advance because I absolutely hate mod_rewrite and can't get my head around it!
I currently have a rule in my .htaccess that converts two parameters in a query string to a pretty URL.
RewriteRule ^projects/([^/]+)/([^/]+)/?$ single-project.php?id=$1&section=$2 [L]
For example, this converts the URL /single-project.php?id=5&section=documents into /projects/5/documents/
What I want to do is have an additional query string (through a new rule) that would convert /projects/5/documents/?subfolder=PDFs into /projects/5/documents/PDFs/
A few caveats:
This additional query string may not always be there
This query string would only need to work if the URL is /projects/[ANY_ID]/documents/
I hope this makes sense and that you can help!
Cheers

With your shown samples, please try following rules in your .htaccess file. Please make sure to clear your browser cache before testing URLs. Have added comments inside rule file for understanding.
RewriteEngine ON
##Op's already present rules, added 1 more flag in it QSA.
RewriteRule ^projects/([^/]+)/([^/]+)/?$ single-project.php?id=$1&section=$2 [NC,QSA,L]
##Newly added Rule to perform internal rewrite for project id here.
RewriteRule ^(projects)/([^/]+)/([^/]+)/(.*)/?$ $1/$2/$3/?subfolder=$4 [NC,QSA,L]

Related

How to redirect from specific subdirectory to a subdomain via .htaccess?

I've been trying to redirect this URL (and all its substructures):
http://example.com/archive/
to (and its corresponding substructures):
http://archive.example.com/
For example: http://example.com/archive/signature/logo.png ==> http://archive.example.com/signature/logo.png
I tried to generate an .htaccess rule using a generator and evaluating it by looking at the regex, which I can understand (I think).
The result was the following rule:
RewriteEngine On
RewriteRule http://example.com/archive/(.*) http://archive.example.com/$1 [R=301,L]
The way I see it, the server will proccess any URL that starts with http://example.com/archive/ , will capture the string that comes next and will change the whole initial portion with the subdomain structure and append the captured string.
Unfortunately, this doesn't seem to work neither on my server, nor on online testing tools such as: http://htaccess.madewithlove.be/
Is there anything I'm missing there?
Thank you!
You should be able to try it this way.
RewriteEngine On
RewriteRule ^archive/(.*)$ http://archive.example.com/$1 [R=301,L]
Note that I did not make it dynamic as you didn't specific if you will have more URL's that need to work this way as well or not.

Apache rewrite condition get second regex match

I''m sorry for asking the millionth Apache rewrite question here. I tried everything I know, but there is a small (hopefully) step that I'm looking for someone to shed a light for me.
I have a URL structure similar to this:
- assets
- assets/dist/19854/css/my.css
- css/my.css
I'm trying to rewrite assets/dist/19854/css/my.css file to css/my.css file in the root.
I have mod_rewrite enabled on my server, and I have basic understanding of rewrite rules, but it would be great if you could assist me with the Regex.
RewriteCond %{REQUEST_URI} ^assets/dist/([0-9/.]+)/(.*)$
RewriteRule ^assets/dist/([0-9]+)/(.*)$ $ [L,QSA]
Problem with the above rule is the it rewrite to ./19854, but I'm actually interested in the second expression's match. If possible, I'd also like to make sure the css/my.css file exists first.
Thanks in advance!
Edit:
Thanks for the comments and the answer. To further explain my case, this is a small site that uses a CDN, and everytime a new build is up, the number in assets/dist/[0-9] gets changed, so all assets' source URL gets changed. But I'm using a CSS compiler to compile CSS files, so CSS files reside in the same folder (css/my.css).
I have some other rewrites so I'm making my RewriteConds more strict.
So far, the above rewrite matches the numeric part, but I'm trying to rewrite to the URL right after the numeric part.
I believe you're attempting in other way round. You can use this code in your DOCUMENT_ROOT/.htaccess file:
RewriteEngine On
RewriteBase /
# route to /css/my.css if it exists
RewriteCond %{DOCUMENT_ROOT}/$1 -f [NC]
RewriteRule ^assets/dist/.+?/(css/my\.css)$ $1 [L,NC]

Problem with htaccess GET form variables in a rewritten url

Essentially my problem is thus; I have a MVC system that redirects all requests to index.php on my site. I have a rewrite rule in my htaccess file to handle those requests like so:
RewriteRule ^([a-zAZ\_\-]+)\/([a-zA-Z\_\-]+)\/([^\/?]*) /?module=$1&class=$2&event=$3
Which translates urls into these type of urls
http://example.com/users/login/
http://example.com/users/info/me
My problem is that I also want GET variables to be applied and used in the URL like so
http://example.com/users/login/?var1=val1&var2=val2
http://example.com/users/info/me?var1=val2...
I've written two different regexes that work perfectly well in a my workbench (expresso) and I've tested them out in PHP however they refuse to work in htaccess. They're not particular complex, I have tried:
^([a-zAZ_\-]+)\/([a-zA-Z_\-]+)\/([^\/\?]*)[\?]*(.*) /?module=$1&class=$2&event=$3&$4
and
^([a-zAZ_\-]+)\/([a-zA-Z_\-]+)\/([^\/\?]*)(?(?=\?)\?(.+)) /?module=$1&class=$2&event=$3&$4
Neither of these work and I'm racking my brains as to why. Essentially it just doesn't recognise the fourth group and returns nothing I thought it might have been due to it being next to an ampersand but I did &var=$4 as a test and it still fell over.
Any help with this would be greatly appreciated as this is driving me insane.
Thanks in advance,
Rupert S.
After all, this is what you need:
RewriteRule ^([a-z_-]+)/([a-z_-]+)/([^/?]*) /?module=$1&class=$2&event=$3 [QSA,NC,L]
[QSA] will append the additional GET parameters to the rewritten query string.
[NC] since it is case insensitive, no need for A-Z matches

What's wrong with this regular expression in a .htaccess file?

I'm trying to understand why this regular expression isn't working in my .htaccess file. I want it so whenever a user goes to the job_wanted.php?jid=ID, they will be taken to job/ID.
What's wrong with this?
RewriteEngine On
RewriteCond %{QUERY_STRING} jid=([0-9]+)
RewriteRule ^job_wanted\.php?$ job/%1? [R]
I want it so when a user clicks on http://localhost/jobwehave.co.za/jobs/ID they are shown the same results as what below would show http://localhost/jobwehave.co.za/jobs?id=ID.
Sorry for the mix up. I still very confused to how this works.
The primary problem is that you can't match the query string as part of RewriteRule. You need to move that part into a RewriteCond statement.
RewriteEngine On
RewriteCond %{QUERY_STRING} jid=([0-9]+)
RewriteRule ^job_wanted\.php$ /job/%1?
Editing to reflect your updated question, which is the opposite of what I've shown here. For the reverse, to convert /job/123 into something your PHP script can consume, you'll want:
RewriteEngine On
RewriteRule ^/job/([0-9]+)$ /path/to/job_wanted.php?jid=$1
But you're probably going to have trouble putting this in an .htaccess file anywhere except the root, and maybe even there. If it works at the root, you'll likely need to strip the leading / from the RewriteRule I show here.
Second edit to reflect your comment: I think what you want is complicated, but this might work:
RewriteEngine On
RewriteRule ^/job/([0-9]+)$ /path/to/job_wanted.php?jid=$1 [L]
RewriteCond %{QUERY_STRING} jid=([0-9]+)
RewriteRule ^job_wanted\.php$ http://host.name/job/%1? [R]
Your fundamental problem is that you want to "fix" existing links, presumably out of your control. In order to change the URL in the browser address bar, you must redirect the browser. There is no other way to do it.
That's what the second cond+rule does: it matches incoming old URLs and redirects to your pretty URL format. This either needs to go in a VirtualHost configuration block or in the .htaccess file in the same directory as your PHP script.
The first rule does the opposite: it converts the pretty URL back into something that Apache can use, but it does so using an internal sub-request that hopefully will not trigger another round of rewriting. If it does, you have an infinite loop. If it works, this will invoke your PHP script with a query string parameter for the job ID and your page will work as it has all along. Note that because this rule assumes a different, probably non-existent file system path, it must go in a VirtualHost block or in the .htaccess file at your site root, i.e. a different location.
Spreading the configuration around different places sounds like a recipe for future problems to me and I don't recommend it. I think you'll be better off to change the links under your control to the pretty versions and not worry about other links.
The ^ anchors the regex at the beginning of the string.
RewriteRule matches the URI beginning with a / (unless it's in some per-directory configuration area).
Either prefix the / or remove the anchor ^ (depending on what you want to achieve)
You haven't captured the job ID in the regex, so you can't reference it in the rewritten URL. Something like this (not tested, caveat emptor, may cause gastric distress, etc.):
RewriteRule ^job/([0-9]+) job_wanted.php?jid=$1
See Start Rewriting for a tutorial on this.
You need to escape the ? and . marks if you want those to be literals.
^job_wanted\.php\?jid=9\?$
But although that explains why your pattern isn't matching, it doesn't address the issue of your URL rewriting. I'm also not sure why you want the ^ and $ are there, since that will prevent it from matching most URLs (e.g. http://www.yoursite.com/job_wanted.php?jid=9 won't work because it doesn't start with job_wanted.php).
I don't know htaccess well, so I can only address the regex portion of your question. In traditional regex syntax, you'd be looking for something like this:
s/job_wanted\.php\?jid=(\d*)/job\/$1/i
Hope that helps.
Did you try to escape special characters (like ?)?
The ? and . characters have a special meaning in regular expressions. You probably just need to escape them.
Also, you need to capture the jid value and use it in the rule.
Try to change your rules to this:
RewriteEngine On
RewriteRule ^job_wanted\.php\?jid=([0-9]+)$ /job/$1
Something like
ReWriteRule ^job\_wanted\.php\?jid\=([0-9-]+)$ /job/$1
should do the trick.

mod_rewrite: Pass the path & query string URL as a parameter

I'm using mod_rewrite to rewrite pretty URLs to a form supported by a Spring 2.5 application.
e.g. /category/cat1?q=x => /controller?category=cat1&q=x
However from my controller I want to know the original URL the request came from (so I can generate a link if required). This approach is needed generically across all pages so it is difficult to hard code.
How can I access the original path + query string from my controller?
I have tried using $0 to include the full path but this doesn't include the query string. I can't just append the path and the query string as this would result in some parts of the path being added as parameters /category/cat1?category=cat1&q=x Note the addition of the unwanted &category=cat1 parameter, this causes the URL to no longer match that sent from the browser.
I'm hoping mod_rewrite will let me reference the full URL and encode it as a parameter so my rule could look like:
RewriteRule /category/(.+)
/controller?category=$1&_originalUrl=${escape:$0}?${escape:<original query string>}
[QSA]
Using my original example the end result passed through to my controller would be:
/controller?category=cat1&_originalUrl=%2Fcategory%2Fcat1%3Fsearch%3Dx&search=x
The important part is the value of &_originalUrl which should be %2Fcategory%2Fcat1%3Fsearch%3Dx which in its unescaped version is /category/cat1?q=x (the original request URL that was sent from the browser).
Any suggestions welcome, thanks in advance!
The query can ony be tested with RewriteCond since RewriteRule does only test the URL path. See Jonathan Feinberg’s example how to do that.
But you could also just set the QSA flag and the old query gets automatically appended to the new one:
RewriteRule ^/category/([^/]+)$ /controller?category=$1 [QSA]
Edit    In response to your comment to this question: If you want to get the initial requested URI path and query, you need to extract it from the request line (THE_REQUEST variable):
RewriteCond %{THE_REQUEST} ^[A-Z]+\ ([^\s]+)
RewriteRule ^/category/([^/]+)$ /controller?category=$1&_originalUrl=%1 [QSA]
But in most languages there is an environment variable with the very same information.
You have to capture the query string in an initial, separate step.
RewriteCond %{query_string} ^q=([^&]+)
RewriteRule ^/category/(cat1)$ /controller?category=$1&q=%1
etc.
Is there a host header you can use? Sorry for being so vague, but last time I had to do this was using PHP (urgh, dont ask), and I think thats how we did it - eg REQUEST_URI (http://www.askapache.com/htaccess/mod_rewrite-variables-cheatsheet.html)
You also may be able to SET a host header in the rewrite (http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html)
eg:
ReWriteRule /category/(cat1)?q=(x) /controller?category=$1&q=$2 [E=FOO:....]
(and no, I'm so totally NOT a mod-rewrite ninja)