Rewriting public assets to omit file extension - .htaccess

For the sake of formality, I want to trim my asset URIs so that file extensions are omitted.
For example, if I request /resources/stylesheets/common, Apache will return /resources/stylesheets/common.css. At the moment, I'm using the following rewrite to get this to work:
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI}.css -f
RewriteRule ^ /%{REQUEST_URI}.css [L]
This works, as it should. However, I need to also do this for other resources, like images and scripts. For simplicity, I would like to avoid repeating this approach for every type of resource.
Question: What method can I use to achieve this in one rule? I'm thinking something along these lines (though this will not work, and I can see why - perhaps Apache doesn't like guess-work):
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI}.(css|js|png) -f
RewriteRule ^ /%{REQUEST_URI}.%1 [L]

Related

Use htaccess to change query parameter to iOS app-specific deep-link [duplicate]

I am trying to do the following:
User visits URL with query parameter: http://www.example.com/?invite=1234
I then want them to be deep linked into the app on their iOS device, so they go to: app_name://1234
Any suggestions on how to accomplish this in my .htaccess file?
I tried this but it doesn't work:
RewriteEngine On # Turn on the rewriting engine
RewriteRule ^invite/(.*)/$ app_name://$1 [NC,L]
If RewriteRule won't work, can anyone send me an example code for RewriteCond or JavaScript to achieve what I need?
Not sure how this will work with the iOS device, but anyway...
RewriteRule ^invite/(.*)/$ app_name://$1 [NC,L]
This doesn't match the given URL. This would match a requested URL of the form example.com/invite/1234/. However, you are also matching anything - your example URL contains digits only.
The RewriteRule pattern matches against the URL-path only, you need to use a RewriteCond directive in order to match the query string. So, to match example.com/?invite=1234 (which has an empty URL-path), you would need to do something like the following instead:
RewriteCond %{QUERY_STRING} ^invite=([^&]+)
RewriteRule ^$ app_name://%1 [R,L]
The %1 backreference refers back to the last matched CondPattern.
I've also restricted the invite parameter value to at least 1 character - or do you really want to allow empty parameter values through? If the value can be only digits then you should limit the pattern to only digits. eg. ^invite=(\d+).
I've include the R flag - since this would have to be an external redirect - if it's going to work at all.
However, this may not work at all unless Apache is aware of the app_name protocol. If its not then it will simply be seen as a relative URL and result in a malformed redirect.

Htaccess caching system in subfolder not working

Sorry if this is a duplicate: I found many questions about caching system, but my problem seems to tied to the fact that the whole script is working within a subfolder.
All I need to do is implementing a simple caching system for my website, but I can't get this to work.
Here's my .htaccess file (widely commented to be clear - sorry if too many comments are confusing):
RewriteEngine on
# Map for lower-case conversion of some case-insensitive arguments:
RewriteMap lc int:tolower
# The script lives into this subfolder:
RewriteBase /mydir/
# IMAGES
# Checks if cached version exists...
RewriteCond cache/$1-$2-$3-{lc:$4}.$5 -f
# ...if yes, redirects to cached version...
RewriteRule ^(hello|world)\/image\/([a-zA-Z0-9\.\-_]+)\/([a-zA-Z0-9\.\-_]+)\/([a-zA-Z0-9\.\-_\s]+)\.(png|gif|jpeg?|jpg)$ cache/$1-$2-$3-{lc:$4}.$5 [L]
# ...if no, tries to generate content dynamically.
RewriteRule ^(hello|world)\/image\/([a-zA-Z0-9\.\-_]+)\/([a-zA-Z0-9\.\-_]+)\/([a-zA-Z0-9\.\-_\s]+)\.(png|gif|jpeg?|jpg)$ index.php?look=$1&action=image&size=$2&data=$3&name=$4&format=$5 [L,QSA]
# OTHER
# This is always non-cached.
RewriteRule ^(hello|world)\/([a-zA-Z0-9\.\-_\s]+)\/([a-zA-Z0-9\.\-_\s]+)?\/?$ index.php?look=$1&action=$2&name=$3 [QSA]
Now, the issue is that the RewriteCond seems to be always failing, as the served image is always generated by PHP. I also tried prepending a %{DOCUMENT_ROOT}, but is still not working. If I move the whole script to the root directory, it magically starts working.
What am I doing wrong?
Well one thing that you are doing wrong is trying to use a rewrite map in an .htaccess file. in the first place. According to the Apache documentation:
The RewriteMap directive may not be used in <Directory> sections or .htaccess files. You must declare the map in server or virtualhost context. You may use the map, once created, in your RewriteRule and RewriteCond directives in those scopes. You just can't declare it in those scopes.
If your ISP / sysadmin has already defined the lc map then you can use it. If not then you can only do case-sensitive file caching on Linux, because its FS naming is case sensitive. However, since these are internally generated images, just drop the case conversion and stick to lower case.
%{DOCUMENT_ROOT} may not be set correctly at time of mod_rewrite execution on some shared hosting configurations. See my Tips for debugging .htaccess rewrite rules for more hints. Also here is the equivalent lines from my blog's .htaccess FYI. The DR variable does work here, but didn't for my previous ISP, to I had to hard-code the parth
# For HTML cacheable blog URIs (a GET to a specific list, with no query params,
# guest user and the HTML cache file exists) then use it instead of executing PHP
RewriteCond %{HTTP_COOKIE} !blog_user
RewriteCond %{REQUEST_METHOD}%{QUERY_STRING} =GET [NC]
RewriteCond %{DOCUMENT_ROOT}html_cache/$1.html -f
RewriteRule ^(article-\d+|index|sitemap.xml|search-\w+|rss-[0-9a-z]*)$ \
html_cache/$1.html [L,E=END:1]
Note that I bypass the cache if the user is logged on or for posts and if any query parameters are set.
Footnote
Your match patterns are complicated because you are not using the syntax of regexps: use the \w and you don't need to escape . in [ ] or / . Also the jpeg isn't right is it? So why not:
RewriteRule ^(hello|world)/image/([.\w\-]+)/([.\w\-]+)/([\w\-]+\.(png|gif|jpe?g))$ \
cache/$1-$2-$3-$4 [L]
etc.. Or even (given that the file rule will only match for valid files in the cache)
RewriteRule ^(hello|world)/image/(.+?)/(.+?)/(.*?\.(png|gif|jpe?g))$ \
cache/$1-$2-$3-$4 [L]
The non-greedy modifier means that (.+?) is the same as ([^/]+) so doing hacks like ../../../../etc/passwd won't walk the file hierarchy.

mod_rewrite .htaccess with %20 translate to -

I have been reading about .htaccess files for a couple of hours now and I think I'm starting to get the idea but I still need some help. I found various answers around SO but still unsure how to do this.
As far as I understand you write a rule for each page extension you want to 'prettify', so if you have something.php , anotherpage.php, thispage.php etc and they are expecting(will receive??) arguments, each needs its own rule. Is this correct?
The site I want to change has urls like this,
maindomain.com/sue.php?r=word1%20word2
and at least one page with two arguments
maindomain.com/kevin.php?r=place%20name&c=person%20name
So what I would like to make is
maindomain.com/sue/word1-word2/
maindomain.com/kevin/place-name/person-name/
Keeping this .php page and making it look like the directory. Most of the tutorials I have read deal with how to remove the .php page to which the argument is passed. But I want to keep it.
the problem I am forseeing is that all of the .php?r=parts of the url are the same ie sue.php?r=, kevin.php?r= and the .htaccess decides which URL to change based on the filename and then omits it. If I want to keep the file name will I have to change the ?r=
so that it is individual? I hope this make sense. So far I have this, but I'm sure it won't work.
Options +FollowSymLinks
RewriteEngine On
RewriteRule ^([a-zA-Z0-9]+)/$1.php?r=$1
RewriteRule ^([a-zA-Z0-9]+)/$1.php?r=$1&c=$1
And I think I have to add ([^-]*) this in some part or some way so that it detects the %20 part of the URL, but then how do I convert it to -. Also, how are my $_GET functions going to work??
I hope my question makes sense
You're missing a space somewhere in those rules, but I think you've got the right idea in making 2 separate rules. The harder problem is converting all the - to spaces. Let's start with the conversion to GET variables:
# check that the "sue.php" actually exists:
RewriteCond %{REQUEST_URI} ^/([a-zA-Z0-9]+)/([^/]+)/?$
RewriteCond %{DOCUMENT_ROOT}/%1.php -f
RewriteRule ^([a-zA-Z0-9]+)/([^/]+)/?$ /$1.php?r=$2 [L,QSA]
RewriteCond %{REQUEST_URI} ^/([a-zA-Z0-9]+)/([^/]+)/([^/]+)/?$
RewriteCond %{DOCUMENT_ROOT}/%1.php -f
RewriteRule ^([a-zA-Z0-9]+)/([^/]+)/([^/]+)/?$ /$1.php?r=$2&c=$3 [L,QSA]
Those will take a URI that looks like /sue/blah/ and:
Extract the sue part
Check that /document_root/sue.php actually exists
rewrite /sue/blah/ to /sue.php?r=blah
Same thing applies to 2 word URI's
Something like /kevin/foo/bar/:
Extract the kevin part
Check that /document_root/kevin.php actually exists
3 rewrite /kevin/foo/bar/ to /kevin.php?r=foo&c=bar
Now, to get rid of the "-" and change them to spaces:
RewriteCond %{QUERY_STRING} ^(.*)(c|r)=([^&]+)-(.*)$
RewriteRule ^(.*)$ /$1?%1%2=%3\ %4 [L]
This looks a little messy but the condition matches the query string, looks for a c= or r= in the query string, matches against a - in the value of a c= or r=, then rewrites the query string to replace the - with a (note that the space gets encoded as a %20). This will remove all the - instances in the values of the GET parameters c and r and replace them with a space.

migrated system with new urls

I am switching system from a MVC to a custom code system. Currently we are using this format for urls:
index.php?part=CAPACITOR&type=CERAMIC&model=0805&page=spec
I need now to rewrite urls like to be more nice for user like
mysitecom/CAPACITOR/
mysitecom/CAPACITOR/CERAMIC/
mysitecom/CAPACITOR/CERAMIC/0805/spec.html#2
where #1 and #2 are the pages loaded in jquery. The developer use the old way using /index.php/CAPACITOR/CERAMIC/0805/spec.html
Because I don't think using the index.php in the url is good, what can I do to make this better?
Here's what you need to use
RewriteEngine On
RewriteBase /
RewriteRule ^([a-z0-9\-_]+)/?$ index.php?part=$1&type=all&model=all&page=index [L,NC]
RewriteRule ^([a-z0-9\-_]+)/([a-z0-9\-_]+)/?$ index.php?part=$1&type=$2&model=all&page=index [L,NC]
RewriteRule ^([a-z0-9\-_]+)/([a-z0-9\-_]+)/([a-z0-9\-_]+)/?$ index.php?part=$1&type=$2&model=$3&page=index [L,NC]
RewriteRule ^([a-z0-9\-_]+)/([a-z0-9\-_]+)/([a-z0-9\-_]+)/([a-z0-9\-_\.]+)\.html$ index.php?part=$1&type=$2&model=$3&page=$4 [L,NC]
So when a folder (example CERAMIC) is not provided you can add a flag to load all, same idea for model. It means that if only the first part is provided only he first rule will be used. As of the page.html by default you can load the index.
Now, a-z0-9\-_ means any letters, numbers, dashes and underscore ONLY. You can use ([^/]+) if you prefer that will allow you to use more characters.
The L mean last meaning if the rule match, it will stop. NC means non case so A = a or ABC = abc.

URL Beautification using .htaccess

in search of a more userfriendly URL, how do i achieve both of the following, elegantly using only .htaccess?
/de/somepage
going to /somepage?ln=de
/zh-CN/somepage#7
going to /somepage?ln=zh-CN#7
summary:
/[language]/[pagefilenameWithoutExtension][optional anchor#][a number from 0-9]
should load (without changing url)
/[pagefilenameWithoutExtension]?ln=[language][optional anchor#][a number from 0-9]
UPDATE, after provided solution:
1. exception /zh-CN/somepage should be reachable as /cn/somepage
2. php generated thumbnails now dont load anymore like:
img src="imgcpu?src=someimage.jpg&w=25&h=25&c=f&f=bw"
RewriteRule ^([a-z][a-z](-[A-Z][A-Z])?)/(.*) /$3?ln=$1 [L]
You don't need to do anything for fragments (eg: #7). They aren't sent to the server. They're handled entirely by the browser.
Update:
If you really want to treat zh-CN as a special case, you could do something like:
RewriteRule ^zh-CN/(.*) /$1?ln=zh-CN [L]
RewriteRule ^cn/(.*) /$1?ln=zh-CN [L]
RewriteRule ^([a-z][a-z])/(.*) /$2?ln=$1 [L]
I would suggest the following -
RewriteEngine on
RewriteRule ^([a-z][a-z])/([a-zA-Z]+) /$2?ln=$1
RewriteRule ^([a-z][a-z])/([a-zA-Z]+#([0-9])+) /$2?ln=$1$3
The first rule takes care of URLs like /de/somepage. The language should be of exactly two characters
length and must contain only a to z characters.
The second rule takes care of URLs like /uk/somepage#7.

Resources