Is PHP allowed to modify .htaccess file in current folder? - php

I have a PHP web app located on shared hosting.
My goal is to modify .htaccess file from PHP code when the PHP page is running.
I need that .htaccess to insert a couple of mod_rewrite lines into it.
The problem is that on Windows+Apache I can dynamically modify .htaccess file
but the same code on Linux reports a problem when I try to access this file in any
way (copy or fopen):
"failed to open stream: Permission denied"
I have given .htaccess file 777 permissions - still no result.
WHat prevents me from doing this? How can I develop a workaround?
P.S.
My initial goal was to be able to add a new RewriteRule into .htaccess that maps a
newly added category_id with new category_name.
If it wasn't shared hosting, I would use something like RewriteMap (in main Apache config) and would be able to access the map file.
This is the first real limitation I've been unable to tackle with PHP+Apache, but I hope it's circuventable too.

This seems like an overly-complex solution to just having a general "load category" page that takes the category name from the URL and loads the corresponding ID.
For example, if the URL is:
http://yoursite.com/category/programming
I would remap that to something like:
http://yoursite.com/category.php?name=programming

I want to suggest something else that also works. Instead of writing a rule for every 'special' url, why not use one for all?
I found it a whole lot easier to use what wordpress uses: every url is redirected to the index.
All you have to do is, set up the index file, read in the directory that was loaded (perhaps using $_SERVER['URI_REQUEST']), and deal with it.
add to .htaccess this:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
Thanks to that chunck you have a system somewhat unlimited at your disposal. If you ever feel like renaming you categrory url, or add another special case, it's already ready!

You only need a small set of rewrite rules. To do what Chad suggests:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^/category/.*$ category.php [QSA]
Thus, anytime someone navigates to /category/category_id, the request will be directed to category.php, which will be handed the /category/ URI in $_SERVER['REQUEST_URI'], from which you can easily get the category ID, and you don't need to bother with editing the .htaccess file every time you add a category.

While I agree with the above comments, it can definitely be done. PHP apps like WordPress do exactly this based on changes made on the settings page. It should be as simple as writing the file out however the parent directory NEEDS to have permission for the web server user to write to it.
If it isn't working for you the trick will be making the parent directory either 777 or 775 and having the group set to whatever group Apache runs under (usually "apache" or "www" or something similar)
Adam (commented on your question) is quite correct though, some other security layer on your server might be preventing you from doing this, and this is probably a good indication that you might be approaching the problem the wrong way.

I agree with Chad Birch. In case you can't be dissuaded, though, in your situation I would first be looking for parent directories with locked-down permissions.
FYI, one of the reasons that rewriting the .htaccess is a bad idea is that any requests that come in while the .htaccess is being rewritten will not have any of your redirects applied.

Related

.htaccess Completely rewrite URL to show file in a folder, rather than page in root

So, I have the current file structure:
ROOT
-> /public
-> /user_views
user_handle.php
user_profile.php
user_feed.php
user_settings.php
.htaccess
As you see, the folder user_views contains a few of the possible views that the client could want to look at. What I am wanting, is for clients that insert the URL http://example.com/user/ to be directed to the page user_handle.php. This handle would act as a root file for all /user/ pages, and it would accordingly split into those pages through numerous $_GET requests.
So far, I have the following .htaccess, but it's not working...
RewriteRule ^user/ user_views/user_handle.php [L]
What could I do to get this to work, so that the url http://example.com/user redirects to the user_handle file in the user_views folder?
Thanks!
I'm not sure I fully understand your question, but it seems you would like to make user_handle.php located under public/user_views act as a "router" for the rest of you PHP files and have all requests to /user/ (e.g. /user/?page=1) be processed by user_handle.php.
If that's the case, your rule seems legit. The only thing I noticed (I might be wrong) is that your .htaccess is located outside the public folder. In that's the case, you need to include 'public/' as part of your rule.
I recreated the folder/file structure you described and it has worked for me using the following .htaccess:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^user/ public/user_views/user_handle.php [L]
</IfModule>
Slight chance this is the problem, but you also might want to double check that mod_rewrite, which is the rule-based rewriting engine is enabled on your server/local environment. It should show up under 'Loaded modules' when you call phpinfo() in any PHP file.
Hope this helps.

Mapping URL into custom files

I want to map URL in my localhost XAMPP into custom files.
For example:
localhost/index.php --> d:\xampp\htdocs\index.php (default)
localhost/normal/data.php --> d:\xampp\htdocs\normal\data.php (default)
localhost/view/userinfo.php --> d:\xampp\htdocs\view.php?p=userinfo (custom)
localhost/view/welcome.php --> d:\xampp\htdocs\view.php?p=welcome (custom)
So, basically, all URL that goes into inside view path will be mapped to view.php files with the filename.php (minus the .php) as its query parameter. There's actually no physical folder view, and no physical files userinfo.php and welcome.php inside the folder.
The reason that I need to do this is that so I can pass all the pages that viewing data into an "application frame" that will wrap the page with header, menu, and footer, and I don't need to give header, menu, and footer call in each page. I might have the actual files userinfo.php that I can $include_once, or I might not (I can just generate it from within the view.php), but hey, that's one of the power of this kind of framework, right? And, if someday I need to change this structure, I can change it from just within one file (view.php), not all.
Can I do this in PHP and XAMPP? How? I've noticed that some website seems to used this practice (URL which have no actual files or even path at all), but when I try to read tutorial for it, I got confused.
URL mapping in PHP?
The accepted answer listed 3 links to learn about URL rewriting. Mostly they're written for Apache in Linux, and mostly they pull all the possible scenario and configuration that I got confused which one I really need with all those long documents and technical jargon. I need just the practical step of my specific problem, and then, I will be able to start from there to explore myself if I have more advanced needs. Please help.
if you do want to go down the mod rewrite route adding the following to an .htaccess file in the site root should do it. You will need to make sure mod rewrite is on for XAMPP and I can't help you there I'm afraid. As you can see it rewrites the url, not the windows filename - so it would work on any OS.
The ([a-z]*) means it will take any filename.php with lowercase letters and redirect to /view.php?p=$1 where the $1 will be replaced by filename.
the [L,R] (L means last rule so stop processing if any more are reached, and the R means redirect (it will change the url in the browser). Use P instead to reverse Proxy (the user will still see the url they requested but the server will serve the correct file) - This will require mod_proxy as well.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_URI} ^view/
RewriteRule ^view/([a-z]*).php$ /view.php?p=$1 [L,R]
</IfModule>
XAMPP uses apache so the rewrites would work the same in Windows as they do in Linux. You could place a .htaccess in the site root directory with some rewrite rules.
However, using PHP
in d:\xampp\htdocs\view\userinfo.php you could include the line
<?php
header('Location: http://localhost/view.php?p=userinfo');
?>
But this must be before any thing is echoed to the screen (even whitespace).
You can use the Apache module mod_rewrite to edit requests before they hit PHP. You want to put something like the following in a .htaccess file in your htdocs directory.
RewriteEngine on
RewriteCond %{REQUEST_URI} ^view/
RewriteRule ^view/(.*)\.php.*$ view.php?p=$1 [L,QSA]
QSA means Query String Append. This means that if there are any GET parameters set on the original request they will be appended to the end of the new request too.
Note that this assumes that Apache is configured with AllowOverride enabled and the mod_rewrite module loaded.

mod_rewrite bug and permission denied

i'm using mod_rewrite to rewrite sites like "url.com/foo" to "url.com/index.php?site=foo".
The Code:
RewriteEngine On
RewriteBase /
RewriteRule ^([0-9a-zA-Z]+)$ index.php?site=$1
If i click on a link with href="/foo" it will give me
http://url.com/foo/?site=foo
The code works at other sites on the same V-Server, i have Boilerplate installed, BUT i dont use the .htaccess of it right now to fix the mod_rewrite, so it cant be a boilerplate issue, or?
I also tried the following code:
RewriteEngine On
RewriteBase /
RewriteRule ^(.*)$ index.php?site=$1
That code, at least, rewrites to index.php?site=foo
BUT it still creates url's like the upper example with the unnecessary folder between.
Edit: to make sure everyone understands the overall idea:
The files are based in http://url.com (index.php, .htaccess) , so i set the RewriteBase to "/".
It should take links like
http://url.com/foo
and rewrite them to
http://url.com/index.php?site=foo
there are no folders included.
I solved it, damn i'm so stupid ;)
I have a folder called url.com/foo/ and the link im redirecting is url.com/foo to url.com/index.php?site=foo so it is always trying to get into that folder. Since i renamed the folder it is working very well.
I have been getting a similar error message on RewriteRule
pcfg_openfile: unable to check htaccess file, ensure it is readable
I also have the subfolder name similar to the redirected URL part but renaming it did not solve the problem (as suggested by Chris).
After multiple attempts, the problem was solved by updating the subfolder permissions to 755 (using cPanel folder permissions dialog) :
User: Read, Write, Execute
Group: Read, Execute
World: Read, Execute
PS: I am not sure if renaming the subfolder was actually required for this scenario since before and after the rename, error message was same.

Hide PHP from user

Is there a way to hide the fact that I'm using PHP from my users? I wanted to do this for two reasons:
1) So the links in the address bar look cleaner (like here on stackoverflow)
2) To prevent potential hackers of knowing immediately what to look for
Is point 2 even realistic or will a hacker know what I'm using anyway? I'm using nginx with php5-fpm.
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php
http://eisabainyo.net/weblog/2007/08/19/removing-file-extension-via-htaccess/
In addition to the mod_rewrite changes, also set expose_php to false: http://www.php.net/manual/en/ini.core.php#ini.expose-php
The above (or perhaps below) answers give info on the technical side, let me answer the moral side:
Don't do it. Point 2 is completely invalid, if someone wants to do harm, this won't stop it. Proper security checks however will. Point 1 is meagerly valid, no one types links anymore these days.
The best way to keep your PHP hidden from public access is to structure your folders accordingly. Best practice is to keep your library and application files at least one level up from the public folder, like:
/application
// application files
/library
// library and vendor files
/public (aka public_html, htdocs etc)
index.php
.htaccess
/css
/images
/js
Use htaccess and mod_rewrite to route requests to the index.php file, which will then dispatch the request to the application.
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php
This way, you only have a single php file publicly accessible, which merely includes other files not available via any url
1) So the links in the address bar look cleaner (like here on stackoverflow)
mmm. OK
2) To prevent potential hackers of knowing immediately what to look for
Security by obscurity. Trust me, that's not going to slow them down much.
A very valid reason for doing this, however, is so that your website is not tie to a particular development language.
I see several people have already mentioned mod_rewrite. It's one solution - but it's a very complex tool to master. Also, be very careful about embedding CGI variables in the path of the URL - you can quickly break stuff.
A simple solution would be to implement every entry-point php script (i.e. anything with is not an include/require file) as 'index.php' and reference it by it's directory.
Alternatively pick your own file extension and replace the references to .php in the config with your extension.

How to understand PHP's URL parsing/routing?

I just inherited a website built in PHP. The main page of www.mysite.com has a href to www.mysite.com/index/35.html somewhere in the page. In the site's root directory and its children there is no document 35.html.
The number 35 is actually an id found in a DB which also holds the html contents of the page.
If I load URL: www.mysite.com/index.php?id=35 the same page loads.
How does PHP know how to automatically convert
/index/35.html
to
/index.php?id=35
EDIT
Based on the answers, I have found a .htaccess file containing rewrite instructions that would explain the functionality.
However, IIS doesn't seem to (or is not configured) know how to use this. (probably because this is an Apache feature?)
So this begs the following question: Is there a way to configure IIS to work with this?
it will be done usign URL Rewriting using .htaccess - should be in the webroot.
It may look something like:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]
May have other bits, but what this basically tells apache is to send anything that DOES NOT physically exist to index.php
It doesn't. There is a mod_rewrite rule that rewrites from /index/foo to /index.php?id=foo, either in a .htaccess file somewhere or in the httpd configuration itself.
RewriteEngine On
RewriteRule ^index/([\d]+)\.html /index.php?id=$1 [NC,L]
This is off the top of my head. Any browsers trying to load an address starting with index/ has any number ending in .html will be internally redirected to index.php?id= whatever the number is.
Edit: Just saw that your working on IIS. This probably won't work for you. Sorry.
I think you will be using .htaccess to redirect all requests to index.php. From there You can pass the query string a routing class, which will parse the url and identify the unique ids.
In this case we can say like, your routing class will parse the request /index/35.html to indexController, indexAction, id=35. now you can pass this id to the model to get corresponding page contents
NB : Here I a am assuming you are using mvc pattern. Anyway it can be treated in your own way, with the concept remaining the same. Hope this make sence.

Categories