Skip to content

Instantly share code, notes, and snippets.

@lcomino
Forked from alganet/php_pratico_streams.md
Created May 31, 2013 01:10

Revisions

  1. Alexandre Gomes Gaigalas revised this gist Feb 21, 2013. 1 changed file with 17 additions and 4 deletions.
    21 changes: 17 additions & 4 deletions php_pratico_streams.md
    Original file line number Diff line number Diff line change
    @@ -36,7 +36,11 @@ Alguns protocolos suportam contextos. Eles são necessários pra trafegar mais i
    $contexto = stream_context_create(array('http' => array(
    'user_agent' => 'My PHP Bot.'
    )));
    $arquivoDoHttp = file_get_contents('http://exemplo.com/my/file.txt', null, $contexto);
    $arquivoDoHttp = file_get_contents(
    'http://exemplo.com/my/file.txt',
    null,
    $contexto
    );

    ```

    @@ -56,14 +60,20 @@ Contudo, no exemplo abaixo, o arquivo nunca vai inteiro para a memória, permiti

    ```php
    <?php
    file_put_contents('/arquivos/salvos/file.txt', file_get_contents('http://example.com/my/file.txt'));
    file_put_contents(
    '/arquivos/salvos/file.txt',
    file_get_contents('http://example.com/my/file.txt')
    );
    ```

    Isso acontece porque se você passa uma função de stream como parâmetro de outra, o PHP automaticamente aplica a função `stream_copy_to_stream`. Você poderia fazer isso manualmente também:

    ```php
    <?php
    stream_copy_to_stream(fopen('http://example.com/my/file.txt', 'r'), fopen('/arquivos/salvos/file.txt', 'w+'));
    stream_copy_to_stream(
    fopen('http://example.com/my/file.txt', 'r'),
    fopen('/arquivos/salvos/file.txt', 'w+')
    );
    ```

    Isso permite que você mexa com arquivos de 2GB tendo apenas 28MB de limite de memória no PHP, porque ele nunca terá o arquivo inteiro na memória, só um pequeno buffer que ele usa pra passar a corrente entre duas streams!
    @@ -97,7 +107,10 @@ Além do `fpassthru`, é possível usar uma stream explícita:
    <?php

    header('Content-Type: image/png');
    stream_copy_to_stream(fopen('/meu/arquivo/de/imagem/gigante.png', 'r'), fopen('php://output', 'w+'));
    stream_copy_to_stream(
    fopen('/meu/arquivo/de/imagem/gigante.png', 'r'),
    fopen('php://output', 'w+')
    );
    ```

    Além do `php://output` também existem outras [streams mágicas](http://www.php.net/manual/en/wrappers.php.php) do php.
  2. Alexandre Gomes Gaigalas created this gist Feb 21, 2013.
    105 changes: 105 additions & 0 deletions php_pratico_streams.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,105 @@
    PHP Prático: Streams
    ====================

    A palavra _stream_ significa _corrente_. Em geral, qualquer conexão de rede é uma stream, e existem vários tipos de protocolos para streams. Esses protocolos definem como os dados fluem na corrente.

    No PHP, [vários protocolos](http://www.php.net/manual/en/wrappers.php) são suportados de forma transparente:

    ```php
    <?php

    $arquivoDoFtp = file_get_contents('ftp://example.com/my/file.txt');
    $arquivoDoDisco = file_get_contents('/my/file.txt');
    $arquivoDoHttp = file_get_contents('http://example.com/my/file.txt');
    ```

    No exemplo acima usamos a mesma função do PHP, a `file_get_contents` para obter o conteúdo de três arquivos em lugares diferentes suportados por protocolos diferentes. O PHP decide qual protocolo de stream usar pelo identificador de esquema `algo://`, se ele for omitido, cai para o padrão `file://`.

    O mais legal disso é que **todas** as funções de arquivos e streams do PHP funcionam com todos os protocolos. Vejamos um exemplo mais legal:


    ```php
    <?php

    $pastaDoFtp = scandir('ftp://example.com/my/images/folder');
    $pastaDoDisco = scandir('/my/images/folder');
    $pastaDoGz = scandir('zlib:///my/images/folder.gz');
    ```

    A função `scandir` é uma das funções de arquivo, portanto ela é capaz de abstrair streams e varrer diretórios tanto locais quanto de um FTP remoto ou arquivo zipado.

    Alguns protocolos suportam contextos. Eles são necessários pra trafegar mais informação sobre uma stream. O contexto pra HTTP por exemplo, entre os [diversos recursos que ele suporta](http://www.php.net/manual/en/context.http.php), permite definir cabeçalhos:

    ```php
    <?php

    $contexto = stream_context_create(array('http' => array(
    'user_agent' => 'My PHP Bot.'
    )));
    $arquivoDoHttp = file_get_contents('http://exemplo.com/my/file.txt', null, $contexto);

    ```

    O exemplo acima obtém um arquivo de um HTTP mas identifica a conexão com um cabeçalho `User-Agent`. É possível enviar cabeçalhos de autenticação, cache, mudar o método para POST, DELETE ou qualquer outro e definir proxies.

    Além disso, o PHP permite que você [crie seus próprios protocolos e os registre](http://php.net/stream_wrapper). Pessoas já criaram vários como esses pra mexer com arquivos no [Amazon S3](https://github.com/punkave/aS3StreamWrapper) e [repositórios Git](https://github.com/teqneers/PHP-Stream-Wrapper-for-Git) com funções simples como `file_get_contents` e `scandir`.

    Outra coisa bastante surpreendente no suporte a streams é a auto-cópia. No exemplo abaixo, o `$arquivoHttp` é baixado inteiro para a memória antes de ser salvo:

    ```php
    <?php
    $arquivoHttp = file_get_contents('http://example.com/my/file.txt');
    file_put_contents('/arquivos/salvos/file.txt', $arquivoHttp);
    ```

    Contudo, no exemplo abaixo, o arquivo nunca vai inteiro para a memória, permitindo que a stream flua livremente do HTTP direto pro disco:

    ```php
    <?php
    file_put_contents('/arquivos/salvos/file.txt', file_get_contents('http://example.com/my/file.txt'));
    ```

    Isso acontece porque se você passa uma função de stream como parâmetro de outra, o PHP automaticamente aplica a função `stream_copy_to_stream`. Você poderia fazer isso manualmente também:

    ```php
    <?php
    stream_copy_to_stream(fopen('http://example.com/my/file.txt', 'r'), fopen('/arquivos/salvos/file.txt', 'w+'));
    ```

    Isso permite que você mexa com arquivos de 2GB tendo apenas 28MB de limite de memória no PHP, porque ele nunca terá o arquivo inteiro na memória, só um pequeno buffer que ele usa pra passar a corrente entre duas streams!

    E se você quiser, é possível ir ainda mais longe com os filtros de stream. No exemplo acima nós copiamos um arquivo do HTTP direto pro disco, mas não é possível ver seu conteúdo. Com filtros de stream isso é possível. O exemplo abaixo baixa um arquivo de um FTP, converte tudo para maiúsculas e salva em um disco local:

    ```php
    <?php
    $arquivoFtpStream = fopen('ftp://example.com/file.txt', 'r');
    $arquivoLocalStream = fopen('/my/file.txt', 'w+');

    stream_filter_append($arquivoLocalStream, "string.toupper", STREAM_FILTER_WRITE);

    stream_copy_to_stream($arquivoFtpStream, $arquivoLocalStream);
    ```

    Usei o filtro `string.toupper`, que é um dos padrões, mas você pode [registrar os seus próprios](http://www.php.net/manual/en/function.stream-filter-register.php).

    Além de tudo, existem algumas streams específicas do PHP. O exemplo abaixo lê uma imagem gigante do disco e exibe ela no navegador sem carregá-la inteira na memória:

    ```php
    <?php

    header('Content-Type: image/png');
    fpassthru(fopen('/meu/arquivo/de/imagem/gigante.png', 'r'));
    ```

    Além do `fpassthru`, é possível usar uma stream explícita:

    ```php
    <?php

    header('Content-Type: image/png');
    stream_copy_to_stream(fopen('/meu/arquivo/de/imagem/gigante.png', 'r'), fopen('php://output', 'w+'));
    ```

    Além do `php://output` também existem outras [streams mágicas](http://www.php.net/manual/en/wrappers.php.php) do php.

    E finalmente, streams são a única forma de fazer o PHP trabalhar de forma assíncrona! Isso é feito com a função `stream_select`, que se for usada em conexões não-bloqueantes, permite que as [streams sejam coletadas de forma assíncrona](http://wezfurlong.org/blog/2005/may/guru-multiplexing/).