Консультация № 172585
24.09.2009, 16:06
0.00 руб.
0 8 1
Здравствуйте, ув. эксперты.

PHP 5.2.4 (Денвер 3).

Имеется объект самописного класса. В самом классе все члены стандартных типов (в основном строки и несколько целочисленных значений). Членов много, около 15. Есть одно поле описательное - оно может быть очень большим (тип данных MySQL - text).

1. Можно ли сохранить объект в сессии и в другом файле его обработать?
2. Можно ли передать этот объект методом POST в другой файл для обработки? Сейчас я "расчленяю" этот объект по скрытым полям формы. А меня интересует именно передача объекта целиком (по терминологии С/С++ - передачи ссылки на него).

Другими словами интересуют механизмы передачи ОБЪЕКТА между скриптами (с наименьшими затратами умственных усилий).

Спасибо.

Обсуждение

Неизвестный
24.09.2009, 16:28
общий
ссылка на объект одного процесса, в другом процессе смысла иметь не будет, подозреваю, что Вам нужно передавать все-таки данные объекта...
serialize + unserialize
Неизвестный
24.09.2009, 16:37
общий
это ответ
Здравствуйте, Грибенников Александр Сергееви!
1. Можно сохранять как есть.
$_SESSION['объект']=$объект;
затем в другом сценарии
session_start();
$объект=$_SESSION['объект'];
Сессии сохраняются в файлы, поэтому нужно позаботиться о свободном месте на жестком диске, если объект будет содержать длинные поля.
2. Можно, причем через одно скрытое поле. Используйте методы serialize/unserialize.
print "<input name=bigobject type=hidden value='".htmlspecialchars(serialize($объект),ENT_QUOTES)."'>";
для восстановления
$объект=unserialize($_POST['bigobject']);
5
Спасибо. Все по делу.
Неизвестный
24.09.2009, 18:38
общий
Принято.

Появилось два встречных вопроса:
1. Существуют ли какие-либо ограничения на этот(эти) способ? Ну там, настройки сервера и тд.
2. Какой способ все-таки более предпочтителен для передачи данных между скриптами? Причем скрипты - не обязательно формы. Я смотрел в ASP.NET - так там параметры он передает POST'ом. Но это одиночные параметры. Как для объекта будет лучше?
Неизвестный
24.09.2009, 20:16
общий
Грибенников Александр Сергееви:
1. Ограничений вроде никаких особых нет. Методом POST можно передавать большие объемы данных. У меня например передается довольно большой контекст в асинхронных запросах. Насчет настроек можно посмотреть в phpinfo, никаких параметров, ограничивающих размер сессии там нет, но объем данных должен помещаться в выделенную php память.
2. Я использую параллельно cookies, метод POST и сессии. Каждый метод имеет как достоинства, так и недостатки:
cookies хорошо использовать для хранения каких-то настроек небольшого объема, не требующих немедленной отправки на сервер, но как-то влияющих на результат последующих запросов и относящихся к странице или сеансу целиком, которые нужно привязать к конкретному компьютеру. Можно изменять с помощью javascript.
POST удобен, когда надо передавать большие объемы данных, привязывать контекст к форме или ее элементам, отправлять файлы, передавать значительные объемы данных из javascript. После запроса методом POST обязательно должно быть перенаправление, либо такие запросы должны выполняться через javascript. Не позволяет пользователю, в отличие от метода GET, сделать закладку или передать ссылку кому-либо.
сессии позволяют привязать достаточно большой объем данных к конкретному сеансу работы пользователя на стороне сервера, не создают большой нагрузки на соединение, как POST-back, но данные, сохраненные в сессии теряются, если пользователь некоторое время не производит никаких действий. В случае с POST-back пользователь может залогиниться в другом окне браузера, если он не закрывался и сохранить контекст. Следует использовать для сохранения результата проверки подлинности и хранения данных, не передаваемых пользователю/от пользователя и не требующих длительного хранения.
Неизвестный
24.09.2009, 21:08
общий
ОК. Сдаюсь.
Есть реальная задача. Начиналась она с мелочей, теперь обросла. В связи с этим я зашел в тупик. Поэтому меня и заинтересовал вопрос о передаче объектов между скриптами.
Всю задачу приводить не буду, только проблемную часть.

Есть некая сущность. Пусть это будут данные сотрудника, это не важно. У этой сущности есть различные свойства. Сами свойства и всю их обработку я запаковал в класс.
Думаю, тут понятно.

На странице(ах) я с этой сущностью могу производить разные действия - просматривать, редактировать и удалять. До сих пор у меня все работает.

Теперь я решил добавить сущности изображение. Но, т.к. загрузка файла не происходит, пока форма не будет отправлена, я решил саму загрузку перенести на отдельную страницу (скрипт). И вот тут возникла сложность.
Предположим, я добавляю нового сотрудника (сущность), или редактирую уже имеющегося. Открывается форма ввода данных; в этой форме есть ссылка на страницу загрузки изображения. И вот я ввожу/редактирую данные, потом решаю прикрепить изображение (данные уже введены, но не переданы). Перехожу по ссылке на загрузку изображения и....

Как сохранить те данные, к. я уже ввел? Если я перейду по ссылке без отправки данных, они потеряются. На данный момент нашел только одни выход - с помощью javascript'a создаю форму, заполняю ее скрытые поля теми данными, к. уже ввел, и отправляю их POST'ом на страницу загрузки изображения (тут, правда, есть варианты. Можно, например, не создавать новую форму, а у этой формы поменять свойство action). И теперь осталась только проблема их возврата.

С помощью ваших ответов, в принципе, уже не кажется все так мрачно. На этой странице (загрузки изображения) можно запаковать полученные данные в объект и после загрузки изображения вернуть их в страницу с формой. А на ней уже разнести данные по форме. А также обработать загруженный файл.

Ход мыслей правильный? Или есть другие алгоритмы решения этой задачи?
Хотелось бы услышать мнение экспертов, т.к. эту сферу программирования я только осваиваю.

Спасибо.

P.S. В "локальных" языках все гораздо проще, особенно в C#. Там просто ссылку передал сообщением, и всех делов. А тут надо поизголяться...
Неизвестный
24.09.2009, 22:02
общий
Аааа, если надо загружать картинку без перезагрузки страницы, то это мелочи. Делаем div, в него вставляем iframe, на который ставим атрибут name и задаем стилем чтобы не было видно, также на него вешаем обработчик onload и добавляем форму, которая будет загружать файл и сабмититься в этот iframe так примерно:
Код:

<!-- GNU GPL blah blah blah -->
<div id=a>
<iframe
name=b
id=b
onload="if(this.is_uploading)
{document.getElementById('a').innerHTML=this.contentWindow.document.firstChild.innerHTML;};"
style='display:none;'
>
</iframe>
<form
method=post
action="upload_async.php"
enctype="multipart/form-data"
target=b
>
<input type=file name=file1>
<input type=sumbit onclick="document.getElementById('b').is_uploading=true;" >
</form>
</div>

А в обработчике загрузки файла делаем примерно так:
Код:
<?php
# GNU GPL blah blah blah
$uploaddir = $_SERVER['DOCUMENT_ROOT'].'/uploads/';
$uploadfile = $uploaddir . basename($_FILES['file1']['name']);
if (move_uploaded_file($_FILES['file1']['tmp_name'], $uploadfile))
{
chmod($uploadfile,0666);
#здесь можно проверить, картинку ли загрузили
# и добавить запись в БД, если нужно
print '<img src=\'http://'.$_SERVER['HTTP_HOST'].'/uploads/'.urlencode(basename($_FILES['file1']['name'])).'\' alt=\''.
htmlspecialchars(basename($_FILES['file1']['name'])).'\' >';
#здесь можно вывести кнопку, которая асинхронным запросом будет удалять картинку с сервера
#и восстанавливать исходное содержимое divа (загрузчик)
}else print 'Failure: '.$uploadfile;
?>

То есть пользователь выбирает картинку, кликает кнопку, картинка загружается на сервер и сразу появляется на месте формы загрузки.
Неизвестный
04.10.2009, 16:44
общий
vladisslav:
При проверке Вашего ответа возникли проблемы. В чистом виде приведенные Вами примеры не работают. Я не знаю, то ли это зависит от настроек веб-сервера/ПХП или это так и есть.

Пришлось потратить время и заставить-таки работать оба эти варианта. Решил написать Вам и привести рабочие примеры.

Итак.
1. Передача объекта через сессию. В чистом виде не передает. Хотя я часто встречал предложенный Вами пример, даже в справочной системе по ПХП. Но страшного ничего нет:
все работает через serialize/unserialize.

2. Передача через массивы GET/POST вообще не работает, даже с serialize/unserialize. Причина оказалась довольно проста и интересна. Оказывается, при сериализации объекта, в строку в качестве разделителся полей добавляется символ с ASCII-кодом 0 (ноль). Если посмотреть на сериализованный в сессию объект через какой-либо специфический редактор, типа NotePad++, то там прямо видно, что стоят сиволы NUL. Это же (ноль-символ) я увидел при посимвольном разборе строки после сериализации объекта (до его передачи в POST). Понятное дело, что после передачи все эти нуль-символы были "отсечены". И в итоге я получил вроде бы корректную строку. Но на самом деле в ней не хватало большого кол-ва символов, к. были утеряны при передаче. Естессно, десериализация оказалась невозможной.
Кроме того, если применить к сериализованному объекту функцию htmlspecialchars (или htmlentities), то после передачи мы получим строку, где все кавычки все равно будут "заэкранированы". Т.е. вместо "object" мы получим "object". Правда, это не так страшно. С этим успешно борется функция stripslashes. Но потеря нуль-символов все равно остается критичной. И десериализовать объект все равно не получится.
Выходом (возможно не очень удачным) оказалась замена (до передачи) всех нуль-символов на какой-нить другой символ, например, с ASCII-кодом 1. Примерно так:
Код:

//На входе, до передачи:
@include_once("Object.php);
$obj = new Object();
$str = serialize($obj);
$str = htmlspecialchars($str);
$str = str_replace(chr(0), chr(1), $str);
//Все это, понятное дело, можно сделать в одной операции
echo "<form action="action.php" method="post">"
."<input name="obj" type="hidden" value="".$str."" />"
."<input type="submit" value="OK">"
."</form>";

//На выходе, после передачи:
@include_once("Object.php);
$str = $_POST['obj'];
$str = stripslashes($str);
$str = str_replace(chr(1), chr(0), $str);
$obj = unserialize($str);
//Все это, понятное дело, можно сделать в одной операции


И вот таким образом удалось заставить корректно передавать и получать объект через массив POST. То же верно и для массива GET.
Отсюда следует, что либо стоит написать две функции, напр. Serialize и Unserialize, к. спрячут эти нагромождения внутри себя. Либо для каждого класса писать свой сериализатор/десериализатор.

Хотелось бы услышать мнение экспертов на счет всего этого.

Повторюсь, я не уверен, возможно дело в настройках апача/пхп.

Спасибо.

P.S. Прошу прощения за возможные опечатки в коде. Писал по памяти, вполне допускаю, что где-нить ошибся в вызове функции. Важно смысл понять.
Неизвестный
05.10.2009, 12:08
общий
Да, есть стандартное решение проблемы. Спасибо vladislav'у.
Может, кому-то понадобится (и самому не забыть ).
Есть пара таких функций - urlencode/urldecode.
Все сводится к простому выражению:
Код:

//на входе, до передачи
<input type="hidden" name="obj" id="obj" value="".htmlspecialchars(urlencode(serialize($obj)), ENT_QUOTES)."" />

//на выходе, после передачи
$obj = unserialize(urldecode($_POST['obj']));


Работает и при включенных magic_quotes_gpc, и при выключенных.

Вопрос закрыт.
Форма ответа