Jump to content

Difficulty setting include path from .htaccess


jhsachs

Recommended Posts

In PHP 5.2.5, using Apache 2.2.17, I'm trying to set the include path through the .htaccess file. It's not working, and I don't see the reason.

 

There was already a .htaccess file in the document root directory. I added this line to it:

[pre]  php_value include_path "/"[/pre] This should make PHP search for includes in the document root directory, no matter where this script was loaded from.

 

My includes actually take this form:

[pre]    include "include/constants.php";[/pre] ...which was originally intended to load ./include/constants.php (relative to the directory containing the script). After I have set include_path, this statement should load /include/constants.php instead.

 

If I call get_include_path, I get "/". It appears that the include path is being set properly. But the include statement continues to load a file relative to the directory that contains the script. (I determined this by storing a different version of the included file in every directory, and figuring out which version got loaded.)

 

I also tried setting include_path to "/xxx" (a non-existent path). Then get_include_path returns "/xxx". The include shouldn't work at all; it does, still loading relative to the directory that contains the script.

 

It seems to me that there must be something in PHP's settings that is making it ignore the value of include_path, but I haven't found it. Does anyone know what is going on here?

Link to comment
Share on other sites

It seems to me that there must be something in PHP's settings that is making it ignore the value of include_path, but I haven't found it

The manual will help to clear that up

If the file isn't found in the include_path' date=' include() will finally check in the calling script's [b']own directory[/b] and the current working directory before failing.

 

 

I added this line to it:

  php_value include_path "/"

This should make PHP search for includes in the document root directory,

A / in PHP does not mean the document root. It actually means the root of the file system. There is no generic symbol in PHP which represents the document root, however there is the $_SERVER['DOCUMENT_ROOT'] superglobal, which in most cases will be set to your document root.

 

Rather than set your include_path within your .htaccess you can set it within your script. Example snippet

$baseDirectory = $_SERVER['DOCUMENT_ROOT']
ini_set('include_path', $baseDirectory  . PATH_SEPARATOR . ini_get('include_path'));

That snippet will add your document root to the include_path dynamically.

Link to comment
Share on other sites

The key to this problem was the fact that include_path is a file path, not a document path. Thank you for pointing that out.

 

The other complication was that I was using a relative pathname in include. To quote the next part of the page you cited:

 

If a path is defined -- whether absolute (starting with a drive letter or \ on Windows, or / on Unix/Linux systems) or relative to the current directory (starting with . or ..) -- the include_path will be ignored altogether.

 

I thought that might be the problem, but because two things were wrong, the test I devised yielded a false negative result.

 

One other comment: this is not a case where setting include_path in the script would be a good solution, because I'd have to set it in several dozen scripts. .htaccess is by far the better solution.

 

 

Link to comment
Share on other sites

My problems with this are not quite over. My development system runs Windows; my client's servers run Linux. Something is happening in Linux that I don't understand.

 

In Windows, I ran a script from the document root which displayed the value returned by getcwd(). It displayed the pathname (in the file system) of the directory from which the script was run.

 

I assumed that the same technique would work in Linux, but it didn't. The value I got looked reasonable; it was in the form /home/content/t/o/n/accountname/html (where "accountname" represents a string that is probably an internal name of the hosting account). I put a .htaccess file in the document root with this contents:

 

  php_value include_path "/home/content/t/o/n/tonitt2010/html/include"

 

When I tried to run a script with this setting, I got an "Internal Server Error" message. I got the same when I set include_path to the value returned by getcwd() alone, without the "/include" suffix.

 

I looked at the value pf $_SERVER['SCRIPT_FILENAME'] on the server, and it was

 

  /home/content/t/o/n/tonitt2010/html/cwd.php

 

(...where cwd.php is the name of the script). That agrees with getcwd(), which is no help!

 

Apparently, in Linux, the cwd of a script run from the document root is not the document root's file system pathname. How can I find out what it is?

Link to comment
Share on other sites

Or use the current directory

for example if

.htaccess is in a folder called php and the folder you wish to include is in php/classes

then

php_value include_path ./classes

should work

or even go back a directoy

php_value include_path ./../classes

 

either way create a test.php file

echo get_include_path();
echo "<br />\n";
echo ini_get('include_path');

and see what you get

 

simple tests to start with

 

also my biggest screw up is the case sensitive, ie calling MyClass.php in Windows works fine.. but fails in linux because the file was called myClass.php

 

hope that helps

Link to comment
Share on other sites

The "Internal Server Error" message has nothing to do with the cwd. The error message is triggered due to the config in your .htaccess file. The php_* flag directives within the .htaccess file will only work if PHP is configured as an Apache module. Your hosting company most probably does not run PHP as an Apache module.

 

This is explained within the manual here

http://php.net/manual/en/configuration.changes.php

 

You maybe able to use custom ini file. Ask your host if they provide this feature

http://www.php.net/manual/en/configuration.file.per-user.php

Link to comment
Share on other sites

This has probably been said, but setting the include path in the htaccess file rather than the php code itself will be annoying for anyone else trying to debug issues in your script. It's much harder to trace, and simply removing or changing the htaccess file could break your entire script.

Link to comment
Share on other sites

Hmm... very puzzling results.

 

I tried this first in Windows. .htaccess is in the document root, and include_path refers to "./include".

 

It worked when I loaded a script from the root directory. When I loaded a script from a subdirectory, it couldn't find the include file.

 

I copied the include directory into the subdirectory containing the script. Then the script worked.

 

I deleted the copy of the include directory from the subdirectory and changed .htaccess's definition of include_path to "../include". Then I could load a script from the root directory or from a subdirectory.

 

So, here's what appears to be happening: the relative pathname in .htaccess is interpreted relative to the directory from which the script is loaded, not the directory from which .htaccess was read! However, if a part of the relative pathname refers to the "parent" of the document root, that part is ignored; thus "../include" refers to a child directory when a script is loaded from the root, but to a sibling directory when a script is loaded from below the root.

 

I believe I can make this work if I put an appropriate setting for include_path in a .htaccess file in each directory where scripts live. That would be less elegant than putting it in a root-level file only, but it would still be quite manageable.

 

But now, on to the Linux server. It doesn't work at all. If I try to set include_path in a .htaccess file, I get the "Internal Server Error" again.  And I have no idea why.

Link to comment
Share on other sites

Later -- message #5 was posted while I was replying to #4, and it explains what is happening completely, and (if I know how the hosting company thinks) accurately. I'll check on the custom ini file; that seems like the only possible solution remaining.

Link to comment
Share on other sites

Does PHP happen to be running as CGI?

 

wildteen88 already solved this for you.

 

Use absolute paths if you're having issues with sub-directories. Relative paths have their place, but when you start using sub-folders, relative paths generally break.

 

Your current solution is hacked together anyways. Use this issue as an excuse to define a configuration variable with a path to your include folder, and use that variable on includes, or define the include_path absolutely at the top of each of your pages. This will make things much easier when it comes to debugging errors.

Link to comment
Share on other sites

xyph, there's somewhat more to this than meets the eye. It didn't seem relevant before, but since you seem to have issues with relative pathnames, it's relevant now.

 

Absolute pathnames have their place, but if you need to store several applications in one document space, absolute pathnames become very complex and fragile. In other words... they break.

 

Your suggestion that I "use this issue as an excuse to define a configuration variable" is puzzling, since this whole topic is about my attempt to do something very similar. The tools that PHP provides for defining configuration variables are generally the same as the ones for defining settings like include_path. We've established that the host does not allow me to do that in .htaccess, and since my last post I've found that they don't allow it in php.ini either. Is there another place to do it? Telling me where, if so, would be helpful.

Link to comment
Share on other sites

I'm just strong against the idea of needing Apache .htaccess, or a custom php.ini to run a script... especially when it's not needed.

 

If it's inside the PHP script itself, it also makes debugging much easier. That's another reason I like to use absolute paths - I can echo the absolute path to the file if things are going wrong. It's hard to actually tell what file you're trying to include with '../../path/file.php' especially when includes are in sub-directories of sub-directories.

 

I don't understand what you mean by several apps in one document space causes absolute paths to become fragile - how so?

 

Just use

http://php.net/manual/en/function.set-include-path.php

At the top of your script.

Link to comment
Share on other sites

I don't understand what you mean by several apps in one document space causes absolute paths to become fragile - how so?

 

OK, here's an example that I will have to deal with over the weekend.

 

I've got an application that I run for a client. Let's say it's in the document space on my development system at localhost/gorp. (The names are changed to confuse the innocent.)

 

I need to create a second copy of the application to test a proposed change that may or may not be adopted. To do that without abandoning my ability to support the version now in QA on my host's server, I need to put it somewhere else in my document space. I might put it in localhost/gorp2, or in localhost/gorp/x. Wherever I put it, I need to make it refer to its own set of include files. How do I do that?

 

If I use absolute pathnames in include, I can do it by editing every script (there are dozens of them). If I use relative pathnames, I can do it by... well, doing nothing. When I copy the application's directory, the problem takes care of itself.

 

I could make things somewhat better by storing a wrapper for each include file in the application's main directory. The scripts could include the wrappers with no pathname, and each wrapper could include a real include file with an absolute pathname. Then I'd only have to change a half dozen wrappers instead of several dozen scripts. But why should I go to the trouble to do that when using relative pathnames eliminates the problem completely?

 

Now suppose we decide to adopt the change. At some point -- on my development system, during the push to QA, or during the push to production -- I have to move the application back to /gorp. If I'm using relative pathnames, I just move it. If I'm using absolute pathnames, I have to undo whatever I did to move the application in the first place. And, depending on when the decision is made, I may have to drag the client through an extra cycle of QA just to confirm that the changes I made did not create problems.

 

set_include_path doesn't affect this argument at all. It only affects the change that has to be made in dozens of scripts or in a half-dozen wrapper files: add a call to set_include_path instead of change an absolute pathname.

 

Now that I've expounded on the advantages of using relative pathnames, I'm curious: what are the advantages of using absolute ones?

Link to comment
Share on other sites

Simple, you use a configuration file.

 

$script_root = '/home/apache/www/script_name/'

 

Just make sure your config file is loaded in all pages that aren't includes. You can then call

require( $script_root . 'path/to/include' )

 

This way, if you have an include in say, script_name/folder1/subfolder/ that has to include a file in script_name/folder2/ you don't have to use something ugly like ../../folder2/. The includes stay simple and identical no matter how complex your folder structure gets. Including script/class/sql.php would be the same code, whether loaded in script/some/folders/deep/ or script/simple/. Again, it's also way easier to debug an absolute path than it is relative paths.

 

You could even define a function, if you wanted to handle errors a certain way.

 

function include_absolute( $path ) {
  $root = '/home/apache/www/script_name/';
  if( !file_exists( $root . $path ) ) return FALSE;
  include( $root. $path );
}

 

You only need to change one line to change the root folder for your entire script.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.