<commit_before><sect1 id="zend.session.advanced_usage">

    <title>Advanced Usage</title>

    <para>
        While the basic usage examples are a perfectly acceptable way to utilize Zend Framework sessions, there are some
        best practices to consider. This section discusses the finer details of session handling and illustrates more
        advanced usage of the Zend_Session component.
    </para>

    <sect2 id="zend.session.advanced_usage.starting_a_session">

        <title>Starting a Session</title>

        <para>
            If you want all requests to have a session facilitated by Zend_Session, then start the session in the
            bootstrap file:
        </para>

        <example id="zend.session.advanced_usage.starting_a_session.example">

            <title>Starting the Global Session</title>

            <programlisting role="php"><![CDATA[
Zend_Session::start();
]]>
            </programlisting>

        </example>

        <para>
            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::start()</code> first. (More on
            advanced features later.)
        </para>

        <para>
            There are four ways to start a session, when using Zend_Session. Two are wrong.
        </para>

        <orderedlist>
            <listitem>
                <para>
                    Wrong: Do not enable PHP's
                    <ulink url="http://www.php.net/manual/en/ref.session.php#ini.session.auto-start"><code>                    session.auto_start</code>
                    setting</ulink>. 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
                    <code>php.ini</code>, then add the following to your <code>.htaccess</code> file (usually in your
                    HTML document root directory):
                    <programlisting role="httpd.conf"><![CDATA[
php_value session.auto_start 0
]]>
</programlisting>
                </para>
            </listitem>
            <listitem>
                <para>
                    Wrong: Do not use PHP's
                    <ulink url="http://www.php.net/session_start"><code>session_start()</code></ulink> function
                    directly. If you use <code>session_start()</code> directly, and then start using
                    <code>Zend_Session_Namespace</code>, 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 <code>Zend_Session_Namespace</code> or calling
                    <code>Zend_Session::start()</code>, an error of level <code>E_NOTICE</code> will be generated, and
                    the call will be ignored.
                </para>
            </listitem>
            <listitem>
                <para>
                    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 bootstrap code.
                    Sessions have some overhead. If some requests need sessions, but other requests will not need to use
                    sessions, then:
                </para>
                <itemizedlist mark="opencircle">
                    <listitem>
                        <para>
                            Unconditionally set the <code>strict</code> option to <code>true</code> using
                            <code>Zend_Session::setOptions()</code> in your bootstrap.
                        </para>
                    </listitem>
                    <listitem>
                        <para>
                            Call <code>Zend_Session::start()</code> only for requests that need to use sessions and
                            before any <code>Zend_Session_Namespace</code> objects are instantiated.
                        </para>
                    </listitem>
                    <listitem>
                        <para>
                            Use "<code>new Zend_Session_Namespace()</code>" normally, where needed, but make sure
                            <code>Zend_Session::start()</code> has been called previously.
                        </para>
                    </listitem>
                </itemizedlist>
                <para>
                    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 application
                    developers enforce a design decision to avoid using sessions for certain requests, since it causes
                    an exception to be thrown when <code>Zend_Session_Namespace</code> is instantiated before
                    <code>Zend_Session::start()</code> is called. Developers should carefully consider the impact of
                    using <code>Zend_Session::setOptions()</code>, since these options have global effect, owing to
                    their correspondence to the underlying options for ext/session.
                </para>
            </listitem>
            <listitem>
                <para>
                    Correct: Just instantiate <code>Zend_Session_Namespace</code> whenever needed, and the underlying
                    PHP session will be automatically started. 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 role="strong">before</emphasis> any
                    output (e.g., <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). See
                    <xref linkend="zend.session.global_session_management.headers_sent" /> for more information.
                </para>
            </listitem>
        </orderedlist>

    </sect2>

    <sect2 id="zend.session.advanced_usage.locking">

        <title>Locking Session Namespaces</title>

        <para>
            Session namespaces can be locked, to prevent further alterations to the data in that namespace. Use
            <code>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
            <code>Zend_Session_Namespace</code> instances does not prevent the use of symbol table aliases to the same
            data (see <ulink url="http://www.php.net/references">PHP references</ulink>).
        </para>

        <example id="zend.session.advanced_usage.locking.example.basic">

            <title>Locking Session Namespaces</title>

            <programlisting role="php"><![CDATA[
$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>

    </sect2>

    <sect2 id="zend.session.advanced_usage.expiration">

        <title>Namespace Expiration</title>

        <para>
            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 either elapsed seconds or the number of "hops", where a hop occurs for each successive request
            that instantiates the namespace at least once.
        </para>

        <example id="zend.session.advanced_usage.expiration.example">

            <title>Expiration Examples</title>

            <programlisting role="php"><![CDATA[
$s = new Zend_Session_Namespace('expireAll');
$s->a = 'apple';
$s->p = 'pear';
$s->o = 'orange';

$s->setExpirationSeconds(5, 'a'); // expire only the key "a" in 5 seconds

// expire entire namespace in 5 "hops"
$s->setExpirationHops(5);

$s->setExpirationSeconds(60);
// The "expireAll" namespace will be marked "expired" on
// the first request received after 60 seconds have elapsed,
// or in 5 hops, whichever happens first.<commit_msg>Fix for ZF-4966<commit_after><sect1 id="zend.session.advanced_usage">

    <title>Advanced Usage</title>

    <para>
        While the basic usage examples are a perfectly acceptable way to utilize Zend Framework sessions, there are some
        best practices to consider. This section discusses the finer details of session handling and illustrates more
        advanced usage of the Zend_Session component.
    </para>

    <sect2 id="zend.session.advanced_usage.starting_a_session">

        <title>Starting a Session</title>

        <para>
            If you want all requests to have a session facilitated by Zend_Session, then start the session in the
            bootstrap file:
        </para>

        <example id="zend.session.advanced_usage.starting_a_session.example">

            <title>Starting the Global Session</title>

            <programlisting role="php"><![CDATA[
Zend_Session::start();
]]>
            </programlisting>

        </example>

        <para>
            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::start()</code> first. (More on
            advanced features later.)
        </para>

        <para>
            There are four ways to start a session, when using Zend_Session. Two are wrong.
        </para>

        <orderedlist>
            <listitem>
                <para>
                    Wrong: Do not enable PHP's
                    <ulink url="http://www.php.net/manual/en/ref.session.php#ini.session.auto-start"><code>                    session.auto_start</code>
                    setting</ulink>. 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
                    <code>php.ini</code>, then add the following to your <code>.htaccess</code> file (usually in your
                    HTML document root directory):
                    <programlisting role="httpd.conf"><![CDATA[
php_value session.auto_start 0
]]>
</programlisting>
                </para>
            </listitem>
            <listitem>
                <para>
                    Wrong: Do not use PHP's
                    <ulink url="http://www.php.net/session_start"><code>session_start()</code></ulink> function
                    directly. If you use <code>session_start()</code> directly, and then start using
                    <code>Zend_Session_Namespace</code>, 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 <code>Zend_Session_Namespace</code> or calling
                    <code>Zend_Session::start()</code>, an error of level <code>E_NOTICE</code> will be generated, and
                    the call will be ignored.
                </para>
            </listitem>
            <listitem>
                <para>
                    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 bootstrap code.
                    Sessions have some overhead. If some requests need sessions, but other requests will not need to use
                    sessions, then:
                </para>
                <itemizedlist mark="opencircle">
                    <listitem>
                        <para>
                            Unconditionally set the <code>strict</code> option to <code>true</code> using
                            <code>Zend_Session::setOptions()</code> in your bootstrap.
                        </para>
                    </listitem>
                    <listitem>
                        <para>
                            Call <code>Zend_Session::start()</code> only for requests that need to use sessions and
                            before any <code>Zend_Session_Namespace</code> objects are instantiated.
                        </para>
                    </listitem>
                    <listitem>
                        <para>
                            Use "<code>new Zend_Session_Namespace()</code>" normally, where needed, but make sure
                            <code>Zend_Session::start()</code> has been called previously.
                        </para>
                    </listitem>
                </itemizedlist>
                <para>
                    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 application
                    developers enforce a design decision to avoid using sessions for certain requests, since it causes
                    an exception to be thrown when <code>Zend_Session_Namespace</code> is instantiated before
                    <code>Zend_Session::start()</code> is called. Developers should carefully consider the impact of
                    using <code>Zend_Session::setOptions()</code>, since these options have global effect, owing to
                    their correspondence to the underlying options for ext/session.
                </para>
            </listitem>
            <listitem>
                <para>
                    Correct: Just instantiate <code>Zend_Session_Namespace</code> whenever needed, and the underlying
                    PHP session will be automatically started. 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 role="strong">before</emphasis> any
                    output (e.g., <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). See
                    <xref linkend="zend.session.global_session_management.headers_sent" /> for more information.
                </para>
            </listitem>
        </orderedlist>

    </sect2>

    <sect2 id="zend.session.advanced_usage.locking">

        <title>Locking Session Namespaces</title>

        <para>
            Session namespaces can be locked, to prevent further alterations to the data in that namespace. Use
            <code>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
            <code>Zend_Session_Namespace</code> instances does not prevent the use of symbol table aliases to the same
            data (see <ulink url="http://www.php.net/references">PHP references</ulink>).
        </para>

        <example id="zend.session.advanced_usage.locking.example.basic">

            <title>Locking Session Namespaces</title>

            <programlisting role="php"><![CDATA[
$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>

    </sect2>

    <sect2 id="zend.session.advanced_usage.expiration">

        <title>Namespace Expiration</title>

        <para>
            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 either elapsed seconds or the number of "hops", where a hop occurs for each successive request.
        </para>

        <example id="zend.session.advanced_usage.expiration.example">

            <title>Expiration Examples</title>

            <programlisting role="php"><![CDATA[
$s = new Zend_Session_Namespace('expireAll');
$s->a = 'apple';
$s->p = 'pear';
$s->o = 'orange';

$s->setExpirationSeconds(5, 'a'); // expire only the key "a" in 5 seconds

// expire entire namespace in 5 "hops"
$s->setExpirationHops(5);

$s->setExpirationSeconds(60);
// The "expireAll" namespace will be marked "expired" on
// the first request received after 60 seconds have elapsed,
// or in 5 hops, whichever happens first.
{'fraction_non_alphanumeric': 0.08660006515365404, 'fraction_numerical': 0.0019546096210229123, 'mean_word_length': 2.0682991837414626, 'pattern_counts': {'":': 0, '<': 317, '<?xml version=': 0, '>': 333, 'https://': 0, 'lorem ipsum': 0, 'www.': 8, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6647822', 'n_tokens_mistral': 4617, 'n_tokens_neox': 4241, 'n_words': 1606}