Kein Programm ist 100% sicher, aber wir wollen es potenziellen Angreifern auch nicht zu leicht machen, daher folgen ein paar Grundlegende Regeln zur Sicherheit von PHP. Ich gehe hier davon aus, dass die installierte PHP-Version auf dem aktuellen Stand ist und somit weniger Angriffsfläche bietet. -> PHP-Sicherheit erhöhen – Teil 1
Falls diese Option aktiv ist, ist das Überschreiben lokaler Variablen via GET / POST möglich z.B.:
test.php: ———
<?php if (!isset($test)) { $test = 1; } echo 'Der Wert von test ist: '.$test; ?>
Browser: ——– …/test.php?test=2
Ab PHP 4.2 ist diese Option (php.ini -> register_globals = Off) jedoch bereits standardmäßig auf “Off” gesetzt.
2.) “Type Casting” verwenden
Casting bedeutet so viel wie Umwandeln einer Variable in einen bestimmten Type z.B. wird aus “123z” -> “123” wenn wir dies zu einer Ganzzahl (int) casten. z.B.
Allgemein kann man prüfen, ob die Variablen überhaupt vorhanden/gesetzt sind.
test.php: ———
<?php if (empty($_GET['zahl']) { [...] if (!isset(($_GET['zahl']) { [...] if (!$_GET['zahl']) { [...] // Warnung ("Notice") falls "error_reporting(E_ALL)" und die Variable nicht definiert wurde
Es gibt noch weitere php-Module z.B. “ctype” mit denen sich Variablen überprüfen lassen, ich will jedoch als nächstes einen allgemein gültigen Ansatz via “regulären Ausdrücken” zeigen.
6.) Variablen prüfen / zuschneiden via “regulären Ausdrücke”
Reguläre Ausdrücke sind Muster, mit denen Zeichenketten beschrieben werden könnten!
Wer die Syntax noch nicht im Kopf hat sollte sich einmal “The Regex Coach” anschauen -> http://weitz.de/regex-coach/
Zusammenfassung: —————-
[abc] -> a oder b oder c [^abc] -> nicht a oder b oder c [a-z] -> von a bis z -> alle Kleinbuchstaben [A-Z] -> von A bis Z -> alle Großbuchstaben [a-zA-Z] -> Buchstaben
[0-9] -> von 0 bis 9 -> Ziffern \d -> von 0 bis 9 -> Ziffern \D -> keine Ziffer
[\r\n\t\f]] -> Wagenrücklauf, New Line, Tabulatur, Seitenwechsel -> Leerzeichen \s -> Leerzeichen \S -> keine Leerzeichen
\b -> Wortanfang bzw. Wortende z.B. “/\bWort\b/” \B -> kein Wortanfang bzw. Wortende z.B. “/\BWort\B/”
. -> ein beliebiges Zeichen (Punkt)
x{m} -> “x” muss genau “m”-Mal vorkommen x{m,} -> “x” muss min. “m”-Mal vorkommen (Ende offen) x{,n} -> “x” darf max. “n”-Mal vorkommen (Anfang offen) x{m,n} -> “x” muss zwischen “m”- und “n”-Mal vorkommen x? -> “x” kann, muss aber nicht an dieser Stelle vorkommen => x{0,1} x* -> “x” kann kein, ein oder mehrmals an dieser Stelle vorkommen => x{0,} x+ -> “x” kann ein oder mehrmals an dieser Stelle vorkommen => x{1,}
^ -> markiert den Beginn einer Zeichenkette $ -> markiert das Ende einer Zeichenkette
| -> Alternative z.B. “/ae|a/”
\ -> Maskierung (Escape-Zeichen) für z.B. einen Punkt “\.”
[] -> Zusammenfassung von Mustern
() -> Zusammenfassung von Mustern + selektieren und an PHP zurückgeben
7.) Maskieren von Strings zur Nutzung in Datenbanken
Sobald Daten in einer Datenbank gespeichert werden, sollte man diese via “mysql_real_escape_string” bzw. “mysqli_real_escape_string” maskieren, so dass “SQL Injection Angriffe” verhindert werden.
Das Problem ist jedoch, dass man diese Verschlüsselung via “Brute-Force-Attacke” erraten bzw. in einer “bösen”-Datenbank ;) mit vielen Kombinationen aus md5-hash und original-Wert auslesen kann. Daher kann man z.B. auch sha1() anstelle von md5() nutzen, was zwar den Zeitaufwand bei “Brute-Force-Attacke” erhöht, jedoch nicht die Schwachstellen der Ein-Weg-Verschlüsselung behebt.
Da das HTTP-Protokoll Daten plain (unverschlüsselt) überträgt, ist eine SSL- bzw. HTTPS-Verschlüsselung immer dann sinnvoll, wenn sensible Daten übertragen werden. So können die Daten beim Transport über das Internet nicht von dritten mitgelesen (Sniffing) werden.
11.) Cross-Site-Scripting (XSS)
Es geht darum Code auszuführen, der von einer fremden Webseite, in die aktuelle Webseite eingeschleust wird. Es ist ein Oberbrgriff für unterschiedliche Arten (serverseitiges & clientseitiges Cross-Site-Scripting) von Angriffen.
Auch dies ist eine Art des serverseitiges Cross-Site-Scriptings und das Ziel des Angreifers ist die Datenbank.
test.php: ———
<?php [...] $sql = "SELECT * FROM tabelle WHERE id=" . $id; [...] ?>
Wenn die Variable die nun per GET, POST oder Cookie überschrieben werden kann, wird eine neue SQL-Query an die Datenbank gesendet. Dabei wird die Tatsache ausgenutzt, dass man mehrere SQL-Befehle mit Simikolon getrennt, ausführen kann.
Gegenmaßnahmen:
-> Anführungsstriche verwenden
Anführungsstriche werden dazu verwendet um Variablen in SQL-Queries zu benutzen.
test.php: ———
[...] SELECT * FROM xyz WHERE id = '$Test' [...]
Ein Angreifer, der $Test verändert kann nicht aus den Anführungsstrichen ausbrechen, sloange $Test geparst wurde und alle ‘ mit \’ maskiert sind. Es gibt jedoch noch weitere Möglichkeiten um sich vor solchen Angriffen zu schützen.
-> Keine Strings in numerischen Variablen zulassen
Die Funktion settype wandelt Variablen (var) in einen Integer (int) um:
-> Datenbankverbindungen mit eingeschränkten Rechten
Gehe sparsam mit der Rechtevergabe an die Web (User) um, so dass im Notfall nicht die komplette Datenbank (DROP DATABASE name) betroffen ist. ;)
-> Werte maskieren
Mit der Funktion mysql(i)_real_escape_string bietet PHP eine einfache Möglichkeit SQL-Befehle zu maskieren.
Hinweis: Neben dem Semikolon ist auch ein doppelter Bindestrich (Kommentar in MySQL) dazu geeignet SQL-Kommandos nach dem eingeschleusten Code abzubrechen.
Zusammenfassung: Wenn man generell Anführungszeichen in den SQL-Kommandos benutzt und Variablen immer maskiert, würde dies zirka wie folgt aussehen…
Bei dem Apache Webserver wird das URL-Handling (Rewrite-Rules) via .htaccess gesteuert, sobald sich eine Datei mit diesem Namen in einem Verzeichnis befindet, werden die darin enthaltenen Befehle vom Apache umgesetzt. Da dieses Verfahren jedoch voraussetzt, dass alle Verzeichnisse zuvor auf eine solche Datei geprüft, diese anschließend eingelesen und verarbeitet werden muss, macht es Sinn wie z.B. beim Nginx Webserver diese in die Konfiguration des Webs aufzunehmen. Leider ist die Syntax und Logik dieser beiden Rewrite-Rules nicht kompatibel, daher folgt eine Einführung in dieses Thema … außerdem habe ich auf github.com/voku/ meine kompletten Konfigurationsdaten für Nginx + PHP + MySQL hochgeladen.
if ($host ~* voku-online.de) { rewrite ^(.*)$ http://suckup.de$1 permanent; }
Fall der Hostname “voku-online.de” ist, dann wird dieser zu “suckup.de” umgeschrieben und alles was hinter der ursprünglichen Hostnamen stand, wird hinter den neuen gesetzt.
^ -> Anfang
.* -> “.” ein beliebiges Zeichen, “*” Wiederholung => alle beliebigen Zeichen
( ) -> erstes Vorkommen der einfachen Klammern wird zur ersten Variable $1 … u.s.w.
## static files are served directly location ~* \.(?:js|css|htm?|js\?ver.*|css\?ver.*)$ { set $betterForCache 0;
if ($args ~* ver=(.*)$) { set $betterForCache 1; } if ($request_uri ~* “/wp-admin”) { set $betterForCache 0; } if ($betterForCache = 1) { rewrite ^(.*) $scheme://$host$uri? last; }
gzip_static on;
autoindex off; expires 1d; add_header Pragma public; # We bypass all delays in the post-check and pre-check parameters of Cache-Control. Both set to 0. add_header Pragma public; add_header Cache-Control “public, must-revalidate, proxy-revalidate, post-check=0, pre-check=0”; ## No need to bleed constant updates. Send the all shebang in one ## fell swoop. tcp_nodelay off; ## Set the OS file cache. open_file_cache max=3000 inactive=120s; open_file_cache_valid 45s; open_file_cache_min_uses 2; open_file_cache_errors off; break; }
Verschachtelte if-Abfragen kann man einfach via Hilfsvariablen (z.B. $betterForCache) erstellen …
Wir sollten PHP-Skript nicht alle mit dem selben User-Berechtigungen (z.B. apache) laufen lassen, daher empfiehlt es sich auf kleinen Webservern suPHP und auf Webseiten mit mehr Traffic “Fast CGI” zu installieren. Alternativ kann man PHP mit “PHP-FPM” (FastCGI Process Manager) auch jeweils als eigenständigen Prozess laufen lassen.
Da einige PHP-Projekte nicht wirklich für Ihre Sicherheit bekannt sind, empfiehlt es sich zudem die “Suhosin” Erweiterung für PHP zu installieren. “Es wurde entworfen, um den Server und die Benutzer vor bekannten und unbekannten Fehlern in PHP-Anwendungen und im PHP-Kern zu schützen.” – Wiki
PS: auf der Webseite -> http://www.dotdeb.org <- findet man einfach zu installierende .deb-Pakete für Debian / Ubuntu in welchen die Suhosin-Erweiterung bereits integriert ist und liegt zudem als “php5-fpm” Version zur Verfügung. ;)
“Gibt einen String zurück, der den angegebenen Formatierungs-Merkmalen entspricht. Dabei wird der gegebene Timestamp/ Zeitstempel oder – falls dieser fehlt – die momentane lokale Zeit benutzt. Der Monats- und Wochentagsname wird entsprechend des per setlocale() eingestellten Wertes gesetzt.” – php.net/manual/de/function.strftime.php
Mit unoconv kann man viele Dokument-Formate konvertieren, unterstützte Formate sind unter anderem das “Open Document Format” (.odt), “MS Word” (.doc), “MS Office Open/MS OOXML” (.xml), “Portable Document Format” (.pdf), “HTML”, “XHTML”, “RTF”, “Docbook” (.xml)…
Funktionen:
konvertiert alle Formate die OpenOffice unterstützt
OpenOffice unterstützt bis zu 100 Dokument Formate :-)
kann genutzt werden um Vorgänge zu automatisieren (Skripte -> z.B. shell oder php)
unterstützt weitere Tools -> “asciidoc”, “docbook2odf/xhtml2odt”
kann Style-Vorlagen (templates) während der Konvertierung anwenden (corporate identity)
kann sowohl als Server, als auch als Client fungieren
Formate:
Es folgt eine Liste von Ausgabe-Formaten von OpenOffice (und somit auch von unoconv), die Eingabe-Formate können sich jedoch unterscheiden -> INPUT / EXPORT
Export:
bib – BibTeX [.bib]
doc – Microsoft Word 97/2000/XP [.doc]
doc6 – Microsoft Word 6.0 [.doc]
doc95 – Microsoft Word 95 [.doc]
docbook – DocBook [.xml]
html – HTML Document (OpenOffice.org Writer) [.html]
odt – Open Document Text [.odt]
ott – Open Document Text [.ott]
ooxml – Microsoft Office Open XML [.xml]
pdb – AportisDoc (Palm) [.pdb]
pdf – Portable Document Format [.pdf]
psw – Pocket Word [.psw]
rtf – Rich Text Format [.rtf]
latex – LaTeX 2e [.ltx]
sdw – StarWriter 5.0 [.sdw]
sdw4 – StarWriter 4.0 [.sdw]
sdw3 – StarWriter 3.0 [.sdw]
stw – Open Office.org 1.0 Text Document Template [.stw]
sxw – Open Office.org 1.0 Text Document [.sxw]
text – Text Encoded [.txt]
txt – Plain Text [.txt]
vor – StarWriter 5.0 Template [.vor]
vor4 – StarWriter 4.0 Template [.vor]
vor3 – StarWriter 3.0 Template [.vor]
xhtml – XHTML Document [.html]
[…]
Installation:
aptitude install unoconv asciidoc docbook2od
Beispiele 1: Standard
Als erstes ein simples Beispiel, hier wird einfach “odt” in ein “pdf” umgewandelt. Sehr hilfreich ist auch sich die Optionen einmal anzuschauen.
# unoconv - Dienst starten
unoconv --listener &
# odt -> pdf
unoconv -f pdf some-document.odt
# Standard
(unoconv --server localhost --port 2002 --stdout -f pdf some-document.odt)
Beispiele 2: Vorlage
Wie bereits auf der Entwicklerseite zu lesen ist, hilf uns ein Screenshot nicht wirklich weiter, daher folgt ein zweites Beispiel mit Vorlagen.
# Client -> Server
unoconv --server 1.2.3.4 --port 4567
Beispiele 4: PHP
Man kann dies nun auch in Shell-Skripten nutzen oder wie in diesem Beispiel in PHP einbinden.
$this->Filegenerator = new FilegeneratorComponent ($this->params["form"]['uploaddocfile']);
// if the filegenerator did all it's magic ok then process
if($this->Filegenerator)
// returns the text version of the PDF
$text = $this->Filegenerator->convertDocToTxt();
// returns the html of the PDF
$html = $this->Filegenerator->convertDocToHtml();
// returns the generated pdf file
$pdf = $this->Filegenerator->convertDocToPdf($doc_id);
}
<?php
/**
* Class Used to convert files.
*@author jamiescott.net
*/
class FilegeneratorComponent extends Object {
// input folder types
private $allowable_files = array ('application/msword' => 'doc' );
// variable set if the constuctor loaded correctly.
private $pass = false;
// store the file info from constuctor reference
private $fileinfo;
/**
* Enter description here...
*
* @param array $fileinfo
* Expected :
* (
[name] => test.doc
[type] => application/msword
[tmp_name] => /Applications/MAMP/tmp/php/php09PYNO
[error] => 0
[size] => 79360
)
*
*
* @return unknown
*/
function __construct($fileinfo) {
// folder to process all the files etc
define ( 'TMP_FOLDER', TMP . 'filegenerator/' . $this->generatefoldername () . '/' );
// where unoconv is installed
define ( 'UNOCONV_PATH', '/usr/bin/unoconv' );
// where to store pdf files
define ( 'PDFSTORE', ROOT . '/uploads/generatedpdfs/' );
// where to store doc files
define ( 'DOCSTORE', ROOT . '/uploads/docfiles/' );
// apache home dir
define ( 'APACHEHOME', '/home/apache' );
// set some shell enviroment vars
putenv ( "HOME=".APACHEHOME );
putenv ( "PWD=".APACHEHOME );
// check the file info is passed the tmp file is there and the correct file type is set
// and the tmp folder could be created
if (is_array ( $fileinfo ) &amp;&amp; file_exists ( $fileinfo ['tmp_name'] ) &amp;&amp; in_array ( $fileinfo ['type'], array_keys ( $this->allowable_files ) ) &amp;&amp; $this->createtmp ()) {
// bass by reference
$this->fileinfo = &amp;$fileinfo;
// the constuctor ran ok
$this->pass = true;
// return true to the instantiation
return true;
} else {
// faild to instantiate
return false;
}
}
/**
* * takes the file set in the constuctor and turns it into a pdf
* stores it in /uploads/docfiles and returns the filename
*
* @return filename if pdf was generated
*/
function convertDocToPdf($foldername=false) {
if ($this->pass) {
// generate a random name
$output_pdf_name = $this->generatefoldername () . '.pdf';
// move it to the tmp folder for processing
if (! copy ( $this->fileinfo ['tmp_name'], TMP_FOLDER . 'input.doc' ))
die ( 'Error copying the doc file' );
$command = UNOCONV_PATH;
$args = ' --server localhost --port 2002 --stdout -f pdf ' . TMP_FOLDER . 'input.doc';
$run = $command . $args;
//echo $run; die;
$pdf = shell_exec ( $run );
$end_of_line = strpos ( $pdf, "\n" );
$start_of_file = substr ( $pdf, 0, $end_of_line );
if (! eregi ( '%PDF', $start_of_file ))
die ( 'Error Generating the PDF file' );
if(!file_exists(PDFSTORE.$foldername)){
mkdir(PDFSTORE.$foldername);
}
// file saved
if(!$this->_createandsave($pdf, PDFSTORE.'/'.$foldername.'/', $output_pdf_name)){
die('Error Saving The PDF');
}
return $output_pdf_name;
}
}
/**
* Return a text version of the Doc
*
* @return unknown
*/
function convertDocToTxt() {
if ($this->pass) {
// move it to the tmp folder for processing
if (! copy ( $this->fileinfo ['tmp_name'], TMP_FOLDER . 'input.doc' ))
die ( 'Error copying the doc file' );
$command = UNOCONV_PATH;
$args = ' --server localhost --port 2002 --stdout -f txt ' . TMP_FOLDER . 'input.doc';
$run = $command . $args;
//echo $run; die;
$txt = shell_exec ( $run );
// guess that if there is less than this characters probably an error
if (strlen($txt) < 10)
die ( 'Error Generating the TXT' );
// return the txt from the PDF
return $txt;
}
}
/**
* Convert the do to heml and return the html
*
* @return unknown
*/
function convertDocToHtml() {
if ($this->pass) {
// move it to the tmp folder for processing
if (! copy ( $this->fileinfo ['tmp_name'], TMP_FOLDER . 'input.doc' ))
die ( 'Error copying the doc file' );
$command = UNOCONV_PATH;
$args = ' --server localhost --port 2002 --stdout -f html ' . TMP_FOLDER . 'input.doc';
$run = $command . $args;
//echo $run; die;
$html= shell_exec ( $run );
$end_of_line = strpos ( $html, "\n" );
$start_of_file = substr ( $html, 0, $end_of_line );
if (! eregi ( 'HTML', $start_of_file ))
die ( 'Error Generating the HTML' );
// return the txt from the PDF
return $html;
}
}
/**
* Create file and store data
*
* @param unknown_type $data
* @param unknown_type $location
* @return unknown
*/
function _createandsave($data, $location, $file) {
if (is_writable ( $location )) {
// In our example we're opening $filename in append mode.
// The file pointer is at the bottom of the file hence
// that's where $somecontent will go when we fwrite() it.
if (! $handle = fopen ( $location.$file, 'w' )) {
trigger_error("Cannot open file ($location$file)");
return false;
}
// Write $somecontent to our opened file.
if (fwrite ( $handle, $data ) === FALSE) {
trigger_error("Cannot write to file ($location$file)");
return false;
}
fclose ( $handle );
return true;
} else {
trigger_error("The file $location.$file is not writable");
return false;
}
}
function __destruct() {
// remove the tmp folder
if (file_exists ( TMP_FOLDER ) &amp;&amp; strlen ( TMP_FOLDER ) > 4)
$this->removetmp ();
}
/**
* Create the tmp directory to hold and process the files
*
* @return unknown
*/
function createtmp() {
if (is_writable ( TMP )) {
if (mkdir ( TMP_FOLDER ))
return true;
} else {
return false;
}
return false;
}
/**
* Delete the tmp dir
*
* @return unknown
*/
function removetmp() {
if (strlen ( TMP_FOLDER ) > 3 &amp;&amp; file_exists ( TMP_FOLDER )) {
if ($this->recursive_remove_directory ( TMP_FOLDER ))
return true;
}
return false;
}
/**
* Return a rendom string for the folder name
*
* @return unknown
*/
function generatefoldername() {
return md5 ( microtime () );
}
/**
* Recursivly delete directroy or empty it
*
* @param unknown_type $directory
* @param unknown_type $empty
* @return unknown
*/
function recursive_remove_directory($directory, $empty = FALSE) {
// if the path has a slash at the end we remove it here
if (substr ( $directory, - 1 ) == '/') {
$directory = substr ( $directory, 0, - 1 );
}
// if the path is not valid or is not a directory ...
if (! file_exists ( $directory ) || ! is_dir ( $directory )) {
// ... we return false and exit the function
return FALSE;
// ... if the path is not readable
} elseif (! is_readable ( $directory )) {
// ... we return false and exit the function
return FALSE;
// ... else if the path is readable
} else {
// we open the directory
$handle = opendir ( $directory );
// and scan through the items inside
while ( FALSE !== ($item = readdir ( $handle )) ) {
// if the filepointer is not the current directory
// or the parent directory
if ($item != '.' &amp;&amp; $item != '..') {
// we build the new path to delete
$path = $directory . '/' . $item;
// if the new path is a directory
if (is_dir ( $path )) {
// we call this function with the new path
recursive_remove_directory ( $path );
// if the new path is a file
} else {
// we remove the file
unlink ( $path );
}
}
}
// close the directory
closedir ( $handle );
// if the option to empty is not set to true
if ($empty == FALSE) {
// try to delete the now empty directory
if (! rmdir ( $directory )) {
// return false if not possible
return FALSE;
}
}
// return success
return TRUE;
}
}
}
?>
Wer komplett auf nginx als Webserver umsteigen will kann dies auch sehr einfach bewerkstelligen. Ich persönlich nutzte diese Methode und es laufen mehrere WordPress-Webseiten, e107, DokuWiki u.s.w. tadellos mit diesem System.
Als erstes müssen wir unsere sources.list ein wenig erweitern… um php5-fpm direkt mit dem Projektmanager installieren zu können, wie dies Funktioniert habe ich bereits in einem anderen Beitrag beschreiben: php-5-FPM
Danach installieren wir nginx (Webserver) + PHP, wenn du noch apache2 oder einen anderen Webserver, welcher auf Port 80 lauscht installiert hast, musst du diesen nun deinstallieren bzw. erst einmal stoppen und ggf. einige libraries nachinstallieren, falls du Ubuntu und nicht Debian nutzt.
Nun kommen wir zur Konfiguration, ich poste hier einfach mal meine komplette Konfig, daher sollte diese ohne Probleme lauffähig sein, wenn du die aktuelle Version installiert hast.
so nun richten wir unsere erste Webseite ein… (domain.de muss in den nachfolgenden Howto durch deine eigene Domain ersetzt werden und natürlich für jede neue Werbepräsenz eine neue Datei angelegt werden.
nun müssen wir die Webseite nur noch aktivieren, indem wir die soeben erstellte Datei verlinken.
cd /etc/nginx/sites-enabled/
ln -s ../sites-available/domain.de.conf .
nginx -t
/etc/init.d/nginx restart
Und schon läuft unser neuer Webserver. :-) Um die neuste Version von Nginx auf Debian/Ubuntu zu installieren kann man ggf. noch folgende Quellen in die “sources.list” eintragen.
Nun leben wir für eine Webseite eine PHP-Konfiguration an:
vim /etc/php5/fpm/pools/domain.conf
[domain]
; one Port for one Website
listen = 127.0.0.1:11000
; uid/gid
user = domain_user
group = domain_group
; logging
request_slowlog_timeout = 5s
slowlog = /var/log/slowlog-domain.log
; Choose how the process manager will control the number of child processes.
pm.max_children = 10
pm.start_servers = 5
pm.min_spare_servers = 2
pm.max_spare_servers = 4
pm.max_requests = 500
; Pass environment variables
env[TMP] = /var/www/www.domain.de/phptmp
env[TMPDIR] = /var/www/www.domain.de/phptmp
env[TEMP] = /var/www/www.domain.de/phptmp
; inculde defaults
include = /etc/php5/fpm/common.conf
; host-specific php ini settings here
;php_admin_value[open_basedir] =
Jetzt läuft der PHP-fpm Prozess mit den Rechten des jeweiligen Users und mit eigenem Tmp-Verzeichnis, wer will kann php-fpm sogar in einer chroot-Umgebung ausführen lassen :-)
Auf Dotdeb.org gibt es PHP in Version 5.3.3 im .deb-Format. Das nachfolgende kleine HowTo zeigt wie du dies auf Debian installieren kannst. Es gibt Pakete für Debian (Lenny), sowohl für amd64 als auch i386 Architekturen.
Install:
1.) als erstes benötigen wir eine Root-Shell
sudo bash
2.) nun können wir die zusätzlichen Quellen einfügen
Falls man bereits mit Debian (Squeeze) arbeitet oder die Lenny-Backports in den Quellen eingefügt hat und daher das Paket libtool > 2.2 installiert hat, muss man eine ältere Version per dpkg installieren, da man ansonsten php5-dev (5.3.1) nicht installieren kann, damit man selber Erweiterungen für PHP kompilieren kann (z.B. eaccelerator). Es folgt ein kleines HowTo:
PHP besitzt selbst keinen Cache, was dazu führt, dass ein Skript bei jedem Aufruf neu übersetzt werden muss. Um dem entgegenzuwirken, gibt es einige Erweiterungen, die diese Funktionalität nachrüsten, wie beispielsweise den eAccelerator den alternativen PHP Cache.
Da PHP selber noch keinen Cache besitzt, was zur Folge hat das die Skript immer und immer wieder neu übersetzt werden müssen, gibt es ein paar Erweiterungen, welche diese Funktion nachrüsten. Und schon sind wir beim Thema.
1.) APC (Alternative PHP Cache)
APC ist ein Open-Source-Zusatzmodul für PHP, das eine beschleunigte Ausführung von PHP-Programmen ermöglicht. Die Beschleunigung wird dadurch erreicht, dass der kompilierte PHP-Quelltext zwischengespeichert wird und bei wiederholter Ausführung das zeitaufwändige Kompilieren nahezu vollständig vermieden werden kann. – Wiki
Als erstes schauen wir uns unsere aktuelle php-Config an…
Die Größe an Dateien welche im Speicher (apc.shm_size) gehalten wird, kann man ganz nach Auslastung des Servers anpassen. Um sich anzeigen zu lassen, wie viel der momentane maximal Wert ist, kannst du folgenden Befehl ausführen. (max seg size (kbytes) = 32768 -> 32MB) Wer einen Root-Server hat kann unter (/etc/sysctl.conf) die folgenden Werte entsprechend anpassen: kernel.shmall, kernel.shmmax
ipcs -lm
/etc/init.d/apache2 restart
[stextbox id=”info”]Die komplette Dokumentation kann im PHP Manual gefunden werden: http://de2.php.net/manual/de/ref.apc.php[/stextbox]
2.) eAccelerator
eAccelerator ist eine Open Source Software zum Einsatz auf Webservern, die als Beschleuniger, Optimierer und Cache für PHP-Seiten dient. – Wiki
Wir schauen uns wieder unsere aktuelle php-Config an…
aptitude install build-essential php5-dev git
cd /usr/src/
git clone https://github.com/eaccelerator/eaccelerator
cd eaccelerator/
phpize
./configure
make
make install
vim /etc/php5/conf.d/eaccelerator.ini
eaccelerator.shm_size Die Menge an Arbeitsspeicher (in Megabytes) welche eAccelerator verwenden darf. Der Standard Wert ist “0”.
eaccelerator.cache_dir Gibt das Verzeichnis an, wo eAccelerator die vorkompilierten Daten auf der Festplatte speichern darf. Die gleichen Daten können auch im Speicher oder auch nur im Speicher untergebracht werden, was einen schnelleren Zugriff zu folge hätte. Der Standard Wert ist “/tmp/eaccelerator”.
eaccelerator.enable Ein- / Ausschalten von eAccelerator. Wobei “1” gleich “an” bedeutet. Der Standard Wert ist “1”.
eaccelerator.optimizer Hier kannst du Ein- / Ausschalten ob der PHP-Code noch optimiert werden soll. Wobei “1” gleich “an” bedeutet. Der Standard Wert ist “1”.
eaccelerator.debug Hier kannst du das Debug-Logging Ein- / Ausschalten. Der Standard Wert ist “0”.
eaccelerator.check_mtime Ein- / Ausschalten für die Prüfung, ob der PHP-Code geändert wurde und somit doch noch mal neu übersetzt werden sollte. Wobei “1” gleich “an” bedeutet. Der Standard Wert ist “1”.
eaccelerator.filter Hier kannst du angeben welche Daten gecacht werden sollen. (z.B. “*.php *.phtml”) Wenn der Eintrag mit einem “!” beginnt, bedeutet dies, das diese Daten nicht gecacht werden. Der Standard Wert ist “”. -> was bedeutet, dass alles gecacht wird.
eaccelerator.shm_max Wenn sehr große Daten nicht in den Arbeitsspeicher wandern sollen, dann mann man diesen Wert setzten. (z.B. 10240, 10K, 1M). Der Standard Wert ist “0”.
eaccelerator.shm_ttl Wenn eaccelerator keinen Arbeitsspeicher mehr zur Verfügung hat, werden alle Daten gelöscht, welche älter sind als z.B. “9000” Sekunden (Webseiten welche die letzten 2 1/2 Stunden nicht besucht wurden) Der Standard Wert ist “0”.
eaccelerator.shm_prune_period Wenn eaccelerator keinen Arbeitsspeicher mehr zur Verfügung hat, werden die Daten welche vor z.B. 9000 Sekunden gecacht wurden gelöscht. Der Standard Wert ist “0”.
eaccelerator.shm_only Ein- / Ausschalten vom Cache auf der Festplatte. Der Standard Wert ist “0”. -> Was bedeutet das sowohl im Arbeitsspeicher als auch auf der Festplatte gecacht wird.
eaccelerator.compress Ein- / Ausschalten der Komprimierung der Daten. Der Standard Wert ist “1”.
eaccelerator.compress_level Stellt den Grad der Komprimierung ein. Der Standard Wert ist “9”. -> Max. Komprimierung
3.) XCache
Opcode-Cacher zum PHP-Beschleunigen auf Servern, beschleunigt den Prozess des Kompilierens von PHP-Skripten, indem er den kompilierten Zustand von PHP-Skripten im RAM zwischenspeichert und die kompilierte Version direkt aus dem Hauptspeicher nutzt.
aptitude install php5-xcache
Hier noch meine Konfiguration für das WordPress Plugin “W3 Total Cache” …
vim /etc/php5/conf.d/xcache.ini
; configuration for php xcache module
[xcache-common]
extension=xcache.so
[xcache.admin]
xcache.admin.enable_auth = Off
;xcache.admin.user = "admin"
;xcache.admin.pass = ""
[xcache]
; select low level shm/allocator scheme implemenation
xcache.shm_scheme = "mmap"
; to disable: xcache.size=0 (Standard)
; to enable : xcache.size=64M etc (any size > 0) and your system mmap allows
xcache.size = 64M
; set to cpu count (cat /proc/cpuinfo |grep -c processor)
xcache.count = 1
; just a hash hints, you can always store count(items) > slots
xcache.slots = 8K
; ttl of the cache item, 0=forever
xcache.ttl = 0
; interval of gc scanning expired items, 0=no scan, other values is in seconds
xcache.gc_interval = 0
; same as aboves but for variable cache
xcache.var_size = 64M
xcache.var_count = 1
xcache.var_slots = 8K
; default ttl
xcache.var_ttl = 0
xcache.var_maxttl = 0
xcache.var_gc_interval = 900
xcache.test = Off
; N/A for /dev/zero
xcache.readonly_protection = Off
; for *nix, xcache.mmap_path is a file path, not directory.
; Use something like "/tmp/xcache" if you want to turn on ReadonlyProtection
; 2 group of php won't share the same /tmp/xcache
; for win32, xcache.mmap_path=anonymous map name, not file path
;
; xcache.mmap_path = "/dev/zero"
; leave it blank(disabled) or "/tmp/phpcore/"
; make sure it's writable by php (without checking open_basedir)
;
; xcache.coredump_directory = ""
; per request settings
xcache.cacher = On
xcache.stat = Off
xcache.optimizer = On
[xcache.coverager]
; per request settings
; enable coverage data collecting for xcache.coveragedump_directory and xcache_coverager_start/stop/get/clean() functions (will hurt executing performance)
;
;xcache.coverager = Off
; ini only settings
; make sure it's readable (care open_basedir) by coverage viewer script
; requires xcache.coverager=On
;
;xcache.coveragedump_directory = ""
Mit folgendem Befehl habe ich die Geschwindigkeit meiner Webseite getestet, wobei ich in der Zwischenzeit, vom apache2 als Webserver Abstand genommen habe und voll auf “nginx” setzte. :-)
ab -n500 -c20 -dS "http://suckup.de/"
Somit wurden 500 Seitenaufrufe, davon 20 parallel ausgeführt, um einen Durchschnittswert zu erhalten habe ich den Befehl 3x ausgeführt und xCache war ein wenig schneller!!! :-)