I am working on a site and learning PHP at the same time so it is relatively new to me. I am working on URL rewrite currently, however, I am not getting the desired result.
I am trying to change: example.com/CMS/listing?id=1 into example.com/CMS/listing/1.
Using the .htaccess file held in the root of the files, I have the following:
RewriteEngine On
RewriteBase /
RewriteRule CMS/listing/([0-9]+) CMS/listing.php?id=$1
And on the site, I have a simple echo function which gets the query string param for id. When I navigate to example.com/CMS/listing?id=1 the function displays 1, however, when I go to example.com/CMS/listing/1 it does not show anything. Is there something I'm missing or doing wrong?
# Get QString Param
$id = $_GET["id"];
echo $id;
Footnote
.htaccess is held at the root, and listing.php is within a folder called CMS.
It looks like you have a conflict with MultiViews. You should disable MultiViews at the top of your .htaccess file:
Options -MultiViews
If MultiViews is enabled then when you request /CMS/listing/1, mod_negotiation will map the request to /CMS/listing.php (appending the file extension, without any URL parameter) before your mod_rewrite directive is able to process the request. (/1 is seen as additional pathname information or PATH_INFO on the URL.)
A URL like /CMS/listing?id=1 (without the file extension) will only work if MultiViews is enabled. In this case, the query string is already present on the URL.
You could also redirect all traffic through to index.php and handle it all in PHP. That is how other CMS' and framework usually do it.
This is the Laravel approach - you don't have to do it this way, but later on when you want to do custom urls on news post or any other this, you have to setup new rules. This way you can just add them to the database and create some kind off route handler. If you want to keeps it simple you could then just create a table in the database where you store urls and a field for the file to be called.
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews -Indexes
</IfModule>
RewriteEngine On
# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]
# Send Requests To Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>
Related
I'm trying to rewrite some old site pages to routes on my shiny new Laravel site. I understand in principle how .htaccess works, but there's a line in the default Laravel .htaccess which (I think) is throwing my own rewrites. So, this is something like what I am trying to do:
RewriteRule ^user/(\d+)*$ ./users
However, Laravel already has this:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
Which effectively says "If the user request is for any file or folder that does not exist, pipe their request through to index.php" - the [L] meaning that this is the last rule for these conditions.
My problem with this is, where do I put my rewrite instructions? If I put it after that rule then surely my rewrite will be ignored as everything is already being sent to index.php (if htaccess rules are sequential)
If I put my rule before Laravel's default rules, does that mean that my rule will mess up what Laravel is trying to do? At the moment, wherever I put my rule, I just get various result ranging from a 500 error to a blank page with no content.
How can I integrate my own rules into Laravel's .htaccess file without stepping on Laravel?
To make sure that Laravel's .htaccess file rules do not conflict with yours, you need to ensure that your rules come before theirs. I am supplying a sample of my .htaccess files with path names changed, each line annotated so that it makes sense to those who are facing the sam problem:
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews
</IfModule>
# Make sure Rewrite engine is running
RewriteEngine On
# Make sure base of site is set to root (othwerwise you can get results like /var/www/public_html/ before the results pages)
RewriteBase /
# For all directory requests in the url (d) e.g. blah.com/directory/
RewriteCond %{REQUEST_FILENAME} !-d
# And for all file requests in the url (f) e.g. blah.com/directory/page.php
RewriteCond %{REQUEST_FILENAME} !-f
# Check for the CONDition that the page has 'product_id' in the url e.g. http:/www.blah.com/show_product.php?product_id=273
RewriteCond %{QUERY_STRING} ^product_id=(.*)$
# If the condition above was met, then check if the page is called list_products.php, if it is, redirect the browser to /product/ with the product id (273) as %1
RewriteRule ^list_products.php$ product\/%1? [R=301,L]
# Simpler redirect for pages without a url variable
Redirect /car-hire.php https://www.blah.com/car-hire
# Then comes Laravel’s .htaccess stuff
# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
</IfModule>
It seems (as CBroe kindly answered in his comment) that keeping your rules ‘on top’ of Laravel’s as above is the answer
I have a food blog website, with many posts stored in a database. When someone clicks on a link to a post, the website searches the database for the post and presents it in a template. I don't store an HTML file for each post.
Right now, I do it by handling a 404 error (which goes off because the requested HTML file doesn't exist) and searching the database from there. I know this isn't right.
How can I set up my web server (Apache running on a Raspberry Pi), so that all requests go to one page, which will do the searching and send the user to the right page? And is this the right thing to do?
You can do that with a file you put in your website root named .htaccess and using the mod_rewrite module. You'll need to make sure .htaccess and mod_rewrite are enabled in the Apache configuration. But once enabled you can do something like this:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php?path=$1 [NC,L,QSA]
That will rewrite any URL that doesn't refer to an actual existing file or directory to your index.php which you can use to handle the request.
For example, if someone visits http://yourdomain.com/article, the path will be internally rewritten to index.php?path=article and you can access the path using $_GET['path'].
Note: If you want to literally serve everything through that single entry point you could remove the two middle lines and that would send everything through there. Including images, scripts, CSS etc, which is generally not what you want.
You need proper .htaccess rules in your public root directory and you need a apache2 mod_rewrite module enabled.
On Ubuntu you can can enable it with the following command:
sudo a2enmod rewrite
your .htaccess file could look like the following:
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews
</IfModule>
RewriteEngine On
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]
# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
</IfModule>
I've taken over a former site/domain, and set up a new site using Wordpress. The WP installation rewrites URL's to static ones, as you'd expect it to.
At the same time I want to preserve the former pages, as they have incoming links. I'm not interested in 301'ing them to "new" pages.
The old URL structure is /index.php?id=123, which I suspect is causing the problem with the WP .htaccess file. For reference, this is what it looks like:
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
I've tried adding the following:
RewriteRule ^([0-9]+).html index.php?id=$1 [R,L]
Doesn't work. Just redirects to site.com/?id=123 and shows the front page.
I should add that I plan on just adding these new pages as regular static HTML files in the format of 123.html, 321.html etc.
How do I use .htaccess to make this work together with the WP installation and what WP puts into the .htaccess file?
To clarify:
I want to have my 123.html static HTML page be index.php?id=123. When you access index.php?id=123 it should bring up 123.html, but show index.php?id=123 in the address bar. If you access 123.html it should 301 to index.php?id=123.
To map an URL with a querystring up to an actual file you'll need to use a RewriteCond to match the querystring itself (as RewriteRule doesn't):
Something along these lines ought to do it:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
# retrieve X.html when index.php?id=X is requested
RewriteCond %{REQUEST_FILENAME} index\.php
RewriteCond %{QUERY_STRING} ^id=([0-9]+)$
RewriteCond %1.html -F
RewriteRule .* %1.html? [L]
# standard WordPress routing
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
This will first check to see if you've got a request for index.php with a querystring like id=X.
Then it'll check to see if a file called X.html actually exists; I'm not 100% happy about having to use the more system hungry subrequest file check -F rather than the standard -f but I can't see a way around it in .htaccess in this case.
If X.html actually exists, it'll fetch that file whilst leaving the URL as index.php?id=X.
However if that file doesn't exist it'll fall back to standard WordPress no file, no directory routing to index.php
I'm not a WordPress expert but that should work; I guess the main WordPress controller uses $_SERVER['REQUEST_URI'] to determine the action.
Note: This won't, however, prevent people from accessing 123.html directly by going to the URL www.site.com/123.html - I kept falling into infinite loops and Apache 500 errors trying to prevent that :|
I am trying to catch ALL requests to files in a directory and it's subdirectories and to route them to one single file in a subdirectory. Here is what the htaccess directives look like:
Options -MultiViews
<IfModule mod_rewrite.c>
RewriteEngine On
# Excluding one directory
RewriteRule ^(excludedfolder)($|/).*\.(php)$ - [L]
# Redirect everything that is html or php to magicscript
RewriteRule \.(php|html|phps)$ /excludedfolder/magicscript.php [L]
RewriteRule ^/?$ /excludedfolder/magicscript.php [L]
RewriteRule ^/?index.php$ /excludedfolder/magicscript.php [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . excludedfolder/magicscript.php [L]
</IfModule>
This works on the mostpart of systems.
If i call someserver.com/testfile.php, it is properly routed to magicfile.php. If i call someserver.com/testfile, it also is properly routed to magicfile.php. The same for subfolders: If i call someserver.com/somefolder/testfile.php or someserver.com/somefolder/testfile, it is properly routed to magicfile.php.
But on some servers, it is not allowed to set the Options -MultiViews which causes the server to completely fail. If I remove the option, it still works, but it doesn't if I don't add the file extension.
How to redirect non existing files to magicfiles.php without having to use Options -MultiViews? Or how to detect if it is allowed to set the option in php?
Thanks for your help!
Maybe the server do not support Options -MultiViews http://httpd.apache.org/docs/2.2/mod/core.html#options
I'm creating a PHP controller for testing purposes on my domain. The domain, by default, is entirely on Wordpress and I'm having issues setting up just the folder testing1 to be controlled by my PHP controller. Here's the code in my .htaccess file:
# BEGIN WordPress
<IfModule mod_rewrite.c>
Options +FollowSymLinks
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php
RewriteRule ^testing1/(.*)$ ./testing1/controller.php
</IfModule>
# END WordPress
When I go to mydomain.com/testing1/ I get an internal server error. Any help is appreciated. Thanks!
Get rid of ./, which is used to point to current directory.
RewriteRule ^testing1/(.*)$ testing1/controller.php
I have it working.
The RewriteRules are executed in order. If one does match, the rest is ignored.
So the result might look like this (just the RewriteRules):
RewriteRule ^testing1/(.*)$ /testing1/controller.php
RewriteRule . /index.php
The second rule does mean that when you type exactly one character (whatever it is), you will get directed to index.php. I don't know though if that is your intended behaviour.