Qual é a melhor maneira de manter um objeto usando formulários em PHP?
-
03-07-2019 - |
Pergunta
Eu tenho uma aplicação PHP onde eu gostaria de certos objetos de persistir, da seguinte maneira:
- O objeto não deve existir no $ _SESSION. janelas do navegador web separadas deve controlar instâncias separadas do objeto.
- O usuário final não deve ser capaz de modificar o objeto alterando o conteúdo da variável _REQUEST $ à mão (se isso acontece, o pedido deve ser tratado como corrompido).
Existe uma melhores práticas / maneira correta de fazer isso? Com PHP cada vez mais orientada a objetos, temo que eu estou reinventando a roda.
O grande propósito deste código é permitir a criação e manipulação de objetos complexos sem o uso de um banco de dados até que estejam a ser cometidos, então eu vou usar uma transação adequada para cometê-los ao banco de dados na íntegra. Eu quero fazer com que meu banco de dados contém apenas a fatura completa, ou nenhuma factura em tudo.
Meu método atual é a seguinte:
<?php
include('encrypt.php');
include('invoice.class.php');
if(isset($_REQUEST['invoice']))
{
$invoice = unserialize(decrypt(base64_decode($_REQUEST['invoice'])));
if(!($invoice instanceOf invoice)) throw new exception('Something bad happened');
}
else
{
// Some pages throw an exception if the $_REQUEST doesn't exist.
$invoice = new invoice();
}
if(isset($_REQUEST['action']) && $_REQUEST['action'] == 'addLine')
{
$invoice->addLine(new invoiceLine($_REQUEST['description'], $_REQUEST['qty'], $_REQUEST['unitprice']);
}
?>
<form action="index.php" method="post">
<input type="text" name="qty" />
...
<input type="hidden" name="invoice" value="<?php echo(base64_encode(encrypt(serialize($invoice)))); ?>" />
</form>
Solução
Você também pode salvar o estado no cliente, sem cookies, usando um simples escondida entrada de formulário. Enquanto os dados (provavelmente um blob serializado) é criptografado e assinado, o usuário não pode modificá-lo sem quebrar a sua sessão.
Steve Gibson usa este método para seu costume sistema de e-commerce. Enquanto seu código não é open source, ele absolutamente explica maneiras de economizar estado sem armazenar dados sensíveis no servidor ou que requerem suporte de cookie no Segurança Agora Episódio # 109 , "sistema de comércio eletrônico do GRC".
Outras dicas
Aqui está um truque: colocá-lo em um cookie
algoritmo puro:
$ dados = serialize ($ object); $ Tempo = tempo (); $ Signature = sha1 ($ serverSideSecret $ time $ data..); $ Bolinho = base64 ( "$ signature- $ tempo- $ dados");
A vantagem é que você
a) pode expirar o cookie quando você quer porque você está usando o timestamp como parte do hash de assinatura.
b) pode verificar que os dados não foi modificado no lado do cliente, porque você pode recriar o hash do segmento de dados no cookie.
Além disso, você não tem que armazenar o objeto inteiro no cookie se ele vai ser muito grande. Apenas armazenar os dados que você precisa no servidor e usar os dados no cookie como uma chave.
Eu não posso levar o crédito para o algoritmo, aprendi-o de Cal Henderson, do Flickr fama.
Edit:. Se você encontrar usando cookies muito complicado, simplesmente esquecê-los e armazenar os dados que teriam ido no cookie em um campo de formulário oculto
O que eu gostaria de fazer é armazenar um tecla (não toda a estrutura, como o seu exemplo é) criptográfico em uma variável de forma oculta. Esta chave é um índice para uma tabela uncreated_invoices
onde armazenar as facturas incompletas.
Entre páginas, você atualizar os dados na tabela de uncreated_invoices, e quando estiver pronto, retire-o e cometê-lo. Se você colocar o nome de usuário na tabela de uncreate_invoices, isso também vai deixá-los pegar onde parou (não tenho certeza se isso é um caso de uso válido). Provavelmente seria uma boa idéia de colocar o nome de usuário nele de qualquer maneira para que as pessoas não podem tentar seqüestrar faturas de outras pessoas.
Você pode provavelmente começar afastado com o armazenamento de dados serializados na tabela de uncreated_invoices, se você quisesse. Pessoalmente, eu normalizá-lo um pouco (o quanto depende do seu esquema) para que você pode facilmente adicionar / remover peças individuais.
Edit:
Eu esqueci de mencionar que você deve limpar a mesa de uncreated_invoices
periodicamente para que ele não encher-se de faturas obsoletos.
Não foi possível armazenar os dados em uma matriz dentro de $ _SESSION, e então ter um ID único para cada janela. Se cada janela tem id único você pode passar a ID ao redor como parte de suas formas. Loja / recuperar os dados da sessão ou banco de dados baseado no id janela.
Então, alguma coisa assim? $ _SESSION [ 'data'] [$ WindowID] -> $ objectname
Se você não pode usar SESSION então você deve manter os dados mesmo. Você deve colocar o em algum lugar dados que persistirá, como um banco de dados ou algum outro arquivo. É a única maneira, além sessão para Persit dados.
Eu levo isso de volta, você pode enviar os dados em cada página HTML e usá-lo localmente. Cada página que aceita os dados devem criar HTML / Javascript que continua a sequência de dados.
Se você armazenar coisas no cliente lado eles podem ser modificados. Existe uma razão específica que você não deseja armazenar os objetos em uma sessão? Se a armazenar o objeto realmente não é viável que você precisa para persistir em outro lugar no servidor.
Isso é bom, eles vão ser capazes de adicionar todos os itens que eles querem. O problema no seu código é que você está tomando o descritor item, quantidade e preço do pedido, o preço realmente deve ser procurado em segundo plano, caso contrário, um usuário poderia entregar ofício seu preço. Heck, itens de valor negativas, e você receber coisas de graça.
Você deseja armazenar alguma coisa. Isso é geralmente feito em bancos de dados. Como você sabe o preço de algo sem olhar-lo em um banco de dados? Portanto, use o mesmo banco de dados para armazenar informações sobre o atual usuário / sessão.
Você pode usar o métodos mágicos __sleep()
e __wakeup()