<?php
//=============================================================================
//
// Description:
// Various functions for manipulating XML
//
// Functions:
// array2xml( )
// generateXsdSig( )
// libxml_display_error( )
// libxml_display_errors( )
// schemaValidate( )
// schemaValidateSource( )
// validXsdSig( )
//
//=============================================================================
function array2xml($array, $defaultElement = 'element', $format = false)
{
//===========================================================================
// Function: array2eventData
// Author: Bob Jackman
// Date: 2008-10-21
// Description: Create an XML representation of an array's elements
//
// Params:
// $array {array} Required: Array of elements to convert to XML
// $defaultElement {string} Optional: Tag name to use for non-associative
// array elements. Defaults to 'element'
// $format {bool} Optional: Whether or not to format the XML
// output with tabs and newline
// characters
//
// Returns: {string} Resultant XML
//===========================================================================
// ==================== Determine Indent Level
if ($format !== false)
{
$stack = debug_backtrace();
$tabs = 0;
foreach ($stack as $level) // -- loop through each stack level
{
if (isset($level['function']) && $level['function'] == 'array2xml') // -- call to this function
{
$tabs++;
}
}
}
else
{
$tabs = 0;
}
// ==================== Generate XML
$xml = '';
if (is_array($array))
{
foreach ($array as $tagName => $value) // -- loop through each array element
{
if (is_numeric($tagName)) // -- non-associative key
{
$tagName = $defaultElement;
}
if (!empty($value)) // -- value exists
{
$xml .= str_repeat("\t", $tabs).'<'.$tagName.'>'.($format !== false ? "\n" : '');
if (is_array($value)) // -- child nodes
{
$xml .= array2xml($value, $defaultElement, $format);
}
else // -- value node
{
$xml .= str_repeat("\t", ($format !== false ? ($tabs + 1) : 0)).$value.($format !== false ? "\n" : '');
}
$xml .= str_repeat("\t", ($format !== false ? ($tabs + 1) : 0)).'</'.$tagName.'>'.($format !== false ? "\n" : '');
}
else // -- no value
{
$xml .= str_repeat("\t", ($format !== false ? ($tabs + 1) : 0)).'<'.$tagName.' />'.($format !== false ? "\n" : '');
}
}
}
if ($depth <= 1) // -- add a root element
{
$xml = '<root>'.($format !== false ? "\n" : '').$xml.($format !== false ? "\n" : '').'</root>';
}
// ==================== Return
return $xml;
}
function schemaValidate($xml, $xsd)
{
//===========================================================================
// Function: schemaValidate
// Author: Bob Jackman
// Date: 2008-10-21
// Description: Validate an XML document against an XSD
//
// Params:
// $xml {string} Required: Path to XML file
// $xsd {string} Required: Path to XSD file
//
// Returns: {bool} TRUE = valid
// FALSE = invalid
//===========================================================================
if (file_exists($xml)) // -- XML file found
{
if (file_exists($xsd)) // -- XSD file found
{
// ==================== Config LIBXML
libxml_use_internal_errors(true);
// ==================== Load XML Document
$xmlDoc = new DOMDocument();
$xmlDoc->load($xml);
// ==================== Validate XML
if (!$xmlDoc->schemaValidate($xsd)) // -- invalid
{
return false;
}
else // -- valid
{
return true;
}
}
else // -- XSD file not found
{
throw new Exception('XSD File not found. Cannot validate.');
}
}
else // -- XML file not found
{
throw new Exception('XML File not found. Cannot validate.');
}
}
function schemaValidateSource($xml, $xsd)
{
//===========================================================================
// Function: schemaValidateSource
// Author: Bob Jackman
// Date: 2008-10-21
// Description: Validate an XML string against an XSD
//
// Params:
// $xml {string} Required: XML string
// $xsd {string} Required: Path to XSD file
//
// Returns: {bool} TRUE = valid
// FALSE = invalid
//===========================================================================
if (file_exists($xsd)) // -- XSD file found
{
// ==================== Config LIBXML
libxml_use_internal_errors(true);
// ==================== Parse XML
$xmlDoc = new DOMDocument();
$xmlDoc->loadXML($xml);
// ==================== Validate XML
if (!$xmlDoc->schemaValidate($xsd)) // -- invalid
{
return false;
}
else // -- valid
{
return true;
}
}
else // -- XSD file not found
{
throw new Exception('XSD File not found. Cannot validate.');
}
}
function libxml_display_error($error)
{
//===========================================================================
// Function: libxml_display_error
// Author: Bob Jackman
// Date: 2008-10-21
// Description: display LIBXML error
//
// Params:
// $error {libXMLError} Required: Lib XML Error Object
//
// Returns: {void}
//===========================================================================
// ==================== Determine Error Type
switch ($error->level)
{
case LIBXML_ERR_WARNING:
$return .= "<b>Warning $error->code</b>: ";
break;
case LIBXML_ERR_ERROR:
$return .= "<b>Error $error->code</b>: ";
break;
case LIBXML_ERR_FATAL:
$return .= "<b>Fatal Error $error->code</b>: ";
break;
}
// ==================== Append Error Message
$return .= trim($error->message);
// ==================== Append Error Location
if ($error->file) // -- file location is specified
{
$return .= " in <b>$error->file</b>";
}
$return .= " on line <b>$error->line</b>\n";
// ===================== Output Error
echo $return;
}
function libxml_display_errors()
{
//===========================================================================
// Function: libxml_display_errors
// Author: Bob Jackman
// Date: 2008-10-21
// Description: display all LIBXML errors
//
// Params:
// None
//
// Returns: {void}
//===========================================================================
// ==================== Get Lib XML Errors
$errors = libxml_get_errors();
if (sizeof($errors)) // -- errors are waiting
{
// ==================== Display Errors
//print '<b>DOMDocument::schemaValidate() Generated Errors!</b>';
foreach ($errors as $error) // -- loop through each error
{
libxml_display_error($error);
}
// ==================== Clear Errors
libxml_clear_errors();
}
}
function validXsdSig(SimpleXMLElement $xmlDoc)
{
//===========================================================================
// Function: validXsdSig
// Author: Bob Jackman
// Date: 2008-10-21
// Description: Determine if the signature contained in an XML document
// is a valid Wats digital signature.
//
// Params:
// $xmlDoc {SimpleXMLElement} Required: XML Document for which to
// validate the signature.
//
// Returns: {Bool} TRUE = valid signature
// FALSE = invalid signature / no signature in XML
//===========================================================================
// ==================== Copy XML Object
$xmlDoc = clone $xmlDoc;
$valid = false;
if (isset($xmlDoc->signature)) // -- signature exists
{
// ==================== Extract Signature
$sig = strval($xmlDoc->signature->attributes()->value);
unset($xmlDoc->signature);
//echo generateXsdSig($xmlDoc)."<br>";
// ==================== Validate Signature
if ($sig == generateXsdSig($xmlDoc)) // -- signature is valid
{
$valid = true;
}
}
// ==================== Return Validation
return $valid;
}
function generateXsdSig(SimpleXMLElement $xmlDoc)
{
//===========================================================================
// Function: generateXsdSig
// Author: Bob Jackman
// Date: 2008-10-21
// Description: Generate and append a valid Wats digital signature to the
// supplied XML document.
//
// Params:
// $xmlDoc {SimpleXMLElement} Required: XML Document for which to
// generate a signature.
//
// Returns: {String} Valid Wats digital signature
//===========================================================================
// ==================== Copy XML Object
$xmlDoc = clone $xmlDoc;
// ********************
// ********************
$seed = 'WesternWats'; // -- Changing this seed will invalidate all previously signed documents!!!
// ********************
// ********************
// ==================== Check for Existing Signature
$sig = null;
if (isset($xmlDoc->signature)) // -- signature already exists
{
if (validXsdSig($xmlDoc)) // -- existing sig is valid
{
$sig = strval($xmlDoc->signature->attributes()->value);
}
else // -- existing sig is invalid
{
unset($xmlDoc->signature);
}
}
if ($sig === null) // -- need a new or replacement sig
{
// ==================== Remove All Whitespace
$xml = preg_replace('/\s*/', '', $xmlDoc->saveXML());
// ==================== Generate Signature
$sig = sha1($seed.$xml);
}
// ==================== Return Signature Value
return $sig;
}
?>