Что такое потоки
В программировании постоянно приходиться работать с различными ресурсами: файлами, сокетами, http-соединениями. У всех есть некий интерфейс доступа, часто несовместимый друг с другом, чтобы устранить данные несоответствия и унифицировать работу с различными источниками данных, начиная с PHP 4.3 были придуманы PHP Streams потоки.
Поток, это передача данных между местами. В данном контексте, местом может быть — файл, ZIP-архив, соединение и даже процесс через командную строку.
Вы должны понимать разницу между открытием файла и открытием веб-страницы, у них обоих есть контент, но это два совершенно разных типа потоковых данных, поэтому для них требуются разные протоколы. Например, мы можем открыть веб-страницу, подключившись к удаленным веб-серверам с помощью HTTP, HTTPS, SSL. Эти протоколы называются потоковыми оболочками, они предоставляют уникальный интерфейс.
Поток stream, это ресурс resource который ведет себя, как источник непрерывной последовательности данных. То есть из потока можно последовательно читать данные, равно как и записывать в него. Также возможно перемещаться в разные позиции внутри потока.
Обертка wrapper, дополнительный код который объясняет потоку особенности работы со специфичными протоколами или кодировками. Например, обертка http знает, как преобразовать URL в HTTP/1.0-запрос для файла на удаленном сервере. Существует множество оберток, как встроенных в PHP изначально, так и дополнительных.
Схема формирования потока
Каждый поток формируется из схемы и цели, в приведенном ниже формате:
схема://цель
Схема это название обертки. Например — file, http, https, ftp, ftps, compress.zlib, compress.bz2, php. На случай, если название обертки не указать, каждая функция, работающая с потоком, имеет свои умолчания, обычно это file://.
Цель зависит от того, какая обертка используется. Для потоков связанных с файловой системой это обычно путь и имя файла. Для сетевых потоков это, как правило, имя хоста с добавлением к нему пути.
Поддерживаемые схемы
file://доступ к локальной файловой системеhttp://доступ к URL-адресам по протоколу HTTP (s)ftp://доступ к URL-адресам по протоколу FTP (s)php://доступ к различным потокам ввода-выводаzlib://сжатые потокиdata://схема Data (RFC 2397)glob://нахождение путей, соответствующих шаблонуphar://PHP архивssh2://Secure Shell 2rar://RARogg://аудио потокиexpect://потоки для взаимодействия с процессами
Потоки PHP
PHP предоставляет несколько разнообразных потоков ввода-вывода, которые позволяют получить доступ к собственным потокам ввода-вывода PHP, к дескрипторам стандартного ввода, вывода и потока ошибок, к временным файловым потокам в памяти и на диске, и фильтрам, которые могут манипулировать другими файловыми ресурсами по мере их считывания или записи.
Потоки PHP имеют функции, которые помогают разработчикам управлять различными ресурсами:
fopen()fwrite()fgets()file_get_contents()
php://stdin, php://stdout, php://stderr
php://stdin, php://stdout и php://stderr позволяют получить прямой доступ к соответствующим потокам ввода или вывода процесса PHP. Поток указывает на копию файлового дескриптора, таким образом, если вы откроете php://stdin и потом закроете его, вы закроете только вашу копию дескриптора. Актуальный поток, на который ссылается STDIN остается неизменным. Обратите внимание, что PHP демонстрировал ошибочное поведение в этом отношении до версии PHP 5.2.1. Рекомендуется просто использовать константы STDIN, STDOUT и STDERR вместо ручного открытия потоков, используя эти обертки.
Поток php://stdin предназначен только для чтения, тогда как php://stdout и php://stderr предназначены только для записи.
php://input
php://input является потоком только для чтения, который позволяет вам читать необработанные данные из тела запроса. В случае POST-запросов предпочтительней использовать php://input вместо $HTTP_RAW_POST_DATA, так как этот метод не зависит от специальных php.ini директив. Кроме того, в тех случаях, где $HTTP_RAW_POST_DATA не заполняется по умолчанию, это потенциально менее затратно для памяти, чем активация директивы always_populate_raw_post_data. php://input не доступен с типом содержимого enctype="multipart/form-data".
До версии PHP 5.6, поток, открытый с php://input может быть прочтен только один раз. Поток не поддерживает операции поиска. Тем не менее, в зависимости от реализации SAPI интерфейса, может быть возможно открыть другой поток php://input и повторить чтение. Это возможно только если тело запроса заранее сохраняется. Это типично для случая с POST-запросом, но не для других методов запросов, таких как PUT или PROPFIND.
php://output
php://output является потоком только для записи, который позволяет вам записать данные в выходной буфер аналогично как это делают функции print и echo.
Дополнительные обертки
Дополнительные обертки можно добавлять либо отдельным скриптом с помощью функции stream_wrapper_register(), либо напрямую из расширения, используя API Working with streams. Добавлять можно произвольное количество оберток, что делает возможности работы с потоками практически безграничными. Посмотреть список зарегистрированных на данный момент оберток можно с помощью функции stream_get_wrappers().
stream_wrapper_register() регистрирует обёртку URL, реализованную в виде PHP-класса, bool stream_wrapper_register ( string $protocol , string $classname [, int $flags = 0 ] ).
Позволяет реализовать собственные обработчики протоколов и потоков для использования со всеми другими функциями файловой системы, такими как fopen(), fread().
<?
$existed = in_array("var", stream_get_wrappers());
if ($existed) {
stream_wrapper_unregister("var");
}
stream_wrapper_register("var", "VariableStream");
$myvar = "";
$fp = fopen("var://myvar", "r+");
fwrite($fp, "line1\n");
fwrite($fp, "line2\n");
fwrite($fp, "line3\n");
rewind($fp);
while (!feof($fp)) {
echo fgets($fp);
}
fclose($fp);
var_dump($myvar);
if ($existed) {
stream_wrapper_restore("var");
}
/*
line1
line2
line3
string(18) "line1
line2
line3
"
*/
Модуль CLI SAPI
Модуль CLI SAPI определяет несколько констант для потоков ввода/вывода для упрощения работы с командной строкой.
Константы, специфичные для модуля CLI SAPI:
STDINуже открытый поток вводаstdin. Он предотвращает необходимость его открывать черезfopen('php://stdin', 'r');STDOUTуже открытый поток выводаstdout. Он предотвращает необходимость его открывать через$stdout = fopen('php://stdout', 'w');STDERRуже открытый поток ошибокstderr. Он предотвращает необходимость его открывать через$stderr = fopen('php://stderr', 'w');