Friday, December 22, 2017

Included php files wont work after moved files subfolder

Leave a Comment

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

enter image description here

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 and include_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.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment