Статьи

Понимание потоков в PHP

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

В руководстве по PHP есть отличное описание потоков:

Потоки были введены в PHP 4.3.0 как способ обобщения файлов, сети, сжатия данных и других операций, которые имеют общий набор функций и применений. В своем простейшем определении поток — это объект ресурса, который демонстрирует поведение в потоке. То есть он может считываться или записываться линейным образом и может быть способен выполнять fseek() в произвольных местах в потоке.

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

Основы Stream

На поток ссылаются как <scheme>://<target> . <scheme> — это имя оболочки, а <target> зависит от синтаксиса оболочки.

Оболочкой по умолчанию является file:// что означает, что мы используем поток каждый раз, когда получаем доступ к файловой системе. Мы можем либо написать readfile('/path/to/somefile.txt') например, либо readfile('file:///path/to/somefile.txt') и получить тот же результат. Если вместо этого мы используем readfile('http://google.com/') то мы говорим PHP использовать обертку потока HTTP.

Как я уже говорил, PHP предоставляет несколько встроенных оболочек , протоколов и фильтров. Чтобы узнать, какие оболочки установлены на нашей машине, мы можем использовать:

 <?php print_r(stream_get_transports()); print_r(stream_get_wrappers()); print_r(stream_get_filters()); 

Моя установка выдает следующее:

  массив
 (
     [0] => tcp
     [1] => UDP
     [2] => unix
     [3] => UDG
     [4] => ssl
     [5] => sslv3
     [6] => sslv2
     [7] => TLS
 )
 массив
 (
     [0] => https
     [1] => ftps
     [2] => compress.zlib
     [3] => compress.bzip2
     [4] => php
     [5] => файл
     [6] => шар
     [7] => данные
     [8] => http
     [9] => ftp
     [10] => почтовый индекс
     [11] => phar
 )
 массив
 (
     [0] => zlib. *
     [1] => bzip2. *
     [2] => convert.iconv. *
     [3] => string.rot13
     [4] => string.toupper
     [5] => string.tolower
     [6] => string.strip_tags
     [7] => конвертировать. *
     [8] => потребляется
     [9] => Дечанк
     [10] => mcrypt. *
     [11] => mdecrypt. *
 ) 

Хороший сет, тебе не кажется?

Кроме того, мы можем написать или использовать сторонние потоки для Amazon S3 , MS Excel , Google Storage , Dropbox и даже Twitter .

Php: // Wrapper

PHP имеет собственную оболочку для доступа к потокам ввода / вывода языка. Существуют базовые оболочки php://stdin , php://stdout и php://stderr которые отображают ресурсы ввода-вывода по умолчанию, и у нас есть php://input , доступный только для чтения, с необработанным тело запроса POST. Это удобно, когда мы имеем дело с удаленными службами, которые помещают полезные данные в тело запроса POST.

Давайте сделаем быстрый тест с использованием cURL:

  curl -d "Hello World" -d "foo = bar & name = John" http: //localhost/dev/streams/php_input.php 

Результат print_r($_POST) в отвечающем скрипте PHP будет:

  массив
 (
     [foo] => бар
     [name] => Джон
 ) 

Обратите внимание, что первый пакет данных недоступен из массива $_POST . Но если вместо этого мы используем readfile('php://input') мы получим:

  Hello World & foo = bar & name = Джон 

В PHP 5.1 были представлены оболочки потока php://memory и php://temp которые используются для чтения и записи временных данных. Как видно из названий, данные хранятся соответственно в памяти или во временном файле, управляемом базовой системой.

Также есть php://filter , мета-оболочка, предназначенная для применения фильтров при открытии потока с помощью функций вроде readfile() или file_get_contents() / stream_get_contents() .

 <?php // Write encoded data file_put_contents("php://filter/write=string.rot13/resource=file:///path/to/somefile.txt","Hello World"); // Read data and encode/decode readfile("php://filter/read=string.toupper|string.rot13/resource=http://www.google.com"); 

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

Потоковые контексты

Контекст — это специфический для потока набор параметров или опций, которые могут изменять и улучшать поведение наших оболочек. Обычный контекст использования — это модификация оболочки HTTP. Это позволяет нам избежать использования cURL для простых сетевых операций.

 <?php $opts = array( 'http'=>array( 'method'=>"POST", 'header'=> "Auth: SecretAuthTokenrn" . "Content-type: application/x-www-form-urlencodedrn" . "Content-length: " . strlen("Hello World"), 'content' => 'Hello World' ) ); $default = stream_context_get_default($opts); readfile('http://localhost/dev/streams/php_input.php'); 

Сначала мы определяем наш массив параметров, массив массивов в формате $array['wrapper']['option_name'] (доступные параметры контекста варьируются в зависимости от конкретной оболочки). Затем мы вызываем stream_context_get_default() которая возвращает контекст по умолчанию и принимает необязательный массив параметров для применения. Оператор readfile() использует эти параметры для извлечения содержимого.

В этом примере содержимое отправляется внутри тела запроса, поэтому удаленный скрипт будет использовать php://input для его чтения. Мы можем получить доступ к заголовкам с помощью apache_request_headers() и получить:

  массив
 (
     [Host] => localhost
     [Auth] => SecretAuthToken
     [Content-type] => application / x-www-form-urlencoded
     [Content-length] => 11
 ) 

Мы изменили параметры контекста по умолчанию, но мы можем создать альтернативные контексты для отдельного использования.

 <?php $alternative = stream_context_create($other_opts); readfile('http://localhost/dev/streams/php_input.php', false, $alternative); 

Вывод

Как мы можем использовать силу потоков в реальном мире? И куда мы можем пойти отсюда? Как мы уже видели, потоки совместно используют некоторые или все функции, связанные с файловой системой, поэтому первое, что приходит мне в голову, это серия виртуальных оболочек файловой системы, которые можно использовать с провайдерами PaaS, такими как Heroku или AppFog, у которых нет настоящей файловой системы. , Без особых усилий мы можем перенести наши приложения из стандартных хостинговых служб в эти облачные сервисы и пользоваться преимуществами. Также — и я покажу в следующей статье — мы можем создавать собственные оболочки и фильтры для наших приложений, которые реализуют пользовательские форматы файлов и кодировку.