Websiteentwicklung: PHP: Konfiguration

Grundlegendes

Bearbeiten

Nehmen Sie sich die Zeit, PHP sorgfältig zu konfigurieren! Da PHP eine sehr mächtige Skriptsprache ist, die sehr viele Dinge kann, kann sie – (z. B.) falsch konfiguriert – auch sehr viel kaputtmachen. Das soll Sie nur warnen und nicht gleich verschrecken. ;)

Die Konfiguration von PHP wird über Direktiven gesteuert. Diese lassen sich in drei Gruppen einteilen, die durch die Konstanten PHP_INI_ALL, PHP_INI_PERDIR und PHP_INI_SYSTEM des Quellcodes bestimmt werden.

Erläuterung der Konstanten
PHP_INI_ALL
Ist eine PHP-Direktive mit dieser Konstante implementiert worden, kann sie in Skripten (z. B. durch ini_set()), in der php.ini und den Konfigurationsdateien httpd.conf und .htaccess geändert werden.
PHP_INI_PERDIR
Ist eine PHP-Direktive mit dieser Konstante implementiert worden, kann sie nicht in Skripten geändert werden, sondern nur in der php.ini und den Konfigurationsdateien httpd.conf und .htaccess.
PHP_INI_SYSTEM
Ist eine PHP-Direktive mit dieser Konstante implementiert worden, kann sie ausschließlich in der php.ini und der httpd.conf geändert werden.

Die Konfigurationsdatei php.ini

Bearbeiten

Die php.ini ist die zentrale Konfigurationsdatei durch die alle Verhaltensregeln von PHP festgelegt werden. Innerhalb des Quellcodes werden zwei verschiedene Konfigurationsdateien mitgeliefert. Das ist zum einen die php.ini-dist und zum anderen die php.ini-recommended. Sie sind gut kommentiert – allerdings nur für jemanden der sich bereits auskennt. Daher sollten sie dieses Kapitel gründlich lesen, damit auch Sie sich auskennen werden.

Manche Einstellung, die Sie in der php.ini vornehmen können, kann Ihnen Arbeit beim Programmieren abnehmen. Sie sollten sich also immer vergewissern, ob es für ein Problem, welches Sie beim Programmieren feststellen und lösen wollen, nur eines einfachen Handgriffs in der Konfiguration bedarf. Sie sollten aber auch bedenken, dass gesetzte Direktiven innerhalb der php.ini systemweite Wirkung entfalten (können). Daher ist es ratsam, hier in Abwägung des mehrheitlichen Nutzen aller Skripte zu konfigurieren.

Kontrollieren Sie Ihre Konfiguration mit der Funktion phpinfo() (oder mit dem Parameter -i, wenn Sie mit dem CLI an der Kommandozeile arbeiten). phpinfo() gibt Ihnen alle erheblichen System-, Server-, Umgebungsvariablen- und Konfigurationangaben aus:

<?php
phpinfo(4); # Hauptdirektiven
phpinfo(8); # Direktiven und Angaben eingebundener Erweiterungen
?>

Hinweis: Das PHP-Komandozeilenprogramm (CLI) parst nur Dateien mit Namen php-cli.ini.


Die Syntax der php.ini gestaltet sich erfreulich übersichtlich:

Direktiven
Direktiven bestehen aus dem Paar Name und Wert, die durch ein Gleichheitszeichen "=" voneinander getrennt werden.
asp_tags=Off
Lesen Sie mehr zu den einzelnen Direktiven unter Alphabetische Liste der Direktiven.
Kommentare
Ein Kommentar beginnt mit ein Semikolon ";". Er endet mit dem Zeilenende. Zeilenübergreifende Kommentare gibt es in PHP nicht.
Direktive=Wert ; Kommentar
Sektionen
Sektionen werden durch einen Text umschlossen von einem Paar Eckiger Klammern ("[" und "]") festgelegt. Sie entfalten für die Steuerung von PHP keinerlei Wirkung und sind nur für die Ausgabe der Funktion parse_ini_file() von Bedeutung.
[Sektion_1]
Variablen
Alle Direktiven können als Variable innerhalb der php.ini eingesetzt werden. Ein Variable setzt sich aus dem Dollarzeichen "$" gefolgt vom in einem Paar Geschweifter Klammern ("{" und "}") notierten Direktivennamen, dessen Inhalt verwendet werden soll. Diese Möglichkeit steht Ihnen erst seit der Version 5.1 zur Verfügung.
open_basedir=${include_path}":/ein/anderer/pfad"

Wohin muss die php.ini

Bearbeiten

Hinweis: Wurde PHP als Apache-Modul (Version 1.3.x) unter der configure-Option des Apachen --activate-module installiert, werden keinerlei Einstellungen der php.ini beachtet. Sie können PHP in diesem Fall nur über die Konfigurationsdateien des Apachen abstimmen. Lesen sie dazu mehr im nächsten Abschnitt Konfiguration unter Apache.



Die Verzeichnisse, unter denen PHP vor der Ausführung von Skripten nach Konfigurationen sucht, werden dem configure-Skript mit den Optionen --with-config-file-path und --with-config-file-scan-dir mitgeteilt und sind nach dem Kompilieren nicht mehr veränderbar. Wenn Sie also wissen wollen, wo Sie Ihre php.ini ablegen müssen, führen Sie folgendes Skript aus und suchen Sie die entsprechenden Optionen in den Spalte für Configure Command und Configuration File:

<?php phpinfo(1); ?>

Eine mögliche Ausgabe könnte so aussehen:

PHP Version 5.1.3
System Linux eddi.to-grip.de 2.6.16.9 #1 Tue Apr 19 12:00:01 CEST 2006 x86_64
Build Date Jan 19 2006 04:16:00
Configure Command './configure' '--disable-all' '--disable-short-tags' '--enable-memory-limit' '--enable-sysvsem' '--enable-sysvshm' '--with-apxs2=/usr/local/apache/bin/apxs' '--with-bz2' '--with-config-file-path=/etc' '--with-openssl' '--with-zend-vm=GOTO' '--with-zlib'
Server API Apache 2.0 Handler
Virtual Directory Support enabled
Configuration File (php.ini) Path /etc/php.ini
PHP API 20041225
PHP Extension 20050922
Zend Extension 220051025
Debug Build no
Thread Safety enabled
Zend Memory Manager enabled
IPv6 Support enabled
Registered PHP Streams php, file, http, ftp, compress.bzip2, compress.zlib, https, ftps
Registered Stream Socket Transports tcp, udp, unix, udg, ssl, sslv3, sslv2, tls
Registered Stream Filters string.rot13, string.toupper, string.tolower, string.strip_tags, convert.*, consumed, bzip2.*, zlib.*
This program makes use of the Zend Scripting Language Engine:
Zend Engine v2.1.0, Copyright (c) 1998-2006 Zend Technologies

Hinweis: Die Konfiguration der Direktive expose_php lässt sich ausschließlich in der php.ini vornehmen.


Konfiguration unter Apache

Bearbeiten

Um PHP durch die Serverkonfigurationsdateien (httpd.conf/.htaccess) steuern zu können, muss PHP als Servermodul installiert sein. Wenn Sie sich nicht sicher sind, mit welchem SAPI Sie es zu tun haben, führen Sie folgendes Skript aus:

<?php echo php_sapi_name(); ?>

Mögliche Ausgaben dieses Skripts sind dabei cgi, cgi-fcgi, apache2handler, apache2filter oder apache. Folgende Beschreibung gilt also nur für die letzten drei SAPIs. Für die Konfiguration der CGI-Binäre lesen Sie bitte Apache: PHP als CGI.

PHP als Webservermodul

Bearbeiten

Als Apache-Modul setzt PHP einige Konfigurationsdirektiven, die Ihnen im folgenden erklärt werden:

php_value name value
Setzt den angegebenen Wert value für die mit name angegebene PHP-Direktive. Diese Direktive kann in allen Konfigurationsdateien (httpd.conf/.htaccess) des Apachen für die Steuerung von PHP-Direktiven verwendet werden, den Wertetyp string oder integer haben, und deren Änderbarkeit auf PHP_INI_ALL | PHP_INI_PERDIR gesetzt ist.
php_flag name on/off
Setzt den angegebenen Wert value für die mit name angegebene PHP-Direktive. Diese Direktive kann in allen Konfigurationsdateien (httpd.conf/.htaccess) des Apachen für die Steuerung von PHP-Direktiven verwendet werden, den Wertetyp boolean haben, und deren Änderbarkeit auf PHP_INI_ALL | PHP_INI_PERDIR gesetzt ist.
php_admin_value name value
Setzt den angegebenen Wert value für die mit name angegebene PHP-Direktive, sodass dieser sich nicht mehr mit Angaben in .htaccess-Dateien überschreiben lässt. Diese Direktive kann in der zentralen Konfiguration (httpd.conf) des Apachen für die Steuerung von PHP-Direktiven verwendet werden, den Wertetyp string oder integer haben, und deren Änderbarkeit auf PHP_INI_ALL | PHP_INI_PERDIR | PHP_INI_SYSTEM gesetzt ist.
php_admin_flag name name on/off
Setzt den angegebenen Wert value für die mit name angegebene PHP-Direktive, sodass dieser sich nicht mehr mit Angaben in .htaccess-Dateien überschreiben lässt. Diese Direktive kann in der zentralen Konfiguration (httpd.conf) des Apachen für die Steuerung von PHP-Direktiven verwendet werden, den Wertetyp boolean haben, und deren Änderbarkeit auf PHP_INI_ALL | PHP_INI_PERDIR | PHP_INI_SYSTEM gesetzt ist.

Ein Beispiel für die Konfiguration eines Virtual-Hosts:

<VirtualHost 127.0.0.1:80>
        ServerName      localhost
        ServerAlias     mein.server
        DocumentRoot    /var/www/default

        <Directory /var/www/default>
                AllowOverride   All
                php_value       include_path        ".:/var/www/inc:/var/www/default/inc"
                php_admin_value memory_limit         2M
                php_admin_value open_basedir         /var/www/default
                php_admin_value post_max_size        100K
                php_admin_flag  safe_mode            On
                php_admin_value upload_max_filesize  0
                php_admin_value upload_tmp_dir       /var/www/uploads
        </Directory>
        <Directory /var/www/default/html>
                php_admin_flag  file_uploads         Off
        </Directory>
        <Directory /var/www/default/upload>
                php_admin_value doc_root             /var/www/default/upload
                php_admin_flag  file_uploads         On
                php_admin_value include_path        "."
                php_admin_value post_max_size        14M
                php_admin_value upload_max_filesize  12M
        </Directory>

        # Andere Angaben
</VirtualHost>

PHP als CGI

Bearbeiten

Die CGI-Binäre von PHP werden über die php.ini konfiguriert, daher werden Ihnen in diesem Abschnitt nur Tricks vorgestellt, wie Sie spezielle Konfigurationen umsetzen können.

Bis vor einigen Jahren suchte PHP im jeweiligen Skript-Verzeichnis nach einer Konfigurationsdatei. Leider ist diese überaus praktische Funktionalität in neueren Versionen aus Sicherheitsgründen nicht mehr umgesetzt worden. Dafür kann PHP auf Kommandozeilenebene mit einem Parameter -c aufgerufen werden, der als Argument den Pfad zu einer php.ini bzw. zu einem Verzeichnis erwartet.

Also erstellen Sie sich ein kleines Shell-Skript, dass PHP mit einer Konfigurationsdateiangabe aufrufen kann:

#!/bin/sh
if [ -e /pfad/zu/php ]
	then
	scandir=`/bin/dirname ${PATH_TRANSLATED}`;
	default='/pfad/zur/default_ini/php.ini';
	cgiprog='/pfad/zu/php -c'

	if [ -e "$scandir/php.ini" ]
		then	$cgiprog $scandir;
		else	$cgiprog $default;
	fi

	else	exit 1;
fi
exit $?;

Dieses Shell-Skript wird im Verzeichnis des PHP-Skriptes nach der Datei php.ini suchen. Ist keine php.ini in diesem Verzeichnis, wird PHP mit einer Default-Konfigurationsdatei (/pfad/zur/default_ini/php.ini) gestartet. Passen Sie die Pfandangaben an Ihre Gegebenheiten an und legen Sie dieses Shell-Skript in das Verzeichnis des CGI-Binärs ab. Ich habe das Skript startphp.sh genannt.

Als nächstes muss die Konfiguration des Apachen geändert werden, damit PHP nicht mehr direkt aufgerufen wird, sondern das Shell-Skript dieses erledigt:

ScriptAlias /wikiphp/                      /pfad/zum/php/verzeichnis/
Action      application/x-httpd-php        /wikiphp/startphp.sh
Action      application/x-httpd-php-source /wikiphp/startphp.sh

Nach einem Restart des Webservers wird PHP sodann mit der verzeichnisweiten (oder eben mit der default) Konfigurationen gestartet. Insbesondere für Anwendungsentwickler erweist sich diese Vorgehensweise als nützlich. Sie können so an einem lokalen Testserver die jeweiligen Konfigurationen (und auch den entsprechenden PHP-Versionen) verschiedener Produktivumgebungen simulieren.

Wenn Sie selbst Webdienste anbieten, ist dieses Skript natürlich nicht für den Einsatz geeignet, da Sie sonst keine Funktionen sperren und andere wirksame Sicherheitsmaßnahmen mehr treffen können. Aber mit einem leicht modifizierten Skript wird es Ihnen möglich, jedem Web eine individuelle Konfiguration zu verpassen.

Wie bereits im ersten Skript nutzen Sie dazu eine Umgebungsvariable. Da jedes Web die serverweit eindeutige Variable SERVER_NAME hat, können Sie diese zur Identifikation nutzen. Für alle Webprojekte, denen Sie also eine individuelle Konfiguration zukommen lassen wollen, erstellen Sie in einem Verzeichnis eine eigene Konfigurationsdatei; für alle anderen Webprojekte wird PHP mit default-Konfigurationen gestartet:

#!/bin/sh
if [ -e /pfad/zu/php ]
	then
	scanini="/pfad/zur/kunden/${SERVER_NAME}.ini";
	default='/pfad/zur/default_ini/php.ini';
	cgiprog='/pfad/zu/php -c'

	if [ -e $scanini ]
		then	$cgiprog $scanini;
		else	$cgiprog $default;
	fi

	else	exit 1;
fi
exit $?;

Die Konfigurationsdatei für den Virtualhost localhost heißt also localhost.ini.

Konfiguration innerhalb von Skripten

Bearbeiten

Die Möglichkeit, PHP innerhalb von Skripten zu konfigurieren, gehört zu den häufig genutzten. Sie können Ihre Skripte dadurch portabel machen, ohne Einstellungen in Konfigurationsdateien, wie der php.ini, vornehmen zu müssen. Jedoch lassen sich nicht alle Direktiven manipulieren. Unter Konfiguration Grundlegendens wurde Ihnen kurz dargelegt, welche drei Kategorien von Direktiven es gibt. Innerhalb von Skripten können Sie nur Direktiven ändern, deren Änderbarkeit durch die Konstante PHP_INI_ALL repräsentiert wird.

Die beiden folgenden Skripte sind im Resultat analog zueinander:

<?php
header('Content-Type: application/xhtml+xml; charset=iso-8859-15',true);
?>
<?php
ini_set('default_mimetype','application/xhtml+xml');
ini_set('default_charset', 'iso-8859-15');
?>

Es wird in beiden Fällen ein HTTP-Header Content-Type gesendet. Auch wenn dies ein schlechtes Beispiel ist, weil diese Konfiguration verzeichnisweit für einen Webauftritt in Konfigurationsdateien gesetzt werden sollte, zeigt Ihnen das zweite Skript die Funktion ini_set(). ini_set() ist die wichtigste Funktion, um innerhalb von Skripten Konfigurationen zu manipulieren.

Beachten Sie im Umgang mit ini_set(), das es unterschiedliche Typen von Direktiven gibt. Die Typen sind boolean, integer und string und verhalten sich wie die gleichnamigen Variablentypen:

<?php
ini_set('display_errors',     false);   # boolean
ini_set('log_errors_max_len', 128);     # integer
ini_set('error_log',         'syslog'); # string
?>

Darüber hinaus gibt es noch eine Vielzahl von Funktionen, die eine ganz bestimmte Direktive manipulieren. Wenn Sie diese kennenlernen wollen, sehen Sie sich dazu die Kommentare in der Alphabetische Liste der Direktiven an.

Themenweite Konfiguration

Bearbeiten

in Bearbeitung!

Der abgesicherte Modus

Bearbeiten

in Bearbeitung!

Dateien hochladen

Bearbeiten

in Bearbeitung!

Datenkompression für Webserver

Bearbeiten

Das Hypertexttransfer Protokoll (HTTP 1.1 RFC 2616) bietet die Möglichkeit Daten auch komprimiert auszuliefern. Ein Client (z. B. Ihr Browser) sendet dazu an einen Server im Anfrageheader Informationen, dass er auch komprimierte Daten akzeptiert und welche Kompressionsverfahren er unterstützt. Gerade zur Sicherung der Bandbreite eines Webservers ist die komprimierte Auslieferung wichtig. PHP sollte daher für Webserver immer mit dem zlib-Modul kompiliert werden. Ist PHP mit diesem Modul übersetzt worden, sollten sie dieses Modul auch nutzen!

Konfiguration in der php.ini:

zlib.output_compression      =1
zlib.output_compression_level=9

oder Konfiguration am Anfang eines jeden Skripts:

ini_set('zlib.output_compression',1);
ini_set('zlib.output_compression_level',9);

PHP wird dadurch veranlaßt, einen internen Ausgabepuffer einzusetzen (die Skriptausgaben aber auch Daten außerhalb der Skriptblöcke werden zwischengespeichert) und nach Beendigung der Skriptausführung die Ausgabe gegebenenfalls zu komprimieren.

PHP auf dem Webserver verschleiern

Bearbeiten

Es kann viel Gründe dafür geben, die Existenz von PHP auf einem Webserver zu verschleiern. Wenn Sie schon einmal nach einer Fertiglösung in Suchmaschinen suchten, die Sie in PHP haben wollten, werden Sie bereits einen guten Grund kennen. Manche Suchmaschinen neigen dazu auch die URL für Ihr Suchmuster als Treffer heranzuziehen und es wird Ihnen ein Haufen belangloser Verweise angeboten, nur weil diese auf .php enden.

Seit 2005 hatten sich auch einige sogenannte "Linux-Würmer" darauf spezialisiert, Suchmaschinen gezielt nach schlecht geschriebenen Skripten zu durchsuchen, um sich zu vermehren. Daher kann das Verschleiern auch ein wenig mehr Sicherheit bringen.

Für einen Besucher einer Internetpräsenz ist natürlich die Dateiendung .php ein deutliches Zeichen auf die eingesetzte Technik. Aber genaugenommen braucht kein Mensch die Dateiendungen, um durch Inhalte zu browsen. Daher ist eine URL der Form www.domain.de/verzeichnis/datei genauso aussagekräftig, wie www.domain.de/verzeichnis/datei.php. Nehmen Sie dazu in Ihre Apache-Konfiguration folgendes auf:

Options +MultiViews

Dies wird mod_negotiation für die Abarbeitung eines Requests auf den Plan rufen. Sollte dieses Modul nicht in den Webserver einkompiliert oder geladen worden sein, können Sie nur die Dateiendungen abändern:

application/x-httpd-php xhtm xhtml

Natürlich können Sie auch mod_rewrite nutzen oder sich des unter Pseudo-URLs durch PATH_INFO gezeigten Tricks bedienen.

Sollten Sie aus sicherheitstaktischen Gründen PHP verschleiern wollen, so seien Sie hiermit gewarnt. Es reicht nicht aus, nur die Dateiendungen zu verbergen. Die Anwesenheit von PHP schlägt sich auch in HTTP-Headern nieder. So erzeugt die erste Beispielkonfiguration folgende Header:

HTTP/1.1 200 OK
Date: Sun, 14 May 2006 06:36:26 GMT
Server: Apache/1.3.35 (Unix) PHP/5.1.4
Content-Location: test.php
TCN: choice
Vary: negotiate,accept
Connection: close
X-Powered-By: PHP/5.1.4
Transfer-Encoding: chunked
Content-Type: text/plain;charset=iso-8859-1

Die Header Content-Location, TCN und Vary rühren dabei vom mod_negotiation. X-Powered-By und der Anhang im Server-Header kommen aber von PHP selbst. Diese können durch die Direktive expose_php in der php.ini deaktiviert werden.

Pseudo-URLs durch PATH_INFO

Bearbeiten

Die hier vermittelten Informationen fordern von Ihnen schon gefestigte Kenntnisse im Umgang mit PHP. Wenn Sie mit PHP beginnen wollen und dieses Wikibook in chronologischer Reihenfolge lesen, wird Sie dieser Abschnitt überfordern. Sie werden noch an einigen Stellen dieses Wikibooks auf Informationen stoßen, die Sie nicht auf Anhieb verstehen werden. Lassen Sie sich davon nicht beirren, sondern kehren Sie mit dem später erworbenen Wissen an diese Stellen wieder zurück!

Dieser Abschnitt könnte auch die Überschrift Machen Sie mod_rewrite arbeitslos haben. mod_rewrite ist ein beliebtes Apache-Modul, das Anfragen an Ressourcen umformulieren kann. Dadurch ist es möglich Pseudolinks in einem Webprojekt einzubetten, die es reell gar nicht gibt. Nur wer braucht schon dieses Modul, wenn er bereits PHP hat? ;)

Legen Sie also eine .htaccess in das oberste Web-Verzeichnis mit folgendem Inhalt:

<Files meinwiki>
       ForceType       application/x-httpd-php
       AcceptPathInfo  On
</Files>

Diese Konfiguration wird den Apache veranlassen die Datei meinwiki wie ein PHP-Skript zu behandeln. Erstellen Sie nun das Skript meinwiki:

<?php

$a = array(
  'application/xhtml+xml' => array('xhtm', 'xhtml'),
  'application/xml' => array('xml'),
  'text/plain' => array('txt', 'asc'),
  'text/html' => array('htm', 'html', 'php', 'phtml'),
);

$pfad = '.'. str_replace('../', '', $_SERVER['PATH_INFO']);

if ($pfad == '.' || (is_dir($pfad) && substr($pfad, -1) != '/')) {
  $protokol = 'http'. (isset($_SERVER['HTTPS']) ? 's' : '') .'://';
  $host = $_SERVER['HTTP_HOST'];
  $pfad = str_replace('../', '', $_SERVER['REQUEST_URI']) .'/';
  header('Location: '. $protokol . $host . $pfad, TRUE, 301);
  exit;
}
elseif (is_dir($pfad)) {
  foreach ($a as $k => $v) {
    for ($i = 0; $i < count($v); $i++) {
      if (file_exists($pfad .'index.'. $v[$i])) {
        header('Content-Type: '. $k);
        if ($v[$i]{0} == 'p') {
          require($pfad .'index.'. $v[$i]);
        }
        else {
          readfile($pfad .'index.'. $v[$i]);
        }
        exit;
      }
    }
  }
}
elseif (file_exists($pfad) && substr($pfad, -1) != '/') {
  $x = pathinfo($pfad);

  foreach ($a as $k => $v) {
    if (in_array($x['extension'], $v)) {
      header('Content-Type: '. $k);
      if ($x['extension']{0} == 'p') {
        require($pfad);
      }
      else {
        readfile($pfad);
      }
      exit;
    }
  }
}

$cgi = (substr(php_sapi_name(), 0, 3) == 'cgi') ? TRUE : FALSE;

header(($cgi ? 'Status: 404' : 'HTTP/1.1 404 Not Found'), TRUE, 404);

echo '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">';
echo '<html>';
echo '<head>';
  echo '<title>404 Not Found</title>';
echo '</head>';
echo '<body>';
  echo '<h1>Not Found</h1>';
  echo '<p>The requested URI '. $_SERVER['REQUEST_URI'] .'was not found on this server.</p>';
echo '</body>';
echo '</html>';

?>

Sie können aber auch die Pfadangaben, wie mod_rewrite es tun würde, in Variablen zerlegen:

$pfad = str_replace('../', '', $_SERVER['PATH_INFO']);

list($_GET['param'], $_GET['datei'], $_GET['vname']) = explode('/', $pfad);

Dieses entspricht folgender Rewrite-Regel:

RewriteEngine On
RewriteRule   ^meinwiki/(.*)/(.*)/(.*) scriptname.php?param=$1&datei=$2&vname=$3

Somit kommen auch Nutzer des IIS in den Genuß einer Rewriteengine.