* $filter = array( * 'name' => FALSE, * 'administration' => FALSE, * 'management' => array('install' => FALSE) * ); * * * @see setOptFilter() * @see parseXml() * @see xml2array() * @var mixed */ public $filter = false; // Optional filter for loaded XML /** * Set true to strip all mention of comments from the returned array (default); * FALSE to return comment markers (object SimpleXMLElement) * * @see setOptStripComments() * @see parseXml() * @see xml2array() * @var boolean */ public $stripComments = true; /** * Add root element to the result array * Exmple: * * * some value * * * * if * $_optAddRoot = true; * xml2array() result is array('root' => array('tag' => 'some value')); * * if * $_optAddRoot = false; * xml2array() result is array('tag' => 'some value'); * * @see xml2array() * @see setOptAddRoot() * @var boolean */ protected $_optAddRoot = false; /** * Always return array, even for single first level tag => value pair * Exmple: * * * some value * * * * if * $_optForceArray = true; * xml2array() result is array('tag' => array('value' => 'some value')); * where 'value' is the value of $_optValueKey * * If * $_optForceArray = false; * xml2array() result is array('tag' => 'some value'); * * @see xml2array() * @see setOptForceArray() * @var boolean */ protected $_optForceArray = false; /** * Key name for simple tag => value pairs * * @see xml2array() * @see setOptValueKey() * @var string */ protected $_optValueKey = '@value'; /** * Constructor - set defaults * */ function __constructor() { $this->reset(); } /** * Reset object * * @param boolean $xml_contents [optional] * @return xmlClass */ function reset($xml_contents = true) { if($xml_contents) { $this->xmlFileContents = ''; } $this->filter = false; $this->stripComments = true; $this->_optAddRoot = false; $this->_optValueKey = '@value'; $this->_optForceArray = false; return $this; } /** * Set addRoot option * * @param boolean $flag * @return xmlClass */ public function setOptAddRoot($flag) { $this->_optAddRoot = (boolean) $flag; return $this; } /** * Set forceArray option * * @param string $flag * @return xmlClass */ public function setOptForceArray($flag) { $this->_optForceArray = (boolean) $flag; return $this; } /** * Set valueKey option * * @param string $str * @return xmlClass */ public function setOptValueKey($str) { $this->_optValueKey = trim((string) $str); return $this; } /** * Set strpComments option * * @param boolean $flag * @return xmlClass */ public function setOptStripComments($flag) { $this->stripComments = (boolean) $flag; return $this; } /** * Set strpComments option * * @param array $filter * @return xmlClass */ public function setOptFilter($filter) { $this->filter = (array) $filter; return $this; } /** * Get Remote file contents * * @param string $address * @param integer $timeout [optional] seconds * @return string */ function getRemoteFile($address, $timeout = 10) { // Could do something like: if ($timeout <= 0) $timeout = $pref['get_remote_timeout']; here $timeout = min($timeout, 120); $timeout = max($timeout, 3); $address = str_replace(array("\r", "\n", "\t"), '', $address); // May be paranoia, but streaky thought it might be a good idea // ... and there shouldn't be unprintable characters in the URL anyway if (function_exists('file_get_contents')) { $old_timeout = e107_ini_set('default_socket_timeout', $timeout); $data = file_get_contents(urlencode($address)); echo "data=".$data; // $data = file_get_contents(htmlspecialchars($address)); // buggy - sometimes fails. if ($old_timeout !== FALSE) { e107_ini_set('default_socket_timeout', $old_timeout); } if ($data) { return $data; } } if (function_exists("curl_init")) { $cu = curl_init(); curl_setopt($cu, CURLOPT_URL, $address); curl_setopt($cu, CURLOPT_RETURNTRANSFER, 1); curl_setopt($cu, CURLOPT_HEADER, 0); curl_setopt($cu, CURLOPT_TIMEOUT, $timeout); $this->xmlFileContents = curl_exec($cu); if (curl_error($cu)) { $this->error = "Curl error: ".curl_errno($cu).", ".curl_error($cu); return FALSE; } curl_close($cu); return $this->xmlFileContents; } if (ini_get("allow_url_fopen")) { $old_timeout = e107_ini_set('default_socket_timeout', $timeout); $remote = @fopen($address, "r"); if (!$remote) { $this->error = "fopen: Unable to open remote XML file: ".$address; return FALSE; } } else { $old_timeout = $timeout; $tmp = parse_url($address); if (!$remote = fsockopen($tmp['host'], 80, $errno, $errstr, $timeout)) { $this->error = "Sockets: Unable to open remote XML file: ".$address; return FALSE; } else { socket_set_timeout($remote, $timeout); fputs($remote, "GET ".urlencode($address)." HTTP/1.0\r\n\r\n"); } } $this->xmlFileContents = ""; while (!feof($remote)) { $this->xmlFileContents .= fgets($remote, 4096); } fclose($remote); if ($old_timeout != $timeout) { if ($old_timeout !== FALSE) { e107_ini_set('default_socket_timeout', $old_timeout); } } return $this->xmlFileContents; } /** * Parse $xmlFileContents XML string to array * * @param string $xml [optional] * @param boolean $simple [optional] false - use xml2array(), true - use xml_convert_to_array() * @return string */ function parseXml($xml = '', $simple = true) { if ($xml) { $this->xmlFileContents = $xml; } elseif ($this->xmlFileContents) { $xml = $this->xmlFileContents; } if (!$xml) { return false; } $xml = simplexml_load_string($xml); $xml = $simple ? $this->xml_convert_to_array($xml, $this->filter, $this->stripComments) : $this->xml2array($xml); return $xml; } /** * Advanced XML parser - handles tags with attributes and values * proper. * TODO - filter (see xml_convert_to_array) * * @param SimpleXMLElement $xml * @param string $rec_parent used for recursive calls only * @return */ function xml2array($xml, $rec_parent = '') { $ret = array(); $tags = get_object_vars($xml); //remove comments if($this->stripComments && isset($tags['comment'])) { unset($tags['comment']); } //first call if(!$rec_parent) { //$ret = $this->xml2array($xml, true); //repeating code because of the _optForceArray functionality if(!is_object($xml)) { return array(); } $tags = array_keys($tags); foreach ($tags as $tag) { if($tag == '@attributes') { $tmp = (array) $xml->attributes(); $ret['@attributes'] = $tmp['@attributes']; continue; } $count = count($xml->{$tag}); if($count > 1) { for ($i = 0; $i < $count; $i++) { $ret[$tag][$i] = $this->xml2array($xml->{$tag}[$i], $tag); } continue; } $ret[$tag] = $this->xml2array($xml->{$tag}, $tag); } return ($this->_optAddRoot ? array($xml->getName() => $ret) : $ret); } //Recursive calls start here if($tags) { $tags = array_keys($tags); $count_tags = count($tags); //loop through tags foreach ($tags as $tag) { switch($tag) { case '@attributes': $tmp = (array) $xml->attributes(); $ret['@attributes'] = $tmp['@attributes']; if($count_tags == 1) //only attributes & possible value { $ret[$this->_optValueKey] = trim((string) $xml); return $ret; } break; case 'comment': $ret[$this->_optValueKey] = trim((string) $xml); $ret['comment'] = $xml->comment; break; //more cases? default: $count = count($xml->{$tag}); if($count >= 1) //array of elements - loop { for ($i = 0; $i < $count; $i++) { $ret[$tag][$i] = $this->xml2array($xml->{$tag}[$i], $tag); } } else //single element { $ret[$tag] = $this->xml2array($xml->{$tag}, $tag); } break; } } return $ret; } //parse value only $ret = trim((string) $xml); return ($this->_optForceArray ? array($this->_optValueKey => $ret) : $ret); } function xml_convert_to_array($xml, $localFilter = FALSE, $stripComments = TRUE) { if (is_object($xml)) { $xml = (array) $xml; } if (is_array($xml)) { foreach ($xml as $k=>$v) { if ($stripComments && ($k === 'comment')) { unset($xml[$k]); continue; } $enabled = FALSE; if ($localFilter === FALSE) { $enabled = TRUE; $onFilter = FALSE; } elseif (isset($localFilter[$k])) { $enabled = TRUE; $onFilter = $localFilter[$k]; } if ($enabled) { if (is_object($v)) { $v = (array) $v; } $xml[$k] = $this->xml_convert_to_array($v, $onFilter, $stripComments); } else { unset($xml[$k]); } } if (count($xml) == 1 && isset($xml[0])) { $xml = $xml[0]; } } return $xml; } /** * Load XML file and parse it (optional) * * @param string $fname local or remote XML source file path * @param boolean|string $parse false - no parse; * true - use xml_convert_to_array(); * in any other case - use xml2array() * * @param boolean $replace_constants [optional] * @return mixed */ function loadXMLfile($fname, $parse = false, $replace_constants = false) { if (empty($fname)) { return false; } $xml = false; if (strpos($fname, '://') !== false) { $this->getRemoteFile($fname); } else { if ($xml = file_get_contents($fname)) { $this->xmlFileContents = $xml; } } if ($this->xmlFileContents) { if ($replace_constants == true) { $this->xmlFileContents = e107::getParser()->replaceConstants($this->xmlFileContents, '', true); } if ($parse) { return $this->parseXML('', ($parse === true)); } else { return $this->xmlFileContents; } } return false; } private function e107ExportValue($val) { if(is_array($val)) { return "WriteArray($val,FALSE)."]]>"; } if((strpos($val,"<")!==FALSE) || (strpos($val,">")!==FALSE) || (strpos($val,"&")!==FALSE)) { return ""; } return $val; } /** * Create an e107 Export File in XML format * @param array $prefs - see e_core_pref $aliases (eg. core, ipool etc) * @param array $tables - table names with the prefix * @param boolean $debug [optional] * @return text / file for download */ public function e107Export($xmlprefs,$tables,$debug=FALSE) { require_once(e_ADMIN."ver.php"); $text = "\n"; $text .= "\n"; if(varset($xmlprefs)) // Export Core Preferences. { $text .= "\t\n"; foreach($xmlprefs as $type) { $theprefs = e107::getConfig($type)->getPref(); $prefsorted = ksort($theprefs); foreach($theprefs as $key=>$val) { if(isset($val)) { $text .= "\t\t<".$type." name='$key'>".$this->e107ExportValue($val)."\n"; } } } $text .= "\t\n"; } if(varset($tables)) { $text .= "\t\n"; foreach($tables as $tbl) { $eTable= str_replace(MPREFIX,"",$tbl); e107::getDB()->db_Select($eTable, "*"); $text .= "\t\n"; while($row = e107::getDB()-> db_Fetch()) { $text .= "\t\t\n"; foreach($row as $key=>$val) { $text .= "\t\t\t".$this->e107ExportValue($val)."\n"; } $text .= "\t\t\n"; } $text .= "\t\n"; } $text .= "\t\n"; } $text .= ""; if($debug==TRUE) { echo "
".htmlentities($text)."
"; } else { header('Content-type: application/xml', TRUE); header("Content-disposition: attachment; filename= e107Export_" . date("Y-m-d").".xml"); header("Cache-Control: max-age=30"); header("Pragma: public"); echo $text; exit; } } /** * Import an e107 XML file into site preferences and DB tables * @param path $file - e107 XML file path * @param string $only [optional] - prefs|database * @param boolean $debug [optional] * @return array with keys 'success' and 'failed' - DB table entry status. */ public function e107Import($file,$only='',$debug=FALSE) { $xmlArray = $this->loadXMLfile($file,'advanced'); if($debug) { print_a($xmlArray); return; } $ret = array(); if(vartrue($xmlArray['prefs']) && $only !='database') // Save Core Prefs { foreach($xmlArray['prefs'] as $type=>$array) { foreach ($array as $val) { $value = (substr($val['@value'],0,7) == "array (") ? e107::getArrayStorage()->ReadArray($val['@value']) : $val['@value']; e107::getConfig($type)->set($val['@attributes']['name'], $value); } e107::getConfig($type)->save(FALSE); } } if(vartrue($xmlArray['database']) && $only !='prefs') { foreach($xmlArray['database']['dbTable'] as $val) { $table = $val['@attributes']['name']; foreach($val['item'] as $item) { $insert_array = array(); foreach($item['field'] as $f) { $fieldkey = $f['@attributes']['name']; $fieldval = (isset($f['@value'])) ? $f['@value'] : ""; $insert_array[$fieldkey] = $fieldval; } if(e107::getDB()->db_Replace($table, $insert_array)!==FALSE) { $ret['success'][] = $table; } else { $ret['failed'][] = $table; } } } } return $ret; } }