Problem uploading image using FileSystem.uploadAsync and image-picker

453 views Asked by At

I am trying to use expo-image-picker and expo-file-system to take/select images and upload to my server. I have it saving the images to a state and can access to display it etc but I am running into issues when attempting to upload it. I am trying to upload it to my server and then using PHP to do what it does with it.

I have existing code example and this is all pretty much based upon it but that does not work either from https://galaxies.dev/react-native-image-upload

Its not exactly what I want anyway, I need to select or take the image and then use image manipulator to compress it. I have this all working and I can get the uri or the base64 data.

How can I use the FileSystem.uploadAsync to upload either the image it self or the base64 data to my server. From the example I am using PHP to get the data and save it.

This is what I am using for my RN code, without the image.manipulation part :

To get the image:

const selectImage = async (useLibrary: boolean) => {
        let result;
        const options: ImagePicker.ImagePickerOptions = {
            mediaTypes: ImagePicker.MediaTypeOptions.Images,
            allowsEditing: true,
            aspect: [4, 3],
            quality: 0.75
        };

        if (useLibrary) {
            result = await ImagePicker.launchImageLibraryAsync(options);
        } else {
            await ImagePicker.requestCameraPermissionsAsync();
            result = await ImagePicker.launchCameraAsync(options);
        }

        // Save image if not cancelled
        if (!result.canceled) {
            setImage(result.assets[0].uri);
            upload_img(image); // I have tried (result.assets[0].uri)
        }
    };

and the code attempting to upload the image:-

const upload_img = async (image) => {
    setUploading(true);
  
    await FileSystem.uploadAsync('https://mysever/upload.php', uri, { // I have tried changing this to the result.assets[0].uri also?
      httpMethod: 'POST',
      uploadType: FileSystem.FileSystemUploadType.MULTIPART,
      fieldName: 'file',
      fileName: 'Test', // I added this
    });
  
    setUploading(false);
  };

I think the problem is where it is getting the uri? I have tried all sorts but it does not seem to work. The closest I have is above and it seems to upload but there is nothing on the server. Is the filename supposed to be there?

There is this bit that saves the image to but seems to assign different information and I think this should somehow be included but I can not work out where :

const saveImage = async (uri: string) => {
    await ensureDirExists();
    const filename = new Date().getTime() + '.jpeg';
    const dest = imgDir + filename;
    await FileSystem.copyAsync({ from: uri, to: dest });
    setImages([...images, dest]); // I am only sending selected file so no need to save it
};

Am I going around it the correct way, I seem to have tried lots of different approaches like fetch, axios and blob but this seemed the best.

The PHP code is the same as the code on the example about but here it is : -

<?php
header('Access-Control-Allow-Origin: *');
$target_path = "/";

$target_path = $target_path . basename( $_FILES['file']['name']);

if(move_uploaded_file($_FILES['file']['tmp_name'], $target_path)) {
header('Content-type: application/json');
$data = ['success' =>
true, 'message' => 'Upload and move success']; echo json_encode( $data ); } else{
header('Content-type: application/json'); $data = ['success' => false, 'message' => 'There was an
error uploading the file, please try again!']; echo json_encode( $data ); } 
?>

Any help would be greatly appreciated

2

There are 2 answers

5
dcourt1 On

The FormData interface provides a way to construct a set of key/value pairs representing form fields and their values, which can be sent using the fetch(), XMLHttpRequest.send() or navigator.sendBeacon() methods. It uses the same format a form would use if the encoding type were set to "multipart/form-data". More details about the feature here

const uploadFile = {
    uri: selectedImage.uri,
    name: selectedImage.fileName,
    type: selectedImage.type, // mimetype
    size: selectedImage.fileSize, //bytes
};

const formData = new FormData();
formData.append('your_key',  uploadFile );

//set your headers with the right content type and optionnaly credentials
const headers = new Headers({
    'Content-Type': 'multipart/form-data',
    'Authorization': //if needed)
});

const apiUrl = 'https://your_backend_here'; //waiting for post request

//finally fetch your api
fetch(apiUrl, {
    method: 'POST',
    headers: headers,
    body: formData
});
1
JulesUK On

I have managed to do it with the image-manipulator like this :-

// Save image if not cancelled
        if (!result.canceled) {
            setImage(result.assets[0].uri);
    
            const manipResult = await ImageManipulator.manipulateAsync(
                result.localUri || result.assets[0].uri,
                [{ rotate: 0 }, { resize: { width: 200, height: 200 } }],
                { compress: 1, format: ImageManipulator.SaveFormat.JPG},
              );
        
            setImage(manipResult.uri);
            uploadImage(manipResult.uri);
        }
    };


    const uploadImage = async (uri) => {
        setUploading(true);
        console.log(uri);     
        await FileSystem.uploadAsync('https://www.mydomain/upload.php', uri, {
          httpMethod: 'POST',
          uploadType: FileSystem.FileSystemUploadType.MULTIPART,
          fieldName: 'file'
        });
      
        setUploading(false);
      };

It works fine using this and the existing PHP but is there anyway I get change the name of the file before uploading?