How to code relative paths in PHP/HTML efficiently and quickly? - php

I've managed to teach myself PHP/PDO/SQL, and yet, I cannot for the life of me figure out how relative paths work in PHP & HTML. I've got a multipage website with a few directories and branches, and I want to be able to create a simple template I can use to make new pages, without having to change the links to my stylesheets and PHP includes every time, depending on directory.
Here's my layout as follows:
MySite (http://localhost/MySite/)
RESOURCES //Not a folder, just here for readability
> serverside > initialize.php
> templates > header.php
footer.php
navuser.php
navmenu.php
> styles > styles.css
> images > variousImages.png
PAGES //Not a folder, just here for readability
> index.php
login.php
register.php
gettingstarted.php
> you > settings > settings.php
> youraccount.php
> yourfavourites.php
Here are the rules of the game: Each page first includes the serverside/initialize.php file (PHP include). Then, each page includes styles/styles.css through a standard HTML href attribute. Each page then includes via PHP both templates/header.php and templates/footer.php, with the former ALSO containing templates/navuser.php, and templates/navmenu.php.
The problem is, if one of the pages is in on a different level (say you/settings/settings.php, for example), then all those includes and hrefs have to change, which seemingly affects the includes inside the includes. It's impossible!
All I want is to be able to specify file names without using true absolute paths so I can have a single template file to duplicate throughout my website if needed - I've looked into __DIR__, __FILE__, $_SERVER['DOCUMENT_ROOT'], casting a variable $dir to act as a document root, but to no success. I don't understand half of what's happening either.
Can anyone shed some light on my situation? I'm essentially looking for a complete explanation of how relative roots/links/files are meant to work in PHP. How do I deal with even more complex directory structures? Again, what should I do? Thanks.

You would usually set a constant containing an absolute path and absolute URL in your index.php file, and then reference them from there on in includes etc.
An example index.php:
<?php
define('ROOT_DIR', __DIR__);
You can then use that constant thereafter:
require ROOT_DIR . '/includes/database.php';
require ROOT_DIR . '/application/controllers/MyController.php';
require ROOT_DIR . '/application/models/MyModel.php';
And so on. Hope this helps.

Related

Dynamically referencing to header and footer in all PHP pages within different directories and sub-directories

UPDATE 1: to have a clear view of what is happening, you can download a snippet of the script from here.
I am working in a new website that has the same header, footer in all PHP pages.
In the header I am referencing to other common files in website that like .css, .js, functions, classes, db connection, and etc.
for instance, the default.css is in /common/stylesheets/
and my header.php and footer.php are in /common/html/ folder
so my header.php file is something like this
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>The Header</title>
<link rel="stylesheet" href="common/stylesheets/default.css">
</head>
<body>
In my website index.php I included the header <?php include('common/html/header.php'); ?> and this is working fine... BUT the problems appear when I include the header in other php pages within other directories or sub directories e.g. /pages/admin/dashboard.php, everything messed up and that page no more linked to the default.css file.
So, what I am looking for is a method or logic where I reference to these common files and folders in every PHP page no matter its location; e.g. site root, a directory in the site root, or a sub-directory... etc...
here is an image of my website root
Your help is highly appreciated...
P.S. I've tried to use some superglobals variables such as $_SERVER[''] in config.inc.php file to define the paths, then I included that file in the header.php. BUT I couldn't figure out which one will dynamically keep referencing to those common folders and files no mater where the PHP page is.
UPDATE 1: to have a clear view of what is happening, you can download a snippet of the script from here.
It is usually a good idea to use fully qualified or absolute URLs to reference your assets:
<link rel="stylesheet" href="http://www.sitenamecom/some/path/to/common/stylesheets/default.css">
Since there are many places where you need the proper URL base to reach the different files, you could define a constant having the web root:
define('WEB_ROOT', 'http://www.sitename.com');
Then you could define other constants to have access to the different parts of the system:
define('WEB_ASSETS', WEB_ROOT . '/common');
So for the style sheet link in your header.php it would be:
<link rel="stylesheet" href="<?php echo WEB_ASSETS; ?>/stylesheets/default.css">
To include files the principle is the same only that in this case you don't work with URLs but with file system's paths. There's not really a dynamic way of solving this, it all goes down to absolute paths.
The problem here is that the tree structure in your local development environment might (and surely won't) match that of your server. So in the configuration file, which is located in your application's root you could define:
define('APP_ROOT', dirname(__FILE__));
Then lets use the admin/index.php file as example:
include '../../../config.inc.php';
include APP_ROOT . '/sitename/common/html/header.php';
The tricky part here is including the configuration. Since, until you do that the APP_ROOT won't be available, relative paths are needed to reach it, and it isn't possible to escape this one; unless you can fully trust the preferred absolute form:
include '/some/path/to/config.inc.php';
Having that leading slash, as I said before, will be a problem if the application is tested in different environments because it is rarely the case that some/path/to is always the same.
This is the usual issue with structures that aren't using index.php for centralization. Maybe you can try adding another include that defines your directories as pseudo-constant and prepending them to your asset urls.
Or you can parse the request url on how deep it is and automatically prepend the needed ../ levels to your assets urls. I've done this for one of my past projects.
I got to warn you though, it's better to solve the root of the issue (lack of centralization) than adding workarounds. It will surely come back to haunt you sooner than you think.
$_SERVER['DOCUMENT_ROOT'] is likely what you are looking for.
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . "/sitename/common/html/header.php");
This should work from any directory. If you want it to be a little more dynamic than typing out "sitename", you can do this:
<?php
$sitename = explode("/", $_SERVER['REQUEST_URI']);
require_once($_SERVER['DOCUMENT_ROOT'] . "/" . $sitename[1] . "/common/html/header.php");
You need to Change your <link rel="stylesheet" href="common/stylesheets/default.css"> to <link rel="stylesheet" href="../../common/stylesheets/default.css">
here is a simple modification in php.ini to include footer.php and header.php for each script
auto_append_file=ABSOLUTE_PATH/footer.php
auto_prepend_file=ABSOLUTE_PATH/header.php
restart your Apache if you are running under easyPhp, xampp,....
Warning : This configuration will be applied in all projects that are executed with the modified PHP
Try <link rel="stylesheet" href="/common/stylesheets/default.css">
Note the leading slash... This directs server to the document root.
I tried it and it works.
My tree:
/var/www/html/
subdir/
body.php
layout/
header.php
footer.php
css/
style.css
header.php
<html>
<head>
<link rel="stylesheet" href="/css/style.css">
</head>
<body>
<p>Header.</p>
<hr>
body.php
<?php
include($_SERVER['DOCUMENT_ROOT'].'/layout/header.php');
echo "Body.<br>";
include($_SERVER['DOCUMENT_ROOT'].'/layout/footer.php');
?>
footer.php
</body>
</html>
style.css
body {
color: red;
}
Viewing http://localhost/subdir/body.php in the browser, I get the expected result: "Header" and "Body" are colored red.
I would store the document root of your website in some define:
define('DOCROOT', $_SERVER['DOCUMENT_ROOT']);
Do this in a PHP file that you include everywhere, preferably in some bootstrap PHP file.
Then you need to prepend your paths with this in your include lines:
<?php include(DOCROOT . "/common/html/header.php"); ?>
Have you also looked at include_once?
Have you tried PHP's set_include_path ?
You can add numerous paths in one set_include_path separating them with a ' :'.
set_include_path('/home/mysite/includes1:/home/mysite/includes2').
PHP.net -> set_include_path
Even without moving to a full front controller (and MVC) setup (which would be good), you are going to save yourself a lot of headaches if you introduce a simple bootstrap-like file.
It's not going to be perfect with your current setup, as your files are including different parts of your system (ie header.php) in various places and sub folders.
Having header load the first output things - i.e. doctype, head and head links etc - is fine in your basic structure, but you have now run into constraints which you cannot work around without making your header.php messy, or including numerous other files before header.php.
In a more solid framework design, the html and doctype outputs are after a lot of other things have been initiated and loaded, to allow control over said html and doctype.
But to help in your case, just load the bootstrap before anything else is loaded/included.
Bootstrap
The bootstrap will load shared resources, and common used data and paths (etc) throughout your application.
You can then add anything else in the bootstrap in the future, if you find a scenario.
A simple example of something in your bootstrap:
bootstrap.php (MUST reside in your root web folder for following constant to work)
// Define root folder
define ('FOLDER_ROOT', __DIR__);
Then throughout your app you can reference that constant (FOLDER_ROOT) to determine the root folder, and work through subfolders as required.
So, using your current setup:
index.php (I presume is in root folder)
include('bootstrap.php');
include(FOLDER_ROOT.'/common/html/header.php');
// Everything else
So then in your bootstrap you can set other things, such as define the default doctype or character encoding, setup error management.
Although you would usually set things like doctype after bootstrap, in a class, the router, some controller, or even a template.
But as you are using common file includes rather than using a more conventional framework design pattern, this way will at least save you some headaches now, and possibly further down the line.
So again in the bootstrap.php:
// Define root folder
define ('FOLDER_ROOT', __DIR__);
// Define CSS folder using root folder constant above
define ('FOLDER_CSS', FOLDER_ROOT.'/common/stylesheets/');
Then in header.php:
echo '<link rel="stylesheet" type="text/css" href="'.FOLDER_CSS.'default.css">';
Sub Folders (ie /admin)
Now in sub folders, such as /pages/admin/dashboard.php etc, you don't have access to these constants, because you are loading your header files and other template like things all separately "across your application".
So it becomes a battle to set your root folder, plus you are now managing it all twice!
You could try loading the root bootstrap file within your admin folder.
So in dashboard.php, something like:
include('/bootstrap.php');
// OR (more likely)
include('../../bootstrap.php');
But this is becoming messy, calling bootstrap in different places, having to call it differently too.
It's not ideal, but it is do-able, in that if you get the bootstrap loaded within your admin area, then you have the root path setup in admin area and so managing other files from your admin files should be easier.
You could try using a new admin specific bootstrap file, eg in /pages/admin/, have adminBootstrap.php.
But then you're setting two different constants for root, and likely more constants to get to your common and css files and folders. It's easy setting your web root path in a file that is in the web root path, and can be tricky (sometimes) setting web root path from another folder.
Stylesheets
You mentioned that using /common/stylesheets/defaults.css (with a preceding slash) doesn't work and causes the source code to show localhost/common/stylesheets/defaults.css.
This would possibly indicate you need to configure your DocumentRoot.
On Linux it's in /etc/apache2/sites-available/, then either the default file, or if you configured your own virtual sites then go into each one.
What is your DocumentRoot set as?
Although if you get the bootstrap working within the admin area this problem might go away, using the constant FOLDER_CSS.
Folder Structure
I also think you should tidy up your folders, as you seem to have separated things into illogical folder names (perhaps logical to you, but will it be when you learn more and come back to it in a year, or another dev tries to use it?).
E.G. I would not know what on earth the folder html is going to contain, as HTML is a protocol, and ultimately your application will serve HTML.
Have a little read into MVC. Don't go into depth as it's a lot of reading/learning, but if you grasp the basics, you can then tidy up your own structure to create your own logical separation of presentation from business a little more logically than it is now.
Front Controller
If instead of using include files, you had a framework, which loads bootstrap and application wide configs, error management, other stuff, then when you come to load your HTML (your header, footer etc), they will have all this application (root folder constants etc) pre-loaded regardless of which sub folder you are trying to load web pages from.
However as you are doing it, you are instead including these things manually whenever you need them in different files, in sub folders.
While you are introducing a small presence of DRY (Don't Repeat Yourself) by having the doctype, head, etc in include files and re-using them, you are still having to repeat yourself with those include files as you re-use them wherever you need them.
Also, what if you wanted to re-style admin differently to the main site? You'd have to include a different header file or a different stylesheet, or just put all code in the same stylesheet.
I'm waffling, but hopefully I'm being clear, and you can see why using header includes is only a small step in the right direction and for small sites. I'm sure you progressed naturally to using those include files from typing out the head/doctype etc in every file.
However now you are trying to break out into other directions, as with your admin area, you can see the constraints and including those same files is becoming harder to manage as your entire application grows.
So if you had a front controller type setup, within your dashboard.php you would have been able to simply used the constants set in the root bootstrap file, and any other sub folder which would be accessed after the core application is loaded.
EG (if using front controller like pattern)
dashboard.php:
include(FOLDER_ROOT.'/common/html/header.php');
I know I've bashed on about front controller already, but a few years back I was at the stage you are now, and moved from having all my files including the header.php, then the page content, then including footer.php, etc, and I instead started using a front controller.
It's really sooo much better!
It is a fair learning curve (with learning curves in all sorts of directions and methods, requirements, etc) and as such will leave it up to you if you want to go further into that.
I now have my own basic MVC front controller system, which I just simply plonk a new file for a new website page into the view/pages folder, and the page can be used immediately in the browser (the system does everything else).

PHP __DIR__ or SCRIPT_ROOT confusion

I'm working ona site and It's becoming more complex with folder structure. I'm sure this is a simple problem for most but I keep getting mixed results.
my folder structure is something like:
Root:
assets
css
js
images
core
init.php
categories
sub category
file.php
includes
header.php
footer.php
and so on.
the init file will be included at the top of every document, excluding the header and footer.
the header and footer are included in every page.
I'd like to achieve something where instead of writing include '../../includes/footer.php' or include '../includes/footer.php' I can just write include '$root. /includes/footer.php' and not need to worry about the links.
The same applies for my nav bar (which is located in the header) if i want to go to index and i'm in a sub folder then it tries to take me to site/subFolder/index.php which doesn't exist. I'd like to use the same idea her and have the nav links as root. file location
Could someone please help? It's killing me and I'm certain it's so simple I'm looking past the obvious.
I've outputted DIR and SERVER_ROOT
I can hash something together using
$bla = $_SERVER['DOCUMENT_ROOT'];//= c:/www
$bla.= "/nameOfMyRootFolder";
but wondering what the best way is as i keep seeing references to DIR
thanks!
$_SERVER['DOCUMENT_ROOT'] is defined in the webserver config and generally doesn't change.
__DIR__ is the directory that the file it is used in resides.
eg: in docroot/includes/header.php __DIR__ == 'docroot/includes' and $_SERVER['DOCUMENT_ROOT'] == 'docroot'
Documentation

PHP Include links

Hello I'm having my first serious go with PHP to create a sample script for my self. It has a basic structure, in my root folder I have:
index.php
core folder (holds most of my php function files)
includes (holders my header.php and footer.php)
sites - (sites has 3 further folders site A, B, C)
CSS
js
All pages are made up by taking a header.php and footer.php from the includes folder and then each page has its own content in the middle. The header.php contains (as well as basic html and links to javascripts stylesheets ect) includes from core folder like so:
include_once '/core/connect.php';
Now these all work great using the index.php which provides links to the 3 different sections of the site, sitea, siteb and sitec.
But when you navigate out of the document root to say /sites/sitea/index.php all those links are now broken.
What is the best way to go about building the links in the header.php section so they are relative site wide no matter which folder you are in?
The idea behind this is that you do only have ONE file for each process.
So process all pages through index.php
index.php would contain, for example,
require('header.php');
include('content.php');
require('footer.php');
That way, it won't break the site if your content doesn't show.
Your index is always loaded from the same path, so header/footer wouldn't change. Just content.
When you're including you want to use a real path, not a relative path...
require_once ($_SERVER['DOCUMENT_ROOT'].'/includes/header.php');
/* something happens here */
require_once ($_SERVER['DOCUMENT_ROOT'].'/includes/footer.php');
The best way is to always use physical path from wherever you are - this way every page that include other page with includes won't get break:
PHP 5.2 and down:
require(dirname(__FILE__) . '/core/connect.php');
PHP 5.3 and above
require(__DIR__ . '/core/connect.php');

Location of "assets" (php, css, jss, ect)

In my root directory I have a bunch of single pages and then the folder "blog" and "assets." For the pages I have a header.php/nav.php/footer.php to call for various css and js.
for example: within the header.php:
<link href="http://beta.rfahaiti.org/assets/css/bootstrap.css" rel="stylesheet">
Then, in the pages I call for: <?php include 'assets/header.php'; ?>
However, this does not seem to be working for any pages within the blog folder -- such as the index.php file in /blog/news/. I assume it's a relative vs absolute link issue but I'm not sure how to fix. Question: what does the php include call need to be for to call for the header.php file?
Thanks!
Try:
<?php include '../assets/header.php'; ?>
or
<?php include '../../assets/header.php'; ?>
depending on your folder structure.
Include paths are relative, try:
<?php include '../assets/header.php'; ?>
You will find the same with HTML document referring to resources e.g CSS.
It is a relative link issue, as you say. For pages two levels deep in /blog/news, you need to go two levels back:
../../assets/header.php
Edit thanks to Juan Sosa for pointing out that what follows is completely wrong.
Alternatively, you could write this:
/assets/header.php
The second approach is cleaner in one sense; however, beware it assumes that your site will always be located at the root of the domain (ie, if it ever got moved to http://beta.rfahaiti.org/theapplication/ or something, then all those type of links would break).

How to use images and php includes across multiple directories?

I am brand new to PHP. I want to use it to include a universal header and footer in an html/jquery site. Currently I am using includes to do this:
<?php include('../includes/footer.php'); ?>
This works fine. Where I encounter a problem is with any images in the header or footer.
An explanation of my file structure:
Root folder: contains index.php and the folders "includes", "img", "php" etc.
php folder: contains gallery.php
includes folder: contains header.php, footer.php
When viewing the index.php all images in the header and footer show properly, but, because they are linked relatively (ex "img/facebook.png"), the do not show in gallery.php. To work they would need a ../ included. But then this would defeat the purpose of a universal header.
Thus I am trying to figure out how to link the images in the includes files in way that is doesn't matter where the php file is located. I have read this thread (which sounds like my problem) but I do not understand any of the answers. I have also read things that suggest $_SERVER['DOCUMENT_ROOT'] .'/folder/';, in conjunction with an echo to display the image. I tried this in my footer.php with this code:
<?php
$path = $_SERVER['DOCUMENT_ROOT'] . '/img/';
$image = ($path . "facebook.png");
echo "<img src=\"$image\" />"; ?>
When I view the page though, I end up with a little torn paper icon instead of my image. I assume this means that the path is incorrect, but I do not know why. facebook.png resides in the img folder. This problem occurs on both index.php and gallery.php.
After this rather long winded explanation (sorry), my mains questions are:
1) How do I get images to show up properly in my includes across multiple directories?
2) If I am going about this in the right way with the echo, what are the possible reasons why it is not working?
Once again, I know nothing about php, so if you could try to make your answers as basic as possible, it would be much appreciated.
Thank you!
Instead of img/facebook.png, add a / before the img/ like this: /img/facebook.png
This says "go to the root, and look for the img folder there. All your images should work fine then. The path of the images are absolute or relative based on the HTML page you're viewing, not which files you use to create it.
Though there's probably not much of reason for a "php" folder - just keep all your pages in the root directory.

Categories