Ionic capacitor file upload on php server using formData or file plugin

I want to update user information on server using a form. I can update information easily but I could not update profile pic.

So I search a lot a try below code in a new project for uploading files on server.

home.page.ts code

import { Component } from '@angular/core';

import { Camera, CameraOptions } from '@ionic-native/Camera/ngx';

import { File } from '@ionic-native/file/ngx';

import { FileTransfer, FileUploadOptions, FileTransferObject } from '@ionic-native/file-transfer/ngx';

import { ActionSheetController } from '@ionic/angular';

@Component({

  selector: 'app-home',

  templateUrl: 'home.page.html',

  styleUrls: ['home.page.scss'],

})

export class HomePage {

  public croppedImagePath = "";

  isLoading = false;

  imageURI: any;

  imageFileName: any;

  private fileTrans: FileTransferObject;

  imagePickerOptions = {

    maximumImagesCount: 1,

    quality: 50

  };

  constructor(

    public actionSheetController: ActionSheetController,

    private file: File,

    private transfer: FileTransfer,

    private camera: Camera,

  ) { }

  pickImage(sourceType) {

    const options: CameraOptions = {

      quality: 100,

      sourceType: sourceType,

      destinationType: this.camera.DestinationType.DATA_URL,

      encodingType: this.camera.EncodingType.JPEG,

      mediaType: this.camera.MediaType.PICTURE

    }

    this.camera.getPicture(options).then((imageData) => {

      // imageData is either a base64 encoded string or a file URI

      this.croppedImagePath = 'data:image/jpeg;base64,' + imageData;

    }, (err) => {

      // Handle error

    });

  }

  async selectImage() {

    const actionSheet = await this.actionSheetController.create({

      header: "Select Image source",

      buttons: [{

        text: 'Load from Library',

        handler: () => {

          this.pickImage(this.camera.PictureSourceType.PHOTOLIBRARY);

        }

      },

      {

        text: 'Use Camera',

        handler: () => {

          this.pickImage(this.camera.PictureSourceType.CAMERA);

        }

      },

      {

        text: 'Cancel',

        role: 'cancel'

      }

      ]

    });

    await actionSheet.present();

  }

  uploadFile() {

    const fileTransfer: FileTransferObject = this.transfer.create();

    let options: FileUploadOptions = {

      fileKey: 'file',

      fileName: 'ionicfile',

      chunkedMode: false,

      mimeType: "image/jpeg",

      headers: {}

    }

    fileTransfer.upload(this.imageURI, 'http://localhost/engace/api/api.php', options)

      .then((data) => {

        console.log(data + " Uploaded Successfully");

        this.imageFileName = "http://192.168.0.7:8080/static/images/ionicfile.jpg"

      }, (err) => {

        console.log(err);

      });

  }

  public download(fileName, filePath) {

    //here encoding path as encodeURI() format.  

    let url = encodeURI(filePath);

    //here initializing object.  

    const fileTransfer: FileTransferObject = this.transfer.create();

    console.log(url);

    // here iam mentioned this line this.file.externalRootDirectory is a native pre-defined file path storage. You can change a file path whatever pre-defined method.  

    fileTransfer.download(url, this.file.externalRootDirectory + fileName, true).then((entry) => {

      //here logging our success downloaded file path in mobile.  

      console.log('download completed: ' + entry.toURL());

    }, (error) => {

      //here logging our error its easier to find out what type of error occured.  

      console.log('download failed: ' + error);

    });

  }

}

HTML

<ion-header [translucent]="true">

  <ion-toolbar>

    <ion-title>

      Blank

    </ion-title>

  </ion-toolbar>

</ion-header>

<ion-content [fullscreen]="true">

  <ion-header collapse="condense">

    <ion-toolbar>

      <ion-title size="large">Blank</ion-title>

    </ion-toolbar>

  </ion-header>

  <div id="container">

    <strong>Ready to create an app?</strong>

    <p (click)="download('1535450786.jpg', 'http://localhost/abc/uploads/1535450786.jpg')">download</p>

  </div>

</ion-content>

No error in the code but When I click on download this gives error:-

Native: tried calling File.externalRootDirectory, but Cordova is not available. Make sure to include cordova.js or run in a device/simulator

This is also creating issue during build.

Is there a simple solution for download and upload files on php server?

Note:- I also try with formData but this does not send anything on server.

Your subject line speaks of Capacitor. Your code uses Cordova. First, you must decide whether you want to stick with the Cordova FileTransfer plugin. If you do, it won’t work in an ordinary desktop browser environment, period. That’s what the error you posted is trying to tell you. So if you want to keep going down this road, you’re going to have to always test in a device or emulator.

If you’re open to forgetting the existence of FileTransfer, then you already had what I think is the best choice here:

This method will work in a desktop browser, in a PWA, in an emulator, on a device. Make a FormData and pass it to HttpClient's post.

Ordinarily, it does, so either you aren’t doing it properly, or your server isn’t set up to handle multipart/form-data.

Thanks for reply again. I will check with formData again. If any issue I will ask you here.

Hi @rapropos , As per your suggestion I was trying to post simple form using formData but no luck.

formData is not posting anything on server.

I am using below code:-

headers: new HttpHeaders({

    'Content-Type': 'application/json; charset=UTF-8',

    'Access-Control-Allow-Origin': '*',

    'enctype': 'multipart/form-data',

  })

let formData: FormData = new FormData();
formData.append('files', this.fileToUpload, this.fileToUpload.name);
formData.append('user_id', this.user);

return this.http.post(this.Base_Url, { data, httpOptions }).subscribe((response: any) => {
});

PHP

header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Allow-Methods: POST, GET, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With");
header("Content-Type: application/json; charset=utf-8");

$postdata = file_get_contents("php://input");
$request = json_decode($postdata);
print_r(request);
print_r($_FILES);

Both are empty. Even nothing empty data{} showing headers (browser inspection).

Please guide me what is wrong here.

  1. headers should not exist. They’re internally inconsistent, inaccurate, and unnecessary. HttpClient will do the right thing when you pass a FormData as the payload to the post request…
  2. …which you aren’t doing. http.post(url, formData), not http.post(url, {data, httpOptions}).
  3. I don’t do PHP, but your backend seems to be expecting JSON, which won’t work when you feed it FormData. Make the PHP handle multipart/form-data properly.
1 Like

Thank you so much you made my day!

What I did:-

http.post(url, formData)

Hi @rapropos , I need one more help.

Please tell me how we can download a file from php server using ionic.

Hope you will suggest an easy way.