DOAP - Remote Abstract Data Access Protocol by Dave

Download DOAP

Please be aware and take note of the following:

DOAP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public Licence as published by the Free Software Foundation, either version 3 of the Licence, or (at your option) any later version.

DOAP is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licence for more details.

Download Package

Download Current Version: doap-0.01.zip

View Code Online

Below is the code for each of the three components; doap.inc.php (DOAP Server PHP library), xmlcreate.inc.php (Support XML Library) and doap.js (DOAP Client JavaScript library).

DOAP Server PHP Library (doap.inc.php)
<?php 
/* -------------------------------------------------------------
This file is part of DOAP (Dave's Own Access Protocol)
 
DOAP is (C) Copyright 2011 PurplePixie Systems
 
DOAP is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
 
DOAP is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with DOAP.  If not, see www.gnu.org/licenses
 
For more information see http://www.purplepixie.org/doap
-------------------------------------------------------------- */
 
/**
 * DOAP Server Module - Dave's Own Access Protocol
 * @author David Cutting
 * @package DOAP
 * @copyright 2010 PurplePixie Systems
 * @version 0.01
**/
 
// First we check for xmlCreate and try to include it if not found
if (!class_exists("XMLCreate"))
{
	$tryfile = dirname(__FILE__)."/"."xmlcreate.inc.php";
	if (file_exists($tryfile)) include_once($tryfile);
}
 
/**
 * DOAP Server Class
 * @package DOAP
**/
class DOAP_Server
{
 
/**
 * Keep list of registered functions and associated data
**/
private $functions = array();
 
/**
 * Register a function
 * @param string $funcname Name of function to register
 * @param int $param_min Minimum parameters for function (optional, default not enforced)
 * @param int $param_max Maximum parameters for function (optional, default not enforced)
**/
function Register($funcname,$param_min=-1, $param_max=-1)
{
	$this->functions[$funcname]['name']=$funcname;
	$this->functions[$funcname]['min']=$param_min;
	$this->functions[$funcname]['max']=$param_max;
}
 
/**
 * Generate a DOAP Error in XML
 * @param int $code Error Code Number
 * @param string $desc Error Description
 * @param bool $outputxml Output XML to Screen (as well as return) (optional, default false)
 * @return string XML output
**/
function Error($code,$desc,$outputxml=true)
{
	$xml = new XMLCreate();
	$xml -> startElement("ERROR");
	$xml -> charElement("CODE",$code,0,false,true);
	$xml -> charElement("DESC",$desc,0,false,true);
	$xml -> endElement("ERROR");
 
	if ($outputxml)
	{
		@header("Content-type: text/xml");
		echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n";
		echo $xml->xml;
	}
 
	return $xml -> xml;
}
 
/**
 * Add an array to the XML output (may be called recursively for arrays in an array object)
 * @param array $array Array to parse
 * @param string &$xml Pointer to output XML
**/
function AddArray($array,&$xml)
{
	$xml -> startElement("ARRAY");
	foreach($array as $element)
	{
		if (!is_array($element)) $xml->charElement("ELEMENT",$element,0,false,true);
		else $this->AddArray($element,$xml);
	}
	$xml->endElement("ARRAY");
}
 
/**
 * Process any DOAP Requests
 * @param bool $outputxml Output XML to the screen (optional, default true)
 * @return string DOAP XML Output
**/
function Process($outputxml=true)
{
	if (!class_exists("xmlCreate"))
	{
		$xml="<ERROR>\n <CODE>208</CODE>\n <DESC>xmlCreate Library Not Found</DESC>\n</ERROR>\n";
		if ($outputxml)
		{
			@header("Content-type: text/xml");
			echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n";
			echo $xml;
		}
		return $xml;
	}
 
	if (isset($_REQUEST['f'])) $func=$_REQUEST['f'];
	else return $this->Error(200,"No function specified",$outputxml);
 
	if (!isset($this->functions[$func])) return $this->Error(201,"Illegal function specified: ".$func,$outputxml);
 
	if (isset($_REQUEST['p'])) $params=$_REQUEST['p'];
	else $params=array();
 
	if (!is_array($params)) $params=array($params);
 
	if (!function_exists($func)) return $this->Error(202,"Non-existant function specified: ".$func,$outputxml);
 
	if ( ($this->functions[$func]['min']>0) && (sizeof($params)<$this->functions[$func]['min']) )
		return $this->Error(203,"Too few parameters for function ".$func." (needs ".$this->functions[$func]['min'].")",$outputxml);
 
	if ( ($this->functions[$func]['max']>=0) && (sizeof($params)>$this->functions[$func]['max']) )
		return $this->Error(203,"Too many parameters for function ".$func." (max ".$this->functions[$func]['max'].")",$outputxml);
 
	switch(sizeof($params)) // Oh dear so messy but without using eval() and the performance hit the only way I think
	{
		case 0: $res = $func();
		break;
		case 1: $res = $func($params[0]);
		break;
		case 2: $res = $func($params[0],$params[1]);
		break;
		case 3: $res = $func($params[0],$params[1],$params[2]);
		break;
		case 4: $res = $func($params[0],$params[1],$params[2],$params[3]);
		break;
		case 5: $res = $func($params[0],$params[1],$params[2],$params[3],$params[4]);
		break;
		case 6: $res = $func($params[0],$params[1],$params[2],$params[3],$params[4], $params[5]);
		break;
		case 7: $res = $func($params[0],$params[1],$params[2],$params[3],$params[4], $params[5],
			$params[6]);
		break;
		case 8: $res = $func($params[0],$params[1],$params[2],$params[3],$params[4], $params[5],
			$params[6], $params[7]);
		break;
		case 9: $res = $func($params[0],$params[1],$params[2],$params[3],$params[4], $params[5],
			$params[6], $params[7], $params[8]);
		break;
		case 10: $res = $func($params[0],$params[1],$params[2],$params[3],$params[4], $params[5],
			$params[6], $params[7], $params[8], $params[9]);
		break;
		default: return $this->Error(204,"Parameters in excess of DOAP Limit (10)",$outputxml);
	}
 
	$xml = new xmlCreate();
 
	if (!is_array($res)) $xml->charElement("RESULT",$res,0,false,true);
	else $this->AddArray($res,$xml);
 
	if ($outputxml)
	{
		@header("Content-type: text/xml");
		echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n";
		echo $xml->xml;
	}
 
	return $xml->xml;
}
 
}
?>


xmlCreator PHP Library (xmlcreate.inc.php)
<?php
/**
 * xmlCreate PHP Utility
 * @version 0.01
 * @author David Cutting
 * @package xmlCreate
*/
 
/**
 * Main xmlCreate class object
*/
class xmlCreate
{
 
/**
 * Contains XML Output
*/
var $xml = "";
 
/**
 * Contains open tags
 * Not yet implemented 
*/
var $open_tags = array();
 
/**
 * Contains Depth of Elements
*/
var $depth = 0;
 
/** 
 * Control the depth (variance)
 * @param integer $varience What to alter the depth by
*/
function setDepth($varience)
	{
	$this->depth += $varience;
	}
 
/** 
 * Pad to depth
*/
function pad()
	{
	if ($this->depth<1) return "";
	return str_pad("",$this->depth," ");
	}
 
/**
 * Start building an open-ended XML element
 * @param string $element Name of the element
 * @param array $vars Optional array of key values to use (or int 0 to skip)
 * @param boolean $single Optional indicator of single element if true
 * @param boolean $newline Optional insert newline at the end
*/
function startElement($element,$vars=0,$single=false,$newline=true)
	{
	$this->xml.=$this->pad();
	$this->xml.="<".$element;
	if ( ($vars!=0) && (is_array($vars)) )
		{
		foreach($vars as $key => $val)
			{
			$this->xml.=" ".$key."=\"".$val."\"";
			}
		}
	if ($single) $this->xml.=" /";
	$this->xml.=">";
	if ($newline) $this->xml.="\n";
	if (!$single) $this->setDepth(1);
	}
 
 
/**
 * End an open-ended XML element
 * @param string $element Name of the element
 * @param boolean $pad Optional use padding (default true)
*/
function endElement($element,$pad=true)
	{
	$this->setDepth(-1);
	if ($pad) $this->xml.=$this->pad();
	$this->xml.="</".$element.">\n";
	}
 
/**
 * Insert data (textual/char data)
 * @param string $data Actual data to insert
 * @param boolean $cdata Wrap with CDATA (optional, default NO)
 * @param boolean $htmlcode Use HTML special characters (optional, default NO)
 * @param boolean $newline Insert newline after data (optional, default YES)
*/
function charData($data, $cdata=false, $htmlcode=false, $newline=true)
	{
	$dataline="";
	if ($cdata) $dataline.="<![CDATA[";
	if ($htmlcode) $data=htmlspecialchars($data);
	$dataline.=$data;
	if ($cdata) $dataline.="]]>";
	if ($newline) $dataline.="\n";
	$this->xml.=$dataline;
	}
 
/**
 * Single element wrapper for (@link startElement)
 * @param string $element Element Name
 * @param array $vars Optional variable array
*/
function singleElement($element,$vars=0)
	{
	$this->startElement($element,$vars,true);
	}
 
/**
 * Single char-element wrapper
 * @param string $element Element Name
 * @param string $data Element Data Content
 * @param array $vars Optional array element variables (int 0 to skip)
 * @param boolean $htmlchars Optional convert data to html special chars (default false)
 * @param boolean $cdata Optional enclose char data in CDATA block (default false)
*/
function charElement($element,$data,$vars=0,$htmlchars=false,$cdata=false)
	{
	$this->startElement($element,$vars,false,false);
	$this->charData($data,$cdata,$htmlchars,false);
	$this->endElement($element,false);
	}
 
/**
 * Returns XML Buffer
 * @return string XML Buffer
*/
function getXML()
	{
	return $this->xml;
	}
 
/**
 * Writes XML Buffer to Screen
 * @param boolean $html Convert to HTML-friendly output (optional, default NO)
 * @param boolean $header Show an xml header (optional, default NO)
 * @param string $head_version XML Header version if shown (optional, default 1.0)
 * @param string $head_encode XML encoding in header if shown (optional, default utf-8)
*/
function echoXML($html=false,$header=false,$head_version="1.0",$head_encode="utf-8")
	{
	$out="";
	if ($header) $out.="<?xml version=\"".$head_version."\" encoding=\"".$head_encode."\"?>\n";
	$out.=$this->xml;
	if ($html) $out=nl2br(htmlspecialchars($out));
	echo $out;
	}
 
}
?>


DOAP Client JavaScript Library (doap.js)
/* -------------------------------------------------------------
This file is part of DOAP (Dave's Own Access Protocol)
 
DOAP is (C) Copyright 2011 PurplePixie Systems
 
DOAP is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
 
DOAP is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with DOAP.  If not, see www.gnu.org/licenses
 
For more information see http://www.purplepixie.org/doap
-------------------------------------------------------------- */
 
function DOAP_Error(code, desc)
{
	this.code = code;
	this.desc = desc;
}
 
function DOAP_xmlhttp()
{
	this.xmlhttp = null;
	if (window.XMLHttpRequest)
	{
		this.xmlhttp = new XMLHttpRequest;
		if (this.xmlhttp.overrideMimeType) this.xmlhttp.overrideMimeType("text/xml");
	}
	else if (window.ActiveXObject)
	{
		try
		{
			this.xmlhttp = new ActiveXObject("Msxml2.HTTP");
		}
		catch(e)
		{
			try
			{
				this.xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
			}
			catch(e)
			{
				// Give Up Now
			}
		}
	}
 
	if (this.xmlhttp == null)
	{
		var error = new DOAP_Error(100,"Failed to Create XMLHTTP Object");
		throw error;
	}
	else return true;
}
 
function DOAP_randomstring( len )
{
	if (!len) var len = 32;
	var allowed = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
	var rstring = "";
 
	for (var i=0; i<len; i++)
	{
		var rchar = Math.floor(Math.random() * allowed.length);
		rstring += allowed.substring(rchar, rchar+1);
	}
 
	return rstring;
}
 
function DOAP_call( func, params )
{
	var callurl = this.url + "?f=" + func;
 
	if (!params) params = Array();
	else if (!params instanceof Array) params = Array(params);
 
	for (var i=0; i<params.length; i++)
	{
		callurl = callurl + "&p["+i+"]="+encodeURIComponent(params[i]);
	}
 
	if (this.nocache)
	{
		callurl += ("&nc=" + this.makerandomstring());
	}
 
	if (this.xmlhttp == null) this.makexmlhttp();
 
 
	if ( this.async && (this.callback != null) ) // async - CAREFUL!
	{
		this.xmlhttp.doap = this;
		this.xmlhttp.open('GET', callurl, true);
 
		this.xmlhttp.onreadystatechange = function()
		{
			if (this.readyState == 4)
			{
				if (this.status == 200)
				{
					if (this.responseXML == null)
					{
						alert("null data");
						var error = new DOAP_Error(102, "XML Result Null (Blank, Invalid or Corrupt)");
						throw error;
					}
					else
					{
						this.doap.callback(this.doap.process(this.responseXML));
					}
				}
				else
				{
					var error = new DOAP_Error(101, "HTTP Result Not 200 ("+this.xmlhttp.status+")");
					throw error;
				}	
			}
		}
		this.xmlhttp.send();
	}
	else // non-sync
	{	
		this.xmlhttp.open('GET', callurl, false);
		this.xmlhttp.send(null);
 
		if (this.xmlhttp.status == 200)
		{
			if (this.xmlhttp.responseXML == null)
			{
				var error = new DOAP_Error(102, "XML Result Null (Blank, Invalid or Corrupt)");
				throw error;
			}
			else return this.process(this.xmlhttp.responseXML);
		}
		else
		{
			var error = new DOAP_Error(101, "HTTP Result Not 200 ("+this.xmlhttp.status+")");
			throw error;
		}	
	}
}
 
function DOAP_array( arrxml )
{
	var arr = Array();
 
	for (var i=0; i<arrxml.childNodes.length; i++)
	{
		var ename = arrxml.childNodes[i].tagName;
		if (ename == "ELEMENT") arr.push(arrxml.childNodes[i].firstChild.nodeValue);
		else if (ename == "ARRAY")
		{
			arr.push(this.processarray(arrxml.childNodes[i]));
		}
		else
		{
			// unknown element type in array return
		}
	}
 
	return arr;
}
 
function DOAP_process( xml )
{
	if (xml.documentElement.tagName == "ERROR")
	{
		var code = xml.getElementsByTagName("CODE")[0].firstChild.nodeValue;
		var desc = xml.getElementsByTagName("DESC")[0].firstChild.nodeValue;
		var error = new DOAP_Error(code, desc);
		throw error;
	}
 
	else if (xml.documentElement.tagName == "RESULT")
	{
		var result = xml.getElementsByTagName("RESULT")[0];
		if (result==null)
		{
			var error = new DOAP_Error(105,"Result Block not in XML");
			throw error;
		}
		var data = result.firstChild.nodeValue;
	}
 
	else if (xml.documentElement.tagName == "ARRAY")
	{
		var arrdata = xml.getElementsByTagName("ARRAY")[0];
		var data = this.processarray(arrdata);
	}
 
	else
	{
		var error=new DOAP_Error(106,"Unknown XML Response Type: "+xml.documentElement.tagName);
		throw error;
	}
 
 
	return data;
}
 
function DOAP()
{
	this.xmlhttp = null;
	this.url = "";
 
	this.nocache = true;
 
	this.async = false;
	this.callback = null;
 
	this.makexmlhttp = DOAP_xmlhttp;
	this.makerandomstring = DOAP_randomstring;
	this.call = DOAP_call;
	this.process = DOAP_process;
	this.processarray = DOAP_array;
}