Upload multipart image to PHP server from iOS app

2019-09-02 22:41发布

I'm trying to upload an image with my iOS app (Swift 2.0). The server gets the request and sends status 200, but when it comes to the file upload the image-data doesn't get uploaded. The print_r($_FILES); command gives me response:

Array
(
)
wrong format for image

This is the code:

func send()
{

    let request = NSMutableURLRequest(URL: NSURL(string: "***URL to upload.php***")!)

    request.HTTPMethod = "POST"
    let postString = "username=\(globalUsr)&photo-name=\(globalImage.description)&photo-description=\(message.text)"

    let myData : NSData! = postString.dataUsingEncoding(NSUTF8StringEncoding)

    let imageData :NSData = UIImageJPEGRepresentation(globalImage, 1.0)!;

    let boundary = "-----SwiftBoundary-----"
    let contentType = "multipart/form-data; boundary=\(boundary)"
    let body = NSMutableData();

    let tempData = NSMutableData()
    let fileName = "\(globalImage.description).jpg"
    let parameterName = "contest-photo"

    tempData.appendData(myData)
    tempData.appendData("--\(boundary)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
    let fileNameContentDisposition = "name=\(parameterName)"
    let contentDisposition = "Content-Disposition: form-data; name=\"\(fileName)\"; \(fileNameContentDisposition)\r\n"
    tempData.appendData(contentDisposition.dataUsingEncoding(NSUTF8StringEncoding)!)
    tempData.appendData("Content-Type: \(contentType)\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
    tempData.appendData(imageData)
    tempData.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)


    body.appendData(tempData)

    body.appendData("\r\n--\(boundary)--\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)

    request.setValue("\(body.length)", forHTTPHeaderField: "Content-Length")
    request.HTTPBody = body


    let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
        data, response, error in

        if error != nil {
            print("error=\(error)")
            return
        }

        let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
        print("responseString = \(responseString!)")
    }
    task.resume()


}

The PHP code is:

<?php

// Load Wordpress
define('WP_USE_THEMES', false);
require_once("../../../../../wp-load.php");

    $username = $_POST["username"];

    $m = contest_upload_photo('contest-upload-photo','contest_upload_photo',username_exists($username ));




function contest_upload_photo($atts, $content = null,$user_ID=null) {

//Important variables 
if ($user_ID == null){
    die(json_encode("There is no user.")); 
}

$html = '';//Inciate output string
$koncovky = array('jpg', 'jpeg', 'png', 'gif');

$number_images = get_user_meta($user_ID, 'contest_user_images', true);
if(empty($number_images)){$number_images=0;}


$error = array();
// Do some minor form validation to make sure there is content

$name = trim($_POST['photo-name']);
    /*if (empty($_POST['photo-title'])){
    $error['title'] = __('Please enter the photo title','photo-contest');
} else {
    $title = trim($_POST['photo-title']);  
}*/


//Check photo
if ($_FILES['contest-photo']['error'] == UPLOAD_ERR_NO_FILE){
    $error['photo'] = __('Please select the image','photo-contest');
    die("no photo selected");
} else {

  //Control upload and extension
  if ($_FILES['contest-photo']['error']) {
    $error['upload_error'] = __('Error image upload.','photo-contest');
    die("Image upload error");
  } 
  elseif (!in_array(strtolower(pathinfo($_FILES['contest-photo']['name'], PATHINFO_EXTENSION)), $koncovky)) {
    $error['extension_error'] = __('Image must be jpg, png or gif.','photo-contest');
    print($koncovky);
    print_r($_FILES);
    die("wrong format for image");
  } 
  elseif (!($imagesize = getimagesize($_FILES['contest-photo']['tmp_name'])) || $imagesize[2] > 3) {
    $error['type_error'] = __('Image type must be jpg, png or gif.','photo-contest');
    die("image too big");
  }   
  else {

    @$img=getimagesize($_FILES['contest-photo']['tmp_name']);

    $minimum = array('width' => '400', 'height' => '400');
    $width= $img[0];
    $height =$img[1];
      if ($width < $minimum['width'] ){
        $error['type_error'] = __('Minimum image width is 400px.','photo-contest');
        die("width is too small");
      }
      elseif ($height <  $minimum['height']){
        $error['type_error'] = __('Minimum image height is 400px.','photo-contest');
        die("height is too small");
      }
      $photo_limit = get_option( 'pcplugin-photo-limit', true );
      $size_maxi = $photo_limit;  
      $size = filesize($_FILES['contest-photo']['tmp_name']); 
      if($size>$size_maxi){  
        $error['size_error'] = __('File size is above allowed limitations!','photo-contest'); 
        die("file is too big"); 
}  
    }


}


if(empty($error)){
//If no exist error - create attachment post
  if(empty($_POST['photo-description'])){ 
    $description = sanitize_text_field($_POST['photo-description']);
  }else{
    $description = '';
  }

@$wp_filetype = wp_check_filetype(basename($_FILES['contest-photo']['name']), null );
@$wp_upload_dir = wp_upload_dir();
$attachment = array(
 'guid' => $wp_upload_dir['url'] . '/' . basename( $_FILES['contest-photo']['name'] ), 
 'post_mime_type' => $wp_filetype['type'],
 'post_title' => $name,
 'post_content' => $description,
 'post_status' => 'inherit'
);

require_once(ABSPATH . 'wp-admin/includes/image.php');
require_once(ABSPATH . "wp-admin" . '/includes/file.php');
require_once(ABSPATH . "wp-admin" . '/includes/media.php');
$attach_id = media_handle_upload( 'contest-photo', 0,$attachment );

$attach_data = wp_generate_attachment_metadata( $attach_id, $wp_upload_dir['url'] . '/' . basename( $_FILES['contest-photo']['name']) );

wp_update_attachment_metadata( $attach_id, $attach_data );

update_post_meta($attach_id,'contest-active',1);
update_post_meta($attach_id,'contest-photo-points',0);
update_post_meta($attach_id,'contest-photo-author',$user_ID);
    update_post_meta($attach_id,'post_author',$user_ID);

$number_images = $number_images+1;
update_user_meta($user_ID, 'contest_user_images', $number_images);


    $my_post = array(
  'ID'           => $attach_id,
  'post_author'   => $user_ID,
    );

    wp_update_post( $my_post );


    $image = get_post( $attach_id );

    if ($attach_id==""){
        die("306");
    }else{
        echo($attach_id); 
    }
    if ( ! $image || 'attachment' != $image->post_type || 'image/' != substr( $image->post_mime_type, 0, 6 ) )
        die( json_encode( array( 'error' => sprintf( __( 'Failed resize: %s is an invalid image ID.', 'regenerate-thumbnails' ), esc_html( $attach_id ) ) ) ) );



    $fullsizepath = get_attached_file( $image->ID );

    if ( false === $fullsizepath || ! file_exists( $fullsizepath ) )

    // @set_time_limit( 900 ); // 5 minutes per image should be PLENTY

    $metadata = wp_generate_attachment_metadata( $image->ID, $fullsizepath );

    if ( is_wp_error( $metadata ) )
    if ( empty( $metadata ) )
    wp_update_attachment_metadata( $image->ID, $metadata );
return $attach_id; 


}


}
    ?>

UPDATE:

If I try it without:

request.setValue(contentType, forHTTPHeaderField: "Content-Type")

I get:

data =<22546865 72652069 73206e6f 20757365 722e22>
response = <NSHTTPURLResponse: 0x7fcd7e184980> { URL: http://www.clip2gether.com/mobile/app/v1/iOS/upload/upload.php } { status code: 200, headers {
"Cache-Control" = "no-store, no-cache, must-revalidate, post-check=0, pre-check=0";
Connection = close;
"Content-Type" = "text/html; charset=UTF-8";
Date = "Sun, 04 Oct 2015 20:39:26 GMT";
Expires = "Thu, 19 Nov 1981 08:52:00 GMT";
Pragma = "no-cache";
Server = "Apache/2.4.10";
"Set-Cookie" = "qtrans_cookie_test=1; path=/; domain=www.clip2gether.com";
"Transfer-Encoding" = Identity;
"X-Powered-By" = "PHP/5.6.12";
} }

And if I try it with the line:

request.setValue(contentType, forHTTPHeaderField: "Content-Type")

data =<41727261 79417272 61790a28 0a290a77 726f6e67 20666f72 6d617420 666f7220 696d6167 65>
response = <NSHTTPURLResponse: 0x7fdd22f3e660> { URL: http://www.clip2gether.com/mobile/app/v1/iOS/upload/upload.php } { status code: 200, headers {
"Cache-Control" = "no-store, no-cache, must-revalidate, post-check=0, pre-check=0";
Connection = close;
"Content-Type" = "text/html; charset=UTF-8";
Date = "Sun, 04 Oct 2015 20:46:19 GMT";
Expires = "Thu, 19 Nov 1981 08:52:00 GMT";
Pragma = "no-cache";
Server = "Apache/2.4.10";
"Set-Cookie" = "qtrans_cookie_test=1; path=/; domain=www.clip2gether.com";
"Transfer-Encoding" = Identity;
"X-Powered-By" = "PHP/5.6.12";
} }

So basically I'm getting the same response with setting the value contentType, as hex-code:

There is no user 

and without setting it

ArrayArray
(
)
wrong format for image

2条回答
Evening l夕情丶
2楼-- · 2019-09-02 23:00

I searched for hours and finally pieced this working code together using mostly info from this page.

Here's how you can upload an image together with a text parameter to a PHP script and save the image on the server.

// PHP SCRIPT (the content of upload.php)
<?php
$image = $_FILES['image-upload']['tmp_name'];
$username = $_POST['username'];
$filename = "upload_" . date("ymd_at_H_i_s", time()) . ".jpg";
if (move_uploaded_file($image, $filename)) {
    echo "Image upload for user ".$username." Success"; // this will show up in XCode output
} else {
    echo "Image upload for user ".$username."  Failed"; // this will show up in XCode output
}
?>




// SWIFT 2.3 IMAGE UPLOAD FUNCTION 
let uploadPHPURL = "http://somehost.com/uploads/upload.php"
func uploadImage(image:UIImage?, userName:String)
{

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {

        let request = NSMutableURLRequest(URL: NSURL(string: self.uploadPHPURL)!)
        request.HTTPMethod = "POST"

        //let image = self.imageView.image
        let imageData :NSData = UIImageJPEGRepresentation(image!, 0.3)!

        let boundary = "--- unique boundary string ---"
        let contentType = "multipart/form-data; boundary=\(boundary)"
        let fileName = "image.jpg"
        let parameterName = "image-upload"

        let body = NSMutableData()


        // duplicate this if you need to send more parameters to the php script
        body.appendData("--\(boundary)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
        body.appendData("Content-Disposition: form-data; name=\"username\"\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
        body.appendData("\(userName)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)



        // this is the file parameter
        body.appendData("--\(boundary)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
        body.appendData("Content-Disposition: form-data; name=\"\(parameterName)\"; filename=\"\(fileName)\"\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
        body.appendData("Content-Type: image/jpeg\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
        body.appendData(imageData)
        body.appendData("\r\n--\(boundary)--".dataUsingEncoding(NSUTF8StringEncoding)!)

        request.setValue(contentType, forHTTPHeaderField: "Content-Type")
        request.setValue("\(body.length)", forHTTPHeaderField: "Content-Length")
        request.HTTPBody = body


        let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
            data, response, error in

            if error != nil {
                print("error=\(error)")
                return
            }

            let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
            print("imageUpload responseString: \(responseString!)")
        }
        task.resume()
    }
}
查看更多
甜甜的少女心
3楼-- · 2019-09-02 23:05

Your body data is wrong formatted for a multipart/form-data enctype. Assuming that you want to POST the following fields:

  • username a text field
  • photo-name a text field
  • photo-description a text field
  • contest-photo a file field(will contain image's binary data)

Your body should look like:

--SwiftBoundary
Content-Disposition: form-data; name="username"

my username value
--SwiftBoundary
Content-Disposition: form-data; name="photo-name"

my photo-name value
--SwiftBoundary
Content-Disposition: form-data; name="photo-description"

my photo-description value
--SwiftBoundary
Content-Disposition: form-data; name="contest-photo"; filename="myfile.jpg"
Content-Type: image/jpeg

...my image binary data...
--SwiftBoundary--

You also will have to set the following headers on request:

  • Content-Length to the length of body
  • and Content-Type: multipart/form-data; boundary=SwiftBoundary, here is important that the boundary string matches the one used in body

If you manage to update your request to look like above, you will find your image data under $_FILES['contest-photo']

Your send function should look something like this:

func send()
{
    let request = NSMutableURLRequest(URL: NSURL(string: "***URL to upload.php***")!)

    request.HTTPMethod = "POST"

    let imageData :NSData = UIImageJPEGRepresentation(globalImage, 1.0)!;

    let boundary = "SwiftBoundary"
    let contentType = "multipart/form-data; boundary=\(boundary)"
    let fileName = "\(globalImage.description).jpg"
    let parameterName = "contest-photo"

    let body = NSMutableData()

    body.appendData("--\(boundary)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
    body.appendData("Content-Disposition: form-data; name=\"username\"\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
    body.appendData("\(globalUsr)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)

    body.appendData("--\(boundary)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
    body.appendData("Content-Disposition: form-data; name=\"photo-name\"\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
    body.appendData("\(globalImage.description)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)

    body.appendData("--\(boundary)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
    body.appendData("Content-Disposition: form-data; name=\"photo-description\"\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
    body.appendData("\(message.text)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)

    body.appendData("--\(boundary)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
    body.appendData("Content-Disposition: form-data; name=\"\(parameterName)\"; filename=\"\(fileName)\"\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
    body.appendData("Content-Type: image/jpeg\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
    body.appendData(imageData)
    body.appendData("\r\n--\(boundary)--".dataUsingEncoding(NSUTF8StringEncoding)!)

    request.setValue(contentType, forHTTPHeaderField: "Content-Type")
    request.setValue("\(body.length)", forHTTPHeaderField: "Content-Length")
    request.HTTPBody = body


    let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
        data, response, error in

        if error != nil {
            print("error=\(error)")
            return
        }

        let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
        print("responseString = \(responseString!)")
    }
    task.resume()
}
查看更多
登录 后发表回答