So, for some unfathomable reason, Affiliate Window have decided to shut-down their XML datafeeds, leaving only CSV feeds available.
They've asked every to migrate to CSV. This doesn't make any sense. The data is better structured in XML and is by far easier to parse.
Instead they've just caused 1,000s of companies that implement their feeds to have to do loads of work to keep their datafeeds working.
For us, we would have had to amend over 100 imports, but instead I've just replicated the XML endpoint, and auto-convert CSV feeds back into their XML equivalent.
For those that want to do the same (you just need to host it at your own domain), feel free to use the code below:
.htaccess:
RewriteEngine On
RewriteRule datafeed/(.*) /index.php [L]
index.php:
<?php
ini_set("memory_limit", -1);
ini_set("max_execution_time", -1);
class ArrayToXML
{
/**
* The main function for converting to an XML document.
* Pass in a multi dimensional array and this recrusively loops through and builds up an XML document.
* Based on: http://snipplr.com/view/3491/convert-php-array-to-xml-or-simple-xml-object-if-you-wish/
*
* @param array $data
* @param string $rootNodeName - what you want the root node to be - defaultsto data.
* @param SimpleXMLElement $xml - should only be used recursively
* @return string XML
*/
public static function toXml($data, $rootNodeName = 'data', &$xml=null)
{
// turn off compatibility mode as simple xml throws a wobbly if you don't.
if ( ini_get('zend.ze1_compatibility_mode') == 1 ) ini_set ( 'zend.ze1_compatibility_mode', 0 );
if ( is_null( $xml ) ) {
$xml = simplexml_load_string(stripslashes("<product></product>"));
}
// loop through the data passed in.
foreach( $data as $key => $value ) {
// no numeric keys in our xml please!
$numeric = false;
if ( is_numeric( $key ) ) {
$numeric = 1;
$key = $rootNodeName;
}
// delete any char not allowed in XML element names
$key = preg_replace('/[^a-z0-9\-\_\.\:]/i', '', $key);
//check to see if there should be an attribute added (expecting to see _id_)
$attrs = false;
//if there are attributes in the array (denoted by attr_**) then add as XML attributes
if ( is_array( $value ) ) {
foreach($value as $i => $v ) {
$attr_start = false;
$attr_start = stripos($i, 'attr_');
if ($attr_start === 0) {
$attrs[substr($i, 5)] = $v; unset($value[$i]);
}
}
}
// if there is another array found recursively call this function
if ( is_array( $value ) ) {
if ( ArrayToXML::is_assoc( $value ) || $numeric ) {
// older SimpleXMLElement Libraries do not have the addChild Method
if (method_exists('SimpleXMLElement','addChild'))
{
$node = $xml->addChild( $key, null );
if ($attrs) {
foreach($attrs as $key => $attribute) {
$node->addAttribute($key, $attribute);
}
}
}
}else{
$node =$xml;
}
// recrusive call.
if ( $numeric ) $key = 'anon';
ArrayToXML::toXml( $value, $key, $node );
} else {
// older SimplXMLElement Libraries do not have the addChild Method
if (method_exists('SimpleXMLElement','addChild'))
{
$childnode = $xml->addChild( $key, htmlspecialchars($value));
if ($attrs) {
foreach($attrs as $key => $attribute) {
$childnode->addAttribute($key, $attribute);
}
}
}
}
}
// pass back as unformatted XML
//return $xml->asXML('data.xml');
// if you want the XML to be formatted, use the below instead to return the XML
$doc = new DOMDocument('1.0');
$doc->preserveWhiteSpace = false;
@$doc->loadXML( ArrayToXML::fixCDATA($xml->asXML()) );
$doc->formatOutput = false;
return preg_replace("/<\\?xml.*\\?>/",'',$doc->saveXML(),1);
}
public static function fixCDATA($string) {
//fix CDATA tags
$find[] = '<![CDATA[';
$replace[] = '<![CDATA[';
$find[] = ']]>';
$replace[] = ']]>';
$string = str_ireplace($find, $replace, $string);
return $string;
}
/**
* Convert an XML document to a multi dimensional array
* Pass in an XML document (or SimpleXMLElement object) and this recrusively loops through and builds a representative array
*
* @param string $xml - XML document - can optionally be a SimpleXMLElement object
* @return array ARRAY
*/
public static function toArray( $xml ) {
if ( is_string( $xml ) ) $xml = new SimpleXMLElement( $xml );
$children = $xml->children();
if ( !$children ) return (string) $xml;
$arr = array();
foreach ( $children as $key => $node ) {
$node = ArrayToXML::toArray( $node );
// support for 'anon' non-associative arrays
if ( $key == 'anon' ) $key = count( $arr );
// if the node is already set, put it into an array
if ( isset( $arr[$key] ) ) {
if ( !is_array( $arr[$key] ) || $arr[$key][0] == null ) $arr[$key] = array( $arr[$key] );
$arr[$key][] = $node;
} else {
$arr[$key] = $node;
}
}
return $arr;
}
// determine if a variable is an associative array
public static function is_assoc( $array ) {
return (is_array($array) && 0 !== count(array_diff_key($array, array_keys(array_keys($array)))));
}
}
$url = "https://productdata.awin.com" . $_SERVER['REQUEST_URI'];
$url = str_replace('/format/xml-tree/', '/format/csv/', $url);
$random = uniqid();
exec('curl '.$url.' > '.$random.'.zip');
exec('unzip -p '.$random.'.zip > '.$random.'.csv');
exec('rm '.$random.'.zip');
function cleanHeader($header) {
return str_replace('Telcos:', '', $header);
}
$xmlarray = new ArrayToXML();
$fh = @fopen($random.'.csv', 'r');
//get headers
$headers = str_getcsv(fgets($fh),',','"','"');
$product = array();
file_put_contents($random.'.xml', '<products>', FILE_APPEND);
while (($d = fgets($fh)) !== false) {
$d = str_getcsv($d,',','"','"');
for($i=0;$i<count($d);$i++) {
if (cleanHeader($headers[$i])) $row[cleanHeader($headers[$i])] = $d[$i];
}
$product[] = $row;
file_put_contents($random.'.xml', $xmlarray->toXml($row, 'product'), FILE_APPEND);
unset($row);
};
file_put_contents($random.'.xml', '</products>', FILE_APPEND);
exec('zip '.$random.'.zip '.$random.'.xml');
header("Content-Type: application/zip");
header("Content-Disposition: attachment; filename=".$random.".zip");
header("Content-Length: " . filesize($random.".zip"));
readfile($random.".zip");
exec('rm '.$random.'.csv');
exec('rm '.$random.'.xml');
exec('rm '.$random.'.zip');
?>