Schalla Geschrieben 22. Juli 2013 Melden Share Geschrieben 22. Juli 2013 Hallo zusammen, ich bin persönlich ein Neuling im Umgang mit Unity, bin allerdings seit 4-5 Jahren in der Webentwicklung tätig. Um auch mal etwas dabei zu steuern, werde ich ein kleines Tutorial zum Thema PHP Keygenerator mit Unityintegration erstellen. 1. Was wird benötigt? Webserver inkl. PHP und mySQL Unity Ein Spiel ( ) 2. Die Serverseite Die Serverseite ist relativ einfach zu erklären. Sie besteht aus folgenden Teilen: PHP Files: config.php (Einstellen der Datenbank Daten sowie Keyoptionen) generate_keys.php (Erstellung der Keys für das Spiel) validate_key.php (Abfrage ob Key valide ist) Datenbank: Tabelle: keyskeys_id keys_code keys_used Wir fangen mit der Datenbank an: Die Datenbank beinhaltet, wie der Name schon sagt, die Keys. Ein Key enthält drei Daten hier: keys_id: Einzigartige ID welche jeden Key zuweisen lässt, ist hier eher unwichtig, allerdings sofern man etwas komplizeres macht in Form eines Systemes wo User Keys zugewiesen sind, ist sowas von nöten. keys_code: Der Code ansich, welcher nach euren Paramtern erstellt worden ist keys_used: Integer Wert welcher definiert ob der Key schon genutzt worden ist. Kommen wir danach zu den PHP Scripts. Die config.php definiert grob gesagt einfach wie was eingestellt ist, hier der kommentierte Inhalt: <?php //Open Database Connection $db=new PDO('mysql:host=localhost;dbname=<DB>;',"<USER>",'<PWD>', array( PDO::ATTR_PERSISTENT =-> true, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION , PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC )); //Set Game Secreat (Avoids public access e.g.) $gamesecret='V@w&Kp-c'; $internpw='unityforever'; //Key Settings $keysetting['parts']=4; //How many parts the key has? $keysetting['partlength']=5; //A part got how many chars? $keysetting['splittedby']="-"; //Which char connect the parts? $keysetting['keychars']="ABCEDFGHIJKLMOPQRSTUVWXYZ123456789"; //Which chars will be used? Die config.php definiert wie ihr seht einige globale Einstellungen, sie wird am Anfang von den beiden anderen Dateien included. Die Datei validate_key.php überprüft ob ein Key... ...existiert ...schonmal benutzt worden ist. Und gibt in Abhängig davon einen Wert zurück welcher von Unity interpretiert werden kann. Der Aufbau ist relativ einfach: <?php require_once("config.php"); //Is the correct gamesecret used? This is against random access e.g. for bruteforcing keys if($_GET['gamesecret']==$gamesecret){ $query=$db->prepare("SELECT keys_id,keys_used FROM `keys` WHERE keys_code=:key"); //Search for Keys with this code $query->execute(array(":key"=>$_GET['key'])); //Implement our Key in the Query (Used against SQL. Injections) $data=$query->fetch(); //Fetch the result data if($data===false){ echo "Key doesn't exist."; //No entry was found }else{ if($data['keys_used']=="0"){ echo "Login Success."; //The key exists and wasn't used yet $db->query("UPDATE `keys` SET keys_used='1' WHERE keys_id=".$data['keys_id']); }else{ echo "Key already used."; //The key exists, but was used already } } } Er fragt ab ob ein Key existiert und sofern er existiert, ob er bereits genutzt worden ist. Sofern er existiert und nicht benutzt worden ist, gibt er "Login success." zurück und beschreibt die Datenbank mit keys_used=1, somit ist der Key danach benutzt. Als nächstes folgt unsere generate_keys.php: <?php session_start(); //Starts the Session Managment require_once("config.php"); if(isset($_POST['pwd']) && $_POST['pwd']==$internpw){ //Was the loginform sended + the pw correct? $_SESSION['logged']=true; } if(isset($_SESSION['logged']) && $_SESSION['logged']==true){ //Is the user logged in? if(isset($_POST['amount'])){ //The form was sent? $keylist=""; //Create empty Var for all the keys $query=$db->prepare("INSERT INTO `keys` SET keys_code=:key"); //Prepare the SQL Query $secruityquery=$db->prepare("SELECT keys_id FROM `keys` WHERE keys_code=:key"); $maxarrayid=strlen($keysetting['keychars'])-1; //How many chars we have in our keychars list? for($i=0;$i<intval($_POST['amount']);$i++){ //Create all keys $key=""; //Loop for each part for($partsnow=0;$partsnow<$keysetting['parts'];$partsnow++){ //Loop for each string of the part for($partlengthnow=0;$partlengthnow<$keysetting['partlength'];$partlengthnow++){ $key.=$keysetting['keychars'][mt_rand(0,$maxarrayid)]; } $key.=$keysetting['splittedby']; //Add the split for each part } $key=substr($key,0,-1); //Remove last splitchar //This is important now! Check if the key doesn't already exists $secruityquery->execute(array(":key"=>$key)); $secruityresult=$secruityquery->fetch(); if(!isset($secruityresult['keys_id'])){ $query->execute(array(":key"=>$key)); //Add the key to the Database $keylist.=$key."\n"; //Add the key to the keylist }else $i--; //Add another loop to the Keycreation } file_put_contents("keys.txt",$keylist,FILE_APPEND); } ?> <!DOCTYPE html> <html> <head> <title>Keymanager - Create Keys</title> <meta charset="UTF-8"> </head> <body> <h2>Keymanager - Create Keys</h2> <form method="post"> <label for="amount">Amount</label> <input type="text" name="amount" id="amount"/> <input type="submit" name="submit" value="Add"> <p>Keys will be added to keys.txt after creation.</p> </form> </body> </html> <?php }else{ ?> <!DOCTYPE html> <html> <head> <title>Keymanager - Login</title> </head> <body> <h2>Keymanager - Login</h2> <form method="post"> <label for="pwd">Passwort</label> <input type="password" name="pwd" id="pwd"/> <input type="submit" name="submit" value="Einloggen"> </form> </body> </html> <?php } Die Datei ist wohl am kompliziertesten, ich habe sie probiert so gut wie möglich zu kommentieren. Sie hat wohl die wichtigste Aufgabe. Sie überprüft, ob der User eingeloggt ist oder nicht und zeigt ggf. die Loginmaske an, erstellt die Keys an Hand der Liste von Zeichen welche gegeben sind und verbindet diese zu einem Key. Der erstellte Key wird überprüft, ob er nicht bereits schon in der DB existiert. Es ist unwahrscheinlich, aber man sollte es lieber im Vorraus vermeiden. Sofern der Key nicht existiert, wird er hinzugefügt zur Datenbank und in der Keyliste abgespeichert. Die letzte Datei ist die keys.txt, sie beinhaltet einfach alle erstellten Keys. Wichtig ist, dass diese einen CHmod von 777 hat! Sonst kann der Server sie nicht beschreiben! Wer sich das ganze mal anschauen möchte: Generator Keyliste Das war es erstmal zum Part der Serverseite, der Code wurde probiert relativ einfach aber natürlich sicher zu halten. Im zweiten Part, morgen oder übermorgen kommen wir dann zum Part in Unity. Feedback oder Kritik ist gerne immer gesehen, da es mein erstes Tutorial war generell sowie zu Unity. Viele Grüße, Daniel unity_tutorial_serverside.rar 2 Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Schalla Geschrieben 22. Juli 2013 Autor Melden Share Geschrieben 22. Juli 2013 3. UnityCode Als nächstes folgt unser Code in Unity. Ich habe es um es einfach zu halten in eine Datei geschrieben, diese wird in der Loginscene der Maincamera angehangen. using UnityEngine; using System.Collections; public class KeyCheck : MonoBehaviour { public string validateKeyURL; //Enter your validate_key.php URL here string productkey; WWW request; WWWForm form; void OnGUI(){ GUI.Box (new Rect(10,10,300,90),"Keycheck"); //Great Box for the Form productkey=GUI.TextField(new Rect(20,40,280,20),productkey,60); //Textinput if(GUI.Button (new Rect(20,70,280,20), "Check Key")){ //If Input pressed, send the form form = new WWWForm(); // Add your fields form.AddField( "gamesecret", "V@wKp-c" ); form.AddField( "key", productkey ); //Send the request StartCoroutine(GetKey()); } } public IEnumerator GetKey() { request = new WWW(validateKeyURL,form); yield return request; Debug.Log (request.text); //Show the answer to the log } } Der Code holt den Input aus dem Textfield und sendet ein Request an die URL. Die URL antwortet dann mit Login success o.Ä. und gibt wieder, ob der Key korrekt war. Anstatt Debug.Log(); könnt ihr hier natürlich auch folgendes machen: public IEnumerator GetKey() { request = new WWW(validateKeyURL,form); yield return request; if(request.text=="Login Success."){ Application.LoadLevel(1); }else{ //Error Handling } } Hier wird sofern der Key korrekt war ein anderes Level geladen, die Möglichkeiten sind da offen. Fragen? Kritik? Sonst etwas? Gerne könnt ihr Vorschläge posten, was ich beim Tutorial verbessern kann oder beim nächsten Beachten, würde mich sogar freuen. Schönen Abend noch! Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
AgentCodeMonk Geschrieben 22. Juli 2013 Melden Share Geschrieben 22. Juli 2013 Moin moin! Ein paar Fragen und Anregungen habe ich doch da gleich. 1. Warum das Ganze als Webanwendung machen und riskieren, dass irgendwer da rankommt? Auch wenn das eher für kleine Spiele benutzt werden wird... Ich tendiere da eher zu einer Lösung mit einer Windows Forms-Anwendung oä.und würde PHP nur als Interface nutzen. Also etwas, was im Idealfall nicht aus der Hand oder ins www gegeben wird, sondern nur vermittelt. Den KeyGenerator als Website zu lösen mag plattformübergteifender sein, aber wann ist man schon unterwegs und denkt sich: ich könnte doch mal ein paar Keys generieren 2. Warum die txt, die ja auch noch auszulesen ist? Mit Schreibrechten? Es sind doch alle Keys in der db und im Idealfall vor ungebetenem Besuch geschützt;) Davon abgesehen wäre es sinnvoll sie zuerst in eine lokale Datenbank und anschließend in die des Servers zu übertragen. 3. Ich würde die ID nicht für den Key, sondern als GUID (global unique id) für den Spieler und/oder Account nutzen. Bin mir nicht sicher ob du das vor hattest. Die ID wird zwar erwähnt, aber ein Fallbeispiel, ein warum und wofür du sie im konkreten Fall nutzen würdest, fehlt mir, daher der Vorschlag. 4. Zum Thema Sicherheit. Schön wäre es doch, wenn du das pw noch verschlüsseln würdest etc pp. Gehört für mich schon dazu. Schön mit einem langsamen Algorithmus, der den HashKey aus pw und pepper checkt. Sowas sollte man sich doch eh angewöhnen, spätestens, wenn du irgendwas aus Unity heraus durch die Gegend schickst, sollten da kein Klartext-Zeugs rumfliegen, sprich dein oder HashKey im Klartext übermittelt werden. Das ist weder in Unity, noch in PHP allzu großer Aufwand und sollte in diesem Tutorial unbedingt passieren, da sonst all die, die aus diesem Tutorial lernen, unsichere Sachen lernen. ...und strings escapen, bitte 5. Da ich PHP eig nur als Schnittstelle nutze und sonst nicht mehr so webentwicklermäßig unterwegs bin, mal die Frage: Was hat PDO für Vorteile? Ich mache das eig immer so mit mysqli (config.php) <?php $db_server = 'localhost'; $db_user = 'root'; $db_pass = 'superMasterPassword'; $db_name = 'dbName'; error_reporting(E_ALL ^ E_NOTICE); @$mysqli = new mysqli($db_server, $db_user, $db_pass, $db_name); ?> (settings.php) <?php $pepper = "ydf7byd7fb798ydfb789"; $serverVersion = "0.1-Build-0001"; $real_hash = hash("sha512",$serverVersion . $pepper); if (isset($_POST["hash"])) { $hash = mysqli_real_escape_string($mysqli, $_POST['hash']); } //usw ?> <?php ob_start();//Hook output buffer include("../config.php"); include("settings.php"); include("character.php"); include("account.php"); ob_end_clean();//Clear output buffer if (mysqli_connect_errno()) { die('<h1>Could not connect to the database</h1><h2>Please try again after a few moments.</h2>'); $mysqli->set_charset("utf8"); } else { if($maintenance == false && $real_hash == $hash) { if ($result = $mysqli->query("SELECT * FROM $rpg_character WHERE guid ='$id' ")) { while ($row = $result->fetch_object()) { $stats = array ( 'race' =>$row->race, 'gender' =>$row->gender, 'factionside' =>$row->factionside, 'level' =>$row->level, 'class' =>$row->class, 'xp' =>$row->xp, 'expTotal' =>$row->expTotal, 'health' =>$row->health, 'power' =>$row->power ); echo json_encode($stats); // needs to be encoded } } $result->close(); $mysqli->close(); } } ?> Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Schalla Geschrieben 22. Juli 2013 Autor Melden Share Geschrieben 22. Juli 2013 Hi CodeMonkey, Danke erstmal für dein Feedback! 1. Das mag im Endeffekt geschmackssache sein, es mag mit Sicherheit sinnvoller sein, jap. Damit kann ich aber leider nicht dienen, da ich in der Hinsicht keine Erfahrung habe Man kann die PHP Datei natürlich auch einfach runter nehmen. 2. Damit die Leute die Keys auch sehen können, die sie generieren Das ist ein Tutorial, ich möchte ja erstmal zeigen wie die Basics gehen. Wie man später damit umgehen kann, um die Keys als PDF via Mail zu bekommen z.B. würde den Umfang sprengen. Die Keys müssen ja auch irgendwie weiter gegeben werden. 3. Die ID ist dafür da, dass wenn du z.B. später nen User hast also Tabelle user ihm die ID zuweisen kannst und somit user mit id verbinden zu können, Key mit User fände ich unpraktisch. Aber ich werde da gerne noch ein Beispiel reinhauen, guter Vorschlag! 4. Strings werden escaped, das wird in PDO mit bind_param gemacht, bevor du mir sowas Vorhalten willst Encoding kann ich später gerne noch nachtragen, aber eher in einem dritten Teil, die Idee ist aber Sinnvoll. 5. Ob mySQLi oder PDO hat ansich keine großen Vorteile, PDO unterstützt mehrere Datenbank Typen z.B. http://net.tutsplus....should-you-use/ Da haste ne fixe Tabelle dazu. VG. Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
AgentCodeMonk Geschrieben 22. Juli 2013 Melden Share Geschrieben 22. Juli 2013 Jupp, dass wird sicher den Rahmen sprengen. Naja, wie man das wegen dem Zuordnen macht... würde da, wie du sagst, dem User die Keys zuordnen, jedoch ohne die key_id, weil ich die überflüssig finde. Es reicht doch völlig <user1><key1> --- <user1><key2> --- <user2><key5343434614>...usw. ...aber auch das ist wohl Geschmackssache. Da muss ich mir PDO nochmal ansehen. Hab nach PHP 4 den Sprung auf 5 nicht so 100% gemacht, weil ich´s nie so richtig brauchte. Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Schalla Geschrieben 22. Juli 2013 Autor Melden Share Geschrieben 22. Juli 2013 Naja, du kannst entweder der Tabelle keys einen Spalte user_id geben oder users eine spalte keys_id, das wären ja die zwei Wege. Was du davon machst, ist denke ich frei. Ich mach lieber Sachen von der user_id abhängig, weil ich die meist in der $_SESSION speicher. Ich denke das ist Geschmackssache mit PDO oder mySQLi. Habe mit beidem mal gearbeitet, finde beides gut. Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Schalla Geschrieben 25. Juli 2013 Autor Melden Share Geschrieben 25. Juli 2013 Update, der kleine Part 2 ist nachgetragen Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
checkalord3 Geschrieben 15. Mai 2017 Melden Share Geschrieben 15. Mai 2017 Am 22.07.2013 um 22:00 schrieb Schalla: Um auch mal etwas dabei zu steuern, werde ich ein kleines Tutorial zum Thema PHP Keygenerator mit Unityintegration erstellen. Ich bin ebenfalls neu in der Unity Szene. Ich lerne auch gern neues, darum würde ich mal gerne fragen: Was ist genau ein Keygenerator? Was könnte man theoretisch alles mit anstellen. So wie ich das ganze jetzt verstanden habe ist das nämlich einfach nur ein Zähler, der jedem Spieler eine gewisse Identität gibt und diese benutzt wird ihn eindeutig identifizieren zu können. Grüße Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Tyroonis Geschrieben 28. Juni 2017 Melden Share Geschrieben 28. Juni 2017 Am 15.5.2017 um 15:50 schrieb checkalord3: Ich bin ebenfalls neu in der Unity Szene. Ich lerne auch gern neues, darum würde ich mal gerne fragen: Was ist genau ein Keygenerator? Was könnte man theoretisch alles mit anstellen. So wie ich das ganze jetzt verstanden habe ist das nämlich einfach nur ein Zähler, der jedem Spieler eine gewisse Identität gibt und diese benutzt wird ihn eindeutig identifizieren zu können. Grüße Um zum besipiel Gamekeys zu generieren. Wenn du dei Spiel nicht über steam oder so vermarkten willst, kannst du so selbst dafür sorgen das dein Spiel nur mit gültigem Key spielbar ist. Oder um Keys für einen Ingameshop zu generieren. Deiner Fantasie sind da keine Grenzen gesetzt. Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Kuxii Geschrieben 23. November 2017 Melden Share Geschrieben 23. November 2017 Läuft aber nicht mehr Bekomme nur diesen Fehler: NullReferenceException: Object reference not set to an instance of an object UnityEngine.GUI.DoTextField (Rect position, Int32 id, UnityEngine.GUIContent content, Boolean multiline, Int32 maxLength, UnityEngine.GUIStyle style, System.String secureText, Char maskChar) (at C:/buildslave/unity/build/Runtime/IMGUI/Managed/GUI.cs:629) UnityEngine.GUI.DoTextField (Rect position, Int32 id, UnityEngine.GUIContent content, Boolean multiline, Int32 maxLength, UnityEngine.GUIStyle style, System.String secureText) (at C:/buildslave/unity/build/Runtime/IMGUI/Managed/GUI.cs:616) UnityEngine.GUI.DoTextField (Rect position, Int32 id, UnityEngine.GUIContent content, Boolean multiline, Int32 maxLength, UnityEngine.GUIStyle style) (at C:/buildslave/unity/build/Runtime/IMGUI/Managed/GUI.cs:611) UnityEngine.GUI.TextField (Rect position, System.String text, Int32 maxLength) (at C:/buildslave/unity/build/Runtime/IMGUI/Managed/GUI.cs:491) KeyCheck.OnGUI () (at Assets/Menü/Scripte/KeyCheck.cs:19) Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.