• Announcements

    • Lars

      Allgemeine Forenregeln   03/13/2017

      Forenregeln Nimm dir bitte einen Moment um die nachfolgenden Regeln durchzulesen. Wenn du diese Regeln akzeptierst und die Registration fortsetzen willst, klick einfach auf den "Mit der Registrierung fortfahren"-Button. Um diese Registration abzubrechen, klick bitte einfach auf den "Zurück" Button deines Browsers. Wir garantieren nicht für die Richtigkeit, Vollständigkeit und Brauchbarkeit der Nachrichten und sind auch nicht dafür verantwortlich. Die Beiträge drücken die Meinung des Autors des Beitrags aus, nicht zwangsläufig das, wofür die Forensoftware steht. Jeder Nutzer, der denkt, dass ein veröffentlichter Beitrag unzulässig bzw. störend ist, ist aufgefordert uns unverzüglich per E-Mail zu kontaktieren. Wir haben das Recht störende Beiträge zu löschen und bemühen uns, das in einem realistischem Zeitraum zu erledigen (sofern wir beschlossen haben, dass die Löschung notwendig ist). Du akzeptierst, durchgehend während der Nutzung dieses Services, dass du dieses Forum nicht dazu missbrauchen wirst, Inhalte zu veröffentlichen, welche bewusst falsch und/oder verleumderisch, ungenau, beleidigend, vulgär, hasserfüllt, belästigend, obszön, sexuell belästigend, bedrohlich, die Privatsphäre einer Person verletzend oder in irgend einer Art und Weise das Gesetz verletzen. Des Weiteren akzeptierst du, dass du keine urheberrechtlich geschützte Inhalte ohne Erlaubnis des Besitzers in diesem Forum veröffentlichst. Mit dem Klick auf den "Mit der Registrierung fortfahren"-Button, akzeptierst du zudem unsere Datenschutzerklärung und stimmst der Speicherung deiner IP-Adresse und personenbezogenen Daten zu, die dafür benötigt werden, um dich im Falle einer rechtswidrigen Tat zurückverfolgen zu können bzw. permanent oder temporär aus dem Forum ausschließen zu können. Es besteht keine Pflicht zur Abgabe der Einwilligung, dies erfolgt alles auf freiwilliger Basis.   Zusatzinformationen Der Forenbetreiber hat das Recht, Nutzer ohne Angabe von Gründen permanent aus dem Forum auszuschließen. Des Weiteren hat er das Recht, Beiträge, Dateianhänge, Umfrage, Blogeinträge, Galleriebilder oder Signaturen ohne Angabe von Gründen zu entfernen. Mit der Registrierung verzichtest du auf alle Rechte an den von dir erstellten Inhalten, bzw. treten diese an das Unity-Insider.de und Unity-Community.de ab. Dies bedeutet im Klartext, dass das Unity-Insider.de und Unity-Community.de frei über deine Texte verfügen kann, sofern diese nicht wiederum die Rechte anderer verletzen. Es besteht weiterhin kein Anspruch von registrierten Nutzern bzw. ehemaligen registrierten Nutzern darauf, dass erstellte Inhalte und/oder die Mitgliedschaft (User) wieder gelöscht werden (Erhaltung der Konsistenz dieses Forums).   Einwilligungserklärung Wenn du mit der Speicherung deiner personenbezogenen Daten sowie den vorstehenden Regeln und Bestimmungen einverstanden bist, kannst du mit einem Klick auf den Mit der Registrierung fortfahren-Button unten fortfahren. Ansonsten drücke bitte Zurück. Stand: 07.03.2011
Schalla

[HowTo] PHP Keygenerator inkl. Abfrage in Unity

8 posts in this topic

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: keys
    • keys_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 people like this

Share this post


Link to post
Share on other sites

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!

Share this post


Link to post
Share on other sites

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

   }
}
?>

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites
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 :)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now