0

I am trying to send an image to a web service API that asks for images to be sent as byte data. After clarifying with them that the data from file_get_contents() is what they are looking for, I wrote my cURL script to send it to them, which is at the end of my post.

What I would like to know is if this is the correct way of sending file_get_contents() data to a web service? Will the 'odd' characters that file_get_contents() produces be OK in transit or do I need to do something to protect them?

So far, none of my attempts have been successful - the API always returns the below error message.

I've only ever transferred images over APIs by base64 encoding them, so many thanks for any assistance you can offer.

My coding to send to the API:

// get the byte data
$image = file_get_contents("/path/to/my/image.jpg");

// url of api to post to
$url = "http://api.web.address";

// data to pass to api
$fields["username"] = "myusername";
$fields["password"] = "mypassword";
$fields["image"] = $image;

$ch = curl_init();
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); 
curl_setopt($ch, CURLOPT_TIMEOUT,        10);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($fields));
$data = curl_exec($ch);

The error returned from the API:

System.ArgumentException: Cannot convert ���� FExif  II*       ��  !           © Corbis.  All Rights Reserved.    ��  Ducky       d  �� �http://ns.adobe.com/xap/1.0/ <?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?> <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.5-c021 79.154911, 2013/10/29-11:47:16        "> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:Description rdf:about="" xmlns:xmpRights="http://ns.adobe.com/xap/1.0/rights/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmpRights:Marked="True" xmpRights:WebStatement="http://pro.corbis.com/search/searchresults.asp?txt=42-17167222&openImage=42-17167222" xmpMM:DocumentID="xmp.did:50BE9125E81E11E38F86E55FB7D795DA" xmpMM:InstanceID="xmp.iid:50BE9124E81E11E38F86E55FB7D795DA" xmp:CreatorTool="Adobe Photoshop CC Windows"> <xmpMM:DerivedFrom stRef:instanceID="8FBAF5153D10876B7ED66A56BC16FEE3" stRef:documentID=... to System.Byte.
Parameter name: type ---> System.FormatException: Input string was not in a correct format.
   at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
   at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
   at System.Byte.Parse(String s, NumberStyles style, NumberFormatInfo info)
   at System.String.System.IConvertible.ToByte(IFormatProvider provider)
   at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
   at System.Web.Services.Protocols.ScalarFormatter.FromString(String value, Type type)
   --- End of inner exception stack trace ---
   at System.Web.Services.Protocols.ScalarFormatter.FromString(String value, Type type)
   at System.Web.Services.Protocols.ValueCollectionParameterReader.Read(NameValueCollection collection)
   at System.Web.Services.Protocols.HttpServerProtocol.ReadParameters()
   at System.Web.Services.Protocols.WebServiceHandler.CoreProcessRequest()

UPDATE

It turns out that it was a byte array that I should have been sending to the API. I wasn't familiar with this in PHP, but this post helped me. So my working code is now:

// get the byte data
$image = file_get_contents("/path/to/my/image.jpg");

// url of api to post to
$url = "http://api.web.address";

// data to pass to api
$fields["username"] = "myusername";
$fields["password"] = "mypassword";
$fields["image"] = unpack('C*', $image);

$ch = curl_init();
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); 
curl_setopt($ch, CURLOPT_TIMEOUT,        10);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($fields));
$data = curl_exec($ch);
Community
  • 1
  • 1
SammyBlackBaron
  • 847
  • 3
  • 13
  • 31

1 Answers1

2

You're doing it wrong. Just have CURL do a standard file upload:

$fields = array(
    'username' => 'foo',
    'password' => 'bar',
    'image' => '@/path/to/your/image'
);

curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);

Note the @ in the image field - that's a signal to CURL to do a file upload, using the path specified after the @. ALso note that http_build_query is NOT being used. CURL will recognize that you're passing in an array and do all the work for you.

If you're on PHP 5.5+, the @ option is deprecated, and you have a new CURLFile class for doing this.

Marc B
  • 356,200
  • 43
  • 426
  • 500
  • Many thanks for the quick answer. I've just tried implementing your code and now the API is returning: `System.InvalidOperationException: Request format is invalid: multipart/form-data; boundary=----------------------------a3eb5869b833. at System.Web.Services.Protocols.HttpServerProtocol.ReadParameters() at System.Web.Services.Protocols.WebServiceHandler.CoreProcessRequest()` – SammyBlackBaron Jun 03 '14 at 14:39
  • ok. then the api really does want a base64 upload. in which case your original thing should work, you just need `$fields['image'] = base64_encode(file_get_contents(...))` type thing. – Marc B Jun 03 '14 at 14:41
  • thanks, but I have tried both `base64_encode(file_get_contents(...))` and `file_get_contents(...)` and the API doesn't accept either. The API does say not to base64 encode images, so will that affect how the value of `file_get_contents` gets transferred to the API? FYI, I've updated my original post with the full error returned from the API - just incase it helps work out what format it is expecting. – SammyBlackBaron Jun 03 '14 at 14:52