htaccess how to rewrite this url - php

How to rewrite this URL:
https://example.com/illustrations.php?category=cats&cat_id=1
to:
https://example.com/category/cats
also, how do I still preserve cat_id param?
I tried this but it does not work:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/?category/(.*?)/?$ /illustrations.php?category=$1 [L]

When I add this code and go to illustrations.php?category=cats it does not change the URL in the browserbar.
Yes, that is "correct".
The code you posted internally rewrites the URL /category/cats (which is the URL you should be linking to in your HTML source) back to the actual filesystem/URL path: /illustrations.php?category=cats. This is required in order to make the "pretty" URL /category/cats "work".
You can't change the URL structure using .htaccess only - if that is what you are implying. You do need to actually change the physical URLs in your HTML source.
You could implement an external redirect (not a rewrite) from /illustrations.php?category=cats to the canonical URL /category/cats using .htaccess, but note that this is only to benefit SEO (and third parties that might have already linked to the old URLs). This is a necessary additional step if you are changing an existing URL structure and SEO is a concern, but it is not part of the "working" of your site.
how do I still preserve cat_id param
You would need to include the value of the cat_id parameter in the URL. eg. /category/cats/1 (as #arkascha suggested in comments) or /category/1/cats - depending on which value is more important. I would put the more important value first, since URLs can be accidentally cropped when shared.
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/?category/(.*?)/?$ /illustrations.php?category=$1 [L]
This rule could be simplified. Filesystem checks are relatively expensive. It looks like you could remove both of these by making your regex more specific. eg. Could /category/1/cats ever map to a file? Do you need directories to be accessible? I would expect the answer to both those questions is "no".
I would also decide on whether to allow trailing slashes or not, rather than allowing both (as in your current rule). Strictly speaking this creates duplicate content (two URLs; same content), so requires additional steps to resolve. Your example URL(s) do not contain a trailing slash.
So, you could simplify your rules to the following in order to rewrite /category/1/cats (no trailing slash) to /illustrations.php?category=cats&cat_id=1
RewriteEngine On
RewriteRule ^category/(\d+)/([\w-]+)$ /illustrations.php?category=$2&cat_id=$1 [L]
This assumes cat_id can be 1 or more digits (0-9). And category is limited to the following characters: a-z, A-Z, 0-9, _ (underscore), - (hyphen).
With regex it is preferable to be as restrictive as possible. By omitting the dot (.) from the last path segment in the above rule it cannot match a physical file (assuming all your files have file extensions).

Related

htaccess - Force a slash to the end of a dynamic URL

I have a single index.php file in a /slug subdirectory and would like to load dynamic content based on the file path. Regardless of what the url is, the content should reference that index.php.
In my code below, the slash is not being added at the end of the url. For example, example.com/slug/33 should be displayed in the address bar as example.com/slug/33/.
I have the following .htaccess in /slug:
Options -Indexes
# Turn mod_rewrite on
RewriteEngine On
RewriteBase /
# Dynamic url
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /slug/index.php/?path=$1 [NC,L,QSA]
I tried adding a / between index.php and ?path=$ but I'm not getting the desired result. Is this even possible?
RewriteRule ^(.*)$ /slug/index.php/?path=$1 [NC,L,QSA]
Changing the substitution string here changes the target of your internal rewrite - it does nothing to change the visible URL. By adding a slash after index.php you are (unnecessarily) adding additional pathname information (path-info) to the resulting URL that your application receives.
To change the visible URL (to append the slash) you need to implement an external redirect. However, to confirm... you must already be linking to the correct canonical URL (ie. with a slash) in your internal links. Appending the slash to the URL in .htaccess is only if you have changed the URL and search engines or 3rd parties are still using the old non-canonical URL (without a trailing slash).
Since the .htaccess file is in the /slug subdirectory and you are rewriting to index.php in that subdirectory then you don't need to prefix the rewritten URL with /slug/. By default, a relative URL-path is relative to the directory that contains the .htaccess file. However, you must also remove the RewriteBase directive (or set this "correctly" to RewriteBase /slug).
To redirect to append a trailing slash you can add the following before the current rewrite:
# Append trailing slash if omitted
RewriteRule ^(.*(?:^|/)[^/.]+)$ /slug/$1/ [R=301,L]
This requires the /slug/ prefix on the substitution string (unless RewriteBase /slug is set), otherwise the external redirect will attempt to redirect to a file-path, which will "break".
The RewriteRule pattern ^(.*(?:^|/)[^/.]+)$ captures URL-paths that do not already end in a slash and do not contain a dot in the last path segment. This is to avoid matching URLs that already contain (what looks-like) a file extension, ie. your static resources (images, CSS, JS, etc.). This should avoid the need for a filesystem check (which are relatively expensive) - to check that the request does not already map to a file. Although, if you are not referencing any static resources with the /slug/ prefix in the URL then this can be simplified.
NB: You should first test with a 302 (temporary) redirect to avoid potential caching issues.
In context (with the use of RewriteBase):
Options -Indexes
# Turn mod_rewrite on
RewriteEngine On
RewriteBase /slug
# Append trailing slash if omitted
RewriteRule ^(.*(?:^|/)[^/.]+)$ $1/ [R=301,L]
# Dynamic url
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.+) index.php?path=$1 [QSA,L]
The use of RewriteBase avoids you having to specify /slug/ in the other directives.
In the regex ^(.*)$, the start-of-string (^) and end-of-string ($) anchors are superfluous. And you might as well change this to use the + quantifier, since you don't want to match the base directory anyway (saves two additional filesystem checks). The NC flag was also superfluous here.

URL rewrite in htaccess results is missing CSS and images

I need to remove a specific thing from my URL. Here I give a page name user.php and get it using $_GET['url'] then make it array using PHP explode() method.
https://www.example.com/index.php?url=user
I need to remove the index.php?url= like this,
https://www.example.com/user
Now I already use this code in .htaccess:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule index.php?url=$1 [QSA, L]
Almost everything was fine the user.php page was loaded perfectly. But when I was given a slash to my URL it stops showing CSS or other IMG directories. But when I delete the .htaccess file it works fine in this URL:
https://www.example.com/index.php?url=user/anonymous
But not works in this URL when I assign the .htaccess rules.
https://www.example.com/user/anonymous
Why my all stylesheet and other directory is not working perfectly?
RewriteRule index.php?url=$1 [QSA, L]
I think you have a couple of glaring typos(?) in your question that make this directive completely invalid... you are missing a RewriteRule pattern, so this won't actually match anything and the erroneous space in the flags argument is syntactically invalid, resulting in a 500 Internal Server Error response?!
The RewriteRule directive should be written like:
RewriteRule ^([\w/-]+)$ index.php?url=$1 [QSA,L]
^([\w/-]+)$ matches a URL-path containing any of the characters: a-z, A-Z, 0-9, _ (underscore), / (slash) and - (hyphen). I've excluded the dot, which is naturally part of real filenames.
You should also ensure that MultiViews is disabled, so that mod_negotiation doesn't rewrite the request before mod_rwrite - since your "extensionless" requests appear to map directly to filenames. eg. /user maps to /user.php. Place the following at the top of your .htaccess file:
Options -MultiViews
But when I was given a slash to my URL it stops showing CSS or other IMG directories.
This isn't a problem with .htaccess, but is caused by using relative client-side URLs to your static resources. When you request the URL /user/anonymous then the browser will resolve any relative URLs relative to /user/anonymous (not the document root - which is probably what you are expecting). If you have a relative URL to css/styles.css then the browser is naturally going to resolve this to /user/css/styles.css - which probably doesn't exist (and is likely getting rewritten to index.php - but that isn't the issue - the fact that it doesn't exist is the issue).
If you look at the network traffic (HTTP requests) in the browser, it should give you a clue as to what's going on.
You need to change your client-side URLs to use either root-relative (starting with a slash) or absolute (scheme + hostname) URLs to fix this issue.
See my answer to the following question on the Webmasters stack that explains this further:
https://webmasters.stackexchange.com/questions/86450/htaccess-rewrite-url-leads-to-missing-css
Use following code in your .htaccess file
RewriteEngine On
#main user page
RewriteRule ^user$ index.php?url=user [L]
#user detail page
RewriteRule ^user/([^/]*)$ index.php?url=$1 [L]

Is there a way to change a php URL with htaccess?

I am trying to change:
example.com/profile.php?id=abcdefgh
To simply:
example.com/abcdefgh
I searched here on StackOverflow and I understood that I need to do something with my .htaccess, I tried this code:
RewriteEngine On
RewriteRule ^([^/]*)$ /profile.php?id=$1 [L]
But it seems nothing changes, when type this URL (example.com/profile.php?id=abcdefgh) it doesn't get rewritten.
P.S. I don't know if the above code is right, i tried it because where I got it from had a similar problem to mine.
This should work.
Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)$ profile.php?id=$1 [QSA,L]
You should be requesting the "pretty" URL, ie. /abcdefgh. Your mod_rewrite directive in .htaccess then internally rewrites this to the "real" URL that actually handles the request (ie. /profile.php?id=$1). That directive is expecting a URL of the form /abcdefgh. However, in its current state I should expect a rewrite loop:
Request /abcdefgh
Request is rewritten to /profile.php?id=abcdefgh.
Processing starts over...
Request is rewritten to /profile.php?id=profile.php (because the regex ^([^/]*)$ matches the profile.php part of the rewritten URL.
GOTO #3
In this example you can avoid the rewrite loop by simply making the RewriteRule pattern (regex) more restrictive. eg. Include a dot (.) in the negated character class (assuming your new "pretty" URLs do not contain a dot).
For example:
RewriteRule ^([^/.]+)$ /profile.php?id=$1 [L]
You then need to actually change the URLs on your website to the new "pretty" URLs.
However, if you are currently getting a 404 then maybe this directive isn't being processed at all? Are .htaccess files enabled? Do you have other directives in your .htaccess file?
UPDATE: in the id the only characters allowed are A-Z
In that case you should be more specific with the regex and match just the characters required. This helps to avoid conflicts and avoids the need for filesystem checks (to some extent) - which are relatively "expensive". Note, however, that you've stated "A-Z" but your example includes lowercase letters. For the sake of argument I'll assume the id can include a-z and A-Z.
So, this now becomes:
RewriteRule ^([a-z]+)$ /profile.php?id=$1 [NC,L]
No other filesystem checks (preceding RewriteCond directives) are necessary. The NC (nocase) makes the regex match case-insensitive.
There is no need to check that the request does not map to a file (with a preceding condition), since the regex ^([a-z]+)$ could never match a file (that includes a file extension).
There is also no need to check that the request does not map to a directory, unless you are requesting directories in the document root directly - which is probably "unlikely". However, therein lies an inherent conflict with this URL structure. If you needed to be able to access a directory then those directory names become invalid IDs - so you would need other checks elsewhere in your system to ensure no IDs were generated that map to physical directories in the document root.

PATH_INFO stops working after internal redirect?

I have been at this for 45 minutes with no luck. I've found similar questions, but none that fully address my situation/problem.
I am trying to do a rewrite that does 2 things: 1) makes clean URL's (removes index.php) 2) hides a directory (my app is at web_root/dir, but I want it appear at domain.com/) 3) leaves $_SERVER('PATH_INFO') unchanged
So, for example. I want:
www.mydomain.com/some/path
to internally rewrite to:
www.mydomain.com/dir/index.php/some/path
This is what I have so far:
RewriteBase /dir/
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/dir.*$
# if I change the [L] to an [R], it all works
# but it obviously "dirties" my desired clean URL
RewriteRule ^(.*)$ /dir/index.php/$1 [L]
# not sure why I need this
RewriteRule ^/?$ /dir/
I should at: there is a proxy at my institution, but I don't think its causing the problem.
Using PHP 5.3 and FastCGI
What's the secret to keep PATH_INFO working with an internal redirect?
Hmmm! Trailing path stuff.
So this path info is being lost in the rewrites?
Have you tried doing the www.mydomain.com/some/path -> www.mydomain.com/dir/index.php/some/path rewrite not in the per-directory context, but earlier in the server's URL handling, like VirtualHost?
I'm thinking that doing it on URL's cannot lose the path info because it is not know at that time which part is physical path and which is trailing junk. Not util the URL is mapped to a file. If you produce the
Heck, how about a simple Alias? Aliases are often used to map abstract URL locations to concrete places in the filesystem for applications. I have a whole bunch of them; here is one:
Alias /cgit/txr /cgit/cgit.cgi/txr
When people access www.kylheku.com/cgit/txr it redirects internally to www.kylheku.com/cgit/cgit.cgi/txr. That URL will work too, but the former one is nicer, because it doesn't have three repetitions of the string cgi.
Needless to say, the alias doesn't lose any trailing stuff from the URL.

PHP all GET parameters with mod_rewrite

I am designing my application. And I should make the next things. All GET parameters (?var=value) with help of mod_rewrite should be transform to the /var/value. How can I do this? I have only 1 .php file (index.php), because I am usign the FrontController pattern. Can you help me with this mod_rewrite rules?Sorry for my english. Thank you in advance.
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.
The following code in your .htaccess will rewrite your URL from eg. /api?other=parameters&added=true to /?api=true&other=parameters&added=true
RewriteRule ^api/ /index.php?api=true&%{QUERY_STRING} [L]
.htaccess
RewriteEngine On
# generic: ?var=value
# you can retrieve /something by looking at $_GET['something']
RewriteRule ^(.+)$ /?var=$1
# but depending on your current links, you might
# need to map everything out. Examples:
# /users/1
# to: ?p=users&userId=1
RewriteRule ^users/([0-9]+)$ /?p=users&userId=$1
# /articles/123/asc
# to: ?p=articles&show=123&sort=asc
RewriteRule ^articles/([0-9]+)/(asc|desc)$ /?p=articles&show=$1&sort=$2
# you can add /? at the end to make a trailing slash work as well:
# /something or /something/
# to: ?var=something
RewriteRule ^(.+)/?$ /?var=$1
The first part is the URL that is received. The second part the rewritten URL which you can read out using $_GET. Everything between ( and ) is seen as a variable. The first will be $1, the second $2. That way you can determine exactly where the variables should go in the rewritten URL, and thereby know how to retrieve them.
You can keep it very general and allow "everything" by using (.+). This simply means: one or more (the +) of any character (the .). Or be more specific and e.g. only allow digits: [0-9]+ (one or more characters in the range 0 through 9). You can find a lot more information on regular expressions on http://www.regular-expressions.info/. And this is a good site to test them: http://gskinner.com/RegExr/.
AFAIK mod_rewrite doesn't deal with parameters after the question mark — regexp end-of-line for rewrite rules matches the end of path before the '?'. So, you're pretty much limited to passing the parameters through, or dropping them altogether upon rewriting.

Categories