I have a problem with php include section. In order to fully explain the problem, I created a test page for you.
First I want to show the schema of the files to you. Also you can download the test files from this LINK and you can test it online TEST LINK
As you can see, there is a subfolder in the htdocs
(root) file and all php files in there. Now I'll show you the php code within the file, respectively.
appname/index.php
<?php include_once 'includes/config.php';?> <div class="callPage">Click Here</div> <div id="testBox"></div> <script type="text/javascript"> $(document).ready(function(){ var siteurl = '<?php echo $url;?>'; $("body").on("click",".callPage", function(){ $.ajax({ url: siteurl+'content/test', beforeSend: function() { //Do something }, complete:function(){ //Do something }, success:function(response){ $("#testBox").html(response); } }); }); function LoadPage(){ $.get(siteurl+'content/test', function(data) { $('#testBox').html(data); }); } LoadPage(); }); </script>
appname/content/test.php
<?php include_once 'includes/config.php'; echo $text.'</br>'; echo $worked.'</br>'; ?>
appname/includes/config.php
<?php $url = 'http://localhost:8888/'; $text = 'Well Come! How are you today ?'; $worked = 'It is working :)'; ?>
When you open the TEST LINK, LoadPage();
javascript function will call test.php
in the content file and display it in #testBox
. First you will not see anything in #testBox
from index.php
. Because config.php
can not be included from test.php
.
I know if I change this line include_once 'includes/config.php';
from test.php
like this include_once '/appname/includes/config.php';
then problem will be fix.
But if the pages multiply and, I want to use the files in the root (htdocs or www) folder, I need to delete appname (subfolder name) => include_once 'appname/includes/config.php';
from all files. It will be a big problem when these files multiply.
Actually the question is exactly:
How can we include php files without specifying the full path to the include, when the application's path relative to the
DOCUMENT_ROOT
is variable or unknown andinclude_path
cannot be reliably modified by all application users?
5 Answers
Answers 1
This is sometimes a problem with includes when you're not using the absolute path on the system.
Explanation
Depending on how PHP is running could affect the way include
&require
work, if PHP is running from inside the appname directory it will work fine if php is told it's running inside the appname directory via a connector it's fine. however, if PHP is run for example www-data@/usr/bin/# php /var/www/somesite.com/htdocs/appname/index.php
the path can be broken.
Fix
if you use define("FS_ROOT", realpath(dirname(__FILE__)));
as the first thing other than if ther is a namespace inside index.php you can then use include FS_ROOT."/includes/config.php";
this means file paths are used from the root of the system so it gets evaluated to include "/var/www/somesite.com/htdocs/appname/index.php"
Why this differs
This differs from ROOT_PATH as ROOT_PATH is sometimes set by PHP configuration by web hosts and this could be the problem. as the PHP execution path could be wrong casing the PHP host application to look in the wrong place for includes and requries.
This also means no include
or require
should ever be using ../
as you should know the path from your codebase.
your appname/index.php
<?php define("FS_ROOT", realpath(dirname(__FILE__))); include_once FS_ROOT.'includes/config.php';?> <div class="callPage">Click Here</div> <div id="testBox"></div> <script type="text/javascript"> $(document).ready(function(){ var siteurl = '<?php echo $url;?>'; $("body").on("click",".callPage", function(){ $.ajax({ url: siteurl+'content/test', beforeSend: function() { //Do something }, complete:function(){ //Do something }, success:function(response){ $("#testBox").html(response); } }); }); function LoadPage(){ $.get(siteurl+'content/test', function(data) { $('#testBox').html(data); }); } LoadPage(); }); </script>
your appname/content/test.php
<?php # as this file is loaded directly and is not in the root directory # we apend the dirname result with ../ so realpath can resolve the root directory for this site define("FS_ROOT", realpath(dirname(__FILE__)."../")); include_once FS_ROOT.'includes/config.php'; echo $text.'</br>'; echo $worked.'</br>'; ?>
Ideally, you should go through a bootstrap and .htaccess so you don't have to change redefine the FS_ROOT
in every file loaded.
you can do this by making sure mod_rewrite
is enabled in apache
create file .htaccess
in appname folder
RewriteCond %{REQUEST_URI} \.(php)$ RewriteRule .* bootstap.php [L]
create bootstrap.php
define("FS_ROOT", realpath(dirname(__FILE__))); include_once FS_ROOT.'includes/config.php'; if(file_exists(FS_ROOT.$_SERVER['REQUEST_URI']){ include(FS_ROOT.$_SERVER['REQUEST_URI']); }else{ // 404 }
this means you don't require the include for the config as it's automaticly included before the script for that request is wanted this is just a base outline and is not 100% secure i would recomended reading up on how to use MVC's and how they work it will give you a better understanding of loading files on demand and requiring files.
Answers 2
If the document file paths need to be dynamic you need to use a database. From what I understand you are planning to make the project bigger, and so you need a normalized database to minimize the amount of code written on the server and to keep your data consistent.
You need:
- a parent table for
filePaths
- a parent table for
fileNames
- a parent table for
akas
<== This is because files may have same name in different folders - a parent table for folders
- a mapping table to solve the
akas
-fileNames
-filePaths
-folders
relationships.
I will show on an example from MySQLi
.
With this code you create the tables in MySQL console
or phpmyadmin
:
// Create parent tables create table `fileNames` ( `fileName` VARCHAR(70) NOT NULL, `description` VARCHAR(250) NULL, PRIMARY KEY(`fileName`) ) ENGINE=InnoDB; create table `fileAkas` ( `aka` VARCHAR(100) NOT NULL, `description` VARCHAR(250) NULL, PRIMARY KEY(`aka`) ) ENGINE=InnoDB; create table `filePaths` ( `filePath` VARCHAR(250) NOT NULL, `description` VARCHAR(250) NULL, PRIMARY KEY(`filePath`) ) ENGINE=InnoDB; create table `folderNames` ( `folderName` VARCHAR(250) NOT NULL, `description` VARCHAR(250) NULL, PRIMARY KEY(`folderName`) ) ENGINE=InnoDB; // Create mapping table create table `fileNames_x_fileAkas_x_filePaths_x_folderNames` ( `aka` VARCHAR(100) NOT NULL, `fileName` VARCHAR(70) NOT NULL, `filePath` VARCHAR(250) NOT NULL, `folderName` VARCHAR(250) NOT NULL, PRIMARY KEY (`aka`, `fileName`, `filePath`, `folderName`), FOREIGN KEY (`aka`) REFERENCES `fileAkas` (`aka`) ON UPDATE CASCADE, FOREIGN KEY (`fileName`) REFERENCES `fileNames` (`fileName`) ON UPDATE CASCADE, FOREIGN KEY (`filePath`) REFERENCES `filePaths` (`filePath`) ON UPDATE CASCADE, FOREIGN KEY (`folderName`) REFERENCES `folderNames` (`folderName`) ON UPDATE CASCADE ) ENGINE=InnoDB;
While this piece of code is only to make sure you are not making MyISAM
tables because MyISAM
doesn't have relationship constraints:
ENGINE=InnoDB
Now make a PHP
program to easily add/change the data. Use this as a separate program and upload it to the server only when you need it:
<?php // Database connection $con = mysqli_connect("localhost","my_user","my_password","my_db"); // Function helper function testIfAddedAndInsert($colName, $tableName, $value, $con) { $result = mysqli_query($con, "SELECT ".$colName." FROM ".$tableName." WHERE ".$colName."='".$value."'"); if(mysqli_num_rows($result) == 0) mysqli_query($con, "INSERT INTO ".$tableName." (".$colName.") VALUES ('".$value."')"); } // Call this to add new file function addNewFile($name, $aka, $path, $folderName, $con) { testIfAddedAndInsert('fileName', 'fileNames', $name, $con); testIfAddedAndInsert('fileAka', 'fileAkas', $aka, $con); testIfAddedAndInsert('filePath', 'filePaths', $path, $con); testIfAddedAndInsert('folderName', 'folderNames', $folderName, $con); } // Call this to change a file path function changeFilePath($aka, $path, $con) { testIfAddedAndInsert('filePath', 'filePaths', $path, $con)); mysqli_query($con, "UPDATE `fileNames_x_fileAkas_x_filePaths_x_folderNames` SET `filePath`= '".$path."' WHERE `fileAka`='".$fileAka."' "); } // Call this to change all paths of all files that belong to a certain folder function changeFolderPath($folderName, $path, $con) { testIfAddedAndInsert('folderPath', 'folderPaths', $folderPath, $con)) mysqli_query($con, "INSERT INTO `folderPaths` (`folderPath`) VALUES ('".$folderPath."')"); mysqli_query($con, "UPDATE `fileNames_x_fileAkas_x_filePaths_x_folderNames` SET `filePath`= '".$path."' WHERE `folderName`='".$folderName."' "); } // ... // You can make as many different functions as you want // To populate/change the database example: addNewFile('config.php', 'conf_PHP_IndexPage', './../conf/', 'conf', $con); // or change all the paths of the items in the folder (not counting subfolder items) changeFolderPath('conf', './../../../', $con); // You could use FOR loops with arrays to enter/change big chunks at a time ?>
Then, after populating your database with valid information, add this to every one of your main PHP
files (the files that are including others):
<?php // Database connection $con = mysqli_connect("localhost","my_user","my_password","my_db"); // Function returns path of file from database function returnPathToFile($fileAka, $con) { $result = mysqli_query($con, "SELECT fileName, filePath FROM fileNames_x_fileAkas_x_filePaths_x_folderNames WHERE fileAka='".$fileAka."'"); if(mysqli_num_rows($result) > 0) { $row = mysqli_fetch_array($result); return $row[1].$row[0]; } return ''; } ?>
And then just call the function to get the result:
<?php $include = returnPathToFile('configFileForTheMainPage', $con); include_once($include); ?>
If any changes occur to the file paths it is easy to change their values, while not having to ever even open the files ever again (for that purpose).
Answers 3
The ROOT_PATH
definition is OK. You could include the path after the definition like:
include ROOT_PATH;
Answers 4
You could use namespaces with PSR. That way you only have to know the top directory. Namespaces aren't tied to the directory stucture. By using PSR you files all files are loaded on call under a base namespace and where called using
use Base\Child
they are called and loaded. If you want to echo something out like you would with an include
or require
just store it in a function to be called from the namespace like this Base\Child\Function()
.
Answers 5
The Test.php is in content folder. If you want to include config.php from includes folder, you must need to do it relatively, so you need to go one level upper.
include '../include/config.php';
This happening because you run the script standalone with ajax, and the folder structure is relative to the test.php.
0 comments:
Post a Comment