2009-03-06 43 views
1

我有一個PHP應用程序,我想某些對象以下列方式堅持:在PHP中使用表單保持對象的最佳方式是什麼?

  1. 的對象不能在$ _SESSION存在。單獨的Web瀏覽器窗口必須控制對象的單獨實例。
  2. 最終用戶不能通過手動更改$ _REQUEST變量的內容來修改對象(如果發生這種情況,請將該請求視爲已損壞)。

是否有最佳做法/正確的方法來做到這一點?隨着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> 
+0

您的問題是什麼? – 2009-03-06 06:15:54

+0

問題在標題中,但我已將它放入q的主體中。對於那個很抱歉。 – Martin 2009-03-06 06:21:31

回答

3

您還可以使用一個簡單的隱藏表單輸入在客戶端保存狀態,無需Cookie。只要數據(可能是序列化的blob)被加密並簽名,用戶就不能修改它,而不會中斷會話。

Steve Gibson將這種方法用於他的定製電子商務系統。雖然他的代碼不是開源的,但他徹底地解釋瞭如何在不存儲敏感數據的情況下保存狀態,或在「GRC的電子商務系統」Security Now Episode #109中要求cookie支持。

0

如果您不能使用SESSION,那麼你必須堅持自己的數據。您必須將數據放置在某個地方,例如數據庫或其他文件。除了SESSION之外,它是唯一的方法來保存數據。

我回過頭來,可以發送每個HTML頁面中的數據並在本地使用它。每個接受數據的頁面都必須創建HTML/Javascript,以繼續數據序列。

0

如果您將東西存儲在客戶端,則可以對其進行修改。是否有一個特定的原因,您不想將對象存儲在會話中?如果實際存儲對象不可行,則需要將其保存在服務器上的其他位置。

+0

如果您打開了多個窗口,將該對象保留在會話中將使兩個窗口都修改相同的對象。這是我的應用程序無法接受的。 – Martin 2009-03-06 06:18:17

+0

讓每個窗口在會話中創建一個新的索引。或者爲服務器上的每個對象創建一個文件 – 2009-03-06 06:22:49

0

這很好,他們將能夠添加他們想要的所有項目。代碼中的問題是,您從請求中獲取物品描述符,數量和價格,價格應該在後臺查找,否則,用戶可以手工制定其價格。哎呀,負值的物品,你可以免費得到東西。

+0

示例應用程序並不意味着向用戶出售某些東西,而是讓用戶在線創建自己的發票並保留記錄。 – Martin 2009-03-06 06:22:48

0

你想存儲的東西。這通常在數據庫中完成。如何在不查看數據庫的情況下知道某些東西的價格?因此,使用相同的數據庫來存儲有關當前用戶/會話的信息。

2

我會做的是存儲加密(不像整個結構,就像你的例子)隱藏的表單變量。該密鑰是uncreated_invoices表的索引,您可以在其中存儲不完整的發票。

在頁面之間,您更新uncreated_invoices表中的數據,當它們完成時,將其拉出並提交。如果你把用戶名放入uncreate_invoices表中,這也會讓他們拿起他們離開的地方(不知道這是否是一個有效的用例)。反正用戶名可能是個好主意,所以人們不能試圖劫持別人的發票。

如果需要,您可以將序列化數據存儲在uncreated_invoices表中。就個人而言,我會對它進行標準化(多少取決於您的模式),以便您可以輕鬆地添加/刪除單個部分。

編輯: 我忘了提及你應該定期清理uncreated_invoices表,因爲它沒有填滿陳舊的發票。

+0

這是一個很好的答案。然後,我必須定期清理未創建的發票表(人們可以刪除會話),並且還可以在每次加載頁面時從表中構建我的對象。 +1 – Martin 2009-03-06 06:51:30

+0

哦,我完全忘了!謝謝! – 2009-03-06 07:11:22

4

這裏有一個技巧:把它放在餅乾裏!

整數算法:

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

的好處是,你當你想,因爲你正在使用時間戳作爲簽名中的散列的一部分

一)可以過期餅乾。 b)可以驗證數據在客戶端沒有被修改,因爲你可以從cookie中的數據段重新創建哈希。

另外,如果整個對象太大,則不必將整個對象存儲在cookie中。只需將您需要的數據存儲在服務器上,並將cookie中的數據用作密鑰即可。

我不能讚揚這個算法,我從Cal Henderson的Flickr名聲中學到了它。

編輯:如果您發現使用cookie過於複雜,請將它們忘掉,並將隱藏在表單字段中的數據存儲在cookie中。

1

你不能存儲內$ _SESSION一個數組中,然後對每個窗口一個唯一的ID。如果每個窗口都有唯一的ID,則可以將ID作爲表單的一部分傳遞給用戶。根據窗口ID在會話或數據庫中存儲/檢索數據。

所以像這樣? $ _SESSION ['data'] [$ windowid] - > $ objectname

相關問題