Online Highscore

Übersicht BlitzBasic FAQ und Tutorials

Neue Antwort erstellen

Xaymar

ehemals "Cgamer"

Betreff: Online Highscore

BeitragFr, Dez 25, 2009 18:02
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich kann jedem PHP Anfänger raten folgendes Tutorial komplett durchzuarbeiten: http://tut.php-q.net/de/index.html!

PHP-Online-Highscore Tutorial

Inhaltsangabe
  • Zuletzt bearbeitet von Xaymar am Mo, Feb 22, 2010 15:29, insgesamt 8-mal bearbeitet

Xaymar

ehemals "Cgamer"

Betreff: 1. Voraussetzungen

BeitragFr, Dez 25, 2009 18:13
Antworten mit Zitat
Benutzer-Profile anzeigen
1. Voraussetzungen

Folgendes werdet ihr brauchen um ein Online-Highscore zu erstellen und zu nutzen:
o Blitzbasic/BlitzPlus/Blitz3D
o Webspace mit MySQL und PHP(Zum testen eignet sich Bplaced.net)
o Texteditor(Ich empfehle Notepad++)

1.1 MySQL
Eure MySQL version sollte 4.0 und höher sein. Mit niedrigeren Versionen habe ich es nicht getestet.

1.2 BlitzBasic, BlitzPlus, Blitz3D
Es ist relativ egal welches ihr davon nutzt, da die Netzwerkfunktionen ja in jeder BlitzBasic Version vorhanden sind.
Hauptsache sie sind auf einem einigermaßen neuen Stand.

1.3 PHP
Eure PHP Version sollte 5.1.5 und höher sein. Mit niedrigeren Versionen habe ich es nicht getestet.

1.4 Webspace
Euer Webspace sollte eine Antwortzeit von unter einer Sekunde haben und mindestens 1mb Speicherplatz für die PHP Datei(en).
Warbseite

Xaymar

ehemals "Cgamer"

Betreff: 2. Der Anfang

BeitragFr, Dez 25, 2009 18:45
Antworten mit Zitat
Benutzer-Profile anzeigen
2. Der Anfang

Als erstes müssen wir bei einem aufruf der PHP Datei mit dem MySQL Server verbinden. Dazu habe ich euch mal folgende PHP Datei erstellt:
Code: [AUSKLAPPEN]
<?php
   //MySQL Connection Data
   $SQL_User = "";      //Benutzername
   $SQL_Pass = "";      //Passwort
   $SQL_Host = "";      //SQL Host
   $SQL_DaBa = "";      //Datenbank auf die zugegriffen wird
   
   //MySQL Connection
   mysql_connect($SQL_Host,$SQL_User,$SQL_Pass) OR die(mysql_error());
   mysql_selectdb($SQL_DaBa) OR die(mysql_error());
   
   //Der Rest des Codes hier drunter
   
   //Der Rest des Codes hier drüber
?>


2.1 Erstes PHP-Online-Highscore Skript
Fangen wir mal mit einem ganz einfachem Online-Highscore an, der nichts weiter speichert außer dem Namen und der Punkte.
Dazu müssen wir eine SQL Tabelle erstellen, ungefähr so
Code: [AUSKLAPPEN]
mysql_query("CREATE TABLE IF NOT EXISTS OnlineHighscore (
Name TEXT,
Punkte INT)") or die(mysql_error());

Fügen wir den code mal in unseren Anfangscode ein. Das PHP Skript wird jetzt nichts anderes machen, als bei jedem Aufruf mit der MySQL Datenbank zu verbinden und die Tabelle zu erstellen(falls sie nicht vorhanden ist), also gehen wir nun einen Schritt weiter und fangen an mit dem speichern des Highscores.

Dazu verwende ich $_GET[...](Ihr könnt auch $_POST[...] verwenden) um den Namen und den Punktestand zu bekommen. GET und POST sind HTTP Methoden zur Datenübertragung(siehe Formular)
Code: [AUSKLAPPEN]
//Getting the Data
$OHS_Action = $_GET['Action'];
$OHS_Spieler = $_GET['Name'];
$OHS_Punkte = $_GET['Punkte'];

Man sieht, dass ich 3 Variablen nehme. $OHS_Action um die Aktion festzulegen was das PHP Skript machen soll, $OHS_Spieler um den Namen zwischenzuspeichern und $OHS_Punkte um die Punkte zwischenzuspeichern. Diesen Code nun wieder in den Anfangscode einfügen.

Jetzt zum eigenltichen Teil des Online Highscore Skripts: Dem speichern, lesen und löschen.
Dazu bräuchten wir eine Select-Case abfrage, in PHP switch-case:break. Die sähe dann wie folgt aus:
Code: [AUSKLAPPEN]
switch($OHS_Action) {
   case "add":      //Add Entry
      //Code für das hinzufügen von Einträgen hier hin
      break;
   case "rem":      //Remove Entry
      //Code für das entfernen von Einträgen hier hin
      break;
   case "red":      //Read Highscore
      //Code für das ausgeben der Highscore Tabelle hier hin
      break;
}

Um nun MySQL zu sagen, dass es einen neuen Eintrag machen soll ersetzen wir "//Code für das hinzufügen von Einträgen hier hin" durch:
Code: [AUSKLAPPEN]
mysql_query("INSERT INTO
      OnlineHighscore
   VALUES
      ('".$OHS_Spieler."','".$OHS_Punkte."')") or die(mysql_error());

Das PHP-Skript würde nun beim aufruf("*.php?action=add&name=test&punkte=1234") einen Eintrag hinzufügen. Jetzt müssen wir Einträge aber auch noch entfernen können.
Dazu ersetzen wir "//Code für das entfernen von Einträgen hier hin" mit folgendem Code:
Code: [AUSKLAPPEN]
mysql_query("DELETE FROM
      OnlineHighscore
   WHERE
      Name = '".$OHS_Spieler."' AND
      Punkte = '".$OHS_Punkte."'") or die(mysql_error());

Jetzt würde das PHP-Skript beim Aufruf("*.php?action=rem&name=test&punkte=1234") den Eintrag "suchen" und löschen.
Das reicht uns hier auch schon.

2.2 Highscores darstellen

Jetzt müssen wir den Highscore natürlich auch darstellen. Dazu brauchen wir wieder nur eine Zeile ersetzen, nämlich "//Code für das ausgeben der Highscore Tabelle hier hin". Die Zeile ersetzen wir durch:
Code: [AUSKLAPPEN]
$result = mysql_query("SELECT
      Name,
      Punkte
   FROM
      OnlineHighscore
   ORDER BY
      Punkte DESC");   //ASC = Aufwärts sortiert, DESC = Abwärts sortiert
$CurrentPlace = 1;
if (mysql_num_rows($result)) {
   while ($row = mysql_fetch_assoc($result)) {
      //Ausgabecode der Liste
      echo $CurrentPlace+"\r\n";
      echo $row['Name']+"\r\n";
      echo $row['Punkte']+"\r\n";
      $CurrentPlace += 1;
   }
}

Die Rückgabe des Skripts könnten wir dann einfach per ReadLine auslesen, aber es ist eure Entscheidung wie ihr es ausgebt. Ziemlich simpel oder? Schwieriger wird es erst, wenn dann die ganzen Online-Highscore Hacker, Cheater und Exploiter kommen(SQL Injection). Darauf gehe ich aber erst später ein.

Den Blitzbasic code sollte man eigentlich selber zusammenstellen können, ich will aber nicht so sein:
BlitzBasic: [AUSKLAPPEN]
Global HTTPServerAdress$ = ""
Global HTTPServerFile$ = "/ohs.php"
Global OHS_TimeOut = 1000

Type OHS_Highscores
Field Place
Field Name$
Field Score
End Type

Function OHS_AddHighscore$(Name$, Punkte)
Local TCP,ExitCode$,StartMS
TCP = OpenTCPStream(HTTPServerAdress, 80)

;HTTP GET
WriteLine TCP, "GET "+HTTPServerFile+"?action=add&name="+Name+"&Punkte="+Punkte+" HTTP/1.0"
WriteLine TCP, ""

StartMS = MilliSecs()
While Eof(TCP)
If MilliSecs()-StartMS > OHS_TimeOut Then Exit
Delay 25
Wend

ExitCode$ = ReadLine(TCP)
While Not Eof(TCP)
DebugLog ReadLine(TCP)
Wend

Return ExitCode
End Function

Function OHS_RemHighscore$(Name$, Punkte)
Local TCP,ExitCode$,StartMS
TCP = OpenTCPStream(HTTPServerAdress, 80)

;HTTP GET
WriteLine TCP, "GET "+HTTPServerFile+"?action=rem&name="+Name+"&Punkte="+Punkte+" HTTP/1.0"
WriteLine TCP, ""

StartMS = MilliSecs()
While Eof(TCP)
If MilliSecs()-StartMS > OHS_TimeOut Then Exit
Delay 25
Wend

ExitCode$ = ReadLine(TCP)
While Not Eof(TCP)
DebugLog ReadLine(TCP)
Wend

Return ExitCode
End Function

Function OHS_GetHighscore$()
Local TCP,ExitCode$,StartMS
TCP = OpenTCPStream(HTTPServerAdress, 80)

;HTTP GET
WriteLine TCP, "GET "+HTTPServerFile+"?action=red HTTP/1.0"
WriteLine TCP, ""

StartMS = MilliSecs()
While Eof(TCP)
If MilliSecs()-StartMS > OHS_TimeOut Then Exit
Delay 25
Wend

ExitCode$ = ReadLine(TCP)
Repeat
Local Ln$ = ReadLine(TCP)
DebugLog Ln$
If Ln$ = ""
While Not Eof(TCP)
Local OHSE.OHS_Highscores = New OHS_Highscores
OHSE\Place = ReadLine(TCP)
OHSE\Name = ReadLine(TCP)
OHSE\Score = ReadLine(TCP)
Wend
EndIf
Until Eof(TCP)

Return ExitCode
End Function
Warbseite
  • Zuletzt bearbeitet von Xaymar am Sa, März 27, 2010 15:01, insgesamt 4-mal bearbeitet

Xaymar

ehemals "Cgamer"

Betreff: 3. Fortgeschrittene Methoden

BeitragMo, Dez 28, 2009 22:16
Antworten mit Zitat
Benutzer-Profile anzeigen
3. Fortgeschrittene Methoden

Manchmal reicht eine einfache Highscoreliste nicht aus, da es ja genug Schummler gibt. In diesem Teil geht es um Methoden zur vermeidung eben dieser.

Vielen Dank an Starwar, der mir den MD5-Code zukommen lassen hat und auch an den originalen Author, Craig Kiesau
MD5:BlitzBasic: [AUSKLAPPEN]
Dim MD5_x(0)

Function MD5$(sMessage$)

;Pads the String as per the MD5 standard
nblk = ((Len(sMessage$) + 8) Shr 6) + 1 ;number of 16-word blocks

Dim MD5_x(nblk * 16 - 1)
;Zero pad the string
For i = 0 To nblk * 16 - 1
MD5_x(i) = 0
Next
;Convert to array of "words"
For i = 0 To (Len(sMessage$) - 1)
MD5_x((i Shr 2)) = MD5_x((i Shr 2)) Or (Asc(Mid(sMessage$, (i + 1), 1)) Shl ((i Mod 4) * 8))
Next
MD5_x((i Shr 2)) = MD5_x((i Shr 2)) Or (128 Shl (((i) Mod 4) * 8))
MD5_x(nblk * 16 - 2) = Len(sMessage$) * 8

;Set initial values
MD5_a = 1732584193 ;&H67452301
MD5_b = -271733879 ;&HEFCDAB89
MD5_c = -1732584194 ;&H98BADCFE
MD5_d = 271733878 ;&H10325476

;Loop through the words
For k = 0 To (nblk * 16 - 1) Step 16
MD5_AA = MD5_a
MD5_BB = MD5_b
MD5_CC = MD5_c
MD5_DD = MD5_d
;Round 1
MD5_a = MD5_FF(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 0), 7, -680876936) ;&HD76AA478
MD5_d = MD5_FF(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 1), 12, -389564586) ;&HE8C7B756
MD5_c = MD5_FF(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 2), 17, 606105819 );&H242070DB
MD5_b = MD5_FF(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 3), 22, -1044525330) ;&HC1BDCEEE
MD5_a = MD5_FF(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 4), 7, -176418897) ;&HF57C0FAF
MD5_d = MD5_FF(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 5), 12, 1200080426 );&H4787C62A
MD5_c = MD5_FF(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 6), 17, -1473231341) ;&HA8304613
MD5_b = MD5_FF(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 7), 22, -45705983) ;&HFD469501
MD5_a = MD5_FF(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 8), 7, 1770035416) ;&H698098D8
MD5_d = MD5_FF(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 9), 12, -1958414417 );&H8B44F7AF
MD5_c = MD5_FF(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 10), 17, -42063 );&HFFFF5BB1
MD5_b = MD5_FF(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 11), 22, -1990404162) ;&H895CD7BE
MD5_a = MD5_FF(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 12), 7, 1804603682) ;&H6B901122
MD5_d = MD5_FF(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 13), 12, -40341101) ;&HFD987193
MD5_c = MD5_FF(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 14), 17, -1502002290) ;&HA679438E
MD5_b = MD5_FF(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 15), 22, 1236535329) ;&H49B40821
;Round 2
MD5_a = MD5_GG(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 1), 5, -165796510) ;&HF61E2562
MD5_d = MD5_GG(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 6), 9, -1069501632) ;&HC040B340
MD5_c = MD5_GG(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 11), 14, 643717713) ;&H265E5A51
MD5_b = MD5_GG(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 0), 20, -373897302) ;&HE9B6C7AA
MD5_a = MD5_GG(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 5), 5, -701558691) ;&HD62F105D
MD5_d = MD5_GG(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 10), 9, 38016083) ;&H2441453
MD5_c = MD5_GG(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 15), 14, -660478335) ;&HD8A1E681
MD5_b = MD5_GG(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 4), 20, -405537848) ;&HE7D3FBC8
MD5_a = MD5_GG(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 9), 5, 568446438) ;&H21E1CDE6
MD5_d = MD5_GG(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 14), 9, -1019803690) ;&HC33707D6
MD5_c = MD5_GG(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 3), 14, -187363961) ;&HF4D50D87
MD5_b = MD5_GG(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 8), 20, 1163531501) ;&H455A14ED
MD5_a = MD5_GG(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 13), 5, -1444681467) ;&HA9E3E905
MD5_d = MD5_GG(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 2), 9, -51403784) ;&HFCEFA3F8
MD5_c = MD5_GG(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 7), 14, 1735328473) ;&H676F02D9
MD5_b = MD5_GG(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 12), 20, -1926607734) ;&H8D2A4C8A
;Round 3
MD5_a = MD5_HH(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 5), 4, -378558) ;&HFFFA3942
MD5_d = MD5_HH(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 8), 11, -2022574463) ;&H8771F681
MD5_c = MD5_HH(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 11), 16, 1839030562) ;&H6D9D6122
MD5_b = MD5_HH(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 14), 23, -35309556) ;&HFDE5380C
MD5_a = MD5_HH(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 1), 4, -1530992060) ;&HA4BEEA44
MD5_d = MD5_HH(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 4), 11, 1272893353) ;&H4BDECFA9
MD5_c = MD5_HH(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 7), 16, -155497632) ;&HF6BB4B60
MD5_b = MD5_HH(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 10), 23, -1094730640) ;&HBEBFBC70
MD5_a = MD5_HH(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 13), 4, 681279174) ;&H289B7EC6
MD5_d = MD5_HH(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 0), 11, -358537222) ;&HEAA127FA
MD5_c = MD5_HH(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 3), 16, -722521979) ;&HD4EF3085
MD5_b = MD5_HH(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 6), 23, 76029189) ;&H4881D05
MD5_a = MD5_HH(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 9), 4, -640364487) ;&HD9D4D039
MD5_d = MD5_HH(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 12), 11, -421815835) ;&HE6DB99E5
MD5_c = MD5_HH(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 15), 16, 530742520) ;&H1FA27CF8
MD5_b = MD5_HH(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 2), 23, -995338651) ;&HC4AC5665
;Round 4
MD5_a = MD5_II(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 0), 6, -198630844) ;&HF4292244
MD5_d = MD5_II(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 7), 10, 1126891415) ;&H432AFF97
MD5_c = MD5_II(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 14), 15, -1416354905) ;&HAB9423A7
MD5_b = MD5_II(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 5), 21, -57434055) ;&HFC93A039
MD5_a = MD5_II(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 12), 6, 1700485571) ;&H655B59C3
MD5_d = MD5_II(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 3), 10, -1894986606) ;&H8F0CCC92
MD5_c = MD5_II(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 10), 15, -1051523) ;&HFFEFF47D
MD5_b = MD5_II(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 1), 21, -2054922799) ;&H85845DD1
MD5_a = MD5_II(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 8), 6, 1873313359) ;&H6FA87E4F
MD5_d = MD5_II(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 15), 10, -30611744) ;&HFE2CE6E0
MD5_c = MD5_II(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 6), 15, -1560198380 );&HA3014314
MD5_b = MD5_II(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 13), 21, 1309151649) ;&H4E0811A1
MD5_a = MD5_II(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 4), 6, -145523070) ;&HF7537E82
MD5_d = MD5_II(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 11), 10, -1120210379) ;&HBD3AF235
MD5_c = MD5_II(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 2), 15, 718787259) ;&H2AD7D2BB
MD5_b = MD5_II(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 9), 21, -343485551) ;&HEB86D391

MD5_a = MD5_a + MD5_AA
MD5_b = MD5_b + MD5_BB
MD5_c = MD5_c + MD5_CC
MD5_d = MD5_d + MD5_DD
Next

Return Lower(WordToHex$(MD5_a) + WordToHex$(MD5_b) + WordToHex$(MD5_c) + WordToHex$(MD5_d))
End Function

Function MD5_F(x, y, z)
Return (x And y) Or (~(x) And z)
End Function

Function MD5_G(x, y, z)
Return (x And z) Or (y And (~(z)))
End Function

Function MD5_H(x, y, z)
Return (x Xor y Xor z)
End Function

Function MD5_I(x, y, z)
Return (y Xor (x Or (~(z))))
End Function

Function MD5_FF(a, b, c, d, x, s, ac)
a = (a + ((MD5_F(b, c, d)+ x)+ ac))
a = RotateLeft(a, s)
Return a + b
End Function

Function MD5_GG(a, b, c, d, x, s, ac)
a = (a + ((MD5_G(b, c, d) + x) + ac))
a = RotateLeft(a, s)
Return a + b
End Function

Function MD5_HH(a, b, c, d, x, s, ac)
a = (a + ((MD5_H(b, c, d) + x) + ac))
a = RotateLeft(a, s)
Return a + b
End Function

Function MD5_II(a, b, c, d, x, s, ac)
a = (a + ((MD5_I(b, c, d) + x) + ac))
a = RotateLeft(a, s)
Return a + b
End Function

Function RotateLeft(lValue, iShiftBits)
Return (lValue Shl iShiftBits) Or (lValue Shr (32 - iShiftBits))
End Function

Function WordToHex$(lValue)
For lCount = 0 To 3
lByte = (lValue Shr lCount * 8) And 255
ToHex$ = ToHex$ + Right("0" + Hex$(lByte), 2)
Next
Return ToHex$
End Function


XorSalt und ShiftString:
BlitzBasic: [AUSKLAPPEN]
Function XorS$(In$,Salt$)
While Len(Salt) < Len(In):Salt = Salt + Salt:Wend
For Pos = 1 To Len(In):Char = Asc(Mid(In,Pos,1)):CharS = Asc(Mid(Salt,Pos,1)):CharE = Char Xor CharS:Ret$ = Ret$ + Chr(CharE):Next
Return Ret$
End Function

Function ShiftString$(In$,PosNeg)
For Pos = 1 To Len(In):Char = Asc(Mid(In,Pos,1)):Char = (Char + PosNeg) Mod 256:While Char < 0:Char = Char + 256:Wend:Ret$ = Ret$ + Chr(Char):Next
Return Ret$
End Function

PHP:Code: [AUSKLAPPEN]
<?php
   function XorS($In,$Key) {
      while (strlen($Key) <= strlen($In)) {
         $Key += $Key;
      }
      
      for ($Pos = 1; $Pos <= strlen($In); $Pos++) {
         $IChar = substr($In,$Pos,1);
         $KChar = substr($Key,$Pos,1);
         
         $Ret += chr(ord($IChar) xor ord($KChar));
      }
      
      return $Ret;
   }
?>



3.1 Verschlüsselung der Punkte
Viele von euch kennen bereits bestimmte Methoden um Sachen zu verschlüsseln.
Ein paar davon sind Xor, Sha1, Sha128, Sha512. Von den angegebenen werden wir nur Xor(mit Salt) benötigen, da es am einfachsten implementiert ist.

Mal ein beispiel warum man es tun sollte:
Eine Person startet Wireshark und hat nebenbei euer Programm am laufen. Nun sieht er den kompletten HTTP Request von uns und kann diesen sehr einfach nachbauen.
Problem: Benutzer hat geschummelt
Ursache: Ungenügend Sicherheitsmaßnahmen
Lösung: Mehr Sicherheitsmaßnahmen einbauen(verschlüsseln)

Hier würden wir also nun irgendeinen auf beiden Plattformen verfügbaren Verschlüsselungsalgorythmus nehmen. Allerdings eignet sich nicht jeder für alles.

MD5 eignet sich zum Beispiel für Passwortübertragungen. Passwörter im Klartext zu übertragen ist, als wenn du leichtsinnig dein Passwort an Dritte weitergibst. Deshalb sollten diese IMMER verschlüsselt sein.
Punkte und Namen müssen nicht zu stark verschlüsselt werden, da man die auch wieder auslesen möchte. Hier reicht schon XOr(0x0=0,0x1=1,1x0=1,1x1=0) um etwas sicherer zu laufen.

Wir ändern also unsere Sendfunktion in BB und in PHP die [case "add"] um. Wir müssten lediglich die eingaben mit der XorS funktion verschlüsseln und entschlüsseln.
Beispiel:
Eingabe: Name=Jan&Punkte=29312
Verschlüsselung: Salt=asd89
Ergebnis: Name=+[DC2][N]&Punkte=SJW [VT][N]

Wenn wir das nun so übertragen würden, werden manche Webserver uns einen Fehler zurücksenden. Wir müssen also die nicht lesbaren Zeichen in HTTP %## Zeichen verwandeln. Das Geht mit folgender Funktion: BlitzBasic: [AUSKLAPPEN]
Function CharsToHTTP$(In$)
For Pos = 1 To Len(In)
Char = Asc(Mid(In,Pos,1))
If Not ((Char >= 48 And Char <= 57) Or (Char >= 65 And Char <= 90) Or (Char >= 97 And Char <= 122))
Ret$ = Ret$ + "%" + Right(Hex(Char),2)
Else
Ret$ = Ret$ + Chr(Char)
EndIf
Next
Return Ret$
End Function

Der HTTP Server wird uns nun wahrscheinlich keine Fehlermeldung mehr zurückliefern, da nun alles richtig ist.
Wir können nun also eine sicheren Online-Highscore erstellen.
Bearbeitete OHS_AddHighScore Funktion:BlitzBasic: [AUSKLAPPEN]
Global OHS_Salt$ = "Hallo Welt"
Function OHS_AddHighscore$(Name$, Punkte)
Local TCP,ExitCode$,StartMS
TCP = OpenTCPStream(HTTPServerAdress, 80)

;HTTP GET
WriteLine TCP, "GET "+HTTPServerFile+"?action=add&name="+CharstoHTTP(XorS(Name,OHS_Salt))+"&Punkte="+CharstoHTTP(XorS(Punkte,OHS_Salt))+" HTTP/1.1"
WriteLine TCP, ""

StartMS = MilliSecs()
While Eof(TCP)
If MilliSecs()-StartMS > OHS_TimeOut Then Exit
Delay 25
Wend

ExitCode$ = ReadLine(TCP)
While Not Eof(TCP)
DebugLog ReadLine(TCP)
Wend

Return ExitCode
End Function

Bearbeitete PHP [switch-case "add"]:Code: [AUSKLAPPEN]
case "add":
   mysql_query("INSERT INTO
      OnlineHighscore
   VALUES
      (".XorS($OHS_Spieler,$OHS_Salt).",".XorS($OHS_Punkte,$OHS_Salt).")") or die(mysql_error());
   break;



3.2 CAPTCHA zur vermeidung von Spammern
CAPTCHAs zu verwenden um Spammer zu vermeiden ist eine schwierige Sache auf beiden Seiten. Das PHP Skript muss ein System haben um CAPTCHAs zu generieren und in Bildform auszugeben, während das BB Programm dieses empfangen, anzeigen und Lösung übertragen muss, wo dann wieder das PHP Skript sich einschaltet um die Lösung zu überprüfen.
Ich gehe davon aus, dass jeder der diesen Teil liest, sich mindestens einmal mit CAPTCHAs beschäftigt hatte. Mit "beschäftigt hatte" meine ich nicht "Angefangen und Aufgegeben"!

Als erstes müssen wir wieder unsere [switch-case "add"] bearbeiten, damit er uns ein Captcha Bild zurückliefert. Wir ersetzen den dort stehen Code mit diesem Code: [AUSKLAPPEN]
         $CAPTCHA = GenerateCaptcha($CAPTCHA_Length, $CAPTCHA_Allowed);
         $result = mysql_query("SELECT
            TXT
         FROM
            OnlineHighscore_CAPTCHA
         WHERE
            IP = '".$GLOBAL_IP."'");
         if ($OHS_CAPTCHA != "") {
            if (mysql_num_rows($result)) {
               while ($row = mysql_fetch_assoc($result)) {
                  //Check if Captcha is OK
                  if ($row['TXT'] == $OHS_CAPTCHA) {
                     mysql_query("INSERT INTO
                        OnlineHighscore
                     VALUES
                        ('".$OHS_Spieler."','".$OHS_Punkte."')") or die(mysql_error());
                     mysql_query("DELETE FROM
                        OnlineHighscore_CAPTCHA
                     WHERE
                        IP = '{$GLOBAL_IP}'") or die(mysql_error());
                  } else {
                     mysql_query("DELETE FROM
                        OnlineHighscore_CAPTCHA
                     WHERE
                        IP = '{$GLOBAL_IP}'") or die(mysql_error());
                     mysql_query("INSERT INTO
                        OnlineHighscore_CAPTCHA
                     VALUES
                        ('{$GLOBAL_IP}','{$CAPTCHA}')") or die(mysql_error());
                     ReturnCaptchaIMG($CAPTCHA);
                  }
               }
            } else {
               mysql_query("DELETE FROM
                  OnlineHighscore_CAPTCHA
               WHERE
                  IP = '{$GLOBAL_IP}'") or die(mysql_error());
               mysql_query("INSERT INTO
                     OnlineHighscore_CAPTCHA
                  VALUES
                     ('{$GLOBAL_IP}','{$CAPTCHA}')") or die(mysql_error());
               ReturnCaptchaIMG($CAPTCHA);
            }
         } else {
            mysql_query("DELETE FROM
               OnlineHighscore_CAPTCHA
            WHERE
               IP = '".$GLOBAL_IP."'") or die(mysql_error());
            mysql_query("INSERT INTO
                     OnlineHighscore_CAPTCHA
                  VALUES
                     ('{$GLOBAL_IP}','{$CAPTCHA}')") or die(mysql_error());
            ReturnCaptchaIMG($CAPTCHA);
         }
         break;

Wer das skript nun ausführen will, bekommt mehrere Fehler. Warum? Ganz einfach: Ich habe 1 neue Tabelle und 2 neue Funktionen verwendet.
Code: [AUSKLAPPEN]
   mysql_query("CREATE TABLE IF NOT EXISTS OnlineHighscore (
      Name TEXT,
      Punkte INT)") or die(mysql_error());
   mysql_query("CREATE TABLE IF NOT EXISTS OnlineHighscore_CAPTCHA (
      IP TEXT,
      TXT TEXT)") or die(mysql_error());
   
   //Getting the Data
   $OHS_Action = $_GET['Action'];
   $OHS_Spieler = $_GET['Name'];
   $OHS_Punkte = $_GET['Punkte'];
   $OHS_CAPTCHA = $_GET['Captcha'];
   
   //Global Data
   $GLOBAL_IP = $_SERVER['REMOTE_ADDR'];
   
   //CAPTCHA Config
   $CAPTCHA_Length = 10;
   $CAPTCHA_Allowed = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

Code: [AUSKLAPPEN]
   function GenerateCaptcha($Length, $Allowed) {
      $txt = "";
      for ($Pos = 0; $Pos <= $Length-1; $Pos++) {
         $txt = $txt.substr($Allowed,rand(0,strlen($Allowed)-1),1);
      }
      return $txt;
   }
   
   function ReturnCaptchaIMG($SCpt) {
      header("Content-Type: image/png");
      //Main Defines
      $CharAreaW = 50;      //Character Area Width
      $CharAreaH = 50;      //Character Area Height
      $CharSize = 24;         //Character Font Size
      $CharFont = "Times.ttf";//Character Font
      
      $CaptchaLen = strlen($SCpt);
      
      //Create Image and clear it
      $im      = ImageCreateTrueColor($CharAreaW*$CaptchaLen,$CharAreaH);
      $bgclr   = ImageColorAllocate($im,0,0,0);
      ImageFilledRectangle($im, 0,0, $CharAreaW*$CaptchaLen, $CharAreaH, $bgclr);
      
      for ($Pos = 0; $Pos < $CaptchaLen; $Pos++) {
         $col = ImageColorAllocate($im,rand(204,255),rand(204,255),rand(204,255));
         $col2 = ImageColorAllocate($im,rand(0,153),rand(0,153),rand(0,153));
         $ang = rand(-45,45);
         $txt = substr($SCpt,$Pos,1);
         $arr = ImageTTFBBox($CharSize, $ang, $CharFont, $txt);
         
         $posx = $Pos*$CharAreaW+$CharAreaW/2-($arr[4]-$arr[0])/2;
         $posy = $CharAreaH/2-($arr[5]-$arr[1])/2;
         
         //Draw some Anti-Bot Rects
         ImageFilledRectangle($im, $Pos*$CharAreaW,0,$Pos*$CharAreaW+$CharAreaW,$CharAreaH, $col);
         ImageFilledRectangle($im, $Pos*$CharAreaW+1,1,$Pos*$CharAreaW+$CharAreaW-2,$CharAreaH-2, $col2);
         
         //DrawText
         ImageTTFText($im, $CharSize, 0, $posx, $posy, $col, $CharFont, $txt);
         
         //Draw some Anti-Bot Lines
         for ($C = 0; $C <= rand(1,5); $C++) {
            $col3 = ImageColorAllocate($im, rand(0,255), rand(0,255), rand(0,255));
            ImageLine($im, $Pos*$CharAreaW, rand(0,$CharAreaH), $Pos*$CharAreaW+$CharAreaW, rand(0,$CharAreaH), $col3);
            ImageLine($im, $Pos*$CharAreaW+rand(0,$CharAreaW), 0, $Pos*$CharAreaW+rand(0,$CharAreaW), $CharAreaH, $col3);
         }
      }

Wenn man nun das Skript ausführen will, erhält man keine Error mehr(Achtung: Manche Browser laden ein Bild zweimal!). Wie man sich nun darauf als Client einstellt ist relativ einfach fertiggestellt:
BlitzBasic: [AUSKLAPPEN]
Function OHS_AddHighscoreS1$()
Local TCP,ExitCode$,StartMS
TCP = OpenTCPStream(HTTPServerAdress, 80)

;HTTP GET
WriteLine TCP, "GET "+HTTPServerFile+"?Action=add HTTP/1.0"
WriteLine TCP, "Host: "+HTTPServerAdress
WriteLine TCP, ""

StartMS = MilliSecs()
While Eof(TCP)
If MilliSecs()-StartMS > OHS_TimeOut Then Exit
Delay 25
Wend

ExitCode = ReadLine(TCP)
While ReadLine(TCP) <> ""
Wend

Local F = WriteFile("Captcha.PNG")
While Not Eof(TCP)
WriteByte F,ReadByte(TCP)
Wend
CloseFile F

Return ExitCode
End Function

Function OHS_AddHighscoreS2$(Captcha$, Name$, Punkte$)
Local TCP,ExitCode$,StartMS
TCP = OpenTCPStream(HTTPServerAdress, 80)

;HTTP GET
WriteLine TCP, "GET "+HTTPServerFile+"?action=add&captcha="+CharsToHTTP(XorS(Captcha,OHS_Salt))+"&name="+CharsToHTTP(XorS(Name,OHS_Salt))+"&Punkte="+CharsToHTTP(XorS(Punkte,OHS_Salt))+" HTTP/1.1"
WriteLine TCP, "Host: "+HTTPServerAdress
WriteLine TCP, ""

StartMS = MilliSecs()
While Eof(TCP)
If MilliSecs()-StartMS > OHS_TimeOut Then Exit
Delay 25
Wend

ExitCode = ReadLine(TCP)
While ReadLine(TCP) <> ""
Wend

If ReadAvail(TCP) > 0
Local F = WriteFile("Captcha.PNG")
While Not Eof(TCP)
WriteByte F,ReadByte(TCP)
Wend
CloseFile F
EndIf

Return ExitCode
End Function

OHS_AddHighScoreS1() rufen wir auf wenn wir das Captcha Bild haben wollen.
OHS_AddHighScoreS2(CAPTCHA,Name,Punkte) rufen wir dann auf wenn überprüft werden soll, ob der Captcha stimmte. Falls nicht, wird ein neues Captcha Bild erstellt.

3.3 IPs ausschließen

Hierbei lassen wir das Skript einfach nicht auf die Clients antworten. Dazu müssen wir uns nur eine neue MySQL Tabelle anlegen:
Code: [AUSKLAPPEN]
   mysql_query("CREATE TABLE IF NOT EXISTS OnlineHighscore_BlockIP (
      IP TEXT)") or die(mysql_error());

In die Tabelle kommen dann alle geblockten IPs rein.

Komplette PHP Highscore blocken:
Unter "$GLOBAL_IP = $_SERVER['REMOTE_ADDR'];" fügen wir dazu folgendes ein:
Code: [AUSKLAPPEN]
$result = mysql_query("SELECT
      IP
   FROM
      OnlineHighscore_BlockIP
   WHERE
      IP = '{$GLOBAL_IP}'");
   if (mysql_num_rows($result)) {
      die();
   }


Hinzufügen von Highscores blocken:
Unter "case "add": //Add Entry" fügen wir dazu folgendes ein:
Code: [AUSKLAPPEN]
         $result = mysql_query("SELECT
            IP
         FROM
            OnlineHighscore_BlockIP
         WHERE
            IP = '{$GLOBAL_IP}'");
         if (mysql_num_rows($result)) {
            die();
         }


Andere Methoden gehen ähnlich
Warbseite
  • Zuletzt bearbeitet von Xaymar am Sa, März 27, 2010 0:38, insgesamt 2-mal bearbeitet

Xaymar

ehemals "Cgamer"

Betreff: 4. Sicherheit

BeitragMo, Feb 22, 2010 15:18
Antworten mit Zitat
Benutzer-Profile anzeigen
4. Sicherheit

Vielmals wird man geradezu überhäuft mit Hack Angriffen und sonstigem. Doch für alles lässt sich eine Lösung finden.

4.1 SQL Injection

Immoment verarbeitet unser Code das, was wir ihm über GET senden. Ziemlich anfällig für SQL Injection.
Was wäre wenn wir nun also nicht unser Programm mehr beim Zugriff haben sondern nun einen "normalen" Benutzer und er würde folgendes tippen: "...?Action=red;TRUNCATE TABLE OnlineHighscore;"?
Richtig, unsere gespeicherten Highscores wären weg.

Zum Glück gibt es eine Funktion die uns vieles abnimmt: MySQL_Real_Escape_String(). Diese müssen wir nur um unsere $_GET[...] setzen.
Code: [AUSKLAPPEN]
$OHS_Action = MySQL_Real_Escape_String($_GET['Action']);
   $OHS_Spieler = MySQL_Real_Escape_String($_GET['Name']);
   $OHS_Punkte = MySQL_Real_Escape_String($_GET['Punkte']);
   $OHS_CAPTCHA = MySQL_Real_Escape_String($_GET['Captcha']);


Jetzt wären wir so ziemlich sicher vor Standart SQL Injection Attacken. Es gibt eine Methode mit der wir das sogar noch verbessern können: Die Variablen verschlüsselt speichern! Diese ist weitaus schwieriger, wenn nicht sogar unmöglich, zu knacken.
Wir verändern dazu nur unsere mysql_querys und zwar setzen wir bei jedem Auslesen oder Einfügen ein XorS([DER EIGENTLICHE TEXT],[DER HASH]) hin.
[case "add":]
Code: [AUSKLAPPEN]
         if ($OHS_CAPTCHA != "") {
            if (mysql_num_rows($result)) {
               while ($row = mysql_fetch_assoc($result)) {
                  //Check if Captcha is OK
                  if ($row['TXT'] == XorS($OHS_CAPTCHA,$Hash)) {
                     mysql_query("INSERT INTO
                        OnlineHighscore
                     VALUES
                        ('".XorS($OHS_Spieler,$Hash)."','".XorS($OHS_Punkte,$Hash)."')") or die(mysql_error());
                     mysql_query("DELETE FROM
                        OnlineHighscore_CAPTCHA
                     WHERE
                        IP = '{$GLOBAL_IP}'") or die(mysql_error());
                  } else {
                     mysql_query("DELETE FROM
                        OnlineHighscore_CAPTCHA
                     WHERE
                        IP = '{$GLOBAL_IP}'") or die(mysql_error());
                     mysql_query("INSERT INTO
                        OnlineHighscore_CAPTCHA
                     VALUES
                        ('{$GLOBAL_IP}','".XorS($CAPTCHA,$Hash)."')") or die(mysql_error());
                     ReturnCaptchaIMG($CAPTCHA);
                  }
               }
            } else {
               mysql_query("DELETE FROM
                  OnlineHighscore_CAPTCHA
               WHERE
                  IP = '{$GLOBAL_IP}'") or die(mysql_error());
               mysql_query("INSERT INTO
                     OnlineHighscore_CAPTCHA
                  VALUES
                     ('{$GLOBAL_IP}','".XorS($CAPTCHA,$Hash)."')") or die(mysql_error());
               ReturnCaptchaIMG($CAPTCHA);
            }
         } else {
            mysql_query("DELETE FROM
               OnlineHighscore_CAPTCHA
            WHERE
               IP = '".$GLOBAL_IP."'") or die(mysql_error());
            mysql_query("INSERT INTO
                     OnlineHighscore_CAPTCHA
                  VALUES
                     ('{$GLOBAL_IP}','".XorS($CAPTCHA,$Hash)."')") or die(mysql_error());
            ReturnCaptchaIMG($CAPTCHA);
         }

[case "rem":]
Code: [AUSKLAPPEN]
         mysql_query("DELETE FROM
            OnlineHighscore
         WHERE
            Name = '".XorS($OHS_Spieler,$Hash)."' AND
            Punkte = '".XorS($OHS_Punkte,$Hash)."'") or die(mysql_error());

[case "red":]
Code: [AUSKLAPPEN]
         $result = mysql_query("SELECT
            Name,
            Punkte
         FROM
            OnlineHighscore
         ORDER BY
            Punkte DESC");   //ASC = Aufwärts sortiert, DESC = Abwärts sortiert
         $CurrentPlace = 1;
         if (mysql_num_rows($result)) {
            while ($row = mysql_fetch_assoc($result)) {
               //Ausgabecode der Liste
               echo $CurrentPlace+"\r\n";
               echo XorS($row['Name'],$Hash)+"\r\n";
               echo XorS($row['Punkte'],$Hash)+"\r\n";
               $CurrentPlace += 1;
            }
         }


Und damit wäre dieses Tutorial abgeschlossen. Im nächsten Beitrag findet ihr den vollen BB und PHP Code.
Warbseite
  • Zuletzt bearbeitet von Xaymar am Sa, März 27, 2010 15:02, insgesamt einmal bearbeitet

Xaymar

ehemals "Cgamer"

BeitragMo, Feb 22, 2010 15:25
Antworten mit Zitat
Benutzer-Profile anzeigen
Vollständiger PHP Code
Code: [AUSKLAPPEN]
<?php
   //MySQL Connection Data
   $SQL_User = "ohs";      //Benutzername
   $SQL_Pass = "ohshs";      //Passwort
   $SQL_Host = "localhost";      //SQL Host
   $SQL_DaBa = "ohs";      //Datenbank auf die zugegriffen wird
   
   //MySQL Connection
   mysql_connect($SQL_Host,$SQL_User,$SQL_Pass) OR die(mysql_error());
   mysql_selectdb($SQL_DaBa) OR die(mysql_error());
   
   //Der Rest des Codes hier drunter
   mysql_query("CREATE TABLE IF NOT EXISTS OnlineHighscore (
      Name TEXT,
      Punkte INT)") or die(mysql_error());
   mysql_query("CREATE TABLE IF NOT EXISTS OnlineHighscore_CAPTCHA (
      IP TEXT,
      TXT TEXT)") or die(mysql_error());
   mysql_query("CREATE TABLE IF NOT EXISTS OnlineHighscore_BlockIP (
      IP TEXT,
      Mode INT)") or die(mysql_error());
   
   //Global Data
   $GLOBAL_IP = $_SERVER['REMOTE_ADDR'];
   $Hash = md5($CAPTCHA_Allowed);
   $OHS_Hash = "Hallo Welt";
   $result = mysql_query("SELECT
      IP,
      Mode
   FROM
      OnlineHighscore_BlockIP
   WHERE
      IP = '{$GLOBAL_IP}'");
   if (mysql_num_rows($result)) {
      while ($row = mysql_fetch_assoc($result)) {
         if ($row['Mode'] == 0) {
            die();
         }
      }
   }
   
   //CAPTCHA Config
   $CAPTCHA_Length = 10;
   $CAPTCHA_Allowed = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
   
   //Getting the Data
   $OHS_Action = MySQL_Real_Escape_String($_GET['Action']);
   $OHS_Spieler = MySQL_Real_Escape_String(XorS($_GET['Name'],$OHS_Salt));
   $OHS_Punkte = MySQL_Real_Escape_String(XorS($_GET['Punkte'],$OHS_Salt));
   $OHS_CAPTCHA = MySQL_Real_Escape_String(XorS($_GET['Captcha'],$OHS_Salt));
   
   switch($OHS_Action) {
      case "add":      //Add Entry
         $result = mysql_query("SELECT
            IP,
            Mode
         FROM
            OnlineHighscore_BlockIP
         WHERE
            IP = '{$GLOBAL_IP}'");
         if (mysql_num_rows($result)) {
            while ($row = mysql_fetch_assoc($result)) {
               if ($row['Mode'] == 1) {
                  die();
               }
            }
         }
         $CAPTCHA = GenerateCaptcha($CAPTCHA_Length, $CAPTCHA_Allowed);
         $result = mysql_query("SELECT
            TXT
         FROM
            OnlineHighscore_CAPTCHA
         WHERE
            IP = '".$GLOBAL_IP."'");
         if ($OHS_CAPTCHA != "") {
            if (mysql_num_rows($result)) {
               while ($row = mysql_fetch_assoc($result)) {
                  //Check if Captcha is OK
                  if ($row['TXT'] == XorS($OHS_CAPTCHA,$Hash)) {
                     mysql_query("INSERT INTO
                        OnlineHighscore
                     VALUES
                        ('".XorS($OHS_Spieler,$Hash)."','".XorS($OHS_Punkte,$Hash)."')") or die(mysql_error());
                     mysql_query("DELETE FROM
                        OnlineHighscore_CAPTCHA
                     WHERE
                        IP = '{$GLOBAL_IP}'") or die(mysql_error());
                  } else {
                     mysql_query("DELETE FROM
                        OnlineHighscore_CAPTCHA
                     WHERE
                        IP = '{$GLOBAL_IP}'") or die(mysql_error());
                     mysql_query("INSERT INTO
                        OnlineHighscore_CAPTCHA
                     VALUES
                        ('{$GLOBAL_IP}','".XorS($CAPTCHA,$Hash)."')") or die(mysql_error());
                     ReturnCaptchaIMG($CAPTCHA);
                  }
               }
            } else {
               mysql_query("DELETE FROM
                  OnlineHighscore_CAPTCHA
               WHERE
                  IP = '{$GLOBAL_IP}'") or die(mysql_error());
               mysql_query("INSERT INTO
                     OnlineHighscore_CAPTCHA
                  VALUES
                     ('{$GLOBAL_IP}','".XorS($CAPTCHA,$Hash)."')") or die(mysql_error());
               ReturnCaptchaIMG($CAPTCHA);
            }
         } else {
            mysql_query("DELETE FROM
               OnlineHighscore_CAPTCHA
            WHERE
               IP = '".$GLOBAL_IP."'") or die(mysql_error());
            mysql_query("INSERT INTO
                     OnlineHighscore_CAPTCHA
                  VALUES
                     ('{$GLOBAL_IP}','".XorS($CAPTCHA,$Hash)."')") or die(mysql_error());
            ReturnCaptchaIMG($CAPTCHA);
         }
         break;
      case "rem":      //Remove Entry
         $result = mysql_query("SELECT
            IP,
            Mode
         FROM
            OnlineHighscore_BlockIP
         WHERE
            IP = '{$GLOBAL_IP}'");
         if (mysql_num_rows($result)) {
            while ($row = mysql_fetch_assoc($result)) {
               if ($row['Mode'] == 2) {
                  die();
               }
            }
         }
         mysql_query("DELETE FROM
            OnlineHighscore
         WHERE
            Name = '".XorS($OHS_Spieler,$Hash)."' AND
            Punkte = '".XorS($OHS_Punkte,$Hash)."'") or die(mysql_error());
         break;
      case "red":      //Read Highscore
         $result = mysql_query("SELECT
            IP,
            Mode
         FROM
            OnlineHighscore_BlockIP
         WHERE
            IP = '{$GLOBAL_IP}'");
         if (mysql_num_rows($result)) {
            while ($row = mysql_fetch_assoc($result)) {
               if ($row['Mode'] == 3) {
                  die();
               }
            }
         }
         $result = mysql_query("SELECT
            Name,
            Punkte
         FROM
            OnlineHighscore
         ORDER BY
            Punkte DESC");   //ASC = Aufwärts sortiert, DESC = Abwärts sortiert
         $CurrentPlace = 1;
         if (mysql_num_rows($result)) {
            while ($row = mysql_fetch_assoc($result)) {
               //Ausgabecode der Liste
               echo $CurrentPlace+"\r\n";
               echo XorS($row['Name'],$Hash)+"\r\n";
               echo XorS($row['Punkte'],$Hash)+"\r\n";
               $CurrentPlace += 1;
            }
         }
         break;
   }
   
   function GenerateCaptcha($Length, $Allowed) {
      $txt = "";
      for ($Pos = 0; $Pos <= $Length-1; $Pos++) {
         $txt = $txt.substr($Allowed,rand(0,strlen($Allowed)-1),1);
      }
      return $txt;
   }
   
   function ReturnCaptchaIMG($SCpt) {
      header("Content-Type: image/png");
      //Main Defines
      $CharAreaW = 50;      //Character Area Width
      $CharAreaH = 50;      //Character Area Height
      $CharSize = 24;         //Character Font Size
      $CharFont = "Times.ttf";//Character Font
      
      $CaptchaLen = strlen($SCpt);
      
      //Create Image and clear it
      $im      = ImageCreateTrueColor($CharAreaW*$CaptchaLen,$CharAreaH);
      $bgclr   = ImageColorAllocate($im,0,0,0);
      ImageFilledRectangle($im, 0,0, $CharAreaW*$CaptchaLen, $CharAreaH, $bgclr);
      
      for ($Pos = 0; $Pos < $CaptchaLen; $Pos++) {
         $col = ImageColorAllocate($im,rand(204,255),rand(204,255),rand(204,255));
         $col2 = ImageColorAllocate($im,rand(0,153),rand(0,153),rand(0,153));
         $ang = rand(-45,45);
         $txt = substr($SCpt,$Pos,1);
         $arr = ImageTTFBBox($CharSize, $ang, $CharFont, $txt);
         
         $posx = $Pos*$CharAreaW+$CharAreaW/2-($arr[4]-$arr[0])/2;
         $posy = $CharAreaH/2-($arr[5]-$arr[1])/2;
         
         //Draw some Anti-Bot Rects
         ImageFilledRectangle($im, $Pos*$CharAreaW,0,$Pos*$CharAreaW+$CharAreaW,$CharAreaH, $col);
         ImageFilledRectangle($im, $Pos*$CharAreaW+1,1,$Pos*$CharAreaW+$CharAreaW-2,$CharAreaH-2, $col2);
         
         //DrawText
         ImageTTFText($im, $CharSize, 0, $posx, $posy, $col, $CharFont, $txt);
         
         //Draw some Anti-Bot Lines
         for ($C = 0; $C <= rand(1,5); $C++) {
            $col3 = ImageColorAllocate($im, rand(0,255), rand(0,255), rand(0,255));
            ImageLine($im, $Pos*$CharAreaW, rand(0,$CharAreaH), $Pos*$CharAreaW+$CharAreaW, rand(0,$CharAreaH), $col3);
            ImageLine($im, $Pos*$CharAreaW+rand(0,$CharAreaW), 0, $Pos*$CharAreaW+rand(0,$CharAreaW), $CharAreaH, $col3);
         }
      }
      
      imagepng($im);
      imagedestroy($im);
   }
   
   function XorS($In,$Key) {
      while (strlen($Key) <= strlen($In)) {
         $Key += $Key;
      }
      
      for ($Pos = 1; $Pos <= strlen($In); $Pos++) {
         $IChar = substr($In,$Pos,1);
         $KChar = substr($Key,$Pos,1);
         
         $Ret += chr(ord($IChar) xor ord($KChar));
      }
      
      return $Ret;
   }
   //Der Rest des Codes hier drüber
?>


Vollständiger BlitzBasic Code:
BlitzBasic: [AUSKLAPPEN]
Global HTTPServerAdress$ = "127.0.0.1"
Global HTTPServerFile$ = "/Web/OnlineHighscore.php"
Global OHS_TimeOut = 1000
Global OHS_Salt$ = "Hallo Welt"

Type OHS_Highscores
Field Place
Field Name$
Field Score
End Type

Function OHS_RemHighscore$(Name$, Punkte)
Local TCP,ExitCode$,StartMS
TCP = OpenTCPStream(HTTPServerAdress, 80)

;HTTP GET
WriteLine TCP, "GET "+HTTPServerFile+"?action=rem&name="+Name+"&Punkte="+Punkte+" HTTP/1.0"
WriteLine TCP, "Host: "+HTTPServerAdress
WriteLine TCP, ""

StartMS = MilliSecs()
While Eof(TCP)
If MilliSecs()-StartMS > OHS_TimeOut Then Exit
Delay 25
Wend

ExitCode$ = ReadLine(TCP)
While Not Eof(TCP)
DebugLog ReadLine(TCP)
Wend

Return ExitCode
End Function

Function OHS_GetHighscore$()
Local TCP,ExitCode$,StartMS
TCP = OpenTCPStream(HTTPServerAdress, 80)

;HTTP GET
WriteLine TCP, "GET "+HTTPServerFile+"?action=red HTTP/1.0"
WriteLine TCP, "Host: "+HTTPServerAdress
WriteLine TCP, ""

StartMS = MilliSecs()
While Eof(TCP)
If MilliSecs()-StartMS > OHS_TimeOut Then Exit
Delay 25
Wend

ExitCode$ = ReadLine(TCP)
Repeat
Local Ln$ = ReadLine(TCP)
DebugLog Ln$
If Ln$ = ""
While Not Eof(TCP)
Local OHSE.OHS_Highscores = New OHS_Highscores
OHSE\Place = ReadLine(TCP)
OHSE\Name = ReadLine(TCP)
OHSE\Score = ReadLine(TCP)
Wend
EndIf
Until Eof(TCP)

Return ExitCode
End Function

Function OHS_AddHighscoreS1$()
Local TCP,ExitCode$,StartMS
TCP = OpenTCPStream(HTTPServerAdress, 80)

;HTTP GET
WriteLine TCP, "GET "+HTTPServerFile+"?Action=add HTTP/1.0"
WriteLine TCP, "Host: "+HTTPServerAdress
WriteLine TCP, ""

StartMS = MilliSecs()
While Eof(TCP)
If MilliSecs()-StartMS > OHS_TimeOut Then Exit
Delay 25
Wend

ExitCode = ReadLine(TCP)
While ReadLine(TCP) <> ""
Wend

Local F = WriteFile("Captcha.PNG")
While Not Eof(TCP)
WriteByte F,ReadByte(TCP)
Wend
CloseFile F

Return ExitCode
End Function

Function OHS_AddHighscoreS2$(Captcha$, Name$, Punkte$)
Local TCP,ExitCode$,StartMS
TCP = OpenTCPStream(HTTPServerAdress, 80)

;HTTP GET
WriteLine TCP, "GET "+HTTPServerFile+"?action=add&captcha="+CharsToHTTP(XorS(Captcha,OHS_Salt))+"&name="+CharsToHTTP(XorS(Name,OHS_Salt))+"&Punkte="+CharsToHTTP(XorS(Punkte,OHS_Salt))+" HTTP/1.1"
WriteLine TCP, "Host: "+HTTPServerAdress
WriteLine TCP, ""

StartMS = MilliSecs()
While Eof(TCP)
If MilliSecs()-StartMS > OHS_TimeOut Then Exit
Delay 25
Wend

ExitCode = ReadLine(TCP)
While ReadLine(TCP) <> ""
Wend

If ReadAvail(TCP) > 0
Local F = WriteFile("Captcha.PNG")
While Not Eof(TCP)
WriteByte F,ReadByte(TCP)
Wend
CloseFile F
EndIf

Return ExitCode
End Function

Dim MD5_x(0)

Function MD5$(sMessage$)

;Pads the String as per the MD5 standard
nblk = ((Len(sMessage$) + 8) Shr 6) + 1 ;number of 16-word blocks

Dim MD5_x(nblk * 16 - 1)
;Zero pad the string
For i = 0 To nblk * 16 - 1
MD5_x(i) = 0
Next
;Convert to array of "words"
For i = 0 To (Len(sMessage$) - 1)
MD5_x((i Shr 2)) = MD5_x((i Shr 2)) Or (Asc(Mid(sMessage$, (i + 1), 1)) Shl ((i Mod 4) * 8))
Next
MD5_x((i Shr 2)) = MD5_x((i Shr 2)) Or (128 Shl (((i) Mod 4) * 8))
MD5_x(nblk * 16 - 2) = Len(sMessage$) * 8

;Set initial values
MD5_a = 1732584193 ;&H67452301
MD5_b = -271733879 ;&HEFCDAB89
MD5_c = -1732584194 ;&H98BADCFE
MD5_d = 271733878 ;&H10325476

;Loop through the words
For k = 0 To (nblk * 16 - 1) Step 16
MD5_AA = MD5_a
MD5_BB = MD5_b
MD5_CC = MD5_c
MD5_DD = MD5_d
;Round 1
MD5_a = MD5_FF(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 0), 7, -680876936) ;&HD76AA478
MD5_d = MD5_FF(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 1), 12, -389564586) ;&HE8C7B756
MD5_c = MD5_FF(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 2), 17, 606105819 );&H242070DB
MD5_b = MD5_FF(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 3), 22, -1044525330) ;&HC1BDCEEE
MD5_a = MD5_FF(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 4), 7, -176418897) ;&HF57C0FAF
MD5_d = MD5_FF(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 5), 12, 1200080426 );&H4787C62A
MD5_c = MD5_FF(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 6), 17, -1473231341) ;&HA8304613
MD5_b = MD5_FF(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 7), 22, -45705983) ;&HFD469501
MD5_a = MD5_FF(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 8), 7, 1770035416) ;&H698098D8
MD5_d = MD5_FF(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 9), 12, -1958414417 );&H8B44F7AF
MD5_c = MD5_FF(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 10), 17, -42063 );&HFFFF5BB1
MD5_b = MD5_FF(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 11), 22, -1990404162) ;&H895CD7BE
MD5_a = MD5_FF(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 12), 7, 1804603682) ;&H6B901122
MD5_d = MD5_FF(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 13), 12, -40341101) ;&HFD987193
MD5_c = MD5_FF(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 14), 17, -1502002290) ;&HA679438E
MD5_b = MD5_FF(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 15), 22, 1236535329) ;&H49B40821
;Round 2
MD5_a = MD5_GG(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 1), 5, -165796510) ;&HF61E2562
MD5_d = MD5_GG(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 6), 9, -1069501632) ;&HC040B340
MD5_c = MD5_GG(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 11), 14, 643717713) ;&H265E5A51
MD5_b = MD5_GG(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 0), 20, -373897302) ;&HE9B6C7AA
MD5_a = MD5_GG(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 5), 5, -701558691) ;&HD62F105D
MD5_d = MD5_GG(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 10), 9, 38016083) ;&H2441453
MD5_c = MD5_GG(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 15), 14, -660478335) ;&HD8A1E681
MD5_b = MD5_GG(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 4), 20, -405537848) ;&HE7D3FBC8
MD5_a = MD5_GG(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 9), 5, 568446438) ;&H21E1CDE6
MD5_d = MD5_GG(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 14), 9, -1019803690) ;&HC33707D6
MD5_c = MD5_GG(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 3), 14, -187363961) ;&HF4D50D87
MD5_b = MD5_GG(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 8), 20, 1163531501) ;&H455A14ED
MD5_a = MD5_GG(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 13), 5, -1444681467) ;&HA9E3E905
MD5_d = MD5_GG(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 2), 9, -51403784) ;&HFCEFA3F8
MD5_c = MD5_GG(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 7), 14, 1735328473) ;&H676F02D9
MD5_b = MD5_GG(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 12), 20, -1926607734) ;&H8D2A4C8A
;Round 3
MD5_a = MD5_HH(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 5), 4, -378558) ;&HFFFA3942
MD5_d = MD5_HH(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 8), 11, -2022574463) ;&H8771F681
MD5_c = MD5_HH(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 11), 16, 1839030562) ;&H6D9D6122
MD5_b = MD5_HH(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 14), 23, -35309556) ;&HFDE5380C
MD5_a = MD5_HH(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 1), 4, -1530992060) ;&HA4BEEA44
MD5_d = MD5_HH(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 4), 11, 1272893353) ;&H4BDECFA9
MD5_c = MD5_HH(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 7), 16, -155497632) ;&HF6BB4B60
MD5_b = MD5_HH(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 10), 23, -1094730640) ;&HBEBFBC70
MD5_a = MD5_HH(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 13), 4, 681279174) ;&H289B7EC6
MD5_d = MD5_HH(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 0), 11, -358537222) ;&HEAA127FA
MD5_c = MD5_HH(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 3), 16, -722521979) ;&HD4EF3085
MD5_b = MD5_HH(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 6), 23, 76029189) ;&H4881D05
MD5_a = MD5_HH(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 9), 4, -640364487) ;&HD9D4D039
MD5_d = MD5_HH(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 12), 11, -421815835) ;&HE6DB99E5
MD5_c = MD5_HH(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 15), 16, 530742520) ;&H1FA27CF8
MD5_b = MD5_HH(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 2), 23, -995338651) ;&HC4AC5665
;Round 4
MD5_a = MD5_II(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 0), 6, -198630844) ;&HF4292244
MD5_d = MD5_II(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 7), 10, 1126891415) ;&H432AFF97
MD5_c = MD5_II(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 14), 15, -1416354905) ;&HAB9423A7
MD5_b = MD5_II(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 5), 21, -57434055) ;&HFC93A039
MD5_a = MD5_II(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 12), 6, 1700485571) ;&H655B59C3
MD5_d = MD5_II(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 3), 10, -1894986606) ;&H8F0CCC92
MD5_c = MD5_II(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 10), 15, -1051523) ;&HFFEFF47D
MD5_b = MD5_II(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 1), 21, -2054922799) ;&H85845DD1
MD5_a = MD5_II(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 8), 6, 1873313359) ;&H6FA87E4F
MD5_d = MD5_II(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 15), 10, -30611744) ;&HFE2CE6E0
MD5_c = MD5_II(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 6), 15, -1560198380 );&HA3014314
MD5_b = MD5_II(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 13), 21, 1309151649) ;&H4E0811A1
MD5_a = MD5_II(MD5_a, MD5_b, MD5_c, MD5_d, MD5_x(k + 4), 6, -145523070) ;&HF7537E82
MD5_d = MD5_II(MD5_d, MD5_a, MD5_b, MD5_c, MD5_x(k + 11), 10, -1120210379) ;&HBD3AF235
MD5_c = MD5_II(MD5_c, MD5_d, MD5_a, MD5_b, MD5_x(k + 2), 15, 718787259) ;&H2AD7D2BB
MD5_b = MD5_II(MD5_b, MD5_c, MD5_d, MD5_a, MD5_x(k + 9), 21, -343485551) ;&HEB86D391

MD5_a = MD5_a + MD5_AA
MD5_b = MD5_b + MD5_BB
MD5_c = MD5_c + MD5_CC
MD5_d = MD5_d + MD5_DD
Next

Return Lower(WordToHex$(MD5_a) + WordToHex$(MD5_b) + WordToHex$(MD5_c) + WordToHex$(MD5_d))
End Function

Function MD5_F(x, y, z)
Return (x And y) Or (~(x) And z)
End Function

Function MD5_G(x, y, z)
Return (x And z) Or (y And (~(z)))
End Function

Function MD5_H(x, y, z)
Return (x Xor y Xor z)
End Function

Function MD5_I(x, y, z)
Return (y Xor (x Or (~(z))))
End Function

Function MD5_FF(a, b, c, d, x, s, ac)
a = (a + ((MD5_F(b, c, d)+ x)+ ac))
a = RotateLeft(a, s)
Return a + b
End Function

Function MD5_GG(a, b, c, d, x, s, ac)
a = (a + ((MD5_G(b, c, d) + x) + ac))
a = RotateLeft(a, s)
Return a + b
End Function

Function MD5_HH(a, b, c, d, x, s, ac)
a = (a + ((MD5_H(b, c, d) + x) + ac))
a = RotateLeft(a, s)
Return a + b
End Function

Function MD5_II(a, b, c, d, x, s, ac)
a = (a + ((MD5_I(b, c, d) + x) + ac))
a = RotateLeft(a, s)
Return a + b
End Function

Function RotateLeft(lValue, iShiftBits)
Return (lValue Shl iShiftBits) Or (lValue Shr (32 - iShiftBits))
End Function

Function WordToHex$(lValue)
For lCount = 0 To 3
lByte = (lValue Shr lCount * 8) And 255
ToHex$ = ToHex$ + Right("0" + Hex$(lByte), 2)
Next
Return ToHex$
End Function

Function XorS$(In$,Salt$)
While Len(Salt) < Len(In):Salt = Salt + Salt:Wend
For Pos = 1 To Len(In):Char = Asc(Mid(In,Pos,1)):CharS = Asc(Mid(Salt,Pos,1)):CharE = Char Xor CharS:Ret$ = Ret$ + Chr(CharE):Next
Return Ret$
End Function

Function ShiftString$(In$,PosNeg)
For Pos = 1 To Len(In):Char = Asc(Mid(In,Pos,1)):Char = (Char + PosNeg) Mod 256:While Char < 0:Char = Char + 256:Wend:Ret$ = Ret$ + Chr(Char):Next
Return Ret$
End Function

Function CharsToHTTP$(In$)
For Pos = 1 To Len(In)
Char = Asc(Mid(In,Pos,1))
If Not ((Char >= 48 And Char <= 57) Or (Char >= 65 And Char <= 90) Or (Char >= 97 And Char <= 122))
Ret$ = Ret$ + "%" + Right(Hex(Char),2)
Else
Ret$ = Ret$ + Chr(Char)
EndIf
Next
Return Ret$
End Function


Das Tutorial wäre hiermit komplett beendet. Ihr dürft hier nun reinschreiben.

Nachtrag: Übrigends haben CopyPaster schlechte Karten. Jeder weiß ja wie euer Quellcode aufgebaut ist.
Warbseite
  • Zuletzt bearbeitet von Xaymar am Sa, März 27, 2010 15:03, insgesamt einmal bearbeitet

Entenfels

BeitragMo, Feb 22, 2010 21:27
Antworten mit Zitat
Benutzer-Profile anzeigen
Danke!!! Very Happy Very Happy Very Happy
Darauf hab ich gewartet!
Die Details sind zu 94 Prozent zutreffend, bei sechs Prozent unvermeidbarer Extrapolation.
-Artemis Fowl von Eoin Colfer

Neue Antwort erstellen


Übersicht BlitzBasic FAQ und Tutorials

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group