|
|
@@ -1,847 +1,532 @@
|
|
|
-<sect1 id="zend.session.advancedusage">
|
|
|
-
|
|
|
- <title>Расширенное использование<!--Advanced Usage--></title>
|
|
|
+<?xml version="1.0" encoding="UTF-8"?>
|
|
|
+<!-- EN-Revision: 22743 -->
|
|
|
+<!-- Reviewed: no -->
|
|
|
+<sect1 id="zend.session.advanced_usage">
|
|
|
+ <title>Расширенное использование</title>
|
|
|
|
|
|
<para>
|
|
|
- Хотя базовое использование является совершенно допустимым вариантом
|
|
|
- использования сессий Zend Framework, стоит рассмотреть другие
|
|
|
- возможности их использования. См.
|
|
|
- <link linkend="zend.auth.introduction.using"> пример на
|
|
|
- <code>Zend_Auth</code></link>, который по умолчанию неявно
|
|
|
- использует Zend_Session_Namespace для сохранения меток аутентификации.
|
|
|
- Этот пример показывает один из способов быстрой и легкой интеграции
|
|
|
- Zend_Session_Namespace и Zend_Auth.
|
|
|
-<!--
|
|
|
- While the basic usage examples are a perfectly acceptable way to utilize Zend Framework sessions, there are some
|
|
|
- best practices to consider. Consider the
|
|
|
- <link linkend="zend.auth.introduction.using"><code>Zend_Auth</code> example</link>
|
|
|
- that transparently uses Zend_Session_Namespace by default to persist authentication tokens. This example shows
|
|
|
- one approach to quickly and easily integrate Zend_Session_Namespace and Zend_Auth.
|
|
|
--->
|
|
|
+ Хотя базовое использование является совершенно допустимым вариантом использования
|
|
|
+ сессий Zend Framework, стоит рассмотреть другие возможности их использования.
|
|
|
+ В этой секции обсуждаются тонкости работы с сессиями и показывается более продвинутое
|
|
|
+ использование компонента <classname>Zend_Session</classname>.
|
|
|
</para>
|
|
|
|
|
|
- <sect2 id="zend.session.startingasession">
|
|
|
-
|
|
|
- <title>Старт сессии<!--Starting a Session--></title>
|
|
|
+ <sect2 id="zend.session.advanced_usage.starting_a_session">
|
|
|
+ <title>Запуск сессии</title>
|
|
|
|
|
|
<para>
|
|
|
- Если вы хотите, чтобы все запросы имели сессии и использовали
|
|
|
- сессии Zend Framework, то стартуйте сессию в файле загрузки:
|
|
|
-<!--
|
|
|
- If you want all requests to have a session and use Zend Framework sessions, then start the session in the
|
|
|
- bootstrap file:
|
|
|
--->
|
|
|
+ Если вы хотите, чтобы все запросы использовали сессии через
|
|
|
+ <classname>Zend_Session</classname>, тогда запускайте сессию в файле инициализации
|
|
|
+ (bootstrap):
|
|
|
</para>
|
|
|
|
|
|
- <example>
|
|
|
- <title>Старт общей сессии<!--Starting the Global Session--></title>
|
|
|
-<programlisting language="php">
|
|
|
-<![CDATA[<?php
|
|
|
-...
|
|
|
-require_once 'Zend/Session.php';
|
|
|
+ <example id="zend.session.advanced_usage.starting_a_session.example">
|
|
|
+ <title>Запуск глобальной сессии</title>
|
|
|
+
|
|
|
+ <programlisting language="php"><![CDATA[
|
|
|
Zend_Session::start();
|
|
|
-...
|
|
|
-?>]]></programlisting>
|
|
|
+]]></programlisting>
|
|
|
</example>
|
|
|
|
|
|
<para>
|
|
|
- Стартуя сессию в файле загрузки, вы исключаете вероятность того, что
|
|
|
- старт сессии произойдет после того, как заголовки будут
|
|
|
- отправлены броузеру, что вызвовет исключение и, возможно,
|
|
|
- отображение испорченной страницы посетителю сайта. Некоторые
|
|
|
- расширенные возможности Zend_Session требуют вызова
|
|
|
- <code>Zend_Session_Core::start()</code> в начале (больше о
|
|
|
- расширенных возможностях будет написано позднее).
|
|
|
-<!--
|
|
|
- By starting the session in the bootstrap file, you avoid the possibility that your session might be started
|
|
|
- after headers have been sent to the browser, which results in an exception, and possibly a broken page for
|
|
|
- website viewers. Various advanced features require <code>Zend_Session_Core::start()</code> first. (More on
|
|
|
- advanced features later).
|
|
|
--->
|
|
|
+ Запуская сессию в файле инициализации, вы исключаете вероятность её запуска после
|
|
|
+ отправки заголовков браузеру, генерации исключения и возможного
|
|
|
+ отображения испорченой страницы посетителю сайта. Некоторые расширенные возможности
|
|
|
+ так же требуют вызова <methodname>Zend_Session::start()</methodname> до начала их
|
|
|
+ использования (Подробнее о расширенных возможностях будет написано позднее.)
|
|
|
</para>
|
|
|
|
|
|
<para>
|
|
|
- Есть четыре способа стартовать сессию, используя Zend_Session. Два
|
|
|
- из них - неправильные.
|
|
|
-<!-- There are four ways to start a session, when using Zend_Session. Two are wrong.
|
|
|
--->
|
|
|
+ Существует четыре способа запустить сессию, используя
|
|
|
+ <classname>Zend_Session</classname>. Два из них - неправильные.
|
|
|
</para>
|
|
|
|
|
|
- <itemizedlist mark='opencircle'>
|
|
|
+ <orderedlist>
|
|
|
<listitem>
|
|
|
<para>
|
|
|
- 1. Неправильно: Устанавливать опцию session.auto_start в
|
|
|
- php.ini или .htaccess (http://www.php.net/manual/en/ref.session.php#ini.session.auto-start).
|
|
|
- Если вы не имеете возможность отключить эту опцию в php.ini,
|
|
|
- то, если используется mod_php (или его эквивалент) и в
|
|
|
- php.ini уже установлена эта опция, добавьте строку
|
|
|
- <code>php_value session.auto_start 0</code> в ваш файл
|
|
|
- .htaccess (обычно находится в корневой директории для
|
|
|
- HTML-документов).
|
|
|
-<!--
|
|
|
- 1. Wrong: Do not set PHP's session.auto_start ini setting in either php.ini or .htaccess
|
|
|
- (http://www.php.net/manual/en/ref.session.php#ini.session.auto-start). If you do not have the
|
|
|
- ability to disable this setting in php.ini, you are using mod_php (or equivalent), and the setting
|
|
|
- is already enabled in php.ini, then add <code>php_value session.auto_start 0</code> to your
|
|
|
- .htaccess file (usually in your HTML document root directory).
|
|
|
--->
|
|
|
+ Неправильно: Не устанавливайте параметр <acronym>PHP</acronym> конфигурации
|
|
|
+ <ulink
|
|
|
+ url="http://www.php.net/manual/en/ref.session.php#ini.session.auto-start">
|
|
|
+ <code>session.auto_start</code></ulink>. Если у вас нет возможности
|
|
|
+ отключить этот параметр в <code>php.ini</code>, вы используете mod_php(или
|
|
|
+ аналог), тогда добавьте следующие строки в ваш <code>.htaccess</code> файл
|
|
|
+ (Обычно находится в корневой директории для <acronym>HTML</acronym>-документов):
|
|
|
</para>
|
|
|
+
|
|
|
+ <programlisting language="httpd.conf"><![CDATA[
|
|
|
+php_value session.auto_start 0
|
|
|
+]]></programlisting>
|
|
|
</listitem>
|
|
|
+
|
|
|
<listitem>
|
|
|
<para>
|
|
|
- 2. Неправильно: Непосредственно использовать функцию
|
|
|
- <ulink url="http://www.php.net/session_start"><code>session_start()</code></ulink>.
|
|
|
- Если вы вызываете <code>session_start()</code> напрямую и
|
|
|
- начинаете использование Zend_Session_Namespace, то при
|
|
|
- вызове метода <code>Zend_Session::start()</code> будет
|
|
|
- сгенерировано исключение ("session has already been
|
|
|
- started"). Если вы вызываете <code>session_start()</code>
|
|
|
- после использования Zend_Session_Namespace или явного вызова
|
|
|
- <code>Zend_Session::start()</code>, то будет сгенерирована
|
|
|
- ошибка уровня E_NOTICE и проигнорирован вызов функции.
|
|
|
-<!--
|
|
|
- 2. Wrong: Do not use PHP's <code>
|
|
|
- <ulink url="http://www.php.net/session_start">session_start()</ulink>
|
|
|
- </code> function directly. If you use <code>session_start()</code> directly, and then start using
|
|
|
- Zend_Session_Namespace, an exception will be thrown by <code>Zend_Session::start()</code> ("session
|
|
|
- has already been started"). If you call <code>session_start()</code>, after using
|
|
|
- Zend_Session_Namespace or starting <code>Zend_Session::start()</code> explicitly, an error of level
|
|
|
- E_NOTICE will be generated, and the call will be ignored.
|
|
|
--->
|
|
|
+ Неправильно: Не используйте вызов <acronym>PHP</acronym> функции <ulink
|
|
|
+ url="http://www.php.net/session_start">
|
|
|
+ <methodname>session_start()</methodname></ulink> напрямую.
|
|
|
+ Если вы вызываете <methodname>session_start()</methodname> напрямую и потом
|
|
|
+ начинаете использовать <classname>Zend_Session_Namespace</classname>,
|
|
|
+ <methodname>Zend_Session::start()</methodname> сгенерирует исключение
|
|
|
+ ("session has already been started"). Если вы вызовете
|
|
|
+ <methodname>session_start()</methodname>после использования
|
|
|
+ <classname>Zend_Session_Namespace</classname> или вызова
|
|
|
+ <methodname>Zend_Session::start()</methodname>, то будет сгенерирована ошибка
|
|
|
+ уровня <constant>E_NOTICE</constant> и вызов будет проигнорирован.
|
|
|
</para>
|
|
|
</listitem>
|
|
|
+
|
|
|
<listitem>
|
|
|
<para>
|
|
|
- 3. Правильно:
|
|
|
- Используйте <code>Zend_Session::start()</code>. Если
|
|
|
- необходимо, чтобы все запросы имели и использовали сессии,
|
|
|
- то поместите вызов этой функции в коде загрузки близко к
|
|
|
- точке входа и без условной логики. При этом присутствуют
|
|
|
- некоторые издержки за счет сессий. Если для одних запросов
|
|
|
- нужны сессии, а для других - нет, то:
|
|
|
-<!--
|
|
|
- 3. Correct: Use <code>Zend_Session::start()</code>. If you want all requests to have and use
|
|
|
- sessions, then place this function call early and unconditionally in your ZF bootstrap code.
|
|
|
- Sessions have some overhead. If some requests need sessions, but other requests will not need to use
|
|
|
- sessions, then:
|
|
|
--->
|
|
|
+ Правильно: Используйте <methodname>Zend_Session::start()</methodname>. Если
|
|
|
+ необходимо, чтобы все запросы имели и использовали сессии, то поместите вызов
|
|
|
+ этой функции в коде инициализации близко к точке входа и без условной логики.
|
|
|
+ При этом присутствуют издержки за счет сессий. Если сессии нужны только
|
|
|
+ некоторым запросам, а остальным - нет, то:
|
|
|
</para>
|
|
|
- <itemizedlist mark='opencircle'>
|
|
|
+
|
|
|
+ <itemizedlist mark="opencircle">
|
|
|
<listitem>
|
|
|
<para>
|
|
|
- Установите опцию <code>strict</code> в true (см.
|
|
|
- <link linkend="zend.session.startingasession"><code>Zend_Session::setOptions()</code></link>) в коде загрузки.
|
|
|
-<!--
|
|
|
- Unconditionally, set the <code>strict</code> option to true (see
|
|
|
- <link
|
|
|
- linkend="zend.session.startingasession"><code>Zend_Session::setOptions()</code>
|
|
|
- </link>
|
|
|
- ) in your userland bootstrap.
|
|
|
--->
|
|
|
+ Установите опцию <code>strict</code> в значение
|
|
|
+ <constant>TRUE</constant> используя
|
|
|
+ <methodname>Zend_Session::setOptions()</methodname> в файле
|
|
|
+ инициализации.
|
|
|
</para>
|
|
|
</listitem>
|
|
|
+
|
|
|
<listitem>
|
|
|
<para>
|
|
|
- Вызывайте <code>Zend_Session::start()</code>
|
|
|
- только при тех запросах, для которых нужны сессии,
|
|
|
- и до того, как будет произведен первый вызов
|
|
|
- <code>new Zend_Session_Namespace()</code>.
|
|
|
-<!--
|
|
|
- Call <code>Zend_Session::start()</code>, only for requests that need to use sessions, before
|
|
|
- the first call to <code>new Zend_Session_Namespace()</code>.
|
|
|
--->
|
|
|
+ Вызывайте <methodname>Zend_Session::start()</methodname> только для
|
|
|
+ запросов, которым нужно использовать сессии, до создания любого
|
|
|
+ объекта <classname>Zend_Session_Namespace</classname>.
|
|
|
</para>
|
|
|
</listitem>
|
|
|
+
|
|
|
<listitem>
|
|
|
<para>
|
|
|
- Используйте
|
|
|
- <code>new Zend_Session_Namespace()</code> как
|
|
|
- обычно и там, где это нужно, но при этом необходимо
|
|
|
- убедиться, что
|
|
|
- <code>Zend_Session::start()</code> был вызван ранее.
|
|
|
-<!--
|
|
|
- Use <code>new Zend_Session_Namespace()</code> normally, where needed, but make sure
|
|
|
- <code>Zend_Session::start()</code> has been called previously.
|
|
|
--->
|
|
|
+ Используйте "<code>new Zend_Session_Namespace()</code>" как обычно, там
|
|
|
+ где требуется, но убедитесь, что
|
|
|
+ <methodname>Zend_Session::start()</methodname> был вызван ранее.
|
|
|
</para>
|
|
|
</listitem>
|
|
|
</itemizedlist>
|
|
|
+
|
|
|
<para>
|
|
|
- Опция <code>strict</code> предотвращает автоматический
|
|
|
- старт сессии с использованием
|
|
|
- <code>Zend_Session::start()</code> при вызове
|
|
|
- <code>new Zend_Session_Namespace()</code>. Эта опция
|
|
|
- помогает разработчикам пользовательских областей приложений
|
|
|
- ZF следовать принятому при проектировании решению не
|
|
|
- использовать сессии для определенных запросов, т.к. при
|
|
|
- установке этой опции и последующем инстанцировании
|
|
|
- Zend_Session_Namespace до явного вызова
|
|
|
- <code>Zend_Session::start()</code> будет сгенерировано
|
|
|
- исключение. Не используйте эту опцию в коде библиотек ZF,
|
|
|
- поскольку проектные решения должны принимать только
|
|
|
- разработчики пользовательской области. Аналогичным образом,
|
|
|
- все разработчики "библиотек" должны осторожно подходить
|
|
|
- к использованию <code>Zend_Session::setOptions()</code>
|
|
|
- в коде их библиотек, поскольку эти опции имеют глобальную
|
|
|
- область действия (как и лежащие в основе опции расширения
|
|
|
- ext/session).
|
|
|
-<!--
|
|
|
- The <code>strict</code> option prevents <code>new Zend_Session_Namespace()</code> from automatically
|
|
|
- starting the session using <code>Zend_Session::start()</code>. Thus, this option helps developers of
|
|
|
- userland ZF applications enforce a design decision to avoid using sessions for certain requests,
|
|
|
- since an error will be thrown when using this option and instantiating Zend_Session_Namespace,
|
|
|
- before an explicit call to <code>Zend_Session::start()</code>. Do not use this option in ZF core
|
|
|
- library code, because only userland developers should make this design choice. Similarly, all
|
|
|
- "library" developers should carefully consider the impact of using
|
|
|
- <code>Zend_Session::setOptions()</code> on users of their library code, since these options have
|
|
|
- global side-effects (as do the underlying options for ext/session).
|
|
|
--->
|
|
|
+ Опция <code>strict</code> предотвращает автоматический старт сессии с
|
|
|
+ использованием <methodname>Zend_Session::start()</methodname> при вызове
|
|
|
+ <code>new Zend_Session_Namespace()</code> Эта опция помогает разработчикам
|
|
|
+ пользовательских приложений следовать принятому при проектировании решению не
|
|
|
+ использовать сессии для определенных запросов, т.к. при установке этой опции и
|
|
|
+ последующем инстанциировании <classname>Zend_Session_Namespace</classname> до
|
|
|
+ явного вызова <methodname>Zend_Session::start()</methodname> будет сгенерировано
|
|
|
+ исключение. Разработчики должны осторожно подходить к использованию
|
|
|
+ <methodname>Zend_Session::setOptions()</methodname>, поскольку эти опции имеют
|
|
|
+ глобальную область действия, вследствие их связи с лежащими в основе опциями
|
|
|
+ расширения ext/session.
|
|
|
</para>
|
|
|
</listitem>
|
|
|
+
|
|
|
<listitem>
|
|
|
<para>
|
|
|
- 4. Правильно: Просто используйте
|
|
|
- <code>new Zend_Session_Namespace()</code> где необходимо, и
|
|
|
- сессия будет автоматически запущена в Zend_Session. Это
|
|
|
- наиболее простой вариант использования, подходящий для
|
|
|
- большинства случаев. Но необходимо будет следить за тем,
|
|
|
- чтобы первый вызов
|
|
|
- <code>new Zend_Session_Namespace()()</code> всегда
|
|
|
- происходил <emphasis>до того</emphasis>, как
|
|
|
- выходные данные будут отправлены клиенту (т.е. до того, как
|
|
|
- агенту пользователя будут отправлены HTTP-заголовки),
|
|
|
- если используются основанные на куках сессии
|
|
|
- (очень рекомендуется). Использование
|
|
|
- <ulink url="http://php.net/outcontrol">буферизации
|
|
|
- вывода</ulink> может быть удачным решением, при этом может
|
|
|
- быть улучшена производительность. Например, в
|
|
|
- <code>php.ini</code>
|
|
|
- "<code>output_buffering = 65535</code>" включает буферизацию
|
|
|
- вывода с размером буфера 64K.
|
|
|
-<!--
|
|
|
- 4. Correct: Just use <code>new Zend_Session_Namespace()</code> whenever needed, and the session will
|
|
|
- be automatically started within Zend_Session. This offers extremely simple usage that works well in
|
|
|
- most situations. However, you then become responsible for ensuring that the first <code>new
|
|
|
- Zend_Session_Namespace()</code> happens <emphasis>before</emphasis> any output (i.e.
|
|
|
- <ulink url="http://www.php.net/headers_sent">HTTP headers</ulink>
|
|
|
- ) has been sent by PHP to the client, if you are using the default, cookie-based sessions (strongly
|
|
|
- recommended). Using
|
|
|
- <ulink url="http://php.net/outcontrol">output buffering</ulink>
|
|
|
- often is sufficient to prevent this issue and may help improve performance. For example, in
|
|
|
- <code>php.ini</code>, "<code>output_buffering = 65535</code>" enables output buffering with a 64K
|
|
|
- buffer.
|
|
|
--->
|
|
|
+ Правильно: Просто используйте <classname>Zend_Session_Namespace</classname> где
|
|
|
+ необходимо, и <acronym>PHP</acronym> сессия будет запущена автоматически.
|
|
|
+ Это наиболее простой вариант использования, подходящий для большинства случаев.
|
|
|
+ Но необходимо следить зе тем, чтобы первый вызов
|
|
|
+ <code>new Zend_Session_Namespace()</code> происходил
|
|
|
+ <emphasis>до того</emphasis>, как <acronym>PHP</acronym> отправит клиенту любые
|
|
|
+ данные(т.е. до того, как агенту пользователя отправлены
|
|
|
+ <ulink url="http://www.php.net/headers_sent">HTTP-заголовки</ulink>), если
|
|
|
+ используется основанные на куки сессии (рекомендуемый вариант). Больше
|
|
|
+ информации можно найти в
|
|
|
+ <link linkend="zend.session.global_session_management.headers_sent">этой
|
|
|
+ секции</link>.
|
|
|
</para>
|
|
|
</listitem>
|
|
|
- </itemizedlist>
|
|
|
-
|
|
|
+ </orderedlist>
|
|
|
</sect2>
|
|
|
|
|
|
- <sect2 id="zend.session.locking">
|
|
|
-
|
|
|
- <title>Блокировка пространств имен<!--Locking Session Namespaces--></title>
|
|
|
+ <sect2 id="zend.session.advanced_usage.locking">
|
|
|
+ <title>Блокировка пространств имен сессии</title>
|
|
|
|
|
|
<para>
|
|
|
- Можно применять блокировку к пространствам имен для предотвращения
|
|
|
- изменения данных в этом пространстве имен. Используйте
|
|
|
- метод <code>Zend_Session_Namespace::lock()</code> для того, чтобы
|
|
|
- сделать определенное пространство имен доступным только для чтения,
|
|
|
- <code>unLock()</code> - чтобы сделать пространство имен доступным
|
|
|
- для чтения и изменений, а <code>isLocked()</code> для проверки того,
|
|
|
- не было ли пространство имен заблокировано ранее. Блокировка не
|
|
|
- сохраняется от одного запроса к другому. Блокировка пространства
|
|
|
- имен не действует на методы установки (setter methods) в объектах,
|
|
|
- сохраненных в пространстве имен, но предотвращает использование
|
|
|
- методов установки пространства имен сессии для удаления или замены
|
|
|
- объектов, сохраненных непосредственно в пространстве имен.
|
|
|
- Также блокирование пространств имен Zend_Session_Namespace не
|
|
|
- препятствует использованию ссылок на те же данные
|
|
|
- (см. <ulink url="http://www.php.net/references">PHP references</ulink>).
|
|
|
-<!--
|
|
|
- Session namespaces can be locked, to prevent further alterations to the data in that namespace. Use
|
|
|
- <code>Zend_Session_Namespace's lock()</code> to make a specific namespace read-only, <code>unLock()</code>
|
|
|
- to make a read-only namespace read-write, and <code>isLocked()</code> to test if a namespace has been
|
|
|
- previously locked. Locks are transient and do not persist from one request to the next. Locking the
|
|
|
- namespace has no effect on setter methods of objects stored in the namespace, but does prevent the use of
|
|
|
- the namespace's setter method to remove or replace objects stored directly in the namespace. Similarly,
|
|
|
- locking Zend_Session_Namespace namespaces does not prevent the use of symbol table aliases to the same data
|
|
|
- (see
|
|
|
- <ulink url="http://www.php.net/references">PHP references</ulink>
|
|
|
- ).
|
|
|
--->
|
|
|
+ Можно применять блокировку к пространству имен для предотвращения изменения данных в
|
|
|
+ нем. Используйте метод <methodname>lock()</methodname> для того,
|
|
|
+ чтобы сделать определенное пространство имен доступным только для чтения,
|
|
|
+ <methodname>unLock()</methodname> - чтобы сделать пространство имен доступным для
|
|
|
+ чтения и изменений, а <methodname>isLocked()</methodname> - для проверки, не было ли
|
|
|
+ пространство имен заблокировано ранее. Блокировка не сохраняется от запроса к запросу,
|
|
|
+ не действует на методы установки(setter methods) в объектах, сохраненных в этом
|
|
|
+ пространстве имен, но предотвращает использование методов
|
|
|
+ установки для замены или удаления объектов, сохраненных непосредственно в пространстве
|
|
|
+ имен. Аналогично, блокировка экземпляра
|
|
|
+ <classname>Zend_Session_Namespace</classname> не препятствует использованию ссылок на
|
|
|
+ те же данные (смотри <ulink url="http://www.php.net/references">PHP references</ulink>).
|
|
|
</para>
|
|
|
|
|
|
- <example>
|
|
|
- <title>Блокировка пространств имен<!--Locking Session Namespaces--></title>
|
|
|
-<programlisting language="php">
|
|
|
-<![CDATA[<?php
|
|
|
- // assuming:
|
|
|
- $userProfileNamespace = new Zend_Session_Namespace('userProfileNamespace');
|
|
|
-
|
|
|
- // marking session as read only locked
|
|
|
- $userProfileNamespace->lock();
|
|
|
-
|
|
|
- // unlocking read-only lock
|
|
|
- if ($userProfileNamespace->isLocked()) {
|
|
|
- $userProfileNamespace->unLock();
|
|
|
- }
|
|
|
-?>]]></programlisting>
|
|
|
- </example>
|
|
|
+ <example id="zend.session.advanced_usage.locking.example.basic">
|
|
|
+ <title>Блокировка пространства имен сессии</title>
|
|
|
|
|
|
- <para>
|
|
|
- Есть некоторые идеи по поводу того, как организовывать модели в
|
|
|
- парадигме MVC для Веб, включая создание моделей представления для
|
|
|
- использования видами (views). Иногда имеющиеся данные, являются ли
|
|
|
- они частью вашей доменной модели или нет, являются подходящими для
|
|
|
- этой задачи. Для того, чтобы предотвратить изменение таких данных,
|
|
|
- используйте блокировку пространств имен сессий до того, как
|
|
|
- предоставить видам доступ к этим подмножествам вашей модели
|
|
|
- представления.
|
|
|
-<!--
|
|
|
- There are numerous ideas for how to manage models in MVC paradigms for the Web, including creating
|
|
|
- presentation models for use by views. Sometimes existing data, whether part of your domain model or not, is
|
|
|
- adequate for the task. To discourage views from applying any processing logic to alter such data, consider
|
|
|
- locking session namespaces before permitting views to access this subset of your "presentation" model.
|
|
|
--->
|
|
|
- </para>
|
|
|
+ <programlisting language="php"><![CDATA[
|
|
|
+$userProfileNamespace = new Zend_Session_Namespace('userProfileNamespace');
|
|
|
|
|
|
- <example>
|
|
|
- <title>Блокировка сессий в видах<!--Locking Sessions in Views--></title>
|
|
|
-<programlisting language="php">
|
|
|
-<![CDATA[<?php
|
|
|
-class FooModule_View extends Zend_View
|
|
|
-{
|
|
|
- public function show($name)
|
|
|
- {
|
|
|
- if (!isset($this->mySessionNamespace)) {
|
|
|
- $this->mySessionNamespace = Zend::registry('FooModule');
|
|
|
- }
|
|
|
-
|
|
|
- if ($this->mySessionNamespace->isLocked()) {
|
|
|
- return parent::render($name);
|
|
|
- }
|
|
|
-
|
|
|
- $this->mySessionNamespace->lock();
|
|
|
- $return = parent::render($name);
|
|
|
- $this->mySessionNamespace->unLock();
|
|
|
-
|
|
|
- return $return;
|
|
|
- }
|
|
|
+// помечаем сессию как заблокированную только для чтения
|
|
|
+$userProfileNamespace->lock();
|
|
|
+
|
|
|
+// снимаем блокировку
|
|
|
+if ($userProfileNamespace->isLocked()) {
|
|
|
+ $userProfileNamespace->unLock();
|
|
|
}
|
|
|
-?>]]></programlisting>
|
|
|
+]]></programlisting>
|
|
|
</example>
|
|
|
-
|
|
|
</sect2>
|
|
|
|
|
|
- <sect2 id="zend.session.expiration">
|
|
|
-
|
|
|
- <title>Время жизни пространства имен<!--Namespace Expiration--></title>
|
|
|
+ <sect2 id="zend.session.advanced_usage.expiration">
|
|
|
+ <title>Время жизни пространства имен</title>
|
|
|
|
|
|
<para>
|
|
|
- Время жизни может быть ограничено как у пространства имен в целом,
|
|
|
- так и у отдельных ключей. Общие случаи использования
|
|
|
- включают в себя передачу временной информации между запросами
|
|
|
- и повышение защищенности от определенных угроз безопасности
|
|
|
- посредством устранения доступа к потенциально чувствительной
|
|
|
- информации по прошествии некоторого времени после
|
|
|
- аутентификации. Истечение времени жизни может быть основано на
|
|
|
- количестве секунд или на концепции "прыжков" (hops), в которой
|
|
|
- "прыжком" считается каждый успешный запрос, в котором активируется
|
|
|
- пространство имен через, как минимум, один
|
|
|
- <varname>$space = new Zend_Session_Namespace('myspace');</varname>.
|
|
|
-<!--
|
|
|
- Limits can be placed on the longevity of both namespaces and
|
|
|
- individual keys in namespaces. Common use cases
|
|
|
- include passing temporary information between requests, and
|
|
|
- reducing exposure to certain security risks by
|
|
|
- removing access to potentially sensitive information some time
|
|
|
- after authentication occurred. Expiration can
|
|
|
- be based on elapsed seconds, or based on the concept of "hops",
|
|
|
- where a hop occurs for each successive
|
|
|
- request that activates the namespace via at least one
|
|
|
- <varname>$space = new Zend_Session_Namespace('myspace');</varname>.
|
|
|
--->
|
|
|
+ Время жизни может быть ограничено как у пространства имен в целом, так и у отдельных
|
|
|
+ ключей. Общие случаи использованию включают в себя передачу временной информации между
|
|
|
+ запросами и повышение защищенности от определенных угроз безопасности посредством
|
|
|
+ удаления доступа к потенциально чувствительной информации по прошествии некоторого
|
|
|
+ времени после аутентификации. Устаревание может быть основано на количестве секунд или
|
|
|
+ на концепции "прыжков" (hops), в которой "прыжок" происходит при каждом успешном
|
|
|
+ запросе.
|
|
|
</para>
|
|
|
|
|
|
- <example>
|
|
|
- <title>Примеры установки времени жизни<!--Expiration Examples--></title>
|
|
|
-<programlisting language="php">
|
|
|
-<![CDATA[<?php
|
|
|
+ <example id="zend.session.advanced_usage.expiration.example">
|
|
|
+ <title>Примеры установки времени жизни</title>
|
|
|
+
|
|
|
+ <programlisting language="php"><![CDATA[
|
|
|
$s = new Zend_Session_Namespace('expireAll');
|
|
|
$s->a = 'apple';
|
|
|
$s->p = 'pear';
|
|
|
$s->o = 'orange';
|
|
|
|
|
|
-// Время жизни установлено только для ключа "a" (5 секунд)
|
|
|
+// время жизни установлено в 5 секунд только для ключа "a"
|
|
|
$s->setExpirationSeconds(5, 'a');
|
|
|
|
|
|
-// Время жизни всего пространства имен - 5 "прыжков"
|
|
|
+// установить время жизни всему пространству имен в 5 "прыжков"
|
|
|
$s->setExpirationHops(5);
|
|
|
|
|
|
$s->setExpirationSeconds(60);
|
|
|
-// Пространство имен "expireAll" будет помечено как с истекшим временем жизни
|
|
|
-// при первом запросе, произведенном после того, как прошло 60 секунд,
|
|
|
-// или после 5 "прыжков" - в зависимости от того, что произошло раньше
|
|
|
-?>]]></programlisting>
|
|
|
+// пространство имен "expireAll" будет помечено как истекшее по
|
|
|
+// прошествии 60 секунд при ближайшем запросе
|
|
|
+// или через 5 "прыжков", в зависимости от того, что произойдет раньше.
|
|
|
+]]></programlisting>
|
|
|
</example>
|
|
|
|
|
|
<para>
|
|
|
При работе с данными, время жизни которых истекает в текущем запросе,
|
|
|
будьте внимательны при их извлечении. Несмотря на то, что данные
|
|
|
возвращаются по ссылке, изменение этих данных не приведет к их
|
|
|
- сохранению после текущего запроса. Для "сброса" времени истечения
|
|
|
+ сохранению после текущего запроса. Для сброса истечения времени жизни,
|
|
|
извлеките данные во временные переменные, уничтожьте эти данные в
|
|
|
пространстве имен и затем установите соответствующий ключ снова.
|
|
|
-<!--
|
|
|
- When working with data expiring from the session in the current
|
|
|
- request, care should be used when retrieving
|
|
|
- it. Although the data is returned by reference, modifying the data
|
|
|
- will not make expiring data persist past
|
|
|
- the current request. In order to "reset" the expiration time, fetch
|
|
|
- the data into temporary variables, use
|
|
|
- the namespace to unset it, and then set the appropriate keys again.
|
|
|
--->
|
|
|
</para>
|
|
|
-
|
|
|
</sect2>
|
|
|
|
|
|
- <sect2 id="zend.session.controllers">
|
|
|
-
|
|
|
- <title>Инкапсуляция сессий и контроллеры<!--Session Encapsulation and Controllers--></title>
|
|
|
+ <sect2 id="zend.session.advanced_usage.controllers">
|
|
|
+ <title>Инкапсуляция сессий и контроллеры</title>
|
|
|
|
|
|
<para>
|
|
|
- Пространства имен могут также использоваться для разделения доступа
|
|
|
- контроллеров к сессиям, чтобы защитить переменные от повреждения.
|
|
|
- Например, контроллер 'Zend_Auth' может хранить свои постоянные
|
|
|
- данные сессии отдельно от всех остальных контроллеров.
|
|
|
-<!--
|
|
|
- Namespaces can also be used to separate session access by controllers to protect variables from
|
|
|
- contamination. For example, the 'Zend_Auth' controller might keep its session state data separate from all
|
|
|
- other controllers.
|
|
|
--->
|
|
|
+ Пространство имен может быть использовано для разделения доступа контроллеров к сессии,
|
|
|
+ для защиты переменных от повреждения. К примеру, контроллер аутентификации может хранить
|
|
|
+ свои данные в сессии отдельно от всех остальных контроллеров для достижения требований
|
|
|
+ безопасности.
|
|
|
</para>
|
|
|
|
|
|
- <example>
|
|
|
- <title>Сессии с пространствами имен для контроллеров с автоматическим истечением времени<!--Namespaced Sessions for Controllers with Automatic Expiration--></title>
|
|
|
-<programlisting language="php">
|
|
|
-<![CDATA[<?php
|
|
|
-require_once 'Zend/Session.php';
|
|
|
+ <example id="zend.session.advanced_usage.controllers.example">
|
|
|
+ <title>Пространства имен сессий с автоматическим устареванием для контроллеров</title>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Следующий код, как часть контроллера, отображающего вопрос в тесте, создает
|
|
|
+ переменную с булевым значением для обозначения, должен ли быть принят ответ
|
|
|
+ на вопрос теста. В данном случае пользователю приложения дается 300 секунд на ответ
|
|
|
+ для отображаемого вопроса.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting language="php"><![CDATA[
|
|
|
+// ...
|
|
|
// контроллер для вывода вопроса
|
|
|
$testSpace = new Zend_Session_Namespace('testSpace');
|
|
|
// установка времени жизни только для этой переменной
|
|
|
-$testSpace->setExpirationSeconds(300, "accept_answer");
|
|
|
+$testSpace->setExpirationSeconds(300, 'accept_answer');
|
|
|
$testSpace->accept_answer = true;
|
|
|
-
|
|
|
---
|
|
|
-
|
|
|
-// контроллер для обработки ответа на вопрос
|
|
|
+//...
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Ниже показан контроллер, обрабатывающий ответы на вопросы теста. Он
|
|
|
+ определяет, принимать ли ответ, на основе того, был ли он отправлен в отведенное
|
|
|
+ время:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting language="php"><![CDATA[
|
|
|
+// ...
|
|
|
+// контроллер обработки ответа
|
|
|
$testSpace = new Zend_Session_Namespace('testSpace');
|
|
|
-
|
|
|
if ($testSpace->accept_answer === true) {
|
|
|
- // время не истекло
|
|
|
+ // в отведенное время
|
|
|
}
|
|
|
else {
|
|
|
- // время истекло
|
|
|
+ // больше отведенного времени
|
|
|
}
|
|
|
-?>]]></programlisting>
|
|
|
+// ...
|
|
|
+]]></programlisting>
|
|
|
</example>
|
|
|
-
|
|
|
</sect2>
|
|
|
|
|
|
- <sect2 id="zend.session.limitinginstances">
|
|
|
-
|
|
|
- <title>Ограничение количества экземпляров Zend_Session_Namespace до одного на каждое пространство имен<!--Limiting Instances of Zend_Session to One Per Namespace--></title>
|
|
|
+ <sect2 id="zend.session.advanced_usage.single_instance">
|
|
|
+ <title>Ограничение количества экземпляров на каждое пространство имен</title>
|
|
|
|
|
|
<para>
|
|
|
- Мы рекомендуем использовать блокировку сессии (см. выше) вместо этой
|
|
|
- функциональной возможности, которая накладывает дополнительное бремя
|
|
|
- на разработчика, состоящее в передаче экземпляров
|
|
|
- Zend_Session_Namespace во все функции и объекты, нуждающихся в
|
|
|
- использовании этих пространств имен.
|
|
|
-<!--
|
|
|
- We recommend using session locking (see above) instead of the feature below, which places extra management
|
|
|
- burden on the developer to pass any Zend_Session_Namespace instances into whatever functions and objects
|
|
|
- need access to each namespace.
|
|
|
--->
|
|
|
+ Хотя <link linkend="zend.session.advanced_usage.locking">блокировка сессии</link>
|
|
|
+ предоставляет неплохой уровень защиты против непреднамеренного использования данных
|
|
|
+ сессии в кокретном пространстве имен, <classname>Zend_Session_Namespace</classname>
|
|
|
+ так же предоставляет
|
|
|
+ возможность предотвратить создание множества экземпляров для одного пространства имен.
|
|
|
</para>
|
|
|
|
|
|
<para>
|
|
|
- Когда создается первый экземпляр Zend_Session_Namespace, связанный с
|
|
|
- определенным пространством имен, вы можете дать команду
|
|
|
- Zend_Session_Namespace больше не создавать объекты для этого
|
|
|
- пространства имен. Таким образом, в дальнейшем попытка создать
|
|
|
- экземпляр Zend_Session_Namespace для
|
|
|
- того же пространства имен вызовет генерацию исключения. Это
|
|
|
- поведение является опциональным и не принято по умолчанию, но
|
|
|
- остается доступным для тех, кто предпочитает передавать по коду
|
|
|
- единственный объект для каждого пространства имен. Это повышает
|
|
|
- защиту пространства имен от изменений компонентами, которые не
|
|
|
- должны делать этого, поскольку тогда они не будут иметь свободного
|
|
|
- доступа к пространствам имен. Тем не менее, ограничение пространства
|
|
|
- имен до одного экземпляра модет привести к большему объему кода или
|
|
|
- к его усложнению, поскольку он отменяет возможность использования
|
|
|
- директив вида
|
|
|
- <varname>$aNamespace = new Zend_Session_Namespace('aNamespace');</varname>
|
|
|
- после того, как был создан первый экземпляр. Это продемонстрировано
|
|
|
- в примере ниже:
|
|
|
-<!--
|
|
|
- When constructing the first instance of Zend_Session_Namespace attached to a specific namespace, you can
|
|
|
- also instruct Zend_Session_Namespace to not make any more instances for that namespace. Thus, any future
|
|
|
- attempts to construct a Zend_Session_Namespace instance having the same namespace will throw an error. Such
|
|
|
- behavior is optional, and not the default behavior, but remains available to those who prefer to pass around
|
|
|
- a single instance object for each namespace. This increases protection from changes by components that
|
|
|
- should not modify a particular session namespace, because they won't have easy access. However, limiting a
|
|
|
- namespace to a single instance may lead to more code or more complex code, as it removes access to the
|
|
|
- convient <varname>$aNamespace = new Zend_Session_Namespace('aNamespace');</varname>, after the first intance has
|
|
|
- been created, as follows in the example below:
|
|
|
--->
|
|
|
+ Для включения этой возможности, передайте <constant>TRUE</constant> вторым аргументом
|
|
|
+ конструктора при создании последнего разрешенного экземпляра
|
|
|
+ <classname>Zend_Session_Namespace</classname>. Любая последующая попытка инстанциации
|
|
|
+ этого пространства имен сгенерирует исключение.
|
|
|
</para>
|
|
|
|
|
|
- <example>
|
|
|
- <title>Ограничение до единичных экземпляров<!--Limiting to Single Instances--></title>
|
|
|
-<programlisting language="php">
|
|
|
-<![CDATA[<?php
|
|
|
- require_once 'Zend/Session.php';
|
|
|
- $authSpaceAccessor1 = new Zend_Session_Namespace('Zend_Auth');
|
|
|
- $authSpaceAccessor2 = new Zend_Session_Namespace('Zend_Auth', Zend_Session_Namespace::SINGLE_INSTANCE);
|
|
|
- $authSpaceAccessor1->foo = 'bar';
|
|
|
- assert($authSpaceAccessor2->foo, 'bar');
|
|
|
- doSomething($options, $authSpaceAccessor2);
|
|
|
- .
|
|
|
- .
|
|
|
- .
|
|
|
- $aNamespaceObject = new Zend_Session_Namespace('Zend_Auth'); // это вызовет ошибку
|
|
|
-?>]]></programlisting>
|
|
|
+ <example id="zend.session.advanced_usage.single_instance.example">
|
|
|
+ <title>Ограничение доступа к пространству имен сессии одним экземпляром</title>
|
|
|
+
|
|
|
+ <programlisting language="php"><![CDATA[
|
|
|
+// создаем экземпляр для пространства имен
|
|
|
+$authSpaceAccessor1 = new Zend_Session_Namespace('Zend_Auth');
|
|
|
+
|
|
|
+// Создание второго экземпляра для пространства имен,
|
|
|
+// и запрет на создание новых
|
|
|
+$authSpaceAccessor2 = new Zend_Session_Namespace('Zend_Auth', true);
|
|
|
+
|
|
|
+// Создание ссылок на существующие возможно
|
|
|
+$authSpaceAccessor3 = $authSpaceAccessor2;
|
|
|
+
|
|
|
+$authSpaceAccessor1->foo = 'bar';
|
|
|
+
|
|
|
+assert($authSpaceAccessor2->foo, 'bar');
|
|
|
+
|
|
|
+try {
|
|
|
+ $aNamespaceObject = new Zend_Session_Namespace('Zend_Auth');
|
|
|
+} catch (Zend_Session_Exception $e) {
|
|
|
+ echo 'Cannot instantiate this namespace since ' .
|
|
|
+ '$authSpaceAccessor2 was created\n';
|
|
|
+}
|
|
|
+]]></programlisting>
|
|
|
</example>
|
|
|
|
|
|
<para>
|
|
|
- Второй параметр в конструкторе выше говорит Zend_Session, что
|
|
|
- в будущем создание любых других экземпляров Zend_Session_Namespace с
|
|
|
- пространством имен 'Zend_Auth' не допустимо. Поскольку
|
|
|
- директиву <code>new Zend_Session_Namespace('Zend_Auth')</code>
|
|
|
- нельзя использовать после того, как будет выполнен приведенный выше
|
|
|
- код, то разработчику нужно будет где-либо сохранять объект
|
|
|
- (<varname>$authSpaceAccessor2</varname> в
|
|
|
- примере выше), если в дальнейшем при обработке того же запроса
|
|
|
- необходим доступ к этому пространству имен сессии.
|
|
|
+ Второй параметр в конструкторе выше говорит
|
|
|
+ <classname>Zend_Session_Namespace</classname>, что любые новые экземпляры с
|
|
|
+ пространством имен "<classname>Zend_Auth</classname>" не разрешены. Попытка создания
|
|
|
+ такого экземпляра вызовет генерацию исключения конструктором. Разработчик сам отвечает
|
|
|
+ за хранение ссылки на экземпляры объектов(<varname>$authSpaceAccessor1</varname>,
|
|
|
+ <varname>$authSpaceAccessor2</varname>, или
|
|
|
+ <varname>$authSpaceAccessor3</varname> в примере выше), если в дальнейшем при обработке
|
|
|
+ того же запроса необходим доступ к этому пространству имен сессии.
|
|
|
Например, вы можете сохранять экземпляр в статической переменной или
|
|
|
- передавать его другим методам, которым нужен доступ к данному
|
|
|
- пространству имен.
|
|
|
-<!--
|
|
|
- The second parameter in the constructor above will tell Zend_Session_Namespace that any future
|
|
|
- Zend_Session's that are instantiated with the 'Zend_Auth' namespace are not allowed, and will thus cause an
|
|
|
- exception. Since <code>new Zend_Session_Namespace('Zend_Auth')</code> will not be allowed after the code
|
|
|
- above has been executed, the developer becomes responsible for storing the instance object
|
|
|
- (<varname>$authSpaceAccessor2</varname> in the example above) somewhere, if access to this session namespace is
|
|
|
- needed at a later time during the same request. For example, a developer may store the instance in a static
|
|
|
- variable, or pass it to other methods that might need access to this session namespace. Session locking (see
|
|
|
- above) provides a more convenient, and less burdensome approach to limiting access to namespaces.
|
|
|
--->
|
|
|
+ передавать его <ulink
|
|
|
+ url="http://www.martinfowler.com/eaaCatalog/registry.html">реестру</ulink> (смотри
|
|
|
+ <link linkend="zend.registry">Zend_Registry</link>), или передавать его другим методам,
|
|
|
+ которым нужен доступ к данному пространству имен.
|
|
|
</para>
|
|
|
-
|
|
|
</sect2>
|
|
|
|
|
|
- <sect2 id="zend.session.modifyingarray">
|
|
|
-
|
|
|
- <title>Работа с массивами в пространствах имен<!--Working with Arrays in Namespaces--></title>
|
|
|
+ <sect2 id="zend.session.advanced_usage.arrays">
|
|
|
+ <title>Работа с массивами</title>
|
|
|
|
|
|
<para>
|
|
|
- Изменение массива внутри пространства имен невозможно. Простейшим
|
|
|
- решением является сохранение массивов после того, как все желаемые
|
|
|
- значения были установлены. <ulink url="http://framework.zend.com/issues/browse/ZF-800">ZF-800</ulink>
|
|
|
- подтверждает известный баг, затрагивающий многие PHP-приложения,
|
|
|
- использующие "магические" методы и массивы.
|
|
|
-
|
|
|
-<!--
|
|
|
- Modifying an array inside a namespace does not work. The simplest solution is to store arrays after all
|
|
|
- desired values have been set.
|
|
|
- <ulink url="http://framework.zend.com/issues/browse/ZF-800">ZF-800</ulink>
|
|
|
- documents a known issue affecting many PHP applications using magic methods and arrays.
|
|
|
--->
|
|
|
+ Всвязи с историей реализаций магических методов в <acronym>PHP</acronym>, изменение
|
|
|
+ массивов внутри пространства имен может не работать при версиях <acronym>PHP</acronym>
|
|
|
+ меньше 5.2.1. Если вы будете работать только с версиями <acronym>PHP</acronym> 5.2.1 или
|
|
|
+ более поздними, тогда вы можете
|
|
|
+ <link linkend="zend.session.advanced_usage.objects">перейти к следующей секции</link>.
|
|
|
</para>
|
|
|
|
|
|
- <example>
|
|
|
- <title>Известные проблемы с массивами<!--Known problem with arrays--></title>
|
|
|
-<programlisting language="php">
|
|
|
-<![CDATA[<?php
|
|
|
- $sessionNamespace = new Zend_Session_Namespace('Foo');
|
|
|
- $sessionNamespace->array = array();
|
|
|
- $sessionNamespace->array['testKey'] = 1; // Не работает в версиях ниже PHP 5.2.1
|
|
|
-?>]]></programlisting>
|
|
|
+ <example id="zend.session.advanced_usage.arrays.example.modifying">
|
|
|
+ <title>Изменение данных массивов с помощью Zend_Session_Namespace</title>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Далее показано, как эта проблема может быть воспроизведена:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting language="php"><![CDATA[
|
|
|
+$sessionNamespace = new Zend_Session_Namespace();
|
|
|
+$sessionNamespace->array = array();
|
|
|
+
|
|
|
+// может не работать, как ожидается, в версиях PHP до 5.2.1
|
|
|
+$sessionNamespace->array['testKey'] = 1;
|
|
|
+echo $sessionNamespace->array['testKey'];
|
|
|
+]]></programlisting>
|
|
|
</example>
|
|
|
|
|
|
- <para>
|
|
|
- Если вам нужно изменить массив после того, как добавили его в
|
|
|
- пространство имен, извлеките массив, произведите необходимые
|
|
|
- изменения и сохраните его под тем же ключом в пространстве имен.
|
|
|
-<!--
|
|
|
- If you need to modify the array after assigning it to a session namespace key, fetch the array, then
|
|
|
- modify it and save the array back to the session namespace.
|
|
|
--->
|
|
|
- </para>
|
|
|
+ <example id="zend.session.advanced_usage.arrays.example.building_prior">
|
|
|
+ <title>Формирование массива до сохранения в сессию</title>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Если возможно, всецело избегайте данной проблемы, сохраняя массивы в пространство
|
|
|
+ имен сессии только после того, как все необходимые значения были установлены.
|
|
|
+ </para>
|
|
|
|
|
|
- <example>
|
|
|
- <title>Обходной путь: извлечение, изменение и сохранение<!--Workaround: fetch, modify, save--></title>
|
|
|
-<programlisting language="php">
|
|
|
-<![CDATA[<?php
|
|
|
- $sessionNamespace = new Zend_Session_Namespace('Foo');
|
|
|
- $sessionNamespace->array = array('tree' => 'apple');
|
|
|
- $tmp = $sessionNamespace->array;
|
|
|
- $tmp['fruit'] = 'peach';
|
|
|
- $sessionNamespace->array = $tmp;
|
|
|
-?>]]></programlisting>
|
|
|
+ <programlisting language="php"><![CDATA[
|
|
|
+$sessionNamespace = new Zend_Session_Namespace('Foo');
|
|
|
+$sessionNamespace->array = array('a', 'b', 'c');
|
|
|
+]]></programlisting>
|
|
|
</example>
|
|
|
|
|
|
<para>
|
|
|
- Можно также сохранить массив, содержащий ссылку на желаемый массив
|
|
|
- и косвенно работать с ним.
|
|
|
-<!--
|
|
|
- Alternatively, store an array containing a reference to the desired array, and then access it indirectly.
|
|
|
--->
|
|
|
+ Если вы используете подверженную проблеме версию <acronym>PHP</acronym> и необходимо
|
|
|
+ изменить массив после его сохранения в пространстве имен сессии, вы можете использовать
|
|
|
+ оба или один из следующих обходных путей:
|
|
|
</para>
|
|
|
|
|
|
- <example>
|
|
|
- <title>Обходной путь: сохранение массива, содержащего ссылку<!--Workaround: store array containing reference--></title>
|
|
|
-<programlisting language="php">
|
|
|
-<![CDATA[<?php
|
|
|
- $myNamespace = new Zend_Session_Namespace('mySpace');
|
|
|
-
|
|
|
- // работает даже с версиями PHP, содержащими баг
|
|
|
- $a = array(1,2,3);
|
|
|
- $myNamespace->someArray = array( & $a ) ;
|
|
|
- $a['foo'] = 'bar';
|
|
|
-?>]]></programlisting>
|
|
|
- </example>
|
|
|
+ <example id="zend.session.advanced_usage.arrays.example.workaround.reassign">
|
|
|
+ <title>Обходной путь: Пересохранение измененного массива</title>
|
|
|
|
|
|
- </sect2>
|
|
|
+ <para>
|
|
|
+ В последующем коде создается копия сохраненного массива, изменяется и сохраняется
|
|
|
+ обратно, перезаписывая оригинал.
|
|
|
+ </para>
|
|
|
|
|
|
- <sect2 id="zend.session.auth">
|
|
|
+ <programlisting language="php"><![CDATA[
|
|
|
+$sessionNamespace = new Zend_Session_Namespace();
|
|
|
|
|
|
- <title>Использование сессий вместе с аутентификацией<!--Using Sessions with Authentication--></title>
|
|
|
+// устанавливаем исходный массив
|
|
|
+$sessionNamespace->array = array('tree' => 'apple');
|
|
|
|
|
|
- <para>
|
|
|
- Если ваш адаптер аутентификации для <code>Zend_Auth</code>
|
|
|
- возвращает результат, в котором идетификатором авторизации является
|
|
|
- объект (не рекомендуется) вместо массива, то выполняйте проверку
|
|
|
- класса идентификатора авторизации до того, как стартовать сессию.
|
|
|
- Вместо этого мы рекомендуем хранить идентификаторы авторизации,
|
|
|
- вычисленные в адаптере авторизации, под хорошо известным ключом в
|
|
|
- пространстве имен сессии. Например, по умолчанию
|
|
|
- <code>Zend_Auth</code> размещает идентификаторы под ключом 'storage'
|
|
|
- пространства имен 'Zend_Auth'.
|
|
|
-<!--
|
|
|
- If your authentication adapter for <code>Zend_Auth</code> returns a result where the authorization identity
|
|
|
- is an object (not recommended), instead of an array, then make sure to require your authorization identity
|
|
|
- class definition before starting the session. Instead, we recommend storing the authorization ids computed
|
|
|
- within an authentication adapter inside a well-known key in a session namespace. For example, the default
|
|
|
- behavior of <code>Zend_Auth</code> places this in the 'storage' key of the 'Zend_Auth' namespace.
|
|
|
--->
|
|
|
- </para>
|
|
|
+// делаем копию массива
|
|
|
+$tmp = $sessionNamespace->array;
|
|
|
|
|
|
- <para>
|
|
|
- Если вы приказали <code>Zend_Auth</code> не сохранять метку сессии в
|
|
|
- сессиях, то можете вручную сохранять ID авторизации под хорошо
|
|
|
- известным ключом в любом пространстве имен сессии.
|
|
|
- Часто приложения имеют свои
|
|
|
- требования к тому, где хранить "мандат" (учетная запись с
|
|
|
- праметрами доступа пользователя) и идентификатор авторизации.
|
|
|
- Приложения часто устанавливают соответствие идентификаторов
|
|
|
- аутентификации (например, имена пользователей) и идентификаторов
|
|
|
- авторизации (например, присвоенное уникальное целое число) во время
|
|
|
- аутентификации, которая должна производится внутри метода
|
|
|
- <code>authenticate()</code> адаптера аутентификации Zend_Auth.
|
|
|
-<!--
|
|
|
- If you tell <code>Zend_Auth</code> to not persist authentication tokens in sessions, then you can manually
|
|
|
- store the authorization id in the session namespace, in a well-known location in a session namespace of your
|
|
|
- choice. Often, applications have specific needs about where to store credentials used (if any) and
|
|
|
- "authorization" identity. Applications often map authentication identities (e.g. usernames) to authorization
|
|
|
- identities (e.g. a uniquely assigned integer) during authentication, which would occur in the Zend_Auth
|
|
|
- authentication adapter's <code>authenticate()</code> method.
|
|
|
--->
|
|
|
- </para>
|
|
|
+// изменяем копию массива
|
|
|
+$tmp['fruit'] = 'peach';
|
|
|
|
|
|
- <example>
|
|
|
- <title>Пример: Простой доступ к ID авторизации<!--Example: Simplified access of authorization ids--></title>
|
|
|
-<programlisting language="php">
|
|
|
-<![CDATA[<?php
|
|
|
- // pre-authentication request
|
|
|
- require_once 'Zend/Auth/Adapter/Digest.php';
|
|
|
- $adapter = new Zend_Auth_Adapter_Digest($filename, $realm, $username, $password);
|
|
|
- $result = $adapter->authenticate();
|
|
|
- require_once 'Zend/Session/Namespace.php';
|
|
|
- $namespace = new Zend_Session_Namespace('Zend_Auth');
|
|
|
- if ($result->isValid()) {
|
|
|
- $namespace->authorizationId = $result->getIdentity();
|
|
|
- $namespace->date = time();
|
|
|
- } else {
|
|
|
- $namespace->attempts++;
|
|
|
- }
|
|
|
-
|
|
|
- // subsequent requests
|
|
|
- require_once 'Zend/Session.php';
|
|
|
- Zend_Session::start();
|
|
|
- $namespace = new Zend_Session_Namespace('Zend_Auth');
|
|
|
-
|
|
|
- echo "Valid: ", (empty($namespace->authorizationId) ? 'No' : 'Yes'), "\n"';
|
|
|
- echo "Authorization / user Id: ", (empty($namespace->authorizationId)
|
|
|
- ? 'none' : print_r($namespace->authorizationId, true)), "\n"';
|
|
|
- echo "Authentication attempts: ", (empty($namespace->attempts)
|
|
|
- ? '0' : $namespace->attempts), "\n"';
|
|
|
- echo "Authenticated on: ",
|
|
|
- (empty($namespace->date) ? 'No' : date(DATE_ATOM, $namespace->date), "\n"';
|
|
|
-?>]]></programlisting>
|
|
|
+// устанавливаем копию массива обратно в пространство имен сессии
|
|
|
+$sessionNamespace->array = $tmp;
|
|
|
+
|
|
|
+echo $sessionNamespace->array['fruit']; // выводит "peach"
|
|
|
+]]></programlisting>
|
|
|
</example>
|
|
|
|
|
|
- <para>
|
|
|
- Идентификаторы авторизации, хранящиеся на клиентской стороне, могут
|
|
|
- использоваться в атаках на поднятие привилегий, если им доверяет
|
|
|
- серверная сторона и если они, например, не дублируются на серверной
|
|
|
- стороне (например, в данных сессии) и затем сверяются с
|
|
|
- идентификатором авторизации, предоставленным клентом для
|
|
|
- действующией сессии. Мы различаем понятия "идентификаторов
|
|
|
- аутентификации" (например, имена пользователей) и "идентификаторов
|
|
|
- авторизации" (например, ID пользователя #101 в таблице БД для
|
|
|
- пользователей).
|
|
|
-<!--
|
|
|
- Authorization ids stored client-side are subject to privilege escalation vulnerabilities, if these ids are
|
|
|
- used and trusted by the server, unless, for example, the id is duplicated on the server-side (e.g. in the
|
|
|
- session) and then cross-checked with the authorization id claimed by the client for the in-effect session.
|
|
|
- We are differentiating between "authentication ids" (e.g. usernames) and "authorization ids" (e.g. user id
|
|
|
- #101 in the users DB table).
|
|
|
--->
|
|
|
- </para>
|
|
|
+ <example id="zend.session.advanced_usage.arrays.example.workaround.reference">
|
|
|
+ <title>Обходной путь: Сохранение массива, содержащего ссылку</title>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ В качестве альтернативы, сохраниение массива, содержащего ссылку на интересующий
|
|
|
+ массив, с его последующим непрямым изменением:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting language="php"><![CDATA[
|
|
|
+$myNamespace = new Zend_Session_Namespace('myNamespace');
|
|
|
+$a = array(1, 2, 3);
|
|
|
+$myNamespace->someArray = array( &$a );
|
|
|
+$a['foo'] = 'bar';
|
|
|
+echo $myNamespace->someArray['foo']; // выводит "bar"
|
|
|
+]]></programlisting>
|
|
|
+ </example>
|
|
|
+ </sect2>
|
|
|
+
|
|
|
+ <sect2 id="zend.session.advanced_usage.objects">
|
|
|
+ <title>Использование сессии с объектами</title>
|
|
|
|
|
|
<para>
|
|
|
- Последнее часто используется для повышения производительности -
|
|
|
- например, для выборки из пула серверов, кеширующих данные сессии,
|
|
|
- чтобы решить проблему "курицы и яйца". Часто
|
|
|
- возникают дебаты о том, использовать ли настоящий ID авторизации в
|
|
|
- куках или некую замену, которая помогает установить соответствие
|
|
|
- с настоящим ID авторизации (или сессии сервера(ов), хранящего
|
|
|
- сессию/профиль пользователя и т.д.), в то время как некоторые
|
|
|
- архитекторы системной безопасности предпочитают избегать
|
|
|
- публикования истинных значений первичных ключей, пытаясь достичь
|
|
|
- некоторого дополнительного уровня защиты в случае наличия
|
|
|
- уязвимостей к SQL-инъекциям.
|
|
|
-<!--
|
|
|
- The latter is not uncommon for performance reasons, such as helping select from a pool of servers caching
|
|
|
- session information to help solve chicken-and-egg problems. Often debates ensue about whether to use the
|
|
|
- real authorization id in the cookie, or some substitute that aids in mapping to the real authorization id
|
|
|
- (or session or server(s) holding the user's session/profile, etc.), as some system security architects wish
|
|
|
- to prevent true "DB primary keys" from escaping into the wild. These architects try and obtain some level of
|
|
|
- protection by obfuscation in the event of a SQL injection vulnerability in their system. Not everyone uses
|
|
|
- auto-increment strategies for authorization ids.
|
|
|
--->
|
|
|
+ Если вы планируете хранить объекты в <acronym>PHP</acronym> сессии, имейте в виду, что
|
|
|
+ они будут <ulink
|
|
|
+ url="http://www.php.net/manual/en/language.oop.serialization.php">сериализованы</ulink>
|
|
|
+ для сохранения. Таким образом, любые объекты, сохраненные в <acronym>PHP</acronym>
|
|
|
+ сессии, должны быть десериализованы при извлечении из хранилища. Подразумевается что
|
|
|
+ разработчик должен обеспечить определение классов для сохраненных объектов до
|
|
|
+ десериализации объекта из сессионного хранилища. Если класс десериализуемого объекта
|
|
|
+ не определен, он становится экземпляром <code>stdClass</code>.
|
|
|
</para>
|
|
|
-
|
|
|
</sect2>
|
|
|
|
|
|
- <sect2 id="zend.session.testing">
|
|
|
-
|
|
|
- <title>Использование сессий с юнит-тестами<!--Using Sessions with Unit Tests--></title>
|
|
|
+ <sect2 id="zend.session.advanced_usage.testing">
|
|
|
+ <title>Использование сессии с юнит тестами</title>
|
|
|
|
|
|
<para>
|
|
|
- Zend Framework использует PHPUnit для своего тестирования. Многие
|
|
|
- разработчики расширяют существующие наборы
|
|
|
- юнит-тестов для покрытия кода в своих приложениях.
|
|
|
- Если при выполнении юнит-тестирований после завершения сессии были
|
|
|
- использованы любые связанные с записью методы, то генерируется
|
|
|
- исключение "<emphasis>Zend_Session is currently marked
|
|
|
- as read-only</emphasis>" ("Zend_Session помечен как доступный только
|
|
|
- для чтения"). Тем не менее, юнит-тесты, использующие Zend_Session,
|
|
|
- требуют особого внимания в разработке, поскольку закрытие
|
|
|
- (<code>Zend_Session::writeClose()</code>) или уничтожение сессии
|
|
|
- (<code>Zend_Session::destroy()</code>) не дает впоследствии
|
|
|
- устанавливать или сбрасывать ключи в любом объекте
|
|
|
- Zend_Session_Namespace. Это поведение является прямым следствием
|
|
|
- использования лежащего в основе расширения ext/session,
|
|
|
- функций <code>session_destroy()</code> и
|
|
|
- <code>session_write_close()</code>, которые не имеют механизма
|
|
|
- "отмены" для облегчения установки/демонтажа в юнит-тестировании.
|
|
|
-<!--
|
|
|
- Zend Framework relies on PHPUnit to facilitate testing of itself. Many developers extend the existing
|
|
|
- suite of unit tests to cover the code in their applications. The exception
|
|
|
- "<emphasis>Zend_Session is currently marked as read-only</emphasis>" is thrown while
|
|
|
- performing unit tests, if any write-related methods are used after ending the session. However, unit tests
|
|
|
- using Zend_Session require extra attention, because closing (<code>Zend_Session::writeClose()</code>), or
|
|
|
- destroying a session (<code>Zend_Session::destroy()</code>) prevents any further setting or unsetting of
|
|
|
- keys in any Zend_Session_Namespace. This behavior is a direct result of the underlying ext/session mechanism
|
|
|
- and PHP's <code>session_destroy()</code> and <code>session_write_close()</code>, which has no "undo"
|
|
|
- mechanism to facilitate setup/teardown with unit tests.
|
|
|
--->
|
|
|
+ Zend Framework опирается на PHPUnit для облегчения своего тестирования. Многие
|
|
|
+ разработчики расширяют существующий набор юнит тестов для покрытия кода в их приложении.
|
|
|
+ Если во время выполнения юнит тестирования после закрытия сессии происходит попытка
|
|
|
+ использования пишущих в сессию методов, генерируется исключение "<emphasis>Zend_Session
|
|
|
+ is currently marked as read-only</emphasis> (Zend_Session в данный момент помечен как
|
|
|
+ только для чтения)". Однако <classname>Zend_Session</classname> требует особое внимание,
|
|
|
+ так как закрытие (<methodname>Zend_Session::writeClose()</methodname>), или уничтожение
|
|
|
+ (<methodname>Zend_Session::destroy()</methodname>) сессии предотвращает дальнейшую
|
|
|
+ установку или удаление ключей в любом экземпляре
|
|
|
+ <classname>Zend_Session_Namespace</classname>.
|
|
|
+ Это поведение - прямой результат используемого механизма ext/session, методов
|
|
|
+ <methodname>session_destroy()</methodname> и
|
|
|
+ <methodname>session_write_close()</methodname> в <acronym>PHP</acronym>, которые не
|
|
|
+ имеют механизма "отменить" для выполнения настройки/сброса юнит теста.
|
|
|
</para>
|
|
|
|
|
|
<para>
|
|
|
- Чтобы обойти это, см. юнит-тест
|
|
|
- <code>testSetExpirationSeconds()</code> в
|
|
|
- <code>tests/Zend/Session/SessionTest.php</code> и
|
|
|
- <code>SessionTestHelper.php</code>, которые используют
|
|
|
- <code>exec()</code> для запуска отдельного процесса. Новый процесс
|
|
|
- более точно имитирует второй, последующий, запрос из броузера.
|
|
|
- Отдельный процесс начинается с "чистой" сессии, так же, как при
|
|
|
- выполнении любого PHP-скрипта для веб-запроса. Кроме этого,
|
|
|
- любые изменения в <varname>$_SESSION[]</varname>, произведенные при вызове
|
|
|
- процесса, становятся доступными и в дочернем процессе, что дает
|
|
|
- родительскому процессу возможность закрыть сессию до использования
|
|
|
- <code>exec()</code>.
|
|
|
-<!--
|
|
|
- To work around this, see the unit test <code>testSetExpirationSeconds()</code> in
|
|
|
- <code>tests/Zend/Session/SessionTest.php and SessionTestHelper.php</code>, which make use of PHP's
|
|
|
- <code>exec()</code> to launch a separate process. The new process more accurately simulates a second,
|
|
|
- successive request from a browser. The separate process begins with a "clean" session, just like any PHP
|
|
|
- script execution for a web request. Also, any changes to <varname>$_SESSION[]</varname> made in the calling
|
|
|
- process become available to the child process, provided the parent closed the session before using
|
|
|
- <code>exec()</code>
|
|
|
--->
|
|
|
+ Для обхода этой проблемы, смотри метод
|
|
|
+ <methodname>testSetExpirationSeconds()</methodname> юнит тестов в
|
|
|
+ <code>SessionTest.php</code> и <code>SessionTestHelper.php</code>. Оба находятся в
|
|
|
+ <code>tests/Zend/Session</code>. Они используют функцию <acronym>PHP</acronym> -
|
|
|
+ <methodname>exec()</methodname> для запуска отдельного процесса. Новый процесс более
|
|
|
+ точно симулирует второй, последующий, запрос от браузера. Отдельный процесс стартует с
|
|
|
+ "чистой" сессией, как любое другое выполнение <acronym>PHP</acronym> скрипта по web
|
|
|
+ запросу. Также, любые изменения в <varname>$_SESSION</varname> сделанные в вызывающем
|
|
|
+ процессе становятся доступны дочернему процессу, при условии что родитель закрыл сессию
|
|
|
+ до вызова <methodname>exec()</methodname>.
|
|
|
</para>
|
|
|
|
|
|
- <example>
|
|
|
- <title>Использование PHPUnit для тестирования кода, написанного с использованием Zend_Session*<!--Using PHPUnit to test code written using Zend_Session*--></title>
|
|
|
-<programlisting language="php">
|
|
|
-<![CDATA[<?php
|
|
|
- // testing setExpirationSeconds()
|
|
|
- require 'tests/Zend/Session/SessionTestHelper.php'; // also see SessionTest.php in trunk/
|
|
|
- $script = 'SessionTestHelper.php';
|
|
|
- $s = new Zend_Session_Namespace('space');
|
|
|
- $s->a = 'apple';
|
|
|
- $s->o = 'orange';
|
|
|
- $s->setExpirationSeconds(5);
|
|
|
-
|
|
|
- Zend_Session::regenerateId();
|
|
|
- $id = Zend_Session::getId();
|
|
|
- session_write_close(); // release session so process below can use it
|
|
|
- sleep(4); // not long enough for things to expire
|
|
|
- exec($script . "expireAll $id expireAll", $result);
|
|
|
- $result = $this->sortResult($result);
|
|
|
- $expect = ';a === apple;o === orange;p === pear';
|
|
|
- $this->assertTrue($result === $expect,
|
|
|
- "iteration over default Zend_Session namespace failed; expecting result === '$expect', but got '$result'");
|
|
|
-
|
|
|
- sleep(2); // long enough for things to expire (total of 6 seconds waiting, but expires in 5)
|
|
|
- exec($script . "expireAll $id expireAll", $result);
|
|
|
- $result = array_pop($result);
|
|
|
- $this->assertTrue($result === '',
|
|
|
- "iteration over default Zend_Session namespace failed; expecting result === '', but got '$result')");
|
|
|
- session_start(); // resume artificially suspended session
|
|
|
-
|
|
|
- // We could split this into a separate test, but actually, if anything leftover from above
|
|
|
- // contaminates the tests below, that is also a bug that we want to know about.
|
|
|
- $s = new Zend_Session_Namespace('expireGuava');
|
|
|
- $s->setExpirationSeconds(5, 'g'); // now try to expire only 1 of the keys in the namespace
|
|
|
- $s->g = 'guava';
|
|
|
- $s->p = 'peach';
|
|
|
- $s->p = 'plum';
|
|
|
-
|
|
|
- session_write_close(); // release session so process below can use it
|
|
|
- sleep(6); // not long enough for things to expire
|
|
|
- exec($script . "expireAll $id expireGuava", $result);
|
|
|
- $result = $this->sortResult($result);
|
|
|
- session_start(); // resume artificially suspended session
|
|
|
- $this->assertTrue($result === ';p === plum',
|
|
|
- "iteration over named Zend_Session namespace failed (result=$result)");
|
|
|
-?>]]></programlisting>
|
|
|
- </example>
|
|
|
+ <example id="zend.session.advanced_usage.testing.example">
|
|
|
+ <title>PHPUnit тестирование кода, зависимого от Zend_Session</title>
|
|
|
|
|
|
+ <programlisting language="php"><![CDATA[
|
|
|
+// тестирование setExpirationSeconds()
|
|
|
+$script = 'SessionTestHelper.php';
|
|
|
+$s = new Zend_Session_Namespace('space');
|
|
|
+$s->a = 'apple';
|
|
|
+$s->o = 'orange';
|
|
|
+$s->setExpirationSeconds(5);
|
|
|
+
|
|
|
+Zend_Session::regenerateId();
|
|
|
+$id = Zend_Session::getId();
|
|
|
+session_write_close(); // освобождаем сессию для процесса ниже
|
|
|
+sleep(4); // недостаточно долго для истекания сессии
|
|
|
+exec($script . "expireAll $id expireAll", $result);
|
|
|
+$result = $this->sortResult($result);
|
|
|
+$expect = ';a === apple;o === orange;p === pear';
|
|
|
+$this->assertTrue($result === $expect,
|
|
|
+ "iteration over default Zend_Session namespace failed; " .
|
|
|
+ "expecting result === '$expect', but got '$result'");
|
|
|
+
|
|
|
+sleep(2); // достаточно для истекания сессии(всего 6 секунд
|
|
|
+ // ожидания, но истекла за 5)
|
|
|
+exec($script . "expireAll $id expireAll", $result);
|
|
|
+$result = array_pop($result);
|
|
|
+$this->assertTrue($result === '',
|
|
|
+ "iteration over default Zend_Session namespace failed; " .
|
|
|
+ "expecting result === '', but got '$result')");
|
|
|
+session_start(); // Восстанавливаем искусственно остановленную сессию
|
|
|
+
|
|
|
+// Мы можем выделить это в отдельный тест, но на самом деле, если
|
|
|
+// какие-либо остатки от теста выше загрязняют тест ниже, это тоже баг,
|
|
|
+// о котором мы хотели бы знать.
|
|
|
+$s = new Zend_Session_Namespace('expireGuava');
|
|
|
+$s->setExpirationSeconds(5, 'g'); // теперь устанавливаем время жизни только
|
|
|
+ // одному ключу в пространстве имен сессии
|
|
|
+$s->g = 'guava';
|
|
|
+$s->p = 'peach';
|
|
|
+$s->p = 'plum';
|
|
|
+
|
|
|
+session_write_close(); // освобождаем сессию для процесса ниже
|
|
|
+sleep(6); // недостаточно долго для истекания сессии
|
|
|
+exec($script . "expireAll $id expireGuava", $result);
|
|
|
+$result = $this->sortResult($result);
|
|
|
+session_start(); // Восстанавливаем искусственно остановленную сессию
|
|
|
+$this->assertTrue($result === ';p === plum',
|
|
|
+ "iteration over named Zend_Session namespace failed (result=$result)");
|
|
|
+]]></programlisting>
|
|
|
+ </example>
|
|
|
</sect2>
|
|
|
-
|
|
|
</sect1>
|