Uma forma simples e rápida de gerar imagens QR Code.

Recentemente tive a oportunidade de implementar QR Code em uma aplicação. Com isso iniciei uma série de pesquisa de libs que facilitariam essa minha tarefa.

Após testar diversas libs encontrei a BaconQrCode e para meu propósito encaixou perfeitamente.

Com isso resolvi compartilhar a experiência com vocês por meio deste post.

Requisitos

  • PHP >= 7.1
  • Ext-gd

Para este post, gostaria de simular uma nova implementação em um sistema existente, para isso criei uma estrutura simples com Silex e Twig para servir como alicerse de aplicação, após clonar o repositório ou baixar o zip basta executar o comando pelo terminal na raiz do projeto para instalar suas dependências.

1
composer install

Aguarde o processo de instalação finalizar, em seguida execute o comando abaixo para iniciar a aplicação.

1
php -S localhost:8080 -t public public/index.php

Abra seu navegador e acesse a url localhost:8080, como resultado teremos uma representação similar ao exibido abaixo.

Formulário para geração do QRCode

Uma breve explicação dos diretórios do sistema:

  • config
    • Contém as configurações básicas da aplicação.
  • public
    • Destinado ao nosso arquivo index.php para inicialização da aplicação.
  • public/img
    • Diretório onde iremos armazenar nossos QR Codes.
  • routes
    • Contém as regras de configuração da nossa rota.
      • Iremos utilizar o arquivo contido nele.
  • views
    • Todas as views da aplicação estão contidas nesse diretório.

Antes de iniciarmos a “codar” como se não houvesse o amanhã, antes vamos planejar nosso processo e alinhar nosso objetivo.

Temos uma aplicação onde devemos implementar um gerador de QR Code, onde no final deve ser exibido na view para o usuário poder consultar, sendo assim temos:

  1. Devemos criar a estrutura de diretórios para conter nossos códigos.
  2. Implementar a regra de negócio para gerar QR Codes.
  3. Passar para a view o resultado, para que assim o usuário possa consultar a imagem.

Sem mais delongas, vamos iniciar a implementação do novo recurso.

1. Configuração e criação de estrutura de diretório

Na raiz do projeto abra o arquivo composer.json e vamos incluir nossa regra de autoload.

1
2
3
4
5
"autoload":{
    "psr-4":{
        "DiegoBrocanelli\\": "src//"
    }
}

Após criação do autoloader, vamos incluir a lib responsável por gerar o QR Code, inclua a seguinte linha no “require”, sendo:

1
"bacon/bacon-qr-code": "dev-master"

O composer.json deve ficar como o exibido abaixo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
    "name": "diego/post-qrcode",
    "description": "Estrutura de projeto para auxiliar no post sobre QR Code",
    "license": "BSD-3-Clause",
    "authors": [
        {
            "name": "Diego Brocanelli",
            "email": "diegod2@msn.com"
        }
    ],
    "minimum-stability": "dev",
    "require": {
        "silex/silex": "^2.2",
        "twig/twig": "^2.4",
        "phpunit/phpunit": "^6.4@dev",
        "bacon/bacon-qr-code": "dev-master"
    },
    "autoload":{
        "psr-4":{
            "DiegoBrocanelli\\":"src//"
        }
    }
}

Com as devidas inclusões realizadas devemos atualizar as dependências do projeto, no terminal na raiz do projeto execute o seguinte comando:

1
composer update

Devemos agora criar a estrutura de diretório, na raiz do projeto crie um diretório chamado “src” e dentro dele um diretório chamado “QRCode”.

Nossa arquitetura está completa, definimos que nossas regras para geração de QRCode será armazenado dentro do diretório “src/QRCode”.

2. Implementação da estrutura de código

Devemos criar nossa estrutura de código, para que assim torne-se fácil consumido o recurso, facilitando também que qualquer membro da nossa equipe possa dar manutenção ou novas implementações.

Podemos iniciar a construir nossa classe, correto? Não!!!

Antes vamos implementar a camada de testes, caso você não conheça ou tenha hábito de testar suas aplicações recomendo fortemente que adote esta prática, estude sobre, pois é outra vida quando passamos a testar nossas aplicações, trazendo maior qualidade e garantia de funcionamento 🙂

O projeto já dispõem do PHPUnit em sua dependência, uma excelente ferramenta para testar nossa aplicação.

Na raiz do projeto crie o diretório “tests” e dentro dele crie a classe “QRCodeTests.php”, nossa  implementação dos testes deve ficar como o demonstrado abaixo.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?php 

declare(strict_types=1);

use PHPUnit\Framework\TestCase; "src/QRCode"
use DiegoBrocanelli\QRCode\QRCode;

class QRCodeTest extends TestCase
{
    protected $qrCode;

    public function setUp()
    {
        $this->qrCode = new QRCode();
    }

    public function testGenerateQRCodesuccessfully() : void
    {
        $this->assertTrue(
            $this->qrCode->generate('content', 200, 'my_qr_code.png')
        );
    }

    public function testFailGenerateQRCode()
    {
        $this->assertFalse(
            $this->qrCode->generate('my name', 300, '')
        );
    }

    /**
     * @expectedException TypeError
     */
    public function testTypeErrorGenerateQRCode()
    {
        $this->assertFalse(
            $this->qrCode->generate(12, '120', '')
        );
    }
}

Analisando nossa classe de teste, podemos observar que a mesma tem uma implementação simples, porém, abordamos casos de sucesso e falha na criação de QR Code.

Para rodar nossos testes, execute pelo terminal o comando abaixo.

1
vendor/bin/phpunit --verbose tests/

Aqui cabe uma observação, foi incluso o parâmetro “verbose” para exibir com maior detalhe o resultado dos nossos testes.

E como pudemos observar os testes falharam, pois não implementamos nossa regra de negócio, este processo é parte da cultura de testes que estamos seguindo.

Podemos agora implementar nossa classe que irá gerar os QR Codes, dentro do diretório “src/QRCode” crie a classe “QRCode.php” e dentro da classe vamos criar o método “generate”, seguindo nossa estrutura de testes este método recebe três parâmetro e retorna boolean, veja o resultado da implementação logo abaixo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?php 

declare(strict_types=1);

namespace DiegoBrocanelli\QRCode;

use BaconQrCode\Renderer\Image\Png;
use BaconQrCode\Writer;
use Exception;

class QRCode
{
    private $fullPath = __DIR__.'/../../public/img/';

    /**
     * Responsável por gerar a imagem do QR Code e armazenar no diretório:
     * ./public/img
     *
     * @param  string $content
     * @param  int $dimension
     * @param  string $imgName
     * @return boolean
     */
    public function generate(string $content, int $dimension, string $imgName) : bool
    {
        try{
            $renderer = new Png();
            $renderer->setHeight($dimension);
            $renderer->setWidth($dimension);
    
            $writer = new Writer($renderer);
            $writer->writeFile($content, $this->fullPath.$imgName);

            if(!file_exists($this->fullPath.$imgName)){
                throw new Exception();
            }

            return true;

        }catch(Exception $exc){
            
            return false;
        }
    }
}

Vamos analisar as implementações realizadas acima.

  • Linhas 7, 8 e 9.
    • Realizamos as importações dos recursos serão utilizados.
  • Linha 13.
    • Definimos o path absoluto onde as imagens serão armazenadas.
  • Linha27
    • Instanciamos a classe Png, responsável por gerar o arquivo .png.
  • Linhas 28 e 29
    • Definimos as dimensões que a imagem terá, no caso, definimos que sempre será uma imagem quadrada.
  • Linha 31
    • Instanciamos o componente responsável por gerar e armazenar a imagem no diretório especificado.
  • Linha 32
    • Aqui passamos 2 parâmetros, sendo:
      1. O conteúdo que será incluso no QR Code, este conteúdo que os leitores irão exibir. Lembrando que pode ser qualquer string, por exemplo URL.
      2. Passamos o path absoluto da imagem juntamente com seu nome, para armazenar o arquivo .png.
  • Linha 34
    • Verificamos se de fato a imagem foi gerada.

Como observado a implementação é simples, visando seu uso de forma descomplicada.

Vamos executar nossos testes? Execute novamente o comando do phpunit no terminal para rodar os testes.

SUCESSO!!! Todos os nossos testes passaram! 🙂

É fantástico ver os testes passarem, pois temos maior confiança que nossas implementações estão corretas.

Vamos agora implementar nosso código para que quando o usuário acione o botão “Gerar” seja gerado e exibido o QR Code.

Para isso abra o arquivo “routes/routes.php” e vamos consumir nossa implementação, o arquivo deve ficar semelhante ao demonstrado abaixo.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php 

declare(strict_types=1);

require_once __DIR__.'/../config/bootstrap.php';

use DiegoBrocanelli\QRCode\QRCode;

$app->match('/', function() use($app) {
    $request = $search_html = filter_input(INPUT_SERVER, 'REQUEST_METHOD');
    
    $img = '';
    if($request === 'POST'){
        $qrCode = new QRCode();

        $img = 'my_first_qrcode.png';

        $qrCode->generate('Hello World with QR Code', 400, $img);
    }

    return $app['twig']->render('index.html', ['img' => $img]);
});

Ao receber uma “request POST” é instanciado a classe que criamos e passamos as informações para o método “generate”.

Para validarmos nossa aplicação, volte ao navegador e pressione F5 em seguida acionar o botão “Gerar”.

E temos nosso QR Code!!!

qr code implementado no post

Para ler o QR Code abra uma app em seu smartphone e aponte para a imagem, onde será exibido a mensagem que inserimos no corpo do QR Code.

Finalizamos nossa implementação, seguimos nosso planejamento, temos cobertura de testes e o usuário está gerando e visualizando ZR Codes.

Espero que este post possa lhe ajudar, e que facilite seu dia a dia.

Caso tenha alguma dúvida deixe um comentário, será fantástico podermos conversar e aprender cada vez mais 🙂

Grande abraço e sucesso em seus projetos.