Testing PHP-Projekte von github via Travis CI

Um seine PHP-Projekte einfach mit verschiedenen PHP-Versionen zu testen, kann man z.B. „Travis CI“ verwenden, dazu hier ein kleines Beispiel:

 

1.) Projekt bei github.com anlegen 

 

2.) PHP-Unit Test erstellen: z.B.: URLifyTest.php && phpunit.xml && bootstrap.php

 

$ phpunit --bootstrap bootstrap.php  URLifyTest.php
PHPUnit 4.0.4 by Sebastian Bergmann.

.....

Time: 161 ms, Memory: 3.75Mb

OK (5 tests, 23 assertions)

 

3.) Travis-Konfiguration anlegen -> „.travis.yml

 

language: php

php:
  - 5.3
  - 5.4
  - 5.5
  - 5.6

before_script:
  - composer self-update
  - composer install --no-interaction --prefer-source --dev

script:
  - phpunit --coverage-text --verbose

 

4.) Projekt bei Travis CI anlegen (https://travis-ci.org/) und schon beim nächsten „git push“ wird das Projekt automatisch getestet …

 

Travis CI
Travis CI

 

 

php – die nächsten Mittwoche berechnen

„Mittwoche“ klingt irgendwie falsch … ;)

for ($i = 0; $i < = 4; $i++) {
	if ($i == 0) {
		$next_wednesday[$i] = date("Y-m-d", strtotime("next Wednesday"));
	}
	else {
		$next_wednesday[$i] = date("Y-m-d", strtotime("next Wednesday", strtotime($next_wednesday[($i-1)])));
	}
}

// DEBUG
print_r($next_wednesday);

php – Regular Expression Schnipsel – Escaping „/“

Hier ein kleines Beispiel wie man die Lesbarkeit von RegEx durch den Delimiter  „#“ verbessern kann … ;)

$zeichenkette = "suckup.de Informationen / test, lall / Linux / lall123";
#$suchmuster = "/^[^\/]*\/[^\/]*\/[^\/]*\/[^\/]/";
$suchmuster = "#^[^/]*/[^/]*/[^/]*/[^/]#";
preg_match($suchmuster, $zeichenkette, $treffer);
print_r($treffer);

 

Ausgabe:

Array ( [0] => suckup.de Informationen / test, lall / Linux / )

UTF-8 Byte Order Mark (BOM) in php-Dateien …

for Linux (shell):

 

BOM aus allen PHP-Dateien entfernen:

find . -type f -iname "*.php" -exec sed -i '1s/^\xEF\xBB\xBF//' {} \;

 

PHP-Dateien mit BOM anzeigen:

find . -type f -iname "*.php" -exec grep -l $'\xEF\xBB\xBF' {} \;

 

mehr Infos:

sed – suckup.de/linux/streameditor-sed

find – suckup.de/linux/find-linux

Byte Order Mark – http://de.wikipedia.org/wiki/Byte_Order_Mark

php – Regular Expression Schnipsel – Links aus -Tags

Habe zu dem Thema („Reguläre Ausdrücke“) bereits ausführlicher geschrieben -> http://suckup.de/howto/php-howto/php-sicherheit-erhoehen-teil-2/ <- daher folgt hier einfach ein Beispiel, welches man sicherlich noch optimieren kann … :)

<?php
$lall =' lall lall123
<a style="gfsedfd;" href="http://test1.de">test
<a style="gfsedfd;" href="test2.php" target="_blank>test</a> dsadsa
<a style="gfsedfd;" href="http://test3.de" target="_blank>test</a>
dsads
';

$lall = str_ireplace("\r", '', $lall);
$lall = str_ireplace("\n", '', $lall);
$lall = str_ireplace("\t", '', $lall);
preg_match_all('/<a [^>].*href="(.*)".*>/i', $lall, $lall_new);
$allLinks = explode("</a>", $lall_new[0][0]);
foreach ($allLinks as $key => $val) {
  $val = trim($val);
  if ($val != '') {
    $data =preg_replace('/.*<a [^>].*href\s*=\s*(["\'])(.*?)\1.*>.*/i',"$2",$val);
    echo $data . "\n";
  }
}
?>
php testtest.php

http://test1.de
test2.php
http://test3.de

PHP-Sicherheit erhöhen – Teil 2

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

1.) „register_globals“ sollten deaktiviert sein!!!

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.

test.php:
———

<?php 
$zahl = (int)$_GET['zahl'];
?>

Browser:
——–
…/test.php?zahl=123z

php.net:
——–
Type Casting -> http://de2.php.net/manual/de/language.types.type-juggling.php

 

3.) Variablen prüfen

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

php.net:
——–
empty() -> http://php.net/manual/de/function.empty.php
isset() -> http://php.net/manual/de/function.isset.php

 

4.) Variablen „Type“ prüfen

test.php:
———

<?php 
if (gettype($_GET['zahl']) == "integer") { $zahl = $_GET['zahl']; }
else { $zahl = (int) $_GET['zahl']; }
?>

Alternative: if (is_int($_GET[‚zahl‘])) { […]

 

5.) „Ctype“ Funktionen

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.

php.net:
——–
http://de2.php.net/manual/de/ref.ctype.php
    
    

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/

The Regex Coach
The 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

[a-zA-Z0-9_] -> Buchstaben, Ziffern, Unterstrich
\w -> Buchstaben, Ziffern, Unterstrich
\W -> keine Buchstaben, Ziffern, Unterstrich

[\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

 
6.1) ein Beispiel

test.php:
———

<?php 
if((!empty($_GET['Text'])) && (preg_match("/^(T|t)est(ing*){0,1}$/",$_GET['Text'])))
{
    $variable = "OK";
} else {
    $variable = "nicht OK";
}
echo 'Der Wert ist '.$variable;
?>

Browser:
——–
…/test.php?Text=Test -> OK -> (T|t)est
…/test.php?Text=test -> OK -> test(ing){0,1} = test(ing)?
…/test.php?Text=testing -> OK -> test(ing){0,1} = test(ing)?
…/test.php?testinggggg -> OK -> g*

 

6.2) noch ein Beispiel

Hier sind nur Zahlen zugelassen …

test.php:
———

<?php 
if((!empty($_GET['Text'])) && (preg_match("/^\d+([\.,]\d+)?$/",$_GET['Text'])))
{
    $variable = "OK";
} else {
    $variable = "nicht OK";
}
echo 'Der Wert ist '.$variable;
?>

Info:
—–
/^\d+([\.,]\d+)?$/ -> ist gleich -> /^[0-9]{1,}([\.,][0-9]{1,})?$/

Browser:
——–
…/test.php?Text=1 -> OK -> [0-9]{1,}
…/test.php?Text=123456789 -> OK -> [0-9]{1,}
…/test.php?Text=1.9 -> OK -> [0-9][\.,][0-9]
…/test.php?Text=123.789 -> OK -> [0-9]{1,}[\.,][0-9]{1,}
…/test.php?Text=123,789 -> OK -> [0-9]{1,}[\.,][0-9]{1,}

 

6.3) und noch ein Beispiel

Hier schneiden wir einen Teil aus einen String aus und geben diesen aus …

test.php:
———

<?php 
$imagemap = "<map id=\"imgmap201111415460\" name=\"imgmap201111415460\"><area shape=\"rect\" alt=\"\" title=\"\" coords=\"151,58,221,148\" href=\"\" target=\"\" /></map>";

$imagemap_name = preg_replace(‚/^<map(.+)name=\“(.+)\“><area(.+)/i‘, „$2“, $imagemap);

echo ‚Imagemap-Name: ‚.$imagemap_name;
?>

Ausgabe => Imagemap-Name: imgmap201111415460

Info:
—–
(.+) -> ist gleich -> (.{1,})

 

php.net:
——–
http://de3.php.net/manual/de/function.preg-replace.php

 

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.

 

php.net:
——–
http://php.net/manual/de/function.mysql-real-escape-string.php

 

8.) Ein-Weg-Verschlüsselung

Bei der Ein-Weg-Verschlüsselung wird nicht die original Eingabe, sondern ein Hash-Wert davon gespeichert z.B. md5

test.php:
———

<?php $passwort = 'mein_Pwd';
echo md5($passwort); ?>

Ausgabe: b4e28e9d7dbf6d41d6e609b3eb46fac4

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.

 

php.net:
——–
http://de.php.net/manual/de/function.md5.php
http://de.php.net/manual/de/function.sha1.php

 

9.) Zwei-Wege-Verschlüsselung

Bei der Zwei-Wege-Verschlüsselung werden Daten über einen Schlüssel verschlüsselt, so dass diese auch wieder entschlüsselt werden können.

test.php:
———

<?php 
function encryptData($value){
$key = "top secret key";
$text = $value;
$iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$crypttext = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $text, MCRYPT_MODE_ECB, $iv);
return $crypttext;
}

function decryptData($value){
$key = „top secret key“;
$crypttext = $value;
$iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$decrypttext = mcrypt_decrypt(MCRYPT_BLOWFISH, $key, $crypttext, MCRYPT_MODE_ECB, $iv);
return trim($decrypttext);
}

$test = encryptData(„Dies ist ein TEST!!!“);

echo $test;
echo „<br><br>“;
echo decryptData($test);
?>

 

Algorithmus:
————
-> MCRYPT_BLOWFISH (blowfish)
-> MCRYPT_TRIPLEDES (tripledes)
-> MCRYPT_RJINDAEL_256 (rjindael-256)
-> MCRYPT_CAST_256 (cast-256)

 

Modus:
——
-> MCRYPT_MODE_ECB (electronic codebook): für kurze Zeichenketten
-> MCRYPT_MODE_CBC (cipher block chaining): zur Dateiverschlüsselung
-> MCRYPT_MODE_CFB (cipher feedback): für Byteströme, mit Verschlüsselung einzelner Bytes
-> […]

 

php.net:
——–
http://php.net/manual/de/function.mcrypt-encrypt.php

 

Unter MySQL ist die „Zwei-Wege-Verschlüsselung“ einfacher zu handhaben, es gibt nur zwei Alternativen

– AES (Advanced Encryption Standard)
– DES: TripleDES

z.B.:
AES_DECRYPT(verschluesselt,schluessel)
AES_ENCRYPT(text,schluessel)

 

dev.mysql.com:
————–
http://dev.mysql.com/doc/refman/5.5/en/encryption-functions.html

 

10.) SSL (Secure Socket Layer)

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.

 

wikipedia.org:
————–
http://de.wikipedia.org/wiki/Cross-Site-Scripting

 

11.1) Serverseitiges Cross-Site-Scripting

Hier wird der „böse“ Code direkt auf dem Server der angegriffenen Webseite ausgeführt (z.B.: von PHP) …

… es folgt ein sehr schwerwiegender Programmierfehler, eine include & GET kombination, um serverseitiges XSS zu demonstrieren.

 

test.php:
———

<?php 
inculde($_GET['skript'];
// etc.
...
?>

Info: Clientseitiges Cross-Site-Scripting -> Hier wird der „böse“ Code via Browser-Technologien (z.B. via JavaScript, ActiveX …) eingeschleust.

 

11.2) SQL Injection

 

wikipedia.org:
————–
http://de.wikipedia.org/wiki/SQL-Injection

 

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:

 

test.php:
———

[...]
settype($Variable, 'integer');
[...]

 

php.net:
——–
settype -> http://www.php.net/manual/de/function.settype.php

 

-> 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…

 

test.php:
———

[...] 
if (!isset($_GET['id'])) { $id = 0; }
else { $id = $_GET['id']; }

if (gettype($id) == „integer“) { $zahl = $id; }
else { $zahl = settype($id, ‚integer‘); }

$sql = „SELECT * FROM tabelle
WHERE id='“ . mysqli_real_escape_string($zahl) . „‚
AND user=’test‘
„;
[…]

Rewrite-Rules: Apache vs Nginx

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.

 

Erklärung: einfache Weiterleitung

 

Apa­che:

Redirect /altes_Verzeichnis/alte_Seite.html http://suckup.de/

 

Nginx: 

rewrite /altes_Verzeichnis/alte_Seite.html http://suckup.de/ last;

 

Falls „/altes_Verzeichnis/alte_Seite.html“ hinter deiner Domain in der URL steht, wird die Anfrage auf die Domain „meine_domain.de“ umgeleitet.

z.B. http://suckup.de/altes_Verzeichnis/alte_Seite.html

 

Erklärung: Domain Weiterleitung

 

Apa­che:

RewriteCond %{HTTP_HOST} ^voku-online.de$ [NC]
RewriteRule ^(.*)$ http://www.suckup.de/$1 [R=301,L]

 

%{HTTP_HOST} -> Hostname

 

Nginx: 

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.

$ -> Ende

z.B. http://voku-online.de/altes_Verzeichnis/alte_Seite.html

 

Erklärung: entferne doppelte „/“

 

Apa­che:

RewriteCond %{REQUEST_URI} ^(.*)//(.*)$
RewriteRule . %1/%2 [R=301,L]

 

 %{REQUEST_URI} -> URL ohne Parameter

 ( ) -> erstes Vorkommen der einfachen Klammern in der „RewriteCond“-Bedingung wird zur ersten Variable %1 … u.s.w.

 

Nginx: 
if ($request_uri ~* „\/\/“) {
rewrite ^(.*)$ $scheme://$host$1 permanent;
}

 

\/ -> Escapezeichen „\“ vor „/“

$scheme -> http bzw. https

$host -> Hostname

permanent -> gibt den Statuscode 301 zurück

 

Erklärung: statische Dateien (.css/.js/.html) beschleunigen

 

Nginx:

## 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 …

$uri -> URL ohne Parameter

z.B.: https://suckup.de/wp-content/themes/mystique/css/core.css?ver=3.3.2

 

weitere Infos:

– Nginx & HttpRewriteModule:  http://wiki.nginx.org/HttpRewriteModule

– Apache & mod_rewrite: http://httpd.apache.org/docs/current/mod/mod_rewrite.html

– Beispiel-Konfiguration (WordPress Multi: Nginx + PHP-FPM): https://github.com/voku/CONFIG–nginx—php-fpm—mysql

PHP-Sicherheit erhöhen – Teil 1

 Jeder Server welcher PHP-Skripte verarbeitet, sollte zumindest zwei Sicherheitsschlösser eingebaut haben, so dass man nicht jedem Tür & Tor öffnet. 

 

1.) suPHP oder suexec + fcgid

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. 

2.) Suhosin

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. ;) 

 

mehr Sicherheit:

Mod-Security und Apache

Mod-Spamhaus und Apache

– WordPress Sicherheit erhöhen

– php.ini / php.net

www.howtoforge.com | viele gute HowTo’s 

Monatsnamen / Wochentagsnamen in deutsch via PHP

„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

 

setlocale(LC_TIME, "de_DE");
echo strftime("%A"); // Wochentagsname
echo strftime("%B"); // Monatsname

unoconv: umwandlung zwischen allen Dokument-Formaten von OpenOffice

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.

# Beispiel Dateien herunterladen 
wget http://dag.wieers.com/cv/Makefile
wget http://dag.wieers.com/cv/curriculum-vitae-dag-wieers.txt
wget http://dag.wieers.com/cv/curriculum-vitae-docbook.ott

# unoconv - Dienst starten
unoconv --listener &
# resume.txt -> resume.xm
asciidoc -b docbook -d article -o resume.xml resume.txt
# resume.xml -> resume.tmp.odt
docbook2odf -f --params generate.meta=0 -o resume.tmp.odt resume.xml
# resume.tmp.odt -> resume.odt + Template
unoconv -f odt -t template.ott -o resume.odt resume.tmp.odt
# resume.tmp.odt -> resume.pdf + Template
unoconv -f pdf -t template.ott -o resume.pdf resume.odt
# resume.tmp.odt -> resume.html + Template
unoconv -f html -t template.ott -o resume.html resume.odt
# resume.tmp.odt -> resume.doc + Template
unoconv -f doc -t template.ott -o resume.doc resume.odt

Beispiele 3: Server <-> Client

Wie bereits erwähnt kann man den Dienst auch als Server starten und von anderen Rechnern darauf zugreifen.

# unoconv - Server-Dienst starten
unoconv --listener --server 1.2.3.4 --port 4567
# 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;&amp;amp; file_exists ( $fileinfo ['tmp_name'] ) &amp;amp;&amp;amp; in_array ( $fileinfo ['type'], array_keys ( $this->allowable_files ) ) &amp;amp;&amp;amp; $this->createtmp ()) {

// bass by reference
$this->fileinfo = &amp;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;&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;&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;&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;
}
}
}
?>