mod_rewrite for SEO friendly URLs - php

I have a CMS that handles SEO friendly URLs created with the CMS. So anything that is an extension of index.php like www.url.com/index.php?id=slug is nicely changed to www.url.com/slug.
However, I also have over a thousand pages that are created with MYSQL query strings that are not connected to my CMS. So I have:
www.url.com/item.php?id=001234&pg=author-title
the information in id and pg are required to produce the page. What I want are for these page urls to be:
www.url.com/item/001234/author-title.html
I've looked at a number of mod_rewrite tutorials searching for all the ways to do this but I can't seem to get it to work.
Here is my .htaccess (keep in mind some of the things in here are used and generated by my CMS:
Edit: Okay, based on the answers so far I have changed my .htaccess to the following:
# Use PHP5 as default
AddHandler application/x-httpd-php5 .php
AddDefaultCharset UTF-8
# File modified on Dec 5 11:28:31 2011 by server
# For security reasons, mod_php is not used on this server. Use a php.ini file for php directives
# php_value default_charset "UTF-8"
Options -Indexes
Options +FollowSymLinks
# blocks direct access to the XML files - they hold all the data!
<Files ~ "\.xml$">
Order allow,deny
Deny from all
Satisfy All
</Files>
<Files sitemap.xml>
Order allow,deny
Allow from all
Satisfy All
</Files>
RewriteEngine on
# Usually it RewriteBase is just '/', but
# replace it with your subdirectory path
RewriteBase /
# Usually it RewriteBase is just '/', but
# replace it with your subdirectory path
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule /?([A-Za-z0-9_-]+)/?$ index.php?id=$1 [QSA,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/?item/([0-9]+)/([a-zA-Z0-9_]+).html$ item.php?id=$1&pg=$2 [QSA,L]
Edit: After changing the .htaccess with the feedback so far, the rewritten URLs are still not producing the desired results. I'm still getting a 404.

Change
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule /?([A-Za-z0-9_-]+)/?$ index.php?id=$1 [QSA,L] #passes to CMS
RewriteRule ^/?([a-zA-Z_]+)/([a-zA-Z_]+).html$ item.php?id=$1&pg=$2 [QSA,L] #passes to your stuff
to
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/?item/([a-zA-Z_]+)/([a-zA-Z_]+).html$ item.php?id=$1&pg=$2 [QSA,L]
# conditions need to be repeated
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule /?([A-Za-z0-9_-]+)/?$ index.php?id=$1 [QSA,L]
Always put more specific rules above more general ones.
And unless your item IDs use letters use:
RewriteRule ^/?item/([0-9]+)/([a-zA-Z_]+).html$ item.php?id=$1&pg=$2 [QSA,L]

You need to add item at the start to match the example you give and make some changes to your character classes. Try:
RewriteRule ^item/([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)\.html$ item.php?id=$1&pg=$2 [QSA,L]
This will match a URL of the form item/[string of letters, numbers and underscore]/[string of letters, numbers and underscore].html
If your IDs are only numeric you can remove the letters from the first character class.

Related

.htaccess stop directory listing and forward to handler.php

I am trying to implement SEO friendly URLs using .htaccess and PHP.
I have achieved 90% of my goal and struggling with just one use case.
Here is what happing, when I access the following url
http://somesite.com/cms/movies/tarzan
it lands on
my-handler.php?the_url=movies/tarzan
This is perfect and that is what I want because then I manage it myself. The real problem is when I don't provide any slugs, then it lists the directory (means show all files and folders in it)
http://somesite.com/cms/
Can someone please help me fix following .htaccess content, so that even if I don't provide slug it should still be handled by my-handler.php instead of lisiting full directory?
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /cms/
RewriteCond %{REQUEST_FILENAME} !/(admin|css|fonts|ico|include|js)/
RewriteRule ^my-handler\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /cms/my-handler.php?the_url=$1 [L,QSA]
</IfModule>
Solved
As per #Roman suggestion, I added the following to the above listing and it solved my problem. Plus I do not have to compromise on accessing physical directories RewriteCond %{REQUEST_FILENAME} !-d
DirectoryIndex my-handler.php
At first you have to set the DirectoryIndex to handle every request which points to / with your my-handler.php. This can be done by adding the line to your .htaccess
DirectoryIndex my-handler.php
To disable the directory listing, you have to forbid the listing by adding the following line to your .htaccess
Options -Indexes
Remember that this configuration is per .htaccess and just for the directory you are placing the file in. If you want to make changes for your whole webserver, you can edit the httpd.conf and search for
Options Indexes
and remove the Indexes option.
Documentation
The listing is provided by the mod_autoindex module.
Nice side-fact
If you just want to disable the listing of specific file-types like .env or .php files, you can add the option IndexIgnore *.php to you .htaccess
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /cms/
RewriteCond %{REQUEST_FILENAME} !/(admin|css|fonts|ico|include|js)/
RewriteRule ^my-handler\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
#RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !.*\.(ico|gif|jpg|jpeg|png|js|css|json|woff|ttf)
RewriteRule ^(.*)$ /cms/my-handler.php?the_url=$1 [L,QSA]
</IfModule>

Recursively remove .php .htaccess & Wordpress

I've set up a Wordpress site.
I need to recursively remove the .php extension on files in a specific folder.
Say:
www.domain.com/wordpresspage/ (set up with permalinks, all good).
I then need to remove .php recursively for folder:
domain.com/gz/*
The content of domain.com/gz/ should have the .php extension removed. But only for this folder.
Folder structure
/
-/images (No .htaccess rules should apply, Wordpress takes care of it.)
-/downloads (No .htaccess rules should apply, Wordpress takes care of it.)
-/gz (.htaccess change, to remove .php file extension, overwriting Wordpress, in this particular folder)
-file1 (No .htaccess rules should apply, Wordpress takes care of it.)
-file2 (No .htaccess rules should apply, Wordpress takes care of it.)
Before I used the following .htaccess content to remove .php extensions, but now I need to only force this on one folder, since Wordpress is taking care of the rest.
#RewriteBase /
#RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /([^.]+)\.php\ HTTP
#RewriteRule ^([^.]+)\.php$ https://example.com/$1 [R=301,L]
#RewriteCond %{REQUEST_URI} !(\.[^./]+)$
#RewriteCond %{REQUEST_fileNAME} !-d
#RewriteCond %{REQUEST_fileNAME} !-f
#RewriteRule (.*) $1.php [L]
I've tried a ton of things already, but the last few included:
Use the old .htaccess file that removes .php on all pages. This solves my path issue, but gives internal server error on the rest of the site.
Tried a gazillion ways of filtering out that folder recursively, to the point I'm no longer sure if it's even possible. (Don't even remember a fraction of what I tried).
Tried in the permalinks to add .php - but since it will redirect to remove it again, I'll get yet another Internal Server Error.
TL;DR - Can I recursively remove .php on a specific path in my .htaccess file, so Wordpress ignores this folder and let's it deal with it's own business?
Added after first round of help, my .htaccess file now looks like this:
# -FrontPage-
IndexIgnore .htaccess */.??* *~ *# */HEADER* */README* */_vti*
RewriteEngine On
# Only apply if request starts with /gz/
# followed by at least one character and ends with .php
RewriteCond %{REQUEST_URI} ^/?gz/[^.]+\.php$
# Redirect to the same location but without .php ant the end
RewriteRule ^/?(.*)\.php$ /$1 [R=301,L]
# Only apply if request starts with /gz/ followed by at least one character
RewriteCond %{REQUEST_URI} ^/?gz/[^.]+$
# and the request it not a real directory
RewriteCond %{REQUEST_FILENAME} !-d
# and the request it not a real file
RewriteCond %{REQUEST_FILENAME} !-f
# Rewrite the request with .php at the end
RewriteRule ^(.*)$ /$1.php [L]
<Limit GET POST>
order deny,allow
deny from all
allow from all
</Limit>
<Limit PUT DELETE>
order deny,allow
deny from all
</Limit>
AddType application/x-httpd-php-old .php
<IfModule security_module>
SecFilterEngine Off
</IfModule>
<IfModule security2_module>
SecRuleRemoveByID 1-99999
SecRuleRemoveByTag unoeuro
</IfModule>
After re-applying Permalinks, Wordpress adds this section to the .htaccess file:
# 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
Thanks in advance,
L
What you could do is the following
RewriteEngine On
# Only apply if no rewrite
RewriteCond %{ENV:REDIRECT_STATUS} ^$
# Only apply if request starts with /gz/
# followed by at least one character and ends with .php
RewriteCond %{REQUEST_URI} ^/?gz/[^.]+\.php$
# Redirect to the same location but without .php ant the end
RewriteRule ^/?(.*)\.php$ /$1 [R=301,L]
# Only apply if request starts with /gz/ followed by at least one character
RewriteCond %{REQUEST_URI} ^/?gz/[^.]+$
# and the request it not a real directory
RewriteCond %{REQUEST_FILENAME} !-d
# and the request it not a real file
RewriteCond %{REQUEST_FILENAME} !-f
# Rewrite the request with .php at the end
RewriteRule ^(.*)$ /$1.php [L]
So if you request e.g. /gz/gz5.php is will be redirect you to to /gz/gz5
and if the request is /gz/gz5 it will rewite to /gz/gz5.php

.htaccess / php url rewriting without routing?

So I've been searching for a while now and can't find anything specific on how to create a pretty url / seo / slug url type system WITHOUT sending everything to a index.php or moving things into subfolders.
Basically I'm making a website which you can currently go to urls like movie.php?id=#### / show.php?id=####. Ideally I'd like the url to be movie/#### or movie/id/#### (or down the line slugs of the name that i can use to grab the right one) etc.
Is there a way to do it without having a single index.php router or am I just going to have to rewrite all my files to adhere to this style?
You can create a rewrite rule in .htaccess that routes the movie urls to movie.php as follows:
movie/123:
RewriteRule ^movie/(\d+)$ movie.php?id=$1 [L]
movie/id/123:
RewriteRule ^movie/id/(\d+)$ movie.php?id=$1 [L]
movie/title-of-movie:
RewriteRule ^movie/(\S+)$ movie.php?slug=$1 [L]
movie/title/title-of-movie:
RewriteRule ^movie/title/(\S+)$ movie.php?slug=$1 [L]
combination movie/123/title-of-movie:
RewriteRule ^movie/(\d+)/(\S+)$ movie.php?id=$1&slug=$2 [L]
Edit: added a full .htaccess example for 1 required with up to 2 extra optional parameters with a fallback on index.php if the url is not for movies.
Options -Indexes
IndexIgnore */*
Options FollowSymLinks
AddDefaultCharset utf-8
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^movie/([^/]+)/?([^/]*)/?([^/]*)$ movie.php?param1=$1&param2=$2&param3=$3 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule . index.php [L]
</IfModule>
^ to match from the beginning
$ to match until the end
? for 0 or 1 occurrence
+ for 1 or more occurrences
* for 0 or more occurrences
If the url rule does not match and the file does not exist then it will route the url to index.php, but you can remove that last part if you don't want that.
Yes, assuming your URL structure follows a relatively consistent pattern, you can definitely do this with an .htaccess file and mod_rewrite (without the need for an index.php file, commonly referred to as a front controller).
Here's a really simple example:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.*)/(.*)$ $1.php?id=$2 [NC,L]
This takes an incoming URL like http://example.com/movie/3 and performs a transparent/internal rewrite (so the user doesn't see the URL change) to http://example.com/movie.php?id=3.
Of course, this example could be expanded to handle more parameters, etc. but hopefully this gets you started on the right path. I highly recommend you read the mod_rewrite documentation for more details: http://httpd.apache.org/docs/2.4/mod/mod_rewrite.html

Wordpress URL Parameters on GoDaddy

I am currently making a website (http://tannernelson.me/ehs)
It's hosted on Godaddy, and I'm using wordpress as a CMS.
I want to be able to make:
http://tannernelson.me/ehs/school/academics/teachers/jsmith
turn into
http://tannernelson.me/ehs/index.php?pagename=teachers&detail=jsmith
So, basically, if there are 4 segments to the url (school/academics/teachers/jsmith) I want the last one to be a variable. So the fourth segment of any url will be the variable "detail"
My current URL rewrite is currently
# Mod Rewrite
Options +FollowSymLinks
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /ehs/index.php [L]
Options -Multiviews
It won't work any other way, even with the default WordPress .htaccess file. And I have no idea what that means, or what kind of request URI is made out of it. It's really confusing.
Any ideas?
The code you have right now means:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
If the requested filename is not (!) a regular file -f and if the requested filename is not (!) a directory -d then:
RewriteRule . /ehs/index.php [L]
Match any single character (.) and if a match is found rewrite the URL to /ehs/index.php and then make this the last rule ([L]) so don't process any further rules.
This doesn't look like what you want, but seems to be working. http://tannernelson.me/ehs/school/academics/teachers/jsmith serves up (I think) http://tannernelson.me/ehs/index.php because I get a custom 404 not found page.
Try the following .htaccess code:
Options +FollowSymLinks
RewriteEngine On
RewriteBase /
# Redirect the ehs/school/academics/$1/$2 URIs to /ehs/index.php?pagename=$1&detail=$2
RewriteRule ^ehs/school/academics/([^/]+)/([^/]+)$ /ehs/index.php?pagename=$1&detail=$2 [L]
# Otherwise if the requested URI is not found (not a file nor a directory)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
#Redirect everything else to index.php
RewriteRule .* /ehs/index.php [L]
Options -Multiviews
I just tested this on my Apache server and it works.

CodeIgniter: How to disable "index.php" in URLs completely (disallow it if manually entered in URL)

I'm using codeigniter and have been able to use url's without "index.php" in there, but if I manually type in "index.php", the urls still work. I'd like to disable access to "index.php/controller" type urls in order to avoid duplicate content penalty from Google.
Here is what my current .htaccess file looks like:
Options +FollowSymLinks
# Turn on URL rewriting
RewriteEngine On
# Installation directory
RewriteBase /
# Protect hidden files from being viewed
<Files .*>
Order Deny,Allow
Deny From All
</Files>
# Protect application and system files from being viewed
RewriteRule ^(?:application|modules|system)\b.* index.php/$0 [L]
# Allow any files or directories that exist to be displayed directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Rewrite all other URLs to index.php/URL
RewriteRule .* index.php/$0 [PT]
You can try this by replacing the last 3 lines with this
RewriteCond $1 !^(index\.php|robots\.txt)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L,QSA]
or maybe simply by removing the last line of your .htaccess.
Also you might need to change your /config/config.php to
$config['index_page'] = “”
The CI manual already gives you an (working) example on how to do it:
You can easily remove this file by using a .htaccess file with some
simple rules. Here is an example of
such a file, using the "negative"
method in which everything is
redirected except the specified items:
RewriteEngine on
RewriteCond $1 !^(index\.php|images|robots\.txt)
RewriteRule ^(.*)$ /index.php/$1 [L]
In the above example, any HTTP request other than those for
index.php, images, and robots.txt is
treated as a request for your
index.php file.
Always be sure to check the manual first. It is really good and gives you an easy answer most of the time.

Categories