tags:

views:

427

answers:

10

One of the ncie things about PHP is that if you do an include/require it works off the directory where the file is (or rather the URI of the request). That means that if you want to include further file you don't need to know from where the original script is running. All you need to know is where the current script is.

Now I want to load a text file and process it. file_get_contents() seems an obvioius way of loading it. The problem is I don't have that same luxury. I either need to specify the file path absolutely, which I don't want to do, or I have to know the location relative to the file that initiated the call, which I don't like either.

Require/include don't seem to work with non-PHP files and that would essentially echo the contents anyway (yes I know I could wrap that in an ob_start(), etc).

Suggestions?

+1  A: 

Define a constant with your desired path to the file, wherever you'd normally put configuration settings. Keeps it simple and customizable.

Mike
+1  A: 

For one, note that the "relative path" will be from wherever the first php script's path was that is currently running (regardless of what file may be doing the including"). Not being able to specify a relative path sounds odd...

Zachery Delafosse
That's the problem I was referring to: require/include use the current script's location (useful). The file_*() methods use the original script's location. That's what I want an elegant solution to.
cletus
A: 

Having to know the path of things is common in the website world. You can store a part of the path, like the beginning in a config variable, something like $config['include_dir']; Specifying the path of a file is as easy as saying include($_SERVER['DOCUMENT_ROOT'] . '/includes/myinclude.inc.php');

I don't know how else you would know what file to include.

tkotitan
Well in Java this isn't a problem because you can load resources via a classloader or, in a Web application, as a resource. I was hoping for something a little more elegant than a constant or even document root (which seems the best so far). File separator diffs Linux vs Windows for example.
cletus
A: 

You're going to need the absolute path to open a file. You can use realpath() convert a relative url path to the absolute path.

Kevin Tighe
A URL and a filesystem path are not the same.
Gumbo
Yes, I'm aware of that. Using realpath() should return the absolute filesystem path given a URL path (unless I'm misunderstanding the docs...can't play with php right now).
Kevin Tighe
URL paths and filesystem paths are not the same! They can be the same (relative from DOCUMENT_ROOT) but they don’t have to (see URL rewriting). And realpath() only returns the absolute path for paths that are valid paths in the filesystem and false otherwise.
Gumbo
Ok. I'm well aware that URL paths and filesystem paths are not the same. My mistake was in misunderstanding the realpath() fcn (I thought it was equivalent to Server.MapPath). Thanks for the clarification.
Kevin Tighe
+8  A: 

You can get the directory associated with the current file using

dirname(__FILE__)

So you could do something like this:

file_get_contents(dirname(__FILE__) . '/foo.txt')
Cd-MaN
+1  A: 

If I understand the documentation for file_get_contents correctly, you can just pass true as a second parameter and the include_path will be used. So, on my system

echo file_get_contents('doc/DB/doc/STATUS', true);

will echo the STATUS document from my PEAR module, because the /usr/share/pear is in my include_path. And while we're at it, I'm not convinced that include() or require() will work on relative paths either unless '.' is part of the include_path. I'll check on that.

Update: Ok, I checked. As it turns out, include() will always consider the current directory as well, no matter what the include_path says.

cg
According to the documentation you linked to, the second argument is a bunch of constants ored together (the flags being FILE_USE_INCLUDE_PATH, FILE_TEXT, and FILE_BINARY). Granted, two of the flags are mutually exclusive...
R. Bemrose
Well, I simplified a little: The second argument *will* be a "bunch of constants" in PHP 6 but I assume that cletus is using PHP 5 max. The second arg is/was bool up to and including PHP 5.
cg
A: 

Check out the $_SERVER properties. http://us2.php.net/manual/en/reserved.variables.server.php

You want

$_SERVER['DOCUMENT_ROOT'];
jacobangel
A: 

require/include are resolving the absolute path from both paths, the current script file’s and the initial executed script file’s:

Files for including are first looked for in each include_path entry relative to the current working directory, and then in the directory of current script. E.g. if your include_path is libraries, current working directory is /www/, you included include/a.php and there is include "b.php" in that file, b.php is first looked in /www/libraries/ and then in /www/include/. If filename begins with ./ or ../, it is looked only in the current working directory. — http://docs.php.net/include

But using absolute paths is better so PHP doesn’t need to “guess” which file is meant.

Gumbo
A: 

To answer your question it seems to me you'll need to write your own include equivalent to return file contents from any number of possible paths. Configure a series of paths in an array and have your function loop through it, use file_exists() and load file contents if the file is found.

Filesystem functions: http://us2.php.net/manual/en/ref.filesystem.php#73954

Also note there are php constants for filesystem path separator for example: DIRECTORY_SEPARATOR , however you don't really need it for portable file paths as forward slash "/" works on Windows.

Ps: A trick often used in Symfony to get absolute paths is:

$path = realpath(dirname(__FILE__)).'/whatever.txt';
faB
A: 

I don't know if you have control over the contents of the file that you're trying to load, but if you do, you could try using smarty templating engine (http://www.smarty.net/)

You'll need to put '{include file="relative/file/path.ext"}' in the files that you're trying to load, but smarty will at least take care of dealing with all the relative paths and confusion for you.

PS: Documentation for the include tag is here:http://www.smarty.net/manual/en/language.function.include.php

Ceilingfish