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

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.

Related

htaccess how to rewrite this url

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).

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]

.htaccess url rewrite behavior being overwritten if filename minus ext. same as url

I'm trying to tidy up the URLs and remove the .php extensions from them and such. I'm in the base folder for the website, so there are no parent .htaccess files that could be taking priority or anything. Here's my htaccess code.
RewriteEngine On
RewriteRule ^give/?$ give.php [NC,L]
This part gives no real problems, because whatever behavior is overwriting it behaves the same way. But when I add in this other line so it will account for url variables,
RewriteRule ^give/([0-9]+)/?$ give.php?step=$1 [NC,L]
It completely ignores it. However, if I rename give.php to anything else, so it doesn't match the url, it works. For example, using given.php causes it to heed the .htaccess rules. I've never run across this issue before. Is there some server setting I can change so I don't have to give my files odd names?
Also note, I tried changing that first line to redirect to another file, but without changing the actual file name give.php. It ignored my redirect and still loaded the give.php file.
Edit: I've tried changing the order of the 2 rules, I've tried commenting both one rule, then the other to see if they are conflicting with eachother. The best I can figure, the server has some sort of default behavior that directs /give/ to /give.php if no directory of /give/ exists. Because even if I remove both rules, going to /give/ still redirects me to /give.php. Only when I change the filename to given.php will it break that default behavior. I also tried setting the simpler rule to this:
RewriteRule ^give/?$ resources.php [NC,L]
And as long as the file give.php existed, it still redirected to give.php. If I removed give.php or changed its name, going to /give would then redirect to resources.php
You may have a conflict with the MultiViews option of mod_negotiation.
Your request may not be hitting the RewriteRule at all, and is instead being handled by the give.php because of mod_negotiation. From the docs:
... if the server receives a request for /some/dir/foo, if /some/dir has MultiViews enabled, and /some/dir/foo does not exist, then the server reads the directory looking for files named foo.*, and effectively fakes up a type map which names all those files, assigning them the same media types and content-encodings it would have if the client had asked for one of them by name. It then chooses the best match to the client's requirements.
Try adding this to your .htaccess and see if things change:
Options -MultiViews
So some changes, first I would try some file conditions before the rule. Second the params as you wrote are only for numbers, and last QSA for more query.
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^give/(.+)$ give.php?step=$1 [QSA, L]

htaccess rewritebase in subdirectories

in a project i have .htaccess files in many Subdirectories.
here is an example Structure:
project/.htaccess
project/admin/.htaccess
project/admin/pdf/.htaccess
in the last one i successfully use the following:
Options +FollowSymLinks
RewriteEngine On
RewriteBase /project/admin/pdf/
RewriteRule ^([pdf\.actions]+)$ pdf.out.actions.php [QSA]
this works fine, if the Project Folder is placed directly in the root directory.
all other subdirs have same htaccess logic, now if the user needs to put the project in any other directory rather than root, he/she has to change all RewriteBase in all htaccess Files in all subdirectories of the project.
my question: how to rewrite my htaccess content, so i get the same result as mentioned above but with "dynamic" base or without Base...etc?
i tried somany things without success.
i removed the line RewriteBase /project/admin/pdf/ and tested it, i get site not found...etc!
any Idea?
thanks
You can try adding something like this to the top of your rules:
RewriteCond %{ENV:URI} ^$
RewriteRule ^(.*)$ - [ENV=URI:$1]
RewriteCond %{ENV:BASE} ^$
RewriteCond %{ENV:URI}::%{REQUEST_URI} ^(.*)::(.*?)\1$
RewriteRule ^ - [ENV=BASE:%2]
And then instead of using RewriteBase, you'll have to include the BASE environment variable everywhere. For example:
RewriteRule ^([pdf\.actions]+)$ %{ENV:BASE}/pdf.out.actions.php [QSA]
The conditions do a couple of things, but both rules change nothing in the URI and only add environment variables.
The first condition is necessary because it grabs the requested URI before anything is done to it, and stores it. This is important because the (.*) grouping in the rule has the base stripped off. We want the unaltered URI with the base stripped off. So the URI environment variable is the URI with the base stripped off.
The second condition is necessary because it compares the URI environment variable with the %{REQUEST_URI}, which is the entire URI, including the base. That comparison yields us the part that was stripped off, or the base, and that'll be stored in the BASE environment variable.
The conditions which match against ^$ is simply ensuring that this is the first time through the rules (meaning neither of the environment variables have been set). The rewrite engine will loop so we only want to set these the first time.
EDIT: actually, now that I'm looking at it, you could probably leave the first one out:
RewriteCond %{ENV:BASE} ^$
RewriteCond $1::%{REQUEST_URI} ^(.*)::(.*?)\1$
RewriteRule ^(.*)$ - [ENV=BASE:%2]
Using the $1 backreference which matches the rule, noting that the rule itself is partly evaluated (pattern applied) before any of the conditions are checked.

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