Каков наилучший способ сохранить объект, используя формы в PHP? - PullRequest
1 голос
/ 06 марта 2009

У меня есть PHP-приложение, в котором я хотел бы, чтобы определенные объекты сохранялись следующим образом:

  1. Объект не должен существовать в $ _SESSION. Отдельные окна веб-браузера должны управлять отдельными экземплярами объекта.
  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>

Ответы [ 9 ]

4 голосов
/ 06 марта 2009

Вот хитрость: поместите это в печенье!

аккуратный алгоритм:

$ data = serialize ($ object); $ time = time (); $ signature = sha1 ($ serverSideSecret. $ time. $ data); $ cookie = base64 ("$ signature- $ time- $ data");

Преимущество в том, что вы

a) может истечь срок действия cookie, если вы хотите, потому что вы используете метку времени как часть хэша подписи.

b) может проверить, что данные не были изменены на стороне клиента, потому что вы можете воссоздать хеш из сегмента данных в cookie.

Кроме того, вам не нужно хранить весь объект в файле cookie, если он будет слишком большим. Просто сохраните необходимые данные на сервере и используйте данные в файле cookie в качестве ключа.

Я не могу взять кредит на алгоритм, я узнал об этом от Кэла Хендерсона, известного из Flickr.

Редактировать: Если вы находите использование файлов cookie слишком сложным, просто забудьте о них и сохраните данные, которые были бы сохранены в файле cookie, в скрытом поле формы.

3 голосов
/ 06 марта 2009

Вы также можете сохранить состояние на клиенте, без файлов cookie, используя простой скрытый ввод данных. Пока данные (вероятно, сериализованный большой двоичный объект) зашифрованы и подписаны, пользователь не может изменять их, не прерывая сеанс.

Стив Гибсон использует этот метод для своей системы электронной торговли. Хотя его код не является открытым исходным кодом, он подробно объясняет способы сохранения состояния без сохранения конфиденциальных данных на сервере и не требует поддержки файлов cookie в Security Now Episode # 109 , «Системе электронной коммерции GRC».

2 голосов
/ 06 марта 2009

Что бы я сделал, это сохранил криптографический ключ (а не всю структуру, как в вашем примере) в скрытой переменной формы. Этот ключ является индексом таблицы uncreated_invoices, в которой хранятся неполные счета.

Между страницами вы обновляете данные в таблице uncreated_invoices, а по завершении извлекаете их и фиксируете. Если вы введете имя пользователя в таблицу uncreate_invoices, это также позволит им выбрать место, где они остановились (не уверен, что это правильный вариант использования). Вероятно, было бы неплохо в любом случае ввести в него имя пользователя, чтобы люди не могли пытаться похитить счета других людей.

Вероятно, вы можете избежать сохранения сериализованных данных в таблице uncreated_invoices, если хотите. Лично я бы немного нормализовал его (насколько это зависит от вашей схемы), чтобы вы могли легко добавлять / удалять отдельные элементы.

Edit: Я забыл упомянуть, что вы должны периодически очищать таблицу uncreated_invoices, чтобы она не заполнялась устаревшими счетами.

1 голос
/ 06 марта 2009

Не удалось сохранить данные в массиве внутри $ _SESSION, а затем иметь уникальный идентификатор для каждого окна. Если каждое окно имеет уникальный идентификатор, вы можете передать его как часть ваших форм. Сохранять / извлекать данные в сеансе или базе данных на основе идентификатора окна.

Так что-то вроде этого? $ _SESSION [ 'данные'] [$ WindowID] -> $ имя_объекта

0 голосов
/ 06 марта 2009

Вы можете использовать магические методы __sleep() и __wakeup()

0 голосов
/ 06 марта 2009

Вы хотите что-то хранить. Обычно это делается в базах данных. Как узнать цену чего-либо, не глядя в базу данных? Поэтому используйте ту же базу данных для хранения информации о текущем пользователе / ​​сеансе.

0 голосов
/ 06 марта 2009

Отлично, они смогут добавлять все предметы, которые хотят. Проблема в вашем коде заключается в том, что вы берете из запроса дескриптор, количество И ЦЕНУ, цена действительно должна быть рассмотрена в фоновом режиме, в противном случае пользователь может вручную обработать их цену. Черт возьми, предметы с отрицательным значением, и вы получаете вещи бесплатно.

0 голосов
/ 06 марта 2009

Если вы храните вещи на стороне клиента, они могут быть изменены. Есть ли конкретная причина, по которой вы не хотите хранить объекты в сеансе? Если хранение объекта на самом деле невозможно, вам нужно сохранить его где-то еще на сервере.

0 голосов
/ 06 марта 2009

Если вы не можете использовать SESSION, вы должны сохранить данные самостоятельно. Вы должны поместить данные где-то, где они будут сохраняться, например, в базу данных или какой-либо другой файл. Это единственный способ, кроме СЕССИИ, чтобы сохранить данные.

Я забираю это, вы можете отправлять данные на каждой HTML-странице и использовать их локально. Каждая страница, которая принимает данные, должна создавать HTML / Javascript, который продолжает последовательность данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...