Since I develop on localhost but deploy elsewhere, and since I don't want to have to force my sites to be under a Windows partition's root directory (currently F:\web_dev\htdocs), code like this:
require_once($_SERVER['DOCUMENT_ROOT'] . '/projXY/database/database_common.php');
OdbcExec($sql); // defined in the file above
causes Netbeans to issue a "Warning: unknown function".
Now, I could get round this by using a directory structure like :
F:\project_1
F:\project_2
instead of
F:\web_dev_htdocs\project_1
F:\web_dev_htdocs\project_2
and then using
require_once('/database/database_common.php');
BUT that imposes constraints on where the end-user an install my site.
Simplest by far would be to tell NetBeans which local directory corresponds to $_SERVER['DOCUMENT_ROOT'], but I can't find a configuration option for that. I am sure this is a common problem. Any suggestions?
Update: NetbBeans v7.0.1
Simply add the /path/to/projXY/database/ directory to your project's include path. Netbeans will then pick up the files there and use them as code references.
http://netbeans.org/kb/docs/php/project-setup.html#phpIncludePath
Addendum
Relying on $_SERVER['DOCUMENT_ROOT'] is generally a bad idea. For one, it eliminates the ability to run parts of your application via the console / command line.
You should instead either use configurable, absolute paths to shared libraries or do as in Brandon's answer and use a relative path from __DIR__ (PHP 5.3) or dirname(__FILE__)
Not sure if this is what you are looking for or not, but I commonly use:
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'file.php');
Related
How do you guys handle the path of files to work either localhost and server without changing the variables?
For example, I have this:
$path = realpath($_SERVER["DOCUMENT_ROOT"]);
returns C:\xampp\htdocs
This would probably work on a online server, but doesn't work on a localhost, because I need to set the folder name of my project.
So, in my 100 files (for example) I would have to change to whenever I want to work in localhost:
$path = realpath($_SERVER["DOCUMENT_ROOT"]) . "/myproject/";
So I thought about a variable with a certain condition which would understand if it's localhost or server.
$path = (strpos(realpath($_SERVER["DOCUMENT_ROOT"]), "xampp") == false ? realpath($_SERVER["DOCUMENT_ROOT"]) : realpath($_SERVER["DOCUMENT_ROOT"]) . '/myproject');
And all I had to do:
<link href="<?php echo $path . '/css/bootstrap/bootstrap.css';?>" rel="stylesheet" type="text/css"/>
The above code does not work (at least in localhost, I haven't tried in a real server), because I get the following errors on console:
Not allowed to load local resource:
file:///C:/xampp/htdocs/myproject/css/bootstrap/bootstrap.css
Which I understand, so I have tried to change my $path variable to:
$path = (strpos(realpath($_SERVER["DOCUMENT_ROOT"]), "xampp") == false ? realpath($_SERVER["DOCUMENT_ROOT"]) : 'http://localhost/myproject');
And I get in the console:
Warning: require_once(): http:// wrapper is disabled in the server configuration by allow_url_include=0 in C:\xampp\htdocs\myproject\backend\orders.php on line 6
Is there any better way?
The most straightforward approach is to just create a local site with the same folder structure than your live site. I suspect you're doing it that way only because you aren't aware of Apache virtual hosts.
In any case, it's always practical to abstract paths as much as possible and constants are always a good choice. I typically define two:
WEB_ROOT to be used in URLs (in my case it's often just /)
FS_ROOT to be used in file system paths
You can feed them with hard-coded values in a settings file or dynamically calculating them. FS_ROOT is trivial to populate: you can use __DIR__ or dirname(__FILE__) for very old PHP versions.
Surprisingly, $_SERVER["DOCUMENT_ROOT"] does not provide accurate info in all hosting services.
Edit #1: I've appreciated a little base misconception in some of your comments so I'll try to shed some light on it.
Finding stuff on the Internet is not the same as finding stuff in your hard disc. The former makes use of URLs:
http://example.com/blog/latest-news?page=3
The latter makes use of file system paths:
/home/alice/pictures/kitten.jpg
C:\Users\Bob\Desktop\Shopping list.txt
In a web based PHP application you normally need to use both and you need to know the difference. You cannot use a URL to grab random files from a computer (not even yours) and you cannot use a file system path to grab anything from someone else's computer. This:
<link rel='stylesheet' href='C:\xampp\htdocs\myproject/css/bootstrap/bootstrap.css'/>
... is plain wrong because your linking a public resource with a file system path that will only work in your PC.
And one more thing... Most operating systems have adopted the convention to consider . and .. special directory names. That convention has been extended to URLs. But you must handle them as any other path component: it's backend/.. and not backend.. for the same reason that foo/bar is not the same as foobar.
Edit #2: Even if you don't use class auto-loading or the include_path directive, it's trivial to load your application wide settings file, either with absolute paths:
require_once(__DIR__ . '/../conf/configuration.php');
... or relative paths:
require_once('../conf/configuration.php');
IHMO, doing this once per script, in the top level PHP file, is a huge benefit over calculating all application paths every single time you use them.
I've seen a number of questions on this site regarding this exact issue, but I'm fairly certain that my case is a bit different. I recently upgraded from ZF 1.9.6 to 1.11.11 and since then things stopped working on my production server.
My localhost is running PHP 5.3.8 while the server is running 5.2.11. I am not sure if that has anything to do with it but I figured I would mention it just in case.
When I first upgraded the framework, I was getting a bunch of open_basedir restriction in effect. errors. I resolved that exactly how several others mentioned, by removing the get_include_path() from the call to set_include_path() in the index.php file. As mentioned here.
That fixed the open_basedir errors, but now I'm having issues elsewhere. In several different files for various reasons I am including files via the include and require statements using relative paths.
For example:
require_once 'application/models/MyModel.php';
But now that suddenly doesn't work anymore! I've had to suddenly prepend all those paths with a ./ like so:
require_once './application/models/MyModel.php';
The problem is, there are way too may instances of that to manually go through and find all of them and change it. Rather, I want to figure out why those paths no longer work on the server but continue to work on my localhost.
My inclination is that it has something to do with the fact that I no longer include the get_include_path() part in the set_include_path() in the index.php file but I am not sure.
Can anyone shed some insight? Thanks!
I suspect it has to do with this note about open_basedir:
The restriction specified with open_basedir is a directory name since PHP 5.2.16 and 5.3.4. Previous versions used it as a prefix.
The difference between checking it as a prefix and checking it as a directory would definitely cause problems like this.
A solution might have something to do with this note in the PHP documentation:
Using a . in the include path allows for relative includes as it means the current directory. However, it is more efficient to explicitly use include './file' than having PHP always check the current directory for every include.
So when setting your include path, I think you should modify the example you linked to like this:
set_include_path(
APPLICATION_PATH . './../library' . PATH_SEPARATOR .
APPLICATION_PATH . './../library/Zend'
);
Notice the "." I added before the first forward slash. This should make it relative to the current working directory and stop you from having to make your includes like ./file.
Also, that says this method is less efficient so you can also consider using a tool such as TextCrawler to do find & replace on multiple files.
Additionally, you can include '.' (current directory - or document root) in your include path when setting it. Like so:
set_include_path(APPLICATION_PATH . '../library'
. PATH_SEPARATOR . APPLICATION_PATH . '../library/Zend'
. PATH_SEPARATOR . '.' // <-- notice this!
);
I just copied the library folder on the root directory of my net server . i.e. /var/www .
and used
require ( 'GChartPhp/gChart.php' ) ;
in my code on the file graph.php.
ERROR : But, for some reason , the browsers do not load this (graph.php) file .
However, I did the same on my local wamp server and my I am able to run the file.
I have no idea what I need to additionally do for this linux / apache server .
Thanks
I suppose the include_path is not configured the same way on your two servers : you might have to add either the WAMP equivalent of /var/www or . to it.
Modifying the include_path can be done by editing your php.ini file, or using set_include_path() at the beginning of your scripts.
Another possible solution would be to use an absolute path to the file you are including -- which can be done using something like this :
include dirname(__FILE__) . '/GChartPhp/gChart.php';
Notes :
__FILE__ will correspond to the full path to the file in which you write it
And using dirname() on it will get you the path to the directory which contains that file.
Which means that this line will use an absolute path... but written relatively to the file in which you put that line.
I'm deploying from my WAMP testing environment to an online test...
Locally I had my include paths something like this:
include('C/wamp/www...')
how do i find the equivalent path on my server?
i've tried using '/' to get to the root but i get this error:
Warning:
require_once(/test123/mvc/views/txt/index_nav_txt.php)
[function.require-once]: failed to
open stream: No such file or directory
in
/home/user/public_html/test123/mvc/views/components/st_footer.php
on line 37
Fatal error: require_once()
[function.require]: Failed opening
required
'/test123/mvc/views/txt/index_nav_txt.php'
(include_path='.:/usr/lib/php:/usr/local/lib/php')
in
/home/user/public_html/test123/mvc/views/components/st_footer.php
on line 37
You would actually need:
require_once("/home/codlife/public_html/test123/mvc/views/txt/index_nav_txt.php");
notice the edition of /home/codlife/public_html/
The initial / Takes you to the root of the server and your code is located inside /home/codlife/public_html/
do you mean
$_SERVER['DOCUMENT_ROOT']
which basically gives you the full path to your working website directory i.e. c:/wamp/www/(windows) or /var/www/vhost/domain.com/httpdocs/ (linux)
You should probably read up on include_path ( http://php.net/include_path ) - This is generally set to include the document root (where your website is) and can be altered so that you don't have to repeatedly include the same paths.
how do i find the equivalent path on my server?
You don't find it - you tell it where it should be. Admittedly this is not always practical when you buy a hosting package (which IME are usually badly supported and come with virtually no documentation).
First thing to note is regardless of where / how the code is hosted, you should always use paths relative to the directories configured on the php include path (or relative to the PHP script initially invoked by the browser request - the '.' entry from the include_path cited in the error) - never absolute paths. You can easily find this out with:
<?php
print ini_get('include_path');
?>
Judging from the path cited in the error message, it appears to be a POSIX system. The root of the filesystem as seen by the webserver might be quite different from the root as seen from your FTP or SSH software, but they are probably the same.
Note that if this is a shared host, then you probably won't have access to put files in /usr/lib/php or /usr/local/lib/php - so your only option is to use a relative path - which is going to get very messy -
You could do some clever coding around this - but do have a look at packages such as Dokuwiki and phpmyadmin to see how they organise the include files in a relocateable way without any dependance on manipulating the php.ini settings.
Alternatively you may be able to override the include_path via .htaccess, e.g.
php_value include_path ".:/home/codlife/public_html:/usr/lib/php:/usr/local/lib/php"
(which would set a base include_path to your document root)
HTH
C.
Use a configuration file where you store things like:
$application_root = '/home/code_life/public_html/';
In this file use all your environment specific variables or constants. When you deploy the application on a different machine, you just update configuration file.
Example:
You have in your root application a folder called settings with settings.php where you can define:
define('DIR_ROOT', dirname(dirname(__FILE__)) . '/');
Now, on every machine, the DIR_ROOT will be the root of your application and you don't have to change anything.
On localhost. I have the following directory structure:
/share/www/trunk/wp-content/plugins/otherfolders
/share/www/portfolio/wp-content/symlink
Where symlink is a symbolic link to /trunk/.../plugins/. Basically, this is because I need to test multiple WordPress installs and set them up, but I don't want to have to move plugins around and copy and paste them everywhere.
However, sometimes I need to crawl up the directory tree to include a config file:
$root = dirname(dirname(dirname(dirname(__FILE__))));
if (file_exists($root.'/wp-load.php')) {
// WP 2.6
require_once($root.'/wp-load.php');
}
The folder always resolves to:
/share/www/trunk
Even when the plugin is being executed and included in
/share/www/portfolio/.
Is it possible in PHP to include files in the share/www/portfolio directory from a script executing in a symlink to the /share/www/trunk/.../plugins directory?
While this problem only happens on my test server, I'd like to have a safely distributable solution so crawling up an extra level is not an option.
The problem that I see with your code is that __FILE__ resolves symlinks automatically.
From the PHP Manual on Magic Constants
... Since PHP 4.0.2, __FILE__ always contains an absolute path with symlinks resolved ...
You can try using $_SERVER["SCRIPT_FILENAME"] instead.
$root = realpath(dirname(dirname(dirname(dirname($_SERVER["SCRIPT_FILENAME"])))));
if (file_exists($root.'/wp-load.php')) {
// WP 2.6
require_once($root.'/wp-load.php');
}
Note that I added the realpath() function to the root directory. Depending on your setup, you may or may not need it.
EDIT: Use $_SERVER["SCRIPT_FILENAME"] instead of $_SERVER["PHP_SELF"] for the file system path.
Here is the solution to that issue: https://github.com/logical-and/symlink-detective
$root = dirname(dirname(dirname(dirname(__FILE__))));
if (file_exists(SymlinkDetective::detectPath($root.'/wp-load.php'))) {
// WP 2.6
require_once(SymlinkDetective::detectPath($root.'/wp-load.php'));
}
or you can try that
try {
$root = dirname(dirname(dirname(dirname(__FILE__))));
require_once SymlinkDetective::detectPath($root.'/wp-load.php', '',
false /* this would throw an exception if file doesn't exists */);
}
catch (Exception $e) {
// nothing to do if file doesn't exists
}
You can use this code snippet to get a path where symlinks are not resolved.
If you don't have bash available, there's probably a different command you can use, but it works on linux enviroments.
I do think it's a malpractice that php resolves symlinks in FILE, since there's no way to get the path with symlinks. Otherwise we could easily get it using realpath.
Oh well.
<?php
$output = array();
exec('pwd', &$output);
define('__LINK__', $output[0].substr(__FILE__, strpos(__FILE__, DIRECTORY_SEPARATOR)));
?>
In some case its possible to change working dir and use getenv('PWD'):
$root = dirname(dirname(dirname(getenv('PWD'))));
if (file_exists($root.'/wp-load.php')) {
// WP 2.6
require_once($root.'/wp-load.php');
}
And change working directory before run this code:
cd /var/www/wp-content/themes/twenty_twelve/ && php script.php
If I were trying to solve this, I'd split __FILE__ along the path bits and create a SplFileInfo for each along the way, test with isDir and isLink, then try to determine how to handle reconstruction of the path once it's known to be different than expected so you can pull from the right directory. (If you're more of a procedural type, there's is_dir and is_link.)
That being said, I think you've already disqualified this solution. Maybe the tools are smart enough to do it for you. Try comparing the result of getRealPath to getPath? getRealPath expressly says that it resolves symlinks, while getPath doesn't expressly say that.
Even then, this sniffing might not be safe on client sites, depending on who the host is. I've seen some pretty creative shared hosting filesystem setups. You could add a check to php_uname and pull out the hostname of the machine, and if it isn't your dev box, don't do the extra work.
The PHP interpreter resolves symlinks before it processes them. You can do this yourself with the readlink function. PHP resolves the links because it's more efficient for *_once functions and code caches like APC, Xcache etc.
What you propably need is another way to find where a particular installation stores it's files. I'd recommend using {$_SERVER['DOCUMENT_ROOT']}/wp-content/wp-load.php assuming /share/www/portfolio is the document root.
None of the suggested solutions worked in all these environments, CLI, PHPUNIT, WebServer.
What I ended up with was defining a variable for my project's root.
define( 'ABSPATH', __DIR__ . '/' );
And then used it in my symlinked plugins.
This may not be what you can always do but if it's okay with your use case it definitely works everywhere!
eg:
require_once(ABSPATH .'/wp-load.php');
If you are using WordPress this is already defined and you can just use it!