user1272589
user1272589

Reputation: 809

Upload item image using Square Connect API and PHP

I've reviewed the old questions posted here on Stackoverflow about this issue. But I didn't find any example for php integration.

Here is a sample of my code to do that but it's failing

    $url = 'https://connect.squareup.com/v1/me/items/9999999/image';
    $auth_bearer = 'Authorization: Bearer ' . $this->accessToken;
    $image_data = base64_encode(file_get_contents('image.jpeg'));
    $header = array(
        $auth_bearer,
        'Accept: application/json',
        'Content-Type: multipart/form-data; boundary=BOUNDARY',

    );

    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
    curl_setopt($ch, CURLOPT_POSTFIELDS, 'files=' . $image_data);
    $head = curl_exec($ch);
    curl_close($ch);

    $response = json_decode($head);
    echo "<pre>";
    print_r($response);
    echo "</pre>";

And nothing happens... any help here?

Thanks

Upvotes: 2

Views: 831

Answers (4)

Braath Waate
Braath Waate

Reputation: 1

Troy's solution using @ is deprecated and I was unable to get it to work. Byron's solution works with the CURLOPT_POST before the CURLOPT_POSTFIELDS (see Mavooks comment at https://www.php.net/manual/en/function.curl-setopt.php) and removing the Content-Type from the header. That is because it is automatically multipart if CURLOPTS_POSTFIELDS is an array and manually including it seems to override it, but then it is missing the boundary.

$square_url = 'https://connect.squareup.com/v1/me/items/' . $square_item_id . '/image';

$cfile = new CURLFile($image_path_on_server, 'image/png', 'image_data');
$image_data = array('image_data' => $cfile);

$curl = curl_init();
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
  'Authorization: Bearer ' . $access_token,
  'Accept: application/json'
));
curl_setopt($curl, CURLOPT_POST, TRUE);
curl_setopt($curl, CURLOPT_POSTFIELDS, $image_data);
curl_setopt($curl, CURLOPT_URL, $square_url);
curl_setopt($curl, CURLOPT_SAFE_UPLOAD, TRUE);
curl_setopt($curl, CURLOPT_BINARYTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($curl, CURLINFO_HEADER_OUT, TRUE);
curl_setopt($curl, CURLOPT_VERBOSE, TRUE);
$json = curl_exec($curl);
curl_close($curl);

Upvotes: 0

ScorpionFiko
ScorpionFiko

Reputation: 43

Strictly speaking Square API documentation, their method can be implemented keeping a few things in mind.

-- Your request must be enclosed in a boundary and contain the Content disposition, name, filename, content type like the sample below.

--BOUNDARY
Content-Disposition: form-data; name="image_data"; filename="MyImage.png"
Content-Type: image/png
                               {BLANK LINE IS REQUIRED}
IMAGE BINARY DATA GOES HERE
--BOUNDARY--

In essence, the format of the request must be exactly as specified in the sample. This includes the 'boundary', the newline characters, the necessary headers, a blank line between the headers (for some reason nothing works if the line isn't present), and the actual image binary data. NOTE: the boundary can be any string that you choose, but it must be used consistently. In code, this would look something like this:

$boundary = "---------------------" . md5(mt_rand() . microtime());
$imageToUpload = "--{$boundary}" . "\r\n" .
             "Content-Disposition: form-data; name=\"image_data\"; filename=\"" . $full_path_to_image_file . "\"" . "\r\n" .
             "Content-Type: image/jpeg" . "\r\n" .
             "\r\n" . // <- empty line is required
             (file_get_contents($full_path_to_image_file)) . "\r\n" .
             "--{$boundary}--";

The above will produce a request that looks like this:

-----------------------51b62743876b1201aee47ff4b1910e49
Content-Disposition: form-data; name="image_data"; filename="/some/directory/image.jpg"
Content-Type: image/jpeg

����
-----------------------51b62743876b1201aee47ff4b1910e49--

-- Technically speaking, the Content-Type in the request must change with the type of image you're uploading (image/jpeg or image/png). You can set the content type to application/octet-stream to cover all basis.

-----------------------51b62743876b1201aee47ff4b1910e49
Content-Disposition: form-data; name="image_data"; filename="/some/directory/image.jpg"
Content-Type: application/octet-stream

����
-----------------------51b62743876b1201aee47ff4b1910e49--

The two examples above will upload an image.

-- 'Image binary data' can be misleading as my every search showed that an image binary is obtained by using the base64_encode function. In my experiments, the base64_encoding doesn't do anything. You only need to open the file with the file_get_contents.

-- In your cURL request, must have the header's Content-Type set to multipart/form-data and have the same boundary as the request. Example below:

curl_setopt($curl, CURLOPT_HTTPHEADER, array('Authorization: Bearer ' . $personalAccessToken, 'Content-Type: multipart/form-data; boundary=' . $boundary ));

So this adds another solution to the mix.

Upvotes: 0

Byron
Byron

Reputation: 33

Here is my PHP implementation for uploading a PNG image. Sometimes a different code view helps.

As @Troy stated, the important field to include for images is 'Content-Type: multipart/form-data'. Everything else I upload to Square uses 'Content-Type: application/json'.

$square_url = 'https://connect.squareup.com/v1/me/items/' . $square_item_id . '/image';

$cfile = new CURLFile($image_path_on_server, 'image/png', 'image_data');
$image_data = array('image_data' => $cfile);

$curl = curl_init();
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
  'Authorization: Bearer ' . $access_token,
  'Content-Type: multipart/form-data',
  'Accept: application/json'
));
curl_setopt($curl, CURLOPT_POSTFIELDS, $image_data);
curl_setopt($curl, CURLOPT_URL, $square_url);
curl_setopt($curl, CURLOPT_POST, TRUE);
curl_setopt($curl, CURLOPT_SAFE_UPLOAD, TRUE);
curl_setopt($curl, CURLOPT_BINARYTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($curl, CURLINFO_HEADER_OUT, TRUE);
curl_setopt($curl, CURLOPT_VERBOSE, TRUE);
$json = curl_exec($curl);
curl_close($curl);

Upvotes: 0

Troy
Troy

Reputation: 1639

You need to post the raw image data (not base64 encoded) with the proper multipart header for a file object. Here's a working example (replace ACCESS_TOKEN, ITEM_ID, and IMAGE_FILE).

<?php
function uploadItemImage($url, $access_token, $image_file) {
    $headers = ["Authorization: Bearer $access_token"];

    $ch = curl_init();

    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, ['image_data' => "@$image_file"]);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

    $data = curl_exec($ch);
    $return_status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    print "POST to $url with status $return_status\n";

    curl_close($ch);

    return $data ? json_decode($data) : false;
}

print_r(
    uploadItemImage(
        'https://connect.squareup.com/v1/me/items/ITEM_ID/image',
        'ACCESS_TOKEN',
        'IMAGE_FILE.jpg'
    )
);
?>

Upvotes: 2

Related Questions