Solved

Use PHP to save or display image returned by JSON call.

Posted on 2016-10-28
20
49 Views
Last Modified: 2016-11-03
Need to retrieve and save or display an image file (usually .jpg or .pdf) returned by a call to a secure outside server.  I'm used to retrieving data arrays in this way (content-type application/xml and application/json), but have never had to deal with a file or image (content-type application/octet-stream).

I can get the return, but don't know how to process it using PHP.  Here is an example of the returned info:

HTTP/1.1 200 OK Cache-Control: no-cache Pragma: no-cache Content-Length: 228863 Content-Type: application/octet-stream Expires: -1 Server: Microsoft-IIS/7.5 Content-Disposition: attachment; filename=picture.jpg X-AspNet-Version: 4.0.30319 X-Powered-By: ASP.NET Date: Fri, 28 Oct 2016 19:43:37 GMT ����JFIF``��XExifMM*GFGIc�i2��>� ... [228K of data].

Can anyone provide pointers?

Thanks!
0
Comment
Question by:springthorpeSoftware
  • 10
  • 7
  • 3
20 Comments
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 41864661
Please give us a link to retrieve the information from the server.  When we have that we can see exactly what is being returned and we can test our proposed solutions.
0
 

Author Comment

by:springthorpeSoftware
ID: 41864862
Ray,

Thanks for replying!

The first part of the return is show above.  The characters for the .jpg begin after the "GMT" and go to the end.

To access, I have to put a UID and PWD in the header.  Not authorized to give out that info, but here is the PHP code:

$gateway = "https://asp.reefpt.com/capi2_APISandbox/api/v2/" . $link;

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $gateway);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
      "Accept: " . $apptype,
      "Content-Type: " . $apptype,      
      "Authorization: " . $SecurityStr)
);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($ch);
curl_close($ch);

In this case, I'm using "application/octet-stream" for $apptype.

I'm getting a return - and the data looks like a graphic.  Just need to know how to handle it.

Bruce
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 41864948
This is a RESTful API.  The central objective here is to get the SSCCE, which in this case is the entire  string of data that you're getting back from the API.  If you don't want to give us the UID and PWD, we can't get that data, and therefore we can't test any proposed solutions.

But, good news.  You can get that data!  Please use file_put_contents($result) to save the results in a file on your server, and then upload that entire file to E-E, or post a link here.

I think once we see the response from the API we will be able to show you how to process it, so please get us that and post back when we can see it.

This is a little beside the point, but there is a chance that any API can fail, and such failures can be intermittent. For that reason, you might want to have some error handling.  This is my teaching example showing how to use cURL to call an API and trap the errors, if any.
<?php // /demo/curl_get_response_object_example.php
/**
 * Demonstrate the basics of cURL GET-method request
 *
 * http://curl.haxx.se/libcurl/c/libcurl-errors.html
 */
error_reporting(E_ALL);


// USAGE EXAMPLE: BECAUSE IT IS ON MY SERVER, I HAVE HARD-CODED THIS
$url = 'https://twitter.com/RayPaseur';

// TRY THE REMOTE WEB SERVICE
$response = new GET_Response_Object($url);

// SHOW THE WORK PRODUCT
echo "<pre>";
if (!$response->document) var_dump($response);
echo htmlentities($response->document);

// SHOW THE COOKIES, IF ANY
echo PHP_EOL;
echo file_get_contents('cookie.txt');


Class GET_Response_Object
{
    public $href, $title, $http_code, $errno, $info, $document;

    public function __construct($href, $user=NULL, $pass=NULL, $get_array=[], $title=NULL)
    {
        // ACTIVATE THIS TO AVOID TIMEOUT FOR LONG RUNNING SCRIPT
        // set_time_limit(10);

        // STORE THE CALL INFORMATION
        $this->href  = $href;
        $this->title = $title;

        // PREPARE THE GET STRING
        $get_string = http_build_query($get_array);
        if ($get_string) $get_string = '?' . $get_string;

        // MAKE THE REQUEST
        if (!$response = $this->my_curl($href, $user, $pass, $get_string))
        {
            // ACTIVATE THIS TO SEE THE ERRORS AS THEY OCCUR
            trigger_error("Errno: $this->errno; HTTP: $this->http_code; URL: $this->href", E_USER_WARNING);
        }
        else
        {
            return $response;
        }
    }

    protected function my_curl($url, $user, $pass, $get_string, $timeout=3)
    {
        // PREPARE THE CURL CALL
        $curl = curl_init();

        // HEADERS AND OPTIONS APPEAR TO BE A FIREFOX BROWSER REFERRED BY GOOGLE
        $header[] = "Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5";
        $header[] = "Cache-Control: max-age=0";
        $header[] = "Connection: keep-alive";
        $header[] = "Keep-Alive: 300";
        $header[] = "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7";
        $header[] = "Accept-Language: en-us,en;q=0.5";
        $header[] = "Pragma: "; // BROWSERS USUALLY LEAVE THIS BLANK

        // SET THE CURL OPTIONS - SEE http://php.net/manual/en/function.curl-setopt.php
        curl_setopt( $curl, CURLOPT_URL,            $url . $get_string  );
        curl_setopt( $curl, CURLOPT_USERAGENT,      'Mozilla/5.0 (Windows NT 6.1; rv:44.0) Gecko/20100101 Firefox/44.0'  );
        curl_setopt( $curl, CURLOPT_HTTPHEADER,     $header  );
        curl_setopt( $curl, CURLOPT_REFERER,        'http://www.google.com'  );
        curl_setopt( $curl, CURLOPT_ENCODING,       'gzip,deflate'  );
        curl_setopt( $curl, CURLOPT_AUTOREFERER,    TRUE  );
        curl_setopt( $curl, CURLOPT_RETURNTRANSFER, TRUE  );
        curl_setopt( $curl, CURLOPT_FOLLOWLOCATION, TRUE  );
        curl_setopt( $curl, CURLOPT_TIMEOUT,        $timeout  );
        curl_setopt( $curl, CURLOPT_HTTPAUTH,       CURLAUTH_ANY );
        curl_setopt( $curl, CURLOPT_USERPWD,        "$user:$pass" );

        curl_setopt( $curl, CURLOPT_VERBOSE,        TRUE   );
        curl_setopt( $curl, CURLOPT_FAILONERROR,    TRUE   );

        // SET THE LOCATION OF THE COOKIE JAR (THIS FILE WILL BE OVERWRITTEN)
        curl_setopt( $curl, CURLOPT_COOKIEFILE,     'cookie.txt' );
        curl_setopt( $curl, CURLOPT_COOKIEJAR,      'cookie.txt' );

        // IF USING SSL, THIS INFORMATION MAY BE IMPORTANT
        // http://php.net/manual/en/function.curl-setopt.php#110457
        // http://php.net/manual/en/function.curl-setopt.php#115993
        // http://php.net/manual/en/function.curl-setopt.php#113754
        // REDACTED IN 2015 curl_setopt( $curl, CURLOPT_SSLVERSION, 3 );
        curl_setopt( $curl, CURLOPT_SSL_VERIFYHOST, FALSE  );
        curl_setopt( $curl, CURLOPT_SSL_VERIFYPEER, FALSE  );

        // RUN THE CURL REQUEST AND GET THE RESULTS
        $this->document  = curl_exec($curl);
        $this->errno     = curl_errno($curl);
        $this->info      = curl_getinfo($curl);
        $this->http_code = $this->info['http_code'];
        curl_close($curl);

        return $this;
    }
}

Open in new window

0
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 41865655
I'm getting a return - and the data looks like a graphic.  Just need to know how to handle it.What do you
want to do with it?
Save it to a file
Send it to a browser.

The data should be a raw image you should be able to save it with
$imagepath="path/to/where/to/save/images/";
$filename = $imagepath . "myimagename.jpg";
file_put_contents($filename, $result);

Open in new window

0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 41865796
@Julian: It may not be quite that simple.  The information in the original post appears to contain an XML file, viewed not with view source, but in the browser window (clearly not the way to see the file structure, which is what we need).  Once we discern the structure of the XML document we will be able to see what part of this file represents an image. That's why I asked our Author to show us the API response.

Also, as noted, APIs can fail, and having a fallback position is worth the little extra effort.  In the case of this application, I got this when browsing their site -- not exactly something that inspires confidence in their software acumen!  So there may be a little more work before we can sign off on this question.
Oops...
0
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 41866466
I missed the XML - had another look - still not seeing it. I see a header for a content type

Content-Type: application/octet-stream

Which does not mention XML - if you are referring to what is returned from the Link posted then I suspect that (with the clue given by ASP in the link) that this is a .Net service which either returns the image directly (which seems to be the case by the content posted in the OP) or a SOAP packet.
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 41866682
I think the reason you're not seeing the XML is because the Author read the XML document into a browser and copied the browser display -- not the "view source."

By way of example, navigate to this URL: https://asp.reefpt.com/capi2_APISandbox/api/v2/

The browser display (depending on how smart or dumb the browser might be) is something like
No HTTP resource was found that matches the request URI 'https://asp.reefpt.com/capi2_APISandbox/api/v2/'.

Open in new window

The "view source" display contains the tags.  This is what we need to see in order to discern the structure of the document
<Error><Message>No HTTP resource was found that matches the request URI 'https://asp.reefpt.com/capi2_APISandbox/api/v2/'.</Message></Error>

Open in new window

These links might provide a little more insight:
https://asp.reefpt.com/capi2_APISandbox/Help
https://forums.asp.net/t/1916587.aspx?WebAPI+No+HTTP+resource+was+found+that+matches+the+request+URI

I think at this point it's best to wait for our Author to post the entire XML document.  Then we will have something to test with, and we won't have so speculate.
0
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 41866714
Yes, those are all .Net service end points - which is why I suspect a SOAP return. Without a login to that API we can't see what the data coming back is - but looking at the base link return tells us nothing.
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 41866723
Check the API sandbox help page.  It doesn't give us much, but it shows what we are likely to find when our Author posts the full XML response document.  Looks like HTTP / REST to me.
0
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 41866771
Except this is most likely an ASP implementation given the url. I am betting this is a SOAP request he is dealing with and should rather be looking at the PHP SOAP library.

From a small .Net service I put together - this is what it sends back when a valid service name with parameters is submitted
Service takes two parameters (name, numdoughnuts) - sends this back
<?xml version="1.0" encoding="utf-8"?>
<string xmlns="http://tempuri.org/">Greetings,Fred are you sure you want 21 doughnuts</string>

Open in new window

0
Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

 

Author Comment

by:springthorpeSoftware
ID: 41872271
Thanks to both of you!

If you will reply with a private way to send you the authentication info, I'll send to you.  (Can't post publicly.)

Files created are attached.  Used two different methods, one containing just the file data, the other containing the entire return.  When I tried to open either with either Paint or Photo Viewer, it tells me that the format is invalid.

When I looked at the "data" being extracted using Notepad++, it had 2 blank lines at the top.  I adjusted what I was extracting for the file to remove them, but still getting "invalid format". (That's the attached file.)

The URL for this one is https://asp.reefpt.com/capi2_APISandbox/api/v2/clientcontact/5/signature

Thanks, again, for your help!
Bruce
5_signature.jpg
Entire-Return.jpg
1
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 41872288
Here is the link to my profile.  It contains my email address, Ray.Paseur@Gmail.com.
https://www.experts-exchange.com/members/Ray_Paseur.html

FWIW, both of the image files opened OK for me using an old copy of PaintShopPro.
0
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 41872301
You can PM the info to me
Profile link
https://www.experts-exchange.com/members/julianH.html
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 41872362
What you've got in the "Entire Return" file is a complete HTTP response, including headers.  If you strip off the headers, you can save or display the image file.  This script shows how.

Please see: https://iconoun.com/demo/temp_spring.php
<?php // demo/temp_spring.php
/**
 * https://www.experts-exchange.com/questions/28979679/Use-PHP-to-save-or-display-image-returned-by-JSON-call.html#a41872301
 */
error_reporting(E_ALL);

// READ THE "ENTIRE RESPONSE" DOCUMENT
$doc = file_get_contents('https://filedb.experts-exchange.com/incoming/2016/11_w45/1125893/Entire-Return.jpg');

// A DELIMITER FOR EOL CHARACTERS
$dlm = "\r\n";

// FIND THE IMAGE
$arr = explode($dlm, $doc);
$img = end($arr);

// SEND THE IMAGE TO THE BROWSER
header('Content-Type: image/jpeg');
echo $img;

Open in new window

0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 41872371
Here's how you can see the "guts" of the HTTP response.  It's not XML - it's just the HTTP headers and data delimited by end-of-line characters.
https://iconoun.com/demo/temp_spring_guts.php
<?php // demo/temp_spring_guts.php
/**
 * https://www.experts-exchange.com/questions/28979679/Use-PHP-to-save-or-display-image-returned-by-JSON-call.html#a41872301
 */
error_reporting(E_ALL);

// READ THE "ENTIRE RESPONSE" DOCUMENT
$doc = file_get_contents('https://filedb.experts-exchange.com/incoming/2016/11_w45/1125893/Entire-Return.jpg');

// A DELIMITER FOR EOL CHARACTERS
$dlm = "\r\n";

// FIND THE IMAGE
$arr = explode($dlm, $doc);
$img = end($arr);

// SHOW THE "GUTS" OF THE HTTP RESPONSE
echo '<pre>';
var_dump($arr);

Open in new window

Outputs something like:
array(13) {
  [0]=>
  string(15) "HTTP/1.1 200 OK"
  [1]=>
  string(23) "Cache-Control: no-cache"
  [2]=>
  string(16) "Pragma: no-cache"
  [3]=>
  string(20) "Content-Length: 2691"
  [4]=>
  string(38) "Content-Type: application/octet-stream"
  [5]=>
  string(11) "Expires: -1"
  [6]=>
  string(25) "Server: Microsoft-IIS/7.5"
  [7]=>
  string(57) "Content-Disposition: attachment; filename=5_signature.jpg"
  [8]=>
  string(27) "X-AspNet-Version: 4.0.30319"
  [9]=>
  string(21) "X-Powered-By: ASP.NET"
  [10]=>
  string(35) "Date: Thu, 03 Nov 2016 14:06:13 GMT"
  [11]=>
  string(0) ""
  [12]=>
  string(2691) "ÿØÿàJFIF``ÿÛC		

 $.' ",#(7),01444'9=82<.342ÿÛC			

2!!22222222222222222222222222222222222222222222222222ÿÀ8È"ÿÄ	
ETC, ETC, ETC

Open in new window

0
 
LVL 108

Accepted Solution

by:
Ray Paseur earned 250 total points
ID: 41872386
Here's how to store the image file from the HTTP response.  
https://iconoun.com/demo/temp_spring_img.php
<?php // demo/temp_spring_img.php
/**
 * https://www.experts-exchange.com/questions/28979679/Use-PHP-to-save-or-display-image-returned-by-JSON-call.html#a41872301
 */
error_reporting(E_ALL);

// READ THE "ENTIRE RESPONSE" DOCUMENT
$doc = file_get_contents('https://filedb.experts-exchange.com/incoming/2016/11_w45/1125893/Entire-Return.jpg');

// A DELIMITER FOR EOL CHARACTERS
$dlm = "\r\n";

// FIND THE IMAGE
$arr = explode($dlm, $doc);
$img = end($arr);

// STORE THE IMAGE ON THE SERVER AND SEND AN IMAGE TAG TO THE BROWSER
file_put_contents('temp_spring.jpg', $img);
echo '<img src="temp_spring.jpg" />';

Open in new window

Unless you want me to experiment with other responses, I don't think I need the site credentials.  The Entire-Return file is all we needed to complete this.
Embedded image
0
 
LVL 51

Assisted Solution

by:Julian Hansen
Julian Hansen earned 250 total points
ID: 41872489
I don't have access to the return but if you are going to be processing an HTTP header the correct way is to look for the double \r\n\r\n which is the delimiter between header and data.

Assuming your result is in $packet then you want to do something like

$start = strpos($packet, "\r\n\r\n");
$data = substr($packet, $start + 4);

Open in new window

$data should now hold the image contents which you can then use file_put_contents to send to a file or in combination with header() directives return to the browser.
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 41872525
@Julian: I think we have this run to ground, but if you want to work on it further, you can use the same responses document I used.  Bruce posted it in the file named Entire-Return.jpg.  Link here:
https://filedb.experts-exchange.com/incoming/2016/11_w45/1125893/Entire-Return.jpg
1
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 41872581
@Ray, thanks. Agree on how much further we can take this. Will leave in the hands of the asker
0
 

Author Closing Comment

by:springthorpeSoftware
ID: 41873070
Thank you both SO much!
Bruce
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Part of the Global Positioning System A geocode (https://developers.google.com/maps/documentation/geocoding/) is the major subset of a GPS coordinate (http://en.wikipedia.org/wiki/Global_Positioning_System), the other parts being the altitude and t…
It was really hard time for me to get the understanding of Delegates in C#. I went through many websites and articles but I found them very clumsy. After going through those sites, I noted down the points in a easy way so here I am sharing that unde…
The viewer will learn how to look for a specific file type in a local or remote server directory using PHP.
The viewer will learn how to create and use a small PHP class to apply a watermark to an image. This video shows the viewer the setup for the PHP watermark as well as important coding language. Continue to Part 2 to learn the core code used in creat…

706 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now