Search Unity

  1. Unity 2020.1 has been released.
    Dismiss Notice
  2. We are looking for feedback on the experimental Unity Safe Mode which is aiming to help you resolve compilation errors faster during project startup.
    Dismiss Notice
  3. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

Android: upload image to server

Discussion in 'Scripting' started by UnityFuchs, Jun 26, 2020.

  1. UnityFuchs

    UnityFuchs

    Joined:
    Apr 18, 2018
    Posts:
    22
    I want: Upload an image from my android-phone to my webspace.
    At the moment, I am testing this with xampp, localhost.

    I have read and tested out, countless solutions and suffered > 50 hours without any solution to work, now. Maybe some GURU can help me. :D
    On the official Unity-page i haven't found a useful tutorial.

    Help: It can be a logic-error. Or my image isn't POST proper. Or there is something with the webspace login. Or something different I don't know about.
    The error "undefined index" looks like there could be data, but it is not an proper image-data.

    Note: This is the solution that looks best, from all my tests.

    Code:

    Code (CSharp):
    1. using System.Collections;
    2. using UnityEngine;
    3. using UnityEngine.Networking;
    4. using System; //Convert.ToBase64String(), no use atm
    5.  
    6. public class Image_Upload : MonoBehaviour
    7. {
    8.     [Header("Activate debug-info.")]
    9.     [SerializeField] private bool debugLog = false;
    10.  
    11.     [Header("Webspace Info.")]
    12.     [SerializeField] private string phpUrl = "http://localhost/Image_Upload.php";
    13.     [SerializeField] private string target_directory = "http://localhost/images/";
    14.     public string my_image_path = "Front/IMG-20200305-WA0056"; //This is for testing : Resources folder
    15.  
    16.     private WWWForm my_form;
    17.    
    18.     private void Start()
    19.     {
    20.         my_form = new WWWForm();
    21.         SetConnection();
    22.     }
    23.  
    24.     private void SetConnection()
    25.     {      
    26.         Sprite my_sprite = Resources.Load<Sprite>(my_image_path); //ändern zu spriterenderer
    27.         Texture2D my_texture = my_sprite.texture;
    28.         if (!my_texture.isReadable) //Texture needs to be readable, otherwise you can't encode it.
    29.         {
    30.             my_texture = Tools.ReadableTexture2D(my_texture); //This is from my Tools.cs. Should work.
    31.             if (debugLog)
    32.                 Debug.Log("Made texture readable.");
    33.         }
    34.         byte[] bytes = my_texture.EncodeToPNG();
    35.  
    36.         if (debugLog)
    37.             Debug.Log("my_image_file: " + bytes.Length);
    38.  
    39.         my_form.AddField("target_directory", target_directory); //Target of the directory to be placed.
    40.         my_form.AddBinaryData("my_image", bytes);
    41.     }
    42.  
    43.     public void Upload()
    44.     {
    45.         StartCoroutine(EstablishConnection());
    46.     }
    47.  
    48.     IEnumerator EstablishConnection()
    49.     {
    50.         if (debugLog)
    51.             Debug.Log("Establish Connection");
    52.  
    53.         using (UnityWebRequest www = UnityWebRequest.Post(phpUrl, my_form))
    54.         {
    55.             yield return www.SendWebRequest(); //Wait until the server answers.
    56.  
    57.             if (www.isNetworkError || www.isHttpError)
    58.             {
    59.                 if (debugLog)
    60.                     Debug.Log("Connection error: " + www.error);
    61.             }
    62.             else
    63.             {
    64.                 if (debugLog)
    65.                     Debug.Log("Connection established: " + www.downloadHandler.text); //Show result as text.
    66.                 byte[] results = www.downloadHandler.data; //Show result as binary data.
    67.             }
    68.         }
    69.     }
    70. }
    71.  
    Code (CSharp):
    1. <?php
    2.     //Webspace Connection data
    3.     $target_directory = $_POST["target_directory"];
    4.     $my_image = $_POST["my_image"];
    5.     $upload_ok = 0;
    6.  
    7.     //echo "Data: " . $target_directory;
    8.     //echo " and Data: " . $my_image;
    9.  
    10.     $image_filetype = strtolower(pathinfo($my_image,PATHINFO_EXTENSION));
    11.  
    12.     //Check image now.
    13.     $check = getimagesize($_FILES[$my_image]["png"]);
    14.  
    15.     if($check !== false)
    16.     {
    17.             echo "File is an image - " . $check["mime"] . ".";
    18.             $upload_ok = 1;
    19.     }
    20.     else
    21.     {
    22.         echo "File is not an image.";
    23.         $upload_ok = 0;
    24.     }
    25. ?>
    Debug:
    Connection data added.

    Made texture readable.

    my_image_file: 1097640

    Establish Connection

    Connection established: <br />
    Notice: Undefined index: my_image in C:\xampp\htdocs\Image_Upload.php on line 4<br />
    <br />
    Notice: Undefined index: in C:\xampp\htdocs\Image_Upload.php on line 13<br />
    <br />
    Warning: getimagesize(): Filename cannot be empty in C:\xampp\htdocs\Image_Upload.php on line 13<br />
    File is not an image.
    UnityEngine.Debug:Log(Object)
    <EstablishConnection>d__8:MoveNext() (at Assets/Image_Upload.cs:68)
    UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)
     
  2. Adrian

    Adrian

    Joined:
    Apr 5, 2008
    Posts:
    484
    The upload part looks fine but server side has many issues. You need to use the name with
    $_FILES
    , not the empty
    $my_image
    variable and there's no sub-entry called "png".

    There's an example in the top comment on Handling file uploads and you should also read the relevant subpage: POST method uploads.

    Also note all the warnings about security concerns. File uploads are tricky to handle properly and can easily lead to your server being exploitable. Make sure you do all the checks and precautions, letting the client decide the target directory is definitely a no-go.
     
  3. UnityFuchs

    UnityFuchs

    Joined:
    Apr 18, 2018
    Posts:
    22
    Step 1: The ["name"]-snippet is like the ID of the $_FILES-array. $_FILES["my_image"]["...ID..."]. Hope I understood that right. There is no error, but I think that this is wrong.
    Code (CSharp):
    1.  
    2. $target_directory = $_POST["target_directory"];
    3. $my_image = $target_directory . basename($_FILES["my_image"]["name"]);
    Step 2: Then, I thought I can work with my $my_image : var.
    Notice: Undefined index: size in C:\xampp\htdocs\Image_Upload.php on line 13<br />
    Code (CSharp):
    1. $check = getimagesize([$my_image]["size"]);
    Have no clue. Commented it out for now. :D

    Step 3: Now I wonder how PHP will upload the image. Couldn't test it out, because I didn't fix all errors, but I think it is something like that:
    Code (CSharp):
    1. sprintf($directory_name, $my_image);
    But that can't be right, because $my_image has concatenatet with my target_directory. I'm totally confused about this PHP.
     
  4. Adrian

    Adrian

    Joined:
    Apr 5, 2008
    Posts:
    484
    You don't directly get the image from
    $_FILES
    , it only provides the information about the uploaded files. You have to use
    $_FILES["my_image"]["xxx"]
    with the "my_image" string for all the information, don't use
    $my_image
    there.

    $_FILES["my_image"]["tmp_name"]
    holds the path to where the uploaded file was temporarily stored, use
    move_uploaded_file($_FILES["my_image"]["tmp_name"], $dst_path);
    to move it somewhere permanent.

    Using the temp path,
    getimagesize($_FILES["my_image"]["tmp_name"]);
    should work as well.
     
    UnityFuchs likes this.
  5. UnityFuchs

    UnityFuchs

    Joined:
    Apr 18, 2018
    Posts:
    22
    I don't get anything you want to tell me and I have read the PHP-sites like 30 times. Again, I try to explain myself and hopefully, you can tell my where my brain stucks.

    //my form from the c#-script
    byte[] bytes = my_texture.EncodeToPNG();
    my_form.AddField("target_directory", target_directory); //string
    my_form.AddBinaryData("my_image", bytes); //byte-array


    Code (CSharp):
    1. <?php
    2.     //01. $target_directory gets the string from the c#-script
    3.     $target_directory = $_POST["target_directory"];
    4.  
    5.     //02. $my_image gets the byte-array from the c#-script.
    6.     //    I want to store the byte-array in this var!
    7.     //    This is wrong ... But in my logic, this should work 100%, like $target_directory.
    8.     //    Otherwise this var is totally useless.
    9.     $my_image = $_POST["my_image"];
    10.  
    11.     //03. $my_image_size : returns array
    12.     //    Now, I think I can adress the indices with $my_image["size"], $my_image["type"], ...
    13.     //    ... and get the size, for example.
    14.     $my_image_size_1 = getimagesize($my_image["size"]);
    15.  
    16.     //04. Another test for the size.
    17.     //Syntax: filesize(filename : string)
    18.     $my_image_size_2 = filesize($my_image["name"]);
    19.  
    20.     //05. Upload the image : returns bool
    21.     //Syntax: move_uploaded_file(filename : string, destination : string)
    22.     $is_uploaded = move_uploaded_file($my_image["name"], $target_directory);
    23. ?>
     
  6. UnityFuchs

    UnityFuchs

    Joined:
    Apr 18, 2018
    Posts:
    22
    I tested something different. Maybe I am closer to a solution, now. Still need some advice.

    Image_Upload.cs
    Code (CSharp):
    1. [SerializeField] private string phpUrl = "http://localhost/Image_Upload.php";
    2. [SerializeField] private string target_directory = "http://localhost/images/";
    3. public string my_image_path = "Front/IMG-20200305-WA0056";
    4. public string file_name = "IMG-20200305-WA0056";
    5.  
    6.     my_form.AddField("target_directory", target_directory);
    7.     my_form.AddField("file_name", file_name);
    8.     my_form.AddBinaryData("my_image", bytes);

    Image_Upload.php
    Code (CSharp):
    1. <?php
    2.     $destination = $_POST["target_directory"];
    3.     //weird $filename
    4.     $filename = "my_image"; //$_POST["file_name"];
    5.     $basename = basename($filename, $_FILES[$filename]["type"]);
    6.  
    7.     print_r($_FILES);
    8.     echo "\n" . "FILES NAME: " . $_FILES[$filename]["name"];
    9.     echo "\n" . "FILES TYPE: " . $_FILES[$filename]["type"];
    10.     echo "\n" . "FILES SIZE: " . $_FILES[$filename]["size"];
    11.     echo "\n" . "FILES tmp_name: " . $_FILES[$filename]["tmp_name"];
    12.     echo "\n" . "FILES error: " . $_FILES[$filename]["error"];
    13.     echo "\n" . "FILES basename: " . $basename;
    14.     echo "\n" . "destination: " . $destination;
    15.  
    16.     $is_uploaded = move_uploaded_file($_FILES[$filename]["name"], $destination);
    17.     if($is_uploaded == TRUE)
    18.     {
    19.         echo "\n" . "File is uploaded";
    20.     }
    21.     else
    22.     {
    23.         echo "\n" . "File is NOT uploaded.";
    24.     }
    25. ?>
    Debug
    Connection established: Array
    (
    [my_image] => Array
    (
    [name] => my_image.png
    [type] => image/png
    [tmp_name] => C:\xampp\tmp\phpC517.tmp
    [error] => 0
    [size] => 1097640
    )

    )

    FILES NAME: my_image.png
    FILES TYPE: image/png
    FILES SIZE: 1097640
    FILES tmp_name: C:\xampp\tmp\phpC517.tmp
    FILES error: 0
    FILES basename: my_image
    destination: http://localhost/images
    File is NOT uploaded.

    $is_uploaded = move_uploaded_file($_FILES[$filename]["tmp_name"], $destination);
    I tried to use the tmp_name instead of the name, too. Then I get an error:

    Warning: move_uploaded_file(http://localhost/images): failed to open stream: HTTP wrapper does not support writeable connections in C:\xampp\htdocs\Image_Upload.php on line 16<br />
    <br />
    Warning: move_uploaded_file(): Unable to move 'C:\xampp\tmp\phpB714.tmp' to 'http://localhost/images' in C:\xampp\htdocs\Image_Upload.php on line 16<br />
     
  7. UnityFuchs

    UnityFuchs

    Joined:
    Apr 18, 2018
    Posts:
    22
    Yay, I made it work. :p

    I still don't understand why you can't add the $_FILES-byte-array to a $variable and
    why you need to use the tmp_name and
    how does this thing ever login to my server and
    why my path needs to be "images/" and not "http://localhost/images/" and
    so on and so on and
    why this is not userfriedly.

    Hint: The print_r($_FILES); helped me alot to understand what data i get, after all.
    ... and Google.

    Anyways, here is what you need:
    Code (CSharp):
    1. <?php
    2.     $folder_name = $_POST["folder_name"]; //added a "create folder" possibility, the mkdir-stuff.
    3.     $destination = $_POST["target_directory"]; //"images/" : string
    4.     $filename = $_POST["file_name"]; //Adding the filename again. Maybe this can be done better.
    5.  
    6.     //Create a new folder on the server to save the images.
    7.     $is_folder_created = mkdir ($destination . $folder_name);
    8.     if($is_folder_created == TRUE) {
    9.         echo "\n" . "New folder created.";
    10.         $basename = $destination . $folder_name . "/" .basename($filename, $_FILES[$filename]["type"]);
    11.     }
    12.     else {
    13.         echo "\n" . "New folder NOT created.";
    14.     }
    15.  
    16.     //Upload the image
    17.     $is_uploaded = move_uploaded_file($_FILES[$filename]["tmp_name"], $basename); //Needs to be ["tmp_name"]
    18.     if($is_uploaded == TRUE) {
    19.         echo "\n" . "File is uploaded";
    20.     }
    21.     else {
    22.         echo "\n" . "File is NOT uploaded.";
    23.     }
    24. ?>
     
unityunity