Zend_Session-AdvancedUsage.xml 25 KB

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