My file structure:
/holiday/admin/list.php
/holiday/includes/functions.php # common functions
/holiday/index.php
# / is the document root
# /holiday/ is a "self-contained" sub-directory
# There are other "self-contained" sub-directories e.g. /promotion/, /international/
In functions.php I have a common function to generate the <head> part of an HTML; also, a function to return an absolute path from the document root. Note my attempt to calculate /holiday/includes/.
<? function get_path() {
// Technically, this returns dirname(__FILE__) - $_SERVER['DOCUMENT_ROOT']
return str_replace($_SERVER['DOCUMENT_ROOT'], "", dirname(__FILE__));
} ?>
<? function open_page($head = "", $body_id = "") { ?>
<!DOCTYPE HTML>
<html>
<head>
<link type="text/css" rel="stylesheet" href="<? echo get_path() . "/../css/savvyextras.css"; ?>" />
<script type="text/javascript" src="<? echo get_path() . "/../scripts/modernizr.js"; ?>"></script>
...
<? } ?>
functions.php is included this way:
// From list.php
require_once('../includes/functions.php');
open_page(...);
// From index.php
require_once('./includes/functions.php');
open_page(...);
I feel like there must be a more straightforward approach to accomplish the same thing here. Any built-in PHP function for my get_path()? Maybe I should approach my problem differently?
Note:
Some folks suggested using a framework (which is a good thing). But, to help me (and others) understand this whole include-file thing, other non-framework explanations?
Related Discussions:
Absolute Path for Deployment in a Non-Root Location
Including files by relative path
#Siku-Siku.Com, auto-loading classes with __autoload() won't really help your main problem. Besides, you'll only be able to get the most out of __autoload() if you move to a mainly object-oriented design, which will bring its own challenges.
Currently, the most sensible thing to do would be as #hafichuk suggests. Make one main includes file, say my_funcs.inc.php, and include it at the top of every other page you have. The advantage is that by giving special .inc extensions to your include files, you can distinguish them more easily. Plus, you can use that to block these files in Apache for just an added bit of security.
If I could also mention:
1) I think short tags are risky. They encourage bad coding practices and leave the door wide open for porting nightmares. And they encourage bad coding practices.
2) Since require is a statement, not a function, it should be used like:
require 'my_file.inc.php';
With the type of layout that you currently have, your best bet is to have a single includes.php file which holds all of your require_once calls, then use require_once('../includes.php') (or equivalent location) at the top of each of your entry scripts. It's a pain to setup and maintain, but at least it's all in one place.
If you plan on moving towards using objects instead of functions, then I'd take a look at using __autoload().
After experimenting more with this and gathering other inputs, I find using constant will do the trick:
# functions.php
define('PREFIX', '/holiday');
<? function open_page($head = "", $body_id = "") { ?>
<!DOCTYPE HTML>
<html>
<head>
<link type="text/css" rel="stylesheet" href="<?php echo PREFIX; ?>/css/savvyextras.css"; ?>" />
<script type="text/javascript" src="<?php echo PREFIX; ?>/scripts/modernizr.js"; ?>"></script>
...
<? } ?>
So, if you need to move /holiday/ to a different sub-directory e.g. /vacation/, you'd simply need to change one constant i.e. PREFIX.
Related
I'm recently doing a website for a school project. In order to organize my work, I create a tree folder that keeps all the work organized. It is similar like this:
Back-Office
Pages
Home
home_test1.php
home_test2.php
home_test3.php
Login
Folder_Login
login.php
logout.php
Resources
CSS
style_home.css
style_navbar.css
style_footer.css
JS
script_home.css
script_navbar.css
Sections
navbar.php
footer.php
After all, with the require() method available in PHP, I want to call the "navbar.php" file to the "home_test1.php", "home_test2.php" and "home_test3.php", but the CSS style that is connected with the file "navbar.php" ("style_navbar.php"), doesn't display.
I've tried to change the path of the CSS style in the file "navbar.php" when I require() to the other file ("home_test1.php") and the CSS style shows up, but wont display in other file with a different path. How can I make this work dynamically? Sorry for long post and bad English grammar.
Thank you in advance.
You need to set your css and js files with absolute path instead of relative path
$dir = realpath($_SERVER["DOCUMENT_ROOT"]);
<link rel="stylesheet" href="<?php echo $dir.'/resources/css/style_home.css'; ?>" >
Without physically seeing you code it is quite hard to debug however there is an "obvious" answer that I'll suggest as a starting point.
The important thing to remember is that PHP and HTML are processed in completely different places. PHP executes on the server and should be used to build a full HTML "document" which it gives to the client/browser. The client/browser then reads the document provided and renders it according to HTML standards.
Calling require() will tell PHP to get the file and slot its contents directly where it was called and as it is a CSS file it will need to sit within the style tags. With a lot of modern browsers, if you use require on a file outside of the html tags, the content will be dumped at the top of the screen or simply ignored due to invalid syntax.
Alternatively if you would like to simply use tell the browser to include the CSS file, you could use the good old method of using <link rel="stylesheet" href="/path/to/file">. It's good to know when and when not to use PHP.
PS: You have .css files in your JS directory.
In PHP, there is a global variable containing various details related to the server. It's called $_SERVER. It contains also the root:-
$_SERVER['DOCUMENT_ROOT']
<?php
$path = $_SERVER['DOCUMENT_ROOT'];
<link rel="stylesheet" href="<?php echo $path.= '/Resources/CSS/style_navbar.css';?>" />
?>
all.
My question is in regards to a problem I'm encountering when trying to add a universal php template for my DOCTYPE section. My DOCTYPE include (aptly entitled doctype.php) lies within the /template directory, and also includes calls pointing to my CSS and JS files that I want to be accessible to all pages.
So the problem is encountered when I try to write the absolute path to these files (the CSS and JS files). Currently, I am trying:
<script type="text/javascript" src="<?php echo $_SERVER['DOCUMENT_ROOT'] . '/file/extension/to/javascript/file.js'; ?>"></script>
and
<link rel="stylesheet" type="text/css" href="<?php echo $_SERVER['DOCUMENT_ROOT'] . 'file/extension/to/css/file.css'; ?>"
I am running the application through WAMP on my localhost.
Taking a look a look at the source code, it appears as though the links are pointing to the appropriate files (c:/wamp/www/examplesite/path/to/file/file.ext), and all should be well. BUT it is not...
The JavaScript is not accessible and the Stylesheet is not functioning. I'm at a loss for what to do.
I've also tried:
-writing the absolute path without the use of PHP
-creating PHP variables to hold the document root and then concatenating the appropriate directory path to access the files.
Any suggestions? And how will this change when I upload the directory structure to my online server vs. my current localhost?
You might want to try $_SERVER['HTTP_REFERER'] instead. It gives you the path you are looking for.
On my local machine, which uses WAMP, I used <?php print_r($_SERVER); ?> to see what values it gives.
Also, there may be some typos in the snippets. For example, you don't need the leading / in the first example you gave.
For example:
<script type="text/javascript" src="<?php echo $_SERVER['HTTP_REFERER'] . 'file/extension/to/javascript/file.js'; ?>"></script>
<link rel="stylesheet" type="text/css" href="<?php echo $_SERVER['HTTP_REFERER'] . 'file/extension/to/css/file.css'; ?>"></link>
Or since HTTP_REFERER can't be trusted in some case, you may want to create a function that builds the base part of the absolute path.
<?php
function getAddress() {
$protocol = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http';
$filenamepattern = '/'.basename(__FILE__).'/';
return $protocol.'://'.$_SERVER['HTTP_HOST'].preg_replace($filenamepattern,"",$_SERVER['REQUEST_URI']);
}
?>
Then call it like so:
<script type="text/javascript" src="<?php echo getAddress() . 'file/extension/to/javascript/file.js'; ?>"></script>
<link rel="stylesheet" type="text/css" href="<?php echo getAddress() . 'file/extension/to/css/file.css'; ?>"></link>
You're pointing to files on your local machine using the file path (ex: C:\some\path\to\file) when you should be using a URL (ex: http://localhost/some/path/to/file). The HTML is parsed by the client's browser so when it attempts to access a path that isn't a URL it can't.
Instead of using $_SERVER['DOCUMENT_ROOT'] you can either use absolute URLs such as
<script type="text/javascript" src="/path/to/my/file.js"></script>
where the "/path" folder is your base web directory, or you can use relative URLs based on whatever the current directory the file is in to which you're including the doctype.php file. I'd recommend not doing the latter as it's a pain in the butt to keep track of.
If you use relative URLs you should have no problems when moving your code to a new host, provided the directory structure remains the same.
Of course any kind of resource (JS, CSS, Images, etc.) has to be accessed via http(s) request and therefore it is impossible to directly access them with an absolute path. Think of the security implications of such an approach. So you always have to use web paths relative to your web root directory.
For example:
<script type="text/javascript" src="http://localhost/myproject/media/ja/file.js"></script>
You're going about the wrong way of including files in your page, you should be using HTTP URLS instead:
<script type="text/javascript" src="/file/extension/to/javascript/file.js"></script>
Or, if you prefer to use a variable with the host name:
<script type="text/javascript" src="http://<?php echo $_SERVER['HTTP_HOST']; ?>/file/extension/to/javascript/file.js"></script>
I created a custom PHP templating system and the way I built it seems, well, inefficient. The three main goals for my template was to:
Pull all site-wide HTML elements from a template.tpl include.
Be able to dynamically assign content in the template.tpl (like <title> or <script>)
Be as efficient and scalable as possible.
In the end, my template system looked something like this:
randomPage.php
<?php
// declare any page specific resources
$pageTitle = "Random Sub-Title";
$pageResources = "/css/someRandomCSS.css"
$pageContent = "/randomPage.tpl"
// include the generic page template
include dirname($_SERVER['DOCUMENT_ROOT']).'/includes/template.tpl'
?>
randomPage.tpl
<h1><?=$pageTitle?></h1>
<p>Some random page's content</p>
template.tpl
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Site -- <?=$pageTitle?></title>
<link href="/css/styles.css" rel="stylesheet" type="text/css">
<link href="<?=pageResources?>" rel="stylesheet" type="text/css">
</head>
<body>
<? include $pageContent ?>
</body>
</html>
The main problem with this system is that for every web page, I need to manage two files: one for logic/data and the other for the page template. This seems largely inefficient to me, and doesn't seem like a very scalable approach.
Recently, I come across the smarty framework, which would allow me to consolidate my system from randomPage.php and randomPage.tpl into something like:
randomSmartyPage.php
{extends file="template.tpl"}
{block name=pageTitle}My Page Title{/block}
{block name=pageResources}
<link href="/css/someRandomCSS.css" rel="stylesheet" text="text/css">
{/block}
{block name=pageContent}My HTML Page Body goes here{/block}
Seeing this approach raised three major questions for me:
Are there any fundamental flaws with how I am approaching my templating system?
Can my original php code be refactored so I don't have to create two files for every web page?
Would using the smarty (or perhaps an alternative framework) be a good idea in this case?
Your code isn't really using any templating engine besides PHP itself, which is fine. A flaw I can see is your template will have access to all variables, and the ones you create for it are all global.
Two files is a good system, one to change what is preprocessed and passed to the view, and one for the view itself, containing HTML or whatever. This allows you to easily swap views, for example, a view for standard browsing and a mobile view for mobile browsers.
It can be a good idea, but I'm a firm believer that using PHP is good enough.
Here is an example, untested. It will encapsulate all the variables so you don't pollute the global namespace.
index.php
function view($file, $vars) {
ob_start();
extract($vars);
include dirname(__FILE__) . '/views/' . $file . '.php';
$buffer = ob_get_contents();
ob_end_clean();
return $buffer;
}
echo view('home', array('content' => Home::getContent()));
views/home.php
<h1>Home</h1>
<?php echo $content; ?>
The approach you are describing is part of MVC design pattern. Separating the different aspects of your application.
What you seem to have already understood is that PHP is a templating system in itself as have many others before you.
Take a look at this benchmark for a rough comparison of popular template systems.
Update 2022.08.29
Updated broken links to archived versions.
Note: The answer remains valid if you're trying to learn the language. But for anything serious, consider using a framework.
I'm rather new to PHP programming but I thought I'd do it right from the beginning, so I came across this fine pdf Web Performance Boot Camp where he suggests:
All sites should always prepare for CDNized static content
and this is how:
<img src=”<?php echo CDN(‘/i/left-menu-background.gif’) ?>”
etc., he also gave an example of how the CDN function? should look like:
sub CDN { return #_[1]; }
or (when you finally have your static content on a CDN)
sub CDN { return ‘http://s.company.net’ . #_[1]; }
(but that's not valid php, right? it looks more like perl...)
Anyway, this goes on with how to rewrite the header like:
<link type="text/css" rel="stylesheet" href="<?php echo $this->CDN("c/".$this->css_file) ?>" />
But honestly, I have no idea how to do it right. So, my question is, how to I prepare my (php) site for a CDN? Where do I put the sub CDN function? How should it look in valid php? How/Where do I include it? Do I have to put a
<?php require('../cdn.php'); ?>
at the beginning of every html/php file I create (that uses scripts/css/static images/etc.)? Thanks for reading this.
If you're expecting to use a CDN in the future, this is not a stupid idea.
A simple function would look like this:
function getURL($url) // Name it whatever you want
{
// Choose one of the following:
return $url; // If you're local
return "http://s.company.net/".$url; // If you're on a CDN or static server
}
and the markup:
<link type="text/css" rel="stylesheet" href="<?php echo getURL("c/".$this->css_file) ?>" />
Do I have to put... at the
beginning of every html/php file I
create (that uses scripts/css/static
images/etc.)?
Yes. It might be wise to include some sort of central bootstrap file (some frameworks call it bootstrap.php) for future shared PHP settings that you may need to introduce. That bootstrap file would then, in turn, include the cdn.php.
I'm new to PHP and I'm having a problem when trying to link my CSS files using include.
Basically I need my files to link back to a certain directory no matter how far down the file is. I have tried using
<?php
include $_SERVER['DOCUMENT_ROOT'] . '/sysprogs/required/header.html';
?>
But header.html contains the links to my css files so the directory it ends up looking for the css files in is
http://localhost/SysProgs/software/CSS/style.css
instead of where I want it to go to which is
http://localhost/SysProgs/required/CSS/style.css
I hope that made sense and I hope you can help me
Thankyou for all your help everyone!
I would definitely not use <base>. I've run into many problems with this before. If you use <base>, ALL of your links will become relative to that base value.
Instead, I would recommend setting PHP constants for common directories. For example:
PHP Code:
<?php
define('CSS_DIR', '/SysProgs/required/CSS/');
?>
HTML Code:
<link href="<?php echo CSS_DIR ?>style.css" rel="stylesheet" type="text/css" />
One Idea
Use the full URL in header.html. This will be unambiguous and robust.
<head>
<link href="/FULL_BASE_URL/style/style.css" rel="stylesheet" type="text/css" />
</head>
Another Idea
Use the <base> header tag. This allows you to specify a base URL for links, including CSS, and may require the least work in the short term (see note below).
<head>
<base href="FULL_BASE_URL" />
<link href="style/style.css" rel="stylesheet" type="text/css" />
</head>
More at w3schools
Note: As is noted in the comments below base may ultimately cause more confusion than it is worth.
I like to define both an absolute path and a webroot in a central place in your application:
<?php
define("APP_WEBROOT", "/myapp");
define("APP_ROOTDIR", "/home/www/example.com/htdocs/myapp");
?>
you can then "absolutize" the correct links like so:
<?php echo APP_WEBROOT; ?>/software/CSS/style.css
I prefer this
over <base> because that tag creates confusion and makes code harder to maintain in the long run
over using absolute paths /software/CSS/style.css because those make you unable to install your application in a subdirectory of your choice: You will always be bound to the root directory.
I run into this problem a lot when designing sites. When I have custom CMS, I use the following:
$basedir = "root_directory/";
$basedirPHP = $_SERVER['DOCUMENT_ROOT'].$basedir;
$basedirHTML = "http://".$_SERVER['SERVER_NAME'].$basedir;
I define $basedir so I can move the site to different subdirectories in the server without any effort. The $basedirPHP and $basedirHTML are so I can call on files either with php, or like you mentioned, when linking CSS, JS, etc.
If you're on wordpress, just use the good ol' bloginfo('template_directory'); to do the same in template files.
The first thing for you to understand, is your question has nothing PHP related. It is as simple as just filenames in your HTML questuon. Without PHP it will remain the same. Just use absolute path to your CSS file
And another thing to think of: consider to accept some questions.