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

resource fopen (string filename, string mode [, bool use_include_path [, resource zcontext]])

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

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

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

Замечание: Некоторые протоколы поддерживают context и/или опции php.ini . Обратитесь к соответствующей странице с описанием используемого протокола для получения списка опций, которые могут быть установлены. (например, значение php.ini user_agent используется обвёрткой http). Для получения описания параметров contexts и zcontext , обратитесь к разделу Stream Functions .

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

Замечание: Начиная с версии PHP 4.3.2, бинарный режим является режимом по умолчанию для всех платформ, которые различают бинарный и текстовый, режимы. Если у вас возникли проблемы после обновления, попробуйте использовать флаг "t" в качестве обходного пути до тех пор, пока вы не измените свои скрипты для достижения большей портируемости, как отмечено выше.

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

Если открыть файл не удалось, функция вернёт 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" );
?>

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

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 достаточно медленный), а я "л ленив, чтобы добавить эти проверки к моим примерам.



error: Content is protected !!