PHPGangsta - Der praktische PHP Blog

PHP Blog von PHPGangsta


Archive for Dezember, 2009

IP-Adressen: Personenbezogene Daten oder nicht?

with 12 comments

ix112009

In der iX 11/2009 fand ich einen sehr interessanten Artikel zum Thema „Zu sorglose Speicherung und Weitergabe von IP-Adressen?“. Wir als Informatiker machen uns da eher selten Gedanken drüber, und lassen einfach die Standard-Einstellungen der Software so wie sie sind. Dass dies aber ein Problem sein kann (oder werden kann) zeigt der Artikel recht deutlich.

„IP-Adressen sind nicht personenbezogen“ war mein erster Gedanke, denn es gibt für mich keine Möglichkeit, aus einer IP-Adresse den Namen oder Anschrift des Benutzers herauszufinden.
Das stimmt allerdings nur so lange wie wir über dynamische IP-Adressen reden. Wenn Privatpersonen statische IP-Adressen besitzen, sieht es schon etwas anders aus, denn darüber kann man eine spezielle Person längere Zeit beobachten, auch wenn man nicht direkt an seinen Namen herankommt. Auch bei Firmen ist die Situation eine andere, denn diese kaufen häufig ganze IP-Bereiche, und die Besitzer von IP-Bereichen sind z.B. im RIPE-Register einsehbar, also zurückverfolgbar. Zwar nicht auf eine Person, aber auf eine Firma.

Doch wir wissen auch, dass die Provider (zumindestens einige) Auskunft geben, wem eine bestimmte IP-Adresse zugeteilt wurde, Gott sei Dank nicht jedem Anfragenden, aber mindestens die Staatsanwaltschaft sowie die Vertreter der Rechteinhaber können das mittlerweile, je nachdem an welchen Provider man gerät und wie er zu diesem Thema steht. Da wir aber nicht trennen können zwischen dynamischen und statischen IP-Adressen, müssen wir eher davon ausgehen, dass sie personenbezogen sind, konsequenterweise müssen wir alle IPs gleich behandeln.

Warum sind personenbezogene Daten etwas besonderes? Wir als Entwickler und Betreiber müssen dann besondere Schutzmaßnahmen ergreifen, damit die Daten bestmöglich geschützt sind. Für Kreditkarteninformationen wissen wir das und es ist auch einleuchtend, aber IP-Adressen werden aktuell von fast niemandem als besonders schützenswert angesehen. Die Webserver (Apache, IIS und alle anderen) speichern standardmäßig zu jedem Request die IP-Adresse in einer einfachen Log-Datei.

Natürlich brauchen wir genau die IP-Adressen auch hier und da, um den Dienst am Laufen zu halten, beispielsweise um fehlgeschlagene Login-Versuche mitzuloggen. Auch hat nahezu jeder irgendeinen Apache-Log-Parser laufen, der täglich Statisiken generiert über die Besucher, deren Herkunftsland etc. Stichworte sind da Webalizer, AWStats, Piwik usw. Es gibt Meinungen, die besagen, dass man zur Gefahrenabwehr oder im Fehlerfall Logdateien braucht und für eine gewisse Zeit erheben und aufbewahren darf. Doch das geht einigen schon zu weit in Richtung „verdachtsloser Aufzeichnung des Surfverhaltens“.

Etwas komplizierter wird es, wenn wir diese Daten (die IP-Adressen) an andere Dienstleister senden. Hä, tun wir das? Ja, das tun wir, wenn auch meistens unbewußt! Wenn wir beispielsweise Geo-Location-Dienste nutzen, schicken wir die IP-Adresse zu einem solchen Dienst, und bekommen das Land/Stadt zurück. Natürlich gibt es auch Offline-Datenbanken, aber in der Praxis nutzen viele wahrscheinlich den Online-Dienst. Google Analytics gehört natürlich auch zum Problemfeld, wo wir die Informationen über Besucher an einen amerikanischen Dienstleister weitergeben.

Auch gibt es im Apache die Einstellung, ob Reverse-DNS-Abfragen gemacht werden sollen, die dann geloggt werden. Das selbe gilt für SMTPs wie beispielsweise Postfix, die Reverse-DNS- und DNS-Abfragen machen, um die Gültigkeit einer Domain, das Vorhandensein eines MX-Eintrags, den Reverse-DNS-Eintrag etc. zu prüfen. Des weiteren senden wir zwecks einer DNS-Blacklist-Prüfung die IP-Adresse an einen Blacklist-Dienst (DNSBL, z.B. Spamhaus, NixSpam).

Wir gehen also mit den IP-Adressen unserer User nicht sonderlich sparsam um. Und genau das klarzumachen war Ziel des Artikels, mit dem Aufruf, bereits Vorbereitungen für Pseudonymisierung und andere Methoden zu treffen, um dem Datenschutz gerecht zu werden. Der Autor rät sogar, seine Dienste so aufzubauen, dass man auf die Speicherung auch ganz verzichten können sollte. Wie das ganze mit IPv6 weitergeht bleibt auch noch abzuwarten, wenn jede Person einen mehr oder weniger festen IP-Bereich bekommt, mit all den Vor- und Nachteilen.

Written by Michael Kliewe

Dezember 15th, 2009 at 9:38 am

Pflichtfelder mit Sternchen markieren via CSS

with 7 comments

Oft möchte man in einem Formular eine Prüfung einbinden, die anschlägt, wenn das Feld nicht gefüllt wurde. Das geht mit dem Zend Framework und Zend_Form sehr einfach:

class Wb_Form_Subscription extends Zend_Form
{
	public function __construct($options = null)
	{
		$element = new Zend_Form_Element_Text('Email');
		$element->setLabel('Email')
				->setRequired(true);
		$this->addElement($element);
	}
}

Mit der setRequired() Funktion fügen wir automatisch eine NotEmpty-Prüfung hinzu, außerdem erhält das Element die CSS-Klasse „required“:

<label for="Email" class="required">Email</label>

Wenn das Formular nun abgeschickt wird und das Feld leer bleibt, erhalten wir eine Fehlermeldung. Diese werden wir nachher noch anpassen. Doch erst möchten wir noch das Feld als Pflichtfeld markieren, mit einem kleinen roten Stern, so wie hier:

required_star

Das können wir auf 3 Arten erledigen, wobei die dritte mein Favorit ist:

$element->setLabel('Email *')
$element->getDecorator('label')->setOption('requiredSuffix', ' * ');

oder via CSS:

.required {
	background-image:url(/img/required-field.png);
	background-position:top right;
	background-repeat:no-repeat;
	padding-right:10px;
}

Eine Beispieldatei kann hier required-field runtergeladen werden.

Achso, die englische Fehlermeldung wollen wir noch anpassen, das geht so:

$element = new Zend_Form_Element_Text('Email');
$element->setLabel('Email')
		->setAttrib('size', 90)
		->setRequired(true)
		->addErrorMessage('Diese Email-Adresse ist ungültig')
		->addValidator('EmailAddress');
$this->addElement($element);

Wenn man für die verschiedenen Validatoren unterschiedliche Fehlermeldungen haben möchte, geht das so:

$element = new Zend_Form_Element_Text('Email');
$element->setLabel('Email')
		->setAttrib('size', 90)
		->setRequired(true)
		->addValidator('NotEmpty', false, array('messages' => 'Leer'))
		->addValidator('EmailAddress', false, array('messages' => 'Ungültig'));
$this->addElement($element);

error_messages

Möchte man nur eine Fehlermeldung haben, muss man den zweiten Parameter ($breakChainOnFailure) auf true setzen. Sobald ein Validator fehlschlägt, wird die Prüfung aller weiteren Validatoren abgebrochen.

Setzt man Zend_Translate ein, sollte man übrigens die Fehlermeldungen mittels Zend_Translate übersetzen lassen, und nicht so wie oben gezeigt. Dazu fügt man einfach eine neue Übersetzung hinzu, mit dem Schlüssel, der sich in den Klassenkonstanten der jeweiligen Validator-Klasse versteckt, wie hier beispielsweise beim EmailAddress-Validator.

Written by Michael Kliewe

Dezember 14th, 2009 at 9:50 am

Posted in PHP

Tagged with , , ,

Virtualisierung: ESXi ausprobieren auf dem Mac

with 3 comments

Wer sich mit Virtualisierung beschäftigt, kommt um VMWare nicht herum. VMWare Workstation haben sicherlich einige von euch schon ausprobiert, sobald es dann aber in Richtung „Server-Virtualisierung“ geht wird die Luft schon dünner.

Wenn man Virtualisierungssoftware (auch Hypervisor genannt) grob unterteilen möchte, gibt es 2 Arten:

  1. Hypervisor, die direkt auf der Hardware laufen („bare metal“, also selbst eine Art Minibetriebssystem) und kein Host-Betriebssystem benötigen. Bekannte Produkte sind hier VMWare ESX, der kostenlose VMWare ESXi, XenServer Hypervisor, Microsofts Hyper-V, Sie werden auch als „Type 1“ oder „Native VM“ bezeichnet.
  2. Applikationen, die auf einem Betriebssystem installiert werden, und dann als Programm gestartet werden. Bekannte Vertreter sind da Sun’s Open Source VirtualBox, VMWare Workstation/Server, Microsoft Virtual PC, KVM, UML, Linux VServer, OpenVZ, Virtuozzo und viele weitere. Sie werden auch als „Type 2“ oder „Hosted VM“ bezeichnet.

In der zweiten Kategorie unterscheidet man dann zwischen „Full Virtualization“ und „Paravirtualization“. Ersteres kann unveränderte Gäste starten, sprich jedes Betriebssystem auf dem Markt, während bei Paravirtualization das Gastbetriebssystem weiß, dass es virtualisiert wird und es angepasst sein muss an diese Situation, es geht also nicht mit jedem Betriebssystem.

Bei den Bare-Metal-Hypervisor gibt es natürlich Hardware-Einschränkungen, da sie direkt auf der Hardware laufen und nicht eine so große Treiber-Unterstützung mitbringen können wie moderne Windows- oder Linux-Betriebssysteme. Daher sollte man sich vorher informieren, ob beispielsweise ESXi auf seiner Hardware überhaupt läuft.

Um etwas mit ESXi zu testen, habe ich mir für zuhause mal einen USB-Stick erstellt mit der ESXi-Software drauf, und davon gebootet. Der Hypervisor bootete auch erfolgreich, jedoch bliebt er beim Laden der USB-Module stecken. Mein Mainboard (ein MSI 790FX GD70) wird also nicht unterstützt. Um trotzdem zu testen, startete ich es in der Firma mal testweise in VMWare Fusion. VMWare Fusion ist quasi das selbe wie VMWare Workstation, nur für Mac. Doch auch hier startete der Hypervisor nicht vernünftig, da ein Hypervisor innerhalb eines Hypervisors nicht unterstützt wird. Doch Dank eines Blog-Artikels habe ich es dennoch ans Laufen bekommen, und nun kann ich ESXi ausgiebig testen.

Ich habe also ein Mac OS X, darauf VMWare Fusion, darin wiederum ESXi installiert, und auf dem ESXi laufen dann weitere Betriebssysteme (aktuell ein Ubuntu 9.10 und Debian Lenny). Damit ich den ESXi administrieren kann, benötigt man VMWare vSphere, welches wiederum nur unter Windows läuft. Also habe ich unter Fusion noch eine Windows Virtual Machine laufen.

Ihr merkt schon, es macht Spass, soviele Betriebssysteme, teilweise verschachtelt, laufen zu lassen 😉

Written by Michael Kliewe

Dezember 10th, 2009 at 5:08 pm

.Net Programmierer hier? Verlosung zu Basta!-Konferenz-Tickets!

with one comment

Die Kollegen von webmasterpro haben mich auf ihre neue Verlosung hingewiesen. Falls sich also ein .Net/C#/Silverlight/Azure – Interessierter hier herumtreibt, sollte er an der Verlosung zu den Tickets teilnehmen. Dazu ist einfach nur ein Kommentar dort zu hinterlassen.

Es gibt volle 3 Tage Konferenzteilnahme in Darmstadt für die 2010 stattfindende Basta! zu gewinnen.

Written by Michael Kliewe

Dezember 3rd, 2009 at 9:00 am

Posted in Allgemein

Tagged with , , , ,

Programmierprinzipien: Law of Demeter

with 14 comments

Professor Ian Holland hat zu Beginn der objektorientierten Zeit (1989) bereits eine wichtige Richtlinie definiert, die die lose Kopplung von Klassen sicherstellen soll: Das „Gesetz von Demeter“ (Law of Demeter, LoD).

Wenn man Klassen soweit es geht voneinander trennt, sind sie übersichtlicher, besser wartbar und testbar, leichter weiterzuentwickeln und wiederzuverwenden. Umgangssprachlich könnte man es beschreiben als „Sprich nur mit deinen nächsten Freunden“ und „Verrate keine Geheimnisse, die andere nichts angehen“.

Ein Praxisbeispiel:

class Order
{
	public $orderStatus = 0;

	public function changeOrderStatus($newStatus, $customer)
	{
		$this->orderStatus = $newStatus;

		if ($newStatus == 3) {
			$this->sendEmail(
					$customer->getData()->getContactInformation()->getEmail(),
					'New Order Status: ' . $newStatus
			);
		}
	}
}

Wer bei diesem Code keine Bauchschmerzen hat, sollte unbedingt weiterlesen. Wenn wir darauf nun die Regeln des LoD loslassen, sehen wir die Probleme.

Eine Klassenmethode sollte nur folgende andere Methoden verwenden:

  • Methoden der eigenen Klasse
  • Methoden der übergebenen Parameter
  • Methoden der mit eigenen Klasse assoziierten Klassen
  • Methoden von Objekten, die die Methode selbst erzeugt hat

Die Zeile 11 wäre also verboten, da sie eine zu enge Kopplung bzw. ein zu großes Wissen über andere Klassen voraussetzt. Lösung wäre hier, nicht das ganze Kundenobjekt an die Methode zu übergeben, sondern nur die für hier wichtigen Kontaktinformationen.

Außerdem verstößt der Code gegen das Geheimnisprinzip, da das Attribut $orderStatus public ist und man so den Status ändern könnte ohne eine Email zu versenden.

Wenn wir einen Test für die oben beschriebene Methode schreiben möchten, müssen wir vorher erst ein Kundenobjekt erzeugen, darin Daten hinterlegen, Kontaktinformationen usw. Doch eigentlich würden die Kontaktinformationen reichen für den Test, das Kundenobjekt ansich ist uns eigentlich egal, da es nicht genutzt wird. Auch Testen wird also durch lose Kopplung einfacher.

Besser wäre z.B. der folgende Code.

class Order
{
	private $_orderStatus = 0;

	public function changeOrderStatus($newStatus, $customerInformation)
	{
		$this->_orderStatus = $newStatus;

		if ($newStatus == 3) {
			$this->_sendEmail(
					$customerInformation->getEmail(),
					'New Order Status: ' . $newStatus
			);
		}
	}
}

Oder man macht es wie im unten stehenden Beispiel. Darin ist auch das Prinzip „Tell don’t ask“ abgebildet, welches besagt, dass man lieber Befehle gibt als Informationen abzufragen:

class Order
{
	private $_orderStatus = 0;

	public function changeOrderStatus($newStatus, $customer)
	{
		$this->_orderStatus = $newStatus;

		if ($newStatus == 3) {
			$customer->sendEmail('New Order Status: ' . $newStatus);
		}
	}
}

Wir geben also dem Kundenobjekt den Befehl, eine Email zu versenden (an den Kunden). Dann ersparen wir uns das Abfragen von Informationen, und wir müssen nicht wissen, wie im Kundenobjekt die Email-Adresse abgespeichert wird. Änderungen der Kundenklasse sind so also viel einfacher und problemloser machbar. Die Klasse Order kümmert sich also hauptsächlich um seine eigenen Dinge, und überlässt alles was den Kunden betrifft wenn es geht der Kundenklasse. Stichwort ist da das Single Responsibility Principle bzw. das  „Eine-Verantwortlichkeit-Prinzip„.

Um nochmal schnell die 4 Prinzipien an Code darzustellen, hier die erlaubten Methodenaufrufe:

Methoden der eigenen Klasse:

class A
{
    public function method1() {
        $this->method2();
    }

    public function method2() {
    }
}

Methoden der Parameter:

class A
{
    public function method1(B $b) {
        $b->method2();
    }
}
class B
{
    public function method2() {
    }
}

Methoden assoziierter Klassen:

class A
{
    private $b;
    public function method1() {
        $this->b->method2();
    }
}
class B
{
    public function method2() {
    }
}

Methoden selbst erzeugter Objekte:

class A
{
    public function method1() {
        $b = new B();
        $b->method2();
    }
}
class B
{
    public function method2() {
    }
}

Weitere Informationen zum LoD gibts im deutschen oder englischen Artikel in der Wikipedia. Oder direkt im Paper des Professors (PDF).

Written by Michael Kliewe

Dezember 2nd, 2009 at 9:02 am