Php прописать путь к файлу

Обновлено: 07.07.2024

realpath() раскрывает все символические ссылки, переходы типа /./ , /../ и лишние символы / в пути path , возвращая канонизированный абсолютный путь к файлу.

Список параметров

Замечание:

Несмотря на то, что путь должен быть указан, переданное значение может быть пустой строкой. В этих случаях значение интерпретируется как текущая рабочая директория.

Возвращаемые значения

realpath() возвращает false при неудаче, например, если файл не существует.

Замечание:

Запускаемый скрипт должен иметь права запуска на всех директориях в проверяемой иерархии, иначе realpath() вернёт false .

Замечание:

Для регистронезависимых файловых систем, realpath() может нормализовать или не нормализовать регистр символов.

Замечание:

Функция realpath() не будет работать с файлом внутри архива Phar, так как путь может быть не реальным, а виртуальным.

Замечание:

В Windows переходы и символические ссылки на каталоги расширяются только на один уровень.

Замечание: Так как тип integer в PHP является целым числом со знаком, и многие платформы используют 32-х битные целые числа, то некоторые функции файловых систем могут возвращать неожиданные результаты для файлов размером больше 2 Гб.

Примеры

<?php
chdir ( '/var/www/' );
echo realpath ( './../../etc/passwd' ) . PHP_EOL ;

echo realpath ( '/tmp/' ) . PHP_EOL ;
?>

Результат выполнения данного примера:

На Windows realpath() изменит пути стиля Unix на стиль Windows.

<?php
echo realpath ( '/windows/system32' ), PHP_EOL ;

echo realpath ( 'C:\Program Files\\' ), PHP_EOL ;
?>

Результат выполнения данного примера:

Смотрите также

  • basename() - Возвращает последний компонент имени из указанного пути
  • dirname() - Возвращает имя родительского каталога из указанного пути
  • pathinfo() - Возвращает информацию о пути к файлу

User Contributed Notes 15 notes

Because realpath() does not work on files that do not
exist, I wrote a function that does.
It replaces (consecutive) occurences of / and \\ with
whatever is in DIRECTORY_SEPARATOR, and processes /. and /.. fine.
Paths returned by get_absolute_path() contain no
(back)slash at position 0 (beginning of the string) or
position -1 (ending)
<?php
function get_absolute_path ( $path ) $path = str_replace (array( '/' , '\\' ), DIRECTORY_SEPARATOR , $path );
$parts = array_filter ( explode ( DIRECTORY_SEPARATOR , $path ), 'strlen' );
$absolutes = array();
foreach ( $parts as $part ) if ( '.' == $part ) continue;
if ( '..' == $part ) array_pop ( $absolutes );
> else $absolutes [] = $part ;
>
>
return implode ( DIRECTORY_SEPARATOR , $absolutes );
>
?>

A test:
<?php
var_dump ( get_absolute_path ( 'this/is/../a/./test/.///is' ));
?>
Returns: string(14) "this/a/test/is"

As you can so, it also produces Yoda-speak. :)

realpath() is just a system/library call to actual realpath() function supported by OS. It does not work on a path as a string, but also resolves symlinks. The resulting path might significantly differs from the input even when absolute path is given. No function in this notes resolves that.

The suggestion on the realpath man page is to look for an existing parent directory. Here is an example:
<?php
function resolvePath ( $path ) if( DIRECTORY_SEPARATOR !== '/' ) $path = str_replace ( DIRECTORY_SEPARATOR , '/' , $path );
>
$search = explode ( '/' , $path );
$search = array_filter ( $search , function( $part ) return $part !== '.' ;
>);
$append = array();
$match = false ;
while( count ( $search ) > 0 ) $match = realpath ( implode ( '/' , $search ));
if( $match !== false ) break;
>
array_unshift ( $append , array_pop ( $search ));
>;
if( $match === false ) $match = getcwd ();
>
if( count ( $append ) > 0 ) $match .= DIRECTORY_SEPARATOR . implode ( DIRECTORY_SEPARATOR , $append );
>
return $match ;
>
?>

The result will retrieve absolute path for non-existing relative path. Even if a path does not exists, there should be existing directory somewhere, for which the realpath could be obtained. If this is not within the relative path (i.e. even current working directory does not exists), getcwd() will retrieve absolute path, so some absolute path is returned (although in that case the PHP process could have huge problems).

namespace MockingMagician \ Organic \ Helper ;

$absolutes = [];
foreach ( $subPaths as $subPath ) if ( '.' === $subPath ) continue;
>
// if $startWithSeparator is false
// and $startWithLetterDir
// and (absolutes is empty or all previous values are ..)
// save absolute cause that's a relative and we can't deal with that and just forget that we want go up
if ( '..' === $subPath
&& ! $startWithSeparator
&& ! $startWithLetterDir
&& empty( array_filter ( $absolutes , function ( $value ) < return !( '..' === $value ); >))
) $absolutes [] = $subPath ;
continue;
>
if ( '..' === $subPath ) array_pop ( $absolutes );
continue;
>
$absolutes [] = $subPath ;
>

return
(( $startWithSeparator ? DIRECTORY_SEPARATOR : $startWithLetterDir ) ?
$startWithLetterDir . DIRECTORY_SEPARATOR : ''
). implode ( DIRECTORY_SEPARATOR , $absolutes );
>

/**
* Examples
*
* echo Path::getAbsolute('/one/two/../two/./three/../../two'); => /one/two
* echo Path::getAbsolute('../one/two/../two/./three/../../two'); => ../one/two
* echo Path::getAbsolute('../.././../one/two/../two/./three/../../two'); => ../../../one/two
* echo Path::getAbsolute('../././../one/two/../two/./three/../../two'); => ../../one/two
* echo Path::getAbsolute('/../one/two/../two/./three/../../two'); => /one/two
* echo Path::getAbsolute('/../../one/two/../two/./three/../../two'); => /one/two
* echo Path::getAbsolute('c:\.\..\one\two\..\two\.\three\..\..\two'); => c:/one/two
*
*/
>

Needed a method to normalize a virtual path that could handle .. references that go beyond the initial folder reference. So I created the following.
<?php

function normalizePath ( $path )
$parts = array(); // Array to build a new path from the good parts
$path = str_replace ( '\\' , '/' , $path ); // Replace backslashes with forwardslashes
$path = preg_replace ( '/\/+/' , '/' , $path ); // Combine multiple slashes into a single slash
$segments = explode ( '/' , $path ); // Collect path segments
$test = '' ; // Initialize testing variable
foreach( $segments as $segment )
if( $segment != '.' )
$test = array_pop ( $parts );
if( is_null ( $test ))
$parts [] = $segment ;
else if( $segment == '..' )
if( $test == '..' )
$parts [] = $test ;

if( $test == '..' || $test == '' )
$parts [] = $segment ;
>
else
$parts [] = $test ;
$parts [] = $segment ;
>
>
>
return implode ( '/' , $parts );
>
?>

Will convert /path/to/test/.././..//..///..///../one/two/../three/filename
to ../../one/three/filename

С помощью функции file_get_contents() можно получить содержимое файла:

Также мы можем получить html-код какой-либо страницы в интернете:

Но работает это далеко не для всех сайтов, у многих есть защита от такого примитивного парсинга.

Чтение файла: file()

Функция file() позволяет получить содержимое файла в виде массива. Разделителем элементов является символ переноса строки.

Создадим в корне сайта файл data.txt со следующим содержимым:

Теперь запустим скрипт index.php со следующим кодом:

При запуске этого скрипта мы получим в браузере:

Заметили, что у первых двух строк длина 7 символов вместо пяти? Это из-за того, что каждая строка содержит в конце символы переноса строки.

Чаще всего они нам не нужны, поэтому их можно убрать, передав вторым параметром константу FILE_IGNORE_NEW_LINES :

Теперь у всех строк будет по 5 символов.

Если нам необходимо получить только заполненные строки в файле и пропустить пустые, можно передать вторым параметром константу FILE_SKIP_EMPTY_LINES :

Разумеется, мы можем передать сразу две константы:

Создание файла и запись в файл: file_put_contents()

Функция file_put_contents() позволяет создать файл и заполнить его данными.

Первым параметром функция принимает путь к файлу, вторым - строку с данными. Для создания пустого файла нужно передать вторым параметром пустую строку.

Если файла не существует - он будет создан. Если существует - данные в файле будут перезаписаны.

Чтобы не перезаписывать данные, а добавить их в конец файла, нужно передать третьим параметром константу FILE_APPEND :

Также вторым параметром можно передать массив:

Но этот вариант не очень удобен, поскольку все элементы массива запишутся подряд, без каких-либо разделителей. Чтобы их добавить, можно использовать функцию implode:

Создание папки или структуры папок

Создать папку можно с помощью функции mkdir() (make directory):

Вторым параметром указываются права доступа к файлу в виде восьмеричного числа, по-умолчанию это 0777 , что означает самые широкие права. Для Windows этот аргумент игнорируется.

Кроме этого, второй параметр может игнорироваться при заданной umask (пользовательская маска (user mask), которая нужна для определения конечных прав доступа). В этом случае принудительно сменить права можно функцией chmod() :

Также мы можем создать структуру папок рекурсивно, для этого нужно третьим параметром передать true :

Но в этом случае права доступа будут заданы только для конечной папки. Для изменения прав у каждой из папок придётся указывать права вручную:

Права доступа - это отдельная объёмная тема, поэтому сейчас мы её пока рассматривать не будем.

Проверка существования файла или папки

Проверить существование папки или файла можно с помощью функции file_exists() :

Если вы хотите проверить существование только папки или только файла, для этого есть специальные функции is_dir() и is_file() :

Проверка прав доступа

Функции is_readable() и is_writable() проверяют, есть ли у пользователя, от имени которого запущен PHP, права на чтение и запись файла или папки:

Копирование, перенос и удаление файла

Для удаления файлов используется функция unlink() :

Чтобы скопировать файл, используем функцию copy() :

Для переименования и переноса файла в другую папку используется функция rename() :

Работа с файлами с помощью fopen()

Функций file() , file_get_contents() и file_put_contents() достаточно для решения большинства задач, связанных с управлением файлами.

Но иногда возникают ситуации, когда нам необходимы более продвинутые инструменты. Например, если у нас есть большой текстовый файл и мы хотим читать его построчно, а не весь сразу, для экономии оперативной памяти.

Итак, открыть (или создать и открыть) файл можно с помощью функции fopen() :

Функция fopen() возвращает так называемый лескриптор. Это ссылка, указатель на файл, его мы будем передавать в другие функции. Кстати, тип данных этого дескриптора - resource .

Первым параметром мы передаём путь к файлу, вторым - модификатор доступа к файлу. Ниже перечислены наиболее популярные модификаторы:

  • r - открытие для чтения, указатель переходит в начало файла.
  • r+ - открытие для чтения и записи, указатель переходит в начало файла.
  • w - открытие для записи, указатель переходит в начало файла. Если файла нет - создаётся, если есть - очищается от данных.
  • w+ - открытие для чтения и записи, в остальном аналогичен w .
  • a - открытие для записи, указатель переходит в конец файла. Если файла нет - создаётся.
  • a+ - открытие для чтения и записи, в остальном аналогичен a .
  • x - создание и открытие для записи, указатель переходит в начало файла. Если файл существует - PHP покажет ошибку.
  • x+ - создание и открытие для чтения и записи, в остальном аналогичен x .

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

Для записи данных в файл существует функция fwrite() . Давайте попробуем создать файл и записать в него какие-нибудь данные:

Заметьте, из-за модификатора w при каждом запуске скрипта данные в файле стираются и добавляются заново. Если модификатор заменить на a , данные будут не перезаписываться, а добавляться в конец файла.

Для построчного чтения файла используется функция fgets() :

При каждом запуске fgets получает следующую строку и возвращает её в $line . Вторым параметром передаётся максимальная длина строки. Это означает, что если строка слишком длинная, она будет обрезана.

Также в PHP существует множество других полезных функций, работающих с дескриптором файла. Почитать о них можно в документации.

Пути к файлам - тема, которая обычно взрывает мозг новичкам. Но не волнуйся, сейчас мы всё расставим по полочкам.

Чем отличаются пути в PHP и URL

Когда мы смотрим любимый фильм или сериал, мы видим только готовый продукт.

А за кадром существует совсем другой, невидимый для нас мир: стилисты и гримёры, искусственные декорации, наложение спецэффектов и многое другое.

В PHP существует такое же разделение. С одной стороны - реальная файловая система с реальными папками и файлами, с другой - URL адреса, которые могут не иметь ничего общего с реальной файловой структурой.

Если ты видишь на каком-нибудь сайте страницу с URL /category/monitors - это совсем не значит, что на сайте есть скрипт /category/monitors/index.php .

Вполне вероятно, что и такой папки там тоже нет, а все URL адреса обрабатываются одним единственным PHP файлом.

И даже если в URL присутствует расширение файла, например /about.html - это тоже не говорит о существовании файла about.html . Может он есть, а может и нет.

Новички часто путают пути к реальным файлам с URL адресами. Сейчас я разберу пару таких ошибок, на примере которых можно будет прочувствовать разницу.

Ошибка №1: Подстановка физического пути в URL

Очень частая ошибка новичков - пытаться подставить в URL адрес ссылку на физический файл, вроде такого:

Это неправильно. Браузер не может видеть реальную файловую структуру сервера. Он не видит никаких дисков D, он видит только URL адреса.

Правильная ссылка выглядит так (разницу объясню чуть позже):

Ошибка №2: Подключение скриптов по URL

Иногда новички пытаются подключить физический файл по его URL:

Это неправильно. Во-первых, подключится не сам скрипт, а результат его работы. Во-вторых, подключать какие-то файлы через URL вообще идея очень опасная.

Абсолютный путь в PHP

Абсолютный путь - это полный путь к папке или файлу. Вот пара примеров для разных операционных систем:

Как видите, это полный путь от корня диска до конкретного файла или папки. Начинается со слеша или буквы диска (Windows).

Получить абсолютный путь скрипта можно с помощью магической константы __FILE__ :

Для получения абсолютного пути к папке, в которой находится скрипт, есть магическая константа __DIR__ :

Как этим пользоваться. Допустим, у нас в корне сайта лежат файлы index.php и config.php и мы хотим подключить второй в первый.

Если мы хотим подключить config.php по его абсолютному пути, есть два способа сделать это:

Поскольку константа __DIR__ не добавляет слеш после последней папки, мы указываем его вручную.

Относительный путь в PHP

У относительных путей в PHP есть один подвох - они могут строиться относительно не той папки, от которой мы ожидаем.

Сначала PHP попытается найти этот файл в папках, указанных в директиве include_path. Посмотреть, что указано в этой директиве конкретно у вас можно с помощью var_dump(get_include_path()); , папки разделяются символом ;

Далее PHP попытается найти файл в папке текущего рабочего каталога.

Например, если мы в index.php подключили файл scripts/script.php, а в этом самом script.php уже пытаемся подключить файл по относительному пути, тогда поиск файла произойдёт и в папке scripts тоже.

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

Именно по этой причине я призываю тебя отказаться от использования относительных путей в PHP.

Кому-то из практикующих разработчиков эта фраза может не понравиться, но я считаю это единственным разумным решением.

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

Абсолютный путь в URL

Абсолютный путь в URL означает путь от корня сайта. Корень сайта - это папка, которая содержит публичную часть сайта, т.е. доступную извне.

Относительный путь в URL

Относительные пути в URL указываются без слеша в начале ссылки, например:

Относительные пути в URL более предсказуемы, чем в PHP. Но я рекомендую использовать их только там, где это действительно необходимо.

Чаще всего их использование приводит к путанице. И вот пара типичных проблем, с которыми часто сталкиваются новички.

Ошибка №1: относительные пути к стилям, скриптам и другим файлам

Представим, что мы решили подключить стили к нашему сайту:

Разработчик указывает относительный URL style.css и видит, что всё работает. По крайней мере, на главной странице.

Но при переходе по любой ссылке, например /products/15 , стили перестают работать.

А причина в том, что относительный путь строится от текущего URL-адреса, а значит в нашем примере он из style.css превратился в /products/15/style.css .

Ошибка №2: Рекурсия в ссылках

При использовании относительных путей есть риск случайно создать на сайте бесконечные ссылки. Вот один из таких способов:

Для работы данного кода должна быть настроена единая точка входа.

Текущий и родительский каталоги

Помимо указания конкретных папок, мы также можем добавить в путь указание "перейти на папку выше", например:

В коде выше мы подключим файл config.php, который находится не в текущей папке, а в родительской. С абсолютными путями это тоже работает:

И с URL-адресами тоже:

Также мы можем указать ссылку на текущий каталог, что бывает актуально в некоторых операционных системах:

image

PHP это скриптовый язык, созданный изначально для быстрого ваяния домашних страничек (да, да изначально это же был Personal Home Page Tools), а в дальнейшем на нём уже стали создавать магазины, социалки и другие поделки на коленке которые выходят за рамки задуманного, но к чему это я – а к тому, что чем больше функционала закодировано, тем больше желание его правильно структурировать, избавиться от дублирования кода, разбить на логические кусочки и подключать лишь при необходимости (это тоже самое чувство, которое возникло у вас, когда вы читали это предложение, его можно было бы разбить на отдельные кусочки). Для этой цели в PHP есть несколько функции, общий смысл которых сводится к подключению и интерпретации указанного файла. Давайте рассмотрим на примере подключения файлов:


Если запустить скрипт index.php, то PHP всё это будет последовательно подключать и выполнять:


Когда файл подключается, то его код оказывается в той же области видимости, что и строка в которой его подключили, таким образом все переменные, доступные в данной строке будут доступны и в подключаемом файле. Если в подключаемом файле были объявлены классы или функции, то они попадают в глобальную область видимости (если конечно для них не был указан namespace).

Если вы подключаете файл внутри функции, то подключаемые файлы получают доступ к области видимости функции, таким образом следующий код тоже будет работать:

Отдельно отмечу магические константы: __DIR__ , __FILE__ , __LINE__ и прочие — они привязаны к контексту и выполняются до того, как происходит включение

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


Если у вас в файле только PHP код, то закрывающий тег принято опускать, дабы случайно не забыть какие-нить символы после закрывающего тега, что чревато проблемами (об этом я ещё расскажу в следующей статье).

А вы видели сайт-файл на 10 000 строк? Аж слёзы на глазах (╥_╥)…

Функции подключения файлов

Как уже было сказано выше, в PHP существует несколько функций для подключения файлов:

    — включает и выполняет указанный файл, если не находит — выдаёт предупреждение E_WARNING — аналогично функции выше, но включает файл единожды — включает и выполняет указанный файл, если не находит — выдаёт фатальную ошибку E_ERROR — аналогично функции выше, но включает файл единожды
В действительности, это не совсем функции, это специальные языковые конструкции, и можно круглые скобочки не использовать. Кроме всего прочего есть и другие способы подключения и выполнения файлов, но это уже сами копайте, пусть это будет для вас «задание со звёздочкой» ;)

Давайте разберём на примерах различия между require и require_once , возьмём один файл echo.php:


И будем его подключать несколько раз:


Результатом выполнения будет два подключения файла echo.php:


Существует ещё парочка директив, которые влияют на подключение, но они вам не потребуются — auto_prepend_file и auto_append_file. Эти директивы позволяют установить файлы которые будут подключены до подключения всех файлов и после выполнения всех скриптов соответственно. Я даже не могу придумать «живой» сценарий, когда это может потребоваться.

Где ищет?

PHP ищет подключаемые файлы в директориях прописанных в директиве include_path. Эта директива также влияет на работу функций fopen() , file() , readfile() и file_get_contents() . Алгоритм работы достаточно простой — при поиске файлов PHP по очереди проверяет каждую директорию из include_path , пока не найдет подключаемый файл, если не найдёт — вернёт ошибку. Для изменения include_path из скрипта следует использовать функцию set_include_path().

При настройке include_path следует учитывать один важный момент — в качестве разделителя путей в Windows и Linux используются различные символы — ";" и ":" соответственно, так что при указании своей директории используйте константу PATH_SEPARATOR , например:


Когда вы прописываете include_path в ini файле, то можете использовать переменные окружения типа $ :

Если при подключении файла вы прописываете абсолютный путь (начинающийся с "/") или относительный (начинающийся с "." или ".."), то директива include_path будет проигнорирована, а поиск будет осуществлён только по указанному пути.

Возможно стоило бы рассказать и про safe_mode, но это уже давно история (с версии 5.4), и я надеюсь вы сталкиваться с ним не будете, но если вдруг, то чтобы знали, что такое было, но прошло.

Использование return

Расскажу о небольшом life-hack'е — если подключаемый файл возвращает что-либо с использованием конструкции return , то эти данные можно получить и использовать, таким образом можно легко организовать подключение файлов конфигурации, приведу пример для наглядности:

Занимательные факты, без которых жилось и так хорошо: если во включаемом файле определены функции, то они могут быть использованы в основном файле вне зависимости от того, были ли они объявлены до return или после

Написать код, который будет собирать конфигурацию из нескольких папок и файлов. Структура файлов следующая:


При этом код должен работать следующим образом:

  • если в системном окружении есть переменная PROJECT_PHP_SERVER и она равна development , то должны быть подключены все файлы из папки default, данные занесены в перемененную $config , затем подключены файлы из папки development, а полученные данные должны перетереть соответствующие пункты сохраненные в $config
  • аналогичное поведение если PROJECT_PHP_SERVER равна production (естественно только для папки production)
  • если переменной нет, или она задана неверно, то подключаются только файлы из папки default

Автоматическое подключение

Конструкции с подключением файлов выглядят очень громоздко, так и ещё и следить за их обновлением — ещё тот подарочек, зацените кусочек кода из примера статьи про исключения:


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

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


Файл, который подключает данный класс:


Теперь о проблемах с данной функцией — представьте ситуацию, что вы подключаете сторонний код, а там уже кто-то прописал функцию __autoload() для своего кода, и вуаля:


Чтобы такого не было, создали функцию, которая позволяет регистрировать произвольную функцию или метод в качестве загрузчика классов — spl_autoload_register. Т.е. мы можем создать несколько функций с произвольным именем для загрузки классов, и зарегистрировать их с помощью spl_autoload_register . Теперь index.php будет выглядеть следующим образом:

Рубрика «а вы знали?»: первый параметр spl_autoload_register() не является обязательным, и вызвав функцию без него, в качестве загрузчика будет использоваться функция spl_autoload, поиск будет осуществлён по папкам из include_path и файлам с расширением .php и .inc , но этот список можно расширить с помощью функции spl_autoload_extensions
Теперь каждый разработчик может регистрировать свой загрузчик, главное чтобы имена классов не совпадали, но это не должно стать проблемой, если вы используете пространства имён.
Поскольку уже давно существует такой продвинутый функционал как spl_autoload_register() , то функцию __autoload() уже заявлена как deprecated в PHP 7.1, а это значит, что в обозримом будущем данную функцию и вовсе уберут (Х_х)
  1. Каждая библиотека должна жить в собственном пространстве имён (т.н. vendor namespace)
  2. Для каждого пространства имён должна быть создана собственная папка
  3. Внутри пространства имён могут быть свои подпространства — тоже в отдельных папках
  4. Один класс — один файл
  5. Имя файла с расширением .php должно точно соответствовать имени класса
Полное имя класса Пространство имён Базовая директория Полный путь
\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

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

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

PHP-инъекция

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


Смотришь на код, и так и хочется чего-нить вредоносного туда передать:


Первое, что приходит на ум — принудительно добавлять расширение .php , но в ряде случаев это можно обойти «благодаря» уязвимости нулевого байта (почитайте, эту уязвимость уже давно исправили, но вдруг вам попадётся интерпретатор более древний, чем PHP 5.3, ну и для общего развития тоже рекомендую):

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

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


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

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

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

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


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

Написать скрипт, который позволит подключать php-скрипты из текущей папки по названию, при этом следуют помнить о возможных уязвимостях и не допустить промашек.

В заключение

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

Читайте также: