You are not logged in.

GameR

Member

  • "GameR" is male
  • "GameR" started this thread

Posts: 2,099

Location: Berlin

Occupation: Student der Geschichte und Bibliothekswissenschaften

  • Send private message

1

Thursday, February 28th 2008, 12:42pm

Die WCF-Codebibel

Voreinstellungen:
Die Voreinstellungen müssen nicht getroffen werden, wirken sich aber positiv auf das Aussehen des Codes aus. Eingerückt wird mit Tabs, die Tabgröße beträgt 8.

Allgemeiner Codestil
Variabeln:
Variablen werden meistens klein Geschrieben und ohne ein Unterstrich (_) als Trennzeichen für Wörter. Ein neues Wort der Variable beginnt immer mit einem Großbuchstaben. Eine Ausnahme stellt das Wort ID da.

PHP Source code

1
2
3
4
5
6
7
8
$meineErsteVariabel//Richtig
$meine_erste_variable//Falsch
$meineerstevariable//Falsch
$MeineErsteVariable//Falsch
$meineID//Richtig
$meineId//Richtig
$meineid//Falsch
$MeineID//Falsch


Klassennamen
Klassenamen fangen mit einem Großgeschrieben Buchstaben an. Jeder erste Buchstabe eines erneuten Worts im Klassennamen wird groß geschrieben. Es werden keine Unterstriche (_) als Worttrennzeichen verwendet.

PHP Source code

1
2
3
4
class MeineErsteKlasse //Richtig
class meine_erste_klasse //Falsch
class meineErsteKlasse //Falsch
class Meine_Erste_Klasse //Falsch


Konstanten
Konstanten bestehen nur aus Großbuchstaben. Hier werden Unterstriche (_) als Worttrennzeichen verwendet. Dies folgt der allgemein empfohlenen PHP-Schreibweise.

PHP Source code

1
2
3
4
MEINE_KONSTANTE //Richtig
Meine_Konstante //Falsch
meinekonstante //Falsch
meineKonstante //Falsch


Funktions- und Methodenamen
Methoden und Funktionen fangen mit einem Kleinbuchstaben an, jedes weitere Wort beginnt mit einem Großbuchstaben. Es werden keine Unterstriche (_) als Trennzeichen verwendet.

PHP Source code

1
2
3
function meineFunktion //richtig
function MeineFunktion //falsch
function Meine_Funktion //falsch


Zuweisung von Variablen
Ein String wird immer zwischen zwei einfachen Hochkommas eingeschlossen, außer es werden diese im String benötigt, dann wird er im doppelten Hochkomma eingeschlossen. Eine Variabel im String wird nicht direkt in den String geschrieben, sondern mit dem entsprechenden Hochkommas eingeschlossen. Zwischen der Variabel und dem Operator, sowie zwischen dem Operator und dem Wert ist ein Leerzeichen.

PHP Source code

1
2
3
4
5
6
7
8
$varString 'Dies ist ein String'//Richtig
$varString "Dies ist ein String"//Falsch
$varString "Dies ist ein 'String'"//Richtig
$varString="Dies ist ein String"//Falsch
//Variablen in Variablen
$varString "Dies ist ein '$newString'"//Falsch
$varString "Dies ist ein '".$newString."'"//Richtig
$varString 'Dies ist ein '.$newString//Richtig

Die Zuweisung von Integerwerten erfolgt ganz normal, aber ohne Hochkommas.

PHP Source code

1
2
3
$varInt 1//Richtig
$varInt "1"//Falsch
$varInt '1'//Falsch


Zuweisung von Arrays
Die Zuweisung erfolgt wie bei den Variablen und auch deren Grundsätze sind soweit zu beachten. Desweiteren gilt, nach dem Schlüsselwort Array folgt sofort eine neue Zeile. Jeder Wert des Arrays wird in einer eigenen Zeile zugewiesen.

PHP Source code

1
2
3
4
$array = array(
        'key1' => 'wert',
        'key2' => 'wert2'
);

Wenn ihr numerische Array erstellt mit dieser Methode, solltet ihr ebenso die numerischen Schlüssel übergeben und es so aufbauen wie hier beschrieben.

Definition und Aufruf von Methoden und Funktionen
Funktionen und Methoden werden nach dem genannten Namenschema benannt, gefolgt von (). Die Variablen zwischen () werden durch ein Komma getrennt. Zwischen einem Parameter und dem vorherigen Komma ist ein Leerzeichen.

PHP Source code

1
2
3
4
5
6
function meineFunktion($param1$param2$param3) {
//Code...
}//Richtig
function meineFunktion($param1,$param1,$param3) {
//Code...
}//Falsch

Methoden beginnen immer mit der Zugriffskontrolle (protected, public, private) gefolgt von function. Sollte die Methode statisch sein, wird die Zugriffskontrolle von dem Wort static gefolgt.

PHP Source code

1
2
3
4
5
6
class MeineKlasse {
    public function meineMethode() {}//Richtig
    function meineMethode() {}//Falsch
    static public function meineMethode() {}//Falsch
    public static function meineMethode() {}//Richtig
}

Der Aufruf wurde bereits geschrieben, wie er aussehen sollte, hier das Beispiel dazu:

PHP Source code

1
2
$var meineFunktion($param1$param2$param3); //Richtig
$var meineFunktion($param1,$param2,$param3); //Falsch


Konstrukte
Zu den Sprachkonstrukt der Schleifen, Anweisungsblöcke werde ich nicht sehr viel schreiben, nur das zwischen den Klammern und dem Befehl ein Leerzeichen ist. Eine Ausnahme stellt der Befehle require und include da. Diese werden behandelt wie Funktionen und ebenso aufgerufen.

PHP Source code

1
2
require('meineDatei.php');
include('meineDatei.php');

Dies gilt auch für die beiden Befehle: require_once und include_once!
Wie die anderen Konstrukte geschrieben werdet, seht ihr im Beispiel:

PHP Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//IF
if ($var != '0') {    
    //code
}
else if ($var != '1') {
    //code
} 
else {    
    //code
}
//Scheifen
while ($row WCF::getDB()->fetchArray($result)) {
    //code
}
foreach ($array AS $key => $val) {
    //Code
}
for ($i 0$i 10$i++) {
    //Code
}

//switch
switch ($var) {
    case 'value':
        //code
            break;
    default:
        //code
}
Komödie ist Tragödie plus Zeit.
- Woody Allen

GameR

Member

  • "GameR" is male
  • "GameR" started this thread

Posts: 2,099

Location: Berlin

Occupation: Student der Geschichte und Bibliothekswissenschaften

  • Send private message

2

Thursday, February 28th 2008, 2:09pm

Übernahme von REQUEST-Variablen
Alle REQUEST-Variablen ($_POST, $_GET, $_REQUEST, $_COOKIE usw.) werden mit folgendem Code übernommen:

PHP Source code

1
if (isset($_REQUEST['param'])) $param $_REQUEST['param'];

Dabei ist zu beachten, das Integer werte mit intval übernommen werden und Strings mit StringUtil::trim.

PHP Source code

1
2
if (isset($_POST['param1'])) $param1 StringUtil::trim($_POST['param1']);
if (isset($_GET['param2'])) $param2 intval($_GET['param2']);


SQL
Ein SQL-Befehl sollte sich nicht auf eine Zeile beschränken, sondern Logisch getrennt werden. Hierfür bieten sich z.b Schlüsselwörter an, Kommas bei Insert befehlen oder Update befehlen.
Zudem sollte, wie bereits oben beschrieben werden, Variabeln nicht direkt eingebettet werden, sondern wie beschrieben eingebunden werden.

PHP Source code

1
$varString "Dies ist ein '".$newString."'"//Richtig

Ich gebe euch am Besten ein Beispiel für eine SELECT und INSERT Befehl.

PHP Source code

1
2
3
4
5
6
7
8
9
10
11
12
//SELECT
$sql "SELECT *
        FROM tabelle
        WHERE id = ".$id."
            AND user = ".$userID;

//insert
$sql "INSERT INTO tabelle
            (name1, name2, name3, name4, name5,
            name6, name7, name8, name9, name10)
        VALUES ('".$wert1."', '".$wert2."', '".$wert3."', 0, 0,
            0, 1, 1, 1, 1)";

Wie ihr gesehen habt, ist so eine logische Gliedrung des SQL-Statements möglich. Dabei ist zu beachten, das SELECT, FROM, WHERE, ORDER BY übergeordnete Gruppen spielen und das man untergeordnete Gruppen wie LEFT JOIN, RIGHT JOIN, AND, OR, ON noch einmal um ein Tab einrückt, so dass man sofort erkennt wozu sie gehören. Ich habe extra dafür ebenso ein komplexeres Statement mir einfallen lassen.

PHP Source code

1
2
3
4
5
6
7
$sql "SELECT v.*, t.*
        FROM tabelle1 v
            LEFT JOIN tabelle2 t
                ON (t.vid = v.id)
        WHERE v.id = ".intval($vID)."
            AND v.name = '".escapeString($vName)."'
        ORDER BY v.id ASC, t.id DESC";

Dies ist ein komplexeres Query, welches euch zeigen soll, wie ich es genau gemeint habe. Ihr konnt damit eine logische Gliederung in eure SQL-Befehle bringen. Eine Tabgröße von 8 sollte gewählt werden.

Sicherheit
Jedem von uns, auch Marcel, passiert es mal, dass eine Sicherheitslücke entsteht, aber sollte nicht passieren, und um das zu verhindern gibt es im WCF sehr nützliche Funktionen wie die escapeString (alias für WCF::getDB()->escapeString, Database::escapeString) und StringUtil::encodeHTML. Beide Funktionen dienen zur Sicherung gegen die beiden häufigsten Angriffspunkte in einem Skript. Der SQL-Injection und der XSS Attacke.

SQL-Injection
Ich hoffe, ich muss nicht beschreiben was eine SQL-Injection ist, aber für den Notfall, habe ich die Wikipediaseite verlinkt. Diese Attacke könnt ihr relativ einfach abwehren, nämlich in dem ihr für alle SQL-Statement, die Werte enthalten ein intval, oder eben escapeString anwendet. Wenn ihr euch an die Regeln für die Übergabe von REQUESt-Variablen gehalten habt, könnt ihr zumindest Sichersein, das Integerwerte, wirklich vom Typeinteger sind, und so nicht mehr behandelt werden müssen. Seid ihr dem euch nicht Sicher, wendet am besten noch mal ein intval auf diese an. Strings, Texte solltet ihr auf jedenfall, bevor ihr sie in SQL-Befehlen verwendet, per escapeString behandelt werden. Tut dies am Besten dort, wo das SQL-Statement ausgeführt wird. Damit verhindert ihr bereits die SQL-Injection.

PHP Source code

1
2
3
4
$sql "SELECT * 
        FROM tabelle
        WHERE name = '".escapeString($name)."'
            AND zahl = ".intval($zahl);

Wenn ihr euch daran haltet, ist die Gefahr einer SQL-Injection geringer. Solltet ihr euch nicht 100% Sichersein, das die Werte eine Zahl sind, wendet lieber erneut ein intval an. Sicher ist Sicher!

XSS
XSS-Attackensind genau wie die SQL-Injections relativ einfach abzuwehren. Man muss nur entsprechende Funktionen benutzen. Diese ist StringUtil::encodeHTML, oder eben in einem Template auf das @ vor einer Variabel zu verzichten. Wendet die Funktion StringUtil::encodeHTML auf alles an, was in die Templates kommt, und was einen Text enthält. Bei Zahlenwerten könnt ihr das gerne weglassen und ein @ verwenden in einem Template.

PHP Source code

1
2
3
4
5
//In PHP
$var "<b>Böses HTML</b>";
echo $var//Dies war ein schlechter Aufruf, denn das HTML wird nicht umgewandelt!
$var StringUtil::encodeHTML($var);
echo $var;//Dies war ein guter Aufruf


Da aber eher mit Templates gearbeitet wird, ist wohl folgendes eher anzutreffen.

PHP Source code

1
WCF::getTPL()->assign('var''<b>Böses HTML</b>');

Somit ergibt sich für das Template 2 Codeformen:

Template source code

1
2
{@$var} <br />Dies war ein Böser aufruf, denn das HTML wurde vollständig an den Browser übergeben.
{$var} <br />Dies war ein gute Aufruf, der HTMLCode wurde umgewandelt und so verhindert.

Hier gilt also wie bei den SQL-Befehlen, solltet ihr euch nicht 100% sichersein, das HTML-Code aus dem Text gefiltert wurde, oder entsprechend in seine Entities (& = &amp;, < = &lt;, >= &gt;) umgewandelt wurde, lasst das @ Zeichen weg!
Komödie ist Tragödie plus Zeit.
- Woody Allen

GameR

Member

  • "GameR" is male
  • "GameR" started this thread

Posts: 2,099

Location: Berlin

Occupation: Student der Geschichte und Bibliothekswissenschaften

  • Send private message

3

Thursday, May 22nd 2008, 4:26pm

//Platzhalter für Kommendes
Komödie ist Tragödie plus Zeit.
- Woody Allen

GameR

Member

  • "GameR" is male
  • "GameR" started this thread

Posts: 2,099

Location: Berlin

Occupation: Student der Geschichte und Bibliothekswissenschaften

  • Send private message

4

Wednesday, May 28th 2008, 9:36am

//Platzhalter für Kommendes.
Komödie ist Tragödie plus Zeit.
- Woody Allen

GameR

Member

  • "GameR" is male
  • "GameR" started this thread

Posts: 2,099

Location: Berlin

Occupation: Student der Geschichte und Bibliothekswissenschaften

  • Send private message

5

Wednesday, May 28th 2008, 9:37am

Codestruktur (Kleine Tipps und Tricks)
So, da ich ja hier nun doch schon einige Pakete durch gesehen habe, gibt es für die „Laien“ unter euch ein paar Tipps, die euch helfen sollen, eure Pakete eher auf Performances zu bringen und Codeschwachstellen zu vermeiden. (Wer ebenso Tipps und Tricks für die Codestruktur hat, soll mir diesen mir bitte per Privater Nachricht senden!)

Lesende Datenbankabfragen in einer Schleife
Ich habe öfters nun gesehen, dass „SELECT“ Abfragen in einer Schleife ausgeführt wird, dies ist aber in 99,99% der Fälle nicht nötig. Oft reicht es für diese in der Schleife getätigten Abfrage eine außerhalb zu tätigen und ein Array zu nutzen und in der Schleife auf das Array zuzugreifen. Damit hat man im schlimmsten Fall keine Datenbankabfrage gesparrt, im besten Fall sparrt N - 1 Datenbankabfragen, wobei N der Anzahl der Schleifendurchläufe entspricht. Ich werde hier nun ein einfaches negatives Beispiel liefern.

PHP Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
$personen = array();
$sql "SELECT    *
        FROM    person";
$result WCF::getDB()->sendQuery($sql);
while ($row WCF::getDB($result)) {
    $sql "SELECT        *
            FROM        personen_daten
            WHERE        personID = ".$row['personID'];
    $row2 WCF::getDB()->getFirstRow($sql);
    $row['info'] = $row2;
    $personen[] = $row;
}
?>

So, wie man hier sieht, werden erst mal alle Personen ausgelesen, und dann die entsprechenden Daten zu diesen Personen. (Ob diese Tabellenaufteilung Sinn macht, in dem Beispiel sei jetzt dahingestellt, es kann je nach Art Sinn machen, es können ja mehrere Datensätze zu einer Person existieren, da er vielleicht mehrere Wohnort hat, oder weil man eben die Daten nur selten ausließt und es daher Sinn macht, die Tabelle noch mal zu teilen.) Wer nun nachrechnet, wird darauf kommen, dass, je mehr Personen es sind, des so mehr Datenbankabfragen werden es. Um genauer zu sein: x = 1 + n (n steht für die Schleifendurchläufe). Das macht also bei 1 Person = 2 Abfragen, bei 2 sind es schon 3, bei 4 sind es 5 usw.
Und genau hier kann man eigentlich durch eine Umstrukturierung bereits Datenbankabfragen sparren. Als ich dieses Beispiel schrieb, nahm ich es absichtlich so, um euch zu zeigen das es zwei Wege gibt, dies besser zu gestallten. Existiert zu einer Person nur ein Datensatz, so kann man dies über einen JOIN lösen, dieser erspart uns nun jede weiter Datenbankabfrage. (x = 1)

PHP Source code

1
2
3
4
5
6
7
8
9
10
11
<?php
$personen = array();
$sql "SELECT        person.*, person_daten.*
        FROM        personen person
        LEFT JOIN    personen_daten person_daten
        ON        (person_daten.personID = person.personID)";
$result WCF::getDB()->sendQuery($sql);
while ($row WCF::getDB()->fetchArray($result)) {
    $personen[] = $row;
}
?>

Wie wir sehen, haben wir eine Abfrage gelöscht, die sonst in einer Schleife hätte durch geführt werden müssen. Alles nur ein bisschen nachdenken und Umstrukturierung eines SQL-Befehls.
Wir kommen aber nun zu einer Variante, die vor allem Benutzt wird, wenn mehrere Daten zu der Person existieren würden. Hier wäre es mit einem JOIN nun nicht mehr möglich und wir müssen eine Abfrage tätigen. Nur wenn wir diese wieder in der Schleife tätigen, kommen wir am ende auf die Formel: x = 1 + n, dabei können wir hier x = 2 setzen, und wie, das Zeig ich euch hier in zwei Varianten, einmal die ohne „Schnickschnack“, es werden alle Daten zu Personen ausgelesen und eine etwas bessere Methode, die eben nur die Daten ausließt die sie wirklich braucht!

PHP Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
//Lese alle Daten zu den Personen!
$personenDaten = array();
$sql "SELECT    *
        FROM    personen_daten";
$result WCF::getDB()->sendQuery($sql);
while ($row WCF::getDB()->fetchArray($result)) {
    $personenDaten[$row['personenID']][] = $row;
}

//Lese alle Personen und ordne ihnen ihre Informationen zu.
$personen = array();
$sql "SELECT    *
        FROM    personen";
$result WCF::getDB()->sendQuery($sql);
while ($row WCF::getDB()->fetchArray($result)) {
    $row['daten'] = $personenDaten[$row['personenID']];
    $personen[] = $row;
}
?>

Diese Variante ließt alle Personen Daten und alle Personen aus. Man braucht genau 2 Abfragen um sowas zu erreichen, vorher waren es ab 2 Personen schon eine Abfrage mehr. Aber was tun, wenn man nur einen bestimmten Satz an Personen will? Nun ja, auch da gibt es eine möglichkeit, man muss nur den Code etwas umstrukturieren.

PHP Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
//Wir holen uns dieses mal als erstes die Personen! Dafür bauen wir dieses mal 2 Arrays zusammen!
$personenIDs = array(); //Dieses Array brauchen wir um die IDs aller ausgelesen Personen zu speichern.
$personen = array(); //Dieses Array speichert die Personen.
$sql "SELECT    *
        FROM    personen
        WHERE    name LIKE 'T%'";
$result WCF::getDB()->sendQuery($sql);
while ($row WCF::getDB()->fetchArray($result)) {
    $personenIDs[] = $row['personenID'];
    $person[$row['personenID']] = $row;
}

//Nun holen wir die Daten zu den Personen
$sql "SELECT    *
        FROM    personen_daten
        WHERE    personenID IN (".implode(","$personenIDs).")";
$result WCF::getDB()->sendQuery($sql);
while ($row WCF::getDB()->fetchArray($result)) {
    $personen[$row['personenID']]['daten'][] = $row;
}
?>

Damit wäre auch das geschafft, ohne das ich zuviele Daten hole oder zuwenig. Somit habt ihr gesehen, dass es möglich ist, auch Abfragen in den Schleifen zu umgehen, wenn seinen Code ein wenig umbaut. Das spaart Datenbankabfragen und bei komplexeren Daten sogar eine weitere schleife die erst durchlaufen werden muss.
Komödie ist Tragödie plus Zeit.
- Woody Allen