在PHP中使用表单持久化对象的最佳方法是什么?

时间:2009-03-06 06:05:49

标签: php oop object persistence

我有一个PHP应用程序,我希望某些对象以下列方式持久存在:

  1. $ _SESSION中不得存在该对象。单独的Web浏览器窗口必须控制对象的单独实例。
  2. 最终用户必须无法通过手动更改$ _REQUEST变量的内容来修改对象(如果发生这种情况,则应将请求视为已损坏)。
  3. 是否有最好的做法/正确的方法来做到这一点?随着PHP越来越面向对象,我担心我会重新发明一个轮子。

    此代码的主要目的是允许在不使用数据库的情况下创建和操作复杂对象,直到它们被提交为止,然后我将使用适当的事务将它们完全提交到数据库。我想这样做,以便我的数据库只包含完整的发票,或者根本没有发票。

    我目前的方法如下:

    <?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>
    

9 个答案:

答案 0 :(得分:4)

这是一个技巧:把它放在一个cookie中!

整洁的算法:

$ data = serialize($ object); $ time = time(); $ signature = sha1($ serverSideSecret。$ time。$ data); $ cookie = base64(“$ signature- $ time- $ data”);

好处是你

a)可以在您需要时使cookie过期,因为您使用时间戳作为签名哈希的一部分。

b)可以验证数据是否未在客户端修改,因为您可以从cookie中的数据段重新创建哈希值。

此外,如果它太大,您不必将整个对象存储在cookie中。只需将您需要的数据存储在服务器上,并将cookie中的数据用作密钥。

我不能赞同这个算法,我是从Flickr成名的Cal Henderson那里学到的。

编辑:如果您发现使用过于复杂的Cookie,请忘记它们,并将隐藏在表单字段中的数据存储在隐藏的表单字段中。

答案 1 :(得分:3)

您还可以使用简单的隐藏表单输入在客户端上保存状态,不使用cookie。只要数据(可能是序列化的blob)经过加密和签名,用户就无法在不中断会话的情况下对其进行修改。

Steve Gibson将这种方法用于他的自定义电子商务系统。虽然他的代码不是开源代码,但他彻底解释了在不将敏感数据存储在服务器上或在Security Now Episode #109“GRC的电子商务系统”中需要cookie支持的情况下保存状态的方法。

答案 2 :(得分:2)

我要做的是在隐藏的表单变量中存储加密的(不是整个结构,就像你的例子一样)。此密钥是uncreated_invoices表的索引,您可以在其中存储不完整的发票。

在页面之间,您更新uncreated_invoices表中的数据,完成后,将其拉出并提交。如果你将用户名放入uncreate_invoices表中,这也会让他们从中断的地方继续(不确定这是否是一个有效的用例)。将用户名放在其中可能是一个好主意,所以人们不能试图劫持其他人的发票。

如果需要,您可以在uncreated_invoices表中存储序列化数据。就个人而言,我会对它进行一些标准化(多少取决于你的架构),这样你就可以轻松添加/删除单个部分。

编辑: 我忘了提到你应该定期清理uncreated_invoices表,这样它就不会填满陈旧的发票。

答案 3 :(得分:1)

无法将数据存储在$ _SESSION中的数组中,然后为每个窗口分配一个唯一的ID。如果每个窗口都有唯一的ID,您可以将id作为表单的一部分传递。根据窗口ID存储/检索会话或数据库中的数据。

这样的事情? $ _SESSION [ '数据'] [$ WINDOWID] - GT; $对象名

答案 4 :(得分:0)

如果您无法使用SESSION,则必须自行保留数据。您必须将数据放在将保留的某个位置,例如数据库或其他文件。除了SESSION之外,它是唯一能够持久化数据的方式。

我把它拿回来,你可以在每个HTML页面中发送数据并在本地使用它。接受数据的每个页面都必须创建继续数据序列的HTML / Javascript。

答案 5 :(得分:0)

如果您将内容存储在客户端,则可以对其进行修改。是否有特定原因您不希望将对象存储在会话中?如果实际存储对象不可行,则需要将其保留在服务器上的其他位置。

答案 6 :(得分:0)

没关系,他们可以添加他们想要的所有物品。您的代码中的问题是您从请求中获取项目描述符,数量和PRICE,价格确实应该在后台查找,否则,用户可以手工制作他们的价格。哎呀,负价值物品,你可以免费得到东西。

答案 7 :(得分:0)

你想存储一些东西。这通常在数据库中完成。如果不在数据库中查找,你怎么知道某些东西的价格?因此,使用相同的数据库来存储有关当前用户/会话的信息。

答案 8 :(得分:0)

您可以使用magic methods __sleep()__wakeup()