Best way to transfer a picture it to a server


#1

I am new to anything related to mobile app programming, Ionic (2), Angular (2), etc.
With my app I let the user take a picture, than categorize it and send it to a server.

I can already take a picture with the app. Now I want to transfer it with some information (a JSON-ified javascript object that contains information about creation date and time plus the category the user chose for that image). The server runs an apache webserver with php and perl.


#2

Look into the cordova file transfer plugin. There is support for it in ionic-native.


#3

I have a working example of the cordova file transfer plugin here for some inspiration :slight_smile:


#4

I upload images to Amazon s3 using a presigned post request. This saves my server from having to do the work and protects my API key.

I don’t use the file transfer plugin because I prefer to scale the images first for the user. For my app, I don’t need a users 4 mb, 16 mp image. A 100kb version will do just fine. I shrink the image using multi-step canvas resizing and then convert the image to a blob for uploading.


#5

hi @jack2,

Could you share to us, how to shrink the image and upload the image ??
Thanks in advance.


#6

I tried to build it for android (and it in fact builds it) but I get errors:

TypeScript error: C:/Users/schmid/ionic2/filetransferexpample/FileTransferExample/source/app/services/plugins.service.ts(54,26): Error TS2304: Cannot find name 'FileTransfer'.
TypeScript error: C:/Users/schmid/ionic2/filetransferexpample/FileTransferExample/source/app/services/plugins.service.ts(55,31): Error TS2304: Cannot find name 'FileUploadOptions'.
TypeScript error: typings/main.d.ts(2,1): Error TS6053: File 'typings/main/ambient/cordova/plugins/filesystem/index.d.ts' not found.
TypeScript error: typings/main.d.ts(3,1): Error TS6053: File 'typings/main/ambient/cordova/plugins/filetransfer/index.d.ts' not found.

Cannot use FileTransfer plugin
#7

These are missing typings. Make sure to install them. It will still work though when you build.
I believe the file transfer plugin is ionic native now. I’ll try to update my example accordingly as soon as possible.


#8

dtaalbers, your tutorial is nice but it gave me quite the headache :grin:

Is it possible that FileTransfer has been renamend to simply Transfer? No matter what I try there is no FileTransfer available anywhere - Transfer, however, is. And when I create an object of type Transfer it gives me all the methods from FileTransfer (i.e. upload, download, onProgress and abort) that are used in several tutorials/examples.

This bugged the hell out of me so I looked down into the source code. In node_modules/ionic-native/dist/index.d.ts there is import { Transfer } from './plugins/filetransfer'; and further down there is one very long export line with all the imported stuff. In this line there is File but no FileTransfer, however there is an item Transfer.
Looking into the plugins folder there is a filetransfer.d.ts file with
exports for the interfaces FileUploadOptions, FileUploadResult, FileTransferError and also for Transfer (but NOT FileTransfer).
So now I’m trying to use Transfer. (My new problem now is that I don’t know how one implements aforementioned interfaces).

For someone who is rather new to software development, especially with (big) frameworks that consists of many different parts, this is rather complex and the (re-)naming can be quite confusing.


#9

Hi,

Yes. The cordova file transfer plugin is ionic-native since a short period of time. My example precedes that time, its a setup that worked when it was not ionic-native. I am in the progress updating the example to a nice ionic-native style. So stay tuned :slight_smile:


#10

I’ve updated my example with the ionic-native version. You can find the example here :slight_smile:


#11

Hey, thank you very much for updating your example. I couldn’t get your repo code to run because of

error peerinvalid The package rxjs@5.0.0-beta.8 does not satisfy its siblings' peerDependencies requirements!

so I went through your code line by line and just changed my code, and file transfer is now working in my app.

But now I’m stuck on the server side :grin: because I have no idea how to save the sent image on the server. I have an apache running with php. I tried dumping the content of $_REQUEST (which contains $_POST and $_GET) into a text file to see what is sent, and all it gives me is the file name I set in the upload function:

Array(
    [fileName] => a_nice_imagephoto699.7003063617065
)

What am I missing now? Where is my image data if not in $_POST or $_GET? Or how do you save the submitted image(s) on the server?


#12

I’m afraid I can not be of much help regarding your PHP server issues. Not much knowledge of PHP but some wordpress experience :stuck_out_tongue: .


#13

OK, I’m stupid lol. A little google search solved my problem …
For those searching the webs and ending at this thread, I want to add what I found out / what I did:

PHP has a bunch of super globals, one of which is $_FILES, which I was completely unaware of. I dumped the array $_FILES into a textfile like this

$files = print_r($_FILES, true);
file_put_contents("uploaded/"files.txt", $files);

to see what it contains and - tada - the $_FILES array seems to contain my image file. To get it out of there and did some more research … There even is a function

`move_uploaded_file(string $filename, string $destination)` 

(doc) that is designated to move files that were uploaded via POST. Did that
move_uploaded_file($_FILES["file"]["tmp_name"], "uploaded/" . $_FILES["file"]["name"].".jpg");
which moved the file and voila, my image is there, just as it should.
Finally got it to work.

Thanks y’all for taking so much time for a newbie :smile:


#14

Hi @dtaalbers,

I’m having trouble using file-transfer. I’m using v 2.0.0 beta 6.
Here is my code …

 saveImage() {
        this.fileName = this.image.substr(this.image.lastIndexOf('/')+1);

        this.userService.uploadPic(this.fileName, this.paramsUserToken).then((result) => {
            console.log('upload success', result);            
            this.uploadImage = result;
        },(error) => {
            console.log(error);
        });
         
        this.userService.saveUserProfilePic(this.uploadImage, this.paramsUserToken, this.paramsUserId).subscribe(results => {
                console.log('success save to users', results);            
                }, (error) => {
                    alert('Save failed', error);
        });
}

and my user_service.js…

uploadPic(dataFile, dataToken) {
        this.platform.ready().then(() => {
            let ft = new Transfer();
            let filename = dataFile + ".jpg";
            let headers = new Headers(this.Backend_Header);
            headers.append('Content-Type', 'multipart/form-data');
            headers.append('user-token', dataToken);
            let options = {
                fileKey: 'file',
                fileName: filename,
                mimeType: 'image/jpeg',
                chunkedMode: false,
                headers: headers
            };
            
            this.Backend_Profile_Pic = this.Backend_File + 'profile/';
            
            ft.upload(dataFile, this.Backend_Profile_Pic, options, false)
                .then((result) => {                 
                    console.log(result);
                    return result;
                }).catch((error) => {
                    console.log(error);
            });         
        });
    }

and my error was

app.bundle.js:32065 TypeError: Cannot read property 'then' of undefined
    at EditUserProfilePage.saveImage (app.bundle.js:1321)
    at AbstractChangeDetector.ChangeDetector_EditUserProfilePage_0.handleEventInternal (viewFactory_EditUserProfilePage:267)
    at AbstractChangeDetector.handleEvent (app.bundle.js:14890)
    at AppView.triggerEventHandlers (app.bundle.js:24719)
    at eval (viewFactory_EditUserProfilePage:951)
    at app.bundle.js:33229
    at app.bundle.js:33307
    at ZoneDelegate.invoke (angular2-polyfills.js:390)
    at Object.onInvoke (app.bundle.js:29153)
    at ZoneDelegate.invoke (angular2-polyfills.js:389)

Please help me to correct the code. I still don’t understand how to use ionic native promise.
Thanks in advance.


#15

Hi,

What I see is that you are trying to handle a promise from the uploadPic function. Like this

this.userService.uploadPic(...).then(...);

But when I look at your uploadFunction I see that it doesn’t return a promise. So it when your trying to handle the promise with .then() it fails.

Try to change the uploadPic function to

  // Notice the return type
  uploadPic = (dataFile, dataToken) : Promise<FileUploadResult> => {
       this.platform.ready().then(() => {

            let ft = new Transfer();
            let filename = dataFile + ".jpg";
            let headers = new Headers(this.Backend_Header);
            headers.append('Content-Type', 'multipart/form-data');
            headers.append('user-token', dataToken);
            let options = {
                fileKey: 'file',
                fileName: filename,
                mimeType: 'image/jpeg',
                chunkedMode: false,
                headers: headers
            };
        
            this.Backend_Profile_Pic = this.Backend_File + 'profile/';

            // return the excisting promise and handle errors in your saveImage function
            return ft.upload(dataFile, this.Backend_Profile_Pic, options, false); 
       });
   }

#16

Hi @dtaalbers,

already try your suggestion… but still the same error…

EXCEPTION: Error during evaluation of "click"
ypeError: Cannot read property ‘then’ of undefined
at EditUserProfilePage.saveImage (app.bundle.js:1321)
at AbstractChangeDetector.ChangeDetector_EditUserProfilePage_0.handleEventInternal (viewFactory_EditUserProfilePage:267)
at AbstractChangeDetector.handleEvent (app.bundle.js:14874)
at AppView.triggerEventHandlers (app.bundle.js:24703)
at eval (viewFactory_EditUserProfilePage:951)
at app.bundle.js:33213
at app.bundle.js:33291
at ZoneDelegate.invoke (angular2-polyfills.js:390)
at Object.onInvoke (app.bundle.js:29137)
at ZoneDelegate.invoke (angular2-polyfills.js:389)

another suggestion???.
Thanks in advance.


#17

Check out Onymos Media component if you prefer the convenience of a commercial plugin, which gets you regular updates when new OS releases, cordova releases, device versions come up along with professional support.

Plus, you can get to market in minutes saving you time to focus on what is core for your app.


#18

Hi @dtaalbers
I like to find a way to post image and data to a node server. Could you tell me if it is possible with your example ?

Thanks in advance.


#19

Hi Jack2,

Are you able to share how to upload an image to S3? I’m struggling and getting post MethodNotAllowed errors after pre-signing it correctly.

I would much appreciate that!

Thanks,

Boris


#20

I’ve tried your example and it’s seems good, but the upload doesn’t work. On the server side I run NodeJS and Multer. Have you ever made this work with this technology ?