3

I'm using Unity to make a button that takes a screenshot and then uploads it to my server.
The point is that if I send a form to the server, the WWW gives me an Internal Server Error.
I've tried a lot of examples from the internet and it still gives me that error. Every time.

This is my C# code for uploading the screenshot:

IEnumerator uploadPhoto(){
    /*yield return new WaitForEndOfFrame();
    Texture2D snap = new Texture2D (webCamTexture.width, webCamTexture.height);
    snap.SetPixels (webCamTexture.GetPixels ());
    snap.Apply ();
    webCamTexture.Stop();*/

    yield return new WaitForEndOfFrame();
    Texture2D snap = new Texture2D(Screen.width, Screen.height);
    snap.ReadPixels(new Rect(0,0,Screen.width,Screen.height),0,0);
    snap.Apply();

    byte[] bytes = snap.EncodeToPNG();

    WWWForm form = new WWWForm();
    form.AddField("username", PlayerPrefs.GetString("username"));
    form.AddBinaryData("form_file", bytes, "screenshot.png", "image/png");
    //Debug.Log(System.BitConverter.ToString(bytes));

    WWW connection = new WWW(url, form); 
    yield return connection;

    if (connection.error != null)
    {
        Debug.Log("Server-side error: " + w.error);
    }
    else
    {
        Debug.Log(connection.text);
    }
}

And this is the php script made to receive that BinaryData:

if ($_POST){
    if ($_FILES["form_file"]["error"] !== UPLOAD_ERR_OK) {
        die("Upload failed with error code " . $_FILES["form_file"]["error"]);
    } else {
        if ((($_FILES["form_file"]["type"] == "image/jpg") || ($_FILES["form_file"]["type"] == "image/jpeg") || ($_FILES["form_file"]["type"] == "image/png")) && ($_FILES["form_file"]["size"] < 20000000000)){
            if ($_FILES["form_file"]["error"] > 0) {
                echo "File error: " . $_FILES["form_file"]["error"] . ""; 
            }else{ 

                echo "Uploaded image: " . $_FILES["form_file"]["name"] . "<br>";
                echo "Type: " . $_FILES["form_file"]["type"] . "<br>";
                echo "Size: " . ($_FILES["form_file"]["size"] / 1024) . " Kb<br>";
                echo "Temporary name: " . $_FILES["form_file"]["tmp_name"] . "<br>";

                if (file_exists("upload/" . $_FILES["form_file"]["name"])){
                    echo $_FILES["form_file"]["name"] . " already exists. ";
                }else{
                    move_uploaded_file($_FILES["form_file"]["tmp_name"], "upload/" . $_FILES["form_file"]["name"]);
                    echo "Stored in: " . "upload/" . $_FILES["form_file"]["name"];
                }
            }
        } else{ 
        echo "Invalid file"; 
        }
    }
} else{
    echo "No POST. ";
}


I don't know what's wrong with this. I'm trying to make this work for 2 days now. I just know that the error is on the server-side. I tried to change the permissions of the script to 777, no effect.
What am I doing wrong?

Kartm
  • 39
  • 1
  • 11
  • 1
    You don't seem to declare `url` in the code posted? (probably just declared somewhere else but, have to ask) As far as checking if the error is in PHP, why not make a simple HTML form that posts to the same url as your c# code and see what happens? Looks like you could make a form as simple as `
    `
    –  Jul 17 '16 at 01:14
  • Yeah, "url" has been declared somewhere else. It seems to work when I create a form like this: `
    `
    – Kartm Jul 17 '16 at 02:03
  • So I think `enctype="multipart/form-data` is the solution. But when I print the headers sent by Unity, I've got this: `multipart/form-data; boundary="LiRsRUtwjolUpWljHmjIWC3T0vP3BcLJziUi6QsO`. What's wrong with Unity? – Kartm Jul 17 '16 at 02:10
  • sorry, completely forgot about `enctype="multipart/form-data"`. Still, next step would be to confirm your c# code is sending the right request headers (sounds like you're going down that route already). The [boundary is not the problem](https://www.w3.org/Protocols/rfc1341/7_2_Multipart.html) That's a feature :) Posting the request (and response) headers might be helpful to answer your question (be sure to remove any sensitive information!!) –  Jul 17 '16 at 02:13
  • So these are request headers (from jsFiddle): `Accept-Encoding: identity; Connection: Keep-Alive; Content-Length: 371632; Content-Type: multipart/form-data;boundary="DKFmp2DHmX4FpZwOymYvtUPImak8molU96aLyRAJ"; X-Unity-Version: 5.3.5f1` and these are response headers: `STATUS = HTTP/1.1 500 Internal Server Error; DATE = Sun, 17 Jul 2016 02:39:08 GMT; SERVER = Apache mod_qos/10.10 mod_bwlimited/1.4; CONTENT-LENGTH = 668; CONNECTION = close; CONTENT-TYPE = text/html; charset=iso-8859-1`. What now? Are these headers right? – Kartm Jul 17 '16 at 02:41
  • 2
    Get a program like Fiddler to example what you're sending to your webserver. Then, try to use something like Postman to send a similar request to the webserver. Make sure you have error logging enabled in PHP and look at the output. If all else fails, die at lines from top to bottom to see how far your program gets before it explodes. – Warty Jul 17 '16 at 03:07
  • BTW what's your reasoning for using ienumerable + yield return? – Warty Jul 17 '16 at 03:08
  • Your problem could just be cause you're making a cross-origin request. read through this, there are code samples http://stackoverflow.com/questions/298745/how-do-i-send-a-cross-domain-post-request-via-javascript –  Jul 17 '16 at 03:09
  • @Warty But the php script isn't even executing, it just returns me Internal Server Error. IEnumerable and yield return are just from my Unity game. – Kartm Jul 17 '16 at 03:25
  • @Terminus Internal Server Error again. Here's my script: [link](http://pastebin.com/1ET5LNxS) Is this code not working only for me? – Kartm Jul 17 '16 at 03:26
  • So are you getting logs from PHP? – Warty Jul 17 '16 at 03:27
  • @Warty My cPanel doesn't show any php errors. But there is something like this in my logs: [link](http://pastebin.com/Bgsyba5k). Is that a 404 error? How is it possible? – Kartm Jul 17 '16 at 03:31
  • 1
    You really need to use something like Postman to throw a request at your server. But yeah, it looks like a 404 error meaning that the webserver probably isn't configured the way you think it should be. Try putting a dummy.txt next to uploadPhoto.php and see if you can access that? – Warty Jul 17 '16 at 03:35
  • @Warty So I tried to use Postman. When I try to put dummy.txt or a *.png file, it returns me "Upload failed with error code ". If you look into my php script, you'll see that there should be an error code. But it's gone. What's going on? – Kartm Jul 17 '16 at 03:40
  • Can you hit dummy.txt or the png file with a web browser? – Warty Jul 17 '16 at 03:40
  • @Warty Oh, wait. I used form-data label in Postman. Everything is working like it should! But only in Postman. When I send my screenshot from Unity game, it still gives me 500 Internal Server Error. – Kartm Jul 17 '16 at 03:42
  • @Warty Yes, I can. So my script seems to work, but when Unity tries to send a POST request, it seems to crash or something. – Kartm Jul 17 '16 at 03:44
  • 1
    Time to grab Fiddler and compare the requests being made! – Warty Jul 17 '16 at 03:45
  • @Warty Done. Here is the request from web browser: [link](http://pastebin.com/nY2ZvQFY) and there's a request from Unity: [link](http://pastebin.com/cngFaC9c). I see the difference, but what does it mean? – Kartm Jul 17 '16 at 03:51
  • Are you sending the same image? One has a significantly different content length than the other. – Warty Jul 17 '16 at 03:55
  • Also, can you try running the webserver locally? Sometimes things like Cloudflare will filter out requests with "strange" user agents (e.g. Java) because it thinks they're bots. – Warty Jul 17 '16 at 03:56
  • @Warty No, it's not the same image. The image from web browser is just a small 39x29 painting, and the second image is (at least it was supposed to be) screenshot of my Unity game. The code is in the first post. – Kartm Jul 17 '16 at 03:58
  • @Warty I think then the error would be different than 500 Internal Server Error. And I don't use things like Cloudflare, it's just a shared web hosting. – Kartm Jul 17 '16 at 04:00
  • 1
    @Kartm What Unity version? Also, can you post the url of the web server or can you create another url on the server so that I or others can try it. I don't know if you are fine with that but if you could, I may be able to reproduce this problem. If you want to do this, you might as well make a temporary username for us to test this. That's up to you. – Programmer Jul 17 '16 at 04:06
  • So what happens if you die at the top of the script? You can try playing around with the headers being sent out to see what the webserver doesn't like, but without more info (e.g. what errors are actually happening) it's hard to say what can be up. My only other guess would be the origin header and hotlink prevention. – Warty Jul 17 '16 at 04:06
  • @Warty Nothing happened, still this error. I just found out that I get Internal Server Error when calling to every script on my website. It stopped when I removed this line: `form.AddBinaryData("form_file", bytes, "screenshot.png", "image/png");`. – Kartm Jul 17 '16 at 04:12
  • @Programmer I think it's the last chance to fix it. The url to the script is [URL](http://fotowyzwania.xaa.pl/game/uploadPhoto.php). – Kartm Jul 17 '16 at 04:14
  • Ok. Got it. What's the password for header? How do I know if the file uploaded successfully? Any message I will get from your server? – Programmer Jul 17 '16 at 04:17
  • There is no password and there's the script code: [link](http://pastebin.com/7SF7ChhN). You will get an echo with the message. – Kartm Jul 17 '16 at 04:19
  • Ok. When I said password, I meant username. I think that the username is username. I will get back to you. – Programmer Jul 17 '16 at 04:19
  • I was able to get the error. Now I need a way to test your php code and make sure that it works. I want to use wireshack to see what's going on. How can I test that script with my web browser? – Programmer Jul 17 '16 at 04:25
  • 2
    @Kartm and you've tried sending an equivalent file over the wire, right? Check for max file upload size. Note the Unity upload isn't compressing e.g. with gzip so it's expecting the server is okay with a 300KB payload. – Warty Jul 17 '16 at 04:33
  • I've set upload_max_filesize to 4M. What do you mean by testing this script in your browser? If you need the code, I sent it. – Kartm Jul 17 '16 at 04:38
  • 1
    I can't continue my testing because it says there is an error on line 8. Please fix that. Remove the */ on your php script – Programmer Jul 17 '16 at 05:10
  • @Programmer Whoops. Done. – Kartm Jul 17 '16 at 13:38
  • 1
    @Kartm I put my answer about what I discovered. I will be back in hours to see if you solved the problem. Please comment under the answer if there is a question. – Programmer Jul 17 '16 at 14:52

1 Answers1

2

Copied your php code to my server and came to conclusion that the problem is from your server. It is not setup properly or this is permission problem which also means that it is not set up properly.

With the php in your question, I got the message from my test server:

Uploaded image: screenshot.png<br>Type: image/png<br>Size: 1.494140625 Kb<br>Temporary name: C:\Windows\Temp\php1354.tmp<br>Stored in: upload/screenshot.png

When ran on your server, I got:

Server-side error: 500 Internal Server Error

The php code I used:

<?php
if ($_POST){
    if ($_FILES["form_file"]["error"] !== UPLOAD_ERR_OK) {
        die("Upload failed with error code " . $_FILES["form_file"]["error"]);
    } else {
        if ((($_FILES["form_file"]["type"] == "image/jpg") || ($_FILES["form_file"]["type"] == "image/jpeg") || ($_FILES["form_file"]["type"] == "image/png")) && ($_FILES["form_file"]["size"] < 20000000000)){
            if ($_FILES["form_file"]["error"] > 0) {
                echo "File error: " . $_FILES["form_file"]["error"] . ""; 
            }else{ 

                echo "Uploaded image: " . $_FILES["form_file"]["name"] . "<br>";
                echo "Type: " . $_FILES["form_file"]["type"] . "<br>";
                echo "Size: " . ($_FILES["form_file"]["size"] / 1024) . " Kb<br>";
                echo "Temporary name: " . $_FILES["form_file"]["tmp_name"] . "<br>";

                if (file_exists("upload/" . $_FILES["form_file"]["name"])){
                    echo $_FILES["form_file"]["name"] . " already exists. ";
                }else{
                    move_uploaded_file($_FILES["form_file"]["tmp_name"], "upload/" . $_FILES["form_file"]["name"]);
                    echo "Stored in: " . "upload/" . $_FILES["form_file"]["name"];
                }
            }
        } else{ 
        echo "Invalid file"; 
        }
    }
} else{
    echo "No POST. ";
}
?>

When I used form.AddField("username", PlayerPrefs.GetString("username")); on your server, I got Upload failed with error code. After including form.AddBinaryData("form_file", bytes, "screenshot.png", "image/png");, I got the 500 error message.

This is a big sign that you don't have permission to read write the file. Also the image was written to C:\Windows\Temp\php1354 on my server. You have to change your php code to write to somewhere else instead of the C:\Windows\Temp\php1354 directory. I would suggest you contact your host to change the permission. This is a server problem. Not Unity or php code fault.

Programmer
  • 121,791
  • 22
  • 236
  • 328
  • I just sent a message to my host, now I'm waiting for response. – Kartm Jul 17 '16 at 21:51
  • 1
    @Kartm Also when I visit the link in your server with my browser, I get an **Upload failed with error code** message. When I visit mine from the browser, I get the **No POST.** message. Please make sure that the php code you have matches with the one in my answer. Let me know when they get get back to you. – Programmer Jul 17 '16 at 22:26
  • I finally got my problem fixed! The host has answered me saying that they were having one of their anti-spam enabled on my server. It works now! HUGE thanks for you guys :) – Kartm Jul 18 '16 at 10:20
  • 1
    @Kartm Lol I knew that. I had to test with my own server to verify your problem. You are welcome and happy coding! – Programmer Jul 18 '16 at 10:22