Como impedir o reenvio de formulário quando a página é atualizada (F5 / CTRL + R)


132

Eu tenho um formulário simples que envia texto para minha tabela SQL. O problema é que, depois que o usuário envia o texto, ele pode atualizar a página e os dados são enviados novamente sem preencher o formulário novamente. Eu poderia redirecionar o usuário para outra página após o envio do texto, mas quero que os usuários permaneçam na mesma página.

Lembro-me de ler algo sobre dar a cada usuário um ID de sessão exclusivo e compará-lo com outro valor que resolveu o problema que estou tendo, mas esqueci onde ele está.



1
Por que você não deseja redirecionar o usuário para outra página?
Adam

@ Adam: Como é um excesso fazer outra solicitação ao servidor que, por sua vez, buscará alguns dados do DB novamente. Mas isso é desperdício de recursos porque nós já buscar todos os dados necessários durante o processamento POSTdo pedido
Eugen Konkov

@EugenKonkov no padrão PRG, você redirecionaria para uma página que mostra uma mensagem de sucesso. Nenhuma busca adicional do DB é necessária.
Adam

@ Adam: Você também pode exibir o registro inteiro criado pelos POSTdados. Nesse caso, você precisa SELECTdo DB. Por exemplo, quando você cria a fatura você será redirecionado para /invoices/53o qual exibir toda a factura em vez de apenas 'sucesso'
Eugen Konkov

Respostas:


96

Use o padrão Publicar / Redirecionar / Obter. http://en.wikipedia.org/wiki/Post/Redirect/Get

Com o meu site, vou armazenar uma mensagem em um cookie ou sessão, redirecionar após a postagem, ler o cookie / sessão e limpar o valor dessa sessão ou variável de cookie.


1
Isso torna o Chrome inutilizável para o desenvolvimento, onde os negócios exigem apenas uma postagem!
John Peters

26
Se você usa o padrão PRG, deixa a página certa? A questão não era como fazer as coisas funcionarem quando não redirecionava?
Adam

1
Parece-me que, se você redirecionar para a mesma página, $ _POST será limpo. Pelo que entendi, esse foi o efeito desejado. Esse era o MEU efeito desejado, de qualquer maneira. Acho que a resposta seria melhor se explicitasse isso.
Donutguy640 01/05/19

Funciona bem, minha única recomendação é garantir que você ative o rigoroso teste de erros para que você esteja capturando erros localmente durante o desenvolvimento, caso contrário eles poderão passar despercebidos.
Maurice

Não responde a pergunta. Não sei por que é a resposta aceita.
YungGun 5/09/19

124

Gostaria também de salientar que você pode usar uma abordagem de javascript, window.history.replaceStatepara impedir o reenvio no botão Atualizar e Voltar.

<script>
    if ( window.history.replaceState ) {
        window.history.replaceState( null, null, window.location.href );
    }
</script>

Prova de conceito aqui: https://dtbaker.net/files/prevent-post-resubmit.php

Eu ainda recomendaria uma abordagem Post / Redirect / Get, mas esta é uma nova solução JS.


1
Obrigado, @dtbaker, é :) incrível
Gufran Hasan

1
Tks, este é um trabalho perfeito para mim, ele só teve que criar página 404 do usuário evitar missunderstanding
Tess Hsu

Simplesmente incrível. Obrigado
user4906240

2
ele não funciona no Safari, ele mudou href mas ainda manter os dados com solicitação post para enviar
Vo Thanh Tung

Isso funcionou para mim, obrigado! Por que você recomenda a abordagem PRG?
IJassar 11/11

16

Você realmente deve usar um padrão Post Redirect Get para lidar com isso, mas se de alguma forma acabou em uma posição em que o PRG não é viável (por exemplo, o próprio formulário está em uma inclusão, impedindo redirecionamentos), você pode usar alguns dos parâmetros de solicitação para criar uma sequência com base no conteúdo e verifique se você ainda não a enviou.

//create digest of the form submission:

    $messageIdent = md5($_POST['name'] . $_POST['email'] . $_POST['phone'] . $_POST['comment']);

//and check it against the stored value:

    $sessionMessageIdent = isset($_SESSION['messageIdent'])?$_SESSION['messageIdent']:'';

    if($messageIdent!=$sessionMessageIdent){//if its different:          
        //save the session var:
            $_SESSION['messageIdent'] = $messageIdent;
        //and...
            do_your_thang();
    } else {
        //you've sent this already!
    }

Obrigado por compartilhar, mas isso não parece funcionar. Atualizar a página realmente envia novamente o formulário para mim. Talvez esteja faltando alguma coisa?
aLearner

A atualização da página reenviará tudo, mas optamos apenas por processar os dados de envio se forem diferentes dos dados enviados na última vez (que armazenamos na sessão var 'messageIdent'). Você está processando o envio do formulário na cláusula 'if messageIdents are different' (ou seja, onde 'do_your_thang ()' está)?
Moob

Obrigado pela sua resposta. Acabei implementando o padrão Post / Redirect / Get, então, não me lembro agora do que exatamente estava me incomodando. Mais uma vez obrigado por voltar.
aLearner

Esse método não visa bloquear o reenvio ... mas Detectar o reenvio, para que você possa alterar seu código para não "fazer" o que você faria se esse fosse um novo envio. Em outras palavras: com esse método, você pode detectar o envio "original" e colocar seus dados. Se NÃO for original, não coloque seus dados. Mostre um aviso de "tentativa de enganar" ou talvez mostre uma "confirmação".
TheSatinKnight

Para que isso funcione, você deve ter iniciado uma sessão adicionando session_start();no início do arquivo. w3schools.com/php/php_sessions.asp diz Nota: A função session_start () deve ser a primeira coisa em seu documento. Antes de qualquer tag HTML.
wkille

16

Eu uso essa linha javascript para bloquear o pop-up solicitando o reenvio do formulário na atualização depois que o formulário é enviado.

if ( window.history.replaceState ) {
  window.history.replaceState( null, null, window.location.href );
}

Basta colocar esta linha no rodapé do seu arquivo e ver a mágica


Seria legal uma versão disso que não pode ser desativada do lado do cliente, mas é curta, fácil, rápida ... e faça o que for necessário. Mantém o histórico para que o usuário possa voltar, sem reenviar a postagem.
Péter Vértényi 6/02/19

16

Você pode impedir o reenvio de formulário por meio de uma variável de sessão.

Primeiro você precisa definir rand()em uma caixa de texto e $_SESSION['rand']na página do formulário:

<form action="" method="post">
  <?php
   $rand=rand();
   $_SESSION['rand']=$rand;
  ?>
 <input type="hidden" value="<?php echo $rand; ?>" name="randcheck" />
   Your Form's Other Field 
 <input type="submit" name="submitbtn" value="submit" />
</form>

Depois disso, verifique $_SESSION['rand']com o $_POST['randcheck']valor da caixa de texto como este:

if(isset($_POST['submitbtn']) && $_POST['randcheck']==$_SESSION['rand'])
{
    // Your code here
}

3
podemos usar <input type="hidden" name="randcheck" id="randcheck" value="<?php echo microtime(); ?>" />em vez
Nikolay Bronskiy

Sim, podemos usar microtime () e time () também em vez de rand (), qualquer função ou variável que dê um valor diferente, podemos usá-lo. MAS certifique-se de definir esse valor para a variável SESSION. aqui SESSÃO é necessário verificar com o campo de verificação aleatória e impedir o reenvio do formulário.
Savoo

a variável da sessão não deve ser limpa depois de verificar se a sessão e os pós-vars correspondem?
Denoise # 30/19

1
@denoise Eu acredito que a idéia do @Savoo é que, após $_POSTos dados do formulário, a mesma página seja recarregada, redefinindo a sessão e postando variáveis. Também a criação de variáveis ​​deve ocorrer após verificar se as variáveis ​​coincidem. Portanto, unsetnão é necessário.
HalfMen

13

Quando o formulário é processado, você redireciona para outra página:

... process complete....
header('Location: thankyou.php');

você também pode redirecionar para a mesma página.

se você estiver fazendo algo como comentários e quiser que o usuário permaneça na mesma página, use o Ajax para lidar com o envio do formulário


12

Encontrei a próxima solução alternativa. Você pode escapar do redirecionamento após processar a POSTsolicitação manipulandohistory objeto.

Então você tem o formulário HTML:

<form method=POST action='/process.php'>
 <input type=submit value=OK>
</form>

Quando você processa este formulário no servidor, em vez de redirecionar o usuário /the/result/page, configure o Locationcabeçalho da seguinte maneira:

$cat process.php
<?php 
     process POST data here
     ... 
     header('Location: /the/result/page');
     exit();
?>

insira a descrição da imagem aqui

Após o processamento dos POSTdados editados, você torna pequeno <script>e o resultado/the/result/page

<?php 
     process POST data here
     render the <script>         // see below
     render `/the/result/page`   // OK
?>

O <script>que você deve render:

<script>
    window.onload = function() {
        history.replaceState("", "", "/the/result/page");
    }
</script>

O resultado é:

insira a descrição da imagem aqui

como você pode ver, os dados do formulário são POSTeditados no process.phpscript.
Este script processou POSTdados e renderização de /the/result/pageuma só vez com:

  1. sem redirecionamento
  2. não há POSTdados quando você atualiza a página (F5)
  3. não há POSTquando você navega para a página anterior / seguinte através do histórico do navegador

UPD

Como outra solução, peço que o recurso solicite à equipe do Mozilla FireFox que permita aos usuários configurar o NextPagecabeçalho que funcionará como Locationcabeçalho e farápost/redirect/get padrão obsoleto.

Em resumo. Quando o processo do servidor forma POSTdados com êxito, ele:

  1. Configurar NextPagecabeçalho em vez deLocation
  2. Renderize o resultado do processamento de POSTdados do formulário como renderizaria para GETsolicitação no post/redirect/getpadrão

O navegador, por sua vez, quando vê o NextPagecabeçalho:

  1. Ajuste window.locationcomNextPage valor
  2. Quando o usuário atualizar a página, o navegador negociará a GETsolicitação em NextPagevez de reformular os POSTdados

Eu acho que isso seria excelente se implementado, não seria? =)


11
  1. Use o cabeçalho e redirecione a página.

    header("Location:your_page.php"); Você pode redirecionar para a mesma página ou página diferente.

  2. Desmarque $ _POST depois de inseri-lo no banco de dados.

    unset($_POST);


54
A desativação de $ _POST não afeta o reenvio de formulário, pelo menos não no Chrome.
Gavin

2
Isso não vai funcionar. Quando o usuário voltar para a página anterior, execute a configuração das variáveis ​​POST novamente.
Sandhu

Qual o motivo do uso unset? Por favor, adicione alguma explicação à sua resposta para que outras pessoas possam aprender com ela
Nico Haase

7

Uma maneira bastante segura é implementar um ID exclusivo na postagem e armazená-lo em cache no

<input type='hidden' name='post_id' value='".createPassword(64)."'>

Então, no seu código, faça o seguinte:

if( ($_SESSION['post_id'] != $_POST['post_id']) )
{
    $_SESSION['post_id'] = $_POST['post_id'];
    //do post stuff
} else {
    //normal display
}

function createPassword($length)
{
    $chars = "abcdefghijkmnopqrstuvwxyz023456789";
    srand((double)microtime()*1000000);
    $i = 0;
    $pass = '' ;

    while ($i <= ($length - 1)) {
        $num = rand() % 33;
        $tmp = substr($chars, $num, 1);
        $pass = $pass . $tmp;
        $i++;
    }
    return $pass;
}

Na verdade, acabei de escrever algo parecido com isso, mas não tive problemas para criar uma senha, apenas enumerei meus formulários (por exemplo: etapas 1 a 5); portanto, se eles são iguais, é legal seguir em frente, caso contrário, não salve em db ou envie e-mails. Mas deixe o usuário chegar onde quer que ele o leve.
Fernando Silva

1
Penso que esta é uma solução melhor do que recarregar a página, pois mostro uma mensagem ao publicar com êxito e recarregar a página excluirá a mensagem. esta grelha funciona para mim, você também pode usar um uniqid
Julio Popócatl

6

Esse método funciona bem para mim e acho que é o mais simples de fazer esse trabalho.

A idéia geral é redirecionar o usuário para algumas outras páginas após o envio do formulário, o que interromperia o reenvio do formulário na atualização da página. Ainda assim, se você precisar manter o usuário na mesma página após o envio do formulário, poderá fazê-lo de várias maneiras, mas aqui estou descrevendo o método javascript.

Método Javascript

Esse método é bastante fácil e bloqueia o pop-up solicitando o reenvio do formulário na atualização assim que o formulário é enviado. Basta colocar esta linha de código javascript no rodapé do seu arquivo e ver a mágica.

<script>
if ( window.history.replaceState ) {
  window.history.replaceState( null, null, window.location.href );
}
</script>


Isso me ajuda também
Ankit

4

Javascript

Esse método é bastante fácil e bloqueia o pop-up solicitando o reenvio do formulário na atualização assim que o formulário é enviado. Basta colocar esta linha de código javascript no rodapé do seu arquivo e ver a mágica.

<script>
    if ( window.history.replaceState ) {
        window.history.replaceState( null, null, window.location.href );
    }
</script>

3

Basta redirecioná-lo para a mesma página depois de usar os dados do formulário, e ele funciona. Eu tentei.

header('location:yourpage.php');

4
Isso está apenas repetindo a mesma resposta que outra pessoa deu anos antes. (Na verdade os outros dois!)
Nick Rice,

Se você duplicar as respostas de outras pessoas, adicione pelo menos alguma explicação à sua resposta para torná-la interessante
Nico Haase

3

Uma versão refinada da postagem de Moob. Crie um hash do POST, salve-o como um cookie de sessão e compare os hashes a cada sessão.

// Optionally Disable browser caching on "Back"
header( 'Cache-Control: no-store, no-cache, must-revalidate' );
header( 'Expires: Sun, 1 Jan 2000 12:00:00 GMT' );
header( 'Last-Modified: ' . gmdate('D, d M Y H:i:s') . 'GMT' );

$post_hash = md5( json_encode( $_POST ) );

if( session_start() )
{
    $post_resubmitted = isset( $_SESSION[ 'post_hash' ] ) && $_SESSION[ 'post_hash' ] == $post_hash;
    $_SESSION[ 'post_hash' ] = $post_hash;
    session_write_close();
}
else
{
    $post_resubmitted = false;
}

if ( $post_resubmitted ) {
  // POST was resubmitted
}
else
{
  // POST was submitted normally
}

2

Basicamente, você precisa redirecionar para fora dessa página, mas isso ainda pode causar problemas enquanto a Internet está lenta (Redirecionar cabeçalho do lado do servidor)

Exemplo de cenário básico:

Clique no botão enviar duas vezes

Maneira de resolver

  • Lado do cliente

    • Desabilitar o botão enviar assim que o cliente clicar nele
    • Se você estiver usando o Jquery: Jquery.one
    • Padrão PRG
  • Lado do servidor

    • Usando carimbo de data / hora de hash baseado em diferenciação / carimbo de data / hora quando a solicitação foi enviada.
    • Use tokens de solicitação. Quando a carga principal for atribuída, atribua uma solicitação temporária que, se repetida, será ignorada.

2

Como evitar o reenvio de formulários php sem redirecionar. Se você estiver usando $ _SESSION (após o session_start) e um formulário $ _POST, poderá fazer algo assim:

if ( !empty($_SESSION['act']) && !empty($_POST['act']) && $_POST['act'] == $_SESSION['act'] ) {
  // do your stuff, save data into database, etc
}

No seu formulário html, coloque isto:

<input type="hidden" id="act" name="act" value="<?php echo ( empty($_POST['act']) || $_POST['act']==2 )? 1 : 2; ?>">
<?php
if ( $_POST['act'] == $_SESSION['act'] ){
    if ( empty( $_SESSION['act'] ) || $_SESSION['act'] == 2 ){
        $_SESSION['act'] = 1;
    } else {
        $_SESSION['act'] = 2;
    }
}
?>

Portanto, toda vez que o formulário é enviado, um novo ato é gerado, armazenado em sessão e comparado com o ato posterior.

Ps: se você estiver usando um formulário Get, poderá alterar facilmente todo o POST com GET e também funcionará.


1

Depois de inseri-lo no banco de dados, chame o método unset () para limpar os dados.

não definido ($ _ POST);

Para impedir a inserção de dados de atualização, faça um redirecionamento de página para a mesma página ou página diferente após a inserção do registro.

cabeçalho ('Localização:'. $ _ SERVER ['PHP_SELF']);


1
Por favor, adicione alguma explicação à sua resposta para que outras pessoas possam aprender com ela - por que essa unsetligação é necessária? O que aconteceria se você a ignorasse?
Nico Haase

0

Usar o padrão Post / Redirect / Get da resposta do Keverw é uma boa idéia. No entanto, você não consegue permanecer na sua página (e acho que era isso que estava pedindo?) Além disso, às vezes, pode falhar :

Se um usuário da web atualizar antes que o envio inicial seja concluído devido ao atraso do servidor, resultando em uma solicitação HTTP POST duplicada em determinados agentes do usuário.

Outra opção seria armazenar em uma sessão se o texto deveria ser gravado no seu banco de dados SQL como este:

if($_SERVER['REQUEST_METHOD'] != 'POST')
{
  $_SESSION['writeSQL'] = true;
}
else
{
  if(isset($_SESSION['writeSQL']) && $_SESSION['writeSQL'])
  {
    $_SESSION['writeSQL'] = false;

    /* save $_POST values into SQL */
  }
}

0

Como já foi dito, não é possível deixar de usar o post / redirecionar / get. Mas, ao mesmo tempo, é muito fácil fazer o que você deseja fazer no lado do servidor.

Na sua página POST, você simplesmente valida a entrada do usuário, mas não age sobre ela; em vez disso, você a copia para uma matriz SESSION. Você então redireciona de volta à página principal de envio novamente. Sua página principal de envio começa verificando se a matriz SESSION que você está usando existe e, em caso afirmativo, copie-a para uma matriz local e desative-a. A partir daí você pode agir sobre isso.

Dessa forma, você realiza todo o seu trabalho principal apenas uma vez, alcançando o que deseja fazer.


0

Procurei uma solução para evitar o reenvio em um grande projeto posteriormente. O código funciona muito com $ _GET e $ _POST e não posso alterar o comportamento dos elementos do formulário sem o risco de erros imprevistos. Então, aqui está o meu código:

<!-- language: lang-php -->
<?php

// Very top of your code:

// Start session:
session_start();

// If Post Form Data send and no File Upload
if ( empty( $_FILES ) && ! empty( $_POST ) ) {
    // Store Post Form Data in Session Variable
    $_SESSION["POST"] = $_POST;
    // Reload Page if there were no outputs
    if ( ! headers_sent() ) {
        // Build URL to reload with GET Parameters
        // Change https to http if your site has no ssl
        $location = "https://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
        // Reload Page
        header( "location: " . $location, true, 303 );
        // Stop any further progress
        die();
    }
}

// Rebuilt POST Form Data from Session Variable
if ( isset( $_SESSION["POST"] ) ) {
    $_POST = $_SESSION["POST"];
    // Tell PHP that POST is sent
    $_SERVER['REQUEST_METHOD'] = 'POST';
}

// Your code:
?><html>
    <head>
        <title>GET/POST Resubmit</title>
    </head>
    <body>

    <h1>Forms:</h1>
    <h2>GET Form:</h2>
    <form action="index.php" method="get">
        <input type="text" id="text_get" value="test text get" name="text_get"/>
        <input type="submit" value="submit">
    </form>
    <h2>POST Form:</h2>
    <form action="index.php" method="post">
        <input type="text" id="text_post" value="test text post" name="text_post"/>
        <input type="submit" value="submit">
    </form>
    <h2>POST Form with GET action:</h2>
    <form action="index.php?text_get2=getwithpost" method="post">
        <input type="text" id="text_post2" value="test text get post" name="text_post2"/>
        <input type="submit" value="submit">
    </form>
    <h2>File Upload Form:</h2>
    <form action="index.php" method="post" enctype="multipart/form-data">
        <input type="file" id="file" name="file">
        <input type="submit" value="submit">
    </form>

    <h1>Results:</h1>
    <h2>GET Form Result:</h2>
    <p>text_get: <?php echo $_GET["text_get"]; ?></p>
    <h2>POST Form Result:</h2>
    <p>text_post: <?php echo $_POST["text_post"]; ?></p>
    <h2>POST Form with GET Result:</h2>
    <p>text_get2: <?php echo $_GET["text_get2"]; ?></p>
    <p>text_post2: <?php echo $_POST["text_post2"]; ?></p>
    <h2>File Upload:</h2>
    <p>file:
    <pre><?php if ( ! empty( $_FILES ) ) {
            echo print_r( $_FILES, true );
        } ?></pre>
    </p>
    <p></p>
    </body>
    </html><?php
// Very Bottom of your code:
// Kill Post Form Data Session Variable, so User can reload the Page without sending post data twice
unset( $_SESSION["POST"] );

Funciona apenas para evitar o reenvio de $ _POST, não de $ _GET. Mas esse é o comportamento que eu preciso. O problema de reenvio não funciona com uploads de arquivos!


0

O que funciona para mim é:

if ( !refreshed()) {
   //Your Submit Here
        if (isset( $_GET['refresh'])) {
            setcookie("refresh",$_GET['refresh'], time() + (86400 * 5), "/");
        }

    }    
}


function refreshed()
{
    if (isset($_GET['refresh'])) {
        $token = $_GET['refresh'];
        if (isset($_COOKIE['refresh'])) {
            if ($_COOKIE['refresh'] != $token) {
                return false;
            } else {
                return true;
            }
        } else {
            return false;
        }
    } else {
        return false;
    }
}  


function createToken($length) {
    $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $charactersLength = strlen($characters);
    $randomString = '';
    for ($i = 0; $i < $length; $i++) {
        $randomString .= $characters[rand(0, $charactersLength - 1)];
    }
    return $randomString;
}

?>

E no seu formulário

 <form  action="?refresh=<?php echo createToken(3)?>">



 </form>

0

Este form.phpexemplo mostra como usar o PRG correto (quando o formulário é válido ou não).

  • Ele redireciona para a mesma página, somente quando o formulário é válido e a ação foi executada.
  • O redirecionamento impede que o formulário seja reenviado na atualização da página.
  • Ele usa a sessão para não perder as mensagens de sucesso que você deseja mostrar quando o formulário é válido.
  • Existem dois botões para teste: "Envio válido", "Envio inválido". Experimente os dois e atualize a página depois disso.
<?php
session_start();

function doSelfRedirect()
{
  header('Location:'.$_SERVER['PHP_SELF']);
  exit;
}

function setFlashMessage($msg)
{
  $_SESSION['message'] = $msg;
}

function getFlashMessage()
{
  if (!empty($_SESSION['message'])) {
    $msg = $_SESSION['message'];
    unset($_SESSION['message']);
  } else {
    $msg = null;
  }

  return $msg;
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
  // Validation primitive example.
  if (empty($_POST['valid'])) {
    $formIsValid = false;
    setFlashMessage('Invalid form submit');
  } else {
    $formIsValid = true;
  }

  if ($formIsValid) {
    // Perform any actions here.
    // ...

    // Cool!
    setFlashMessage('Form is valid. Action performed.');

    // Prevent form resubmission.
    doSelfRedirect();
  }
}
?>
<h1>Hello form</h1>

<?php if ($msg = getFlashMessage()): ?>
  <div><?= $msg ?></div>
<?php endif; ?>

<form method="post">
  <input type="text" name="foo" value="bar"><br><br>
  <button type="submit" name="invalid" value="0">Invalid submit</button>
  <button type="submit" name="valid" value="1">Valid submit</button>
</form>

-2
if (($_SERVER['REQUEST_METHOD'] == 'POST') and (isset($_SESSION['uniq']))){
    if($everything_fine){
        unset($_SESSION['uniq']);
    }
}
else{
    $_SESSION['uniq'] = uniqid();
}

Por favor, adicione alguma explicação à sua resposta para que outras pessoas possam aprender com ela - de onde $everything_finevem?
Nico Haase

-3

Por que não usar a $_POST['submit']variável como uma declaração lógica para salvar o que estiver no formulário. Você sempre pode redirecionar para a mesma página (caso atualizem e quando acessarem go backo navegador, a variável de envio não será mais definida. Verifique se o botão de envio tem um namee idde submit.


1
Dê uma olhada em en.wikipedia.org/wiki/Post/Redirect/Get ! Esta é a abordagem correta #
1126
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.