mod_rewrite and hyperlinks with spaces - php

So I'm no .htaccess expert, by no means, but I have managed to put this code together for a webiste I'm making:
Options -Indexes +Includes
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_URI}::$1 ^(.*?/)(.*)::\2$
RewriteRule ^(.*)$ - [E=BASE:%1]
RewriteRule ^\.htaccess$ - [F]
RewriteRule ^$ /%{ENV:BASE}/index.php?id=home
RewriteCond %{REQUEST_URI} !\.php$ [NC]
RewriteCond %{REQUEST_FILENAME} !-s
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ $1 [R=301,L]
RewriteRule ^([a-zA-Z0-9]*)$ /%{ENV:BASE}/index.php?id=$1 [QSA,L]
</IfModule>
It basically changes www.example.com/some/dir/index.php?id=home to www.example.com/some/dir/home while the first few rules are creating some kind of relative path value so I don't have to change the RewriteBase everytime I change the base folder (this is important for this project!).
It works perfectly fine, but now I have encountered a problem where there have to be spaces in the URL like www.example.com/some dir/sub folder/home and this messes everything up.
If you click a link on the page (e.g. "href="home"") it redirects to www.example.com/home instead of www.example.com/some dir/sub folder/home with a 404 error, obviously (even though it works if there are no spaces!). I found out if right click > "copy link to clipboard" it becomes the encoded version www.example.com/some%20dir/sub%20folder/home even if it shows the decoded version in the address bar. BUT if you manually type the decoded version www.example.com/some dir/sub folder/home it still works fine.
There seems to be a problem with spaces and encoding. How do I get my hyperlinks working properly?
-- EDIT --
Thanks to the tutorial posted by elcodedocle, I simply added backslash space: ^([a-zA-Z0-9/ ]*)$ to the regex in the last rule, even if it's not the best method. Then I noticed the [L] flag in the second last rule. I removed it because this shouldn't be the last rule (don't know why it was there in the first place...) and now it works! Well, kind of...
Now, If there is a trailing slash at the end of the URL it sill doesn't work anymore. Probabply because of the removal of the [L] flag in the rule but I don't know how to fix this...

Have your .htaccess like this:
Options -Indexes +Includes -MultiViews
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_URI}::$1 ^(.*?/)(.*)::\2$
RewriteRule ^(.*)$ - [E=BASE:%1]
RewriteCond %{REQUEST_URI} !\.php$ [NC]
RewriteCond %{REQUEST_FILENAME} !-s
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ %{ENV:BASE}$1 [R=302,L,NE]
RewriteRule ^\.htaccess$ - [F]
RewriteRule ^$ /%{ENV:BASE}/index.php?id=home [L,QSA]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+?)/?$ %{ENV:BASE}index.php?id=$1 [QSA,L]
</IfModule>
This is working fine under all the test cases you have described in your question like handling spaces, trailing slashes etc.

Try changing:
RewriteRule ^([a-zA-Z0-9]*)$ /%{ENV:BASE}/index.php?id=$1 [QSA,L]
to
RewriteRule ^([a-zA-Z0-9%]*)$ /%{ENV:BASE}/index.php?id=$1 [QSA,L]
(It's a wild guess but it's the only one of your rules that has problems with %)
[EDIT] Unencoded spaces are not allowed in URIs. The ban on spaces is enforced by all browsers as they will convert every space to %20 before sending the request via the http protocol. A workaround to handle them in mod_rewrite is described on this tutorial:
Since URLs can't have spaces (except as %20), use underlines or
hyphens to replace them. If you ABSOLUTELY have to use spaces (%20) in
your URIs, you can include them in your regex within a range
definition as {space}, i.e., ([a-zA-Z\ ]+). However, this is NOT
advised.
[EDIT2] If that doesn't work, you may have to translate %20 into spaces, then apply the other rules. Here is a hack based on this answer you may try:
sedspace.sh:
#!/bin/sh
sed -u 's/%20/ /g'
.htaccess:
...
RewriteMap sed-space prg:sedspace.sh
RewriteRule ^(.*)$ ${sed-space:$1}
...
(Make sure that sedspace.sh is executable)

Related

.htaccess rewrite url with letters öäå and passing variables

Lets say survey name is test.
When completing form it redirects to
www.example.com/survey_thank_you.php?survey_name=test
then rewrites it to www.example.com/test/thank_you and it works as inteded.
But because here we use öäå the issue emerge. If survey name is testä, it redirects allright but rewrites it to
www.example.com/test%25C3%25A4/thank_you (this works)
and it should rewrite to www.example.com/testä/thank_you
also if go straight to www.example.com/testä/thank_you it works.
htaccess:
Options +FollowSymLinks
Options -MultiViews
RewriteEngine on
AddCharset UTF-8 .php
AddDefaultCharset utf-8
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{QUERY_STRING} ^survey_name=(.*)/?$
RewriteRule ^survey_thank_you\.php$ /%1/thank_you [R,L,QSD]
RewriteRule ^(.*)/thank_you$ survey_thank_you.php?survey_name=$1 [L,NC,QSA]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^(.*)/?$ survey_form.php?survey_name=$1 [L,NC,QSA]
If i change (.*) to ([0-9a-zA-Z]+) it rewrites it allright /testä/thank_you but then i get error 404. Any suggestions much appreciated.
test%25C3%25A4 would be the result of double URL encoding. One level decoded, leaves test%C3%A4.
You can use the NE flag to try and avoid double encoding in this place, https://httpd.apache.org/docs/2.4/rewrite/flags.html#flag_ne

Remove File Extension and URL Variable using .htaccess

I'm making up myself a small blog and I found a useful .htaccess file to remove file extensions:
AddType text/x-component .htc
RewriteEngine On
RewriteBase /
# remove .php; use THE_REQUEST to prevent infinite loops
RewriteCond %{THE_REQUEST} ^GET\ (.*)\.php\ HTTP
RewriteRule (.*)\.php$ $1 [R=301]
# remove index
RewriteRule (.*)/index$ $1/ [R=301]
# remove slash if not directory
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} /$
RewriteRule (.*)/ $1 [R=301]
# add .php to access file, but don't redirect
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteCond %{REQUEST_URI} !/$
RewriteRule (.*) $1\.php
This works just fine and all pages are showing up .php less. I know wanted to extend this so when I click a link to a specific blog post (say /blog/index.php?art=1) it just shows in the url as website/blog/1. I thought to tag on to the end of the .htaccess file:
RewriteRule ^blog/(.*)$ blog/index.php?art=$0 [L]
But that doesn't seem to be working. EDIT Actually it breaks the blog page so no snippets are pulled through from the DB
My .htaccess file is in the root directory and the blog files are /root/blog/index.php
Any help would be gratefully appreciated
Unlike most other languages, the parameters in .htaccess are not 0-based. To access the first parameter, you should use $1, not $0.
The following should work:
RewriteRule ^blog/(.*)$ blog/index.php?art=$1 [L]
It might also be worthwhile to add some tests in there, for example you might only want numerical values passed to art, so you can improve it using:
RewriteRule ^blog/([0-9]+)$ blog/index.php?art=$1 [L]
Also, it might be worthwhile to add the QSA flag, since this will also preserve any query string that is passed in the original URL:
RewriteRule ^blog/([0-9]+)$ blog/index.php?art=$1 [L,QSA]

Clean URL redirection htaccess

i have a website SongsBar.com , when a query is searched on my website, the url in the browser displays like this - http://songsbar.com/download.php?q={search text}.
i want it be appear like this http://songsbar.com/download/{search text}.html
.htaccess
RewriteEngine On
RewriteRule ^download/([^/]*)\.html$ /download.php?q=$1 [L]
First, you need to make sure Multiviews (mod_negotiation) is turned off, otherwise it'll mess with the /download/ and /download.php stuff.
Then you need to externally redirect requests for download.php
Then you need to internally rewrite the /download/ requests back to the php file (the browser is oblivious to this happening.
Options -Multiviews
RewriteEngine On
RewriteCond %{THE_REQUEST} \ /+download.php\?q=([^&\ ]+)
RewriteRule ^ /download/%1.html? [L,R=301,NE]
RewriteRule ^download/(.+)\.html$ /download.php?q=$1 [L,B,QSA]
The B flag may not be necessary. It depends on what kind of stuff you plan on putting in the parameter. The flag ensures that special characters get encoded.
http://httpd.apache.org/docs/current/mod/mod_rewrite.html
Something like : RewriteCond %{REQUEST_FILENAME}
You can achieve this with something along the lines of:
RewriteEngine On
RewriteBase /download/
RewriteCond %{REQUEST_FILENAME} !-f #if the file actually exists don't rewrite
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)\.html$ /download.php?q=$1 [L]

Remove .php from example.com/test.php/foo/bar

I'm looking for a way to simply remove ".php" from a url while ignoring everything after the .php
So example.com/test.php/foo/bar would become example.com/test/foo/bar
and then in the PHP template I can search for and utilize foo or bar as I please. Everything I've found to remove .php interferes with the variables at the end.
UPDATE: I've found some success by removing .php from the file name and then using ForceType. Although It'd still be nice if I could keep the .php extension so my Code Editor knows how to highlight the syntax :)
<FilesMatch "^test$">
ForceType application/x-httpd-php5
</FilesMatch>
Update 2
Here's a RewriteRule that I've tried using to some success, but when I add a trailing slash and some content after, it results in a 500 internal server error
RewriteEngine On
RewriteBase /
# remove .php; use THE_REQUEST to prevent infinite loops
RewriteCond %{THE_REQUEST} ^GET\ (.*)\.php\ HTTP
RewriteRule (.*)\.php$ $1 [R=301]
# remove index
RewriteRule (.*)/index$ $1/ [R=301]
# remove slash if not directory
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} /$
RewriteRule (.*)/ $1 [R=301]
# add .php to access file, but don't redirect
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteCond %{REQUEST_URI} !/$
RewriteRule (.*) $1\.php [L]
Your last block is almost there. However you need a bigger assortment of RewriteConds to make it work with an optional PATH_INFO.
Namely you need to match the word characters from the REQUEST_FILENAME/_URI first, and then test for existence of a like-named .php script:
RewriteCond %{REQUEST_URI} ^/(w+)/
RewriteCond %{DOCUMENT_ROOT}/%1.php -f
RewriteRule ^(\w+)/(.+)$ $1.php/$2 [L]
The last RewriteRule depends on existing trailing vars. Add one of the generic rule blocks for plain http://example.com/test requests without PATH_INFO. Note that this specific set will work with xyz.php scripts in the webroot only.
Please try to recheck this:
RewriteCond %{REQUEST_URI} ^/([a-z0-9-_]+)/([a-z0-9-_]+)/([a-z0-9-_]+)/?$
RewriteRule ^(.*) ^/%1.php/%2/%3

Mod_rewrite trouble: Want to direct from ?= to a flat link, nothing seems to work

I have a site that currently serves results as example.com/index.php?show=foo
and I'd like it to read example.com/show/foo.
My understanding is this would make them visible to search engine robots, and it seems a much simpler way to do this than to create a couple hundred html files...
I've tried the following .htaccess code:
Options +FollowSymLinks
RewriteEngine on
RewriteRule ^show/(.*)$ index.php?show=$1 [NC,L]
No dice.
Also tried this, which I found on another stack overflow question:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([0-9A-Za-z]+)/?$ /index.php?show=$1 [L]
</IfModule>
Any ideas on what I'm missing here?
Note that ^([0-9A-Za-z]+)/?$ will try to match a request URI that only includes alphanumeric characters optionally trailed by a slash. Therefore the URI show/foo will not be matched because there are more characters at the end (ie, after the slash, where the expression expects to find the end of the string).
Try:
RewriteRule ^show/([0-9A-Za-z]+)/?$ /index.php?show=$1 [L]
Also, to capture aditional query parameters, you could do:
RewriteRule ^show/([0-9A-Za-z]+)/?$ /index.php?show=$1&%{QUERY_STRING} [L]
This means a URL like /show/page?id=1 rewrites to /index.php?show=page&id=1
I do something like this on sites that use 'seo-friendly' URLs.
In .htaccess:
Options +FollowSymLinks
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* /index.php [L]
Then on index.php:
if ($_SERVER['REQUEST_URI']=="home") {
include ("home.php");
}
The .htaccess rule tells it to load index.php if the file or directory asked for was not found. Then you just parse the request URI to decide what index.php should do.
You're on the right track, but your rule has issues. .* is pretty all inclusive. Start there and go more restrictive if needed.

Categories