Location: PHPKode > scripts > PHP Xforms > php-xforms/PhpXforms.php
<?php

/**
 * class PhpXforms
 *
 * @author Victor Bolshov <hide@address.com>
 * @copyright Use it if you like it
 *
 */

class PhpXforms {

	/**
	 * @var string
	 */
	protected $_schema;

	/**
	 * @var string
	 */
	protected $_xmlSource;

	/**
	 * @var bool
	 */
	protected $_schemaAsSource;

	/**
	 * @var callback
	 */
	protected $_dataValidator;

	/**
	 * @var callback
	 */
	protected $_dataProcessor;

	/**
	 * @var callback
	 */
	protected $_exceptionHandler;

	/**
	 * @var callback
	 */
	protected $_onSuccessCallback;

	/**
	 * User-submitted data, in the form of PHP-array
	 * @var array
	 */
	protected $_data;

	/**
	 * Constructor
	 *
	 * @param string $schema XMLSchema (either path to file containing schema source or the source itself;
	 * in the latter case the second parameter must be set to TRUE)
	 */
	function __construct($schema, $asSource = false)
	{
		$this->_schemaAsSource = (bool) $asSource;
		$this->_schema = (string) $schema;
		if (! $this->_schemaAsSource && ! is_readable($this->_schema))
		{
			throw new PhpXformsException('Schema file ' . $this->_schema . ' is unreadable');
		}
	}

	/**
	 * Set the source document to be validated
	 *
	 * @param string $source XML document
	 * @return void
	 */
	function setXmlSource($source)
	{
		$this->_xmlSource = $source;
	}

	/**
	 * Set a callback for additional data validation.
	 * Callback must accept array of data (possibly multidimensional) as parameter and
	 * throw an Exception in case of validation error.
	 *
	 * NOTE: primary validation (datatypes, min-max values) is actually supposed to be done with XmlSchema,
	 * this callback is for additional validation, such as check for unique field in the database.
	 *
	 * @param callback $callback
	 * @return void
	 * @throws PhpXformsException
	 */
	function setValidatorCallback($callback)
	{
		$this->_setCallback($this->_dataValidator, $callback);
	}

	/**
	 * @see setValidatorCallback
	 * This function is an alias to setValidatorCallback(array($object, $method))
	 *
	 * @param object $object
	 * @param string $method
	 * @return void
	 * @throws PhpXformsException
	 */
	function setValidator($object, $method)
	{
		$this->setValidatorCallback(array($object, $method));
	}

	/**
	 * Set a callback for data processing.
	 * Callback must accept array of data (possibly multidimensional) as parameter and
	 * throw an Exception in case of error.
	 *
	 * @param callback $callback
	 * @return void
	 * @throws PhpXformsException
	 */
	function setProcessorCallback($callback)
	{
		$this->_setCallback($this->_dataProcessor, $callback);
	}

	/**
	 * @see setProcessorCallback
	 * This function is an alias to setProcessorCallback(array($object, $method))
	 *
	 * @param object $object
	 * @param string $method
	 * @return void
	 * @throws PhpXformsException
	 */
	function setProcessor($object, $method)
	{
		$this->setProcessorCallback(array($object, $method));
	}

	/**
	 * Set a callback for exception handling.
	 * Callback must accept an Exception as parameter
	 *
	 * @param callback $callback
	 * @return void
	 * @throws PhpXformsException
	 */
	function setExceptionHandlerCallback($callback)
	{
		$this->_setCallback($this->_exceptionHandler, $callback);
	}

	/**
	 * @see setExceptionHandlerCallback
	 * This function is an alias to setExceptionHandlerCallback(array($object, $method))
	 *
	 * @param object $object
	 * @param string $method
	 * @return void
	 * @throws PhpXformsException
	 */
	function setExceptionHandler($object, $method)
	{
		$this->setExceptionHandlerCallback(array($object, $method));
	}

	/**
	 * Sets default exception handler.
	 * @see setExceptionHandler
	 * @see PhpXforms_ExceptionHandler
	 * @param object $object
	 * @param string $method
	 * @return void
	 * @throws PhpXformsException
	 */
	function setDefaultExceptionHandler($encoding = null)
	{
		require_once dirname(__FILE__) . '/' . __CLASS__ . '/ExceptionHandler.php';
		$this->setExceptionHandler(
			new PhpXforms_ExceptionHandler($encoding), 'xmlErrorList');
	}

	/**
	 * Set a callback for execute after successful data processing.
	 * Callback must accept array of data (possibly multidimensional) as parameter
	 *
	 * @param callback $callback
	 * @return void
	 * @throws PhpXformsException
	 */
	function setSuccessProcessorCallback($callback)
	{
		$this->_setCallback($this->_onSuccessCallback, $callback);
	}

	/**
	 * @see setSuccessProcessorCallback
	 * This function is an alias to setSuccessProcessorCallback(array($object, $method))
	 *
	 * @param object $object
	 * @param string $method
	 * @return void
	 * @throws PhpXformsException
	 */
	function setSuccessProcessor($object, $method)
	{
		$this->setSuccessProcessorCallback(array($object, $method));
	}

	/**
	 * Sets default processor for successful data-processing.
	 * @see setSuccessProcessor
	 * @see PhpXforms_SuccessProcessor
	 * @param object $object
	 * @param string $method
	 * @return void
	 * @throws PhpXformsException
	 */
	function setDefaultSuccessProcessor($encoding = null)
	{
		require_once dirname(__FILE__) . '/' . __CLASS__ . '/SuccessProcessor.php';
		$this->setSuccessProcessor(
			new PhpXforms_SuccessProcessor($encoding), 'emptyErrorList');
	}

	/**
	 * Perform validation and data-processing
	 *
	 * @throws Exception
	 */
	function run()
	{
		$this->_ensureXmlSource();
		try {

			// validation
			$this->_data = $this->_validate();

			// data processing
			if (null !== $this->_dataProcessor)
			{
				call_user_func($this->_dataProcessor, $this->_data);
			}

			// success! handle it, too...
			if (null !== $this->_onSuccessCallback)
			{
				call_user_func($this->_onSuccessCallback, $this->_data);
			}

		} catch (Exception $e) {
			if (null === $this->_exceptionHandler)
			{
				throw $e;
			}
			else
			{
				call_user_func($this->_exceptionHandler, $e);
			}
		}
	}

	/**
	 * Export user-submitted data as an array
	 * @return array
	 */
	function export()
	{
		if (null === $this->_data)
		{
			throw new PhpXformsException('Data is empty! Consider using run() first.');
		}
		return (array) $this->_data;
	}

	/**
	 * Validates user-submitted XML data with XmlSchema and (optionally)
	 * with user-provided validator
	 *
	 * @return array Validated data
	 * @throws PhpXformsException
	 */
	protected function _validate()
	{
		$this->_schemaValidate();

		$data = (array) simplexml_load_string($this->_xmlSource);

		if (null !== $this->_dataValidator)
		{
			call_user_func($this->_dataValidator, $data);
		}

		return $data;
	}

	/**
	 * Validates user-submitted XML data with XmlSchema
	 *
	 * @throws PhpXformsException
	 * @access protected
	 */
	protected function _schemaValidate()
	{
		$doc = $this->_getSourceDomDocument();
		ini_set('track_errors', 'On');
		if ($this->_schemaAsSource)
		{
			$valid = @ $doc->schemaValidateSource($this->_schema);
		}
		else
		{
			$valid = @ $doc->schemaValidate($this->_schema);
		}

		if (! $valid)
		{
			throw new PhpXformsException('Schema validation error: ' . $php_errormsg);
		}
	}

	/**
	 * @param mixed $ref
	 * @param callback $callback
	 * @access protected
	 */
	protected function _setCallback(& $ref, $callback)
	{
		if (! is_callable($callback))
		{
			throw new PhpXformsException('Invalid callback');
		}

		$ref = $callback;
	}

	/**
	 * Make sure we have what to validate/process.
	 * In case we do not have a XML document specified by user,
	 * $HTTP_RAW_POST_DATA is used
	 * @access protected
	 */
	protected function _ensureXmlSource()
	{
		if (null === $this->_xmlSource)
		{
			$this->_xmlSource = $this->_getRawData();
		}
	}

	/**
	 * @throws PhpXformsException
	 * @access protected
	 */
	protected function _assertPostRequest()
	{
		if ($_SERVER['REQUEST_METHOD'] != 'POST')
		{
			throw new PhpXformsException('Illegal request method');
		}
	}

	/**
	 * retrieve $HTTP_RAW_POST_DATA
	 * @throws PhpXformsException
	 * @access protected
	 */
	protected function _getRawData()
	{
		$this->_assertPostRequest();
		if (empty($GLOBALS['HTTP_RAW_POST_DATA']))
		{
			throw new PhpXformsException('Couldn\'t find HTTP_RAW_POST_DATA');
		}

		return $GLOBALS['HTTP_RAW_POST_DATA'];
	}

	/**
	 * @return DomDocument
	 * @throws PhpXformsException
	 * @access protected
	 */
	protected function _getSourceDomDocument()
	{
		$ret = new DOMDocument();
		if (! $ret->loadXml($this->_xmlSource))
		{
			throw new PhpXformsException('XML source doesn\'t seem to be a valid XML string');
		}

		return $ret;
	}
}

/**
 * Exceptions for PhpXforms
 */
class PhpXformsException extends Exception {

}
Return current item: PHP Xforms