I'm fairly new to both Unity and PHP, and I am currently working on a project where I can parse data from a MySQL database to Unity, using PHP.
I initially wanted to try and enable a method where the user can perhaps change the php script and enable it to choose a different table of data, however I was advised that it may be safer to list all variables within the php script and call it from Unity accordingly;
Display.php
$table = mysql_real_escape_string($_GET['table'], $db);
if ($table == "shoes") {
$query = "SELECT * FROM `shoes` ORDER by `price` ASC LIMIT 10";
elseif ($table == "sneakers") {
$query = "SELECT * FROM `sneakers` ORDER by `price` ASC LIMIT 10";
$result = mysql_query($query) or die('Query failed: ' . mysql_error());
$num_results = mysql_num_rows($result);
for($i = 0; $i < $num_results; $i++)
{
$row = mysql_fetch_array($result);
echo $row['shopname'] . "\t" . $row['price'] . "\n";
}
I'm having trouble calling the php and choosing the table that I want to select, I am pretty new to this, so I apologise if this seems completely incompetent to you guys.
Here is the my Unity Script;
HSController.cs
void Start()
{
StartCoroutine(GetScores());
}
// remember to use StartCoroutine when calling this function!
IEnumerator PostScores(string name, int score)
{
string hash = Md5Sum(name + score + secretKey);
string post_url = addScoreURL + "name=" + WWW.EscapeURL(name) + "&score=" + score + "&hash=" + hash;
WWW hs_post = new WWW(post_url);
yield return hs_post; // Wait until the download is done
if (hs_post.error != null)
{
print("There was an error posting the high score: " + hs_post.error);
}
}
IEnumerator GetScores()
{
gameObject.guiText.text = "Loading...";
WWW hs_get = new WWW(highscoreURL);
yield return hs_get;
if (hs_get.error != null)
{
print("There was an error getting the high score: " + hs_get.error);
}
else
{
gameObject.guiText.text = hs_get.text; // this is a GUIText that will display the scores in game.
}
}
Any help or a point in the right direction would be great!
Kind Regards
Let me try to rewrite this into a working example:
C#
void Start() {
StartCoroutine(GetData());
}
IEnumerator GetData() {
gameObject.guiText.text = "Loading...";
WWW www = new WWW("http://yoururl.com/yourphp.php?table=shoes"); //GET data is sent via the URL
while(!www.isDone && string.IsNullOrEmpty(www.error)) {
gameObject.guiText.text = "Loading... " + www.Progress.ToString("0%"); //Show progress
yield return null;
}
if(string.IsNullOrEmpty(www.error)) gameObject.guiText.text = www.text;
else Debug.LogWarning(www.error);
}
PHP
<?php
//DB connection goes here
if ($_REQUEST['table'] === "shoes") { //I'm using REQUEST instead of GET, so it will work with both GET and POST
$query = "SELECT * FROM `shoes` ORDER by `price` ASC LIMIT 10";
} elseif ($_REQUEST['table'] === "sneakers") {
$query = "SELECT * FROM `sneakers` ORDER by `price` ASC LIMIT 10";
}
$result = mysql_query($query) or die(mysql_error());
while ($row = mysql_fetch_assoc($result)) {
echo $row['shopname'] . "\t" . $row['price'] . "\n";
}
?>
Hope this helps!
Related
So I have a list in c# that's being converted to a string, which is then converted to a 2-dimensional array in PHP, which is then sent to MySQL database. Now how do I go about reversing this, whereby I can download from the database to PHP than to c# list.
This is what I have so far, but I'm not sure if I need to download the data back to an array in PHP or if I should download it as a string and break it up into a list in c#?
This is my c# code:
public List<Ship> shipList = new List<Ship>();
string shipListString = "";
WWWForm form = new WWWForm();
form.AddField("username", username);
form.AddField("shipcount", ShipInventory.Count);
for (int i = 0; i < shipList.Count; i++)
{
shipListString = shipListString + " " + shipList[i].id + " '" + shipList[i].username + "' '" + shipList[i].name + "' " + shipList[i].power +
"zzz";// + ShipInventory[i];
}
form.AddField("shipinventory", shipListString);
WWW www = new WWW("x.x.x.x/savedata.php", form);
yield return www;
And this is my php:
$shiparraytobesplit = $_POST["shipinventory"];
$ships = explode("zzz", $shiparraytobesplit);
unset($ships[count($ships)-1]);
$shipinfo = array_map(function($ship) {
$tempshipinfo = explode(" ", $ship);
$ship_assoc = [
"id" => $tempshipinfo[1],
"name" => $tempshipinfo[2],
"username" => $tempshipinfo[3],
"hp" => $tempshipinfo[4]
];
return $ship_assoc;
}, $ships);
$sql = sprintf('INSERT INTO shipinventory (shipid,shipname,username,shippower) VALUES (%s)', implode(',',array_values($shipinfo[$i])));
if(!mysqli_query($con, $sql))
{
echo("error description: " . mysqli_error($con));
}
This is working well to upload my c# list into the database, but I'm not sure what's the best way to download it from the database back to a c# list. Any advice would be awesome! Thanks
Ok so I managed to make it work but I imagine there are better methods so please share! Thanks:
C# Script:
WWW www = new WWW("x.x.x.x/loaddata.php");
yield return www;
stringFromPHP = www.text;
char[] delimiterENTER = new char[] {'\n' };
char[] delimiterSPACE = new char[] { ' ' };
shipStringArray = stringFromPHP.Split(delimiterENTER, StringSplitOptions.RemoveEmptyEntries);
shipList.Clear();
for (int i = 0; i < shipStringArray.Count(); i++)
{
string[] shipInfo = shipStringArray[i].Split(delimiterSPACE);
shipList.Add(new Ship(Int32.Parse(shipInfo[0]), shipInfo[1], shipInfo[2], Int32.Parse(shipInfo[3]), shipStringArray[i]));
}
and php:
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
$query = "SELECT shipid, username, shipname, shippower FROM shipinventory";
if ($result = mysqli_query($con, $query)) {
while ($row = mysqli_fetch_assoc($result)) {
$stringtoexplodeincsharp printf ("%s %s %s %s\n",(int) $row["shipid"], $row["username"], $row["shipname"],(int) $row["shippower"]);
}
mysqli_free_result($result);
}
mysqli_close($con);
In my script im expecting the text bytesDownloadedText to be updated with how many bytes have been downloaded so far but it only runs once and stays on 0. How do I fix this
private IEnumerator DownloadFile(){
WWW w = new WWW (PATH_TO_DOWNLOAD);
bytesDownloadedText.text = w.bytesDownloaded.ToString();
yield return w;
if (w.error != null) {
Debug.LogError ("Error: " + w.error);
} else {
scriptText = w.text;
filesDownloaded = true;
Debug.Log (scriptText);
}
}
Edit: New code + Additional debugging information
private IEnumerator DownloadFile(){
WWW w = new WWW (PATH_TO_DOWNLOAD);
while(!w.isDone){
bytesDownloadedText.text = w.bytesDownloaded.ToString ();
Debug.Log ("Bytes Downloaded: " + w.bytesDownloaded);
yield return null;
}
Debug.Log ("Exiting while loop");
if (w.error != null) {
Debug.LogError ("Error: " + w.error);
} else {
//bytesDownloadedText.text = w.bytesDownloaded.ToString ();
scriptText = w.text;
filesDownloaded = true;
Debug.Log (scriptText);
}
}
Filesize: 337 bytes
Download Path: https://deathcrow.altervista.org/websharp/files.php
3.Code where DownloadFile is called
private void Start(){
StartCoroutine (DownloadFile ());
}
The while loop is exiting
w.text returns the test script from the server(which is code)
using UnityEngine;
public class TestScript: MonoBehaviour{
public void Update(){
if (Input.GetMouseButtonDown (0)) {
RaycastHit hit;
if (Physics.Raycast (Camera.main.ScreenPointToRay(Input.mousePosition),out hit)){
if (hit.transform.tag == "Destroy") {
Destroy (hit.transform.root.gameObject);
}
}
}
}
}
Edit: Online code
<?
$scriptText = "";
$file_handle = fopen("TestScript.cs","r");
while(!feof($file_handle)){
$line = fgets($file_handle);
$scriptText = $scriptText . $line;
}
fclose($file_handle);
$size = strlen($scriptText);
header("Content-length: ".$size);
echo $scriptText;
?>
Do not yield WWW if you want to use the bytesDownloaded property as that will pause your code until WWW returns which makes it impossible to read how much data has been downloaded.
You have to put WWW.bytesDownloaded in a loop then use WWW.isDone to detect when WWW is done and then exit the loop. Inside that loop, you can use WWW.bytesDownloaded to display the downloaded data. Finally, you must wait for a frame after each loop so that other scripts can execute or Unity will freeze until the download is done.
This is what that code should look like:
private IEnumerator DownloadFile()
{
WWW w = new WWW(PATH_TO_DOWNLOAD);
while (!w.isDone)
{
yield return null;
bytesDownloadedText.text = w.bytesDownloaded.ToString();
Debug.Log("Bytes Downloaded: " + w.bytesDownloaded);
}
if (w.error != null)
{
Debug.LogError("Error: " + w.error);
}
else
{
scriptText = w.text;
filesDownloaded = true;
Debug.Log(scriptText);
}
}
Note: There are some instances where the bytesDownloaded property returns 0. This has nothing to do with Unity. This happens mostly when your server is not sending the Content-Length header.
Example of sending the Content-Length header from the server(php):
<?php
//String to send
$data = "Test message to send";
//Get size
$size= strlen($data);
//Set Content-length header
header("Content-length: ".$size);
//Finally, you can send the data
echo $data;
?>
How do I send a PUT request using UnityWebRequest?
The PUT is being sent; Uploaded!! is being printed to the console. However, nothing is being updated. I think I'm formatting myData incorrectly.
The actual URL I'm trying to send the PUT to is formatted like... http://servername.com/api/dogs/1/token=fndskajfdafdsf&cleanliness_level=20
Sorry, I can't remember what that format is called.
This is the code that I have:
public string url = "http://servername.com/api/dogs/1";
.
.
.
void Start() {
StartCoroutine (UpdateDogs ("clean"));
}
IEnumerator UpdateDogs (string button)
{
byte[] myData;
if (button == "feed") {
myData = System.Text.Encoding.UTF8.GetBytes ("?token=" + token + "&health_level=" + healthLevel);
} else {
myData = System.Text.Encoding.UTF8.GetBytes ("?token=" + token + "&cleanliness_level=" + cleanlinessLevel);
}
using (UnityWebRequest www = UnityWebRequest.Put (url, myData)) {
yield return www.Send ();
if (www.isError) {
Debug.Log ("PUT ERROR: " + www.error);
} else {
Debug.Log ("Uploaded!!");
}
}
It looks like you're missing an & in the parameter string after the token.
token + "cleanliness_level=
Should be
token + "&cleanliness_level=
Similarly for the other possible parameters.
myData in UnityWebRequest.Put is only for http body data. It doesn't seem like you need that. Instead you should add your query parameters to the URL, like such:
public string url = "http://servername.com/api/dogs/1";
if (button == "feed") {
url += "?token=" + token + "&health_level=" + healthLevel;
} else {
url += "?token=" + token + "&cleanliness_level=" + cleanlinessLevel;
}
using (UnityWebRequest www = UnityWebRequest.Put (url, "dummy")) { // UnityWebRequest.Put requires a body, see comments below
yield return www.Send ();
if (www.isError) {
Debug.Log ("PUT ERROR: " + www.error);
} else {
Debug.Log ("Uploaded!!");
}
}
I think you are missing a forward slash before token when you send it.
Try debugging what you actually send with
Debug.Log (www.text);
Next advice is that maybe the error is with what code you use on the back end receiving the data.
I am programming a login system now on Unity, but I have this weird bug. For some reason when I get the output of the php file, the if statement in the C# file can't see that 'loginreturn' (= AccountDoesntExist) and the string "AccountDoesntExist" are the same. I don't know why but maybe you smart people see the bug and can help me out.
C# Code:
IEnumerator TryLogin(string username, string password)
{
WWWForm form = new WWWForm();
form.AddField("username", username);
form.AddField("password", password);
WWW loginWWW = new WWW(LoginURL, form);
yield return loginWWW;
if (!string.IsNullOrEmpty(loginWWW.error))
{
Debug.LogError("Cannot connect to LOGIN servers! Error: " + loginWWW.error);
}else
{
string loginreturn = loginWWW.text;
Debug.Log(loginWWW.text);
Debug.Log(loginreturn);
if (loginreturn == "AccountDoesntExist")
Debug.Log("WORKS!");
}
}
PHP Code (which will always return "AccountDoesntExist" because of the way I log in):
<?php
$inputusername = $_REQUEST["username"];
$password = $_REQUEST["password"];
$servername = "localhost";
$username = "chatsystem_accs";
$password = "CENCORED";
$dbname = "chatsystem_accs";
//Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
//Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
//Connected successfully
$sql = "SELECT `username`, `password` FROM `accounts`";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
if ($inputusername == $row["username"]) {
if (password_verify($password, $row["password"])) {
echo "Success";
}else {
echo "UsernameOrPasswordIncorrect";
}
}else {
echo "AccountDoesntExist";
}
}
}else {
echo "AccountDoesntExist";
}
//Close connection
$conn->close();
?>
Very likely a UTF-8 problem. There is an extra data in the received bytes. Convert the received data to UTF-8 before comparing it.
Replace
string loginreturn = loginWWW.text;
with
string loginreturn = System.Text.Encoding.UTF8.GetString(loginWWW.bytes, 3, loginWWW.bytes.Length - 3);
EDIT:
Did debugging like this:
Debug.Log("Received Length: "+ loginreturn.Length);
Debug.Log("Compare Length: " + "AccountDoesntExist".Length);
and the results were:
Received Length: 19
Compare Length: 18
This is wrong. There is an extra character somewhere.
Debugged again with the function below then called it with displayAsChar(loginreturn);
void displayAsChar(string badValue)
{
char[] values = badValue.ToCharArray();
for (int i = 0; i < values.Length; i++)
{
string tempResult = "Value at index " + i + " is: " + values[i];
Debug.Log(tempResult);
}
}
It shows there is an empty character at the end of the character. I thought that was just " " but it wasn't.
I made another function to see what this empty character is:
void showStringAsHex(string badValue)
{
foreach (char c in badValue)
Debug.Log("To Unicode: " + ((int)c).ToString("X2"));
}
Bingo. That last character is 0A (Hex) which is also represented as \n. This is used as a line feed.
FIX:
Before doing the compare action, trim the string. This will remove any escape character and empty strings in the beginning and end of the character.
To trim the character, simply add the code below before comparing the string.
loginreturn = loginreturn.Trim();
Why post the debugging process?
The characters might be different for different servers. Posting this will help others troubleshoot and fix this problem for them-selves in the future.
So i'm using MySQL and C# in order to grab info from a database, but when i try to use that database info again in MySQL doesn't work because it seems to be adding a small space in front of the data. Let me show you what i mean.
php code that displays info on webpage
// Create connection
$conn = mysqli_connect($servername, $username, $password, $dbname);
// Check connection
if (!$conn) {
die("Connection failed: " . mysqli_connect_error());
}
$nick = $_POST["myform_nick"];
$sql = "SELECT Lin FROM scores WHERE name='$nick'";
$result = mysqli_query($conn, $sql);
if (mysqli_num_rows($result) > 0) {
// output data of each row
while($row = mysqli_fetch_assoc($result)) {
echo $row["Lin"];
}
}
Then in C# it is like this...
IEnumerator LeagueCheck(){
var form = new WWWForm ();
form.AddField( "myform_nick", formNick );
WWW w = new WWW (URL, form);
yield return w;
if (w.error != null) {
print(w.error); //if there is an error, tell us
}
else {
print("League Check 1");
LinII = w.text; //here we return the data our PHP told us
print (w.text);
Lin = LinI + LinII;
w.Dispose(); //clear our form in game
StartCoroutine (LeagueCheck2 ());
}
}
Inside LeagueCheck2 it uses LinII to grab another thing from the database but it can't find it because it comes back like this
" Dominators"
instead of like this
"Dominators"
So my question is how can i get it to remove that little space in front of Dominators.
What i've tried to fix this
using System;
LinII = String.Trim(w.text);
LinII = w.text;
LinII.Trim();
LinII.Replace(" ","");
void Timer(){
LinII.Trim();
}
//In the IEnumator LeagueCheck();
Lin = LinI + LinII;
w.Dispose(); //clear our form in game
Trimer();
StartCoroutine (LeagueCheck2 ());
This should work if w.text and LinII are a string
if (w.error != null) {
print(w.error); //if there is an error, tell us
}
else {
print("League Check 1");
LinII = w.text.Trim(); //here we return the data our PHP told us
print (LinII );
Lin = LinI + LinII;
w.Dispose(); //clear our form in game
StartCoroutine (LeagueCheck2 ());
}