spl_autoload fails when script ran from command line - php

I know this has to do with the path not being quite right but it has me baffled. I can run my script with no problems at all from the browser but when I do to the exact same spot from a shell, spl_autoload complains and dies:
Fatal error: spl_autoload(): Class db
could not be loaded in...
I am using the absolute path from the root directory, echoed to screen and pasted it into a shell and verified that it is good. Please... what am I missing??

Try using the __DIR__ constant to locate the files, CLI PHP doesn't uses the same working dir.
Use something like this:
function __autoload($class)
{
require_once(dirname(__FILE__) . '/path/to/libraries/' . $class . '.php');
}

you can usually grab your root directory for the project with something along the lines of :
// The file that defines this is 2 directories below root, hence the ../ changes.
define('PATH_ROOT', realpath(dirname(__FILE__) . '/../../'));
Once you have your root path you can modify your include path, using set_include_path. (remember to include get_include_path when you set it otherwise you'll lose the defaults)
once thats sorted, just setup your autoloader assuming against the root dir and you should be fine, since its a bit more concrete than relying on relative paths which can change according to the working dir.

Related

Assist with diagnosing PHP include, failed to open stream

I am attempting to move an old Intranet site running on Apache 2.2, to a WAMP setup (latest version) on my local machine.
One of the issues I have currently, is a require_once path failing to open, and I cannot determine what the cause is.
I have WAMP installed in:
C:\Wamp
I have changed http.conf and vhosts.conf to change the document root from
C:\Wamp\www
to
C:\Wamp\www\Intranet
This folder contains an index.php, which I can see being loaded correctly when browsing to localhost.
Index.php has an iFrame that loads welcome.php from
/site/welcome.php
This works, as the iFrame loads, but throws a 500 error.
Enabling PHP errors, the welcome.php page in the iFrame gives me an error on a require_once. The require_once is:
/site/login/config.php.
As you can see, I am using absolute paths here, so the fact that index.php is able to load /site/welcome.php, tells me it is loading the correct file from:
C:\Wamp\www\Intranet\site\welcome.php
I would expect then, my require_once with an absolute path to be loading:
C:\Wamp\www\Intranet\site\login\config.php
Which is a valid file path.
What is confusing me, is that the first absolute path I am using, seems to be starting from the document root, not the physical directory root.
The second absolute path I am using, does not seem to be starting from the document root.
Even more interestingly, if I change the require_once from:
/site/login/config.php
to
/login/config.php
It works?! I wouldn't expect it to, as that would suggest the absolute path I am specifying, is in fact a relative path?
I don't think this path (/site/login/config.php) makes sense on a windows machine.
Better than hardcoding the full file path, determine it on runtime.
E.g.:
define('ROOT_DIR', realpath(dirname(__FILE__)));
// because *nix and Windows path separators aren't the same (/ vs \)
define('DS', DIRECTORY_SEPARATOR);
// just for convenience sake, you could use DIRECTORY_SEPARATOR on its own.
Then including your config file, from welcome.php would be:
require_once(ROOT_DIR . DS . 'login' . DS . 'config.php');
I think that besides you are confusing the path that you use in the iframe declaration (which is a url path) with the path you use in the require (which is a filesystem path).
How i tend to resolve most of my include/require errors is by setting a variable path:
$path = dirname(__FILE__);
include($path.'/file.php');
This will prevent you from having trouble with different environments in this case being windows and linux.
Or even better:
define('ROOTPATH', realpath(dirname(__FILE__) . '/'));
require ROOTPATH.'login/config.php';
Another thing, probably not causing your issues, but being good practice is to set the DIRECTORY_SEPaRATOR.
define('DS', DIRECTORY_SEPARATOR);
include(DS.'home'.DS.'www'.DS);
This will make PHP use the correct slash (either / or \)

Running php from cmd: relative paths issue

I am currently testing some code in cmd, and I'm experiencing some problems with relative paths.
It is clearly visible that the path is set correctly, furthermore it works as expected under http protocol. I assume there's something that's blocking relative paths in cmd, because if I replace that with an absolute path the file gets included. This however is not efficient as filesystems may change and the use of relative paths is a must. I'm really bad with OS stuff so I guess I shouldn't be making any more assumptions. Thanks!
EDIT: Mind = Blown
Basics:
When called from HTTP the working directory of index.php is C:\xampp\htdocs\actualframework\public\ when called from command line (in your example) it is C:\xampp\php. So the script tries to include C:\xampp\Framework/class/routers/System.php which isn't there.
You need to utilize the __DIR__ constant in order to make the require command working independently from where index.php was called:
require(__DIR__ . "/../Framework/class/routers/System.php");
__DIR__ points to the directory where the source file is located which is using the __DIR__ constant, in your example: C:\xampp\htdocs\actualframework\public\
Using include_path
Another good idea is to utilize the include_path directive in order to make the real location of a library file transparent to the application. This will give you more freedom when you once change the directory layout. include_path is a configuration value that can be set in php.ini or in scripts and contains a list od directories where php should look if you pass relative paths to require or include as well as some functions like file_get_contents(), fopen(), ...
Configure the include path on top of your index.php (or in a separate bootstrap.php which gets included):
ini_set('include_path', implode(PATH_SEPARATOR, array(
__DIR__ . '/../Framework/class',
__DIR__ . '/../Framework/interface',
// add the existing value at the end
ini_get('include_path')
)));
Now you can use paths like this to require classes:
require_once 'System.php';
require_once 'routers/Foo.php';
Autoloading
Since PHP5 there is a feature called autoloading which eases the including of classes. Autoloading basically provides the ability to define a hook function which gets called every time a class is accessed which has not been defined before. Imagine you have the following files:
lib/Person.php
<?php
class Person {
... some code
}
index.php
<?php
$hek2mgl = new Person();
Normally this code will trigger an error because Person is accessed without including lib/Person.php before. This is the point where autoloading can be used. Lets see how a simple autoload method can look like in this (simple example):
function autoload($classname) {
$path = __DIR__ . "/lib/$classname.php";
if(file_exists($path)) {
require_once $path;
}
}
You need to reqister the autoloader using spl_autoload_register(). index.php can look like this:
<?php
// define simple autoloader for project
function autoload($classname) {
$path = __DIR__ . "/lib/$classname.php";
if(file_exists($path)) {
require_once $path;
}
}
// register autoloader
spl_autoload_register('autoload');
// will work now
$hek2mgl = new Person();
If you ask me, autoloading is one of the coolest things in PHP5. You can refine the autoload method in order to work with the include_path directive. Doing so it gets easy to work with a couple of libraries without taking care about where they are physically stored in filesystem. You may give my Jm_Autloader a try, the code is on github and you can install it using PEAR or composer.
As #hek2mgl points out, it has to do with the current working directory being wrong.
In your case the working directory is c:/xampp/php/ but it should be c:/xampp/htdocs/actualframework/public/.
There's at least two solutions to fix this, the most obvious one being changing the working directory on the command line:
cd c:/xampp/htdocs/actualframework/public/
c:/xampp/php/php.exe index.php
Alternatively you can set the current working directory from your PHP script by adding the following into your index.php before you try to include/require anything:
chdir(realpath(dirname(__FILE__)));

what's wrong with my require_once path?

I've switched my files over from a local environment to my vps and now my facebook notification isn't working even thought I'm pretty sure I've updated all the paths correctly. I've tried writing the require path numerous ways.
I'm doing a "$.post" from jquery to a php page where the facebook notification is sent and am getting this error:
<b>Fatal error</b>: Class 'Facebook' not found in
<b>/home/zjkkvcxc/public_html/accepted.php</b> on line <b>9</b><br />
//THIS IS MY PHP REQUIRE PATH.
require_once('php-sdk/facebook.php') ;
//IN MY LOCAL ENVIRONMENT I WAS USING THIS PATH BECAUSE IT WAS THE ONLY ONE THAT WORKED. THIS DOESN'T WORK ON MY VPS THOUGH.
require_once(dirname(__FILE__).'/php-sdk/facebook.php') ;
You use require_once and have error "Class 'Facebook' not found". If you tried require_once on a file that does not exist, it would cause other error: "Fatal error: require(): Failed opening required 'php-sdk/facebook.php'". So the path is probably OK. Check if you uploaded php-sdk properly. The facebook.php might be empty.
Your error is :
Fatal error</b>: Class 'Facebook' not found in
<b>/home/zjkkvcxc/public_html/accepted.php</b> on line <b>9
The valuable information here is :
the error occurred because the Facebook class is unknown which means that require_once did not pop this error
the error occurred on line 9 of accepted.php
Now you have to look why the class Facebook is unknown on line 9.
if you have included the facebook.php before line 9 it is probably not containing the right class. (class names are case sensitive!)
if you include facebook.php after line 9 you just have to call it earlier.
PS: posting the first 10-15 lines of accepted.php might give us enough information to pinpoint the exact problem here.
I have faced issues like this before, and the best way to handle this is to set your true filepath as a variable & prepend that to your includes/requires. Becuase the whole dirname(__FILE__) setup can act oddly in different environments especially those that use symbolic links. Explicitly stating where files are to be set is the best solution.
So let’s assume this is your codebase path; as per your example:
/home/zjkkvcxc/public_html/
Set that as a variable that all of your pages load in some way like this:
$BASE_PATH = '/home/zjkkvcxc/public_html/';
And now when you make calls to the file system for your app, do this:
require_once($BASE_PATH . 'php-sdk/facebook.php');
What is nice about a setup like this is that you can make your app portable between environments by just changing $BASE_PATH to match your local environment. Like this might be a path for a MAMP (Mac OS X LAMP) setup:
$BASE_PATH = '/Application/MAMP/htdocs/';
Regarding how odd __FILE__ can act in symlinked environments, read up here:
Since PHP 4.0.2, _ FILE _ always contains an absolute path with
symlinks resolved whereas in older versions it contained relative path
under some circumstances.
Class not found error not refers to problem loading file. You are using a require , if file not exists a require error will be raised and this is not the case.
Probably the class inside facebook.php is not called Facebook, probably is with another name or with other case like "facebook"
Fatal error</b>: Class 'Facebook' not found in
<b>/home/zjkkvcxc/public_html/accepted.php</b> on line <b>9
Is it possible that:
your short_open_tag is enabled on your local environment and
it's disabled on your vps and
you are using <?instead of <?php in your facebook.php file
For some odd reason, i encounter circumstances where php doesn't find the file i need through conventional means. i found some code used for searching a directory and retrieving a list of files, which was advantageous in a url generation script i was writing. overtime, i have used this simple script for many tasks, such as finding files when normal require/include fails. in a pinch, this hack works for me.
Just fill in the file name $somefile and directory name $log_directory if your directory is in the base path just type it with no slashes. if its below the base path type it like this /path/to/folder
hope this helps.
$somefile = '<!--Filename You need to find-->';
$log_directory = '<!--Directory you want to search-->';
$results_array = array();
if (is_dir($log_directory))
{
if ($handle = opendir($log_directory))
{
while(($file = readdir($handle)) !== FALSE)
{
$results_array[] = $file;
}
closedir($handle);
}
}
foreach($results_array as $value)
{
if ($value == $somefile) {
$url_include = $log_directory."/".$value;
}else{
die("error file not found.");
}
}
require_once("$url_include");
require_once JPATH_SITE.'/php-sdk/facebook.php';
The require path you said is wrong:
require_once('php-sdk/facebook.php') ;
This need there has a file got full pathname: /dir/to/your/actual/include/path/php-sdk/facebook.php
And later you require file in include_path wrong, dirname(__FILE__) OR __DIR__ is directory of the file where require_once() is called, so you are looking for facebook.php in php-sdk sub-directory under you current php script.
To fix your problem, you have 2 plan
Better one, find your actual include_path and put php-sdk files in, include_path can find from php.ini, or run php -m from shell, or phpinfo(), in this way, your first require_once() will work.
Make sure php-sdk directory includes facebook.php is in same parent directory with your calling php script, this is not common usage, but will make your second require_once() work.
I suggest you to study more on php include_path configure and __FILE__ magic constant.
define('DOC_ROOT', realpath(dirname(__FILE__) . '/'));
require_once(DOC_ROOT . '/php-sdk/facebook.php');
Assuming the folder php-sdk is at the root of you website directory.
require_once('php-sdk/facebook.php') ;
This assumes that the facebook.php file is in a folder that resides in the current folder of the PHP file beind called.
Is this the case? I suspect not since you have an error!
Are you in a folder up from the root?
---ROOT
---ROOT > FOO --your script here?
---ROOT > php-sdk --facebook in here
If so...
require_once('../php-sdk/facebook.php');
would work.
Try $_SERVER['DOCUMENT_ROOT'].'/path to /php-sdk/facebook.php'
$_SERVER['DOCUMENT_ROOT'] will give absolute path for www or htdocs folder then you can provide path to facebook.php

require_once not working as I expect it to [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
relative path in require_once doesn’t work
I have a project structure as such:
ProjectName/
src
test
TestClass.php
tests
TestTestClass.php
WhenI try and do require_once '/ProjectName/src/test/TestClass.php'; into tests/TestTestClass.php I get an error from PHP stating that: no such file or directory.
I have checked the spelling, I have checked everything. I cannot give it the full /home/userName/bla/bla path as I need to hand this off to some one else.
Any ideas?
This is expected behaviour. When you execute TestTestClass.php, your working directory is set to ProjectName/tests.
It would be better to use ../src/test/TestClass.php.
Your path is actually absolute, so you will be working straight from /, which is not what you're expecting. If your include_path is set to your server's directory root, then your code will work without the first /. If you don't wish to rely on include_path or arbitrary levelling (with ..), you can always set an environment variable in your first file that defines the full path to your application root, then use that for all includes.
For example, /ProjectName/index.php:
define('APPPATH', __DIR__);
.. and in /ProjectName/tests/TestTestClass.php:
require_once APPPATH . '/src/test/TestClass.php';
absolute filepaths passed to require/include/require_once/include_once all work from the filesystem root, not to the webserver root
Use the special DIR to get the current path of the script and like so it will be easier for you to find script paths:
require_once(__DIR__ . '../folder/whatever.php');
You'd benefit from creating a path constant for your project. This is quiet easy to do with the __FILE__ constant and dirname().
define('ROOT_PATH', dirname(__FILE__));
The above could be put in a configuration file so it is easier to include files throughout your project.
require_once ROOT_PATH . '/src/test/TestClass.php';
I'd also suggest looking into an autoloader.

How do you know the correct path to use in a PHP require_once() statement

As many do I have a config.php file in the root of a web app that I want to include in almost every other php file. So most of them have a line like:
require_once("config.php");
or sometimes
require_once("../config.php");
or even
require_once("../../config.php");
But I never get it right the first time. I can't figure out what php is going to consider to be the current working directory when reading one of these files. It is apparently not the directory where the file containing the require_once() call is made because I can have two files in the same directory that have different paths for the config.php.
How I have a situation where one path is correct for refreshing the page but an ajax can that updates part of the page requires a different path to the config.php in the require_once() statement;
What's the secret? From where is that path evaluated?
Shoot, I was afraid this wouldn't be a common problem - This is occurring under apache 2.2.8 and PHP 5.2.6 running on windows.
The current working directory for PHP is the directory in which the called script file is located. If your files looked like this:
/A
foo.php
tar.php
B/
bar.php
If you call foo.php (ex: http://example.com/foo.php), the working directory will be /A/. If you call bar.php (ex: http://example.com/B/bar.php), the working directory will be /A/B/.
There is where it gets tricky. Let us say that foo.php is such:
<?php
require_once( 'B/bar.php' );
?>
And bar.php is:
<?php
require_once( 'tar.php');
?>
If we call foo.php, then bar.php will successfully call tar.php because tar.php and foo.php are in the same directory which happens to be the working directory. If you instead call bar.php, it will fail.
Generally you will see either in all files:
require_once( realpath( dirname( __FILE__ ) ).'/../../path/to/file.php' );
or with the config file:
// config file
define( "APP_ROOT", realpath( dirname( __FILE__ ) ).'/' );
with the rest of the files using:
require_once( APP_ROOT.'../../path/to/file.php' );
I like to do this:
require_once(dirname(__FILE__)."/../_include/header.inc");
That way your paths can always be relative to the current file location.
I use the dirname(__FILE__) thing like bobwienholt most the time, but what it could pay to do is have a base entry point that loads all your other code that defines a constant refereing to the root of the project, ie
define("ROOT",dirname(__FILE__).'/' );
and then later all you need to know is where the path is relative to root, ie:
require(ROOT . "/lib/tool/error.php");
note,
you should REALLY avoid paths with "../" at the start of them, they are not relative to the file, but relative to where you ARE and this creates broken-ass code.
cd foo
php bar/baz.php
-> some error saying it cant find the file
cd bar
php baz.php
-> suddenly working.
Important
If you use "../" notation, it takes complete ignorance of the PHP Include Path, And ONLY considers where the person whom is running it is.
I include this code at the top of every page:
//get basic page variables
$self=$_SERVER['PHP_SELF'];
$thispath=dirname($_SERVER['PHP_SELF']);
$sitebasepath=$_SERVER['DOCUMENT_ROOT'];
//include the global settings, variables and includes
include_once("$sitebasepath/globals/global.include.php");
Include and require both take either a relative path or the full rooted path. I prefer working with the full path and make all my references like the inlcude statement above. This allows me to enter a general variable $sitebasepath that handles account specific information that may change from machine to machine and then simply type the path from the webroot, ie. /globals/whatever_file.php
I also use the $self variable in forms that may call themselves to handle data input.
Hope that helps.
If you have sufficient access rights, try to modify PHP's include_path setting for the whole site. If you cannot do that, you'll either have to route every request through the same PHP script (eg. using Apache mod_rewrite) or you'll have to use an "initialization" script that sets up the include_path:
$includeDir = realpath(dirname(__FILE__) . '/include');
ini_set('include_path', $includeDir . PATH_SEPARATOR . ini_get('include_path'));
After that file is included, use paths relative to the include directory:
require_once '../init.php'; // The init-script
require_once 'MyFile.php'; // Includes /include/MyFile.php
Since require and require_once are very similar to include and include_once, all the documentation is posted under the "include" functions doc area on php.net From that page
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.
Further, you can find all the current include paths by doing a "php -i" from the command line. You can edit the include path in your php.ini file, and also via ini_set(). You can also run the php_info() function in your page to get a printout of your env vars if the CLI is inconvenient.
The only place I've seen the path evaluated from is the file that you are currently editing. I've never had any problems with it, but if you are, you might want to provide more information (PHP version, OS, etc).
The path of the PHP file requested in the original GET or POST is essentially the 'working directory' of that script. Any "included" or "required" scripts will inherit that as their working directory as well.
I will either use absolute paths in require statements or modify PHP's include_path to include any path in my app I may want to use to save me the extra typing. You'll find that in php.ini.
include_path = ".:/list/of/paths/:/another/path/:/and/another/one"
I don't know if it'll help you out in this particular instance but the magical constants like FILE and DIR can come in handy if you ever need to know the path a particular file is running in.
http://us2.php.net/manual/en/language.constants.predefined.php
Take a look at the function getcwd. http://us2.php.net/getcwd

Categories