So I'm trying to use url rewriting to simplify url's on a website.
Example usage:
www.example.com/test -> www.example.com/index.php?page=test
www.example.com/test/x -> www.example.com/index.php?page=test&value=x
I use this for the rewriting:
RewriteEngine on
#Simplify url
RewriteRule ^(\w+)/?$ index.php?page=$1
RewriteRule ^test/(\w+)/?$ index.php?page=test&value=$1
The issue is that this approach seems to preserve the location prior to the rewrite. So other files loaded on the website like CSS are relative to the original location rather than the location after being rewritten.
Example:
www.example.com/test/x rewrites to
www.example.com/index.php?page=test&value=x.
But CSS files loaded when a user enters www.example.com/test/x are loaded relative to the /test/ folder rather than the / folder. So they're not found.
Am I doing something incorrectly? I'd assumed that rewriting would literally redirect, so things like this wouldn't be an issue. I'd like to solve this issue rather than just using absolute url's for everything - so I can still use it on my test server.
It's important to keep in mind that rewriting is not the same as redirecting. The browser doesn't know about the rewrite that is happening; it just sees the folder structure as it seems.
Relative URLs for site resources are resolved by the browser. So, if you access www.example.com/test/x, and the browser sees <link href="style.css">, it naturally reads this as www.example.com/test/x/style.css, and tries to request this file, only to receive a 404.
One common solution is to always use absolute URLs like www.example.com/style.css. You would most likely store your site's URL as a constant and use <link href="<?php echo SITE_URL; ?>/style.css">.
1)
There is nothing wrong using absolute URLs. You can use define.
For the development environment use:
define('BASE_URL', 'http://test.server.local/');
then for the production environment just change it to:
define('BASE_URL', 'http://www.example.com/');
On all the pages of Your code, You can access those URLs as
x page
So You don't need to change code on all the pages where You reference the BASE_URL
2)
It is a good idea to place all your css in the styles/ directory, then in .htaccess file you can exclude it from rewriting like that:
RewriteEngine on
# add this line:
RewriteRule ^/?styles/.+$ - [L]
#Simplify url
RewriteRule ^(\w+)/?$ index.php?page=$1
RewriteRule ^test/(\w+)/?$ index.php?page=test&value=$1
UPDATE (regarding Your comment)
If you use the concept of BASE_URL the correct URL is made on server and then passed to the browser. If you use <base> you depend on the client side (browser the user uses). It is a good practice to use BASE_URL on the server side, thus you won't depend on the client's browser.
Check out this answer: Is it recommended to use the base html tag?
You can also include the php file (that has the define() function) to all your pages, thus there is no need to use <base> on every page. Here is a nice example of using this.
Related
When I use rewrite rules to clean my URL, I can't access my CSS files. Without the rewrite rules my page works fine, but with the rewrite rules images,CSS and JS documents cannot be linked. What could be the problem?
My .htaccess codes
RewriteEngine On
RewriteRule ^index?$ index.php
RewriteRule ^product_details/([0-9]+) product_details.php?id=$1
Now I don't understand why my edit.php is unable to locate external files even though it loads from the correct path on server-side (mysite.com/). And it does not show the URL in an extra directory (in this case mysite.com/e/).
Mod Rewrite will redirect www.example.com/product_details/123 to product_details.php?id=123 on server-side.
Your browser thinks that /product_details/ points to a directory and resolves relative links accordingly.
The solution is to use absolute paths or add <base href="//www.example.com/"> to your html head element.
I'm working on the complete structure of a web page, and I'm using directories to the url of the site the user can understand the site map, with categories and subcategories. for example. My homepage is www.mantarrayamx.com.
The page I am trying to load is www.mantarrayamx.com/services/seo, but for seo I am using the subdomain seo.mantarrayamx.com to access this directory directly.
I'm using third-party code, for example "font awesome". Unfortunately, the web page loading failed because the links are relative. I try entering in the CSS and JS including of third-party code and yet it still loads with errors. You can see the difference between loading by subdomain and loading by sub-directory here:
mantarrayamx.com/servicios/posicionamientoweb/
posicionamientoweb.mantarrayamx.com/
The question is:
What is the best way to use and manage subdomains and links (../img/)?
For example: How do you do google in your applications:
drive.google.com
mail.google.com
If I have to modify the .htaccess file, please give me an example.
As far as I get your question, you are accessing a subdirectory of your server by using a subdomain. On this subdomain, your data is in the root-directory. I guess you are using absolute links in your app, like:
/service/type/(index.php) or
/about/me/(index.php)
First of all: If you just want to have this for seo-friendlieness and beautiful links, you should definitely use mod_rewrite or the appropriate nginx-config. This saves you from having real subdirectories - you just "fake" them. The following code rewrites all requested URLS to index.php?r=theenteredurl. In PHP (or, if you want, any other processing language of your choice) you can sanitize the URL, analyse it and then server the correct content.
mod_rewrite:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteBase /
RewriteRule ^(.*)$ index.php?r=$1 [L]
Nginx:
location / {
try_files $uri $uri/ /index.php?r=$request_uri;
}
The good thing about this solution is, that the only file that really gets processed is your index.php and you therefor have your app/website tidy and on one place. But be aware: HTML, CSS and JS relative links do NOT work as you might expect with this solution, since they do not see what PHP processes, but only what is in the address-bar of your browser. All relative links are relative to the fake subdirectory. To solve this, you can define a base-url in your HTML-file. All other files loaded in this HTML file will be relative to this url.
If I got you wrong and you really want to have real sub-directories on the one domain and no subdirectories on the other, then you could use the HTML base-tag to define a different base-URL depending on whether you are on the main domain or the subdomain. To find out the latter, try the PHP super-global $_SERVER. Please note, that HTML cannot access something that is out of the public scope - if your ressources are in a higher subdirectory that is not publicly accessable on this subdomain, you have no chance of loading it in HTML files.
I have a complex problem that I an unable to solve for days now. Maybe some expert with more knowledge of htaccess functionality will be able to help out.
I have two files placed in the root directory - test.php and files_include.php.
The URL that a user would normally see is:
www.example.com/test.php?cs1=A&cs2=B&cs3=C&cs4=D
Since this is a ugly URL I would like to rewrite it to something better like:
www.example.com/search/A-B-C-D.html
Using a rule in .htaccess like this I can easily rewrite the URL:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^search/([^-]*)-([^-]*)-([^-]*)-([^-]*)\.html$ /test.php?cs1=$1&cs2=$2&cs3=$3&cs4=$4 [L]
In the file test.php I call for the website config files like this:
include('files_include.php');
Now the problem. As soon as I rewrite the URL to a location different from the root one, I get a really strange issue. The page still renders correct in browser but:
Problem 1. I have to replace src="images with src="../images if I want to see the image correct. This can be easily corrected by giving an absolute link, it is the easier part to do.
But the question is why is the relative path changing? Is .htaccess making the browser think we are in search'/ folder? The answer to this question will help me to identify the main issue, which is Problem2.
Problem 2. Sitemaps generators cannot follow the links on the page once the URL is rewritten, as if it appears blank to them, no matter that in browser all looks fine.
Therefore I am guessing that by rewriting the URL to search/A-B-C-D.html I am breaking something with the inclusion of files_include.php.
Basically, I need a general idea of were to look at and the things I should have in mind when rewriting root/test.php to root/search/A-B-C-D.html
Any suggestions?
Your browser is clueless about 'pretty' and 'ugly' urls. It just requests a folder or a file. If you request http://example.com/search/A-B-C-D.html, to the browser you are requesting a page A-B-C-D.html in the /search/ folder. If you have any relative urls on that page, it will request them relative to that /search/ folder. The browser has no clue, and should have no clue, what the internal representation of a request looks like. Heck, at your end of the line it might even be translated to instructions for a colony of hamsters, which will then send correct data through. The browser doesn't need to know how hamsters behave ;-)
The first problem is easily resolved by making your urls absolute. I wouldn't recommend making them relative to the pretty url. An alternate solutions would be to add the <base> tag to the <head> tag of your page. The href property of this tag will be used as a base for any relative links on your page. See mdn for more information. You would then do:
<head>
<base href="/">
</head>
As for your second problem, the include itself is not the problem. include(..) will first try to find the file in the include_path, and otherwise in the script's directory and the working directory. This doesn't change if you create pretty urls. Apache, and php, still know where the actual file is located you are executing. If an include statement fails to load a file it will generate an error too, which is another way you can tell if the include itself is the problem. See the documentation.
But the question is why is the relative path changing? Is .htaccess making the browser think we are in search'/ folder? The answer to this question will help me to identify the main issue, which is Problem2.
It's changing because the browser is loading /search/something-something-sometrhing-something.html instead of /test.php. The first URL has a relative URI base as: /search/ and the second URL has a base of /.
For the second problem, you could try externally redirecting, but not sure if that'll help the sitemap itself, it depends on the generator. Try adding this rule:
RewriteCond %{THE_REQUEST} \ /+test\.php\?cs1=([^&]*)&cs2=([^&]*)&cs3=([^&]*)&cs4=([^&\ ]*)
RewriteRule ^ /search/%1-%2-%3-%4.html [L,R]
I'm using mod rewrite to redirect all requests targeting non-existent files/directories to index.php?url=*
This is surely the most common thing you do with mod_rewrite yet I have a problem:
Naturally, if the page url is "mydomain.com/blog/view/1", the browser will look for images, stylesheets and relative links in the "virtual" directory "mydomain.com/blog/view/".
Problem 1:
Is using the base tag the best solution? I see that none of the PHP frameworks out there use the base tag, though.
I'm currently having a regex replace all the relative links to point to the right path before output. Is that "okay"?
Problem 2:
It is possible that the server doesn't support mod_rewrite. However, all public files like images, stylesheets and the requests collector index.php are located in the directory /myapp/public. Normally mod_rewrite points all request to /public so it seems as if public was actually the root directory too all users.
However if there is no mod_rewrite, I then have to point the users to /public from the root directory with a header() call. That means, however that all links are broken again because suddenly all images, etc. have to be called via /public/myimage.jpg
Additional info: When there is no mod_rewrite the above request would look like this: mydomain.com/public/index.php/blog/view/1
What would be the best solutions for both problems?
Edit/Additional question:
Is there a way to make /public/ the base dir using plain htaccess code?
Write the app in such a way that it doesn't need mod_rewrite to function (at the cost of having "ugly" urls). Progressively enhance it with mod_rewrite to achieve the desired result. This probably means that you'll need to store some base path config info in your app.
I don't understand these problems at all.
Yes, this is surely the most common thing you do with mod_rewrite, yet with 2 conditions:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
So, nothing hurt your existing images.
Why not to use just absolute path, e.g. /myapp/public/myimage.jpg, so, no virtual directory will hurt image path?
what about path info? You could use it without mod_rewrite
/index.php/path/to/another/file.jpg
<?php
echo $_SERVER["PATH_INFO"]; // outputs /path/to/another/file.jpg
?>
Anyways, if you want to know if mod_rewrite is supported by your server :
<?php
echo "mod_rewrite : ".(!empty($_SERVER["REDIRECT_URL"])?"supported":"not supported");
?>
Then you ll know if mod_rewrite is the solution or maybe path_info is more well suited for you, you could make support functions that could look for both too.
I'm writing multilingual website. I have several files on server like:
/index.php
/files.php
/funny.php
And would like to add language support by placing language code into URL like this:
http://mywebsite/en/index.php
would redirect to:
http://mywebsite/index.php?lang=en
And
http://mywebsite/en/files.php
would redirect to:
http://mywebsite/files.php?lang=en
I would like to put more languages for example:
http://mywebsite/ch-ZH/index.php
And I would like this to work only for files with php and php5 extension. Rest of files should be the same as they are.
So for example when i will go to address
http://mywebsite/ch-ZH/index.php
I would like my PHP to recognize that current path is
http://mywebsite
and NOT
http://mywebsite/ch-ZH
It's necessary for me because in my PHP code I relate on current path and would like them to work as they are working now.
Could you please write how to prepare htaccess file on Apache to meet this criteria?
Try this:
RewriteEngine on
RewriteRule ^([a-z]{2}(-[A-Z]{2})?)/(.*) $3?lang=$1 [L,QSA]
And for the current path problem, you have to know how relative URIs are resolved: Relative URIs are resolved by the client from a base URI that is the URI (not filesystem path!) of the current resource if not declared otherwise.
So if a document has the URI /en/foo/bar and the relative path ./baz in it, the client resolves this to /en/foo/baz (as obviously the client doesn’t know about the actual filesystem path).
For having ./baz resolved to /baz, you have to change the base URI which can be done with the HTML element BASE.
If you don't want to use ModRewrite, you can put symbolic links in the web folder (ln -s . en) and check the URL in PHP.
Something like this should do the trick,
RewriteEngine on
RewriteRule ^(.[^/]+)/(.*).php([5])?$ $2.php$3?lang=$1 [L]
This will only match .php and .php5 files, so the rest of your files will be unaffected.