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.
Related
I am trying to figure out how to stop UnityWebRequest download immediately with a button in android application.
Stopping coroutine with StopCoroutine("downLoadFromServer"); does not stop UnityWebRequest.
I tried using UnityWebRequest.Dispose(); or UnityWebRequest.Abort(); with no success.
Below is the download i'm trying to stop.
private IEnumerator downLoadFromServer()
{
var url = "https://example.com/app.apk";
var savePath = Path.Combine(Application.persistentDataPath, "data", "app.apk");
using (var uwr = UnityWebRequest.Get(url))
{
uwr.SetRequestHeader("Authorization", "Basic " + System.Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes("test:test")));
uwr.SendWebRequest();
while (!uwr.isDone)
{
progressText.text = $"Progress: {uwr.downloadProgress:P}";
yield return null;
}
var yourBytes = uwr.downloadHandler.data;
progressText.text = $"Done downloading. Size: {yourBytes.Length}";
//Create Directory if it does not exist
var directoryName = Path.GetDirectoryName(savePath);
if (!Directory.Exists(directoryName))
{
Directory.CreateDirectory(directoryName);
progressText.text = "Created Dir";
}
try
{
//Now Save it
System.IO.File.WriteAllBytes(savePath, yourBytes);
Debug.Log("Saved Data to: " + savePath.Replace("/", "\\"));
progressText.text = "Saved Data";
}
catch (Exception e)
{
Debug.LogWarning("Failed To Save Data to: " + savePath.Replace("/", "\\"));
Debug.LogWarning("Error: " + e.Message);
progressText.text = "Error Saving Data";
}
}
//Install APK
installApp(savePath);
}
Thank you,
Chris
You are right: Stopping the Coroutine does not cancel the UnityWebRequest, you are just not keeping track of it anymore.
Actually UnityWebRequest.Abort should do exactly that
If in progress, halts the UnityWebRequest as soon as possible.
This method may be called at any time. If the UnityWebRequest has not already completed, the UnityWebRequest will halt uploading or downloading data as soon as possible. Aborted UnityWebRequests are considered to have encountered a system error. Either the isNetworkError or the isHttpError property will return true and the error property will be "User Aborted".
However this makes ofcourse only sense if you actually check the result of the request which currently you aren't doing and you should do anyway!
A way to use it would be to make the uwr a class wide field so you can access it from somewhere else and as said actually add a check if the download succeeded:
private UnityWebRequest uwr;
private IEnumerator downLoadFromServer()
{
...
// NOTE: Remove the var so the class field uwr is assigned to, not only
// a local variable
using(uwr = UnityWebRequest.Get(...))
{
...
// Always check if a request was actually successful before continuing
if(uwr.isHttpError || uwr.isNetworkError || !string.IsNullOrWhiteSpace(uwr.error))
{
Debug.LogWarning($"Download Failed with {uwr.responseCode}, reason: {uwr.error}", this);
progressText.text = $"Download Failed: {uwr.error}";
// Cancel this Coroutine
yield break;
}
var yourBytes = uwr.downloadHandler.data;
...
}
//Install APK
installApp(savePath);
}
Then you can simply do
public void AbortDownload()
{
if(uwr != null && !uwr.isDone)
{
Debug.Log("Aborting download ...", this);
uwr.Abort();
}
else
{
Debug.Log("Not downloading, nothing to do ...", this);
}
}
which should make the download "fail" and thereby also finish the Coroutine
I am trying to upload a file into the server which is a .json file.I am sending the Binary data along with file name and Mimetype but in the backend it does not show which file extension it is.
How does this thing work?What happens if I have same filename but different extensions to upload into the server.Wht will happen if I want to upload and later deserialize it as two different extensions?
IEnumerator UploadFileData()
{
string mapnamedl = "123";
Debug.Log("Mapname local = " + mapnamedl);
string locapath = "file://" + Application.persistentDataPath + "/" + mapnamedl + ".json";
Debug.Log("local path = " + locapath);
WWW localFile = new WWW(locapath);
yield return localFile;
if (localFile.error == null)
{
Debug.Log("Local file found successfully");
}
else
{
Debug.Log("Open file error: " + localFile.error);
yield break; // stop the coroutine here
}
Debug.Log("local file text" + localFile.text);
WWWForm postForm = new WWWForm();
string mimetypes = "application/json";
postForm.AddBinaryData("Jsondata", localFile.bytes, mapnamedl, mimetypes);
UnityWebRequest www = UnityWebRequest.Post("https://test.com/car/hariupload/save.php", postForm);
yield return www.SendWebRequest();
if (www.isNetworkError || www.isHttpError)
{
Debug.Log(www.error);
}
else
{
string JSONDATAstring = www.downloadHandler.text;
Debug.Log("Json String is = " + JSONDATAstring);
JSONNode JNode = SimpleJSON.JSON.Parse(JSONDATAstring);
string login = (JNode["upload"][0]["success"]).ToString();
Debug.Log("login is = " + login);
if (login == "1")
{
Debug.Log("Form upload complete!");
}
else if (login == "0")
{
Debug.Log("Failed ");
}
}
}
+if you have binary (non-alphanumeric) data (or a significantly sized payload) to transmit, use multipart/form-data. Otherwise, use application/x-www-form-urlencoded.
-if you have to send non-ASCII text or large binary data, the form-data is for that.
You can use Raw if you want to send plain text or JSON or any other kind of string. Like the name suggests, Postman sends your raw string data as it is without modifications. The type of data that you are sending can be set by using the content-type header from the drop down.
Binary can be used when you want to attach non-textual data to the request, e.g. a video/audio file, images, or any other binary data file.
more details on : documentation
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;
?>
I have taken some code from MSDN to read emails using IMAP Client. I have changed little bit code so i can only read unseen email.
I am writing all response in Richtextbox.
The problems is format of Body text of Email is unreadable while all other text is fine.
void ReadEmail()
{
try
{
// there should be no gap between the imap command and the \r\n
// ssl.read() -- while ssl.readbyte!= eof does not work because there is no eof from server
// cannot check for \r\n because in case of larger response from server ex:read email message
// there are lot of lines so \r \n appears at the end of each line
//ssl.timeout sets the underlying tcp connections timeout if the read or write
//time out exceeds then the undelying connection is closed
tcpc = new System.Net.Sockets.TcpClient("imap.gmail.com", 993);
ssl = new System.Net.Security.SslStream(tcpc.GetStream());
ssl.AuthenticateAsClient("imap.gmail.com");
receiveResponse("");
username = "charlie#gmail.com";
password = "********";
receiveResponse("$ LOGIN " + username + " " + password + " \r\n");
receiveResponse("$ LIST " + "\"\"" + " \"*\"" + "\r\n");
receiveResponse("$ SELECT INBOX\r\n");
receiveResponse("$ UID SEARCH UNSEEN\r\n");
MatchCollection collection= Regex.Matches(Result,#" (\d{1,4})");
foreach (Match m in collection)
{
UNREAD_UID.Add(int.Parse(m.Groups[1].Value));
}
foreach (int x in UNREAD_UID)
{
receiveResponse("$ FETCH " +x + " body[header]\r\n");
richTextBox1.Text += Environment.NewLine+"-----------------------------------------------------------------------------------------------------------------------"+Environment.NewLine;
receiveResponse("$ FETCH " +x + " body[text]\r\n");
richTextBox1.Text += Environment.NewLine + "###########################################################2" + Environment.NewLine;
richTextBox1.Update();
}
//receiveResponse("$ STATUS INBOX (MESSAGES)\r\n");
// int number = 1;
receiveResponse("$ LOGOUT\r\n");
}
catch (Exception ex)
{
Console.WriteLine("error: " + ex.Message);
}
finally
{
if (sw != null)
{
sw.Close();
sw.Dispose();
}
if (ssl != null)
{
ssl.Close();
ssl.Dispose();
}
if (tcpc != null)
{
tcpc.Close();
}
}
}
void receiveResponse(string command)
{
try
{
if (command != "")
{
if (tcpc.Connected)
{
dummy = Encoding.ASCII.GetBytes(command);
ssl.Write(dummy, 0, dummy.Length);
}
else
{
throw new ApplicationException("TCP CONNECTION DISCONNECTED");
}
}
ssl.Flush();
buffer = new byte[5120];
bytes = ssl.Read(buffer, 0, 5120);
sb.Append(Encoding.ASCII.GetString(buffer));
Result = sb.ToString();
richTextBox1.Text += Environment.NewLine + Environment.NewLine + Environment.NewLine + Environment.NewLine + sb.ToString();
sb = new StringBuilder();
}
catch (Exception ex)
{
throw new ApplicationException(ex.Message);
}
}
Here is Sample of what i am getting
108 FETCH (BODY[TEXT] {25656}
DQoNCg0KDQo8IURPQ1RZUEUgaHRtbD4NCjxodG1sPg0KPGhlYWQ+DQo8dGl0bGU+TWlj
cm9zb2Z0IHR1cm5zIChhbG1vc3QpIGFueSBjYW1lcmEgaW50byBhIEtpbmVjdDwvdGl0
bGU+DQo8bWV0YSBodHRwLWVxdWl2PSJDb250ZW50LVR5cGUiIGNvbnRlbnQ9InRleHQv
aHRtbDsgY2hhcnNldD1VVEYtOCI+DQo8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVu
dD0id2lkdGg9ZGV2aWNlLXdpZHRoIj4NCjwhLS0gRWZmaW5nIFdpbmRvd3MgOCBNYWls
IGNsaWVudC4gQWRkIC13ZWJraXQtbWluLWRldmljZS1waXhlbC1yYXRpbzogMSB0byBz
Y2FyZSBpdCBhd2F5IGZyb20gdGhpcyBiaXQuIC0tPg0KPHN0eWxlIHR5cGU9InRleHQv
Y3NzIj4NCkBtZWRpYSBzY3JlZW4gYW5kIChtYXgtZGV2aWNlLXdpZHRoOiA1MDBweCkg
YW5kICgtd2Via2l0LW1pbi1kZXZpY2UtcGl4ZWwtcmF0aW86IDEpIHsNCgkuYm9keS1j
b250YWluZXIgeyB3aWR0aDoxMDAlICFpbXBvcnRhbnQ7IH0NCgkuYmFubmVyICAgICAg
ICAgeyBkaXNwbGF5OiBub25lICFpbXBvcnRhbnQ7IH0NCgkubW9iaWxlLWJhbm5lciAg
eyBkaXNwbGF5OiBibG9jayAhaW1wb3J0YW50OyB3aWR0aDozNDBweCAhaW1wb3J0YW50
OyBiYWNrZ3JvdW5kOiB1cmwoaHR0cDovL3d3dy5jb2RlcHJvamVjdC5jb20vc2NyaXB0
L21haWxvdXRzL3RlbXBsYXRlcy9uZXdzbGV0dGVyLWluc2lkZXIucG5nKSBuby1yZXBl
YXQgdG9wIGxlZ
Kindly help me.
You need to examine the Content-Transfer-Encoding header to undo Transfer encoding (in this case, that's Base64. Other alternatives are 7-bit or Quoted Printable). Or, better, download the entire message (Body[]) and apply a MIME parser/decoder to it to get an object representation of the headers, body, and attachments.
Max's answer above is correct, but I'm going to illustrate how to implement his suggestion using my MailKit library:
using (var client = new ImapClient ()) {
client.Connect ("imap.gmail.com", 993, true);
// since we're not using an OAuth2 token, remove it from the set
// of possible authentication mechanisms to try:
client.AuthenticationMechanisms.Remove ("XOAUTH2");
client.Authenticate ("charlie#gmail.com", "*****");
// SELECT the INBOX folder
client.Inbox.Open (FolderAccess.ReadWrite);
foreach (var uid in client.Inbox.Search (SearchQuery.NotSeen)) {
var message = client.Inbox.GetMessage (uid);
// at this point, 'message' is a MIME DOM that you can walk
// over to get the particular MIME-part that you want. For
// example, we could get a body part with a filename of
// "test.txt" using LINQ like this:
var attachment = message.BodyParts.OfType<MimePart> ()
.FirstOrDefault (x => x.FileName == "test.txt");
// decode the content to a MemoryStream:
using (var memory = new MemoryStream ()) {
attachment.ContentObject.DecodeTo (memory);
}
// since the attachment is probably a TextPart
// (based on the file extension above), we can actually
// use a simpler approach:
var textPart = attachment as TextPart;
if (textPart != null) {
// decode the content and convert into a 'string'
var text = textPart.Text;
}
}
client.Disconnect (true);
}
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!