Integração com PagSeguro

Update: no tutorial foi utilizado a versão 2.0 da biblioteca, sendo que atualmente está na versão 2.1.0 . Fiz as modificações que sejam compatível para essa nova versão.

Uma das grandes dificuldades quando vamos construir uma loja virtual é relacionado à forma de pagamento para o cliente. Eu tenho um videoaula ensinando a como criar um carrinho de compras, e das perguntas mais freqüentes é relacionado a essa integração.

Hoje temos várias formas de integração para facilitar a vida do cliente, e nossa também, como pagseguro, pagamento digital, moip, f2b, entre outros.

E nesse tutorial vou mostrar uma maneira de utilizar a integração do pagseguro. O próprio pagseguro disponibilizou bibliotecas, com ele de PHP, para realizar essa integração, facilitando o nosso trabalho.

Observações Importantes:

  • Utilizarei como base a minha videoaula de carrinho de compras
  • O pedido não será armazenado em banco de dados.
  • Não mostrarei como fazer validação de dados, existe uma vídeo-aula que ensino a fazer validação, a idéia é como usar a biblioteca do pagseguro.
  • Provavelmente esse tutorial irá virá uma videoaula, só não tenho data prevista para fazer e lançar.
  • Foi adicionado mais um item, que seria o peso do produto. Na videoaula não foi mostrado o peso, mas para cálculo de frete é necessário o peso do produto.

Então vamos começar.

VIDEOAULA

Abaixo o link da vídeo aula do carrinho de compras. O tutorial será baseado nessa vídeo aula:

http://www.davidchc.com.br/video-aula/php/carrinho-de-compras-com-php/

TABELA

Primeiro vamos da uma olhada nossa tabela de produtos:

Se você reparar  tem  um novo campo nessa tabela, diferente da aula de carrinho de compras, que é o Peso. Esse peso é importante para o cálculo do frete. Na biblioteca o peso tem q ser um valor inteiro. Então, se você trabalha com a base em Kg, exemplo: 0,300 , você irá colocar 300.

FORMULÁRIO

Agora vamos dá uma olhada como ficaria nosso carrinho de compras (aparência) com nosso Formulário:

Código do Formulário:

<form class="frmCliente" action="finalizar.php" method="post">
<fieldset>
<legend>Dados do Cliente</legend>
			<label>
				<span>Nome :</span> <input name="nome" type="text" />
			</label>

			<label>
				<span>E-mail :</span> <input name="email" type="text" />
			</label>

			<label>
				<span>DDD :</span> <input maxlength="2" name="ddd" size="2" type="text" />
			</label>

			<label>
				<span>Telefone :</span> <input name="telefone" type="text" />
			</label>
</fieldset>

<fieldset>
<legend>Endereço</legend>
			<label>
				<span>Rua :</span> <input name="rua" type="text" />
			</label>

			<label>
				<span>Número :</span> <input name="número" type="text" />
			</label>

			<label>
				<span>Complemento :</span> <input name="complemento" type="text" />
			</label>

			<label>
				<span>Bairro :</span> <input name="bairro" type="text" />
			</label>

			<label>
				<span>Cidade :</span> <input name="cidade" type="text" />
			</label>

			<label>
				<span>UF :</span> <input maxlength="2" name="uf" size="2" type="text" />
			</label>

			<label>
				<span>CEP :</span> <input name="cep" type="text" />
			</label>

			<input type="submit" value="FInalizar a Compra" />
</fieldset>
</form>

Apenas foi acrescentado o formulário para o preenchimento dos dados do cliente, com isso o cliente não precisará preencher as informações para o pagseguro.

SESSION (CARRINHO)

Sabemos que  os dados do carrinho estão numa session, onde está o ID do produto , e a quantidade. Na vídeo aula fizemos uma estrutura :

$_SESSION[‘carrinho’][‘id_produto’] = qtd_produto

Como temos essas informações na session, podemos resgatar esse valor em outras páginas, basta iniciar a session, como session_start()

BIBLIOTECA DO PAGSEGURO

Agora vamos baixar a biblioteca do pagseguro:

https://pagseguro.uol.com.br/v2/guia-de-integracao/downloads.html

Dentro desse arquivo compactado, você entrará a pasta source, e dentro dela tem  duas pastas: Uma chama examples, como vários exemplos de integração; PagSeguroLibrary, que  é a biblioteca para essa integração. Você irá descompactar essa pasta, a PagSeguroLibrary , e colocar no seu projeto.

CÓDIGO COMPLETO COM COMENTÁRIOS

Irei colocar todo o código com os comentários, creio que dessa maneira fiquei mais fácil pra acompanhar todo o processo.

<?php
//Verifica se foi enviado um metodo POST
if($_SERVER['REQUEST_METHOD'] == 'POST') {

	//Inicia a session
	session_start();

	//inclui o arquivo PagSeguroLibrary.php, para utilizamos a biblioteca
	require_once "PagSeguroLibrary/PagSeguroLibrary.php";

	//inclui a conexão com banco de dados
	require_once "conexao.php";

	/***********************************************************************
	 *
	 * Vamos agora resgatar as informações enviada pelo cliente
	 * Para isso utilizarem a função filter_input_array para resgatar e filtrar
	 * os dados. O recomendado realizar uma validação, pra verificar
	 * se os dados estão de acordo que você espera receber
	 **************************************************************************/
	$post = filter_input_array(INPUT_POST,
							array(
								'nome'	=> FILTER_SANITIZE_STRING,
								'email'	=> FILTER_SANITIZE_STRING,
								'ddd'	=>  FILTER_SANITIZE_ENCODED,
								'telefone' =>FILTER_SANITIZE_STRING,
								'rua'     =>FILTER_SANITIZE_STRING,
								'numero' =>FILTER_SANITIZE_STRING,
								'complemento' =>FILTER_SANITIZE_STRING,
								'bairro' =>FILTER_SANITIZE_STRING,
								'cidade' =>FILTER_SANITIZE_STRING,
								'uf' =>FILTER_SANITIZE_STRING,
								'cep' =>FILTER_SANITIZE_STRING
								)
							);

	/******************************************************************************
	 * Agora vamos vamos integrar com o pagseguro
	 *
	 ******************************************************************************/

	//Instancia a Classe PaymenteRequest
	$pagseguro = new PagSeguroPaymentRequest();

	//Informa o tipo de moeda
	$pagseguro->setCurrency('BRL');

	/** Informo o Tipo de Frete:
	 * 1 => Encomenda normal (PAC)
	 * 2 => SEDEX
	 * 3 => Tipo de frete não especificado
	 */
	$pagseguro->setShippingType(2);

	/**
	 * Informo o código de referência do Pedido.
	 * É importante para identificar o pedido, e também caso queira trabalhar
	 * com retorno automatico.
	 * Se estivesse trabalho com tabelas pra guardar o pedido
	 * seria o ID do Pedido.
	 * Nesse exemplo irei colocar um valor aleatório
	 */
	$pagseguro->setReference(uniqid(true));

	/**
	 * Informo os dados do Cliente
	 * Nome:
	 * Email:
	 * DDD:
	 * Telefone : (valor numerico , exemplo: 6998522)
	 */
	$pagseguro->setSender($post['nome'], $post['email'],
                                $post['ddd'], $post['telefone']);

	/**
	 * Informo as informações do endereço do cliente
	 * CEP
	 * Rua
	 * Numero
	 * Complemento
	 * Bairro
	 * Cidade
	 * Estado
	 * Pais
	 */
	$pagseguro->setShippingAddress($post['cep'], $post['rua'], $post['numero'],
                                                $post['complemento'],  $post['bairro'],
                                                $post['cidade'],$post['uf'], 'BRA');

	/**
	 * Iremos nessa parte selecionar os produtos e adicionar
	 */

	//Resgata os ID's, e transforma em string, separado por virgula
	$ids = implode(', ',array_keys($_SESSION['carrinho']));

	//Cria SQL para seleciona os produtos, filtrando pelo ID dos produtos
	//Dessa maneira irei realizar apenas uma consulta no banco de dados
	$sql   = sprintf("SELECT * FROM produtos WHERE id IN (%s)", $ids);

	//Executa o SQL
	$query  = mysql_query($sql);

	//Resgata os valores da tabela produtos
	while ($row = mysql_fetch_assoc($query)){
		$id      = $row['id'];
		$produto = $row['produto'];
		$qtd     = $_SESSION['carrinho'][$id];
		$preco   = $row['preco'];
		$peso    = $row['peso'];

		/**
		 * Agora vamos adicionar os produtos.
		 * Algo importante é relacionado ao peso do produto.
		 * Esse valor terá que ser inteiro. Então 0,300 será 300.
		 * As informações a serem adiciona no metodo addItem
		 * ID
		 * Produto
		 * Quantidade
		 * Valor
		 * Peso
		 */
		$pagseguro->addItem($id, $produto, $qtd, $preco, $peso);

	}

	/**
	 * Iremos agora utilizar a classe AccountCredentials para adicionar as nossas credencias
	 * Quer seria o email cadastrado no pagseguro, e TOKEN gerado no pagseguro
	 */
	$credenciais = new PagSeguroAccountCredentials('seu_email@_no_pagseguro.com', 'VALOR DO TOKEN');

	/**
	 * Agora vamos adicionar as credenciais informada na classe AccountCredentials
	 * Com isso será gerado uma URL para o pagseguro
	 *
	 */
	$url = $pagseguro->register($credenciais);

	//Agora vamos redirecionar para o PagSeguro
	header("Location: $url");

}

Essa maneira que mostrei é apenas uma forma de utilizar as classes disponibilizadas pelo pagseguro, você verá no manual da biblioteca várias formas de utilizá-las também. Espero que tenha ajudado, e até uma próxima.

51 Comentários.

  1. Lucas Silva disse:

    Muito bom David, isso vai ser de muita ajuda pra mim, to pretendendo desenvolver uma loja pra mim!

    PS: já dei minha contribuição com retweet e LIKE =)

  2. Atanaildo disse:

    Fala David! Muito bom o artigo já estava procurando como fazer isso a um tempo srsrs muito obg msm.
    Agora vc poderia me tirar uma duvida, o meu deu os seguintes erros:

    Fatal error: Uncaught exception ‘Exception’ with message ‘CURL library is required.’ in D:\Dropbox\Notebook atanaildo\fabulosa\include\PagSeguroLibrary\utils\HttpConnection.class.php on line 30

    Exception: CURL library is required. in D:\Dropbox\Notebook atanaildo\fabulosa\include\PagSeguroLibrary\utils\HttpConnection.class.php on line 30

    vc sabe me informar oq pode ser?

    • admin disse:

      Atanaildo, pela mensagem , vc tem q está habilitado a biblioteca CURL para poder funcionar

      • Atanaildo disse:

        David, bom Dia! muito obg pela resposta eu consegui resolver este erro ai habilitando a biblioteca CURL. Só que agora esta dando este erro:

        Fatal error: Uncaught exception ‘Exception’ with message ‘CURL can’t connect: couldn’t connect to host’ in D:\Dropbox\Notebook atanaildo\fabulosa\include\PagSeguroLibrary\utils\HttpConnection.class.php on line 96

        Exception: CURL can’t connect: couldn’t connect to host in D:\Dropbox\Notebook atanaildo\fabulosa\include\PagSeguroLibrary\utils\HttpConnection.class.php on line 96

  3. Romário disse:

    Olha só o que ta acontecendo comigo! =( alguma solução? Obrigado, ótimo tutorial.
    Fatal error: Uncaught exception ‘PagSeguroServiceException’ with message ‘[HTTP 400] – BAD_REQUEST [11033] – Item description is required.’ in C:\wamp\www\PVCNEW\produtos\PagSeguroLibrary\service\PaymentService.class.php:66 Stack trace: #0 C:\wamp\www\PVCNEW\produtos\PagSeguroLibrary\domain\PaymentRequest.class.php(420): PaymentService::createCheckoutRequest(Object(AccountCredentials), Object(PaymentRequest)) #1 C:\wamp\www\PVCNEW\produtos\finalizar.php(138): PaymentRequest->register(Object(AccountCredentials)) #2 {main} thrown in C:\wamp\www\PVCNEW\produtos\PagSeguroLibrary\service\PaymentService.class.php on line 66

  4. Edson Souza disse:

    Muito bom o Tutorial, estive acompanhando, me indicaram o teu tutorial pelo facebook, e realmente é bem interessante. Fui corrigindo os erros que me aparecia por precisar configurar umas coisas antes. Até que ele me mostrou esse erro:

    Fatal error: Uncaught exception ‘PagSeguroServiceException’ with message ‘[HTTP 400] – BAD_REQUEST [11024] – Items invalid quantity.’ in C:\wamp\www\mxcatalogo\PagSeguroLibrary\service\PaymentService.class.php:66 Stack trace: #0 C:\wamp\www\mxcatalogo\PagSeguroLibrary\domain\PaymentRequest.class.php(420): PaymentService::createCheckoutRequest(Object(AccountCredentials), Object(PaymentRequest)) #1 C:\wamp\www\mxcatalogo\pagseguro.php(139): PaymentRequest->register(Object(AccountCredentials)) #2 {main} thrown in C:\wamp\www\mxcatalogo\PagSeguroLibrary\service\PaymentService.class.php on line 66

  5. Edson Souza disse:

    É parecido com o erro do amigo a cima, porém eu não consegui resolver, se puder me ajudar.

    • admin disse:

      Edson, eu revi o tutorial, e encontrei um erro na hora de resgatar o nome do produto, antes estava assim:

             $produto = $produto['produto'];
      

      E teria que está assim:

      
      $produto = $row['produto'];
      
      

      Dá uma olhada, e ver se não era isso q tá dando erro.

  6. Edson Souza disse:

    Voltando aqui, novamente ne rs, bem eu fiz exatamente como estava o teu e funcionou perfeitamente, porém ao tentar adaptar ao um catalogo já existente, deu erro em relação a quantidade “[HTTP 400] – BAD_REQUEST [11024] – Items invalid quantity.” bem foi o que eu entendi, eu dei um print r no array, e me retornou “Array ( [0] => Array ( [Nulo] => Nulo [709] => Array ( [cod] => 709 [titulo] => 2011 Fox Racing V1 Checked Out [qtd] => 1 ) [708] => Array ( [cod] => 708 [titulo] => EVS F2 Youth Modular Preto. [qtd] => 1 ) ) ) “, se for possivel dar uma idéia de como consertar isso eu agradeço, se não for possivel eu entendo o teu lado. Agradeço pelo tutorial e pela atenção.

  7. Edson Souza disse:

    Cara não tu já me ajudou, eu vi aquela video aula sobre array, e consegui resolver esse problema que mencionei acima.

    Muito obrigado pelas videos aulas.

    • admin disse:

      O site tá fora do ar

      Update

      Veja se está está passando ID pela URL, se for a mesma a ID ele vai sobreescrever.

      http://pastebin.com/sw3KJSfT

      E sobre q query string, o código acima mostra como seria.

      • Werdeson disse:

        Conseguir linkar agora, obrigado David, porém continua adicionar mais um produto ao carrinho, ele sempre adiciona mais um no mesmo produto e aumenta o valor do mesmo

        • admin disse:

          Então vc está enviando o mesmo ID, veja essa parte:

          $id = intval($_GET['id']);
          if(!isset($_SESSION['carrinho'][$id])){
                   $_SESSION['carrinho'][$id] = 1;
          }else{
                $_SESSION['carrinho'][$id] += 1;
          }
          

          Se fosse escrever isso:

          Resgata o ID via URL
          Verifica se o ID está inserido no array
          Se estiver, inclui o valor 1
          Senão incrementa + 1

          Se o valor o produto estiver no ID, ele vai incrementar. Vc pode tirar esse incremento

          $id = intval($_GET['id']);
          if(!isset($_SESSION['carrinho'][$id])){
                   $_SESSION['carrinho'][$id] = 1;
          }
          

          Recomendo essa minha video aula sobre entendendo o array q pode te ajudar a manipular melhor:

          http://www.davidchc.com.br/video-aula/php/entendendo-array-no-php/

  8. Tuk disse:

    Fatal error: Uncaught exception ‘PagSeguroServiceException’ with message ‘[HTTP 401] – UNAUTHORIZED ‘

    http://forum.imasters.com.br/topic/449259-implementacao-pagseguro/

    • admin disse:

      Pelo q vi esse servidor testes ele recebe um post, que feito com a classe anterior, e nessa é tudo feita pela nova API, provavelmente não vai funcionar.

  9. Croata disse:

    David , que fantastico esse tutorial , e aquele tutorial ,que deveria vir em todo manual de bibliotecas , obrigado mesmo !!!

    e como o Lucas , vou esperar ansioso pelo retorno automatico

  10. Josiélio disse:

    O pessoal do Downs Master, me indicou o seu blog pra eu ver tutorias avançados, você manja muito David! parabéns :)

  11. Fernando disse:

    Olá David creio que seu post irá salvar miinha pele agora, me da um help em um erro aqui?
    Parece que o meu codigo não encontra a classe de pagamento;
    Vlw cara.

    Fatal error: Class ‘PaymentRequest’ not found in /home/storage/9/f3/a2/jolietjolie/public_html/1bk/pagseguro.php on line 49

    • admin disse:

      Fernando, eu fiz o tutorial com a versão 2.0, e vc ter pegado a versão 2.1. No caso ocorreu algumas mudanças, e uma delas, é as classes agora estão com nome pagseguro na frente, exemplo: PagSeguroPaymentRequest. Por isso ocorre está ocorrendo. Depois irei atualizar o tutorial, pra essa nova versão.

  12. mauro disse:

    David na hora de enviar os dados esta dando o seguinte

    Warning: mysql_fetch_assoc() expects parameter 1 to be resource, boolean given in C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\carrinho\finalizar.php on line 105 Fatal error: Uncaught exception ‘PagSeguroServiceException’ with message ‘[HTTP 400] – BAD_REQUEST [11024] – Items invalid quantity.’ in C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\carrinho\PagSeguroLibrary\service\PagSeguroPaymentService.class.php:66 Stack trace: #0 C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\carrinho\PagSeguroLibrary\domain\PagSeguroPaymentRequest.class.php(420): PagSeguroPaymentService::createCheckoutRequest(Object(PagSeguroAccountCredentials), Object(PagSeguroPaymentRequest)) #1 C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\carrinho\finalizar.php(138): PagSeguroPaymentRequest->register(Object(PagSeguroAccountCredentials)) #2 {main} thrown in C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\carrinho\PagSeguroLibrary\service\PagSeguroPaymentService.class.php on line 66

    • admin disse:

      Mauro, veja que o primeiro erro é relacionado ao mysql_feych_assoc, provavelmente o erro está na hora de executar o SQL com mysql_query

  13. mauro disse:

    Poderia me ajudar?

  14. mauro disse:

    Boa noite a todos!
    Estou tentando fazer o tutorial do David CHC mas na hora da integração esta dando seguinte erro: Warning: mysql_fetch_assoc() expects parameter 1 to be resource, boolean given in C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\meu_site\finalizar.php on line 105 Fatal error: Uncaught exception ‘PagSeguroServiceException’ with message ‘[HTTP 400] – BAD_REQUEST [11024] …
    Alguém ai sabe como sanar este erro?

    Desde já Obrigado!

    • admin disse:

      Mauro, como te respondi anteriormente, o vc precisa ver a execução do SQL. Adicione um die(mysql_error()) pra ver a mensagem de erro,

       $query  = mysql_query($sql) or die(mysql_error());
      
  15. Caio Mecina disse:

    Boa noite não consigo incluir o valor do frete alguem poderia me ajudar? tudo está funcionando apenas estou com problemas na hora de inclusão do valor do frete. o itemShippingCost1.

    Favor aguardo resposta.

    Att;

    Caio Mecina

  16. Guilherme disse:

    Olá, como faço para que o pagseguro não peça endereço de entrega, logo que o produto é digital e não é necessário informar este.

    Obrigado!

  17. Isael Ferreira disse:

    Ae ficou “trímassa” parceiro ;)
    http://img571.imageshack.us/img571/3103/capturarkmp.png
    Pra quem não deu conta de fazer basta prestar atenção que vai dar certo, aqui funcionou sem ter que fazer muita alteração no código.

  18. antonia disse:

    alguem pode me ajudar me explique como trabalhar com o pagseguro

    • David CHC disse:

      antonia, o pagseguro é intermediário, onde a pessoa pagará no pagseguro a compra, terão mudança de status informando a situação do pagamento, e depois de 14 dias, vc pode transferir esse dinheiro pra vc sua conta.

  19. Nádya disse:

    David, boa tarde!
    Só estou escrevendo porque realmente não encontro solução para este problema. Fiz tudo direitinho, e aparentemente esta tudo funcionando, desde o carrinho de compras até a requisição de pagamento. O problema é no email do comprador. Aparece uma mensagem de erro do pagseguro e eu não consigo achar uma solução. Desculpe incomoda-lo, mas será que dá pra me dar uma mãozinha?

    O erro:

    Fatal error: Uncaught exception ‘PagSeguroServiceException’ with message ‘[HTTP 400] – BAD_REQUEST [11010] – senderEmail invalid value: nadyadg@hotmail.com ‘ in /home/astyncom/public_html/PagSeguroLibrary/service/PagSeguroPaymentService.class.php:66 Stack trace: #0 /home/astyncom/public_html/PagSeguroLibrary/domain/PagSeguroPaymentRequest.class.php(434): PagSeguroPaymentService::createCheckoutRequest(Object(PagSeguroAccountCredentials), Object(PagSeguroPaymentRequest)) #1 /home/astyncom/public_html/finalizar.php(134): PagSeguroPaymentRequest->register(Object(PagSeguroAccountCredentials)) #2 {main} thrown in /home/astyncom/public_html/PagSeguroLibrary/service/PagSeguroPaymentService.class.php on line 66

    Faz 2 dias que tô nesse e não acho onde errei! Valew!

    • David CHC disse:

      Nádya, aparentemente tá com problema relacionado a credencial, no caso o e-mail q vc tá informando. É esse email mesmo que está criado a conta no pagseguro?

      $credenciais = new PagSeguroAccountCredentials('nadyadg@hotmail.com', 'VALOR DO TOKEN');
      
      • Nádya disse:

        David, obrigada por responder. Este email que esta dando erro no caso é o do comprador. Utilizei exatamente como no tutorial. Quando apago no código $post['email'], e substituo pelo email “nadyadg@hotmail.com” ele executa a venda normalmente e aceita o email digitado. Não entendo porque ele não aceita o email que veio do post. Tá estranho isso né.

        • David CHC disse:

          Nádya, tenta verificar se o email está sendo recebido via post, tente dá um print_r no $post

          print_r($post);
          
          • Nádya disse:

            David, fiz e esta recebendo o post normal, o e-mail aparece. Interessante que colocando o email manualmente ele vai. E mesmo mudando para outros métodos, ele não aceita o email pelo post. Pior que não acho nada parecido com esse erro na web pra ajudar :O(

          • Nádya disse:

            David, uma outra dúvida, acho que você vai poder me ajudar. Como resgato o valor do código do pedido? É que preciso gravar no banco de dados, e vou colocar a inclusão antes de redirecionar para url, se desse para pegar o mesmo valor de $pagseguro->setReference(uniqid(true)); seria perfeito!
            Muito obrigada pela ajuda,

  20. Nádya disse:

    David, esquece a segunda pergunta, já consegui, fiz assim:

    $uniqid = uniqid(true);
    $pagseguro->setReference($uniqid);

    No bd usei a variavel $uniqid

    (Mas eu aguardo uma ajuda com o primeiro problema se der…rsrsrs)

    Valew!

    • David CHC disse:

      @Nádya, vc tá usando o mesmo email que tá configurado na sua conta do pagseguro? Se tiver, tente utilizar outro email pra fazer um teste.


Criando uma função...

Recebi um dúvida do Dymmer Kellson , sobre um questão ...

Recuperando total de...

Nessa aula vou mostrar como recuperar o total de compartilhamento ...

Recuperar quantidade...

Nessa aula mostro como recuperar informações de URL no facebook, ...

Transformando as out...

O opencart por padrão trabalhar com a URL amigáveis dos ...

Trabalhando com busc...

Para quem trabalhar com URL amigável, um momento terá que ...

Criando uma função

Recebi um dúvida do Dymmer Kellson , sobre um questão ...

Recuperando total de

Nessa aula vou mostrar como recuperar o total de compartilhamento ...

Recuperar quantidade

Nessa aula mostro como recuperar informações de URL no facebook, ...

Transformando as out

O opencart por padrão trabalhar com a URL amigáveis dos ...

Trabalhando com busc

Para quem trabalhar com URL amigável, um momento terá que ...