PHP confused about use of __DIR__ and ../ in a path - php

I came across a project with this structure.
-projectRoot
--src
---bootstrap.php
--composer.json
--public
---index.php
---css
---images
Now in public directory, index.php contains the following
//in projectRoot/public/index.php
<?php
require __DIR__."/../src/bootstrap.php";
?>
I understand that __DIR__ constant resolve to absolute directory of the current executing php script file.So in the above example I would expect it to be ProjectRoot/public.
the quention
Which path will require in index.php look into ? and what does a parent dir .. in the path above resolve to ?
PS: I read that the whole point of the setup above is to ensure relative paths continue to work regardless where index.php is called. How does that work exactly? thanks.

<?php
require __DIR__ . "/some_file.php";
/* __DIR__ SIMPLY POINTS TO THE DIRECTORY IN WHICH THE ACTIVE SCRIPT LIVES
- THE DIRECTORY OF THE EXECUTING SCRIPT... THEN REQUIRES THE FILE
"some_file.php" WITHIN THAT DIRECTORY.
THE REAL-PATH SHOULD REFLECT SOMETHING LIKE: projectRoot/public/some_file.php
*/
require __DIR__ . "/../src/bootstrap.php";
/* FOLLOWING THE LOGIC ABOVE, __DIR__ . "/../" __DIR__ AGAIN POINTS TO
THE DIRECTORY IN WHICH THE ACTIVE SCRIPT LIVES WHILE "/../" TELLS
THE REQUIRE DIRECTIVE TO LOOK ONE DIRECTORY ABOVE THE CURRENT DIRECTORY
(AND LOCATE WITHIN THAT DIRECTORY ANOTHER DIRECTORY CALLED "src" IN THIS CASE...)
THEN WITHIN THAT "scr" DIRECTORY LOOK FOR A FILE CALLED:
"bootstrap.php" AND REQUIRE/INCLUDE IT...
THE REAL-PATH SHOULD REFLECT SOMETHING LIKE: projectRoot/src/bootstrap.php
*/
// TO UNDERSTAND THESE CONCEPTS MORE CLEARLY, IT WOULD BE ADVISED TO
// TRY SOMETHING LIKE THESE:
var_dump( realpath(__DIR__ . "/../src/bootstrap.php") );
var_dump( realpath(__DIR__ . "/index.php") );

Here's what's happening in your index.php:
__DIR__ // This will be projectRoot/public
/../ // This will go one level up so it'll be projectRoot
src/ // This will go inside the src folder (projectRoot/src)
bootstrap.php // This will open the bootstrap.php
So in the end, it's going to target projectRoot/src/bootstrap.php... that's the file it's requiring.

Related

How to include config file in multiple directories php pages

I have a following directory structure for my project in which I have Init.php file under core folder. I wanted to include this file on every pages under the views folder to auto load all my classes defined under classes folder. But when I am including require_once '../../core/Init.php'; from a sub-directory of views folder it gives me following error
require_once(classes/Config.php): failed to open stream: No such file or directory in
Including this file in every pages under the views folder
require_once 'core/Init.php';
core/Init.php
spl_autoload_register(function($class) {
require_once 'classes/' . $class . '.php';
});
My directory structure is as below
I would like to include this single file (core/Init.php) into all my files, directories and sub-directories of views folder. Any one have an idea how would I do it.
Thanks!
The root of your problem is that your code actually gets executed from multiple directories.
Instead it should be called through a single point of entry (usually referred to as "bootstrap file").
Basically, you do something like this.
$config = require __DIR__ '/../config.php';
$page = $_GET['page'] ?? 'home';
if (in_array($page, $whitelist)) {
require __DIR__ . "/path/to/pages/{$page}.php";
}
Oh, and don't refer to your template as "views". They are not.
Structure! When starting the application tell it where to find things then add the spl_autoload_register function and setup the things which are always accessible:
.../www/index.php
eg (in index.php):
chdir(__DIR__):
Now every thing starts at .../www/ directory. From that point you can start to setup all paths you wish to include. Relative or absolute.
Kind regards

php include path on windows

I work with PHP on Windows, sience a few days. The whole time I've been indicated include in the following manner:
In index.php file:
require ('include/init.inc');
In the directory "include" I stated:
In init.inc file:
require ("workbench.inc");
But suddenly no longer works. At one time I must also in "init.inc" specify the directory.
Why did it all the time to work, and suddenly no more?
From the PHP documentation:
Files are included based on the file path given or, if none is given,
the include_path specified. If the file isn't found in the
include_path, include will finally check in the calling script's own
directory and the current working directory before failing
So the current working directory (CWD) is important when including other files. It can be retrieved by getcwd().
If your directory structure looks like this
rootdir/
include/
init.rc
workbench.rc
index.php
then a require('include/init.rc') will only work if rootdir/ is the CWD or is part of the search path. Likewise, require('init.inc') assumes the CWD is rootdir/include/. Since the current working directory can change, it is idomatic in PHP to use the more robust
// in index.php
require(__DIR__ . '/include/init.rc');
// in workbench.rc
require(__DIR__ . '/init.rc');
Then the require will work independent of the CWD. This works because the magic constant __DIR__ is replaced by the absolute path to the file that contains the constant without a trailing directory separator, for example
in index.php, __DIR__ is D:\path\to\rootdir and
in include/init.rc, __DIR__ is D:\path\to\rootdir\include.

PHP Relative paths for require file

I've been going over those two topics:
include, require and relative paths
PHP - with require_once/include/require, the path is relative to what?
and couldn't make my script to work, none of presented methods are working or maybe I'm doing something wrong.
Anyway this is where my problem occurred:
Root/ //this is root location for server
APP/ //this is root location for script
Root/APP/core/init.php //this is where I include classes and functions from
Root/APP/classes/some_class.php //this is where all classes are
Root/APP/functions/some_function.php //this is where all functions are
and so obviously I need to include init.php everywhere so I did in every file like this:
require_once 'core/init.php';
it was working until I have decided to create a location for admin files like this:
Root/APP/Admin/some_admin_file.php
and when I included init this way:
require_once '../core/init.php';
script failed to open functions, no such file in APP/Core/ folder
so I used DIR method presented in topic above and than even weirder thing happened, error:
no such file in APP/Core/classes/Admin/
What is that? :D I'm lost with this, could someone help a bit ;)
Include paths are relative to the current working directory, which can be inspected using getcwd(); this can be a source of many issues when your project becomes bigger.
To make include paths more stable, you should use the __DIR__ and __FILE__ magic constants; for instance, in your particular case:
require_once dirname(__DIR__) . '/core/init.php';
The dirname(__DIR__) expression is effectively the parent directory of the script that's currently being run.
Btw, __DIR__ could also be written as dirname(__FILE__).

include file(s) from another directory

Currently I am trying to include a PHP file from another directory.
public_html/a/class/test.php <-- from this file i would to include a file from
public_html/b/common.php <-- wanted to include this file
Not sure what I should do because I have tried using
dirname(__FILE__)
and this keeps on returning public_html/a/ for me instead.
I have tried something like this
dirname(__FILE__).'/../b/common.php'
but it does not help me in getting my file.
You can simply keep moving up the directory tree until you have the common ancestor:
require dirname(dirname(__DIR__)) . '/b/common.php';
The magic constant __DIR__ equals dirname(__FILE__), and was introduced in 5.3. Each use of dirname() goes back one directory, i.e.:
dirname('public_html/a/class'); // public_html/a
dirname('public_html/a'); // public_html
Btw, editors such as PhpStorm also understand this use of relative paths.
First of all i suggest you to define a variable for basepath and include that defined variable in relative files.
// This should be on any root directory file
define("PR_BASEPATH", dirname(__FILE__));
And according to your implementation, Assume you are in
public_html/a/class/test.php
and dirname(__FILE__) returns the directory name of the current file that always return the directory class according to test.php file.
And you want to include public_html/b/common.php that is on the other directory /b. So you have to get the document root directory first.
include $_SERVER['DOCUMENT_ROOT'] . "/b/common.php";
Take a look on $_SERVER['DOCUMENT_ROOT']
include('../../b/common.php');
would include file for you, make sure both directory have same usergroup as user.

include files from anywhere on the server

I have website running perfectly on production server. I have moved it to another web server. (VPS).
Let me explain you with example:
The directory structure:
includes/
header.php
business/
index.php
some other files...
index2.php
In my previous version, I used
include_once(includes/header.php)
in index.php and index2.php. It runs fine. but in my new server setup it's giving me error regarding path (obvious).
ERROR:
include_once(includes/header.php): failed to open stream: No such file or directory
And because of that:
Fatal error: Class 'EncryptionClass' not found
I think there are some server configurations which I need to do. But, I don't know how?
Please guide me. Let me know if you want more information.
if using PHP 5.3+ Try using:
include_once(__DIR__.'/includes/header.php');
DIR is a magic constant that will return the full directory that the file is in.
You could supply an absolute file system path to the include:
include_once($_SERVER['DOCUMENT_ROOT'] . "/includes/header.php");
I would simply add your includes directory to the include_path. For example, in index2.php
set_include_path(implode(PATH_SEPARATOR, [
__DIR__ . '/includes', // relative to this file, index2.php
get_include_path()
]));
include_once 'header.php';
and similarly in business/index.php...
set_include_path(implode(PATH_SEPARATOR, [
__DIR__ . '/../includes', // relative to this file, business/index.php
get_include_path()
]));
include_once 'header.php';
Personally, I would use PSR-0 file-to-class name mappings and configure an autoloader, eg
includes/EncryptionClass.php
class EncryptionClass { ... }
index2.php
spl_autoload_register(function($class) {
require_once __DIR__ . '/includes/' . $class . '.php';
});
$encryptionClass = new EncryptionClass();

Categories