<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: PHP Brasil</title>
    <description>The latest articles on DEV Community by PHP Brasil (@phpbrasil).</description>
    <link>https://dev.to/phpbrasil</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F3010%2F2f075cd3-9688-4efc-a0d1-e04fb3b9b480.jpg</url>
      <title>DEV Community: PHP Brasil</title>
      <link>https://dev.to/phpbrasil</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/phpbrasil"/>
    <language>en</language>
    <item>
      <title>Protegendo seu servidor contra acessos indevidos</title>
      <dc:creator>Daniel</dc:creator>
      <pubDate>Wed, 03 Feb 2021 16:08:30 +0000</pubDate>
      <link>https://dev.to/phpbrasil/protegendo-seu-servidor-contra-acessos-indevidos-3mac</link>
      <guid>https://dev.to/phpbrasil/protegendo-seu-servidor-contra-acessos-indevidos-3mac</guid>
      <description>&lt;p&gt;Se você precisa de segurança extra em um servidor Linux/Debian, e você sempre precisa, lá vai uma dica de ouro, desative acesso SSH por meio de senhas, assim você evitará qualquer ataque do tipo força bruta, vamos a prática.&lt;/p&gt;

&lt;h3&gt;
  
  
  No servidor
&lt;/h3&gt;

&lt;p&gt;Crie um par de chaves SSH;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-keygen &lt;span class="nt"&gt;-b&lt;/span&gt; 4096

Generating public/private rsa key pair.
Enter file &lt;span class="k"&gt;in &lt;/span&gt;which to save the key &lt;span class="o"&gt;(&lt;/span&gt;/home/pi/.ssh/id_rsa&lt;span class="o"&gt;)&lt;/span&gt;:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tecle enter para confirmar;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Created directory &lt;span class="s1"&gt;'/home/pi/.ssh'&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Crie uma senha para sua chave SSH e confirme;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Enter passphrase &lt;span class="o"&gt;(&lt;/span&gt;empty &lt;span class="k"&gt;for &lt;/span&gt;no passphrase&lt;span class="o"&gt;)&lt;/span&gt;:
Enter same passphrase again:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A chave foi gerada com sucesso, veja o resultado abaixo;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;The key fingerprint is:
SHA256:oVHrP/nGj3umYFkKRvnC/SKk8nSgHmeZ/OTUAQS+gvs pi@raspberrypi
The key&lt;span class="s1"&gt;'s randomart image is:
+---[RSA 4096]----+
|      ..o        |
|     . o o       |
|      o *        |
|   .   B =       |
|  . . + S + .    |
|   . + B = B     |
|  . + O = @..    |
|   o B * o =o.o  |
|    E . o  .=*.  |
+----[SHA256]-----+
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Chaves SSH ficam salvas na pasta oculta &lt;code&gt;.ssh&lt;/code&gt; na raiz do seu usuário Linux, no meu caso estão em:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/home/pi/.ssh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Digitando o comando &lt;code&gt;ls&lt;/code&gt; dá pra ver o seu par de chaves(pública, privada), do lado do servidor o trabalho está terminado.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;id_rsa  id_rsa.pub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  No cliente
&lt;/h3&gt;

&lt;p&gt;Autorize a sua máquina cliente a se conectar ao servidor sem precisar digitar uma senha, para isso vamos copiar a chave pública do cliente para dentro do servidor, e autorizar o acesso, basta um simples comando pra isso:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; ~/.ssh/id_rsa.pub | ssh pi@192.168.15.2 &lt;span class="s1"&gt;'mkdir -p ~/.ssh &amp;amp;&amp;amp; cat &amp;gt;&amp;gt; ~/.ssh/authorized_keys'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Na próxima etapa digite &lt;code&gt;yes&lt;/code&gt;, assim você está informando que reconhece o servidor;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;The authenticity of host &lt;span class="s1"&gt;'192.168.15.2 (192.168.15.2)'&lt;/span&gt; can&lt;span class="s1"&gt;'t be established.
ECDSA key fingerprint is SHA256:g1gtgJgDd24rXR0KJTTBjdLUI+SX829GTwQ1CYgVCiQ.
Are you sure you want to continue connecting (yes/no/[fingerprint])?
Warning: Permanently added '&lt;/span&gt;192.168.15.2&lt;span class="s1"&gt;' (ECDSA) to the list of known hosts.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neste momento um arquivo chamado &lt;code&gt;.ssh/authorized_keys&lt;/code&gt; será criado no servidor, esse arquivo tem a chave pública do cliente, indicando assim que o mesmo possui autorização de acesso ao servidor.&lt;/p&gt;

&lt;p&gt;Digite a senha do servidor;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pi@192.168.15.2&lt;span class="s1"&gt;'s password:
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Conecte-se ao servidor;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &amp;lt;USERNAME&amp;gt;@&amp;lt;IP-ADDRESS&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No meu caso o comando será;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh pi@192.168.15.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pra mim a mensagem de boas-vindas foi a seguinte:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Linux raspberrypi 5.4.83-v7+ &lt;span class="c"&gt;#1379 SMP Mon Dec 13 20:08:57 GMT 2020 armv7l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Passo final, o "pulo do gato"
&lt;/h3&gt;

&lt;p&gt;O último passo é desativar a autenticação por senha no servidor, para isso basta editar o arquivo com as configurações de ssh no servidor, use o comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /etc/ssh/sshd_config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O arquivo será aberto e estará pronto para edição, apenas procure o seguinte trecho:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#PasswordAuthentication yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Edite o trecho removendo o comentário &lt;code&gt;#&lt;/code&gt; deixando assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;PasswordAuthentication no
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reinicie o servidor&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;reboot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tudo certo, a partir de agora você não precisa mais digitar senhas para ter acesso ao servidor, e ainda garante que apenas acessos via SSH e autorizados serão aceitos, desta forma a segurança está garantida no seu servidor&lt;/p&gt;

</description>
      <category>security</category>
      <category>cybersecurity</category>
      <category>linux</category>
    </item>
    <item>
      <title>Assinando commits com uma chave GPG</title>
      <dc:creator>Daniel</dc:creator>
      <pubDate>Thu, 17 Dec 2020 16:16:02 +0000</pubDate>
      <link>https://dev.to/phpbrasil/assinando-commits-com-uma-chave-gpg-2hl3</link>
      <guid>https://dev.to/phpbrasil/assinando-commits-com-uma-chave-gpg-2hl3</guid>
      <description>&lt;p&gt;O Git tem a opção de assinar e verificar seus commits utilizando-se de chave GPG, para isso basta seguir os passos a seguir&lt;/p&gt;

&lt;h4&gt;
  
  
  Passo 1 - Gere uma nova chave GPG
&lt;/h4&gt;

&lt;p&gt;1 - Digite o comando para gerar a chave GPG;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gpg --full-generate-key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2 - Selecione a opção: (1) RSA e RSA (padrão);&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gpg (GnuPG) 2.2.4; Copyright (C) 2017 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Por favor selecione o tipo de chave desejado:
   (1) RSA e RSA (padrão)
   (2) DSA e Elgamal
   (3) DSA (apenas assinatura)
   (4) RSA (apenas assinar)
Sua opção? 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3 - Digite o maior comprimento(4096), para sua nova chave GPG;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RSA chaves podem ter o seu comprimento entre 1024 e 4096 bits.
Que tamanho de chave você quer? (3072) 4096
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4 - Decida qual o prazo de expiração para sua chave;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Por favor especifique por quanto tempo a chave deve ser válida.
         0 = chave não expira
      &amp;lt;n&amp;gt;  = chave expira em n dias
      &amp;lt;n&amp;gt;w = chave expira em n semanas
      &amp;lt;n&amp;gt;m = chave expira em n meses
      &amp;lt;n&amp;gt;y = chave expira em n anos
A chave é valida por? (0) 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;5 - Confirme o tempo de expiração da chave;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A chave não expira nunca
Está correto (s/N)?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;6 - Digite seu nome completo;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GnuPG precisa construir uma ID de usuário para identificar sua chave.

Nome completo: 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;7 - Digite seu email;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Endereço de correio eletrônico:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;8 - Crie um comentário para sua chave caso seja necessário;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Comentário: 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;9 - Confirme as informações que você acabou de preencher, basta digitar o para OK;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Você selecionou este identificador de usuário:
    "Joao Ninguem &amp;lt;joao@ninguem.nada&amp;gt;"

Muda (N)ome, (C)omentário, (E)ndereço ou (O)k/(S)air?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;10 - Digite uma senha segura para sua chave GPG e confirme a senha;&lt;/p&gt;

&lt;p&gt;11 - Aguarde o processo de criação de sua chave finalizar;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Precisamos gerar muitos bytes aleatórios. É uma boa idéia realizar outra
atividade (digitar no teclado, mover o mouse, usar os discos) durante a
geração dos números primos; isso dá ao gerador de números aleatórios
uma chance melhor de conseguir entropia suficiente.
gpg: chave FD2B172CC4C9F3E4 marcada como plenamente confiável
gpg: revocation certificate stored as '/home/geekcom/.gnupg/openpgp-revocs.d/92518C10D23E004325112DB9FD2B172CC4C9F3E4.rev'
chaves pública e privada criadas e assinadas.

pub   rsa4096 2020-04-28 [SC]
      92518C10D23E004325112DB9FD2B172CC4C9F3E4
uid                      Joao Ninguem &amp;lt;joao@ninguem.nada&amp;gt;
sub   rsa4096 2020-04-28 [E]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neste momento sua chave GPG foi gerado com sucesso, agora é necessário adiciona-la ao GitHub.&lt;/p&gt;

&lt;h4&gt;
  
  
  Passo 2 - Adicionando uma chave GPG ao GitHub
&lt;/h4&gt;

&lt;p&gt;1 - Use o seguinte comando para listar a chave GPG privada que você acabou de criar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gpg --list-secret-keys --keyid-format LONG joao@ninguem.nada
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Substitua &lt;code&gt;joao@ninguem.nada&lt;/code&gt; pelo e-mail que você usou para criar a chave.&lt;/p&gt;

&lt;p&gt;2 - Copie o ID da chave GPG que começa com sec. No exemplo a seguir, é FD2B172CC4C9F3E4:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sec   rsa4096/FD2B172CC4C9F3E4 2020-04-28 [SC]
      92518C10D23E004325112DB9FD2B172CC4C9F3E4
uid                 [final] Joao Ninguem &amp;lt;joao@ninguem.nada&amp;gt;
ssb   rsa4096/AB9EC40EA9DE16E3 2020-04-28 [E]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3 - Exporte a chave pública desse ID (substitua pelo seu ID da chave da etapa anterior):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gpg --armor --export FD2B172CC4C9F3E4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4 - Por fim, copie a chave pública e adicione-a nas configurações do seu perfil do GitHub em &lt;code&gt;https://github.com/settings/keys&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Passo 3 - Associando sua chave GPG ao Git
&lt;/h4&gt;

&lt;p&gt;1 -  Depois de criar sua chave GPG e adicioná-la à sua conta GitLab, é hora de informar ao Git qual chave usar.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gpg --list-secret-keys --keyid-format LONG joao@ninguem.nada
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Substitua &lt;code&gt;joao@ninguem.nada&lt;/code&gt; pelo seu email.&lt;/p&gt;

&lt;p&gt;2 - Copie o ID da chave GPG que começa com sec. No exemplo a seguir, é FD2B172CC4C9F3E4:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sec   rsa4096/FD2B172CC4C9F3E4 2020-04-28 [SC]
      92518C10D23E004325112DB9FD2B172CC4C9F3E4
uid                 [final] Joao Ninguem &amp;lt;joao@ninguem.nada&amp;gt;
ssb   rsa4096/AB9EC40EA9DE16E3 2020-04-28 [E]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3 - Diga ao Git que deseja usar essa chave para assinar os seus commits:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git config --global user.signingkey FD2B172CC4C9F3E4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Substitua FD2B172CC4C9F3E4 pelo ID da sua chave GPG.&lt;/p&gt;

&lt;h4&gt;
  
  
  Passo 4 - Assinando commits com sua chave GPG
&lt;/h4&gt;

&lt;p&gt;Depois de criar sua chave GPG e adicioná-la à sua conta, você pode começar a assinar seus commits:&lt;/p&gt;

&lt;p&gt;1 - Continua como você costumava fazer, a única diferença é a adição da flag -S:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git commit -S -m "mensagem do meu commit"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2 - Digite a senha da sua chave GPG quando solicitada.&lt;/p&gt;

&lt;p&gt;A partir de agora seus commits podem assinados com sua chave GPG sempre que desejar, no GitHub você poderá ver que seus commits estão assinados.&lt;/p&gt;

</description>
      <category>security</category>
      <category>git</category>
      <category>github</category>
    </item>
    <item>
      <title>Como o PHP lida com a questão da segurança</title>
      <dc:creator>Daniel</dc:creator>
      <pubDate>Tue, 29 Sep 2020 19:04:28 +0000</pubDate>
      <link>https://dev.to/phpbrasil/como-o-php-lida-com-a-questao-da-seguranca-6l4</link>
      <guid>https://dev.to/phpbrasil/como-o-php-lida-com-a-questao-da-seguranca-6l4</guid>
      <description>&lt;h2&gt;
  
  
  O que é um problema de segurança?
&lt;/h2&gt;

&lt;p&gt;O time do PHP classifica como problemas de segurança, bugs que:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Permitem que os usuários executem ações não autorizadas;&lt;/li&gt;
&lt;li&gt;Cruzam os limites de segurança;&lt;/li&gt;
&lt;li&gt;Acessam dados que não deveriam ser acessíveis;&lt;/li&gt;
&lt;li&gt;Impactam severamente a acessibilidade ou desempenho do sistema.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O objetivo desta classificação é alertar os usuários e desenvolvedores sobre problemas que precisam ser tratados como prioridade.&lt;/p&gt;

&lt;h2&gt;
  
  
  O PHP é seguro
&lt;/h2&gt;

&lt;p&gt;Esta afirmação é possível com base no conhecimento do ciclo de vida de uma vulnerabilidade no PHP, em resumo o processo funciona assim:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uma possível vulnerabilidade é reportada;&lt;/li&gt;
&lt;li&gt;Então ela é avaliada por alguém do time ou um contribuidor externo/você que está lendo;&lt;/li&gt;
&lt;li&gt;Acontecerá uma discussão sobre o suposto bug;&lt;/li&gt;
&lt;li&gt;O problema é resolvido;&lt;/li&gt;
&lt;li&gt;Uma versão menor (por exemplo: 7.4.9), é criada contendo a solução, depois é possível ver no log de mudanças tudo que foi resolvido;&lt;/li&gt;
&lt;li&gt;Novas versões, são criadas em média a cada 4 semanas.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Cuidando da segurança
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Mantenha-se informado, fique atento aos materiais que a comunidade disponibiliza;&lt;/li&gt;
&lt;li&gt;Sempre que possível atualize a versão;&lt;/li&gt;
&lt;li&gt;Observe todos os outros aspectos de segurança (códigos, sistemas operacionais, configurações, infra estrutura e o fator humano/engenharia social).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Nenhum sistema é invulnerável, pois o fator humano sempre existirá. Entretanto é possível mitigar a maioria dos problemas que acontecem em softwares, mas isso requer um pouco de atenção e cuidados por parte de todos os envolvidos.&lt;/p&gt;

&lt;p&gt;Deixe nos comentários o que você acha disso.&lt;/p&gt;

&lt;h2&gt;
  
  
  Referências e links úteis
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://bugs.php.net/" rel="noopener noreferrer"&gt;https://bugs.php.net/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://wiki.php.net/security" rel="noopener noreferrer"&gt;https://wiki.php.net/security&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.php.net/supported-versions.php" rel="noopener noreferrer"&gt;https://www.php.net/supported-versions.php&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.php.net/eol.php" rel="noopener noreferrer"&gt;https://www.php.net/eol.php&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>security</category>
    </item>
    <item>
      <title>PHP assíncrono de forma nativa</title>
      <dc:creator>Vinicius Dias</dc:creator>
      <pubDate>Wed, 16 Sep 2020 12:42:21 +0000</pubDate>
      <link>https://dev.to/phpbrasil/php-assincrono-de-forma-nativa-1db1</link>
      <guid>https://dev.to/phpbrasil/php-assincrono-de-forma-nativa-1db1</guid>
      <description>&lt;p&gt;Realizar acesso a streams é uma tarefa relativamente comum para devs PHP. Seja lendo e escrevendo em arquivos, fazendo requisições HTTP, etc.&lt;/p&gt;

&lt;p&gt;Operações de I/O são custosas e levam algum tempo para executar. Quando temos diversas operações desse tipo, uma técnica que pode ajudar (e muito) na performance da aplicação é realizá-las de forma assíncrona.&lt;/p&gt;

&lt;h2&gt;
  
  
  Acesso a streams
&lt;/h2&gt;

&lt;p&gt;Antes de falar sobre técnicas e funções que permitem a programação assíncrona, é importante saber como normalmente nós trabalhamos com I/O.&lt;/p&gt;

&lt;p&gt;Acesso a arquivos, requisições HTTP, sockets e muito mais pode ser feito através de &lt;a href="https://php.net/streams"&gt;streams&lt;/a&gt;. Um stream é basicamente um fluxo de dados, sendo que a origem desse fluxo pode variar (vide o início desse parágrafo). Quando utilizamos funções como &lt;code&gt;file_get_contents&lt;/code&gt;, &lt;code&gt;fopen&lt;/code&gt;, &lt;code&gt;fgets&lt;/code&gt;, e as demais, estamos trabalhando com streams do PHP.&lt;/p&gt;

&lt;h2&gt;
  
  
  Programação assíncrona
&lt;/h2&gt;

&lt;p&gt;Se você não está familiarizado com o termo "programação assíncrona", recomendo assistir este vídeo antes de continuar o artigo:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/zLfXPSeCkB8"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Entendido o que é programação assíncrona, como podemos fazer acesso a streams de forma assíncrona utilizando PHP sem nenhuma extensão ou biblioteca externa? Será possível?&lt;/p&gt;

&lt;h2&gt;
  
  
  Eventos
&lt;/h2&gt;

&lt;p&gt;Programação orientada a eventos não é novidade e nós utilizamos muito na web. Para agir quando um botão for clicado, ou quando um texto for digitado em um &lt;code&gt;input&lt;/code&gt; nós utilizamos eventos no JavaScript. Eventos podem acontecer a qualquer momento então sua natureza é assíncrona. Mas será possível fazer algo parecido do lado do PHP?&lt;/p&gt;

&lt;p&gt;Antes de falar do PHP em si, acho válido citar que o sistema operacional já trabalha com chamadas assíncronas. Diversos eventos acontecem durante a execução do seu sistema, e há código reagindo a estes eventos o tempo todo. Utilizando PHP nós podemos acessar algumas dessas funcionalidades do sistema operacional&lt;/p&gt;

&lt;h3&gt;
  
  
  Função stream_select
&lt;/h3&gt;

&lt;p&gt;Uma função não muito comum para nós que trabalhamos com PHP é a &lt;a href="https://php.net/stream_select"&gt;stream_select&lt;/a&gt;. Essa função nos permite "observar" modificações que possam acontecer em streams. O probelma é que ela não é nada fácil de se entender, então vou tentar tornar este processo menos doloroso para você.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cenário
&lt;/h2&gt;

&lt;p&gt;Imagine que para executar uma tarefa nós precisemos ler 5 arquivos distintos e depois realizar algum processamento. Normalmente utilizando PHP nós poderíamos fazer algo como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="nv"&gt;$conteudoDoArquivo1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;file_get_contents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'arquivo1.txt'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$conteudoDoArquivo2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;file_get_contents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'arquivo2.txt'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$conteudoDoArquivo3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;file_get_contents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'arquivo3.txt'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$conteudoDoArquivo4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;file_get_contents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'arquivo4.txt'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$conteudoDoArquivo5&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;file_get_contents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'arquivo5.txt'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Processar os 5 arquivos&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O problema nessa abordagem é óbvio: Antes de ler o &lt;code&gt;arquivo2.txt&lt;/code&gt; precisamos terminar de ler todo o conteúdo de &lt;code&gt;arquivo1.txt&lt;/code&gt;. Enquanto o computador espera, nós já poderíamos estar sendo os demais arquivos e os processando de forma individual.&lt;/p&gt;

&lt;p&gt;Quando temos uma operação de I/O (acesso a arquivos, rede, etc) sendo realizada de forma síncrona, o processador fica ocioso enquanto a operação não é executada. Ou seja, enquanto o arquivo estiver sendo carregado, o processador fica esperando, sem fazer nada. É exatamente isso que queremos evitar. Queremos garantir que ele continue trabalhando enquanto o arquivo não estiver pronto para leitura.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solução com assincronicidade
&lt;/h2&gt;

&lt;p&gt;Para resolver essa situação, podemos utilizar a função &lt;code&gt;stream_select&lt;/code&gt; que observa alterações no status de uma lista de streams, ou seja, quando algum dos arquivos estiver pronto para leitura, essa função nos avisará. E é interessante citar que a leitura não necessariamente vai acontecer em ordem. O sistema operacional pode abrir o &lt;code&gt;arquivo3.txt&lt;/code&gt; mais rápido do que o &lt;code&gt;arquivo1.txt&lt;/code&gt;, por exemplo. Neste cenário, vamos processá-lo logo, sem ficar esperando os arquivos anteriores.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="nv"&gt;$listaDeStreamsDeArquivos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nb"&gt;fopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'arquivo1.txt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'r'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nb"&gt;fopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'arquivo2.txt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'r'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nb"&gt;fopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'arquivo3.txt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'r'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nb"&gt;fopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'arquivo4.txt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'r'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nb"&gt;fopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'arquivo5.txt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'r'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$listaDeStreamsDeArquivos&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$streamDeArquivo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;stream_set_blocking&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$streamDeArquivo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$streamsParaLer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$listaDeStreamsDeArquivos&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nv"&gt;$streamsComNovidades&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;stream_select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$streamsParaLer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$write&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$except&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$streamsComNovidades&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'Erro inesperado'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$streamsComNovidades&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$streamsParaLer&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$indice&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$streamDeArquivo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$conteudo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;stream_get_contents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$streamDeArquivo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// processa o conteúdo do arquivo&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;feof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$streamDeArquivo&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;fclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$streamDeArquivo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nb"&gt;unset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$listaDeStreamsDeArquivos&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$indice&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$listaDeStreamsDeArquivos&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Explicação
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Preparação
&lt;/h4&gt;

&lt;p&gt;Como eu disse, não é muito fácil, então vamos por partes. Primeiro abrimos todos os arquivos que queremos ler com o &lt;code&gt;fopen&lt;/code&gt;. Até aí sem segredo. Depois, informamos com a função &lt;code&gt;stream_set_blocking&lt;/code&gt; que o recurso deve ser aberto em modo não-bloqueante - assim, o processo que acessa o arquivo não bloqueará a CPU por causar um estado de espera ao tentar acessar os arquivos.&lt;/p&gt;

&lt;p&gt;Nesse ponto, temos um array com 5 recursos abertos para podermos trabalhar com estes streams. Então analisando o este pedaço de código:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$listaDeStreamsDeArquivos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nb"&gt;fopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'arquivo1.txt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'r'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nb"&gt;fopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'arquivo2.txt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'r'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nb"&gt;fopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'arquivo3.txt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'r'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nb"&gt;fopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'arquivo4.txt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'r'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nb"&gt;fopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'arquivo5.txt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'r'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nb"&gt;var_dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$listaDeStreamsDeArquivos&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Teríamos a seguinte saída:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois disso que começa a parte difícil. A chamada para a função &lt;code&gt;stream_select&lt;/code&gt; deve estar em um loop, porque pode acontecer de nem todos os streams estarem prontos para leitura logo de cara.&lt;/p&gt;

&lt;h4&gt;
  
  
  Parâmetros
&lt;/h4&gt;

&lt;p&gt;Segundo detalhe importante: os parâmetros. O 3 primeiros parâmetros dessa função são passados por referência. Por isso o segundo e terceiro são variáveis que nós nem tínhamos definido ainda. O primeiro parâmetro é a lista de streams que queremos observar para ler. O segundo é para escrita. Já o terceiro, menos comum, é para dados excepcionais que possuem maior prioridade. Os 2 últimos parâmetros são sobre timeout.&lt;/p&gt;

&lt;p&gt;O parâmetro passado como 1 indica o número de segundos que essa função deve esperar receber uma notificação de novidade nos streams até "desistir", ou seja, o timeout. Esse é o motivo pelo qual ela deve estar em um loop. Se esse tempo passar e nós não tivermos novidade, devemos tentar de novo depois. Caso algum (não necessariamente todos) stream esteja pronto antes desse 1 segundo, a função retornará. O último parâmetro, que informamos como 0, indica o tempo em microsegundos para timeout.&lt;/p&gt;

&lt;h4&gt;
  
  
  Retorno e leitura
&lt;/h4&gt;

&lt;p&gt;Agora vamos falar do retorno. Essa função retorna o número de streams que contém modificações. No nosso caso, vai informar quantos arquivos estão prontos para leitura. Porém em caso de erro essa função nos retorna o valor &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Além disso, os parâmetros que nós passamos podem ter sido modificados. Por isso eu realizo uma cópia da lista original de streams em &lt;code&gt;$arquivosParaLer = $listaDeArquivos;&lt;/code&gt;. Após o retorno da função, o parâmetro passado vai conter apenas os streams que possuem novidades, ou seja, no nosso caso, os arquivos que estão prontos para leitura.&lt;/p&gt;

&lt;p&gt;Para exemplificar, vamos supor que na primeira execução do loop todos os arquivos já estejam disponíveis. Nesse caso, analisando os valores das variáveis, podemos entender o que está acontecendo. Analisando então o valor de &lt;code&gt;$streamsComNovidades&lt;/code&gt;, teríamos &lt;code&gt;int(5)&lt;/code&gt; como resultado deste cenário.&lt;/p&gt;

&lt;p&gt;Já analisando ambos arrays de streams (&lt;code&gt;$listaDeStreamsDeArquivos&lt;/code&gt; e &lt;code&gt;$streamsParaLer&lt;/code&gt;), teríamos exatamente o mesmo resultado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora caso na primeira execução tivéssemos apenas 3 dos 5 arquivos prontos, e analisássemos os 3 valores anteriores, teríamos ter algo como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nb"&gt;var_dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$streamsComNovidades&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$listaDeStreamsDeArquivos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$streamsParaLer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Onde, nesse caso, o segundo array exibido é o de &lt;code&gt;$streamsParaLer&lt;/code&gt;, e possui apenas os 3 arquivos prontos para leitura.&lt;/p&gt;

&lt;p&gt;Sendo assim, posso percorrer este array tendo a certeza de que há dados para ler e processar. Mas não há garantia de que todo o conteúdo do arquivo estará lá, por isso verifico se cheguei ao fim do arquivo com &lt;code&gt;feof&lt;/code&gt;. Para arquivos pequenos, via de regra, todo o conteúdo virá de uma vez só, mas não conte com isso e prepare seu código para ler até mesmo um único byte por vez.&lt;/p&gt;

&lt;p&gt;Após ler todo o arquivo, devemos fechá-lo. Mas um outro detalhe importante é que eu também o removo da lista original de streams que queremos ler. Faço isso para que caso seja necessária uma nova iteração no loop, ou seja, caso nem todos os arquivos tenham sido lidos, eu não tente ler novamente os arquivos que já foram lidos e fechados.&lt;/p&gt;

&lt;p&gt;Com isso temos nossa condição de saída do loop. Quando todos os arquivos tiverem sido removidos e minha lista estiver vazia, sei que processei todos os arquivos.&lt;/p&gt;

&lt;p&gt;PS.: A função &lt;code&gt;stream_set_blocking&lt;/code&gt; só surte efeito com arquivos e sockets. Os outros wrappers, com esta técnica, não podem ser lidos de forma assíncrona e não bloqueante.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conceitos
&lt;/h2&gt;

&lt;p&gt;Esse código obviamente pode ser refatorado para torná-lo um pouco mais legível, mas acredito que a lógica por trás dele tenha ficado clara. Caso contrário, você pode usar a sessão de comentários dessa página para fazer perguntas.&lt;/p&gt;

&lt;p&gt;O que nós escrevemos de forma rudimentar aqui pode ser visto como uma implementação do que é conhecido como &lt;em&gt;Event Loop&lt;/em&gt;, ou loop de eventos. Você provavelmente já ouviu esse termo se estuda sobre a runtime Node.js.&lt;/p&gt;

&lt;p&gt;Claro que essa implementação não é completa ou otimizada, mas atende nosso propósito: ler arquivos conforme eles fiquem prontos para leitura. Dessa forma nós vamos pedir para que o sistema operacional prepare todos os arquivos para leitura de uma só vez.&lt;/p&gt;

&lt;p&gt;As vantagens nessa abordagem assíncrona são mais perceptíveis quando temos operações mais lentas como chamadas HTTP, por exemplo. Mas isso aumentaria a complexidade do código para este artigo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Claro que o PHP já possui ferramentas que realizam este trabalho de forma muito mais simples. ReactPHP com seu pacote de Streams é um ótimo exemplo.&lt;/p&gt;

&lt;p&gt;Mas seguindo o que citei no post sobre aprendizado, eu penso como &lt;a href="https://pt.wikipedia.org/wiki/Richard_Feynman"&gt;Richard Feynman&lt;/a&gt; (Nobel de física): "O que eu não consigo criar, eu não entendo". Então antes de utilizar uma ferramenta que realiza o trabalho para mim, eu gosto de saber como realizar este trabalho sem ela. Com isso, se algum problema acontecer com a biblioteca, por exemplo, eu vou estar mais preparado para resolvê-lo já que eu entendo um pouco melhor como as coisas funcionam.&lt;/p&gt;

&lt;p&gt;Além disso, se chamadas HTTP assíncronas com essa técnica é um assunto que te interessa, interaja com essa publicação para que eu produza um conteúdo sobre isso.&lt;/p&gt;

</description>
      <category>php</category>
      <category>async</category>
      <category>performance</category>
    </item>
    <item>
      <title>TDD: Iniciando com TDD no PHP</title>
      <dc:creator>Eduardo Figueiredo Gonçalves</dc:creator>
      <pubDate>Sat, 23 May 2020 02:53:27 +0000</pubDate>
      <link>https://dev.to/phpbrasil/tdd-iniciando-com-tdd-no-php-47nb</link>
      <guid>https://dev.to/phpbrasil/tdd-iniciando-com-tdd-no-php-47nb</guid>
      <description>&lt;h1&gt;
  
  
  TDD
&lt;/h1&gt;

&lt;p&gt;Estava estudando um pouco sobre TDD e vi o &lt;a href="https://code.tutsplus.com/tutorials/lets-tdd-a-simple-app-in-php--net-26186" rel="noopener noreferrer"&gt;artigo&lt;/a&gt; que me fez pensar em algumas coisas interessantes e resolvi escrever esse post.&lt;/p&gt;

&lt;p&gt;Vou fazer algumas colocações sobre o material e mostrar alguns exemplos dele, recomendo darem uma lida no texto antes que eu curti demais. Durante sprints de desenvolvimento em SCRUM há situações que podem ser resumidas à imagem:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AM255AzrVeQb3FCJz21eATA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AM255AzrVeQb3FCJz21eATA.jpeg" alt="Persista!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Há momentos do dia em que estamos com muito gás e outros que a nossa produtividade se esgota. Desde sistemas de pequena complexidade até em sistemas mais complexos há alguns CRUDs que se repetem como por exemplo CRUD de Autenticação e CRUD de ACL (Controle de Acesso), será que quando formos unir todas os módulos tudo funcionará conforme esperado? Acredito que a grande maioria saiba que as chances de erros inesperados é enorme e para contornarmos esse problema falaremos sobre a técnica de TDD que é uma grande aliada do programador. As regras de TDD são: escreva testes, escreva código, refatore.&lt;/p&gt;

&lt;p&gt;TDD do inglês Test Driven Development ou em nossa língua nativa Desenvolvimento Guiado por Testes basicamente consiste em seguir um simples algoritmo de 3 passos para o desenvolvimento de software.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Você não tem permissão de escrever um código de produção se não tiver escrito um teste antes.&lt;/li&gt;
&lt;li&gt;Escreva um teste em que o seu código de produção falhe.&lt;/li&gt;
&lt;li&gt;Escreva o código de produção que faça seu teste que falhou no passo anterior passar.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Os passos devem ser repetidos até termos um código que cubra o máximo de possibilidade de falhas possível.&lt;/p&gt;

&lt;p&gt;Basicamente TDD é uma técnica de desenvolvimento e design de software em que devemos escrever testes antes de código de produção. Geralmente times ágeis adotam essa prática e é uma das principais ferramentas no desenvolvimento de software ágil.&lt;/p&gt;

&lt;p&gt;Segundo a Wikipedia:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Test Driven Development (TDD) ou em português Desenvolvimento guiado por testes é uma técnica de desenvolvimento de software que se relaciona com o conceito de verificação e validação e se baseia em um ciclo curto de repetições: Primeiramente o desenvolvedor escreve um caso de teste automatizado que define uma melhoria desejada ou uma nova funcionalidade.&lt;/p&gt;

&lt;p&gt;Desenvolvimento dirigido por testes requer dos desenvolvedores criar testes de unidade automatizados que definam requisitos em código antes de escrever o código da aplicação. Os testes contém asserções que podem ser verdadeiras ou falsas. Após as mesmas serem consideradas verdadeiras após sua execução, os testes confirmam o comportamento correto, permitindo os desenvolvedores evoluir e refatorar o código.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Fonte: &lt;a href="https://pt.wikipedia.org/wiki/Test_Driven_Development" rel="noopener noreferrer"&gt;https://pt.wikipedia.org/wiki/Test_Driven_Development&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  PHP Unit
&lt;/h2&gt;

&lt;p&gt;PHP Unit é uma ferramenta que permite desenvolvedores PHP a escreverem testes unitários e praticarem o TDD. PHP Unit é um framework completo criado por &lt;a href="https://github.com/sebastianbergmann" rel="noopener noreferrer"&gt;Sebastian Bergmann&lt;/a&gt; com suporte à tecnica de mocking onde criamos objetos falsos que simulam comportamentos de objetos reais.&lt;/p&gt;

&lt;p&gt;Não entrarei nos detalhes da instalação desta ferramenta pois a própria documentação é bem rica e inclusive traduzida em português, o composer novamente é uma mão na roda para adicionar o PHP Unit ao nosso projeto.&lt;/p&gt;

&lt;p&gt;Fonte: &lt;a href="https://phpunit.de/" rel="noopener noreferrer"&gt;https://phpunit.de/&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  O que TDD não é:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Apenas criar testes unitários;&lt;/li&gt;
&lt;li&gt;É ter testes unitários;&lt;/li&gt;
&lt;li&gt;Perda de tempo;&lt;/li&gt;
&lt;li&gt;TDD = software sem bug.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  O que ganho implementando TDD?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Menor custo para manutenção do software;&lt;/li&gt;
&lt;li&gt;Melhorar nas estimativas;&lt;/li&gt;
&lt;li&gt;Legibilidade do código;&lt;/li&gt;
&lt;li&gt;Design guiado por Testes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Deixo um &lt;a href="https://github.com/eduardofg87/lets-tdd-a-simple-app" rel="noopener noreferrer"&gt;repositório&lt;/a&gt; para quem está iniciando com TDD no PHP.&lt;/p&gt;

&lt;p&gt;A estrutura do projeto foi criada utilizando o comando &lt;code&gt;composer init&lt;/code&gt; que facilita para seguirmos o PSR-4, já os nomes de variáveis e o estilo de codificação procurei seguei PSR-1 e PSR-2, abaixo temos a estrutura do projeto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- app
  - Wrapper.php
- tests/
  - FirstTest.php
- .gitignore
- LICENSE
- README.MD
- composer.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No arquivo FirstTest.php temos a implementação dos testes, eles foram escritos seguindo os passos de 1 a 3 e assim que foi escrito cada método de teste logo em seguida foi escrito cada método de produção:&lt;/p&gt;

&lt;h3&gt;
  
  
  Classe de Testes: FirstTest.php
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FEYq48ywVcAAjjuF%3Fformat%3Djpg%26name%3D4096x4096" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FEYq48ywVcAAjjuF%3Fformat%3Djpg%26name%3D4096x4096" alt="Testes"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Código de produção: Wrapper.php
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FEYq27ThUYAANDO6%3Fformat%3Djpg%26name%3D4096x4096" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FEYq27ThUYAANDO6%3Fformat%3Djpg%26name%3D4096x4096" alt="Wrapper"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Os testes foram criados na classe WrapperTest e possui 8 métodos que são:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;testItShouldWrapAnEmptyString&lt;/li&gt;
&lt;li&gt;testDoesNotWrapAShorterThanMaxCharsWord&lt;/li&gt;
&lt;li&gt;testItWrapsAWordSeveralTimesIfItsTooLong&lt;/li&gt;
&lt;li&gt;testItWrapsTwoWordsWhenSpaceAtTheEndOfLine&lt;/li&gt;
&lt;li&gt;testItWrapsTwoWordsWhenLineEndIsAfterFirstWord&lt;/li&gt;
&lt;li&gt;testItWraps3WordsOn2Lines&lt;/li&gt;
&lt;li&gt;testItWraps2WordsOn3Lines&lt;/li&gt;
&lt;li&gt;testItWraps2WordsAtBoundry&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;O projeto se resume em uma classe de produção chamada Wrapper (Embalagem) e seu único método wrap que significa embrulhar/envolver recebe 2 argumentos &lt;code&gt;$text&lt;/code&gt; e &lt;code&gt;$lineLength&lt;/code&gt;, sendo o primeiro o texto que será envolvido e o segundo o tamanho da linha. O código de produção foi refatorado e a última versão do método wrap é capaz de passar todos os testes. Deixei comentado as versões anteriores do método wrap que passam os testes.&lt;/p&gt;

&lt;p&gt;Chegamos ao fim, espero ter contribuído com o aprendizado sobre TDD!&lt;/p&gt;

&lt;p&gt;p.s.: Agradecimentos especiais ao &lt;a href="https://github.com/wilcorrea" rel="noopener noreferrer"&gt;Wil Correa&lt;/a&gt; pela revisão.&lt;/p&gt;

</description>
      <category>php</category>
      <category>tdd</category>
      <category>phpunit</category>
      <category>psr</category>
    </item>
  </channel>
</rss>
