0

I have some php code that calls an api I have on a different server/instance and echos the response. Whenever I attempt to run the php below in a browser I get an xml parsing error stating extra content at the end of the document. I cannot figure out where the error in my code is, Any pointers would be greatly appreciated!

PHP:

<?php


//define API instance info
define('API_URL','somewhere.com/getAllAlbums');
define('API_ID','someuser');
define('SIGNATURE','somekey');

// Generate a request date stamp
$request_date=date("mdYHis");

// Get token -
// load the existing token, and add 1 to it
$fp=fopen("/somedirectory","r");
$token=fread($fp,filesize("/samedirectoryasabove"));
fclose($fp);
$token=sprintf("%d",$token);
$token++;

// Write out the new token in place of the old one for next time
$fp=fopen("/samedirectoryasabove","w");
$written=fwrite($fp,$token);
fclose($fp);

// Generate the hash to be sent and matched
$auth_string=API_ID . ":" . $token . ":" . $request_date;
$auth_string_hash=base64_encode(hash_hmac('sha256',$auth_string,SIGNATURE,1));

// Set up the POST request for information
// This could be different for each different API information request
$post_fields=array('token'=>$token,timestamp=>$request_date);
$post_string="";
foreach($post_fields as $key=>$value)
        $post_string.=$key . "=" . $value . "&";
$post_string=rtrim($post_string,"&");

//  Use CURL to make the request to the API server
$request = API_URL;
$curl = curl_init($request);
curl_setopt($curl,CURLOPT_POST, count($post_fields));
curl_setopt($curl,CURLOPT_POSTFIELDS, $post_string);
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Authorization: ' . $auth_string_hash)); 
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
$response=curl_exec($curl);
curl_close($curl);

// Echos response, problem here?
header('Content-Type: text/xml');
echo "$response";

?>

API PHP

<?php

error_reporting(E_ALL ^ E_NOTICE);

// The following four statements allow AJAX style Javascript requests to get through by allowing certain headers
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: OPTIONS, HEAD, GET, POST');
header('Access-Control-Max-Age: 604800');
header('Access-Control-Allow-Headers: X-Requested-With,Content-Type, Content-Length, Authorization, Connection');


$valid_user = 'someuser';

//db host
define(DB_HOST,'192.168.1.116'); 
define(DB_USER,'DBUSER');
define(DB_PASSWORD,'DBPASS');
define(DB_DATABASE,'databasename');  
$dbConn=mysqli_connect(DB_HOST,DB_USER,DB_PASSWORD,DB_DATABASE);

$query="select signature from api_keys where id='$valid_user'";
$result=mysqli_query($dbConn,$query);
$cnt=mysqli_num_rows($result);
if($cnt!=1)
        invalidRequest('001');

$row=mysqli_fetch_assoc($result);
$signature = $row["signature"];



$headers=apache_request_headers();
$digest=$headers["Authorization"];


if (is_null($digest))
{
        invalidRequest('002');
}

// Attempt to auth the request - grab the token and request date provided by the external API caller
$token=$_POST["token"];
$request_date=$_POST["timestamp"];

// No token or reqauest generates an error
if(!$token || !$request_date)
{
        invalidRequest('002');
}
// The page wasn't called right, so throw an error
if(!$_GET["action"])
{
    invalidRequest('002');
}



$hash_string=base64_encode(hash_hmac('sha256',$valid_user . ":" . $token . ":" . $request_date,$signature,1));
//echo $hash_string . ":" . $digest;
//exit();
// Compare the hash we generated with the one provided by the requester
// If they do not match, throw an error
if($hash_string!=$digest)
{
        invalidRequest('002');
}


$query="select token from api_tokens where id='$valid_user' and token='$token'";
$result=mysqli_query($dbConn,$query);
$cnt=mysqli_num_rows($result);
 ('$valid_user','$token','" . date("Y-m-d H:i:s") . "')";

// Get the information requested and return it as XML string.
if($_GET["action"]=='getAllAlbums')
{
    // This is a request for all the albums in the DB
    $query="select id,artist,name from albums order by id";
    $result=mysqli_query($dbConn,$query);
    if(mysqli_num_rows($result) < 1)
        invalidRequest('006');
    $xml_string="<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
    $xml_string.="<music_inventory>\n";
    while($row=mysqli_fetch_assoc($result))
    {
        $xml_string.="<album id=\"" . $row["id"] . "\">\n";
        $xml_string.="<artist>" . htmlentities($row["artist"]) . "</artist>\n";
        $xml_string.="<name>" . htmlentities($row["name"]) . "</name>\n";
        $xml_string.="</album>\n";
    }
    $xml_string.="</music_inventory>";
}
else if($_GET["action"]=='getAlbum')
{
    // This was a request for a single album's full info
    $query="select id,type,albumart,artist,name,year,label,disc,totaldiscs from albums where id='" . $_POST["albumID"] . "'";
    $result=mysqli_query($dbConn,$query);
    if(mysqli_num_rows($result) < 1)
        invalidRequest('006');
    $xml_string="<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
    $xml_string.="<music_inventory>\n";
    while($row=mysqli_fetch_assoc($result))
    {
        if($row["type"]=='F')
            $type='full length';
        else if($row["type"]=='E')
            $type='EP';
        else
            $type='unknown';
        $xml_string.="<album id=\"" . $row["id"] . "\" type=\"$type\" albumart=\"" . $row["albumart"] . "\">\n";
        $xml_string.="<artist>" . $row["artist"] . "</artist>\n";
        $xml_string.="<name>" . $row["name"] . "</name>\n";
        $xml_string.="<year>" . $row["year"] . "</year>\n";
        $xml_string.="<label>" . $row["label"] . "</label>\n";
        $xml_string.="<disc>" . $row["disc"] . "</disc>\n";
        $xml_string.="<totaldiscs>" . $row["totaldiscs"] . "</totaldiscs>\n";
    }
    $query="select id,track_number,track_title,track_artist from tracklist where id='" . $_POST["albumID"] . "' order by track_number";
    $result=mysqli_query($dbConn,$query);
    $xml_string.="   <tracklist>\n";
    while($row=mysqli_fetch_assoc($result))
    {
        $xml_string.="<track id=\"" . $row["track_number"] . "\">" . htmlentities($row["track_title"]) . "</track>\n";
    }
    $xml_string.="</tracklist>\n";
    $xml_string.="</album>\n";
    $xml_string.="</music_inventory>\n";
}
else if($_GET["action"]=='getTrackList')
{
    // This was a request for a specific album's track list
    $xml_string="<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
    $query="select id,track_number,track_title,track_artist from tracklist where id='" . $_POST["albumID"] . "' order by track_number";
    $result=mysqli_query($dbConn,$query);
    $xml_string.="<music_inventory>";
    $xml_string.="<album id=\"" . $_POST["albumID"] . "\"></album>\n";
    $xml_string.="<tracklist>\n";
    while($row=mysqli_fetch_assoc($result))
    {
        $xml_string.="<track id=\"" . $row["track_number"] . "\">" . $row["track_title"] . "</track>\n";
    }
    $xml_string.="</tracklist>\n";
    $xml_string.="</music_inventory>";
}
else
{
    // This did not have a valid request attached to it
    invalidRequest('003');
}
// Echo out the result as XML
header('Content-Type: text/xml');
echo $xml_string;
exit();

function invalidRequest($error)
{
    // This is the error thrown in all cases above.
    $xml_string="<?xml version=\"1.0\"?>\n";
    $xml_string.="<systemerror>\n";
    $xml_string.=" <errorcode>$error</errorcode>\n";
    $xml_string.="</systemerror>\n";
    header('Content-Type: text/xml');
    echo $xml_string;
        exit();
}

?>
exeleon
  • 121
  • 2
  • 14
  • You are creating XML "by hand" (string concatenation). This is known to be an error-prone procedure. It's also a procedure known done by inexperienced programmers. Both in combination this more or less often leads to error situations like the one you describe (*"extra content at the end of the document"*). Please relate to existing Q&A material we have on site about this error first. There can be many concrete reasons why this exactly causes the error *in your situation* but Q&A wise the aim is to describe the error message and offer general solutions to it. – hakre Apr 28 '15 at 06:17

1 Answers1

0

That error message means that the XML string you're outputting is invalid. There's (probably) nothing wrong with the PHP code you posted. Take a look at the source and ensure that every element is properly closed and nested correctly. It's possible that the API is sending you bad data. If the API response always has the same error, you can hack a fix by doing a string operation (str_replace or preg_replace, for instance) before passing it to your browser or simplexml_decode_string().

Mikkel
  • 1,192
  • 9
  • 22