Reading returned XML data with PHP

I have an API consisting of two files that takes a url from a user, processed it, and sends an array to another file to return XML data back to the user. My problem is that I do not know how to get the return data (if I were the user) and parse it. Using a browser, the XML will display fine. I am hoping there are PHP functions that will send the url and retrieve the result for parsing.
Here is an example of the url sent by the user:
http://www.domain.com/xmlapi.php?a=1&b=2&c=3

Open in new window

Those query vars are then processed, sent to another server, and an array of results is returned. I then create a query string from those results place that string into another query and send that to another file that returns the XML.
The query string looks like this:
XMLProcess.php?Q=Element1^Value|Element2^Value|ElementThree^Value ... etc.

Open in new window

That file looks like this
   $dom = new DOMDocument("1.0", 'utf-8');
   header ("Content-Type:text/xml");
   $QArray = explode('|',$_REQUEST[Q]);
   foreach($QArray as $value)
   {
      $x = explode('^',$value);
      $XMLItems[$x[0]] = $x[1];
   }
   $root = $dom->createElement("Requests");
   $dom->appendChild($root);
   foreach($XMLItems as $key => $value)
   {
         $key = $dom->createElement($key);
         $root->appendChild($key);
         $variable = $dom->createTextNode($value);
         $key->appendChild($variable);
      }
   }
   echo $dom->saveXML();

Open in new window

As I say, this will display well-formatted xml in a browser, but is there a way to receive and parse this xml data with PHP?
Am I creating extra problems by having a secondary processing file (XMLProcess.php), rather than just including this XML creation code in the xmlapi.php file?

I'm trying to avoid using something like CURL or SOAP, if possible.
LVL 1
RationalRabbitAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

gr8gonzoConsultantCommented:
I'm not understanding the flow of things, because it seems like you're switching between 1st person and 3rd person during your descriptions and it's hard to say what YOU are doing versus an end user.

From what I'm reading, my -guess- here is this:

1. You own www.domain.com.

2. End user opens their browser and goes to:
http://www.domain.com/xmlapi.php?a=1&b=2&c=3

3. The xmlapi.php script performs a server-side call to:
XMLProcess.php?Q=Element1^Value|Element2^Value|ElementThree^Value ... etc.

4. XMLProcess.php converts the "Q" query string into an XML string and returns it to xmlapi.php.

5. xmlapi.php returns the XML to the end user.

Is that a correct understanding of the flow?

You're talking about "receiving" and "parsing" the XML data with PHP, which doesn't appear to be part of flow, so that's where I'm getting confused...
0
Julian HansenCommented:
If you are wanting to read the XML from another server then cURL is probably the solution. On some systems you can use file_get_contents but this is often blocked for security reasons but you can try

$rawxml = file_get_contents("http://www.yourserver.com/yourscript.php");

Open in new window


Failing that cUrl is the way to go
0
RationalRabbitAuthor Commented:
@Julian Hansen
I tried file_get_contents. What I get in return is
[function.file-get-contents]: failed to open stream: HTTP request failed! HTTP/1.1 400 Bad Request in {url} on line 2
0
C++ 11 Fundamentals

This course will introduce you to C++ 11 and teach you about syntax fundamentals.

gr8gonzoConsultantCommented:
So is XMLProcess.php on a separate server?
0
RationalRabbitAuthor Commented:
@gr8gonzo
Yes, that's basically correct, although I would say it is XMLProcess.php that is sending the data back to the user,
0
gr8gonzoConsultantCommented:
If the user calls xmlapi.php, then xmlapi.php is where the response comes from, even if xmlapi.php is calling another script on the backend:

USER <---> xmlapi.php <---> XMLProcess.php

Is there a reason that XMLProcess.php has to be on a separate server? It doesn't look like it does anything except convert your query string to XML...
0
RationalRabbitAuthor Commented:
@gr8gonzo
xmlapi.php and XMLProcess.php are both on the same server.
xmlapi.php accesses database program calls on an LTL400 which returns parameters to return to the user.
0
gr8gonzoConsultantCommented:
If they're on the same physical server, you might be able to just include() it to run it as if it were an extension of your xmlapi.php script:

xmlapi.php
...process some stuff...
$Q = "Element1^Value|Element2^Value|ElementThree^Value ... ";
include("/path/to/XMLProcess.php");
echo $results;

Open in new window


XMLProcess.php
$dom = new DOMDocument("1.0", 'utf-8');
   header ("Content-Type:text/xml");
   $QArray = explode('|',$Q); // <-------------
  ..etc...
  $results = $dom->saveXML();

Open in new window

0
RationalRabbitAuthor Commented:
So, the API calls another API for the LTL400. That's how the data is processed.
0
Julian HansenCommented:
If I understand you correctly though you are providing an API for your clients to call - or is this requirement different?
0
RationalRabbitAuthor Commented:
gr8gonzo
Yes, that's what I was thinking, which is why I made it part of my question. I'm wondering if that is making things more difficult, and I don't see why I couldn't just include it.
0
RationalRabbitAuthor Commented:
Julian Hansen
Yes - same thing. They ask for an example in PHP and I've found myself unable to produce it.
User sends query string attached to xmlapi.php and expects a return they can deal with - preferably with PHP.
0
RationalRabbitAuthor Commented:
The problem with using XMLProcess as an include is the header information. I assume this is required if I am using $dom->saveXML();, no?

   $dom = new DOMDocument("1.0", 'utf-8');
   header ("Content-Type:text/xml");

Open in new window


Or is it maybe altogether better to just send the XML as a string, without any header info?
0
David FavorLinux/LXD/WordPress/Hosting SavantCommented:
Maybe what you're saying is you'd like the output to download (as a .xml file), rather than render in a browser window.

The way you'd do this is to configure your Apache (or other server) to associate the generic MIME type for downloads... Something like...

<FilesMatch "\.(?i:xml)$">
      ForceType application/octet-stream
      Header set Content-Disposition attachment
</FilesMatch>

Open in new window


Changing your FilesMatch to match the exact download paths of all .xml files.
0
gr8gonzoConsultantCommented:
Actually, that header info might be fine if you don't have any output before it is called, since xmlapi.php is the one returning the response to the end user.
0
RationalRabbitAuthor Commented:
gr8gonco
Obviously somewhere - I tried it. Does a server request send headers? does a db query send headers? such as this:
   if(isset($_SERVER))
   {
      if(isset($_SERVER["HTTP_X_FORWARDED_FOR"])){$ip = $_SERVER["HTTP_X_FORWARDED_FOR"];}
      elseif(isset($_SERVER["HTTP_CLIENT_IP"])){$ip = $_SERVER["HTTP_CLIENT_IP"];}
      else{$ip = $_SERVER["REMOTE_ADDR"];}
   }
   else
   {
      if(getenv("HTTP_X_FORWARDED_FOR")){$ip = getenv("HTTP_X_FORWARDED_FOR");}
      elseif(getenv("HTTP_CLIENT_IP")){$ip = getenv("HTTP_CLIENT_IP");}
      else{$ip = getenv("REMOTE_ADDR");}
   }
   $IP = $ip;
   include('../node/nodeconfig.php');
   mysql_query("INSERT INTO PUAPILog (IP, URL, Acct, Server, Type, Time) values ('$IP', '$_SERVER[REQUEST_URI]', '$_REQUEST[code]', '$Node', '$_REQUEST[type]', NOW())");
   $LogID = mysql_insert_id();

Open in new window

0
RationalRabbitAuthor Commented:
David Favor
Can this be set somehow, such as an .htaccess in that directory so that it doesn't affect other XML operations on the server?
0
gr8gonzoConsultantCommented:
A DB query does not send headers. Where is that code snippet from?
0
RationalRabbitAuthor Commented:
The code snippet is from the top of xmlapi.php - the program the user originally sends a query string to.
IT could just as well be placed at the end of the file if it causes a problem.
0
RationalRabbitAuthor Commented:
However, i5_program_prepare() and i5_program_call() are sending arrays to the mainframe.
0
gr8gonzoConsultantCommented:
So try adding ob_start() to the very top of xmlapi.php's PHP contents.

That should start output buffering and will let PHP properly handle the output order so that headers can be sent as needed.
0
David FavorLinux/LXD/WordPress/Hosting SavantCommented:
You can set the above Apache config in .htaccess or Apache config.

You adjust the FilesMatch or similar type directives, to only effect the directory of files you'd like downloaded rather than rendered.
0
gr8gonzoConsultantCommented:
@David - that Apache directive only impacts files that are accessed directly with the .xml extension. The XML in this case is being streamed through a PHP file.

If the OP wants to prompt the user to download the XML file instead of viewing it through the browser, he/she can do that with headers, but it didn't seem like that was the intent (I may be wrong) ?
0
RationalRabbitAuthor Commented:
What the user is sending us is information on their product and location. Basically, we're sending most of that information back to them, along with a product number an other identifying information. We need all of the information but we're sending some back so that all information will be together. In most cases, It is an automated process on both ends, without human interaction, other than the user's data entry person who initiates the process.
0
RationalRabbitAuthor Commented:
gr8gonzo
Seems that a file would probably be optimal. There, certainly, creating a file is no problem. As far as returning it, I have no knowledge on how to do that, other than what was mentioned by David here. One of the reasons a file would be optimal is - people can use almost any language or utility they want and, if they are on my level, if one searches for examples around the Web, there are plenty of examples from JavaScript to almost anything you want to used for receiving an XML file and parsing it. Should be kept in mind too, that each customer has an account number, so that could be used, if necessary. What I don't know is:
1. How best to do this :) create a mass of directories, each with their own unique file? or utilize a db table?
2. They have to send the parameters first before the file can be created. so they can't just say (for example) file_get_contents(file.xml) or something similar, or can they?  Could they, for instance attach a query string to that?
0
gr8gonzoConsultantCommented:
If you have XML data stored inside a string variable and you want to send it to the end user's browser so that the browser is prompted to download the file, then you use headers like this:

// Up here do everything that ends up putting the XML data into a variable called $xmlData

// Then do this:
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=results.xml');
header('Content-Transfer-Encoding: binary');
header('Connection: Keep-Alive');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . strlen($xmlData));
echo $xmlData;
die();
0
RationalRabbitAuthor Commented:
That would require human interaction, which is what I am trying to avoid. " In most cases, It is an automated process on both ends, without human interaction, other than the user's data entry person who initiates the process." And there may not even be a data entry person. The entire process could be automated. Chances are, they are sending that information to some other piece of equipment.
0
gr8gonzoConsultantCommented:
If it's automated, the headers don't really matter.

Headers are simple instructions for the browser. If the requesting entity doesn't care about headers (e.g. a script instead of a browser), then it won't bother with them - it'll just get the content as-is.
0
RationalRabbitAuthor Commented:
So I took a look at icecat - a product info service I use. The query I send to them looks like this:
$data = file_get_contents('https://'.$username.':'.$password.'@data.icecat.biz/xml_s3/xml_server3.cgi?prod_id='.$ProductID.';vendor='.$Brand.';lang=EN;output=productxml');

Open in new window

and is easy to parse using SimpleXML
   $xml = new SimpleXMLElement($data, null. true);
   ###########################################
   #        X P A T H  A R R A Y S           #
   ###########################################
   $ProductAttribs      = $xml->xpath("//Product");
   $ProductDescription  = $xml->xpath("//ProductDescription");
   $SummaryDescription  = $xml->xpath("//SummaryDescription");

Open in new window

etc....
[EDIT - rephrasing so as not to be confusing]  So, they are not providing a file (as in "filename.xml"), but rather receiving a query, as I am doing. What can they be doing that I am not?
(file_get_contents() will fail with my data)
0
gr8gonzoConsultantCommented:
So file_get_contents() is basically doing what your browser is doing. You've passed in a protocol ("https://") at the beginning, which tells PHP to run a subroutine / wrapper that kicks off a network request to the icecat server.

The icecat server is almost guaranteed to return headers, but because file_get_contents isn't a full-fledged browser that pays attention to headers, it simply takes the CONTENTS of the response and then stores them into that $data variable.

In this case, you have the XMLProcess.php on the same server as xmlapi.php, so making a network call to it is like going from your bedroom to your living room by leaving the house, hopping into your car, pulling out of the driveway, pulling back INTO the driveway, getting out of the car, and going back into the house and going to the living room.

Basically, the PHP routine for xmlapi.php invokes the network services to go resolve the domain, and then make a network connection that leaves the server and immediately gets routed back into the same server to the web service which hands the request off to PHP to run XMLProcess.php. It's a ton of overhead, when you consider that everything is on the same server. Plus, sometimes you end up with DNS resolution problems.

If it will continue to be on the same server, then it makes sense to just call the file directly. And again, you can dynamically bring that script into your current one with include(). No headers needed or anything - just put your data into a variable within xmlapi.php and then include() XMLProcess.php and then have XMLProcess.php access that variable directly as if it were just another part of the same script. Then have XMLProcess.php put its results into a variable that your xmlapi.php accesses immediately after include.

If you'd like some real-time guidance here, we can always do a paid live session where we can share screens and I can walk you through the changes.
0
Julian HansenCommented:
We are going in circles here - we have established already (in this question https://www.experts-exchange.com/questions/29068519/Return-XML-file-in-PHP-API.html) that a file and a string data are identical except for the headers - which in an API situation are meaningless.

We have also established this is an API - a request is made to a PHP script which returns XML - this is very standard and requires nothing more than an echo of the data by the script after the XML has been assembled. Whether or not the calling script and response script are on the same server, the scenario potentially exists where an external call will be made in which case using a local only solution will not cater for the new requirement. My advice is to proceed along the path that most API development follows and have the called script return a string of data (in this case XML) - no files, no headers just XML.

The question then becomes how do you consume that API. In PHP there are really only two ways of doing this.

Method 1: file_get_contents  (subject to security settings)

Example
file_get_contents('http://www.domain.com/xmlapi.php?a=1&b=2&c=3');

Method 2: cUrl
Use cUrl to call the API
Adapted from the curl_exec() page
<?php
// create a new cURL resource
$ch = curl_init();

// set URL and other appropriate options
curl_setopt($ch, CURLOPT_URL, "xmlapi.php?a=1&b=2&c=3");
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// grab URL and pass it to the browser
$result = curl_exec($ch);
//echo $result;
$xml = simplexml_load_string($result);

// close cURL resource, and free up system resources
curl_close($ch);


echo "The value of <first> is " . $xml->first . "<br>";
echo "The value of <second> attribute b is " . $xml->second->Attributes()[0] . "<br>";
echo "The value of <third> is " . $xml->second->third . "<br>";

Open in new window

The source script
<?php
$a = isset($_GET['a']) ? $_GET['a'] : '';
$b = isset($_GET['b']) ? $_GET['b'] : '';
$c = isset($_GET['c']) ? $_GET['c'] : '';
echo <<< XML
<?xml version="1.0"?>
<data>
  <first>{$a}</first>
  <second b="{$b}">
    <third>{$c}</third>
  </second>
</data>
XML;
?>

Open in new window

0
RationalRabbitAuthor Commented:
Sounds good. When is a good time for you? I'll want to see what I can do, first. It appears that file_get_contents may be failing because of something in the URL. Does that seem possible if it will return proper XML data to a browser? In other words, if it works using a browser, shouldn't it work with file _get_contents? Of course, maybe it will. XMLProcess has been converted to an include. but I got the headers already sent error, so I'll remove the header info and try again. I that doesn't work, I could sure use some help to get something up and running by sometime tomorrow morning, if that's possible. What time zone are you in? I'm on pacific time.
0
Julian HansenCommented:
It appears that file_get_contents may be failing because of something in the URL. Does that seem possible
I am guessing it is disabled in the php.ini - this is very common because it is a security risk.

XMLProcess has been converted to an include. but I got the headers already sent error, so I'll remove the header info and try again
Again we need to understand the use case here - because if this is an API that will be called remotely then includes are not the way to go.
If this is an API in the form of a library - i.e. something someone includes in their project to extend functionality of their script then includes are the only way to go.

In either case, unless you are preparing to send a file for download in a browser or you are passing security tokens, headers are meaningless and If you are using an include then doubly so.

Regarding getting something up and running - unless I can get a handle on the use case I can't help any further. The sample I provided above works - you can load that on your server - make the URL adjustments and you should get the following output
The value of is 1
The value of attribute b is 2
The value of is 3

Open in new window


BOTTOM LINE
What kind of API is this
a) One that applications will call remotely (not part of their script) - we call this a service
b) One that applications include to extend functionality - we call this a library

Until we can get a handle on the use case we are not going to be able to nail this one down.
0
RationalRabbitAuthor Commented:
What's installed on the server as far as cUrl, I haven't checked. I did change XMLProcess to this which sends the text back to the browser ok,
However, using file_get_contents(), I get the same "failed to load" error. This server is running FastCGI on IIS. Perhaps it has something to do with that. I'm sending you both a message.
 
 $QArray = explode('|',$QString);
   foreach($QArray as $value)
   {
      $x = explode('^',$value);
      $XMLItems[$x[0]] = $x[1];
   }
   echo('<Requests>');
   foreach($XMLItems as $key => $value)
   {
         if(empty($value))
         {
            echo('<'.$key.'/>');
         }
         else
         {
            echo('<'.$key.'>'.$value.'</'.$key.'>');
         }
   }
   echo('</Requests>');

Open in new window

0
RationalRabbitAuthor Commented:
Julian
I'm not sure we're on the same track here as far as includes go. What I'm talking about is eliminating the redirect to XMLProcess with a query string, and instead, including it in the main php file, xmlapi.php

So, it looks like I'm going to have to assume that something on the server is preventing file_get_contents() from running. I guess I will see if cUrl is available and try that.
0
Julian HansenCommented:
I don't think we are going to resolve this quickly. We are talking file_get_contents and include in the same discussion and they really don't belong together.

include => when you want to include functionality in your script
Example
<?php
include("myfunc.php");
myFunc("Hello World");

Open in new window


myfunc.php
<?php
function myFunc($str) {
 echo $str;
}

Open in new window


In the above example the capability of the first script is extended by the functionality available in the second - i.e. by including the second we are able to make use of functions / data that are defined in that script.

file_get_contents
A way of reading data into a script
<?php
$json = file_get_contents('myjson.json');
$data = json_decode($json);
echo "Name: {$data->firstname}";

Open in new window


myson.json
{
   "firstname": "Mickey",
   "lastname": "Mouse",
   "email": "mickeyM@toonland.com"
}

Open in new window


Can you see the difference between these two approaches?

The primary focus of this thread (and your other thread) has been consuming XML data.

This tends to suggest that you are creating a process that creates XML data and another process that must read that data.

In otherwords you have
xmlapi.php => creates XML
XMLProcess.php => Needs to use XML

I don't see any scope for an include here. If xmlapi.php outputs XML then including that file in your XMLProcess is just going to ... output the XML not make it available for XMLProcess to work with. So I am really confused as to why include is even in the mix.

That leaves us with calling the script - I have already dealt with the two methods above.

I have also already stated that file_get_contents on a URL will fail in instances where the configuration of the server has been set to disable that functionality.
In your php.ini file look for this line
allow_url_fopen = On

Open in new window

On = file_get_contents on remote url is enabled
Off = file_get_contents on remote url is disabled

Your script also requires authentication - which should work for file_get_contents.

NB: There is another option to try and that is simplexml_load_file (although this is also constrained by the setting above).

For instance here is a sample script against my server that uses both file_get_contents (to get JSON data) and simplexml_load_file (to get XML data) from a secured resource.

Please see if this runs on your server
NB: This is a test server - no need to remove names and passwords - they are open for the reason of demonstration.
<?php
$json = file_get_contents("http://guest:password@www.marcorpsa.com/ee/sectest/sampledata.json");
$data = json_decode($json);
echo "<h2>JSON</h2>";
echo "<pre>" . print_r($data, true) . "</pre>";

echo "<h2>XML</h2>";
$data = simplexml_load_file('http://guest:password@www.marcorpsa.com/ee/sectest/sampledata.xml');
echo "<pre>" . print_r($data, true) . "</pre>";

Open in new window

0
RationalRabbitAuthor Commented:
Julian
I'm sorry, I don't get your apparent confusion over includes at all. The reason this was brought up was that, originally I was calling a second script, "XMLProcess.php" using a JavaScript redirect function. Why that was being done that way is superfluous at this point. That entire script (XMLProcess.php) I listed at the beginning of this question. It was no problem to just include that file, rather than redirecting and sending a query string to it. So I did that. Header problem occurred. Removed the header lines and the XML processing altogether, changing it to a pure text string with XML bracketing, which I displayed above. I don't see a difference as to whether this bit of code is an include or not. it can just as easily be dropped into the file and eliminated as a separate file altogether.

Reading further, you assessment,
In otherwords you have
xmlapi.php => creates XML
XMLProcess.php => Needs to use XML
is incorrect. Thus, I see now, the confusion. I hope I have explained that in the above paragraph.

allow_url_fopen is On

Your script also requires authentication - which should work for file_get_contents.
You must be looking at the icat example I posted as a example of indicating what I was after. My API does not require authentication.

NB: There is another option to try and that is simplexml_load_file (although this is also constrained by the setting above).
I have not tried simplexml_load_file, but I have tried simplexml_load_string, which gave me the following error:
Warning: simplexml_load_string() [function.simplexml-load-string]: Entity: line 1: parser error : Start tag expected, '<' not found

For instance here is a sample script ...
Yes, these will run from my server, but, of course, the question is would they run if sampledata.json and sampledata.xml were on my server.
0
RationalRabbitAuthor Commented:
Using simpleXMLl_load_file(), I get
FastCGI Error
The FastCGI Handler was unable to process the request.

Error Details:

    The FastCGI process exited unexpectedly
    Error Number: -1073741819 (0xc0000005).
    Error Description: Unknown Error

HTTP Error 500 - Server Error.
Internet Information Services (IIS)
0
RationalRabbitAuthor Commented:
It feels like this is going all over the place.
I'm sorry if I have contributed to that, but I really don't understand the confusion.
  • I have explained that the customer is sending a simple (although fairly long) query string.
  • I have explained that the API is currently working and has been returning (when XML is requested) XML and that, if the query string is sent from a browser, it will return properly formatted XML. I am told companies have been using that. How they have been using it, I don't know.
  • We have determined that my desire, due to a complaint from one of my client's customers, is to write a PHP script (that, I assume, they may insert into another script of their own) that will properly receive the data, which should be as simple as file_get_contents().  
  • I have shown a small portion of a script I wrote for another client, receiving an XML file from ICECAT, in the hope that would further underline that I understand how that process should work, as well as explain what I am after.
The problem is, it's not working.
We have eliminated a couple of possibilities, but PHP functions are still not working.
The question is "why?".
0
Julian HansenCommented:
Ok, I think this is solidifying - things got murky when we headed in to headers and include() territory which was a mistake.

You have a URL based API - it returns XML and you want to be able to read that into a string, parse the XML and access the data.

Good - all doable.

Why is file_get_Contents() not working - have you tried the simplexml_load_File() option I showed above - did that work?

Have you checked your PHP.ini file to see if the allow_url_fopen is on or off?

Lets start with those two first.

My recommendation is ultimately we go with the cUrl option - because you cannot guarantee that allow_url_fopen will be on.

I will need to modify the cUrl script I gave you earlier to support authentication - I will do that in the morning.
0
RationalRabbitAuthor Commented:
Julian
Ran your cUrl script. (ion a file titled "loadstring.php" - seen below)
Seems to be loading cUrl - at least I would expect an error message if not. (perhaps not?)
However, the line
echo "The value of <first> is " . $xml->first . "<br>";

Open in new window

Produces nothing except for the line break. (Looking at the page source, I see the "<br>", but not the text before it. Odd.
But the line
echo "The value of <second> attribute b is " . $xml->second->Attributes()[0] . "<br>"

Open in new window

;
produces the error
Parse error: syntax error, unexpected '[', expecting ',' or ';' in C:\websites\dev\loadstring.php on line 19
0
RationalRabbitAuthor Commented:
As I mentioned before, I tried the simpleXML_load_file() as well as simpleXML_load_string() and allow_url_fopen is On
0
RationalRabbitAuthor Commented:
Ran curl example, both within my structure and as-is. both times received the following error only (with the exception of one "<br >" before it)
Parse error: syntax error, unexpected '[', expecting ',' or ';' in C:\websites\dev\pickup\curltest.php on line 19
0
RationalRabbitAuthor Commented:
Great curl test script below. And what I found was that there is apparently something in the query causing the problem.
How did I determine that?
I first ran the script(s) as is to determine that curl was working correctly.
I then ran the sending script with my sample query. It failed (The line "echo 'GET/POST: ' . print_r($_REQUEST, true) . PHP_EOL;" returned "array()".
I them ran the sending script with a one var query string. The above line returned the query variable.
Have no idea what might make the query string cough, unless it's the pipes at the end. (for outside viewers, if you have gotten this far, I've messaged the actual query to Julian and Gonzo) [EDIT] Could also be the email address, since "@" is used for authentication (which may be why Julian thought my query required authentication?)
Process of elimination time. Hopefully, near the end. Rest assurred, you will both get credit for all your time and help. Not that I'm saying Eureka yet ... we'll see.

CURL API thanks to Dan "pixelbrackets" on GitHub https://gist.github.com/pixelbrackets/86513e10c590b25fd673bc30b50288d9
<?php
/**
 * Simple request response script
 * Show all incoming data, eg. to test cURL requests
 */

echo 'API'. PHP_EOL . '==='. PHP_EOL;

echo 'Request Time: ' . time() . PHP_EOL;

echo 'Request Method: ' . print_r($_SERVER['REQUEST_METHOD'], true) . PHP_EOL;

if(FALSE === empty($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) {
   echo 'Request Header Method: ' . print_r($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'], true) . PHP_EOL;
}

echo 'Server Data: ' . print_r($_SERVER, true) . PHP_EOL;

echo 'Request Files: ' . print_r($_FILES, true) . PHP_EOL;

echo 'Request Data: ' . PHP_EOL;
// Will only work with GET & POST
echo 'GET/POST: ' . print_r($_REQUEST, true) . PHP_EOL;
// …DELETE & PUT are not converted into PHP superglobals automatically!
// Note: input stream may be accessed only once!
parse_str(file_get_contents('php://input'), $_DELETE);
echo 'DELETE/PUT: ' . print_r($_DELETE, true) . PHP_EOL;
?> 

Open in new window



CurlRequest.php (there are other options on the GitHub page)
if(!function_exists('curl_init')) {
   die('cURL not available!');
}

$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'http://www.example.com/Curlapi.php');
curl_setopt($curl, CURLOPT_FAILONERROR, true);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

$output = curl_exec($curl);
if ($output === FALSE) {
   echo 'An error has occurred: ' . curl_error($curl) . PHP_EOL;
}
else {
   echo $output;
}
?>

Open in new window

0
RationalRabbitAuthor Commented:
urlencode() does the trick in cURL. Does not work for file_get_contents() because it does not decode. Trying to find out why not.
0
Julian HansenCommented:
As I mentioned in my last post - the cUrl I posted will need to be modified to include support for username and password.

The cUrl above is not dissimilar to the one I posted - no auth so it won't work.

If you PM me your actual URL I can test the code before posting it.
0
RationalRabbitAuthor Commented:
As I mentioned previously, there is an e-mail address in the URL. That's just part of the info being sent. There is no authentication required. As I also stated, the cURL code I posted works fine, once I urlencoded the URL. So, at this point, I am trying to get file_get_contents() to work. It works, but the url is not decoded when received so is invalid. I know this because I capture the URI and post it in a db table. I am only urlencoding those fields that require it. Still, all gets come up blank.

I also mentioned when I PM'd you that you cannot access the server. It is a development server behind a Sonic Wall, with no access outside the system.

Any idea why the urlencoded string is not decoding? I could parse it, but that's kind of yucky.
0
Julian HansenCommented:
I am sorry this is taking so long but it seems that we keep getting stuck on things we shouldn't.

Earlier you posted this
$data = file_get_contents('https://'.$username.':'.$password.'@data.icecat.biz/xml_s3/xml_server3.cgi?prod_id='.$ProductID.';vendor='.$Brand.';lang=EN;output=productxml');

Open in new window

I am guessing based on your last post that this is not the URL you are using?

So, at this point, I am trying to get file_get_contents() to work
Fine - but bear in mind if this code is going to run on the client side and they have disabled allow_url_fopen then your code won't work. cUrl is the only solution that will port.

It works, but the url is not decoded when received so is invalid
I don't understand - the URL is not decoded when received - I thought your API was returning XML which should not require decoding?
0
RationalRabbitAuthor Commented:
Sorry, actually my error. The urlencoded string is working for file_get_contents() as well. Not completely solved yet, though. There is still a header problem.
How do I avoid this?
<!DOCTYPE html>
<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>MME Pickup Request API</title></head><body>

<br />
<b>Warning</b>:  Cannot modify header information - headers already sent by (output started at C:\websites\dev\pickup\putest2.php:4) in <b>C:\websites\dev\pickup\XMLProcess2.php</b> on line <b>3</b><br />
<?xml version="1.0" encoding="utf-8"?>
<Requests><Delivery>11/20/2017</Delivery><Customer>8762492</Customer><Contact>John Doe</Contact></Request>
 </body>
 </html>

Open in new window

0
Julian HansenCommented:
Why are you using headers?
Why is your xml wrapped in a <!doctype HTML><html>

The error is saying you are doing a header() call after sending output to the browser - but I am confused as to why headers are even in the mix.
0
RationalRabbitAuthor Commented:
With all due respect, Julian, the main problem seems to be that you are skimming rather than reading and I have addressed your confusions more then once, but they keep coming up.

The Icecat example, as I have mentioned twice previously, and possibly in a PM, was simply that - an example. (See 42371490, 42342420) I have also mentioned and reiterated that allow_url_fopen is ON.

As  for the decode issue, that is solved. but to respond to your question, fields with spaces, etc. had to be urlencoded for both cURL and file_get_contents. cURL was a lot easier, though. I was able to urlencode the entire query string and it worked fine. With file_get_contents I had to urlencode the values only, so I only did that to those that needed it.

So, the only problem left is how the heck do I get rid of that html header?
I was able to get rid of the header error using this code in XMLProcess (This is the entire code in that file that is now an include pulled into putest.)
<?php
   $QArray = explode('|',$QString);
   foreach($QArray as $value)
   {
      $x = explode('^',$value);
      $XMLItems[$x[0]] = $x[1];
   }
   $str = '<Requests>';
   foreach($XMLItems as $key => $value)
   {
         if(empty($value))
         {
            $str .= ('<'.$key.'/>');
         }
         else
         {
            $str .= ('<'.$key.'>'.$value.'</'.$key.'>');
         }
   }
   $str .= ('</Requests>');

   /* echo($str); */
echo <<< XML
<?xml version="1.0"?>
   {$str}
XML;
?>

Open in new window

But, as you can see from the results below, There is still an html header at the top of the page. Maybe this won't present a problem?
<!DOCTYPE html>
<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>Request API</title></head><body>

<?xml version="1.0"?>
   <Requests><Delivery>11/20/2017</Delivery><Customer>8762492</Customer><Contact>John Doe</Contact></Requests> </body>
 </html>

Open in new window


The process is this:
1. In a strictly PHP file, I have two lines:
$TheQuery = " { the url-endoced query string } ";
  $gxml = file_get_contents("http://dev.domain.com/putest2.php?".$TheQuery);
echo $gxml;

Open in new window

2. putest2.php does a whole lot of processing and runs the code from XMLProcess, which is included. So the html header is coming from putest2.
0
RationalRabbitAuthor Commented:
Why is the HTML header there? Mainly, brain not working.
Actually, there's not a good excuse, but a reason. This file (putest2) doesn't just put out XML. The user can choose their file type and, frankly, in my ignorance, I didn't think it mattered, so the HTML header is at the top of the processing file. Just dawned on me that it is a simple matter of moving it.
0
RationalRabbitAuthor Commented:
Moved the HTML header, so now producing a file like this. taking a look at the results and the code above, do you see any problems?
<?xml version="1.0"?>
   <Requests><Delivery>11/20/2017</Delivery><Customer>8762492</Customer><Contact>John Doe</Contact></Requests>

Open in new window

0
Julian HansenCommented:
Nope - that looks like the type of response you want from an API call.
0
RationalRabbitAuthor Commented:
Really appreciate your hanging in there julian. I'm sure my nievety is a bit frustrating.
0
Julian HansenCommented:
I'm sure my nievety is a bit frustrating
I end up saying a this a lot but don't mind because it is important - we all had to start somewhere. The reason most of us on EE do what we do is because we went through the same process and there were people that helped us through it. There is no frustration.
0
RationalRabbitAuthor Commented:
So, after all this, we came up with two methods - cURL and straight PHP.
Calling Program Using Straight PHP
URL encoding necessary for spaces, apostrophes, etc.,
Two things to note:
1. Encoding the entire query string as a whole will produce an invalid string when received.
2. Do not use urldecode() in the receiving file
<?php
   $TheQuery = 'Name='.urlencode("John Doe").'&Address='.urlencode("24 W 35th Ave").'&City='.urlencode("Warm Springs").'&State=CO&Zip=60649';
   $XML = file_get_contents("http://www.domain.com/getxml.php?".$TheQuery);
   echo $XML;
?>

Open in new window

Calling Program Using cURL
This code thanks to Dan "pixelbrackets" on GitHub https://gist.github.com/pixelbrackets/86513e10c590b25fd673bc30b50288d9
You will find additional options there to Require fresh connection; Send POST request instead of GET and transfer data; Timeout in seconds; Dont verify SSL certificate and more.
<?PHP
if(!function_exists('curl_init'))
{
   die('cURL not available!');
}
$TheQuery = 'Name='.urlencode("John Doe").'&Address='.urlencode("24 W 35th Ave").'&City='.urlencode("Warm Springs").'&State=CO&Zip=60649';
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'http://www.domain.com/getxml.php?'.$TheQuery);
curl_setopt($curl, CURLOPT_FAILONERROR, true);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

$output = curl_exec($curl);
if ($output === FALSE)
{
   echo 'An error has occurred: ' . curl_error($curl) . PHP_EOL;
}
else
{
   echo $output;
}
?>

Open in new window

getxml.php - The Processing File
<?
   # ----- V A L I D A T I O N ----- #
   $Error = array();
   if(empty($_REQUEST['Name']))
   {
      $Error[] = "Name cannot be blank";
   }
   if(strlen($_REQUEST['Zip']) < 5)
   {
      $Error[] = "Improper Zip Code";
   }
   # -------- E R R O R S --------- #
   if(!empty($Error))
   {
      $str = '<Errors>';
      foreach($Error as $value)
      {
         $str .= ('<Error>'.$value.'</Error>');
      }
      $str .= ('</Errors>');
      echo ('<?xml version="1.0"?>
         '.$str);
   }
   else
   {
      # Do any processing here
      # For this simple example, we are going to return
      # a list of books and authors, as well as returning
      # the personal information provided.
      # We've searched a database and come up with an
      # array of book names called "$BookList".
      $str = '<Customer><Name>'.$_REQUEST['Name'].'</Name><Address>'.$_REQUEST['Address'].'</Address><City>'.$_REQUEST['City'].'</city><State>'.$_REQUEST['State'].'</State><Zip>'.$_REQUEST['Zip'].'</zip></Customer>';
      $str .= '<Books>';
      foreach($BookList as $key => $value)
      {
         // if theres a chance of any empty values, do this
         if(empty($value))
         {
            $str .= ('<'.$key.'/>');
         }
         else
         {
            $str .= ('<'.$key.'>'.$value.'</'.$key.'>');
         }
      }
      $str .= ('</Books>');

      echo ('<?xml version="1.0"?>
         '.$str);
   }
?>

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
RationalRabbitAuthor Commented:
This was the best way to show precisely what the end solution was so that others may benefit.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
PHP

From novice to tech pro — start learning today.