2

I'm writing programs to try to learn Android. I'm trying to get a video to upload to the server with retrofit. My retrofit works uploading EditText etc. I'm using the same IP address here as I do there.

In the code the camera works fine records video and renames the video, I believe the select video works fine (not totally sure on that but gallery opens I select a video and it doesn't crash, and the PHP allows me to post a video using Postman). But when I hit the upload button crash.

I'm not sure if the issue is in getting the real path, in the retrofit code, or maybe my file select doesn't work? I tried multiple examples. Just not getting it to work. I can't figure out the error. I tried to throw some toasts in there to see if I am getting an error but I don't ever get a toast.

Here is my code:

Slim/PHP index

  $app->post('/saveFile', function(Request $request, Response $response){

 $response = array();

if (isset($_POST['desc']) && ($_POST['ID']) && strlen($_POST['desc']) > 0 && 
$_FILES['image']['error'] === UPLOAD_ERR_OK) {

$upload = new uploads();

            $file = $_FILES['image']['tmp_name'];

            $desc = $_POST['desc'];
            $ID = $_POST['ID'];  

            if ($upload->saveFile($ID, $file, 
 getFileExtension($_FILES['image']['name']), $desc)) {
                $response['error'] = false;
                $response['message'] = 'File Uploaded Successfullly';
            }

         else {
            $response['error'] = true;
            $response['message'] = 'Required parameters are not available';
        }


        echo json_encode($response);

 } 
});

 function getFileExtension($file)
{
$path_parts = pathinfo($file);
return $path_parts['extension'];
}

uploads.php

 class uploads
{

 private $con;

 public function __construct()
 {
    require_once dirname(__FILE__) . '/DbConnect.php';

    $db = new DbConnect();
    $this->con = $db->connect();
}


public function saveFile($ID, $file, $extension, $desc)
{
    $name = round(microtime(true) * 1000) . '.' . $extension;
    $filedest = dirname(__FILE__) . UPLOAD_PATH . $name;
    move_uploaded_file($file, $filedest);

    $url = $server_ip = gethostbyname(gethostname());

    $stmt = $this->con->prepare("INSERT INTO images (ID, description, url) 
 VALUES (?, ?, ?)");
    $stmt->bind_param("sss", $ID, $desc, $name);
    if ($stmt->execute())
        return true;
else

    return false;
}


}

API interface

@Multipart
@POST("saveFile")
Call<MyResponse> uploadImage(@Part MultipartBody.Part file, @Part("desc") 
RequestBody desc, @Field("ID") String ID);

my activity class

 public class vidcam extends Activity implements View.OnClickListener {

 String ID, prepend;
 private final int VIDEO_REQUEST_CODE = 100;
 private final int REQUEST_TAKE_GALLERY_VIDEO =22;

 File video_file;

 Button RecordButton, tobaitana, viduploadbutton, uploadvideo;
 Uri selectedVideo;


 @Override
 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_vidcam);

    RecordButton = (Button) findViewById(R.id.RecordButton);
    RecordButton.setOnClickListener(this);

    tobaitana = (Button) findViewById(R.id.tobaitana);
    tobaitana.setOnClickListener(this);

    viduploadbutton = (Button) findViewById(R.id.viduploadbutton);
    viduploadbutton.setOnClickListener(this);

    uploadvideo = (Button) findViewById(R.id.uploadvideo);
    uploadvideo.setOnClickListener(this);

 }
 @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent 
data) {

    if (requestCode == VIDEO_REQUEST_CODE){
        Toast.makeText(getApplicationContext(), "Video Saved", 
 Toast.LENGTH_LONG).show();
    }
    if (resultCode == RESULT_OK) {
        if(requestCode == REQUEST_TAKE_GALLERY_VIDEO){
            selectedVideo = data.getData();

 }}}

 public File getfilepath () throws IOException {

    File videofolder = new File("sdcard/video_app");
    if (!videofolder.exists())
    {
        videofolder.mkdir();
    }

    String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    prepend = "MOBILITY_" + timestamp + "_";
    video_file = File.createTempFile(prepend, ".mp4", videofolder);

    return video_file;
}

@Override
public void onClick(View view) {
    switch (view.getId()){

        case R.id.RecordButton:
            Intent video_intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
            File videolocation = null;
            try {
                videolocation = getfilepath();
            } catch (IOException e) {
                e.printStackTrace();
            }
            Uri video_uri = Uri.fromFile(videolocation);
            video_intent.putExtra(MediaStore.EXTRA_OUTPUT, video_uri);
            video_intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
            startActivityForResult(video_intent, VIDEO_REQUEST_CODE);
            break;

        case R.id.tobaitana:
            Intent toanbait = new Intent(this, Abait.class);
            startActivity(toanbait);
            break;

        case R.id.viduploadbutton:
            Intent selectfile = new Intent(Intent.ACTION_PICK, MediaStore.Video.Media.EXTERNAL_CONTENT_URI);
            startActivityForResult(selectfile, REQUEST_TAKE_GALLERY_VIDEO);
            break;

        case R.id.uploadvideo:
            uploadFile(selectedVideo);
            break;
    }
}

public void useID() {
    SharedPreferences shareID = getSharedPreferences("shareID", Context.MODE_PRIVATE);
    ID = shareID.getString("ID", "");
}

private String getRealPathFromURI(Uri contentUri) {
   String filePath;
   Cursor cursor = getContentResolver().query(contentUri, null, null, null, null);
   if(cursor == null)
   {
       filePath = contentUri.getPath();
   }else {
       cursor.moveToFirst();
   int idx = cursor.getColumnIndex(MediaStore.Video.VideoColumns.DATA);
   filePath = cursor.getString(idx);
   cursor.close();
       Toast.makeText(getApplicationContext(), "realpath toast" + filePath, Toast.LENGTH_LONG).show();

   }
   return filePath;
}

private void uploadFile(Uri selectedVideo) {
    useID();
    File vidfile = new File(getRealPathFromURI(selectedVideo));
    if (vidfile.exists()) {
    RequestBody requestBody = RequestBody.create(MediaType.parse(getContentResolver().getType(selectedVideo)), vidfile);
    MultipartBody.Part file = MultipartBody.Part.createFormData("filename", vidfile.getName(), requestBody);
    RequestBody desc = RequestBody.create(MediaType.parse("text/plain"), vidfile.getName());

    Call<MyResponse> call = RetrofitClient.getInstance().getAPIService().uploadImage(file, desc, ID);

    call.enqueue(new Callback<MyResponse>() {
        @Override
        public void onResponse(Call<MyResponse> call, Response<MyResponse> response) {

            if (!response.body().error) {
                Toast.makeText(getApplicationContext(), "File Uploaded Successfully...", Toast.LENGTH_LONG).show();
            } else {
                Toast.makeText(getApplicationContext(), "Some error occurred...", Toast.LENGTH_LONG).show();
            }
        }
        @Override
        public void onFailure(Call<MyResponse> call, Throwable t) {
            Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_LONG).show();
        }
    });
} else {Toast.makeText(getApplicationContext(), "no file exists...", Toast.LENGTH_LONG).show();
    }
 }
 }
halfer
  • 19,824
  • 17
  • 99
  • 186
gtcode
  • 47
  • 2
  • 7
  • Can you provide detail of the crash? – Lan Nguyen Aug 28 '18 at 23:50
  • I'm not sure how to do that. My computer is to old to run the emulator I put it on a S3 to test it. Basically I hit the case R.id.uploadvideo: button and it crashes. – gtcode Aug 29 '18 at 01:01
  • Your Android Studio did not print any log about the crash? – Lan Nguyen Aug 29 '18 at 02:24
  • OK, is I think I solved one problem. My S3 API is only 17. and the code I was using I think may have been to new? So I used Paul Burke method to help with that. https://stackoverflow.com/questions/20067508/get-real-path-from-uri-android-kitkat-new-storage-access-framework But I am still getting an error. java lang IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $ – gtcode Aug 29 '18 at 02:25
  • I can't emulate on my laptop, it's too old. All my computer equipment is years old. I'm not rich unfortunately. So I am learning to code on older equipment. – gtcode Aug 29 '18 at 02:27
  • It means you parsed a json string with invalid object type – Lan Nguyen Aug 29 '18 at 02:50
  • yes but these are the only 2 strings I have parsed anything in. And they both look correct RequestBody requestBody = RequestBody.create(MediaType.parse(getContentResolver().getType(selectedVideo)), vidfile); MultipartBody.Part file = MultipartBody.Part.createFormData("filename", vidfile.getName(), requestBody); RequestBody desc = RequestBody.create(MediaType.parse("text/plain"), vidfile.getName()); – gtcode Aug 29 '18 at 03:19
  • one is used to get the multipart body. the file. and the other should get the file name to go to the sql server database. – gtcode Aug 29 '18 at 03:23
  • https://stackoverflow.com/questions/39918814/use-jsonreader-setlenienttrue-to-accept-malformed-json-at-line-1-column-1-path this is the error, but I have no idea what it means. They give a fix but I don't under stand their answer. – gtcode Aug 29 '18 at 06:11

1 Answers1

0

Your controller method is all wrong, you have to use the Request / Response objects and than return the modified Response; My version is closer to the intended usage, but it is no way perfect, mostly because I don't have the android tools.

I hope it helps, more info here: Request UploadedFiles HttpStatusCodes

    $app->post('/saveFile', function(\Slim\Http\Request $request, \Slim\Http\Response $response){

    $responseData = [];
    $responseCode = 400;

    /** @var \Psr\Http\Message\UploadedFileInterface[] $files */
    $files    = $request->getUploadedFiles();
    /** @var string[] $postData */
    $postData = $request->getParsedBody();

    if ( !empty($postData['desc']) && ($postData['ID']) && !empty($files)) {
        $upload = new uploads();

        // use this if you are only upload one file
        // otherwise loop though them all
        $file = reset($files);

        $desc = $postData['desc'];
        $ID   = $postData['ID'];

        // this means the file was uploaded ok
        if ( $file->getError() === UPLOAD_ERR_OK ) {
            if ( $upload->saveFile($ID, $file, $file->getClientMediaType(), $desc) ) {
                $responseData['error']   = false;
                $responseData['message'] = 'File Uploaded Successfully';

                $responseCode = 200;
            }

            else {
                $responseData['error']   = true;
                $responseData['message'] = 'Required parameters are not available';

                $responseCode = 406;
            }
        }
        else {
            $responseData['error']   = true;
            $responseData['message'] = 'File upload error: '. $file->getError();

            $responseCode = 409;
        }
    }

    return $response->withJson($responseData, $responseCode);
});

Uploads edit

class uploads
{

    private $con;

    public function __construct()
    {
        // you shouldn't need this if you  are using Slim
        // and you are doing require_once '/vendor/autoload.php' at the beginning of your 
        // index.php
        require_once dirname(__FILE__) . '/DbConnect.php';

        $db = new DbConnect();
        $this->con = $db->connect();
    }


    public function saveFile($ID, \Psr\Http\Message\UploadedFileInterface $file, $extension, $desc)
    {
        $name     = round(microtime(true) * 1000) . '.' . $extension;
        $filedest = dirname(__FILE__) . UPLOAD_PATH . $name;

        $file->moveTo($filedest);

        $url = $server_ip = gethostbyname(gethostname());

        $stmt = $this->con->prepare("INSERT INTO images (ID, description, url) VALUES (?, ?, ?)");
        $stmt->bind_param("sss", $ID, $desc, $name);

        return $stmt->execute();
    }
}
zedling
  • 638
  • 8
  • 28
  • thank you for your reply. I think you are on the right track here. I do think there was a problem with the path before but now that i think is fixed. I am getting the ID, and the desc( which is the file name) the url post to the Database is 1535579779132.multipart/form-data and no file is actually uploading. on top of it the app crashes but it's at least posting. So there is definitely a problem between the two. PHP is not my strong point. I only learned it as much as I needed it in order to learn android. so off to google i go – gtcode Aug 29 '18 at 22:03
  • ok I got the database data to post what I want it to post. But still not getting the file and the app crashes. But it's at least sending the ID, desc(file name) and the url(path on server) to the database. – gtcode Aug 29 '18 at 23:11
  • ok, database fills correctly, app no longer crashes it sends a response file uploaded successfully. but I have 1 problem. No file is uploading. I have even tried on postman nothing is going up. $file = reset($files); to $file->getClientFilename() to move_uploaded_file($file, $filedest); is somehow not coded right. – gtcode Aug 30 '18 at 04:06
  • ahh sorry, I forgot about the upload; you can pass the whole `$file` object to you uploads class; and then call `$file->moveTo($filedest)` instead of `move_uploaded_file`; I'll update my answer – zedling Aug 30 '18 at 09:22
  • I seem to get an error on that Type: InvalidArgumentException Message: Upload target path is not writable File: C:\xampp\htdocs\LearnAndroid1\vendor\slim\slim\Slim\Http\UploadedFile.php Line: 231 I'm not sure that the directory is the problem. I was able to use postman to upload to it prior. – gtcode Aug 30 '18 at 22:04
  • I wanted you to know I went back to an older way of doing it and i got my file to upload. Instead of using @Part MultipartBody.Part file and the rest of the multipart i used (@Part("image\"; filename=\"myfile.jpg\" ") RequestBody file and then changed some on the php side. It finally uploaded. I would like to learn the MultipartBody.Part but I am totally lost for figuring it out. My PHP skills are just not that good. But I finally got my file to upload so I'm taking that as a win for today, got to take my victories where i can. I saved the other code with the error, love to learn how to fix – gtcode Aug 30 '18 at 23:16