www.alexander-merz.com | Alexander Merz

Tomcat&PHP - Vordefinierte Variablen

Letzte Woche kündigte ich bereits an, dass Tomcat uns eine Reihe von Objekten bereitstellt, über die wir dessen Funktionen nutzen können. Dieses schauen wir uns heute an. Und werden unsere erste Webseite schreiben, die Tomcat-Fahigkeiten nutzt!

Wer bereits nur ein wenig mit JSP gearbeitet hat, wird wissen, dass innerhalb einer JSP-Seite verschiedene vordefinierte Objekte zur Verfügung stehen. Diese dienen dazu, die Funktionen und Fähigkeiten des Web(-Applikations-)Servers zu nutzen. Neben dem Zugriff auf die Daten des HTTP-Request und Methoden zur Steuerung der Ausgabe (Response), betrifft dies auch die Session-Funktionen und die Eigenschaften der jeweiligen Applikation des Contextes.

Gemäß JSR 223 müssen diese auch für Scriptsprachen bereitgestellt, also auch für unsere PHP-Seiten innerhalb des Tomcats. Allerdings entsprechen die Objekte nicht ganz den Originalen in JSP-Seiten. Das soll uns aber für diesen Artikel nicht weiter stören.

Führen wir eine PHP-Seite innerhalb von Tomcat, dann stehen uns vier vordefinierte Java-Objekte zur Verfügung: $request, $response, $context und $servlet. Es handelt sich um globale, aber keine superglobale Variablen. Man muss sich also explizit darum kümmern, dass sie auch in Funktionen und Methoden verfügbar sind.

JSP-Programmieren werden $request und $repsonse bekannt vorkommen, es sind 100% die gleichen HttpServletRequest- bzw. HttpServletResponse-Objekte wie in JSP. Die Variable $context ist eine Mischung des application- und des pageContext-Objektes in JSP. Das Objekt $servlet ist JSR 223-spezifisch, und nicht zu verwechseln mit dem Servlet-Interface.

Schauen wir uns im Folgenden die einzelnen Objekte näher an.

Das $request-Objekt

Das Request-Objekt kapselt die Daten des HTTP-Requests. Um z.B. die übergebenen Parameter des Request zu erfahren, rufen Sie einfach die getParameter()-Methode auf. Dazu benötigt man unter PHP natürlich kein explizites Objekt. Aber über dieses Objekt erhalten wir viele Daten über den Request, die uns sonst nicht zur Verfügung stehen.

Zum Beispiel habe ich im zweiten Teil geschrieben, dass verschiedene Server-Variablen unter Tomcat nicht zu Verfügung stehen, wie $_SERVER['QUERY_STRING']. Für diese fehlenden Variablen können häufig Methoden des Request-Objektes benutzt werden. Für Query-String ist das getQueryString().

Ausserdem erhalten Sie über das Request-Objekt ein Objekt zum Zugriff und zur Nutzung der aktuellen Session. Doch dazu weiter unten mehr.

Eine vollständige Übersicht über die Methoden des Objektes finden Sie in der J2EE-Dokumentation: http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/ServletRequest.html

Das $reponse-Objekt

Das Response-Objekt enthält Methoden zum Senden von Cookies, HTTP-Headern und zur Kodierung von URLs. Sieht man von den Kodier-Methoden ab, sollten die Methoden nicht benutzt werden, und stattdessen die PHP-Funktionen vorziehen. Den die PHP-Äquivalente wie header() unterstützen die Output-Buffering-Funktionen (ob_*), im Gegensatz zu den Request-Methoden. Folgendes funktioniert unter Tomcat nämlich nicht:

<?php
ob_start();
echo ...;
$request->setHeader(...);
...
?>

Auch hier ist die vollständige API-Übersicht in der J2EE-Dokumentation zu finden: http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/ServletResponse.html

Das $servlet-Objekt

Über das Servlet-Objekt erhalten wir die aktuelle Instanz des Context-Objektes, dass sich aber auch bereits im $context-Objekt befindet. Die Methode getEngine() liefert uns ein Engine-Objekt zurück, dass für die Ausführung unserer PHP-Seite innerhalb von Tomcat verantwortlich ist. Für die praktische Programmierung ist dieses Objekt aber wenig sinnvoll einsetzbar.

Das $context-Objekt

Das Context-Objekt ist das Interessanteste von allen. Es erlaubt die die Ablage von Daten innerhalb der verschiedenen Scopes und erlaubt die Aktivierung und Deaktivierung von Tomcat-Sessions innerhalb unserer Applikation. Darauf werden wir in unserem Beispiel weiter unten noch eingehen.

Das $context- und $servlet-Objekt bzw. die Java-Klassen sind dokumentiert in der JSR 223-Spezifikation (http://jcp.org/aboutJava/communityprocess/pr/jsr223/index.html).

Das Session-Objekt

Mit dem Session-Objekt können Sie Daten innerhalb einer Session speichern. Es steht nicht unmittelbar zur Verfügung, sondern muss erst vom $request-Objekt geholt werden. Um den Inhalt einer Variable in der Session zu hinterlegen, rufen Sie setAttribute() des Session-Objektes auf. Die Methode erwartet als ersten Wert den Namen des Attributes (quasi der "Variablenname") und als zweites den zu speichernden Wert. Um den Wert eines Attributes zu holen, rufen Sie getAttrribute() mit dem Attributnamen auf. Das ganze kann z.B. so aussehen:

<?php
$session = $request->getSession();

// Wert schon in der Session hinterlegt?
if($session->getAttribute('myAttribute')) {
  // Ja, dann gib ihn aus.
  echo $session->getAttribute('myAttribute');
} else {
  // Nein, dann setzte ihn
  $session->setAttribute('myAttribute', ‚Testwert');
}
?>

Es gibt allerdings einige Einschränkungen. Erstens können Sie nur skalare Werte wie Strings und Zahlen, und Arrays, sowie Java-Objekte speichern. Nicht gespeichert werden können leider Ressourcen, wie Datenbankverbindungen, oder Objekte von PHP-Klassen.

Der Session-Identifier kann auch bei Tomcat per URL oder Cookie weitergegeben werden. Soll die Übergabe per Cookies vermieden werden, muss dies in der server.xml entsprechend konfiguriert werden.

Um den Session-Identifier an eine URL zu hängen, benutzen Sie die Methode encodeUrl() bzw. encodeRedirectUrl() des $reponse-Objektes:

$url = $response->encodeUrl("test.php");
Die Methoden verändern die URL aber nur dann, wenn die Übergabe per Cookie nicht erlaubt wurde, sei es dass dies der Benutzer abgelehnt hat oder aufgrund der Tomcat-Konfiguration.

Haben Sie bei PHP den automatischen Session-Support und use_trans_sid aktiviert, dann führt der Aufruf obiger Zeile tatsächlich zu einer URL, die beide Session-Identifier enthält, die von PHP und Tomcat: http://localhost:8800/test.php;jsessionid=730EF30CE69B909D90F15BB390DA00
FA?PHPSESSID=786649d508e5a5eb57bc5e2ca1e127d9

Das Session-Objekt ist dokumentiert auf http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/http/HttpSession.html

Das Beispiel

Im folgenden Beispiel demonstriere ich die Verwendung des Application-Scopes. Die Anwendung unterscheidet sich nicht wesentlich von der Session-Benutzung. Auch hier gelten die Einschränkungen, dass keine Ressourcen oder PHP-Klassen abgelegt werden können.

Nichtsdestotrotz bleibt immer noch ein weites Betätigungsfeld. In unserem Beispiel werden wir eine Template-Datei laden und im Application-Scope hinterlegen. Bei den folgenden Seitenaufrufen wird dass Template nur noch aus dem Application-Scope geholt. Bei einer einzigen kleinen Datei scheint der Zeitgewinn nicht nennenswert. Aber bei komplexen Seiten mit vielen Template-Schnipseln, und wenn z.B. Datenbank-Inhalte im Application-Scope gecacht werden, wird der Gewinn signifikant.

Das Template:

<html>
 <head>
  <title>Application-Scope-Test</title>
 </head>
 <body>
  <h1>Überschrift</h1>
  <p>
    {USESCOPE}
  </p>
  <a href="test.php">Neu laden</a>
 </body>
</html>

Das PHP-Skript

Wir laden als Vorspiel das HTML_Template_IT-Package für die Template-Verarbeitung.

<?php
require_once 'HTML/Template/IT.php';
$tit = new HTML_Template_IT();

Als nächstes kommt die Logik für den Application-Scope. In einer if-Anweisung prüfen wir, ob bereits ein entsprechendes Attribut im Application-Scope existiert, wenn ja, dann holen wir das Template und setzten eine Zeichenkette zur Erfolgskontrolle. Die Zeichenkette wird nachher im Template ausgegeben.

if($context->getAttribute("tomcat_template", 
     $context->APPLICATION_SCOPE)) {
    $tpl = $context->getAttribute("tomcat_template", 
     $context->APPLICATION_SCOPE);
    $usescope = "APPLICATION_SCOPE wird benutzt";
}

Wie Sie sehen greifen Sie auf Attribute im Application-Scope über das $context-Objekt zu, und sie müssen eine Konstante angeben, welcher Scope benutzt werden soll.

Existiert das Attribute noch nicht, dann laden wir das Template aus der Datei und speichern es im Application-Scope, und wir setzen die Zeichenkette auf einen anderen Wert.

else {
    $tpl = file_get_contents('\www\tomcat\test.tpl');
    $context->setAttribute("tomcat_template", $tpl, 
     $context->APPLICATION_SCOPE);
    $usescope = "APPLICATION_SCOPE wird nicht benutzt";
}
Beachten Sie den absoluten Pfad bei file_get_contents(). Er ist unbedingt notwendig, wie im zweiten Artikel bereits angeführt.

Der Rest des Skriptes besteht nur noch aus der Ausführung der Template-Klasse:

$tit->setTemplate($tpl);
$tit->setVariable("USESCOPE", $usescope);
$tit->parseCurrentBlock();
echo $tit->show();
?>

Jetzt können Sie das Skript testen, in dem Sie es mehrmals aufrufen. Nur beim ersten Aufruf wird die Zeile "APPLICATION_SCOPE wird nicht benutzt" ausgegeben. Bei allen weiteren die Zeile "APPLICATION_SCOPE wird benutzt". Sie können an der URL im Skript erkennen, dass wir keine Session benutzen. Wenn Sie denken, da spielen irgendwelche geheimen Cookies eine Rolle, dann probieren Sie auch einen zweiten Browser aus.

Das war es für heute erst mal. Nächste Woche werden wir JSP-Tags in PHP-Skripten nutzen!

1. Teil: Tomcat&PHP - Installation
2. Teil:Tomcat&PHP - Wie funktioniert es?
4. Teil: Tomcat&PHP - JSP-Tags in PHP
5. Teil: Tomcat&PHP - Performance