I a primary website and a site using a subdomain with the following directory structure
Primary website:
/home/mysite/public_html/
Subdomain:
/home/mysite/subdomain/
I would like my classes directory to be shared between the primary and subdomain. The classes reside here:
/home/mysite/public_html/classes/
I am trying to autoload the classes from a file in the subdomain's directory
/home/mysite/subdomain/includes/bootstrap.php
which contains this code:
$classdir = '/home/mysite/public_html/classes/';
function __autoload($class_name) {
var_dump($class_name);
require_once ($classdir.$class_name.'.php');
}
My issue is that the classes are not being loaded.
Please note this code works perfectly when used in a file located in the primary domain directory:
/home/mysite/public_html/includes/bootstrap.php
Including them individually works fine, such as:
require_once($classdir.'/class1.php');
require_once($classdir.'/class2.php');
However there are dozens of them and i would like to autoload them
Thank you for your time.
Fixed the issue with spl_autoload_register() as below
$classdir = '/home/mysite/public_html/classes/';
function autoLoader( $class_name ){
$path = $classdir . $class_name . '.php';
include_once( $path );
}
spl_autoload_register( 'autoLoader' );
Related
All my PHP include files are in a single directory:
https://www.mywebsite.com/includes
Inserting these files in top level pages is easy enough:
<?php include 'includes/logo.php'; ?>
<?php include 'includes/main_nav.php'; ?>
<?php include 'includes/news.php'; ?>
etc.
For sub-directory pages I've been doing this:
<?php include '../includes/logo.php'; ?>
<?php include '../includes/main_nav.php'; ?>
<?php include '../includes/news.php'; ?>
and this:
<?php include '../../includes/logo.php'; ?>
<?php include '../../includes/main_nav.php'; ?>
<?php include '../../includes/news.php'; ?>
So far so good, but I suspected it wasn't going to continuing being this easy.
Now I need to include this file:
top_five_news_stories.php
in this:
news.php
At this point, my relative path strategy fails because the include in the include can have only one path structure.
I've read several posts recommending absolute paths using:
dirname(__FILE__)
realpath(dirname(__FILE__)
$_SERVER["DOCUMENT_ROOT"]
However, they all come with some kind of caveat relating to PHP configuration, server configuration or operating system. In other words, there's often a comment by somebody saying it didn't work in their case, or doesn't work in IIS, or doesn't work in UNIX, or something else.
A solution I haven't seen is one I thought would be most simple: Just set a variable:
$base = "https://www.mywebsite.com/includes";
then:
<?php include $base . "logo.php" ?>
Considering that I already use the HTML base element, which works in a similar way, this method strikes me as simple and efficient.
But since it wasn't mentioned in any of the posts I read, I'm wondering if I'm overlooking a potential problem.
Frankly, if I had to go to production to today, I would use this:
<?php include $_SERVER['DOCUMENT_ROOT'] . '/logo.php" ?>
which works for me and is commonly mentioned.
But I'm wondering if using a variable is a reliable, efficient method?
Don't
I would advise against using anything that needs something outside of PHP, like the $_SERVER variable.
$_SERVER['DOCUMENT_ROOT'] is usually set by the webserver, which makes it unusable for scripts running from the command line. So don't use this.
Also don't use url's. The path-part in a url is not the same as the path of the file on disk. In fact, that path can not even exist on disk (think Apache rewrites).
Including url's also needs you to turn allow_url_include on, which introduces (severe) security risks if used improperly.
Do
If your minimal supported PHP version is 5.3 (I hope it is!), you can use the magic constant __DIR__. 2 examples:
define(ROOT_DIR, __DIR__);
define(ROOT_DIR, realpath(__DIR__ . '/..'));
If you need to support lower versions, use dirname(__FILE__). 2 examples:
define(ROOT_DIR, dirname(__FILE__));
define(ROOT_DIR, realpath(dirname(__FILE__) . '/..'));
Make sure ROOT_DIR points to the root of you project, not some subdirectory inside it.
You can then safely use ROOT_DIR to include other files:
include ROOT_DIR . '/some/other/file.php';
Note that I'm defining a constant (ROOT_DIR), not a variable. Variables can change, but the root directory of you project doesn't, so a constant fits better.
realpath()
realpath() will resolve any relative parts and symlinks to the canonicalized absolute pathname.
So given the following files and symlink:
/path/to/some/file.php
/path/to/another/file.php
/path/to/symlink => /path/to/another
and /path/to/file.php contains:
define(ROOT_DIR, realpath(__DIR__ . '/../symlink'));
then ROOT_DIR would become /path/to/another, because:
__DIR__ equals to /path/to/some (so we get /path/to/some/../symlink)
.. is 1 directory up (so we get /path/to/symlink)
symlink points to /path/to/another
You don't really need to use realpath(), but it does tidy up the path if you're relying on relative parts or symlinks. It's also easier to debug.
Autoloading
If you need to include files that contain classes, you'd best use autoloading. That way you won't need include statements at all.
Use a framework
One last pease of advise: This problem has been solved many many times over. I suggest you go look into a framework like Symfony, Zend Framework, Laravel, etc. If you don't want a "full stack" solution, look into micro-frameworks like Silex, Slim, Lumen, etc.
Jasper makes some good points, and a further reason for not using DOCUMENT_ROOT is that content accessible via a URL does not have to be within this directory (consider Apache's alias, scriptalias and mod_user_dir, for example).
As Barmar points out PHP explicitly provides functionality for declaring a base directory for includes. While this is typically set in the config it can be overridden/added to at runtime in your code. You never want to see a variable in your include/require directives. It breaks automatic tools and hides vulnerabilities. Nor should you ever include using the file wrappers.
There is an argument in OO programming for never using include/require explicitly but just autoloading class definitions. However the problem of locating the code remains.
The short answer is that there is no best solution for the problem you describe. Each method has its drawbacks - the best solution is completely dependent on the context. For an enterprise application, setting the include_path simplifies development processes and, if not directly accessible from the webserver enhances security. It also allows for selectively overlaying functionality by manipulating the order of multiple entries in the path.
On the other hand this is not a good model for software you intend to distribute to less technical users likely to be confused about multiple paths whom may not have access to directories outside the document root or to change the default config.
Using relative paths is a robust and portable solution. I don't understand your problem with including top_five_news_stories.php.
A solution which gives you the benefits of both the enterprise and low-end hosting is shown below. This however has the drawback that it needs code added to each entry point in the site (and requires the app to be installed in a named sub directory):
define('APP_NAME', 'mikesdemo');
$base=substr(__DIR__, 0, strrpos(__DIR__, APP_NAME))
. APP_NAME . '/include';
set_include_path(get_include_path() . PATH_SEPARATOR . $base);
The more sophisticated user can then simply....
mv /var/www/html/mikesdemo/include/* /usr/local/php/include/
File Arquitecture Rework:
define a path for every tipe of file like that:
+root
|
+------app(D)(all php script MVC)
|
+------conf(D)(all php Config file)
|
+------assets(D)(all file js and css static image)
|
+------fileup(D)(all file Uploades)
|
+------index.php(F)(Procesor of petition http)
in your index you need include all File of config Like style C++:
Example:
require_once ('conf/config.security.php'); #Configuration around Security in PHP
require_once ('conf/config.conpro.php'); #Configuration around Constantent
require_once ('conf/config.classlib.php'); #Lib class around Generic DB Conection ETC
require_once ('conf/config.classlibmvc.php'); #Lib class around MVC specific class
And example of config file:
Declare Root Directory + Path that shared the file
$APP_DIR_CLASS = $_SERVER['DOCUMENT_ROOT'] . '/app/classgeneric/';
Define library file:
if (!defined('DBMANAGER_CLASS')) define('DBMANAGER_CLASS' ,'class.managerdb.php' );
Include or require the class
require_once $APP_DIR_CLASS . DBMANAGER_CLASS;
when you are in a class and need use DB class you can call it easy:
class Class_Exmaple{
public function __construct(){
$this -> DBMANAGER = new Class_BDManager();
}
public function __destruct(){
$this -> DBMANAGER = new Class_BDManager();
}
public function ConsultDB(){
$query ='Selec * From Tablename';
$result = $this -> DBMANAGER -> ExecuteQ($query);
print_r(result);
}
}
is a easy way to implement but you need learn more about injection and Class Loaders.
There is no "correct way" to require/include an internal script in your project. A lot (most) MVC frameworks use similar best practices to global file access in a router object.
Let's take an example, here is our directory infrastructure:
App/
Controllers/
Controller.php
Models/
Model.php
Views/
View.php
404/
index.php
index.php
.htaccess
Inside our .htaccess we would have a rewrite rule to the index.php in the root directory of your server.
Inside this file, is where we actually run the whole of your Software. For example, this is a great router I use AltoRouter.
First things first, we need to add a way to stop direct browser access and an error path to any controllers, models and views:
define( 'ERROR_PATH', strtolower(explode( '/', $_SERVER['SERVER_PROTOCOL'][0]) . '://' . $_SERVER['SERVER_NAME'] . '/404' );
define( 'IN_APP', 0 );
Which is then used in your controllers, models and views like:
if( !defined( 'IN_APP' ) ) {
header('Location: ' . ERROR_PATH);
exit();
}
Your file path will be the root file path if you declare __FILE__ in this instance (index.php) so we can use it any way (best practice is global defines).
define( '_DIR_', dirname( __FILE__ ) );
Then start requiring your files:
$includeFiles = [
glob( _DIR_ . '/Controllers/*.php' ),
glob( _DIR_ . '/Models/*.php' )
];
foreach( $includeFiles as $dir ):
foreach( $dir as $file ):
require_once( $file );
endforeach;
endforeach;
I am using jquery datatable plugin which is in outside of my Codeigniter app. The datatable php editor uses namespaces.
And i have to import all editor class files inside the codeigniter controllers. So, i have to pull all files and classes inside to the "/assets/datatable/extensions/Editor/php" into my newly created controller file.
Controller file code,
// trying to import all files in this directory
$path = $_SERVER['DOCUMENT_ROOT'] . '/datatables/extensions/Editor/php';
//set_include_path(get_include_path() . PATH_SEPARATOR . $path);
ini_set('include_path', get_include_path() . PATH_SEPARATOR . $path);
Editor::inst($db, 'contactus', 'id')
->fields(
Field::inst('Position')
->validator('Validate::numeric', array('empty' => false)), Field::inst('Question')
->validator('Validate::notEmpty'), Field::inst('Answer')
->validator('Validate::notEmpty')
)
->process($_POST)
->json();
The both "set_include_path" and "ini_set" not working in my case. It returns the below error
Fatal error: Class 'Editor' not found in /var/www/html//application/controllers/ajax.php on line 50.
Please suggest for the same.
This always works for me:
require_once($path);
instead of ini_set(). Also make sure that the path is really correct. You can use a relative path (relative to index.php). So you get something like $path = './application/libraries/custom/autoload.php';.
(I can't post this as a comment)
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
PHP require file from top directory
I've been using PHP for a long time but I've always just written it to get the job done, now I'm trying to learn best practices and improve my skill. Right now I'm wondering what is the best method for including files in PHP scripts from any directory.
I have always done the following:
<?php
// From settings.php
define('ABSPATH', '/home/dalyn/public_html/');
// Then I put this at he top of all of my other files
include 'includes/settings.php';
include ABSPATH . 'includes/db.php';
include ABSPATH . 'includes/functions.php';
?>
But if my files are in a subdirectory I need to do something like:
<?php
include '../includes/settings.php';
include ABSPATH . 'includes/db.php';
include ABSPATH . 'includes/functions.php';
?>
Is there a better way to be doing this? I'm starting to learn OOP so if there is an OOP solution that applies I'm all ears.
Thank you.
I usually have something similar to this in my application/Bootstrap.php (for a zend framework application).
define( 'BASE_PATH' , dirname( __DIR__ ) . '/' ); //!< application root directory: note this file is not in the root directory
define( 'VAR_PATH' , BASE_PATH . 'var/' ); //!< optional system generated config files
define( 'CACHE_PATH' , BASE_PATH . 'cache/' ); //!< caches in the filesystem. See ISV_CacheManager
define( 'APPLICATION_PATH' , BASE_PATH . 'application/' ); //!< where the modules live
define( 'MODEL_PATH' , APPLICATION_PATH . 'models/' ); //!< path to models
define( 'FORM_PATH' , APPLICATION_PATH . 'forms/' ); //!< path to forms
define( 'CONTROLLER_PATH' , APPLICATION_PATH . 'modules/default/controllers/' ); //!< path to default module controllers
define( 'HELPER_PATH' , APPLICATION_PATH . 'helpers/' ); //!< global zend view helpers
define( 'INCLUDE_PATH' , APPLICATION_PATH . 'include/' ); //!< useful support classes
define( 'DOCUMENT_ROOT' , $_SERVER['DOCUMENT_ROOT'] ); //!< http root directory. note _no_ trailing slash.
define( 'IMAGE_PATH' , '/image/' ); //!< from the http document root
define( 'SCRIPT_PATH' , '/js/' ); //!< from the http DOCUMENT_ROOT
Some of those get fed to an autoloader, others I use for direct include paths like
require_once MODEL_PATH . 'Directory/Directory/IncludeFile.php';
did you try autoloading? http://php.net/manual/en/language.oop5.autoload.php .. Sorry I dont have permissions to write comments yet..
Updated.. Wesley is right, you will need to have the class name same as file name for autoload to work. I am sorry to assume that you are doing OOP-PHP. If not autoload will not work you will have to do it traditional way
function __autoload($class) {
require ABSPATH. $class .".php";
}
Any file inside the ABSPATH with classname = filename will be automatically loaded.
If you have various paths with different files in them than you will have to create multiple constant variables with path name. And than call them inside autoload with the specific path.
for eg.
class Myprogram{
public function __construct(){
define('ABSPATH', '/home/dalyn/public_html/');
define('ABSPATH_1', '/home/dalyn/public_html/includes');
define('ABSPATH_2', '/home/dalyn/public_html/some_other_folder');
}
function __autoload($class) {
require ABSPATH. $class .".php";
require ABSPATH_1. $class .".php";
require ABSPATH_2. $class .".php";
}
}
//Some other file
$myProg = new Myprogram(); // this will define your constants as well as autoload all the required files
and if you are not using OOP. Than you will have to define different paths as constants and include the files the way you do it now.
and if you want to automate this process
this code will be helpful.
if ($handle = opendir(ABSPATH)) {
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != "..") {
include_once ABSPATH . $entry;
}
}
closedir($handle);
}
this will include all the files present in the folder ABSPATH. You can create a function and call it with whatever path you want to put.
Hope this helps.
Dins
when I include something I use the dirname(__FILE__) to get the path to the file that try to include.
<?php
include dirname(__FILE__).'/includes/db.php';
But if you use OOP I suggest you to look at some class loader that will include the file automaticaly for you when you use a class. There is some already coded that exist like the one with Doctrine and the one with Composer.
http://www.doctrine-project.org/
http://getcomposer.org/
set_include_path('.'.PATH_SEPARATOR.'your path to includes folder'
. PATH_SEPARATOR . './library/'
);
In PHP when we include or require some file using some initializers like the following. How can we overcome filepath issues which occurs if you include the same initializer in a sub-directory or different location.
<?php
// settings
$settings = array('config');
foreach ($settings as $setting) {
require_once "../system/settings/{$setting}.php";
}
// neutrals
$neutrals = array('functions');
foreach ($neutrals as $neutral) {
require_once "../system/neutrals/{$neutral}.php";
}
// helpers
$helpers = array('database', 'file', 'logger', 'user', 'session', 'database');
foreach ($helpers as $helper) {
require_once "../system/helpers/{$helper}.php";
}
// models
$models = array('test');
foreach ($models as $model) {
require_once "../system/models/{$model}.php";
}
?>
Above script is in a file all_initializer.php. The hurdle here is that i cant use the same initializer in a public sub-directory or other location as it will occur fatal errors (if its a required file) of file not found.
EDIT
For e.g. I am using this initialzer in a public folder in a index.php file then there's a sub-directory in the public folder public/sub. How can I use the same initializer in public/sub/index.php as I used in public/index.php ?
You could use the file_exists to avoid fatal errors
// neutrals
$neutrals = array('functions');
foreach ($neutrals as $neutral) {
if (file_exists("../system/neutrals/{$neutral}.php")
{
require_once "../system/neutrals/{$neutral}.php";
}
else
{
// Do some logging here so as to know that something went wrong
}
}
As for the path issues you are referring to, you can include this file from anywhere so long as you supply the proper base path for your operations. Defining a ROOT_PATH in your index.php file would help you detect where your script is and what it needs to load.
So for instance if you have this structure:
/system
/system/neutrals
/system/models
/public
/public/index.php
in your index.php you can define a ROOT_PATH constant that will be used throughout the application and serve as a point of reference.
// this points to the folder that has /public and /system
define('ROOT_PATH', dirname(dirname(__FILE__))));
You can also have a constant just for your system folder
define('SYSTEM_PATH', ROOT_PATH . '/system');
and then all your require_once declarations become:
require_once SYSTEM_PATH ."/neutrals/{$neutral}.php";
EDIT: Based on additional information in the question
Structure:
/all_includes.php
/system
/system/neutrals
/system/models
/public
/public/index.php
/public/sub/index_sub.php
In index.php you define
// this points to the folder that has /public and /system
define('ROOT_PATH', dirname(dirname(__FILE__))));
and then:
require_once ROOT_PATH . '/all_includes.php';
to do your initialization. The same thing happens in the public/sub/index_sub.php.
Your all_includes.php becomes:
// neutrals
$neutrals = array('functions');
foreach ($neutrals as $neutral) {
if (file_exists(ROOT_PATH . "/system/neutrals/{$neutral}.php")
{
require_once ROOT_PATH . "/system/neutrals/{$neutral}.php";
}
else
{
// Do some logging here so as to know that something went wrong
}
}
The way most of the php frameworks work is similar to the following, zend framework works like this:
Declare a constant APPLICATION_PATH and then make all the paths relative to this one.
define("APPLICATION_PATH", "/var/www/mysite");
And then all your requires will be relative to your APPLICATION_PATH.
require_once APPLICATION_PATH ."/system/helpers/{$helper}.php";
* With this approach you can include files from whatever script without issues. Because all the paths are going to be relative to your APPLICATION_PATH.
Simple.. don't use relative paths... in your foreach loops, you could do:
require($_SERVER['DOCUMENT_ROOT'].'/system/thing.php');
the pathing problem can be solved in this way, you have one file that is always in the same place. for example you have (this is you public html)
.
..
folder/subfolder/filetoinclude.php
folder2/includein.php
thefilefolder/thefile.php
ok now in the file php you have a variable
$path=dirname(__FILE__);
this will always give you the absolute path to that file, then you ca use this $path variable and build your include paths around it.
in this example you have to include $path.'../folder/subfolder/filetoinclude.php';
The pint is to alway use the same point of origin, and not use relative paths.
and then you can make a custom include function in thefile.php, and then the things get really easy.
I am seeking a way of allowing my PHP applications to be perfectly portable. My problem is, although I am utilizing relative path to include PHP classes, I always face issues when I try to deploy me application in a new environment.
For example, I have implemented an application under Ubuntu and it just run perfectly. However, when I moved it to a shared hosting running Centos, I had to modify all the include statements.
So, I am asking about the best way to include classes, considering having multiple folders which contain various classes that are dependent on another multiple classes in different levels of the folder hierarchy.
just keep one "main" folder.
In your index.php (for ex.) configure the "main" folder location and either use that as the 'base' for includes (I suppose you hard-code the include/require path?)
Else use the 'base' within the autoload functionality.
Now you are able to move the 'main' folder around and all you need to do is update just one line of code in your index.php
It is still a manual update. True that. You can also ofc. use something like glob() and search for you "mainlib.php" file (for ex.) and 'cache' that folders location to use it in the next calls?
This for example is how I do it:
<?php
/**
* cfg.php
*
* Main config file
*
* #package Public
*/
// Compatibility
$version = '5.2.3';//restricted by htmlentities()' 4th parameter
if(version_compare(PHP_VERSION, $version, '<')) {
die('Required PHP version is ' . $version . ', current is ' . PHP_VERSION);
}
// Environment
define('DEVELOPMENT', in_array($_SERVER['REMOTE_ADDR'], array('127.0.0.1', '::1')));
define('PRIVATE_DIR', DEVELOPMENT ? 'private' . DIRECTORY_SEPARATOR : '..'.DIRECTORY_SEPARATOR.'private_html'.DIRECTORY_SEPARATOR.'tickets');
define('APPLICATION_LINK','application_red'.DIRECTORY_SEPARATOR);
define('LIBRARY_LINK','library'.DIRECTORY_SEPARATOR);
define("MEM_START",memory_get_usage(true));
// Behavior
if(DEVELOPMENT) {
ini_set('display_errors', 'On');
error_reporting(E_ALL | E_STRICT);//report all errors
}
else {
ini_set('display_errors', 'Off');
error_reporting(0);
}
// Timezone
date_default_timezone_set('Europe/Amsterdam');
// Constants
define('ROOT', dirname(__FILE__) . DIRECTORY_SEPARATOR);
define('APP', ROOT . '..'.DIRECTORY_SEPARATOR.PRIVATE_DIR.''.APPLICATION_LINK);
define('LIB', ROOT . '..'.DIRECTORY_SEPARATOR.PRIVATE_DIR.''.LIBRARY_LINK);
define('CACHE', APP.'cache'.DIRECTORY_SEPARATOR);
index.php/utest.php:
<?php
include("cfg.php");
// Start library
require_once LIB.'Library.php';
$library = new Library();
//etc.......
You don't need to make reference to a hardwired folder at all. In my current project I do this:
public static function getProjectRoot()
{
return realpath(
dirname( __FILE__ ) . DIRECTORY_SEPARATOR . '..' .
DIRECTORY_SEPARATOR . '..'
);
}
The class in which this features is two folder levels inside the project - hence the two .. operators to traverse up the directory structure. Since that location will never change in relation to the project root, this doesn't need changing, and I don't ever need to hardwire any paths.
Edit: in relation to include/require statements, use an autoloader, and (apart from a couple of bootstrap files) you don't generally need to use includes/requires at all.