I currently have this line in my .htaccess file making URLs "pretty" for pages.
RewriteRule ^([A-Za-z0-9-]+)/$ /directory/?type=page&title=$1 [L]
However, I sometimes have sub-pages (/page/sub-page/sub-page/), yet this line only supports one level (/page/).
How can I alter this code to support sub-pages (any amount) and make the title variable something like:
&title=page/sub-page/sub-page
/ being the seperator.
I know that this will definitely be a huge help:
RewriteRule loop in .htaccess not working
However, due to my lack of knowledge with regex and mod-rewrite, I don't know how to make it properly work with what I already have.
Try this:
AllowEncodedSlashes On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^([/a-z0-9-]+)/?$ /directory/?type=page&title=$1 [NC,B,L]
Don't worry about A-Z because of the NC flag.
After doing some regex research, and doing some testing, it seems like this is the answer to my problem:
RewriteRule ^(([a-zA-Z0-9-]+)/(([a-zA-Z0-9-]+)\/?)+)$ /directory/?type=page&title=$1 [L]
I altered my previous code and allowed support for multiple sub-directories. Then I placed it into a capture group and placed that data into the title variable.
Related
I have a simple website comprised of one page with a div that gets populated with ajax content based on the links the user selects. This site is running on an Apache server with an .htaccess file in the domain's root directory. Requests to www.mydomain.com are directed to scripts/index.php while requests for dynamic content (but not resource files) are directed to the same .php script with the requested content passed as a parameter (e.g., www.mydomain.com/myProject will be rewritten as scripts/index.php?dynContent=myProject).
My rewrite rules are below and for the most part they are performing those described tasks properly; however, I've encountered some URLs that do not match the second condition even though I would expect them to -- though this is the first time I've had to write rules for an .htaccess file so I don't really know what I'm talking about... A good example of a URL that fails the second condition is www.mydomain.com/about, but I've encountered many more just by testing random words/letters.
Can you tell me why www.mydomain.com/about fails the second condition? Also, if there is a more elegant way to achieve the objectives I described above, I would love to learn about it. Thank you!!
RewriteCond %{HTTP_HOST} ^(www.)?mydomain.com$ [NC]
RewriteRule ^(/)?$ scripts/index.php [L]
RewriteCond %{REQUEST_URI} .*[^index.php|.css|.js|.jpg|.html|.swf]$
RewriteRule .* scripts/index.php?dynContent=$1 [L]
This is because regex in your 2nd rules is incorrect.
Change your code to:
RewriteCond %{HTTP_HOST} ^(www\.)?mydomain\.com$ [NC]
RewriteRule ^(/)?$ scripts/index.php [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !\.(php|css|js|jpe?g|html|swf)$
RewriteRule ^(.*)$ scripts/index.php?dynContent=$1 [L]
I have an application that routes all requests through index.php.
Here's my setup:
I access the application at http://www.example.com/sample/
On the filesystem, the application sits in /home/chris/www/sample/
The web-accessible directory of the application lives at /home/chris/www/sample/app/web.
The DocumentRoot is set to /home/chris/www
/home/chris/www/sample/.htaccess is configured as follows:
RewriteEngine on
RewriteCond %{REQUEST_URI} ^/sample/(.+)$
RewriteCond %{DOCUMENT_ROOT}/sample/app/web/%1 -f
RewriteRule ^/sample/(.*)$ %{DOCUMENT_ROOT}/sample/app/web/%1 [L]
RewriteRule ^(.+)$ index.php?ws_page=$1 [L,NC,QSA]
I've tried multiple configurations, but haven't figured out why I keep getting 404's on calls to "real" files.
Sample 404:
`http://www.example.com/sample/_css/960/reset.css`
(which I want to have rewritten to /home/chris/www/sample/app/web/_css/960/reset.css)
EDIT
I have already tried
RewriteCond %{REQUEST_URI} !-f
RewriteCond %{REQUEST_URI} !-d
RewriteCond %{REQUEST_URI} !-l
and they did not work, because the %{REQUEST_URI} prefix does not match the filesystem prefix of these files.
EDIT 2
To clarify, I want requests of the form
`http://www.example.com/sample/foo/bar`
to be rewritten to the filesystem object /home/chris/www/sample/app/web/foo/bar, but only if that filesystem object exists.
One of the biggest bear-pits in reading the mod_rewrite documentation in the difference in behaviour in a system (that this the main and vhost configs that apache reads on start-up and those directive processes in a per-directory context. See the Per-directory Rewrites subsection of the RewriteRule documentation for further details.
When using the rewrite engine in .htaccess files the per-directory prefix (which always is the same for a specific directory) is automatically removed for the RewriteRule pattern matching and automatically added after any relative (not starting with a slash or protocol name) substitution encounters the end of a rule set. See the RewriteBase directive for more information regarding what prefix will be added back to relative substitions.
and later
The removed prefix always ends with a slash, meaning the matching occurs against a string which never has a leading slash. Therefore, a Pattern with ^/ never matches in per-directory context. What you've done is to code around this.
Incidentally, this is why it is always safer to specify a RewriteBase, as the engine gets this wrong without this.
BTW, this second quote can be wrong because the prefix add-back occurs at the then of the rule set execution, and if you have a successful rule which is to a different relative branch (that is the target starts with a /) but without the [L] flag set, then the engine falls through to any subsequent rules with a leading / set. Most confusing, so my general advice is never rely on fall-through rules. Always force an immediate internal or external redirect on a successful substitution in a per-directory context as the engine has this and a couple of other bugs in this fall-through processing.
Have your code like this:
Options +FollowSymLinks -MultiViews
# Turn mod_rewrite on
RewriteEngine On
RewriteBase /sample
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s/+sample/(.+)\s [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond /home/chris/www/sample/app/web/%1 -f [NC]
RewriteRule ^ /sample/app/web/%1 [L]
# If the request is not for a valid file
RewriteCond %{REQUEST_FILENAME} !-f
# If the request is not for a valid symlink
RewriteCond %{REQUEST_FILENAME} !-l
# If the request is not for a valid directory
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ index.php?page=$1 [L,QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
These two rules will skip files (-f) and directories (-d) which actually exist.
Mad bonus points to whomever can explain to me why my the EOS anchor ($) was to blame for the RewriteRule not working.
I wound up with this:
RewriteEngine on
RewriteCond %{REQUEST_URI} ^/sample/(.+)
RewriteCond %{DOCUMENT_ROOT}/sample/app/web/%1 -f
RewriteRule ^(.*)$ app/web/$1 [L,NC,QSA]
RewriteCond %{REQUEST_URI} !(^/sample/app/web)
RewriteRule ^(.+)$ index.php?ws_page=$1 [L,NC,QSA]
Many thanks to all who helped me diagnose this weirdness.
I'm trying to prevent, in this case WordPress, from rewriting certain URLs. In this case I'm trying to prevent it from ever handling a request in the uploads directory, and instead leave those to the server's 404 page. So I'm assuming it's as simple as adding the rule:
RewriteCond %{REQUEST_URI} !^/wp-content/uploads/
This rule should evaluate to false and make the chain of rules fail for those requests, thus stopping the rewrite. But no... Perhaps I need to match the cover the full string in my expression?
RewriteCond %{REQUEST_URI} !^/wp-content/uploads/.*$
Nope, that's not it either. So after scratching my head I do a check of sanity. Perhaps something is wrong with the actual pattern. So I make a simple test case.
RewriteCond %{REQUEST_URI} ^/xyz/$
In this case, the rewrite happens if and only if the requested URL is /xyz/ and shows the server's 404 page for any other page. This is exactly what I expected. So I'll just stick in a ! to negate that pattern.
RewriteCond %{REQUEST_URI} !^/xyz/$
Now I'm expecting to see the exact opposite of the above condition. The rewrite should not happen for /xyz/ but for every other possible URL. Instead, the rewrite happens for every URL, both /xyz/ and others.
So, either the use of negated regexes in RewriteConds is broken in Apache, or there's something fundamental I don't understand about it. Which one is it?
The server is Apache2.
The file in its entirety:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/wp-content/uploads/
RewriteRule . /index.php [L]
</IfModule>
WordPress's default file plus my rule.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_URI} !^/wp-content/uploads/ [OR]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
So, after a lot of irritation, I figured out the problem, sort of. As it turned out, the rule in my original question actually did exactly what it was supposed to. So did a number of other ways of doing the same thing, such as
RewriteRule ^wp-content/uploads/.*$ - [L]
(Mark rule as last if pattern matches) or
RewriteRule ^wp-content/uploads/.*$ - [S=1]
(Skip the next rule if pattern matches) as well as the negated rule in the question, as mentioned. All of those rules worked just fine, and returned control to Apache without rewriting.
The problem happened after those rules were processed. Instead, the problem was that I deleted a the default 404.shtml, 403.shtml etc templates that my host provided. If you don't have any .htaccess rewrites, that works just fine; the server will dish up its own default 404 page and everything works. (At least that's what I thought, but in actual fact it was the double error "Additionally, a 404 Not Found error was encountered while trying to use an ErrorDocument to handle the request.")
When you do have a .htaccess, on the other hand, it is executed a second time for the 404 page. If the page is there, it will be used, but now, instead the request for 404.shtml was caught by the catch-all rule and rewritten to index.php. For this reason, all other suggestions I've gotten here, or elsewhere, have all failed because in the end the 404 page has been rewritten to index.php.
So, the solution was simply to restore the error templates. In retrospect it was pretty stupid to delete them, but I have this "start from scratch" mentality. Don't want anything seemingly unnecessary lying around. At least now I understand what was going on, which is what I wanted.
Finally a comment to Cecil: I never wanted to forbid access to anything, just stop the rewrite from taking place. Not that it matters much now, but I just wanted to clarify this.
If /wp-content/uploads/ is really the prefix of the requested URI path, your rule was supposed to work as expected.
But as it obviously doesn’t work, try not to match the path prefix of the full URI path but only the remaining path without the contextual per-directory path prefix, in case of the .htaccess file in the document root directory the URI path without the leading /:
RewriteCond $0 !^wp-content/uploads/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .+ /index.php [L]
If that doesn’t work neither, it would certainly help to get some insight into mod_rewrite’s rewriting process by using its logging feature. So set RewriteLogLevel to a level of at least 4, make your request and take a look at the entries in the log file specified with RewriteLog. There you can see how mod_rewrite handles your request and with RewriteLogLevel greater or equal to 4 you will also see the values of variables like %{REQUEST_URI}.
I have found many examples like this when taking a "WordPress First" approach. For example, adding:
ErrorDocument 404 /error-docs/404.html
to the .htaccess file takes care of the message ("Additionally, a 404 Not Found error...").
Came across this trying to do the same thing in a Drupal site, but might be the same for WP since it all goes through index.php. Negating index.php was the key. This sends everything to the new domain except old-domain.org/my_path_to_ignore:
RewriteCond %{REQUEST_URI} !^/my_path_to_ignore$
RewriteCond %{REQUEST_URI} !index.php
RewriteCond %{HTTP_HOST} ^old-domain\.org$ [NC]
RewriteRule ^(.*)$ http%{ENV:protossl}://new-domain.org/$1 [L,R=301]
Hi
I need some help (the solution and the explanation please)
In my application there is a php page called page.php which gets a parameter page by GET and delivers content accordingly.
What I want is:
Make this page the entry point, catch all and redirect it to page.php.
Use the URI as the page parameter value. (domain.com/string will become domain.com/page.php?page=string)
When I used ^(.*)$ page.php?page=$! it was working, except it also manipulated every resource that was called (js, css, images, etc..)
Thanks
You need to add RewriteCond statements to avoid any existing files.
RewriteEngine on
RewriteBase /
# Allow files that exists to bypass rewrites
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ page.php?page=$1 [L,QSA]
I have a directory named dollars that contains a file index.php. I would like for the url http://localhost/dollars/foo to translate to dollars/index.php?dollars=foo. This is the .htaccess file that I currently have in the dollars directorty:
Options +FollowSymLinks
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !^index\.php
RewriteRule ^(.+)$ index.php?dollars=$1 [L]
The idea being that any request other than a request to index.php should use the RewriteRule.
However, this does not work.
I've been looking for a while trying to figure out how to create the redirect I want, but I don't even know if I'm on the right track. Regex were never my thing. Thanks for any help!
A often-used solution for rewrites is to just check that the path being requested doesn't point to an actual file/directory, and rewrite it if it doesn't - since the rewritten URL will then point to an actual file, no loop occurs.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
Amber's answer should get things working for you, but I wanted to address what was going wrong in your specific case. You had the right idea, but %{REQUEST_FILENAME} actually ends up being a fully qualified path here, so your regular expression should check for index.php at the end, not the beginning.
Consequently, you should find that this will work more like you expect:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !index\.php$
RewriteRule ^(.+)$ index.php?dollars=$1
Swapping out the RewriteConds for those that Amber mentioned would be less problematic if you added other things to that directory, though, so I'd recommend using that in place of this anyway.