Zend_Session-AdvancedUsage.xml 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- EN-Revision: 24249 -->
  3. <!-- Reviewed: no -->
  4. <sect1 id="zend.session.advanced_usage">
  5. <title>Fortgeschrittene Benutzung</title>
  6. <para>
  7. Wärend die Beispiele für die Basisnutzung völlig akzeptierbar sind, in ihrem Weg Zend
  8. Framework Sessions zu Benutzen, ist auch die beste Praxis zu bedenken. Diese Sektion
  9. beschreibt die näheren Details von Session Handling und illustriert die fortgeschrittene
  10. Benutzung der <classname>Zend_Session</classname> Komponente.
  11. </para>
  12. <sect2 id="zend.session.advanced_usage.starting_a_session">
  13. <title>Starten einer Session</title>
  14. <para>
  15. Wenn man alle Anfragen einer Session durch <classname>Zend_Session</classname>
  16. bearbeitet haben will, muß die Session in der Bootstrap Datei gestartet werden:
  17. </para>
  18. <example id="zend.session.advanced_usage.starting_a_session.example">
  19. <title>Starten einer globalen Session</title>
  20. <programlisting language="php"><![CDATA[
  21. Zend_Session::start();
  22. ]]></programlisting>
  23. </example>
  24. <para>
  25. Durch das Starten der Session in der Bootstrap Datei verhindert man das die Session
  26. gestartet werden könnte nachdem die Header an den Browser gesendet wurde, was zu einer
  27. Ausnahme und möglicherweise zu einer fehlerhaften Seiten im Browser führen würde. Viele
  28. gehobenen Features benötigen zuerst <methodname>Zend_Session::start()</methodname>.
  29. (Mehr dazu später in den gehobenen Features)
  30. </para>
  31. <para>
  32. Es gibt vier Wege eine Session zustarten wenn <classname>Zend_Session</classname>
  33. verwendet wird. Zwei sind falsch.
  34. </para>
  35. <orderedlist>
  36. <listitem>
  37. <para>
  38. Falsch: <acronym>PHP</acronym>'s <ulink
  39. url="http://www.php.net/manual/de/ref.session.php#ini.session.auto-start"><code>session.auto_start</code>
  40. Einstellung</ulink> darf nicht eingeschaltet werden. Wenn keine Möglichkeit
  41. besteht diese Einstellung in php.ini zu deaktivieren, und mod_php (oder
  42. ähnliches) verwendet wird, und die Einstellung schon in <code>php.ini</code>
  43. aktiviert ist, kann das folgende in der <code>.htaccess</code> Datei
  44. (normalerweise im <acronym>HTML</acronym> Dokumenten Basisverzeichnis)
  45. hinzugefügt werden:
  46. </para>
  47. <programlisting language="httpd.conf"><![CDATA[
  48. php_value session.auto_start 0
  49. ]]></programlisting>
  50. </listitem>
  51. <listitem>
  52. <para>
  53. Falsch: <acronym>PHP</acronym>'s <ulink
  54. url="http://www.php.net/session_start"><methodname>session_start()</methodname></ulink>
  55. Funktion darf nicht direkt verwendet werden. Wenn
  56. <methodname>session_start()</methodname> direkt, und anschließend
  57. <classname>Zend_Session_Namespace</classname> verwendet wird, wird von
  58. <methodname>Zend_Session::start()</methodname> eine Ausnahme geworfen ("session
  59. has already been started"). Wenn <methodname>Zend_Session::start()</methodname>
  60. ausgerufen wird, nachdem <classname>Zend_Session_Namespace</classname> verwendet
  61. wird oder <methodname>Zend_Session::start()</methodname> explizit verwendet
  62. wird, wird ein Fehler vom Level <constant>E_NOTICE</constant> erzeugt und der
  63. Aufruf wird ignoriert.
  64. </para>
  65. </listitem>
  66. <listitem>
  67. <para>
  68. Richtig: Verwenden von <methodname>Zend_Session::start()</methodname>. Wenn es
  69. gewünscht ist, das alle Anfragen eine Session haben und verwenden, sollte diese
  70. Funktion sehr früh, direkt und entscheidungslos in der Bootstrap Datei
  71. aufgerufen werden. Session haben einigen Overhead. Wenn einige Anfragen Sessions
  72. benötigen aber andere Anfragen keine Sessions verwenden, dann:
  73. </para>
  74. <itemizedlist mark="opencircle">
  75. <listitem>
  76. <para>
  77. Entscheidungslos, die <code>strict</code> Option auf
  78. <constant>TRUE</constant> setzen durch Verwendung von
  79. <methodname>Zend_Session::setOptions()</methodname> in der Bootstrap
  80. Datei.
  81. </para>
  82. </listitem>
  83. <listitem>
  84. <para>
  85. Aufruf von <methodname>Zend_Session::start()</methodname> nur für die
  86. Anfragen die eine Session verwenden müssen und vor jeglichen
  87. <classname>Zend_Session_Namespace</classname> initiiert werden.
  88. </para>
  89. </listitem>
  90. <listitem>
  91. <para>
  92. Normales verwenden von "<code>new Zend_Session_Namespace()</code>" wo es
  93. benötigt wird, aber sicherstellen das davor
  94. <methodname>Zend_Session::start()</methodname> ausgerufen wurde.
  95. </para>
  96. </listitem>
  97. </itemizedlist>
  98. <para>
  99. Die Option <code>strict</code> verhindert das <code>new
  100. Zend_Session_Namespace()</code> automatisch eine Session startet und dabei
  101. <methodname>Zend_Session::start()</methodname> verwendet. Deshalb hilft diese
  102. Option Anwendungs Entwicklern, sich für ein Design entscheiden zu können welches
  103. verhindert das für bestimmte Anfragen Sessions verwendet werden, da es eine
  104. Ausnahme verursachen würde wenn <classname>Zend_Session_Namespace</classname>
  105. instanziiert wird, bevor <methodname>Zend_Session::start()</methodname>
  106. aufgerufen wird. Entwickler sollten vorsichtig entscheiden welchen Einfluß die
  107. Verwendung von <methodname>Zend_Session::setOptions()</methodname> hat, da diese
  108. Optionen globale Seiteneffekte hat, in Folge der Korrespondenz der
  109. darunterliegenden Optionen für ext/session.
  110. </para>
  111. </listitem>
  112. <listitem>
  113. <para>
  114. Richtig: Einfach <code>new Zend_Session_Namespace()</code> instanzieren wo dies
  115. auch immer notwendig ist, und die darunterliegende <acronym>PHP</acronym>
  116. Session wird automatisch gestartet. Das bietet eine extrem simple Handhabung die
  117. in den meisten Situationen gut funktioniert. Trotzdem ist man dann dafür
  118. verantwortlich darauf zu schauen dass das erste
  119. <code>new Zend_Session_Namespace()</code> passiert <emphasis>bevor</emphasis>
  120. irgendeine Ausgabe (z.B. <ulink
  121. url="http://www.php.net/headers_sent">HTTP headers</ulink> ) von
  122. <acronym>PHP</acronym> an den Client gesendet wird, wenn standardmäßige,
  123. Cookie-basierte Sessions verwendet werden (sehr empfehlenswert). Siehe <link
  124. linkend="zend.session.global_session_management.headers_sent">dieses
  125. Kapitel</link> für weitere Informationen.
  126. </para>
  127. </listitem>
  128. </orderedlist>
  129. </sect2>
  130. <sect2 id="zend.session.advanced_usage.locking">
  131. <title>Gesperrte Session Namensräume</title>
  132. <para>
  133. Session Namensräume können gesperrt werden um weitere Veränderungen der Daten in diesem
  134. Namensraum zu verhindern. Die Verwendung von <methodname>lock()</methodname> macht einen
  135. speziellen Namensraum nur-lesbar, <methodname>unLock()</methodname> macht einen
  136. nur-lesbaren Namensraum les- und schreibbar, und <methodname>isLocked()</methodname>
  137. prüft ob ein Namensraum vorher gesperrt wurde. Sperren sind flüchtig und bestehen nicht
  138. von einer Anfrage zur nächsten. Die Sperre des Namensraumes hat keinen Effekt auf
  139. Setz-Methoden von Objekten welche im Namensraum gespeichert sind, aber sie verhindert
  140. die Verwendung der Setz-Methoden des Namensraumes welche das gespeicherte Objekt direkt
  141. im Namensraum löschen oder ersetzen. Gleichwohl verhindert das Sperren von
  142. <classname>Zend_Session_Namespace</classname> Instanzen nicht die Verwendung von
  143. symbolischen Tabellen-Aliasen auf die gleichen Daten (siehe <ulink
  144. url="http://www.php.net/references">PHP references</ulink>).
  145. </para>
  146. <example id="zend.session.advanced_usage.locking.example.basic">
  147. <title>Sperren von Session Namensräumen</title>
  148. <programlisting language="php"><![CDATA[
  149. $userProfileNamespace = new Zend_Session_Namespace('userProfileNamespace');
  150. // marking session as read only locked
  151. $userProfileNamespace->lock();
  152. // unlocking read-only lock
  153. if ($userProfileNamespace->isLocked()) {
  154. $userProfileNamespace->unLock();
  155. }
  156. ]]></programlisting>
  157. </example>
  158. </sect2>
  159. <sect2 id="zend.session.advanced_usage.expiration">
  160. <title>Verfall von Namensräumen</title>
  161. <para>
  162. Limits können plaziert werden an der Lebensdauer von beidem, Namensräumen und
  163. individuellen Schlüsseln in Namensräumen. Normale Anwendungsfälle beinhalten das
  164. Durchlaufen von temporären Informationen zwischen Anfragen, und das vermindern der
  165. Aufdeckung von vielfältigen Sicherheitsrisiken durch das Entfernen des Zugangs zu
  166. potentiell sensitiven Informationen, manchmal nachdem Authentifizierung stettgefunden
  167. hat. Das Ende kann entweder auf abgelaufenen Sekunden oder der Anzahl von "Sprüngen"
  168. basieren, wobei ein Sprung für jede folgende Anfrage stattfindet.
  169. </para>
  170. <example id="zend.session.advanced_usage.expiration.example">
  171. <title>Beispiel für den Verfall</title>
  172. <programlisting language="php"><![CDATA[
  173. $s = new Zend_Session_Namespace('expireAll');
  174. $s->a = 'Apfel';
  175. $s->p = 'Pfirsich';
  176. $s->o = 'Orange';
  177. $s->setExpirationSeconds(5, 'a'); // Der Schlüssel "a" läuft in 5 Sekunden ab
  178. // Der komplette Namensraum läuft in 5 "Sprüngen"
  179. $s->setExpirationHops(5);
  180. $s->setExpirationSeconds(60);
  181. // Der "expireAll" Namensraum wird als "abgelaufen" markiert
  182. // sobald der erste Aufruf empfangen wurde und 60 Sekunden
  183. // vergangen sind, oder in 5 Sprüngen, was auch immer zuerst stattfindet
  184. ]]></programlisting>
  185. </example>
  186. <para>
  187. Wenn mit Daten einer Session gearbeitet wird, die in der aktuellen Anfrage ablaufen,
  188. sollte Vorsicht beim Empfangen dieser Daten gehalten werden. Auch wenn diese Daten durch
  189. Referenz zurückgegeben werden, wird die Änderung derselben, diese Daten nicht über diese
  190. Abfrage hinweg gültig machen. Um die Zeit für das Ablaufen "zurückzusetzen", müssen die
  191. Daten in eine temporäre Variable geholt werden, diese im Namensraum entfernt und
  192. anschliessend der entsprechende Schlüssel wieder gesetzt werden.
  193. </para>
  194. </sect2>
  195. <sect2 id="zend.session.advanced_usage.controllers">
  196. <title>Kapseln von Sessions und Controller</title>
  197. <para>
  198. Namensräume können auch verwendet werden um den Zugriff auf Sessions durch Controller
  199. zu seperieren um Variablen vor Kontaminierung zu schützen. Zum Beispiel könnte ein
  200. Authentifizierungs Controller seine Session Daten von allen anderen Controllern separat
  201. halten um notwendigen Sicherheiten zu entsprechen.
  202. </para>
  203. <example id="zend.session.advanced_usage.controllers.example">
  204. <title>Session Namensräume für Controller mit automatischem Verfall</title>
  205. <para>
  206. Der folgende Code ist Teil eines Controllers der die Test Frage anzeigt und eine
  207. boolsche Variable initialisiert die anzeigt ob eine geschickte Antwort zur Test
  208. Frage akzeptiert werden sollte oder nicht. In diesem Fall wird dem Benutzer der
  209. Anwendung 300 Sekunden Zeit gegeben die angezeigte Frage zu beantworten.
  210. </para>
  211. <programlisting language="php"><![CDATA[
  212. // ...
  213. // Im Frage-View Controller
  214. $testSpace = new Zend_Session_Namespace('testSpace');
  215. $testSpace->setExpirationSeconds(300, 'accept_answer');
  216. // Nur diese Variable ablaufen lassen
  217. $testSpace->accept_answer = true;
  218. //...
  219. ]]></programlisting>
  220. <para>
  221. Danach bestimmt der Controller der die Antworten für die Test Fragen bearbeitet ob
  222. eine Antwort akzeptiert wird oder nach basierend darauf ob der Benutzer die Antwort
  223. in der erlaubten Zeit übermittelt hat:
  224. </para>
  225. <programlisting language="php"><![CDATA[
  226. // ...
  227. // Im Frage-Prozess Controller
  228. $testSpace = new Zend_Session_Namespace('testSpace');
  229. if ($testSpace->accept_answer === true) {
  230. // innerhalb der Zeit
  231. }
  232. else {
  233. // nicht innerhalb der Zeit
  234. }
  235. // ...
  236. ]]></programlisting>
  237. </example>
  238. </sect2>
  239. <sect2 id="zend.session.advanced_usage.single_instance">
  240. <title>Mehrfache Instanzen pro Namensraum verhindern</title>
  241. <para>
  242. Obwohl <link linkend="zend.session.advanced_usage.locking">session locking</link> einen
  243. guten Grad von Schutz gegen unerlaubte Verwendung von Session Daten in einem Namensraum
  244. bietet, bietet <classname>Zend_Session_Namespace</classname> auch die Fähigkeit die
  245. Erzeugung von mehreren Instanzen zu verhindern die zu einem einzelnen Namensraum
  246. korrespondieren.
  247. </para>
  248. <para>
  249. Um dieses Verhalten einzuschalten, muß <constant>TRUE</constant> als zweites Argument im
  250. Konstruktor angegeben werden wenn die letzte erlaubt Instanz von
  251. <classname>Zend_Session_Namespace</classname> erzeugt wurde. Jeder weitere Versuch den
  252. selben Namensraum zu instanzieren wird in einer geworfenen Ausnahme resultieren.
  253. </para>
  254. <example id="zend.session.advanced_usage.single_instance.example">
  255. <title>Zugriff auf Session Namensräume auf eine einzelne Instanz limitieren</title>
  256. <programlisting language="php"><![CDATA[
  257. // Eine Instanz eines Namensraumes erstellen
  258. $authSpaceAccessor1 = new Zend_Session_Namespace('Zend_Auth');
  259. // Eine weitere Instanz des selben Namensraumes erstellen,
  260. // aber weitere Instanzen verbieten
  261. $authSpaceAccessor2 = new Zend_Session_Namespace('Zend_Auth', true);
  262. // Eine Referenz erstellen ist immer noch möglich
  263. $authSpaceAccessor3 = $authSpaceAccessor2;
  264. $authSpaceAccessor1->foo = 'bar';
  265. assert($authSpaceAccessor2->foo, 'bar');
  266. try {
  267. $aNamespaceObject = new Zend_Session_Namespace('Zend_Auth');
  268. } catch (Zend_Session_Exception $e) {
  269. echo 'Dieser Namensraum kann nicht instanziert werden da ' .
  270. '$authSpaceAccessor2 erstellt wurde\n';
  271. }
  272. ]]></programlisting>
  273. </example>
  274. <para>
  275. Der zweite Parameter oben im Konstruktor sagt
  276. <classname>Zend_Session_Namespace</classname> das alle zukünftigen Instanzen mit dem
  277. <classname>Zend_Auth</classname> Namensraum nicht erlaubt sind. Der Versuch solche
  278. Instanzen zu erstellen verursacht eine Ausnahme die vom Konstruktor geworfen wird. Der
  279. Entwickler wird darauf aufmerksam gemacht eine Referenz zu einer Instanz des Objektes
  280. irgendwo zu speichern (<varname>$authSpaceAccessor1</varname>,
  281. <varname>$authSpaceAccessor2</varname>, oder <varname>$authSpaceAccessor3</varname> im
  282. obigen Beispiel), wenn der Zugriff auf den Namensraum der Session zu einer späteren Zeit
  283. während des selben Requests benötigt wird. Zum Beispiel, könnte ein Entwickler die
  284. Referenz in einer statischen Variable speichern, die Referenz zu einer <ulink
  285. url="http://www.martinfowler.com/eaaCatalog/registry.html">Registry</ulink>
  286. hinzufügen (siehe <link linkend="zend.registry">Zend_Registry</link>), oder diese
  287. andernfalls für andere Methoden verfügbar zu machen die Zugriff auf den Namensraum der
  288. Session benötigen.
  289. </para>
  290. </sect2>
  291. <sect2 id="zend.session.advanced_usage.arrays">
  292. <title>Arbeiten mit Arrays</title>
  293. <para>
  294. Durch die Vergangenheit der Implmentationen der Magischen Methoden in
  295. <acronym>PHP</acronym>, wird das Ändern von Arrays innerhalb eines Namensraumes nicht
  296. unter <acronym>PHP</acronym> Versionen vor 5.2.1 funktionieren. Wenn nur mit
  297. <acronym>PHP</acronym> 5.2.1 oder neuer gearbeitet wird, kann <link
  298. linkend="zend.session.advanced_usage.objects">zum nächsten Kapitel gesprungen</link>
  299. werden.
  300. </para>
  301. <example id="zend.session.advanced_usage.arrays.example.modifying">
  302. <title>Array Daten innerhalb eines Session Namensraumes verändern</title>
  303. <para>
  304. Das folgende illustriert wie das Problem reproduziert werden kann:
  305. </para>
  306. <programlisting language="php"><![CDATA[
  307. $sessionNamespace = new Zend_Session_Namespace();
  308. $sessionNamespace->array = array();
  309. // wird nicht wie gewünscht funktionieren vor PHP 5.2.1
  310. $sessionNamespace->array['testKey'] = 1;
  311. echo $sessionNamespace->array['testKey'];
  312. ]]></programlisting>
  313. </example>
  314. <example id="zend.session.advanced_usage.arrays.example.building_prior">
  315. <title>Arrays erstellen bevor es Session Speicher gab</title>
  316. <para>
  317. Wenn möglich, sollte das Problem vermieden werden indem Array nur dann im Session
  318. Namensraum gespeichert werden nachdem alle gewünschten Arraywerte gesetzt wurden.
  319. </para>
  320. <programlisting language="php"><![CDATA[
  321. $sessionNamespace = new Zend_Session_Namespace('Foo');
  322. $sessionNamespace->array = array('a', 'b', 'c');
  323. ]]></programlisting>
  324. </example>
  325. <para>
  326. Wenn eine betroffene Version von <acronym>PHP</acronym> verwendet wird and ein Array
  327. modifiziert werden soll nachdem es mit einem Schlüssel für den Session Namensraum
  328. verbunden wurde, kann einer oder beide der folgenden Workarounds verwendet werden.
  329. </para>
  330. <example id="zend.session.advanced_usage.arrays.example.workaround.reassign">
  331. <title>Workaround: Ein geändertes Array neu Verbinden</title>
  332. <para>
  333. Im folgenden Code wird eine Kopie des gespeicherten Array erstellt, geändert und
  334. wieder dem Platz von dem die Kopie erstellt wurde zugeordnet wobei das originale
  335. Array überschrieben wird.
  336. </para>
  337. <programlisting language="php"><![CDATA[
  338. $sessionNamespace = new Zend_Session_Namespace();
  339. // Das ursprüngliche Array hinzufügen
  340. $sessionNamespace->array = array('tree' => 'apple');
  341. // Eine Kopie des Arrays erstellen
  342. $tmp = $sessionNamespace->array;
  343. // Die Kopie des Arrays ändern
  344. $tmp['fruit'] = 'peach';
  345. // Die Kopie des Arrays wieder mit dem Namensraum der Session verknüpfen
  346. $sessionNamespace->array = $tmp;
  347. echo $sessionNamespace->array['fruit']; // gibt "peach" aus
  348. ]]></programlisting>
  349. </example>
  350. <example id="zend.session.advanced_usage.arrays.example.workaround.reference">
  351. <title>Workaround: Array das Referenz enthält speichern</title>
  352. <para>
  353. Alternativ, kann ein Array gespeichert werden das eine Referenz zum gewünschten
  354. Array enthält, die auf dieses dann indirekt zugegriffen werden.
  355. </para>
  356. <programlisting language="php"><![CDATA[
  357. $myNamespace = new Zend_Session_Namespace('myNamespace');
  358. $a = array(1, 2, 3);
  359. $myNamespace->someArray = array( &$a );
  360. $a['foo'] = 'bar';
  361. echo $myNamespace->someArray['foo']; // gibt "bar" aus
  362. ]]></programlisting>
  363. </example>
  364. </sect2>
  365. <sect2 id="zend.session.advanced_usage.objects">
  366. <title>Sessions mit Objekten verwenden</title>
  367. <para>
  368. Wenn Objekte in einer <acronym>PHP</acronym> Session fixiert werden sollen, muß bedacht
  369. werden das diese für das Speichern <ulink
  370. url="http://www.php.net/manual/de/language.oop.serialization.php">serialisiert</ulink>
  371. werden. Deshalb muß jedes Objekt das in einer <acronym>PHP</acronym> Session verewigt
  372. wurde deserialisiert werden nachdem es vom Speicher empfangen wurde. Das impliziert das
  373. der Entwickler sicherstellen muß das die Klassen für das verewigte Objekt definiert
  374. werden müssen bevor das Objekt vom Session Speicher deserialisiert wird. Wenn die
  375. Klasse eines unserialisierten Objektes nicht definiert wurde, wird es eine Instand von
  376. <code>stdClass</code>.
  377. </para>
  378. </sect2>
  379. <sect2 id="zend.session.advanced_usage.testing">
  380. <title>Verwenden von Sessions mit Unit Tests</title>
  381. <para>
  382. Zend Framework vertraut auf PHPUnit um das Testen von sich selbst zu ermöglichen. Viele
  383. Entwickler erweitern die existierende Sammlung von Unit Tests um den Code in deren
  384. Anwendungen anzudecken. Die Ausnahme "<emphasis>Zend_Session ist aktuell als nur-lesbar
  385. markiert</emphasis>" wird geworfen während Unit Tests durchgeführt werden, wenn
  386. irgendeine schreibende Methode verwendet wird nachdem Ende der Session. Trotzdem
  387. benötigen Unit Tests die <classname>Zend_Session</classname> verwenden besondere
  388. Aufmerksamkeit weil das Schließen (<methodname>Zend_Session::writeClose()</methodname>)
  389. oder Zerstören einer Session (<methodname>Zend_Session::destroy()</methodname>) weitere
  390. Änderungen oder Rücknahmen von Schlüsseln in jeder Instanz von
  391. <classname>Zend_Session_Namespace</classname> verhindert. Dieses Verhalten ist ein
  392. direktes Resultat des darunterliegenden ext/session Mechanismus und
  393. <acronym>PHP</acronym>'s <methodname>session_destroy()</methodname> und
  394. <methodname>session_write_close()</methodname> welche keinen "rückgängig machen"
  395. Mechanismus unterstützen um Setup/Teardown innerhalb der Unit Tests zu unterstützen.
  396. </para>
  397. <para>
  398. Um das Umzuarbeiten, siehe den Unit Test
  399. <methodname>testSetExpirationSeconds()</methodname> in <code>SessionTest.php</code> und
  400. <code>SessionTestHelper.php</code>, beide im <code>tests/Zend/Session</code>
  401. Verzeichnis, welche <acronym>PHP</acronym>'s <methodname>exec()</methodname> verwenden
  402. um einen eigenständigen Prozess zu starten. Der neue Prozess simuliert eine zweite
  403. Anfrage eines Browsers, viel genauer. Der separate Prozess beginnt mit einer "reinen"
  404. Session, genauso wie jede <acronym>PHP</acronym> Skript Ausführung für eine Web Anfrage.
  405. Auch jede Änderung in <varname>$_SESSION</varname> welche im aufrufenden Prozess gemacht
  406. wurde, ist im Kind-Prozess verfügbar, ermöglicht wenn der Elternprozess die Session
  407. beendet hat, bevor <methodname>exec()</methodname> verwendet wird.
  408. </para>
  409. <example id="zend.session.advanced_usage.testing.example">
  410. <title>PHPUnit Test Code der auf Zend_Session beruht</title>
  411. <programlisting language="php"><![CDATA[
  412. // testen von setExpirationSeconds()
  413. $script = 'SessionTestHelper.php';
  414. $s = new Zend_Session_Namespace('space');
  415. $s->a = 'apple';
  416. $s->o = 'orange';
  417. $s->setExpirationSeconds(5);
  418. Zend_Session::regenerateId();
  419. $id = Zend_Session::getId();
  420. // Session freigeben damit der untere Prozess Sie verwenden kann
  421. session_write_close();
  422. sleep(4); // nicht lange genug damit die Dinge ablaufen
  423. exec($script . "expireAll $id expireAll", $result);
  424. $result = $this->sortResult($result);
  425. $expect = ';a === apfel;o === orange;p === pfirsich';
  426. $this->assertTrue($result === $expect,
  427. "Iterierung durch standard Zend_Session Namensraum fehlgeschlagen; " .
  428. "erwartet result === '$expect', aber '$result' bekommen");
  429. sleep(2); // lange genug damit die Dinge ablaufen (insgesamt 6 Sekunden
  430. // warten, aber nach 5 Sekunden abgelaufen)
  431. exec($script . "expireAll $id expireAll", $result);
  432. $result = array_pop($result);
  433. $this->assertTrue($result === '',
  434. "Iterierung durch standard Zend_Session Namensraum fehlgeschlagen; " .
  435. "erwartet result === '', aber '$result' bekommen)");
  436. session_start(); // wiederherstellen der vorher eingefrorenen Session
  437. // Das könnte in einen separaten Test abgeteilt werden, aber aktuell, wenn
  438. // irgendwas vom darüberleigenden Test den darunterliegenden Test
  439. // kontaminiert, ist das auch ein Fehler den wir wissen wollen.
  440. $s = new Zend_Session_Namespace('expireGuava');
  441. $s->setExpirationSeconds(5, 'g'); // Versuch nur einen Schlüssel im
  442. // Namensraum ablaufen zu lassen
  443. $s->g = 'guava';
  444. $s->p = 'peach';
  445. $s->p = 'plum';
  446. // Session auflösen damit der untere Prozess sie verwenden kann
  447. session_write_close();
  448. sleep(6); // Nicht lange genug damit die Dinge ablaufen können
  449. exec($script . "expireAll $id expireGuava", $result);
  450. $result = $this->sortResult($result);
  451. session_start(); // Die bestimmte Session wiederherstellen
  452. $this->assertTrue($result === ';p === plum',
  453. "Iterierung durch benannte Zend_Session Namensräume " .
  454. "fehlgeschlaten (result=$result)");
  455. ]]></programlisting>
  456. </example>
  457. </sect2>
  458. </sect1>