Открытие файлов и внешние данные. Потенциальная уязвимость php-скриптов

(PHP 4, PHP 5, PHP 7)

fopen — Открывает файл или URL

Описание

Resource fopen (string $filename , string $mode [, bool $use_include_path = false [, resource $context ]])

fopen() закрепляет именованный ресурс, указанный в аргументе filename , за потоком.

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

Если filename передан в форме "scheme://...", он считается URL"ом и PHP проведёт поиск обработчика протокола (также известного как "обертка") для этой схемы. Если ни одна обёртка не закреплена за протоколом, PHP выдаст замечание, чтобы помочь вам отследить потенциальную проблему в вашем скрипте и затем продолжит выполнение, как если бы filename указывал на обыкновенный файл.

Если PHP установлено, что filename указывает на локальный файл, тогда выполняется попытка открыть поток к этому файлу. Файл должен быть доступен PHP, так что вам следует убедиться, что права доступа на файл это разрешают. Если вы включили безопасный режим или open_basedir , то накладываются дальнейшие ограничения.

Если PHP установлено, что filename указывает на зарегистрированный протокол и этот протокол зарегистрирован как сетевой URL, PHP выполняет проверку состояния директивы allow_url_fopen . Если она выключена, PHP выдаст предупреждение и вызов fopen закончится неудачей.

Замечание :

Список поддерживаемых протоколов доступен в разделе Поддерживаемые протоколы и обработчики (wrappers) . Некоторые протоколы (обертки ) поддерживают контекст и/или опции php.ini . Обратитесь к соответствующей странице с описанием используемого протокола для получения списка опций, которые могут быть установлены. (например, значение php.ini user_agent используется оберткой http ).

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

$handle = fopen ("c:\\folder\\resource.txt" , "r" );
?>

Параметр mode указывает тип доступа, который вы запрашиваете у потока. Он может быть одним из следующих вариантов:

Список возможных режимов для fopen() используя mode
mode Описание
"r" Открывает файл только для чтения; помещает указатель в начало файла.
"r+" Открывает файл для чтения и записи; помещает указатель в начало файла.
"w" Открывает файл только для записи; помещает указатель в начало файла и обрезает файл до нулевой длины. Если файл не существует - пробует его создать.
"w+" Открывает файл для чтения и записи; помещает указатель в начало файла и обрезает файл до нулевой длины. Если файл не существует - пытается его создать.
"a" Открывает файл только для записи; помещает указатель в конец файла. Если файл не существует - пытается его создать.
"a+" Открывает файл для чтения и записи; помещает указатель в конец файла. Если файл не существует - пытается его создать.
"x" Создаёт и открывает только для записи; помещает указатель в начало файла. Если файл уже существует, вызов fopen() закончится неудачей, вернёт FALSE и выдаст ошибку уровня E_WARNING . Если файл не существует, попытается его создать. Это эквивалентно указанию флагов O_EXCL|O_CREAT для внутреннего системного вызова open(2) .
"x+" Создаёт и открывает для чтения и записи; иначе имеет то же поведение что и"x" .
"c" Открывает файл только для записи. Если файл не существует, то он создается. Если же файл существует, то он не обрезается (в отличии от "w" ), и вызов к этой функции не вызывает ошибку (также как и в случае с "x" ). Указатель на файл будет установлен на начало файла. Это может быть полезно при желании заблокировать файл (смотри flock() ) перед изменением, так как использование "w" может обрезать файл еще до того как была получена блокировка (если вы желаете обрезать файл, можно использовать функцию ftruncate() после запроса на блокировку).
"c+" Открывает файл для чтения и записи; иначе имеет то же поведение, что и "c" .

Замечание :

Разные семейства операционных систем имеют разные соглашения относительно окончания строк. Когда вы пишете текст и хотите вставить разрыв строки, вы должны использовать правильные символы (или символ) для вашей операционной системы. Системы семейства Unix используют \n в качестве символа конца строки, системы семейства Windows используют \r\n в качестве символов окончания строки и системы семейства Macintosh используют \r в качестве символа конца строки.

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

Windows предлагает флаг режима текстовой трансляции ("t" ), который автоматически переведёт \n в \r\n во время работы с файлом. И наоборот - вы также можете использовать "b" , чтобы принудительно включить бинарный режим, в котором ваши данные не будут преобразовываться. Чтобы использовать эти режимы, укажите "b" или "t" последней буквой параметра mode .

Так как установка флага трансляции по умолчанию зависит от SAPI и используемой версии PHP, рекомендуем явно задавать указанный флаг из соображений портируемости. Вы должны использовать режим "t" , если вы работаете с текстовым файлом и использовать \n для обозначения конца строки в вашем скрипте, при этом не беспокоясь за читаемость ваших файлов в других приложениях типа "Блокнота". Во всех остальных случаях используйте флаг "b" .

Если вы явно не укажете флаг "b" во время работы с бинарными файлами, вы можете столкнуться со странной порчей ваших данных, включая испорченные файлы изображений и странные проблемы с символами \r\n .

Замечание :

Из соображений портируемости, настоятельно рекомендуется всегда использовать флаг "b" при открытии файлов с помощью fopen() .

Замечание :

Кроме того, из соображений портируемости, также настойчиво рекомендуется переписать старый код, который полагается на режим "t" , чтобы вместо этого он использовал правильные концы строк и режим "b" .

use_include_path

Необязательный третий параметр use_include_path может быть установлен в "1" или TRUE , если вы также хотите провести поиск файла в include_path .

Context

Замечание : Поддержка контекста была добавлена в PHP 5.0.0. Для описания контекстов смотрите раздел Потоки .

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

Возвращает указатель на файл в случае успешной работы, или FALSE в случае ошибки.

Ошибки

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

Список изменений

Примеры

Пример #1 Примеры использования fopen()

$handle = fopen ("/home/rasmus/file.txt" , "r" );
$handle = fopen ("/home/rasmus/file.gif" , "wb" );
$handle = fopen ("http://www.example.com/" , "r" );
$handle = fopen ("ftp://user:[email protected]/somefile.txt" , "w" );
?>

Примечания

Внимание

При использовании SSL, Microsoft IIS нарушает протокол, закрывая соединение без отправки индикатора close_notify . PHP сообщит об этом как "SSL: Fatal Protocol Error" в тот момент, когда вы достигнете конца данных. Чтобы обойти это, вы должны установить error_reporting на уровень, исключающий E_WARNING. PHP версий 4.3.7 и старше умеет определять, что на стороне сервера находится проблемный IIS при открытии потока с помощью обертки https:// и не выводит предупреждение. Если вы используете fsockopen() для создания ssl:// сокета, вы сами отвечаете за определение и подавление этого предупреждения.

Замечание : Когда опция safe mode включена, PHP проверяет, имеет ли каталог, с которым вы собираетесь работать, такой же UID (владельца), как и выполняемый скрипт.

Замечание :

Если вы сталкиваетесь с проблемами во время чтения или записи файлов, и вы используете PHP в виде серверного модуля, убедитесь в том, что процесс сервера имеет доступ к используемым вами файлам и директориям.

Замечание :

Эта функция также может выполниться успешно, в случае если filename является директорией. Если вы не уверены является ли filename файлом или директорией, то вам необходимо воспользоваться функцией is_dir() , до вызова fopen() .

In this chapter we will teach you how to open, read, and close a file on the server.

PHP Open File - fopen()

A better method to open files is with the fopen() function. This function gives you more options than the readfile() function.

We will use the text file, "webdictionary.txt", during the lessons:

AJAX = Asynchronous JavaScript and XML
CSS = Cascading Style Sheets
HTML = Hyper Text Markup Language
PHP = PHP Hypertext Preprocessor
SQL = Structured Query Language
SVG = Scalable Vector Graphics
XML = EXtensible Markup Language

The first parameter of fopen() contains the name of the file to be opened and the second parameter specifies in which mode the file should be opened. The following example also generates a message if the fopen() function is unable to open the specified file:

Example


echo fread($myfile,filesize("webdictionary.txt"));
fclose($myfile);
?>

Run example »

Tip: The fread() and the fclose() functions will be explained below.

The file may be opened in one of the following modes:

Modes Description
r Open a file for read only
w Open a file for write only
a Open a file for write only
x Creates a new file for write only
r+ Open a file for read/write . File pointer starts at the beginning of the file
w+ Open a file for read/write . Erases the contents of the file or creates a new file if it doesn"t exist. File pointer starts at the beginning of the file
a+ Open a file for read/write . The existing data in file is preserved. File pointer starts at the end of the file. Creates a new file if the file doesn"t exist
x+ Creates a new file for read/write . Returns FALSE and an error if file already exists

PHP Read File - fread()

The fread() function reads from an open file.

The first parameter of fread() contains the name of the file to read from and the second parameter specifies the maximum number of bytes to read.

The following PHP code reads the "webdictionary.txt" file to the end:

Fread($myfile,filesize("webdictionary.txt"));

PHP Close File - fclose()

The fclose() function is used to close an open file.

It"s a good programming practice to close all files after you have finished with them. You don"t want an open file running around on your server taking up resources!

The fclose() requires the name of the file (or a variable that holds the filename) we want to close:

$myfile = fopen("webdictionary.txt", "r");
// some code to be executed....
fclose($myfile);
?>

PHP Read Single Line - fgets()

The fgets() function is used to read a single line from a file.

The example below outputs the first line of the "webdictionary.txt" file:

Note: After a call to the fgets() function, the file pointer has moved to the next line.

PHP Check End-Of-File - feof()

The feof() function checks if the "end-of-file" (EOF) has been reached.

The feof() function is useful for looping through data of unknown length.

The example below reads the "webdictionary.txt" file line by line, until end-of-file is reached:

Example

$myfile = fopen("webdictionary.txt", "r") or die("Unable to open file!");
// Output one line until end-of-file
while(!feof($myfile)) {
echo fgets($myfile) . "
";
}
fclose($myfile);
?>

Run example »

PHP Read Single Character - fgetc()

The fgetc() function is used to read a single character from a file.

The example below reads the "webdictionary.txt" file character by character, until end-of-file is reached:

Example

$myfile = fopen("webdictionary.txt", "r") or die("Unable to open file!");
// Output one character until end-of-file
while(!feof($myfile)) {
echo fgetc($myfile);
}
fclose($myfile);
?>

Run example »

Note: After a call to the fgetc() function, the file pointer moves to the next character.

Complete PHP Filesystem Reference

For a complete reference of filesystem functions, go to our complete

16.5K

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

Файлы php

Файлы с расширением php содержат в себе код написанный, на одноименном языке программирования. В отличие от других языков, php является серверным языком программирования. То есть он выполняется на стороне сервера. Поэтому для отладки его кода на клиентской машине должен быть установлен локальный сервер.

Для работы с файлами php используются специальные приложения – программные редакторы. Наиболее распространенными из них являются:

  • Dreamweaver.
  • PHPEdit.
  • Eclipse PHP Development.
При создании сайтов на основе php может потребоваться многократное использование программного кода. В таких ситуациях удобно подключать уже готовые решения, находящиеся в другом файле. Для этого используется конструкция include . Ее синтаксис:

include имя_файла

Пример подключения:

Подключаемый файл:


Подключение файла также возможно с помощью конструкции require . В отличие от include она подключает файл еще до выполнения программного кода. С помощью require в коде возможно лишь одно обращение к этому файлу. При повторном обращении система выдаст сообщение о глобальной ошибке и остановит выполнение программы.

Конструкция include подключает источник лишь во время выполнения программы. Она поддерживает множественное чтение файла php . При возникновении ошибки будет выведено лишь предупреждающее сообщение, а исполнение кода продолжится со следующей строчки.

Открытие и закрытие файлов

В php все операции с файлами осуществляются в несколько этапов:

  • Открытие файла;
  • Редактирование содержимого;
  • Закрытие файла.

Для открытия файла используется функция fopen() . Ее синтаксис:

int fopen(string filename, string mode [, int use_include_path])

Принимаемые аргументы:

  • string filename – имя файла или абсолютный путь к нему. Если путь к файлу не будет указан, то будет произведен его поиск в текущем каталоге. При отсутствии искомого файла система выведет сообщение об ошибке. Пример:

  • string mode – указывает режим открытия файла. Принимаемые аргументом значения:
  • r – файл открыт только для чтения, файловый указатель устанавливается в начале;
  • r+ – файл открыт для чтения и записи;
  • w – создается новый файл только для записи. Если файл с таким именем уже существует, в нем происходит автоматическое удаление всех данных;
  • w+ — создается новый файл для записи и чтения. При существовании такого файла происходит полная перезапись его данных на новые;
  • a – файл открыт для записи. Указатель устанавливается в конце. То есть запись в файл php начнется не с начала, а с конца;
  • a+ – открытие файла в режиме чтения и записи. Запись начнется с конца;
  • b – режим работы с файлом, содержащим в себе двоичные данные (в двоичной системе исчисления). Этот режим доступен только в операционной системе Windows.

Для закрытия доступа к файлу служит функция fclose () . Синтаксис:

int fclose (int file) , где int file – дескриптор сайта, который нужно закрыть.

После каждого чтения или записи файл нужно закрывать этой функцией. Иначе остается открытым поток, созданный для файла. А это ведет к лишнему расходу серверных мощностей.

Пример:

Чтение и запись файлов

Для простого отображения всего содержимого файла идеально подходит функция readfile () . Ее синтаксис:

readfile (string filename) , где string filename – строковое имя фала (не дескриптор ).


Тот же самый файл можно прочитать с помощью функции fpassthru () . Она считывает данные от конечной позиции указателя и до конца файла. Ее синтаксис:

int fpassthru (int file)

Для работы с функцией требуется открытие и закрытие файла. Пример:

Результат аналогичен предыдущему.

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

  • string fgets (int file, int length) – функция считывает строку длиною length . Пример:

  • string fread (int file, int length) – по действию идентична предыдущей.

Для записи текстовых данных в файл существует две идентичные функции:

  • int fputs (int file, string string [, int length ])
  • int fwrite (int file, string string [, int length ])

Функции записывают в файл int file строку string string указанной длины int length (необязательный аргумент ). Пример:

Создание и удаление файлов

Чтобы создать файл php , можно использовать функцию fopen() в режиме доступа «w » или «w+ ». Или функцию touch () . Она устанавливает время изменения файла. При отсутствии элемента с искомым именем он будет создан. Ее синтаксис.

У меня было какое-то время в выходные, поэтому я сделал небольшое исследование по proc_open() на системах * nix.

В то время как proc_open() не блокирует выполнение PHP script, даже если shell script не запускается в фоновом режиме. PHP автоматически вызывает proc_close() после того, как PHP скрипт полностью выполняется, если вы его не вызываете. Итак, мы можем представить, что у нас всегда есть строка с proc_close() в конце script.

Проблема заключается в неочевидном, но логичном прообразе proc_close(). Предположим, что у нас есть script like:

$proc = proc_open("top -b -n 10000", array(array("pipe", "r"), array("pipe", "w")), $pipes); //Process some data outputted by our script, but not all data echo fread($pipes,100); //Don"t wait till scipt execution ended - exit //close pipes array_map("fclose",$pipes); //close process proc_close($proc);

Странно, proc_close(), ожидающий до завершения оболочки script, но наш script был вскоре прекращен. Это происходит потому, что мы закрыли каналы (кажется, что PHP делает это тихо, если мы забыли), так как этот script пытается что-то написать уже несуществующему трубу - он получает ошибку и завершает работу.

Теперь попробуем без труб (ну, будет, но они будут использовать текущий tty без ссылки на PHP):

$proc = proc_open("top -b -n 10000", array(), $pipes); proc_close($proc);

Теперь наш PHP script ждет завершения нашей оболочки script. Мы можем избежать этого? К счастью, PHP порождает сценарии оболочки с помощью

Sh -c "shell_script"

поэтому мы можем просто убить процесс sh и оставить наш script запущен:

$proc = proc_open("top -b -n 10000", array(), $pipes); $proc_status=proc_get_status($proc); exec("kill -9 ".$proc_status["pid"]); proc_close($proc);

Конечно, мы могли бы просто запустить этот процесс в фоновом режиме, например:

$proc = proc_open("top -b -n 10000 &", array(), $pipes); proc_close($proc);

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

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

Сначала создайте файл где-нибудь (/usr/share/gdb_null_descr в моем примере) со следующим содержимым:

P dup2(open("/dev/null",0),1) p dup2(open("/dev/null",0),2)

Он скажет gdb изменить дескрипторы 1 и 2 (ну, как правило, stdout и stderr) для новых обработчиков файлов (/dev/null в этом примере, но вы можете его изменить).

Теперь, последнее: убедитесь, что gdb может подключаться к другим запущенным процессам - по умолчанию это относится к некоторым системам, но, например, на ubuntu 10.10 вам нужно установить /proc/sys/kernel/yama/ptrace _scope на 0, если вы не запускайте его как root.

$proc = proc_open("top -b -n 10000", array(array("pipe", "r"), array("pipe", "w"), array("pipe", "w")), $pipes); //Process some data outputted by our script, but not all data echo fread($pipes,100); $proc_status=proc_get_status($proc); //Find real pid of our process(we need to go down one step in process tree) $pid=trim(exec("ps h -o pid --ppid ".$proc_status["pid"])); //Kill parent sh process exec("kill -s 9 ".$proc_status["pid"]); //Change stdin/stdout handlers in our process exec("gdb -p ".$pid." --batch -x /usr/share/gdb_null_descr"); array_map("fclose",$pipes); proc_close($proc);

edit: Я забыл упомянуть, что PHP не запускает вашу оболочку script мгновенно, поэтому вам нужно немного подождать, прежде чем выполнять другие команды оболочки, но обычно это достаточно быстро (или PHP достаточно медленный), а я "л ленив, чтобы добавить эти проверки к моим примерам.