]> git.andy128k.dev Git - ipf-xmlrpc.git/commitdiff
move to root
authorAndrey Kutejko <andy128k@gmail.com>
Sun, 28 Jul 2013 11:32:54 +0000 (14:32 +0300)
committerAndrey Kutejko <andy128k@gmail.com>
Sun, 28 Jul 2013 11:32:54 +0000 (14:32 +0300)
64 files changed:
ipf/server/abstract.php [deleted file]
ipf/server/interface.php [deleted file]
ipf/server/reflection.php [deleted file]
ipf/server/reflection/class.php [deleted file]
ipf/server/reflection/function.php [deleted file]
ipf/server/reflection/function/abstract.php [deleted file]
ipf/server/reflection/method.php [deleted file]
ipf/server/reflection/node.php [deleted file]
ipf/server/reflection/parameter.php [deleted file]
ipf/server/reflection/prototype.php [deleted file]
ipf/server/reflection/returnvalue.php [deleted file]
ipf/xmlrpc/fault.php [deleted file]
ipf/xmlrpc/request.php [deleted file]
ipf/xmlrpc/request/http.php [deleted file]
ipf/xmlrpc/request/stdin.php [deleted file]
ipf/xmlrpc/response.php [deleted file]
ipf/xmlrpc/response/http.php [deleted file]
ipf/xmlrpc/server.php [deleted file]
ipf/xmlrpc/server/cache.php [deleted file]
ipf/xmlrpc/server/fault.php [deleted file]
ipf/xmlrpc/value.php [deleted file]
ipf/xmlrpc/value/array.php [deleted file]
ipf/xmlrpc/value/base64.php [deleted file]
ipf/xmlrpc/value/boolean.php [deleted file]
ipf/xmlrpc/value/collection.php [deleted file]
ipf/xmlrpc/value/datetime.php [deleted file]
ipf/xmlrpc/value/double.php [deleted file]
ipf/xmlrpc/value/integer.php [deleted file]
ipf/xmlrpc/value/nil.php [deleted file]
ipf/xmlrpc/value/scalar.php [deleted file]
ipf/xmlrpc/value/string.php [deleted file]
ipf/xmlrpc/value/struct.php [deleted file]
server/abstract.php [new file with mode: 0644]
server/interface.php [new file with mode: 0644]
server/reflection.php [new file with mode: 0644]
server/reflection/class.php [new file with mode: 0644]
server/reflection/function.php [new file with mode: 0644]
server/reflection/function/abstract.php [new file with mode: 0644]
server/reflection/method.php [new file with mode: 0644]
server/reflection/node.php [new file with mode: 0644]
server/reflection/parameter.php [new file with mode: 0644]
server/reflection/prototype.php [new file with mode: 0644]
server/reflection/returnvalue.php [new file with mode: 0644]
xmlrpc/fault.php [new file with mode: 0644]
xmlrpc/request.php [new file with mode: 0644]
xmlrpc/request/http.php [new file with mode: 0644]
xmlrpc/request/stdin.php [new file with mode: 0644]
xmlrpc/response.php [new file with mode: 0644]
xmlrpc/response/http.php [new file with mode: 0644]
xmlrpc/server.php [new file with mode: 0644]
xmlrpc/server/cache.php [new file with mode: 0644]
xmlrpc/server/fault.php [new file with mode: 0644]
xmlrpc/value.php [new file with mode: 0644]
xmlrpc/value/array.php [new file with mode: 0644]
xmlrpc/value/base64.php [new file with mode: 0644]
xmlrpc/value/boolean.php [new file with mode: 0644]
xmlrpc/value/collection.php [new file with mode: 0644]
xmlrpc/value/datetime.php [new file with mode: 0644]
xmlrpc/value/double.php [new file with mode: 0644]
xmlrpc/value/integer.php [new file with mode: 0644]
xmlrpc/value/nil.php [new file with mode: 0644]
xmlrpc/value/scalar.php [new file with mode: 0644]
xmlrpc/value/string.php [new file with mode: 0644]
xmlrpc/value/struct.php [new file with mode: 0644]

diff --git a/ipf/server/abstract.php b/ipf/server/abstract.php
deleted file mode 100644 (file)
index b0cf6a1..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-<?php
-
-abstract class IPF_Server_Abstract implements IPF_Server_Interface
-{
-    protected static $magic_methods = array(
-        '__construct',
-        '__destruct',
-        '__get',
-        '__set',
-        '__call',
-        '__sleep',
-        '__wakeup',
-        '__isset',
-        '__unset',
-        '__tostring',
-        '__clone',
-        '__set_state',
-    );
-
-    public static function lowerCase(&$value, &$key)
-    {
-        return $value = strtolower($value);
-    }
-}
diff --git a/ipf/server/interface.php b/ipf/server/interface.php
deleted file mode 100644 (file)
index 8176019..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-<?php
-
-interface IPF_Server_Interface
-{
-    public function addFunction($function, $namespace = '');
-    public function setClass($class, $namespace = '', $argv = null);
-    public function fault($fault = null, $code = 404);
-    public function handle($request = false);
-    public function getFunctions();
-    public function loadFunctions($definition);
-    public function setPersistence($mode);
-}
diff --git a/ipf/server/reflection.php b/ipf/server/reflection.php
deleted file mode 100644 (file)
index f6f98f2..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-<?php
-
-class IPF_Server_Reflection
-{
-    public static function reflectClass($class, $argv = false, $namespace = '')
-    {
-        if (is_object($class)) {
-            $reflection = new ReflectionObject($class);
-        } elseif (class_exists($class)) {
-            $reflection = new ReflectionClass($class);
-        } else {
-            throw new IPF_Exception('Invalid class or object passed to attachClass()');
-        }
-
-        if ($argv && !is_array($argv)) {
-            throw new IPF_Exception('Invalid argv argument passed to reflectClass');
-        }
-        return new IPF_Server_Reflection_Class($reflection, $namespace, $argv);
-    }
-
-    public static function reflectFunction($function, $argv = false, $namespace = '')
-    {
-        if (!is_string($function) || !function_exists($function)) {
-            throw new IPF_Exception('Invalid function "' . $function . '" passed to reflectFunction');
-        }
-        if ($argv && !is_array($argv)) {
-            throw new IPF_Exception('Invalid argv argument passed to reflectClass');
-        }
-        return new IPF_Server_Reflection_Function(new ReflectionFunction($function), $namespace, $argv);
-    }
-}
diff --git a/ipf/server/reflection/class.php b/ipf/server/reflection/class.php
deleted file mode 100644 (file)
index d082be5..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-<?php
-
-class IPF_Server_Reflection_Class
-{
-    protected $_config = array();
-    protected $_methods = array();
-    protected $_namespace = null;
-    protected $_reflection;
-    public function __construct(ReflectionClass $reflection, $namespace = null, $argv = false)
-    {
-        $this->_reflection = $reflection;
-        $this->setNamespace($namespace);
-
-        foreach ($reflection->getMethods() as $method) {
-            // Don't aggregate magic methods
-            if ('__' == substr($method->getName(), 0, 2)) {
-                continue;
-            }
-
-            if ($method->isPublic()) {
-                // Get signatures and description
-                $this->_methods[] = new IPF_Server_Reflection_Method($this, $method, $this->getNamespace(), $argv);
-            }
-        }
-    }
-
-    public function __call($method, $args)
-    {
-        if (method_exists($this->_reflection, $method)) {
-            return call_user_func_array(array($this->_reflection, $method), $args);
-        }
-        throw new IPF_Exception('Invalid reflection method');
-    }
-
-    public function __get($key)
-    {
-        if (isset($this->_config[$key])) {
-            return $this->_config[$key];
-        }
-
-        return null;
-    }
-
-    public function __set($key, $value)
-    {
-        $this->_config[$key] = $value;
-    }
-
-    public function getMethods()
-    {
-        return $this->_methods;
-    }
-
-    public function getNamespace()
-    {
-        return $this->_namespace;
-    }
-
-    public function setNamespace($namespace)
-    {
-        if (empty($namespace)) {
-            $this->_namespace = '';
-            return;
-        }
-
-        if (!is_string($namespace) || !preg_match('/[a-z0-9_\.]+/i', $namespace)) {
-            throw new IPF_Exception('Invalid namespace');
-        }
-
-        $this->_namespace = $namespace;
-    }
-
-    public function __wakeup()
-    {
-        $this->_reflection = new ReflectionClass($this->getName());
-    }
-}
diff --git a/ipf/server/reflection/function.php b/ipf/server/reflection/function.php
deleted file mode 100644 (file)
index a4cd63c..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-<?php
-
-class IPF_Server_Reflection_Function extends IPF_Server_Reflection_Function_Abstract{
-}
diff --git a/ipf/server/reflection/function/abstract.php b/ipf/server/reflection/function/abstract.php
deleted file mode 100644 (file)
index f65405d..0000000
+++ /dev/null
@@ -1,293 +0,0 @@
-<?php
-
-class IPF_Server_Reflection_Function_Abstract
-{
-    protected $_reflection;
-    protected $_argv = array();
-    protected $_config = array();
-    protected $_class;
-    protected $_description = '';
-    protected $_namespace;
-
-    protected $_prototypes = array();
-
-    private $_return;
-    private $_returnDesc;
-    private $_paramDesc;
-    private $_sigParams;
-    private $_sigParamsDepth;
-
-    public function __construct(Reflector $r, $namespace = null, $argv = array())
-    {
-        // In PHP 5.1.x, ReflectionMethod extends ReflectionFunction. In 5.2.x,
-        // both extend ReflectionFunctionAbstract. So, we can't do normal type
-        // hinting in the prototype, but instead need to do some explicit
-        // testing here.
-        if ((!$r instanceof ReflectionFunction)
-            && (!$r instanceof ReflectionMethod)) {
-            throw new IPF_Exception('Invalid reflection class');
-        }
-        $this->_reflection = $r;
-
-        // Determine namespace
-        if (null !== $namespace){
-            $this->setNamespace($namespace);
-        }
-
-        // Determine arguments
-        if (is_array($argv)) {
-            $this->_argv = $argv;
-        }
-
-        // If method call, need to store some info on the class
-        if ($r instanceof ReflectionMethod) {
-            $this->_class = $r->getDeclaringClass()->getName();
-        }
-
-        // Perform some introspection
-        $this->_reflect();
-    }
-
-    protected function _addTree(IPF_Server_Reflection_Node $parent, $level = 0)
-    {
-        if ($level >= $this->_sigParamsDepth) {
-            return;
-        }
-
-        foreach ($this->_sigParams[$level] as $value) {
-            $node = new IPF_Server_Reflection_Node($value, $parent);
-            if ((null !== $value) && ($this->_sigParamsDepth > $level + 1)) {
-                $this->_addTree($node, $level + 1);
-            }
-        }
-    }
-
-    protected function _buildTree()
-    {
-        $returnTree = array();
-        foreach ((array) $this->_return as $value) {
-            $node = new IPF_Server_Reflection_Node($value);
-            $this->_addTree($node);
-            $returnTree[] = $node;
-        }
-
-        return $returnTree;
-    }
-
-    protected function _buildSignatures($return, $returnDesc, $paramTypes, $paramDesc)
-    {
-        $this->_return         = $return;
-        $this->_returnDesc     = $returnDesc;
-        $this->_paramDesc      = $paramDesc;
-        $this->_sigParams      = $paramTypes;
-        $this->_sigParamsDepth = count($paramTypes);
-        $signatureTrees        = $this->_buildTree();
-        $signatures            = array();
-
-        $endPoints = array();
-        foreach ($signatureTrees as $root) {
-            $tmp = $root->getEndPoints();
-            if (empty($tmp)) {
-                $endPoints = array_merge($endPoints, array($root));
-            } else {
-                $endPoints = array_merge($endPoints, $tmp);
-            }
-        }
-
-        foreach ($endPoints as $node) {
-            if (!$node instanceof IPF_Server_Reflection_Node) {
-                continue;
-            }
-
-            $signature = array();
-            do {
-                array_unshift($signature, $node->getValue());
-                $node = $node->getParent();
-            } while ($node instanceof IPF_Server_Reflection_Node);
-
-            $signatures[] = $signature;
-        }
-
-        // Build prototypes
-        $params = $this->_reflection->getParameters();
-        foreach ($signatures as $signature) {
-            $return = new IPF_Server_Reflection_ReturnValue(array_shift($signature), $this->_returnDesc);
-            $tmp    = array();
-            foreach ($signature as $key => $type) {
-                $param = new IPF_Server_Reflection_Parameter($params[$key], $type, $this->_paramDesc[$key]);
-                $param->setPosition($key);
-                $tmp[] = $param;
-            }
-
-            $this->_prototypes[] = new IPF_Server_Reflection_Prototype($return, $tmp);
-        }
-    }
-
-    protected function _reflect()
-    {
-        $function           = $this->_reflection;
-        $helpText           = '';
-        $signatures         = array();
-        $returnDesc         = '';
-        $paramCount         = $function->getNumberOfParameters();
-        $paramCountRequired = $function->getNumberOfRequiredParameters();
-        $parameters         = $function->getParameters();
-        $docBlock           = $function->getDocComment();
-
-        if (!empty($docBlock)) {
-            // Get help text
-            if (preg_match(':/\*\*\s*\r?\n\s*\*\s(.*?)\r?\n\s*\*(\s@|/):s', $docBlock, $matches))
-            {
-                $helpText = $matches[1];
-                $helpText = preg_replace('/(^\s*\*\s)/m', '', $helpText);
-                $helpText = preg_replace('/\r?\n\s*\*\s*(\r?\n)*/s', "\n", $helpText);
-                $helpText = trim($helpText);
-            }
-
-            // Get return type(s) and description
-            $return     = 'void';
-            if (preg_match('/@return\s+(\S+)/', $docBlock, $matches)) {
-                $return = explode('|', $matches[1]);
-                if (preg_match('/@return\s+\S+\s+(.*?)(@|\*\/)/s', $docBlock, $matches))
-                {
-                    $value = $matches[1];
-                    $value = preg_replace('/\s?\*\s/m', '', $value);
-                    $value = preg_replace('/\s{2,}/', ' ', $value);
-                    $returnDesc = trim($value);
-                }
-            }
-
-            // Get param types and description
-            if (preg_match_all('/@param\s+([^\s]+)/m', $docBlock, $matches)) {
-                $paramTypesTmp = $matches[1];
-                if (preg_match_all('/@param\s+\S+\s+(\$^\S+)\s+(.*?)(@|\*\/)/s', $docBlock, $matches))
-                {
-                    $paramDesc = $matches[2];
-                    foreach ($paramDesc as $key => $value) {
-                        $value = preg_replace('/\s?\*\s/m', '', $value);
-                        $value = preg_replace('/\s{2,}/', ' ', $value);
-                        $paramDesc[$key] = trim($value);
-                    }
-                }
-            }
-        } else {
-            $helpText = $function->getName();
-            $return   = 'void';
-        }
-
-        // Set method description
-        $this->setDescription($helpText);
-
-        // Get all param types as arrays
-        if (!isset($paramTypesTmp) && (0 < $paramCount)) {
-            $paramTypesTmp = array_fill(0, $paramCount, 'mixed');
-        } elseif (!isset($paramTypesTmp)) {
-            $paramTypesTmp = array();
-        } elseif (count($paramTypesTmp) < $paramCount) {
-            $start = $paramCount - count($paramTypesTmp);
-            for ($i = $start; $i < $paramCount; ++$i) {
-                $paramTypesTmp[$i] = 'mixed';
-            }
-        }
-
-        // Get all param descriptions as arrays
-        if (!isset($paramDesc) && (0 < $paramCount)) {
-            $paramDesc = array_fill(0, $paramCount, '');
-        } elseif (!isset($paramDesc)) {
-            $paramDesc = array();
-        } elseif (count($paramDesc) < $paramCount) {
-            $start = $paramCount - count($paramDesc);
-            for ($i = $start; $i < $paramCount; ++$i) {
-                $paramDesc[$i] = '';
-            }
-        }
-
-
-        $paramTypes = array();
-        foreach ($paramTypesTmp as $i => $param) {
-            $tmp = explode('|', $param);
-            if ($parameters[$i]->isOptional()) {
-                array_unshift($tmp, null);
-            }
-            $paramTypes[] = $tmp;
-        }
-
-        $this->_buildSignatures($return, $returnDesc, $paramTypes, $paramDesc);
-    }
-
-    public function __call($method, $args)
-    {
-        if (method_exists($this->_reflection, $method)) {
-            return call_user_func_array(array($this->_reflection, $method), $args);
-        }
-
-        throw new IPF_Exception('Invalid reflection method ("' .$method. '")');
-    }
-
-    public function __get($key)
-    {
-        if (isset($this->_config[$key])) {
-            return $this->_config[$key];
-        }
-
-        return null;
-    }
-
-    public function __set($key, $value)
-    {
-        $this->_config[$key] = $value;
-    }
-
-    public function setNamespace($namespace)
-    {
-        if (empty($namespace)) {
-            $this->_namespace = '';
-            return;
-        }
-
-        if (!is_string($namespace) || !preg_match('/[a-z0-9_\.]+/i', $namespace)) {
-            throw new IPF_Exception('Invalid namespace');
-        }
-
-        $this->_namespace = $namespace;
-    }
-
-    public function getNamespace()
-    {
-        return $this->_namespace;
-    }
-
-    public function setDescription($string)
-    {
-        if (!is_string($string)) {
-            throw new IPF_Exception('Invalid description');
-        }
-
-        $this->_description = $string;
-    }
-
-    public function getDescription()
-    {
-        return $this->_description;
-    }
-
-    public function getPrototypes()
-    {
-        return $this->_prototypes;
-    }
-
-    public function getInvokeArguments()
-    {
-        return $this->_argv;
-    }
-
-    public function __wakeup()
-    {
-        if ($this->_reflection instanceof ReflectionMethod) {
-            $class = new ReflectionClass($this->_class);
-            $this->_reflection = new ReflectionMethod($class->newInstance(), $this->getName());
-        } else {
-            $this->_reflection = new ReflectionFunction($this->getName());
-        }
-    }
-}
diff --git a/ipf/server/reflection/method.php b/ipf/server/reflection/method.php
deleted file mode 100644 (file)
index 9aaee14..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-<?php
-
-class IPF_Server_Reflection_Method extends IPF_Server_Reflection_Function_Abstract
-{
-    protected $_class;
-    protected $_classReflection;
-
-    public function __construct(IPF_Server_Reflection_Class $class, ReflectionMethod $r, $namespace = null, $argv = array())
-    {
-        $this->_classReflection = $class;
-        $this->_reflection      = $r;
-
-        $classNamespace = $class->getNamespace();
-
-        // Determine namespace
-        if (!empty($namespace)) {
-            $this->setNamespace($namespace);
-        } elseif (!empty($classNamespace)) {
-            $this->setNamespace($classNamespace);
-        }
-
-        // Determine arguments
-        if (is_array($argv)) {
-            $this->_argv = $argv;
-        }
-
-        // If method call, need to store some info on the class
-        $this->_class = $class->getName();
-
-        // Perform some introspection
-        $this->_reflect();
-    }
-
-    public function getDeclaringClass()
-    {
-        return $this->_classReflection;
-    }
-
-    public function __wakeup()
-    {
-        $this->_classReflection = new IPF_Server_Reflection_Class(new ReflectionClass($this->_class), $this->getNamespace(), $this->getInvokeArguments());
-        $this->_reflection = new ReflectionMethod($this->_classReflection->getName(), $this->getName());
-    }
-
-}
diff --git a/ipf/server/reflection/node.php b/ipf/server/reflection/node.php
deleted file mode 100644 (file)
index 5ee1a2a..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-<?php
-
-class IPF_Server_Reflection_Node
-{
-    protected $_value = null;
-    protected $_children = array();
-    protected $_parent = null;
-
-    public function __construct($value, IPF_Server_Reflection_Node $parent = null)
-    {
-        $this->_value = $value;
-        if (null !== $parent) {
-            $this->setParent($parent, true);
-        }
-
-        return $this;
-    }
-
-    public function setParent(IPF_Server_Reflection_Node $node, $new = false)
-    {
-        $this->_parent = $node;
-
-        if ($new) {
-            $node->attachChild($this);
-            return;
-        }
-    }
-
-    public function createChild($value)
-    {
-        $child = new self($value, $this);
-
-        return $child;
-    }
-
-    public function attachChild(IPF_Server_Reflection_Node $node)
-    {
-        $this->_children[] = $node;
-
-        if ($node->getParent() !== $this) {
-            $node->setParent($this);
-        }
-    }
-
-    public function getChildren()
-    {
-        return $this->_children;
-    }
-
-    public function hasChildren()
-    {
-        return count($this->_children) > 0;
-    }
-
-    public function getParent()
-    {
-        return $this->_parent;
-    }
-
-    public function getValue()
-    {
-        return $this->_value;
-    }
-
-    public function setValue($value)
-    {
-        $this->_value = $value;
-    }
-
-    public function getEndPoints()
-    {
-        $endPoints = array();
-        if (!$this->hasChildren()) {
-            return $endPoints;
-        }
-
-        foreach ($this->_children as $child) {
-            $value = $child->getValue();
-
-            if (null === $value) {
-                $endPoints[] = $this;
-            } elseif ((null !== $value)
-                && $child->hasChildren())
-            {
-                $childEndPoints = $child->getEndPoints();
-                if (!empty($childEndPoints)) {
-                    $endPoints = array_merge($endPoints, $childEndPoints);
-                }
-            } elseif ((null !== $value) && !$child->hasChildren()) {
-                $endPoints[] = $child;
-            }
-        }
-
-        return $endPoints;
-    }
-}
diff --git a/ipf/server/reflection/parameter.php b/ipf/server/reflection/parameter.php
deleted file mode 100644 (file)
index d043314..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-<?php
-
-class IPF_Server_Reflection_Parameter
-{
-    protected $_reflection;
-    protected $_position;
-    protected $_type;
-    protected $_description;
-
-    public function __construct(ReflectionParameter $r, $type = 'mixed', $description = '')
-    {
-        $this->_reflection = $r;
-        $this->setType($type);
-        $this->setDescription($description);
-    }
-
-    public function __call($method, $args)
-    {
-        if (method_exists($this->_reflection, $method)) {
-            return call_user_func_array(array($this->_reflection, $method), $args);
-        }
-        throw new IPF_Exception('Invalid reflection method');
-    }
-
-    public function getType()
-    {
-        return $this->_type;
-    }
-
-    public function setType($type)
-    {
-        if (!is_string($type) && (null !== $type)) {
-            throw new IPF_Exception('Invalid parameter type');
-        }
-        $this->_type = $type;
-    }
-
-    public function getDescription()
-    {
-        return $this->_description;
-    }
-
-    public function setDescription($description)
-    {
-        if (!is_string($description) && (null !== $description)) {
-            throw new IPF_Exception('Invalid parameter description');
-        }
-        $this->_description = $description;
-    }
-
-    public function setPosition($index)
-    {
-        $this->_position = (int) $index;
-    }
-
-    public function getPosition()
-    {
-        return $this->_position;
-    }
-}
diff --git a/ipf/server/reflection/prototype.php b/ipf/server/reflection/prototype.php
deleted file mode 100644 (file)
index c34375d..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-<?php
-
-class IPF_Server_Reflection_Prototype
-{
-    public function __construct(IPF_Server_Reflection_ReturnValue $return, $params = null)
-    {
-        $this->_return = $return;
-
-        if (!is_array($params) && (null !== $params)) {
-            throw new IPF_Exception('Invalid parameters');
-        }
-
-        if (is_array($params)) {
-            foreach ($params as $param) {
-                if (!$param instanceof IPF_Server_Reflection_Parameter) {
-                    throw new IPF_Exception('One or more params are invalid');
-                }
-            }
-        }
-
-        $this->_params = $params;
-    }
-
-    public function getReturnType()
-    {
-        return $this->_return->getType();
-    }
-
-    public function getReturnValue()
-    {
-        return $this->_return;
-    }
-
-    public function getParameters()
-    {
-        return $this->_params;
-    }
-}
diff --git a/ipf/server/reflection/returnvalue.php b/ipf/server/reflection/returnvalue.php
deleted file mode 100644 (file)
index c33fb2c..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-
-class IPF_Server_Reflection_ReturnValue
-{
-    protected $_type;
-    protected $_description;
-
-    public function __construct($type = 'mixed', $description = '')
-    {
-        $this->setType($type);
-        $this->setDescription($description);
-    }
-
-    public function getType()
-    {
-        return $this->_type;
-    }
-
-    public function setType($type)
-    {
-        if (!is_string($type) && (null !== $type)) {
-            throw new IPF_Exception('Invalid parameter type');
-        }
-        $this->_type = $type;
-    }
-
-    public function getDescription()
-    {
-        return $this->_description;
-    }
-
-    public function setDescription($description)
-    {
-        if (!is_string($description) && (null !== $description)) {
-            throw new IPF_Exception('Invalid parameter description');
-        }
-        $this->_description = $description;
-    }
-}
diff --git a/ipf/xmlrpc/fault.php b/ipf/xmlrpc/fault.php
deleted file mode 100644 (file)
index 7b1d7b7..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-<?php
-
-class IPF_XmlRpc_Fault
-{
-    protected $_code;
-    protected $_encoding = 'UTF-8';
-    protected $_message;
-
-    protected $_internal = array(
-        404 => 'Unknown Error',
-
-        // 610 - 619 reflection errors
-        610 => 'Invalid method class',
-        611 => 'Unable to attach function or callback; not callable',
-        612 => 'Unable to load array; not an array',
-        613 => 'One or more method records are corrupt or otherwise unusable',
-
-        // 620 - 629 dispatch errors
-        620 => 'Method does not exist',
-        621 => 'Error instantiating class to invoke method',
-        622 => 'Method missing implementation',
-        623 => 'Calling parameters do not match signature',
-
-        // 630 - 639 request errors
-        630 => 'Unable to read request',
-        631 => 'Failed to parse request',
-        632 => 'Invalid request, no method passed; request must contain a \'methodName\' tag',
-        633 => 'Param must contain a value',
-        634 => 'Invalid method name',
-        635 => 'Invalid XML provided to request',
-        636 => 'Error creating xmlrpc value',
-
-        // 640 - 649 system.* errors
-        640 => 'Method does not exist',
-
-        // 650 - 659 response errors
-        650 => 'Invalid XML provided for response',
-        651 => 'Failed to parse response',
-        652 => 'Invalid response',
-        653 => 'Invalid XMLRPC value in response',
-    );
-
-    public function __construct($code = 404, $message = '')
-    {
-        $this->setCode($code);
-        $code = $this->getCode();
-
-        if (empty($message) && isset($this->_internal[$code])) {
-            $message = $this->_internal[$code];
-        } elseif (empty($message)) {
-            $message = 'Unknown error';
-        }
-        $this->setMessage($message);
-    }
-
-    public function setCode($code)
-    {
-        $this->_code = (int) $code;
-        return $this;
-    }
-
-    public function getCode()
-    {
-        return $this->_code;
-    }
-
-    public function setMessage($message)
-    {
-        $this->_message = (string) $message;
-        return $this;
-    }
-
-    public function getMessage()
-    {
-        return $this->_message;
-    }
-
-    public function setEncoding($encoding)
-    {
-        $this->_encoding = $encoding;
-        return $this;
-    }
-
-    public function getEncoding()
-    {
-        return $this->_encoding;
-    }
-
-    public function loadXml($fault)
-    {
-        if (!is_string($fault)) {
-            throw new IPF_Exception('Invalid XML provided to fault');
-        }
-
-        try {
-            $xml = @new SimpleXMLElement($fault);
-        } catch (Exception $e) {
-            // Not valid XML
-            throw new IPF_Exception('Failed to parse XML fault: ' .  $e->getMessage(), 500);
-        }
-
-        // Check for fault
-        if (!$xml->fault) {
-            // Not a fault
-            return false;
-        }
-
-        if (!$xml->fault->value->struct) {
-            // not a proper fault
-            throw new IPF_Exception('Invalid fault structure', 500);
-        }
-
-        $structXml = $xml->fault->value->asXML();
-        $structXml = preg_replace('/<\?xml version=.*?\?>/i', '', $structXml);
-        $struct    = IPF_XmlRpc_Value::getXmlRpcValue(trim($structXml), IPF_XmlRpc_Value::XML_STRING);
-        $struct    = $struct->getValue();
-
-        if (isset($struct['faultCode'])) {
-            $code = $struct['faultCode'];
-        }
-        if (isset($struct['faultString'])) {
-            $message = $struct['faultString'];
-        }
-
-        if (empty($code) && empty($message)) {
-            throw new IPF_Exception('Fault code and string required');
-        }
-
-        if (empty($code)) {
-            $code = '404';
-        }
-
-        if (empty($message)) {
-            if (isset($this->_internal[$code])) {
-                $message = $this->_internal[$code];
-            } else {
-                $message = 'Unknown Error';
-            }
-        }
-
-        $this->setCode($code);
-        $this->setMessage($message);
-
-        return true;
-    }
-
-    public static function isFault($xml)
-    {
-        $fault = new self();
-        try {
-            $isFault = $fault->loadXml($xml);
-        } catch (IPF_Exception $e) {
-            $isFault = false;
-        }
-
-        return $isFault;
-    }
-
-    public function saveXML()
-    {
-        // Create fault value
-        $faultStruct = array(
-            'faultCode'   => $this->getCode(),
-            'faultString' => $this->getMessage()
-        );
-        $value = IPF_XmlRpc_Value::getXmlRpcValue($faultStruct);
-        $valueDOM = new DOMDocument('1.0', $this->getEncoding());
-        $valueDOM->loadXML($value->saveXML());
-
-        // Build response XML
-        $dom  = new DOMDocument('1.0', 'ISO-8859-1');
-        $r    = $dom->appendChild($dom->createElement('methodResponse'));
-        $f    = $r->appendChild($dom->createElement('fault'));
-        $f->appendChild($dom->importNode($valueDOM->documentElement, 1));
-
-        return $dom->saveXML();
-    }
-
-    public function __toString()
-    {
-        return $this->saveXML();
-    }
-}
diff --git a/ipf/xmlrpc/request.php b/ipf/xmlrpc/request.php
deleted file mode 100644 (file)
index 39c4edc..0000000
+++ /dev/null
@@ -1,257 +0,0 @@
-<?php
-
-class IPF_XmlRpc_Request
-{
-    protected $_encoding = 'UTF-8';
-    protected $_method;
-    protected $_xml;
-    protected $_params = array();
-    protected $_fault = null;
-    protected $_types = array();
-    protected $_xmlRpcParams = array();
-
-    public function __construct($method = null, $params = null)
-    {
-        if ($method !== null) {
-            $this->setMethod($method);
-        }
-
-        if ($params !== null) {
-            $this->setParams($params);
-        }
-    }
-
-    public function setEncoding($encoding)
-    {
-        $this->_encoding = $encoding;
-        return $this;
-    }
-
-    public function getEncoding()
-    {
-        return $this->_encoding;
-    }
-
-    public function setMethod($method)
-    {
-        if (!is_string($method) || !preg_match('/^[a-z0-9_.:\/]+$/i', $method)) {
-            $this->_fault = new IPF_XmlRpc_Fault(634, 'Invalid method name ("' . $method . '")');
-            $this->_fault->setEncoding($this->getEncoding());
-            return false;
-        }
-
-        $this->_method = $method;
-        return true;
-    }
-
-    public function getMethod()
-    {
-        return $this->_method;
-    }
-
-    public function addParam($value, $type = null)
-    {
-        $this->_params[] = $value;
-        if (null === $type) {
-            // Detect type if not provided explicitly
-            if ($value instanceof IPF_XmlRpc_Value) {
-                $type = $value->getType();
-            } else {
-                $xmlRpcValue = IPF_XmlRpc_Value::getXmlRpcValue($value);
-                $type        = $xmlRpcValue->getType();
-            }
-        }
-        $this->_types[]  = $type;
-        $this->_xmlRpcParams[] = array('value' => $value, 'type' => $type);
-    }
-
-    public function setParams()
-    {
-        $argc = func_num_args();
-        $argv = func_get_args();
-        if (0 == $argc) {
-            return;
-        }
-
-        if ((1 == $argc) && is_array($argv[0])) {
-            $params     = array();
-            $types      = array();
-            $wellFormed = true;
-            foreach ($argv[0] as $arg) {
-                if (!is_array($arg) || !isset($arg['value'])) {
-                    $wellFormed = false;
-                    break;
-                }
-                $params[] = $arg['value'];
-
-                if (!isset($arg['type'])) {
-                    $xmlRpcValue = IPF_XmlRpc_Value::getXmlRpcValue($arg['value']);
-                    $arg['type'] = $xmlRpcValue->getType();
-                }
-                $types[] = $arg['type'];
-            }
-            if ($wellFormed) {
-                $this->_xmlRpcParams = $argv[0];
-                $this->_params = $params;
-                $this->_types  = $types;
-            } else {
-                $this->_params = $argv[0];
-                $this->_types  = array();
-                $xmlRpcParams  = array();
-                foreach ($argv[0] as $arg) {
-                    if ($arg instanceof IPF_XmlRpc_Value) {
-                        $type = $arg->getType();
-                    } else {
-                        $xmlRpcValue = IPF_XmlRpc_Value::getXmlRpcValue($arg);
-                        $type        = $xmlRpcValue->getType();
-                    }
-                    $xmlRpcParams[] = array('value' => $arg, 'type' => $type);
-                    $this->_types[] = $type;
-                }
-                $this->_xmlRpcParams = $xmlRpcParams;
-            }
-            return;
-        }
-
-        $this->_params = $argv;
-        $this->_types  = array();
-        $xmlRpcParams  = array();
-        foreach ($argv as $arg) {
-            if ($arg instanceof IPF_XmlRpc_Value) {
-                $type = $arg->getType();
-            } else {
-                $xmlRpcValue = IPF_XmlRpc_Value::getXmlRpcValue($arg);
-                $type        = $xmlRpcValue->getType();
-            }
-            $xmlRpcParams[] = array('value' => $arg, 'type' => $type);
-            $this->_types[] = $type;
-        }
-        $this->_xmlRpcParams = $xmlRpcParams;
-    }
-
-    public function getParams()
-    {
-        return $this->_params;
-    }
-
-    public function getTypes()
-    {
-        return $this->_types;
-    }
-
-    public function loadXml($request)
-    {
-        if (!is_string($request)) {
-            $this->_fault = new IPF_XmlRpc_Fault(635);
-            $this->_fault->setEncoding($this->getEncoding());
-            return false;
-        }
-
-        try {
-            $xml = @new SimpleXMLElement($request);
-        } catch (Exception $e) {
-            // Not valid XML
-            $this->_fault = new IPF_XmlRpc_Fault(631);
-            $this->_fault->setEncoding($this->getEncoding());
-            return false;
-        }
-
-        // Check for method name
-        if (empty($xml->methodName)) {
-            // Missing method name
-            $this->_fault = new IPF_XmlRpc_Fault(632);
-            $this->_fault->setEncoding($this->getEncoding());
-            return false;
-        }
-
-        $this->_method = (string) $xml->methodName;
-
-        // Check for parameters
-        if (!empty($xml->params)) {
-            $types = array();
-            $argv  = array();
-            foreach ($xml->params->children() as $param) {
-                if (! $param->value instanceof SimpleXMLElement) {
-                    $this->_fault = new IPF_XmlRpc_Fault(633);
-                    $this->_fault->setEncoding($this->getEncoding());
-                    return false;
-                }
-
-                try {
-                    $param   = IPF_XmlRpc_Value::getXmlRpcValue($param->value, IPF_XmlRpc_Value::XML_STRING);
-                    $types[] = $param->getType();
-                    $argv[]  = $param->getValue();
-                } catch (Exception $e) {
-                    $this->_fault = new IPF_XmlRpc_Fault(636);
-                    $this->_fault->setEncoding($this->getEncoding());
-                    return false;
-                }
-            }
-
-            $this->_types  = $types;
-            $this->_params = $argv;
-        }
-
-        $this->_xml = $request;
-
-        return true;
-    }
-
-    public function isFault()
-    {
-        return $this->_fault instanceof IPF_XmlRpc_Fault;
-    }
-
-    public function getFault()
-    {
-        return $this->_fault;
-    }
-
-    protected function _getXmlRpcParams()
-    {
-        $params = array();
-        if (is_array($this->_xmlRpcParams)) {
-            foreach ($this->_xmlRpcParams as $param) {
-                $value = $param['value'];
-                $type  = isset($param['type']) ? $param['type'] : IPF_XmlRpc_Value::AUTO_DETECT_TYPE;
-
-                if (!$value instanceof IPF_XmlRpc_Value) {
-                    $value = IPF_XmlRpc_Value::getXmlRpcValue($value, $type);
-                }
-                $params[] = $value;
-            }
-        }
-
-        return $params;
-    }
-
-    public function saveXML()
-    {
-        $args   = $this->_getXmlRpcParams();
-        $method = $this->getMethod();
-
-        $dom = new DOMDocument('1.0', $this->getEncoding());
-        $mCall = $dom->appendChild($dom->createElement('methodCall'));
-        $mName = $mCall->appendChild($dom->createElement('methodName', $method));
-
-        if (is_array($args) && count($args)) {
-            $params = $mCall->appendChild($dom->createElement('params'));
-
-            foreach ($args as $arg) {
-                /* @var $arg IPF_XmlRpc_Value */
-                $argDOM = new DOMDocument('1.0', $this->getEncoding());
-                $argDOM->loadXML($arg->saveXML());
-
-                $param = $params->appendChild($dom->createElement('param'));
-                $param->appendChild($dom->importNode($argDOM->documentElement, 1));
-            }
-        }
-
-        return $dom->saveXML();
-    }
-
-    public function __toString()
-    {
-        return $this->saveXML();
-    }
-}
diff --git a/ipf/xmlrpc/request/http.php b/ipf/xmlrpc/request/http.php
deleted file mode 100644 (file)
index f66114e..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-<?php
-
-class IPF_XmlRpc_Request_Http extends IPF_XmlRpc_Request
-{
-    protected $_headers;
-    protected $_xml;
-    public function __construct()
-    {
-        $fh = fopen('php://input', 'r');
-        if (!$fh) {
-            $this->_fault = new IPF_Exception(630);
-            return;
-        }
-
-        $xml = '';
-        while (!feof($fh)) {
-            $xml .= fgets($fh);
-        }
-        fclose($fh);
-
-        $this->_xml = $xml;
-
-        $this->loadXml($xml);
-    }
-
-    public function getRawRequest()
-    {
-        return $this->_xml;
-    }
-
-    public function getHeaders()
-    {
-        if (null === $this->_headers) {
-            $this->_headers = array();
-            foreach ($_SERVER as $key => $value) {
-                if ('HTTP_' == substr($key, 0, 5)) {
-                    $header = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($key, 5)))));
-                    $this->_headers[$header] = $value;
-                }
-            }
-        }
-
-        return $this->_headers;
-    }
-
-    public function getFullRequest()
-    {
-        $request = '';
-        foreach ($this->getHeaders() as $key => $value) {
-            $request .= $key . ': ' . $value . "\n";
-        }
-
-        $request .= $this->_xml;
-
-        return $request;
-    }
-}
diff --git a/ipf/xmlrpc/request/stdin.php b/ipf/xmlrpc/request/stdin.php
deleted file mode 100644 (file)
index 0538d2b..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-<?php
-
-class IPF_XmlRpc_Request_Stdin extends IPF_XmlRpc_Request
-{
-    protected $_xml;
-
-    public function __construct()
-    {
-        $fh = fopen('php://stdin', 'r');
-        if (!$fh) {
-            $this->_fault = new IPF_XmlRpc_Fault(630);
-            return;
-        }
-
-        $xml = '';
-        while (!feof($fh)) {
-            $xml .= fgets($fh);
-        }
-        fclose($fh);
-
-        $this->_xml = $xml;
-
-        $this->loadXml($xml);
-    }
-
-    public function getRawRequest()
-    {
-        return $this->_xml;
-    }
-}
diff --git a/ipf/xmlrpc/response.php b/ipf/xmlrpc/response.php
deleted file mode 100644 (file)
index 5f2f78a..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-<?php
-
-class IPF_XmlRpc_Response
-{
-    protected $_return;
-    protected $_type;
-    protected $_encoding = 'UTF-8';
-    protected $_fault = null;
-
-    public function __construct($return = null, $type = null)
-    {
-        $this->setReturnValue($return, $type);
-    }
-
-    public function setEncoding($encoding)
-    {
-        $this->_encoding = $encoding;
-        return $this;
-    }
-
-    public function getEncoding()
-    {
-        return $this->_encoding;
-    }
-
-    public function setReturnValue($value, $type = null)
-    {
-        $this->_return = $value;
-        $this->_type = (string) $type;
-    }
-
-    public function getReturnValue()
-    {
-        return $this->_return;
-    }
-
-    protected function _getXmlRpcReturn()
-    {
-        return IPF_XmlRpc_Value::getXmlRpcValue($this->_return);
-    }
-
-    public function isFault()
-    {
-        return $this->_fault instanceof IPF_XmlRpc_Fault;
-    }
-
-    public function getFault()
-    {
-        return $this->_fault;
-    }
-
-    public function loadXml($response)
-    {
-        if (!is_string($response)) {
-            $this->_fault = new IPF_XmlRpc_Fault(650);
-            $this->_fault->setEncoding($this->getEncoding());
-            return false;
-        }
-
-        try {
-            $xml = @new SimpleXMLElement($response);
-        } catch (Exception $e) {
-            // Not valid XML
-            $this->_fault = new IPF_XmlRpc_Fault(651);
-            $this->_fault->setEncoding($this->getEncoding());
-            return false;
-        }
-
-        if (!empty($xml->fault)) {
-            // fault response
-            $this->_fault = new IPF_XmlRpc_Fault();
-            $this->_fault->setEncoding($this->getEncoding());
-            $this->_fault->loadXml($response);
-            return false;
-        }
-
-        if (empty($xml->params)) {
-            // Invalid response
-            $this->_fault = new IPF_XmlRpc_Fault(652);
-            $this->_fault->setEncoding($this->getEncoding());
-            return false;
-        }
-
-        try {
-            if (!isset($xml->params) || !isset($xml->params->param) || !isset($xml->params->param->value)) {
-                throw new IPF_Exception('Missing XML-RPC value in XML');
-            }
-            $valueXml = $xml->params->param->value->asXML();
-            $valueXml = preg_replace('/<\?xml version=.*?\?>/i', '', $valueXml);
-            $value = IPF_XmlRpc_Value::getXmlRpcValue(trim($valueXml), IPF_XmlRpc_Value::XML_STRING);
-        } catch (IPF_Exception $e) {
-            $this->_fault = new IPF_XmlRpc_Fault(653);
-            $this->_fault->setEncoding($this->getEncoding());
-            return false;
-        }
-
-        $this->setReturnValue($value->getValue());
-        return true;
-    }
-
-    public function saveXML()
-    {
-        $value = $this->_getXmlRpcReturn();
-        $valueDOM = new DOMDocument('1.0', $this->getEncoding());
-        $valueDOM->loadXML($value->saveXML());
-
-        $dom      = new DOMDocument('1.0', $this->getEncoding());
-        $response = $dom->appendChild($dom->createElement('methodResponse'));
-        $params   = $response->appendChild($dom->createElement('params'));
-        $param    = $params->appendChild($dom->createElement('param'));
-
-        $param->appendChild($dom->importNode($valueDOM->documentElement, true));
-
-        return $dom->saveXML();
-    }
-
-    public function __toString()
-    {
-        return $this->saveXML();
-    }
-}
diff --git a/ipf/xmlrpc/response/http.php b/ipf/xmlrpc/response/http.php
deleted file mode 100644 (file)
index fa767b5..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-<?php
-
-class IPF_XmlRpc_Response_Http extends IPF_XmlRpc_Response
-{
-    public function __toString()
-    {
-        if (!headers_sent()) {
-            header('Content-Type: text/xml; charset=' . strtolower($this->getEncoding()));
-        }
-        return parent::__toString();
-    }
-}
diff --git a/ipf/xmlrpc/server.php b/ipf/xmlrpc/server.php
deleted file mode 100644 (file)
index a3a5a3a..0000000
+++ /dev/null
@@ -1,428 +0,0 @@
-<?php
-
-class IPF_XmlRpc_Server
-{
-    protected $_encoding = 'UTF-8';
-    protected $_methods = array();
-    protected $_request = null;
-    protected $_responseClass = 'IPF_XmlRpc_Response_Http';
-
-    protected $_table = array();
-
-    protected $_typeMap = array(
-        'i4'               => 'i4',
-        'int'              => 'int',
-        'integer'          => 'int',
-        'double'           => 'double',
-        'float'            => 'double',
-        'real'             => 'double',
-        'boolean'          => 'boolean',
-        'bool'             => 'boolean',
-        'true'             => 'boolean',
-        'false'            => 'boolean',
-        'string'           => 'string',
-        'str'              => 'string',
-        'base64'           => 'base64',
-        'dateTime.iso8601' => 'dateTime.iso8601',
-        'date'             => 'dateTime.iso8601',
-        'time'             => 'dateTime.iso8601',
-        'time'             => 'dateTime.iso8601',
-        'array'            => 'array',
-        'struct'           => 'struct',
-        'null'             => 'nil',
-        'nil'              => 'nil',
-        'void'             => 'void',
-        'mixed'            => 'struct'
-    );
-
-    public function __construct()
-    {
-        // Setup system.* methods
-        $system = array(
-            'listMethods',
-            'methodHelp',
-            'methodSignature',
-            'multicall'
-        );
-
-        $class = IPF_Server_Reflection::reflectClass($this);
-        foreach ($system as $method) {
-            $reflection = new IPF_Server_Reflection_Method($class, new ReflectionMethod($this, $method), 'system');
-            $reflection->system = true;
-            $this->_methods[] = $reflection;
-        }
-
-        $this->_buildDispatchTable();
-    }
-
-    protected function _fixTypes(IPF_Server_Reflection_Function_Abstract $method)
-    {
-        foreach ($method->getPrototypes() as $prototype) {
-            foreach ($prototype->getParameters() as $param) {
-                $pType = $param->getType();
-                if (isset($this->_typeMap[$pType])) {
-                    $param->setType($this->_typeMap[$pType]);
-                } else {
-                    $param->setType('void');
-                }
-            }
-        }
-    }
-
-    protected function _buildDispatchTable()
-    {
-        $table      = array();
-        foreach ($this->_methods as $dispatchable) {
-            if ($dispatchable instanceof IPF_Server_Reflection_Function_Abstract) {
-                // function/method call
-                $ns   = $dispatchable->getNamespace();
-                $name = $dispatchable->getName();
-                $name = empty($ns) ? $name : $ns . '.' . $name;
-
-                if (isset($table[$name])) {
-                    throw new IPF_Exception('Duplicate method registered: ' . $name);
-                }
-                $table[$name] = $dispatchable;
-                $this->_fixTypes($dispatchable);
-
-                continue;
-            }
-
-            if ($dispatchable instanceof IPF_Server_Reflection_Class) {
-                foreach ($dispatchable->getMethods() as $method) {
-                    $ns   = $method->getNamespace();
-                    $name = $method->getName();
-                    $name = empty($ns) ? $name : $ns . '.' . $name;
-
-                    if (isset($table[$name])) {
-                        throw new IPF_Exception('Duplicate method registered: ' . $name);
-                    }
-                    $table[$name] = $method;
-                    $this->_fixTypes($method);
-                    continue;
-                }
-            }
-        }
-
-        $this->_table = $table;
-    }
-
-    public function setEncoding($encoding)
-    {
-        $this->_encoding = $encoding;
-        return $this;
-    }
-
-    public function getEncoding()
-    {
-        return $this->_encoding;
-    }
-
-    public function addFunction($function, $namespace = '')
-    {
-        if (!is_string($function) && !is_array($function)) {
-            throw new IPF_Exception('Unable to attach function; invalid', 611);
-        }
-
-        $argv = null;
-        if (2 < func_num_args()) {
-            $argv = func_get_args();
-            $argv = array_slice($argv, 2);
-        }
-
-        $function = (array) $function;
-        foreach ($function as $func) {
-            if (!is_string($func) || !function_exists($func)) {
-                throw new IPF_Exception('Unable to attach function; invalid', 611);
-            }
-            $this->_methods[] = IPF_Server_Reflection::reflectFunction($func, $argv, $namespace);
-        }
-
-        $this->_buildDispatchTable();
-    }
-
-    public function loadFunctions($array)
-    {
-        if (!is_array($array)) {
-            throw new IPF_Exception('Unable to load array; not an array', 612);
-        }
-
-        foreach ($array as $key => $value) {
-            if (!$value instanceof IPF_Server_Reflection_Function_Abstract
-                && !$value instanceof IPF_Server_Reflection_Class)
-            {
-                throw new IPF_Exception('One or more method records are corrupt or otherwise unusable', 613);
-            }
-
-            if ($value->system) {
-                unset($array[$key]);
-            }
-        }
-
-        foreach ($array as $dispatchable) {
-            $this->_methods[] = $dispatchable;
-        }
-
-        $this->_buildDispatchTable();
-    }
-
-    public function setPersistence($class = null)
-    {
-    }
-
-    public function setClass($class, $namespace = '', $argv = null)
-    {
-        if (is_string($class) && !class_exists($class)) {
-            if (!class_exists($class)) {
-                throw new IPF_Exception('Invalid method class', 610);
-            }
-        }
-
-        $argv = null;
-        if (3 < func_num_args()) {
-            $argv = func_get_args();
-            $argv = array_slice($argv, 3);
-        }
-
-        $this->_methods[] = IPF_Reflection::reflectClass($class, $argv, $namespace);
-        $this->_buildDispatchTable();
-    }
-
-    public function setRequest($request)
-    {
-        if (is_string($request) && class_exists($request)) {
-            $request = new $request();
-            if (!$request instanceof IPF_XmlRpc_Request) {
-                throw new IPF_Exception('Invalid request class');
-            }
-            $request->setEncoding($this->getEncoding());
-        } elseif (!$request instanceof IPF_XmlRpc_Request) {
-            throw new IPF_Exception('Invalid request object');
-        }
-
-        $this->_request = $request;
-        return $this;
-    }
-
-    public function getRequest()
-    {
-        return $this->_request;
-    }
-
-    public function fault($fault, $code = 404)
-    {
-        if (!$fault instanceof Exception) {
-            $fault = (string) $fault;
-            $fault = new IPF_Exception($fault, $code);
-        }
-        return IPF_XmlRpc_Server_Fault::getInstance($fault);
-    }
-
-    protected function _handle(IPF_XmlRpc_Request $request)
-    {
-        $method = $request->getMethod();
-
-        // Check for valid method
-        if (!isset($this->_table[$method])) {
-            throw new IPF_Exception('Method "' . $method . '" does not exist', 620);
-        }
-
-        $info     = $this->_table[$method];
-        $params   = $request->getParams();
-        $argv     = $info->getInvokeArguments();
-        if (0 < count($argv)) {
-            $params = array_merge($params, $argv);
-        }
-
-        // Check calling parameters against signatures
-        $matched    = false;
-        $sigCalled  = $request->getTypes();
-
-        $sigLength  = count($sigCalled);
-        $paramsLen  = count($params);
-        if ($sigLength < $paramsLen) {
-            for ($i = $sigLength; $i < $paramsLen; ++$i) {
-                $xmlRpcValue = IPF_XmlRpc_Value::getXmlRpcValue($params[$i]);
-                $sigCalled[] = $xmlRpcValue->getType();
-            }
-        }
-
-        $signatures = $info->getPrototypes();
-        foreach ($signatures as $signature) {
-            $sigParams = $signature->getParameters();
-            $tmpParams = array();
-            foreach ($sigParams as $param) {
-                $tmpParams[] = $param->getType();
-            }
-            if ($sigCalled === $tmpParams) {
-                $matched = true;
-                break;
-            }
-        }
-        if (!$matched) {
-            throw new IPF_Exception('Calling parameters do not match signature', 623);
-        }
-
-        if ($info instanceof IPF_Server_Reflection_Function) {
-            $func = $info->getName();
-            $return = call_user_func_array($func, $params);
-        } elseif (($info instanceof IPF_Server_Reflection_Method) && $info->system) {
-            // System methods
-            $return = $info->invokeArgs($this, $params);
-        } elseif ($info instanceof IPF_Server_Reflection_Method) {
-            // Get class
-            $class = $info->getDeclaringClass()->getName();
-
-            if ('static' == $info->isStatic()) {
-                // for some reason, invokeArgs() does not work the same as
-                // invoke(), and expects the first argument to be an object.
-                // So, using a callback if the method is static.
-                $return = call_user_func_array(array($class, $info->getName()), $params);
-            } else {
-                // Object methods
-                try {
-                    $object = $info->getDeclaringClass()->newInstance();
-                } catch (Exception $e) {
-                    throw new IPF_Exception('Error instantiating class ' . $class . ' to invoke method ' . $info->getName(), 621);
-                }
-
-                $return = $info->invokeArgs($object, $params);
-            }
-        } else {
-            throw new IPF_Exception('Method missing implementation ' . get_class($info), 622);
-        }
-
-        $response = new ReflectionClass($this->_responseClass);
-        return $response->newInstance($return);
-    }
-
-    public function handle(IPF_XmlRpc_Request $request = null)
-    {
-        // Get request
-        if ((null === $request) && (null === ($request = $this->getRequest()))) {
-            $request = new IPF_XmlRpc_Request_Http();
-            $request->setEncoding($this->getEncoding());
-        }
-
-        $this->setRequest($request);
-
-        if ($request->isFault()) {
-            $response = $request->getFault();
-        } else {
-            try {
-                $response = $this->_handle($request);
-            } catch (Exception $e) {
-                $response = $this->fault($e);
-            }
-        }
-
-        // Set output encoding
-        $response->setEncoding($this->getEncoding());
-
-        return $response;
-    }
-
-    public function setResponseClass($class)
-    {
-        if (class_exists($class)) {
-            $reflection = new ReflectionClass($class);
-            if ($reflection->isSubclassOf(new ReflectionClass('IPF_XmlRpc_Response'))) {
-                $this->_responseClass = $class;
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    public function getFunctions()
-    {
-        $return = array();
-        foreach ($this->_methods as $method) {
-            if ($method instanceof IPF_Server_Reflection_Class
-                && ($method->system))
-            {
-                continue;
-            }
-
-            $return[] = $method;
-        }
-
-        return $return;
-    }
-
-    public function listMethods()
-    {
-        return array_keys($this->_table);
-    }
-
-    public function methodHelp($method)
-    {
-        if (!isset($this->_table[$method])) {
-            throw new IPF_Exception('Method "' . $method . '"does not exist', 640);
-        }
-
-        return $this->_table[$method]->getDescription();
-    }
-
-    public function methodSignature($method)
-    {
-        if (!isset($this->_table[$method])) {
-            throw new IPF_Exception('Method "' . $method . '"does not exist', 640);
-        }
-        $prototypes = $this->_table[$method]->getPrototypes();
-
-        $signatures = array();
-        foreach ($prototypes as $prototype) {
-            $signature = array($prototype->getReturnType());
-            foreach ($prototype->getParameters() as $parameter) {
-                $signature[] = $parameter->getType();
-            }
-            $signatures[] = $signature;
-        }
-
-        return $signatures;
-    }
-
-    public function multicall($methods)
-    {
-        $responses = array();
-        foreach ($methods as $method) {
-            $fault = false;
-            if (!is_array($method)) {
-                $fault = $this->fault('system.multicall expects each method to be a struct', 601);
-            } elseif (!isset($method['methodName'])) {
-                $fault = $this->fault('Missing methodName', 602);
-            } elseif (!isset($method['params'])) {
-                $fault = $this->fault('Missing params', 603);
-            } elseif (!is_array($method['params'])) {
-                $fault = $this->fault('Params must be an array', 604);
-            } else {
-                if ('system.multicall' == $method['methodName']) {
-                    // don't allow recursive calls to multicall
-                    $fault = $this->fault('Recursive system.multicall forbidden', 605);
-                }
-            }
-
-            if (!$fault) {
-                try {
-                    $request = new IPF_XmlRpc_Request();
-                    $request->setMethod($method['methodName']);
-                    $request->setParams($method['params']);
-                    $response = $this->_handle($request);
-                    $responses[] = $response->getReturnValue();
-                } catch (Exception $e) {
-                    $fault = $this->fault($e);
-                }
-            }
-
-            if ($fault) {
-                $responses[] = array(
-                    'faultCode'   => $fault->getCode(),
-                    'faultString' => $fault->getMessage()
-                );
-            }
-        }
-        return $responses;
-    }
-}
diff --git a/ipf/xmlrpc/server/cache.php b/ipf/xmlrpc/server/cache.php
deleted file mode 100644 (file)
index aa6c7e7..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-<?php
-
-class IPF_XmlRpc_Server_Cache
-{
-    public static function save($filename, IPF_XmlRpc_Server $server)
-    {
-        if (!is_string($filename)
-            || (!file_exists($filename) && !is_writable(dirname($filename))))
-        {
-            return false;
-        }
-
-        // Remove system.* methods
-        $methods = $server->getFunctions();
-        foreach ($methods as $name => $method) {
-            if ($method->system) {
-                unset($methods[$name]);
-            }
-        }
-
-        // Store
-        if (0 === @file_put_contents($filename, serialize($methods))) {
-            return false;
-        }
-
-        return true;
-    }
-
-    public static function get($filename, IPF_XmlRpc_Server $server)
-    {
-        if (!is_string($filename)
-            || !file_exists($filename)
-            || !is_readable($filename))
-        {
-            return false;
-        }
-
-        if (false === ($dispatch = @file_get_contents($filename))) {
-            return false;
-        }
-
-        if (false === ($dispatchArray = @unserialize($dispatch))) {
-            return false;
-        }
-
-        $server->loadFunctions($dispatchArray);
-
-        return true;
-    }
-
-    public static function delete($filename)
-    {
-        if (is_string($filename) && file_exists($filename)) {
-            unlink($filename);
-            return true;
-        }
-
-        return false;
-    }
-}
diff --git a/ipf/xmlrpc/server/fault.php b/ipf/xmlrpc/server/fault.php
deleted file mode 100644 (file)
index 50db5ed..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-<?php
-
-class IPF_XmlRpc_Server_Fault extends IPF_XmlRpc_Fault
-{
-    protected $_exception;
-    protected static $_faultExceptionClasses = array('IPF_Exception' => true);
-    protected static $_observers = array();
-
-    public function __construct(Exception $e)
-    {
-        $this->_exception = $e;
-        $code             = 404;
-        $message          = 'Unknown error';
-        $exceptionClass   = get_class($e);
-
-        foreach (array_keys(self::$_faultExceptionClasses) as $class) {
-            if ($e instanceof $class) {
-                $code    = $e->getCode();
-                $message = $e->getMessage();
-                break;
-            }
-        }
-
-        parent::__construct($code, $message);
-
-        // Notify exception observers, if present
-        if (!empty(self::$_observers)) {
-            foreach (array_keys(self::$_observers) as $observer) {
-                call_user_func(array($observer, 'observe'), $this);
-            }
-        }
-    }
-
-    public static function getInstance(Exception $e)
-    {
-        return new self($e);
-    }
-
-    public static function attachFaultException($classes)
-    {
-        if (!is_array($classes)) {
-            $classes = (array) $classes;
-        }
-
-        foreach ($classes as $class) {
-            if (is_string($class) && class_exists($class)) {
-                self::$_faultExceptionClasses[$class] = true;
-            }
-        }
-    }
-
-    public static function detachFaultException($classes)
-    {
-        if (!is_array($classes)) {
-            $classes = (array) $classes;
-        }
-
-        foreach ($classes as $class) {
-            if (is_string($class) && isset(self::$_faultExceptionClasses[$class])) {
-                unset(self::$_faultExceptionClasses[$class]);
-            }
-        }
-    }
-
-    public static function attachObserver($class)
-    {
-        if (!is_string($class)
-            || !class_exists($class)
-            || !is_callable(array($class, 'observe')))
-        {
-            return false;
-        }
-
-        if (!isset(self::$_observers[$class])) {
-            self::$_observers[$class] = true;
-        }
-
-        return true;
-    }
-
-    public static function detachObserver($class)
-    {
-        if (!isset(self::$_observers[$class])) {
-            return false;
-        }
-
-        unset(self::$_observers[$class]);
-        return true;
-    }
-
-    public function getException()
-    {
-        return $this->_exception;
-    }
-}
diff --git a/ipf/xmlrpc/value.php b/ipf/xmlrpc/value.php
deleted file mode 100644 (file)
index 5201bed..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-<?php
-
-abstract class IPF_XmlRpc_Value
-{
-    protected $_value;
-    protected $_type;
-    protected $_as_xml;
-    protected $_as_dom;
-
-    const AUTO_DETECT_TYPE = 'auto_detect';
-    const XML_STRING = 'xml';
-
-    const XMLRPC_TYPE_I4       = 'i4';
-    const XMLRPC_TYPE_INTEGER  = 'int';
-    const XMLRPC_TYPE_DOUBLE   = 'double';
-    const XMLRPC_TYPE_BOOLEAN  = 'boolean';
-    const XMLRPC_TYPE_STRING   = 'string';
-    const XMLRPC_TYPE_DATETIME = 'dateTime.iso8601';
-    const XMLRPC_TYPE_BASE64   = 'base64';
-    const XMLRPC_TYPE_ARRAY    = 'array';
-    const XMLRPC_TYPE_STRUCT   = 'struct';
-    const XMLRPC_TYPE_NIL      = 'nil';
-
-    public function getType()
-    {
-        return $this->_type;
-    }
-
-    abstract public function getValue();
-    abstract public function saveXML();
-
-    public function getAsDOM()
-    {
-        if (!$this->_as_dom) {
-            $doc = new DOMDocument('1.0');
-            $doc->loadXML($this->saveXML());
-            $this->_as_dom = $doc->documentElement;
-        }
-
-        return $this->_as_dom;
-    }
-
-    protected function _stripXmlDeclaration(DOMDocument $dom)
-    {
-        return preg_replace('/<\?xml version="1.0"( encoding="[^\"]*")?\?>\n/u', '', $dom->saveXML());
-    }
-
-    public static function getXmlRpcValue($value, $type = self::AUTO_DETECT_TYPE)
-    {
-        switch ($type) {
-            case self::AUTO_DETECT_TYPE:
-                // Auto detect the XML-RPC native type from the PHP type of $value
-                return self::_phpVarToNativeXmlRpc($value);
-
-            case self::XML_STRING:
-                // Parse the XML string given in $value and get the XML-RPC value in it
-                return self::_xmlStringToNativeXmlRpc($value);
-
-            case self::XMLRPC_TYPE_I4:
-                // fall through to the next case
-            case self::XMLRPC_TYPE_INTEGER:
-                return new IPF_XmlRpc_Value_Integer($value);
-
-            case self::XMLRPC_TYPE_DOUBLE:
-                return new IPF_XmlRpc_Value_Double($value);
-
-            case self::XMLRPC_TYPE_BOOLEAN:
-                return new IPF_XmlRpc_Value_Boolean($value);
-
-            case self::XMLRPC_TYPE_STRING:
-                return new IPF_XmlRpc_Value_String($value);
-
-            case self::XMLRPC_TYPE_BASE64:
-                return new IPF_XmlRpc_Value_Base64($value);
-
-            case self::XMLRPC_TYPE_NIL:
-                return new IPF_XmlRpc_Value_Nil();
-
-            case self::XMLRPC_TYPE_DATETIME:
-                return new IPF_XmlRpc_Value_DateTime($value);
-
-            case self::XMLRPC_TYPE_ARRAY:
-                return new IPF_XmlRpc_Value_Array($value);
-
-            case self::XMLRPC_TYPE_STRUCT:
-                return new IPF_XmlRpc_Value_Struct($value);
-
-            default:
-                throw new IPF_Exception('Given type is not a '. __CLASS__ .' constant');
-        }
-    }
-
-    private static function _phpVarToNativeXmlRpc($value)
-    {
-        switch (gettype($value)) {
-            case 'object':
-                // Check to see if it's an XmlRpc value
-                if ($value instanceof IPF_XmlRpc_Value) {
-                    return $value;
-                }
-                
-                // Otherwise, we convert the object into a struct
-                $value = get_object_vars($value);
-                // Break intentionally omitted
-            case 'array':
-                // Default native type for a PHP array (a simple numeric array) is 'array'
-                $obj = 'IPF_XmlRpc_Value_Array';
-
-                // Determine if this is an associative array
-                if (!empty($value) && is_array($value) && (array_keys($value) !== range(0, count($value) - 1))) {
-                    $obj = 'IPF_XmlRpc_Value_Struct';
-                }
-                return new $obj($value);
-
-            case 'integer':
-                return new IPF_XmlRpc_Value_Integer($value);
-
-            case 'double':
-                return new IPF_XmlRpc_Value_Double($value);
-
-            case 'boolean':
-                return new IPF_XmlRpc_Value_Boolean($value);
-
-            case 'NULL':
-            case 'null':
-                return new IPF_XmlRpc_Value_Nil();
-
-            case 'string':
-                // Fall through to the next case
-            default:
-                // If type isn't identified (or identified as string), it treated as string
-                return new IPF_XmlRpc_Value_String($value);
-        }
-    }
-
-    private static function _xmlStringToNativeXmlRpc($simple_xml)
-    {
-        if (!$simple_xml instanceof SimpleXMLElement) {
-            try {
-                $simple_xml = @new SimpleXMLElement($simple_xml);
-            } catch (Exception $e) {
-                // The given string is not a valid XML
-                throw new IPF_Exception('Failed to create XML-RPC value from XML string: '.$e->getMessage(),$e->getCode());
-            }
-        }
-
-        // Get the key (tag name) and value from the simple xml object and convert the value to an XML-RPC native value
-        list($type, $value) = each($simple_xml);
-        if (!$type) {    // If no type was specified, the default is string
-            $type = self::XMLRPC_TYPE_STRING;
-        }
-
-        switch ($type) {
-            // All valid and known XML-RPC native values
-            case self::XMLRPC_TYPE_I4:
-                // Fall through to the next case
-            case self::XMLRPC_TYPE_INTEGER:
-                $xmlrpc_val = new IPF_XmlRpc_Value_Integer($value);
-                break;
-            case self::XMLRPC_TYPE_DOUBLE:
-                $xmlrpc_val = new IPF_XmlRpc_Value_Double($value);
-                break;
-            case self::XMLRPC_TYPE_BOOLEAN:
-                $xmlrpc_val = new IPF_XmlRpc_Value_Boolean($value);
-                break;
-            case self::XMLRPC_TYPE_STRING:
-                $xmlrpc_val = new IPF_XmlRpc_Value_String($value);
-                break;
-            case self::XMLRPC_TYPE_DATETIME:  // The value should already be in a iso8601 format
-                $xmlrpc_val = new IPF_XmlRpc_Value_DateTime($value);
-                break;
-            case self::XMLRPC_TYPE_BASE64:    // The value should already be base64 encoded
-                $xmlrpc_val = new IPF_XmlRpc_Value_Base64($value ,true);
-                break;
-            case self::XMLRPC_TYPE_NIL:    // The value should always be NULL
-                $xmlrpc_val = new IPF_XmlRpc_Value_Nil();
-                break;
-            case self::XMLRPC_TYPE_ARRAY:
-                // If the XML is valid, $value must be an SimpleXML element and contain the <data> tag
-                if (!$value instanceof SimpleXMLElement) {
-                    throw new IPF_Exception('XML string is invalid for XML-RPC native '. self::XMLRPC_TYPE_ARRAY .' type');
-                } 
-
-                // PHP 5.2.4 introduced a regression in how empty($xml->value) 
-                // returns; need to look for the item specifically
-                $data = null;
-                foreach ($value->children() as $key => $value) {
-                    if ('data' == $key) {
-                        $data = $value;
-                        break;
-                    }
-                }
-                
-                if (null === $data) {
-                    throw new IPF_Exception('Invalid XML for XML-RPC native '. self::XMLRPC_TYPE_ARRAY .' type: ARRAY tag must contain DATA tag');
-                }
-                $values = array();
-                // Parse all the elements of the array from the XML string
-                // (simple xml element) to IPF_XmlRpc_Value objects
-                foreach ($data->value as $element) {
-                    $values[] = self::_xmlStringToNativeXmlRpc($element);
-                }
-                $xmlrpc_val = new IPF_XmlRpc_Value_Array($values);
-                break;
-            case self::XMLRPC_TYPE_STRUCT:
-                // If the XML is valid, $value must be an SimpleXML
-                if ((!$value instanceof SimpleXMLElement)) {
-                    throw new IPF_Exception('XML string is invalid for XML-RPC native '. self::XMLRPC_TYPE_STRUCT .' type');
-                }
-                $values = array();
-                // Parse all the memebers of the struct from the XML string
-                // (simple xml element) to IPF_XmlRpc_Value objects
-                foreach ($value->member as $member) {
-                    // @todo? If a member doesn't have a <value> tag, we don't add it to the struct
-                    // Maybe we want to throw an exception here ?
-                    if ((!$member->value instanceof SimpleXMLElement) || empty($member->value)) {
-                        continue;
-                        //throw new IPF_XmlRpc_Value_Exception('Member of the '. self::XMLRPC_TYPE_STRUCT .' XML-RPC native type must contain a VALUE tag');
-                    }
-                    $values[(string)$member->name] = self::_xmlStringToNativeXmlRpc($member->value);
-                }
-                $xmlrpc_val = new IPF_XmlRpc_Value_Struct($values);
-                break;
-            default:
-                throw new IPF_Exception('Value type \''. $type .'\' parsed from the XML string is not a known XML-RPC native type');
-                break;
-        }
-        $xmlrpc_val->_setXML($simple_xml->asXML());
-
-        return $xmlrpc_val;
-    }
-
-    private function _setXML($xml)
-    {
-        $this->_as_xml = $xml;
-    }
-
-}
-
-
diff --git a/ipf/xmlrpc/value/array.php b/ipf/xmlrpc/value/array.php
deleted file mode 100644 (file)
index ead3419..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-<?php
-
-class IPF_XmlRpc_Value_Array extends IPF_XmlRpc_Value_Collection
-{
-    public function __construct($value)
-    {
-        $this->_type = self::XMLRPC_TYPE_ARRAY;
-        parent::__construct($value);
-    }
-
-    public function saveXML()
-    {
-        if (!$this->_as_xml) {   // The XML code was not calculated yet
-            $dom   = new DOMDocument('1.0');
-            $value = $dom->appendChild($dom->createElement('value'));
-            $array = $value->appendChild($dom->createElement('array'));
-            $data  = $array->appendChild($dom->createElement('data'));
-
-            if (is_array($this->_value)) {
-                foreach ($this->_value as $val) {
-                    /* @var $val IPF_XmlRpc_Value */
-                    $data->appendChild($dom->importNode($val->getAsDOM(), true));
-                }
-            }
-
-            $this->_as_dom = $value;
-            $this->_as_xml = $this->_stripXmlDeclaration($dom);
-        }
-
-        return $this->_as_xml;
-    }
-}
-
diff --git a/ipf/xmlrpc/value/base64.php b/ipf/xmlrpc/value/base64.php
deleted file mode 100644 (file)
index 0583f9f..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-<?php
-
-class IPF_XmlRpc_Value_Base64 extends IPF_XmlRpc_Value_Scalar
-{
-    public function __construct($value, $already_encoded=false)
-    {
-        $this->_type = self::XMLRPC_TYPE_BASE64;
-
-        $value = (string)$value;    // Make sure this value is string
-        if (!$already_encoded) {
-            $value = base64_encode($value);     // We encode it in base64
-        }
-        $this->_value = $value;
-    }
-
-    public function getValue()
-    {
-        return base64_decode($this->_value);
-    }
-
-    public function saveXML()
-    {
-        if (! $this->_as_xml) {   // The XML was not generated yet
-            $dom   = new DOMDocument('1.0', 'UTF-8');
-            $value = $dom->appendChild($dom->createElement('value'));
-            $type  = $value->appendChild($dom->createElement($this->_type));
-            $type->appendChild($dom->createTextNode($this->_value));
-
-            $this->_as_dom = $value;
-            $this->_as_xml = $this->_stripXmlDeclaration($dom);
-        }
-
-        return $this->_as_xml;
-    }
-}
-
diff --git a/ipf/xmlrpc/value/boolean.php b/ipf/xmlrpc/value/boolean.php
deleted file mode 100644 (file)
index c0cf52c..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-<?php
-
-class IPF_XmlRpc_Value_Boolean extends IPF_XmlRpc_Value_Scalar
-{
-    public function __construct($value)
-    {
-        $this->_type = self::XMLRPC_TYPE_BOOLEAN;
-        $this->_value = (int)(bool)$value;
-    }
-
-    public function getValue()
-    {
-        return (bool)$this->_value;
-    }
-
-    public function saveXML()
-    {
-        if (! $this->_as_xml) {   // The XML was not generated yet
-            $dom   = new DOMDocument('1.0', 'UTF-8');
-            $value = $dom->appendChild($dom->createElement('value'));
-            $type  = $value->appendChild($dom->createElement($this->_type));
-            $type->appendChild($dom->createTextNode($this->_value));
-
-            $this->_as_dom = $value;
-            $this->_as_xml = $this->_stripXmlDeclaration($dom);
-        }
-
-        return $this->_as_xml;
-    }
-}
-
diff --git a/ipf/xmlrpc/value/collection.php b/ipf/xmlrpc/value/collection.php
deleted file mode 100644 (file)
index a720f10..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-<?php
-
-abstract class IPF_XmlRpc_Value_Collection extends IPF_XmlRpc_Value
-{
-    public function __construct($value)
-    {
-        $values = (array)$value;   // Make sure that the value is an array
-        foreach ($values as $key => $value) {
-            // If the elements of the given array are not IPF_XmlRpc_Value objects,
-            // we need to convert them as such (using auto-detection from PHP value)
-            if (!$value instanceof parent) {
-                $value = self::getXmlRpcValue($value, self::AUTO_DETECT_TYPE);
-            }
-            $this->_value[$key] = $value;
-        }
-    }
-
-    public function getValue()
-    {
-        $values = (array)$this->_value;
-        foreach ($values as $key => $value) {
-            /* @var $value IPF_XmlRpc_Value */
-            if (!$value instanceof parent) {
-                throw new IPF_Exception('Values of '. get_class($this) .' type must be IPF_XmlRpc_Value objects');
-            }
-            $values[$key] = $value->getValue();
-        }
-        return $values;
-    }
-
-}
-
diff --git a/ipf/xmlrpc/value/datetime.php b/ipf/xmlrpc/value/datetime.php
deleted file mode 100644 (file)
index 569cd75..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-<?php
-
-class IPF_XmlRpc_Value_DateTime extends IPF_XmlRpc_Value_Scalar
-{
-    public function __construct($value)
-    {
-        $this->_type = self::XMLRPC_TYPE_DATETIME;
-
-        // If the value is not numeric, we try to convert it to a timestamp (using the strtotime function)
-        if (is_numeric($value)) {   // The value is numeric, we make sure it is an integer
-            $value = (int)$value;
-        } else {
-            $value = strtotime($value);
-            if ($value === false || $value == -1) { // cannot convert the value to a timestamp
-                throw new IPF_Exception('Cannot convert given value \''. $value .'\' to a timestamp');
-            }
-        }
-        $value = date('c', $value); // Convert the timestamp to iso8601 format
-
-        // Strip out TZ information and dashes
-        $value = preg_replace('/(\+|-)\d{2}:\d{2}$/', '', $value);
-        $value = str_replace('-', '', $value);
-
-        $this->_value = $value;
-    }
-
-    public function getValue()
-    {
-        return $this->_value;
-    }
-
-}
-
diff --git a/ipf/xmlrpc/value/double.php b/ipf/xmlrpc/value/double.php
deleted file mode 100644 (file)
index e0a8536..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-<?php
-
-class IPF_XmlRpc_Value_Double extends IPF_XmlRpc_Value_Scalar
-{
-    public function __construct($value)
-    {
-        $this->_type = self::XMLRPC_TYPE_DOUBLE;
-        $this->_value = sprintf('%f',(float)$value);    // Make sure this value is float (double) and without the scientific notation
-    }
-
-    public function getValue()
-    {
-        return (float)$this->_value;
-    }
-
-}
-
diff --git a/ipf/xmlrpc/value/integer.php b/ipf/xmlrpc/value/integer.php
deleted file mode 100644 (file)
index 5de4c8d..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-<?php
-
-class IPF_XmlRpc_Value_Integer extends IPF_XmlRpc_Value_Scalar
-{
-    public function __construct($value)
-    {
-        $this->_type = self::XMLRPC_TYPE_INTEGER;
-        $this->_value = (int)$value;    // Make sure this value is integer
-    }
-
-    public function getValue()
-    {
-        return $this->_value;
-    }
-
-}
-
diff --git a/ipf/xmlrpc/value/nil.php b/ipf/xmlrpc/value/nil.php
deleted file mode 100644 (file)
index e04c670..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-<?php
-
-class IPF_XmlRpc_Value_Nil extends IPF_XmlRpc_Value_Scalar
-{
-    public function __construct()
-    {
-        $this->_type = self::XMLRPC_TYPE_NIL;
-        $this->_value = null;
-    }
-
-    public function getValue()
-    {
-        return null;
-    }
-
-    public function saveXML()
-    {
-        if (! $this->_as_xml) {   // The XML was not generated yet
-            $dom   = new DOMDocument('1.0', 'UTF-8');
-            $value = $dom->appendChild($dom->createElement('value'));
-            $type  = $value->appendChild($dom->createElement($this->_type));
-
-            $this->_as_dom = $value;
-            $this->_as_xml = $this->_stripXmlDeclaration($dom);
-        }
-
-        return $this->_as_xml;
-    }
-}
-
diff --git a/ipf/xmlrpc/value/scalar.php b/ipf/xmlrpc/value/scalar.php
deleted file mode 100644 (file)
index a950fb5..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-<?php
-
-abstract class IPF_XmlRpc_Value_Scalar extends IPF_XmlRpc_Value
-{
-    public function saveXML()
-    {
-        if (!$this->_as_xml) {   // The XML code was not calculated yet
-            $dom   = new DOMDocument('1.0');
-            $value = $dom->appendChild($dom->createElement('value'));
-            $type  = $value->appendChild($dom->createElement($this->_type));
-            $type->appendChild($dom->createTextNode($this->getValue()));
-
-            $this->_as_dom = $value;
-            $this->_as_xml = $this->_stripXmlDeclaration($dom);
-        }
-
-        return $this->_as_xml;
-    }
-}
-
diff --git a/ipf/xmlrpc/value/string.php b/ipf/xmlrpc/value/string.php
deleted file mode 100644 (file)
index 635293a..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-<?php
-
-class IPF_XmlRpc_Value_String extends IPF_XmlRpc_Value_Scalar
-{
-    public function __construct($value)
-    {
-        $this->_type = self::XMLRPC_TYPE_STRING;
-
-        // Make sure this value is string and all XML characters are encoded
-        $this->_value = $this->_xml_entities($value);
-    }
-
-    public function getValue()
-    {
-        return html_entity_decode($this->_value, ENT_QUOTES, 'UTF-8');
-    }
-
-    private function _xml_entities($str)
-    {
-        return htmlentities($str, ENT_QUOTES, 'UTF-8');
-    }
-
-}
-
diff --git a/ipf/xmlrpc/value/struct.php b/ipf/xmlrpc/value/struct.php
deleted file mode 100644 (file)
index f6ed6ce..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-
-class IPF_XmlRpc_Value_Struct extends IPF_XmlRpc_Value_Collection
-{
-    public function __construct($value)
-    {
-        $this->_type = self::XMLRPC_TYPE_STRUCT;
-        parent::__construct($value);
-    }
-
-    public function saveXML()
-    {
-        if (!$this->_as_xml) {   // The XML code was not calculated yet
-            $dom    = new DOMDocument('1.0');
-            $value  = $dom->appendChild($dom->createElement('value'));
-            $struct = $value->appendChild($dom->createElement('struct'));
-
-            if (is_array($this->_value)) {
-                foreach ($this->_value as $name => $val) {
-                    /* @var $val IPF_XmlRpc_Value */
-                    $member = $struct->appendChild($dom->createElement('member'));
-                    $member->appendChild($dom->createElement('name', $name));
-                    $member->appendChild($dom->importNode($val->getAsDOM(), 1));
-                }
-            }
-
-            $this->_as_dom = $value;
-            $this->_as_xml = $this->_stripXmlDeclaration($dom);
-        }
-
-        return $this->_as_xml;
-    }
-}
-
diff --git a/server/abstract.php b/server/abstract.php
new file mode 100644 (file)
index 0000000..b0cf6a1
--- /dev/null
@@ -0,0 +1,24 @@
+<?php
+
+abstract class IPF_Server_Abstract implements IPF_Server_Interface
+{
+    protected static $magic_methods = array(
+        '__construct',
+        '__destruct',
+        '__get',
+        '__set',
+        '__call',
+        '__sleep',
+        '__wakeup',
+        '__isset',
+        '__unset',
+        '__tostring',
+        '__clone',
+        '__set_state',
+    );
+
+    public static function lowerCase(&$value, &$key)
+    {
+        return $value = strtolower($value);
+    }
+}
diff --git a/server/interface.php b/server/interface.php
new file mode 100644 (file)
index 0000000..8176019
--- /dev/null
@@ -0,0 +1,12 @@
+<?php
+
+interface IPF_Server_Interface
+{
+    public function addFunction($function, $namespace = '');
+    public function setClass($class, $namespace = '', $argv = null);
+    public function fault($fault = null, $code = 404);
+    public function handle($request = false);
+    public function getFunctions();
+    public function loadFunctions($definition);
+    public function setPersistence($mode);
+}
diff --git a/server/reflection.php b/server/reflection.php
new file mode 100644 (file)
index 0000000..f6f98f2
--- /dev/null
@@ -0,0 +1,31 @@
+<?php
+
+class IPF_Server_Reflection
+{
+    public static function reflectClass($class, $argv = false, $namespace = '')
+    {
+        if (is_object($class)) {
+            $reflection = new ReflectionObject($class);
+        } elseif (class_exists($class)) {
+            $reflection = new ReflectionClass($class);
+        } else {
+            throw new IPF_Exception('Invalid class or object passed to attachClass()');
+        }
+
+        if ($argv && !is_array($argv)) {
+            throw new IPF_Exception('Invalid argv argument passed to reflectClass');
+        }
+        return new IPF_Server_Reflection_Class($reflection, $namespace, $argv);
+    }
+
+    public static function reflectFunction($function, $argv = false, $namespace = '')
+    {
+        if (!is_string($function) || !function_exists($function)) {
+            throw new IPF_Exception('Invalid function "' . $function . '" passed to reflectFunction');
+        }
+        if ($argv && !is_array($argv)) {
+            throw new IPF_Exception('Invalid argv argument passed to reflectClass');
+        }
+        return new IPF_Server_Reflection_Function(new ReflectionFunction($function), $namespace, $argv);
+    }
+}
diff --git a/server/reflection/class.php b/server/reflection/class.php
new file mode 100644 (file)
index 0000000..d082be5
--- /dev/null
@@ -0,0 +1,77 @@
+<?php
+
+class IPF_Server_Reflection_Class
+{
+    protected $_config = array();
+    protected $_methods = array();
+    protected $_namespace = null;
+    protected $_reflection;
+    public function __construct(ReflectionClass $reflection, $namespace = null, $argv = false)
+    {
+        $this->_reflection = $reflection;
+        $this->setNamespace($namespace);
+
+        foreach ($reflection->getMethods() as $method) {
+            // Don't aggregate magic methods
+            if ('__' == substr($method->getName(), 0, 2)) {
+                continue;
+            }
+
+            if ($method->isPublic()) {
+                // Get signatures and description
+                $this->_methods[] = new IPF_Server_Reflection_Method($this, $method, $this->getNamespace(), $argv);
+            }
+        }
+    }
+
+    public function __call($method, $args)
+    {
+        if (method_exists($this->_reflection, $method)) {
+            return call_user_func_array(array($this->_reflection, $method), $args);
+        }
+        throw new IPF_Exception('Invalid reflection method');
+    }
+
+    public function __get($key)
+    {
+        if (isset($this->_config[$key])) {
+            return $this->_config[$key];
+        }
+
+        return null;
+    }
+
+    public function __set($key, $value)
+    {
+        $this->_config[$key] = $value;
+    }
+
+    public function getMethods()
+    {
+        return $this->_methods;
+    }
+
+    public function getNamespace()
+    {
+        return $this->_namespace;
+    }
+
+    public function setNamespace($namespace)
+    {
+        if (empty($namespace)) {
+            $this->_namespace = '';
+            return;
+        }
+
+        if (!is_string($namespace) || !preg_match('/[a-z0-9_\.]+/i', $namespace)) {
+            throw new IPF_Exception('Invalid namespace');
+        }
+
+        $this->_namespace = $namespace;
+    }
+
+    public function __wakeup()
+    {
+        $this->_reflection = new ReflectionClass($this->getName());
+    }
+}
diff --git a/server/reflection/function.php b/server/reflection/function.php
new file mode 100644 (file)
index 0000000..a4cd63c
--- /dev/null
@@ -0,0 +1,4 @@
+<?php
+
+class IPF_Server_Reflection_Function extends IPF_Server_Reflection_Function_Abstract{
+}
diff --git a/server/reflection/function/abstract.php b/server/reflection/function/abstract.php
new file mode 100644 (file)
index 0000000..f65405d
--- /dev/null
@@ -0,0 +1,293 @@
+<?php
+
+class IPF_Server_Reflection_Function_Abstract
+{
+    protected $_reflection;
+    protected $_argv = array();
+    protected $_config = array();
+    protected $_class;
+    protected $_description = '';
+    protected $_namespace;
+
+    protected $_prototypes = array();
+
+    private $_return;
+    private $_returnDesc;
+    private $_paramDesc;
+    private $_sigParams;
+    private $_sigParamsDepth;
+
+    public function __construct(Reflector $r, $namespace = null, $argv = array())
+    {
+        // In PHP 5.1.x, ReflectionMethod extends ReflectionFunction. In 5.2.x,
+        // both extend ReflectionFunctionAbstract. So, we can't do normal type
+        // hinting in the prototype, but instead need to do some explicit
+        // testing here.
+        if ((!$r instanceof ReflectionFunction)
+            && (!$r instanceof ReflectionMethod)) {
+            throw new IPF_Exception('Invalid reflection class');
+        }
+        $this->_reflection = $r;
+
+        // Determine namespace
+        if (null !== $namespace){
+            $this->setNamespace($namespace);
+        }
+
+        // Determine arguments
+        if (is_array($argv)) {
+            $this->_argv = $argv;
+        }
+
+        // If method call, need to store some info on the class
+        if ($r instanceof ReflectionMethod) {
+            $this->_class = $r->getDeclaringClass()->getName();
+        }
+
+        // Perform some introspection
+        $this->_reflect();
+    }
+
+    protected function _addTree(IPF_Server_Reflection_Node $parent, $level = 0)
+    {
+        if ($level >= $this->_sigParamsDepth) {
+            return;
+        }
+
+        foreach ($this->_sigParams[$level] as $value) {
+            $node = new IPF_Server_Reflection_Node($value, $parent);
+            if ((null !== $value) && ($this->_sigParamsDepth > $level + 1)) {
+                $this->_addTree($node, $level + 1);
+            }
+        }
+    }
+
+    protected function _buildTree()
+    {
+        $returnTree = array();
+        foreach ((array) $this->_return as $value) {
+            $node = new IPF_Server_Reflection_Node($value);
+            $this->_addTree($node);
+            $returnTree[] = $node;
+        }
+
+        return $returnTree;
+    }
+
+    protected function _buildSignatures($return, $returnDesc, $paramTypes, $paramDesc)
+    {
+        $this->_return         = $return;
+        $this->_returnDesc     = $returnDesc;
+        $this->_paramDesc      = $paramDesc;
+        $this->_sigParams      = $paramTypes;
+        $this->_sigParamsDepth = count($paramTypes);
+        $signatureTrees        = $this->_buildTree();
+        $signatures            = array();
+
+        $endPoints = array();
+        foreach ($signatureTrees as $root) {
+            $tmp = $root->getEndPoints();
+            if (empty($tmp)) {
+                $endPoints = array_merge($endPoints, array($root));
+            } else {
+                $endPoints = array_merge($endPoints, $tmp);
+            }
+        }
+
+        foreach ($endPoints as $node) {
+            if (!$node instanceof IPF_Server_Reflection_Node) {
+                continue;
+            }
+
+            $signature = array();
+            do {
+                array_unshift($signature, $node->getValue());
+                $node = $node->getParent();
+            } while ($node instanceof IPF_Server_Reflection_Node);
+
+            $signatures[] = $signature;
+        }
+
+        // Build prototypes
+        $params = $this->_reflection->getParameters();
+        foreach ($signatures as $signature) {
+            $return = new IPF_Server_Reflection_ReturnValue(array_shift($signature), $this->_returnDesc);
+            $tmp    = array();
+            foreach ($signature as $key => $type) {
+                $param = new IPF_Server_Reflection_Parameter($params[$key], $type, $this->_paramDesc[$key]);
+                $param->setPosition($key);
+                $tmp[] = $param;
+            }
+
+            $this->_prototypes[] = new IPF_Server_Reflection_Prototype($return, $tmp);
+        }
+    }
+
+    protected function _reflect()
+    {
+        $function           = $this->_reflection;
+        $helpText           = '';
+        $signatures         = array();
+        $returnDesc         = '';
+        $paramCount         = $function->getNumberOfParameters();
+        $paramCountRequired = $function->getNumberOfRequiredParameters();
+        $parameters         = $function->getParameters();
+        $docBlock           = $function->getDocComment();
+
+        if (!empty($docBlock)) {
+            // Get help text
+            if (preg_match(':/\*\*\s*\r?\n\s*\*\s(.*?)\r?\n\s*\*(\s@|/):s', $docBlock, $matches))
+            {
+                $helpText = $matches[1];
+                $helpText = preg_replace('/(^\s*\*\s)/m', '', $helpText);
+                $helpText = preg_replace('/\r?\n\s*\*\s*(\r?\n)*/s', "\n", $helpText);
+                $helpText = trim($helpText);
+            }
+
+            // Get return type(s) and description
+            $return     = 'void';
+            if (preg_match('/@return\s+(\S+)/', $docBlock, $matches)) {
+                $return = explode('|', $matches[1]);
+                if (preg_match('/@return\s+\S+\s+(.*?)(@|\*\/)/s', $docBlock, $matches))
+                {
+                    $value = $matches[1];
+                    $value = preg_replace('/\s?\*\s/m', '', $value);
+                    $value = preg_replace('/\s{2,}/', ' ', $value);
+                    $returnDesc = trim($value);
+                }
+            }
+
+            // Get param types and description
+            if (preg_match_all('/@param\s+([^\s]+)/m', $docBlock, $matches)) {
+                $paramTypesTmp = $matches[1];
+                if (preg_match_all('/@param\s+\S+\s+(\$^\S+)\s+(.*?)(@|\*\/)/s', $docBlock, $matches))
+                {
+                    $paramDesc = $matches[2];
+                    foreach ($paramDesc as $key => $value) {
+                        $value = preg_replace('/\s?\*\s/m', '', $value);
+                        $value = preg_replace('/\s{2,}/', ' ', $value);
+                        $paramDesc[$key] = trim($value);
+                    }
+                }
+            }
+        } else {
+            $helpText = $function->getName();
+            $return   = 'void';
+        }
+
+        // Set method description
+        $this->setDescription($helpText);
+
+        // Get all param types as arrays
+        if (!isset($paramTypesTmp) && (0 < $paramCount)) {
+            $paramTypesTmp = array_fill(0, $paramCount, 'mixed');
+        } elseif (!isset($paramTypesTmp)) {
+            $paramTypesTmp = array();
+        } elseif (count($paramTypesTmp) < $paramCount) {
+            $start = $paramCount - count($paramTypesTmp);
+            for ($i = $start; $i < $paramCount; ++$i) {
+                $paramTypesTmp[$i] = 'mixed';
+            }
+        }
+
+        // Get all param descriptions as arrays
+        if (!isset($paramDesc) && (0 < $paramCount)) {
+            $paramDesc = array_fill(0, $paramCount, '');
+        } elseif (!isset($paramDesc)) {
+            $paramDesc = array();
+        } elseif (count($paramDesc) < $paramCount) {
+            $start = $paramCount - count($paramDesc);
+            for ($i = $start; $i < $paramCount; ++$i) {
+                $paramDesc[$i] = '';
+            }
+        }
+
+
+        $paramTypes = array();
+        foreach ($paramTypesTmp as $i => $param) {
+            $tmp = explode('|', $param);
+            if ($parameters[$i]->isOptional()) {
+                array_unshift($tmp, null);
+            }
+            $paramTypes[] = $tmp;
+        }
+
+        $this->_buildSignatures($return, $returnDesc, $paramTypes, $paramDesc);
+    }
+
+    public function __call($method, $args)
+    {
+        if (method_exists($this->_reflection, $method)) {
+            return call_user_func_array(array($this->_reflection, $method), $args);
+        }
+
+        throw new IPF_Exception('Invalid reflection method ("' .$method. '")');
+    }
+
+    public function __get($key)
+    {
+        if (isset($this->_config[$key])) {
+            return $this->_config[$key];
+        }
+
+        return null;
+    }
+
+    public function __set($key, $value)
+    {
+        $this->_config[$key] = $value;
+    }
+
+    public function setNamespace($namespace)
+    {
+        if (empty($namespace)) {
+            $this->_namespace = '';
+            return;
+        }
+
+        if (!is_string($namespace) || !preg_match('/[a-z0-9_\.]+/i', $namespace)) {
+            throw new IPF_Exception('Invalid namespace');
+        }
+
+        $this->_namespace = $namespace;
+    }
+
+    public function getNamespace()
+    {
+        return $this->_namespace;
+    }
+
+    public function setDescription($string)
+    {
+        if (!is_string($string)) {
+            throw new IPF_Exception('Invalid description');
+        }
+
+        $this->_description = $string;
+    }
+
+    public function getDescription()
+    {
+        return $this->_description;
+    }
+
+    public function getPrototypes()
+    {
+        return $this->_prototypes;
+    }
+
+    public function getInvokeArguments()
+    {
+        return $this->_argv;
+    }
+
+    public function __wakeup()
+    {
+        if ($this->_reflection instanceof ReflectionMethod) {
+            $class = new ReflectionClass($this->_class);
+            $this->_reflection = new ReflectionMethod($class->newInstance(), $this->getName());
+        } else {
+            $this->_reflection = new ReflectionFunction($this->getName());
+        }
+    }
+}
diff --git a/server/reflection/method.php b/server/reflection/method.php
new file mode 100644 (file)
index 0000000..9aaee14
--- /dev/null
@@ -0,0 +1,45 @@
+<?php
+
+class IPF_Server_Reflection_Method extends IPF_Server_Reflection_Function_Abstract
+{
+    protected $_class;
+    protected $_classReflection;
+
+    public function __construct(IPF_Server_Reflection_Class $class, ReflectionMethod $r, $namespace = null, $argv = array())
+    {
+        $this->_classReflection = $class;
+        $this->_reflection      = $r;
+
+        $classNamespace = $class->getNamespace();
+
+        // Determine namespace
+        if (!empty($namespace)) {
+            $this->setNamespace($namespace);
+        } elseif (!empty($classNamespace)) {
+            $this->setNamespace($classNamespace);
+        }
+
+        // Determine arguments
+        if (is_array($argv)) {
+            $this->_argv = $argv;
+        }
+
+        // If method call, need to store some info on the class
+        $this->_class = $class->getName();
+
+        // Perform some introspection
+        $this->_reflect();
+    }
+
+    public function getDeclaringClass()
+    {
+        return $this->_classReflection;
+    }
+
+    public function __wakeup()
+    {
+        $this->_classReflection = new IPF_Server_Reflection_Class(new ReflectionClass($this->_class), $this->getNamespace(), $this->getInvokeArguments());
+        $this->_reflection = new ReflectionMethod($this->_classReflection->getName(), $this->getName());
+    }
+
+}
diff --git a/server/reflection/node.php b/server/reflection/node.php
new file mode 100644 (file)
index 0000000..5ee1a2a
--- /dev/null
@@ -0,0 +1,96 @@
+<?php
+
+class IPF_Server_Reflection_Node
+{
+    protected $_value = null;
+    protected $_children = array();
+    protected $_parent = null;
+
+    public function __construct($value, IPF_Server_Reflection_Node $parent = null)
+    {
+        $this->_value = $value;
+        if (null !== $parent) {
+            $this->setParent($parent, true);
+        }
+
+        return $this;
+    }
+
+    public function setParent(IPF_Server_Reflection_Node $node, $new = false)
+    {
+        $this->_parent = $node;
+
+        if ($new) {
+            $node->attachChild($this);
+            return;
+        }
+    }
+
+    public function createChild($value)
+    {
+        $child = new self($value, $this);
+
+        return $child;
+    }
+
+    public function attachChild(IPF_Server_Reflection_Node $node)
+    {
+        $this->_children[] = $node;
+
+        if ($node->getParent() !== $this) {
+            $node->setParent($this);
+        }
+    }
+
+    public function getChildren()
+    {
+        return $this->_children;
+    }
+
+    public function hasChildren()
+    {
+        return count($this->_children) > 0;
+    }
+
+    public function getParent()
+    {
+        return $this->_parent;
+    }
+
+    public function getValue()
+    {
+        return $this->_value;
+    }
+
+    public function setValue($value)
+    {
+        $this->_value = $value;
+    }
+
+    public function getEndPoints()
+    {
+        $endPoints = array();
+        if (!$this->hasChildren()) {
+            return $endPoints;
+        }
+
+        foreach ($this->_children as $child) {
+            $value = $child->getValue();
+
+            if (null === $value) {
+                $endPoints[] = $this;
+            } elseif ((null !== $value)
+                && $child->hasChildren())
+            {
+                $childEndPoints = $child->getEndPoints();
+                if (!empty($childEndPoints)) {
+                    $endPoints = array_merge($endPoints, $childEndPoints);
+                }
+            } elseif ((null !== $value) && !$child->hasChildren()) {
+                $endPoints[] = $child;
+            }
+        }
+
+        return $endPoints;
+    }
+}
diff --git a/server/reflection/parameter.php b/server/reflection/parameter.php
new file mode 100644 (file)
index 0000000..d043314
--- /dev/null
@@ -0,0 +1,60 @@
+<?php
+
+class IPF_Server_Reflection_Parameter
+{
+    protected $_reflection;
+    protected $_position;
+    protected $_type;
+    protected $_description;
+
+    public function __construct(ReflectionParameter $r, $type = 'mixed', $description = '')
+    {
+        $this->_reflection = $r;
+        $this->setType($type);
+        $this->setDescription($description);
+    }
+
+    public function __call($method, $args)
+    {
+        if (method_exists($this->_reflection, $method)) {
+            return call_user_func_array(array($this->_reflection, $method), $args);
+        }
+        throw new IPF_Exception('Invalid reflection method');
+    }
+
+    public function getType()
+    {
+        return $this->_type;
+    }
+
+    public function setType($type)
+    {
+        if (!is_string($type) && (null !== $type)) {
+            throw new IPF_Exception('Invalid parameter type');
+        }
+        $this->_type = $type;
+    }
+
+    public function getDescription()
+    {
+        return $this->_description;
+    }
+
+    public function setDescription($description)
+    {
+        if (!is_string($description) && (null !== $description)) {
+            throw new IPF_Exception('Invalid parameter description');
+        }
+        $this->_description = $description;
+    }
+
+    public function setPosition($index)
+    {
+        $this->_position = (int) $index;
+    }
+
+    public function getPosition()
+    {
+        return $this->_position;
+    }
+}
diff --git a/server/reflection/prototype.php b/server/reflection/prototype.php
new file mode 100644 (file)
index 0000000..c34375d
--- /dev/null
@@ -0,0 +1,38 @@
+<?php
+
+class IPF_Server_Reflection_Prototype
+{
+    public function __construct(IPF_Server_Reflection_ReturnValue $return, $params = null)
+    {
+        $this->_return = $return;
+
+        if (!is_array($params) && (null !== $params)) {
+            throw new IPF_Exception('Invalid parameters');
+        }
+
+        if (is_array($params)) {
+            foreach ($params as $param) {
+                if (!$param instanceof IPF_Server_Reflection_Parameter) {
+                    throw new IPF_Exception('One or more params are invalid');
+                }
+            }
+        }
+
+        $this->_params = $params;
+    }
+
+    public function getReturnType()
+    {
+        return $this->_return->getType();
+    }
+
+    public function getReturnValue()
+    {
+        return $this->_return;
+    }
+
+    public function getParameters()
+    {
+        return $this->_params;
+    }
+}
diff --git a/server/reflection/returnvalue.php b/server/reflection/returnvalue.php
new file mode 100644 (file)
index 0000000..c33fb2c
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+
+class IPF_Server_Reflection_ReturnValue
+{
+    protected $_type;
+    protected $_description;
+
+    public function __construct($type = 'mixed', $description = '')
+    {
+        $this->setType($type);
+        $this->setDescription($description);
+    }
+
+    public function getType()
+    {
+        return $this->_type;
+    }
+
+    public function setType($type)
+    {
+        if (!is_string($type) && (null !== $type)) {
+            throw new IPF_Exception('Invalid parameter type');
+        }
+        $this->_type = $type;
+    }
+
+    public function getDescription()
+    {
+        return $this->_description;
+    }
+
+    public function setDescription($description)
+    {
+        if (!is_string($description) && (null !== $description)) {
+            throw new IPF_Exception('Invalid parameter description');
+        }
+        $this->_description = $description;
+    }
+}
diff --git a/xmlrpc/fault.php b/xmlrpc/fault.php
new file mode 100644 (file)
index 0000000..7b1d7b7
--- /dev/null
@@ -0,0 +1,183 @@
+<?php
+
+class IPF_XmlRpc_Fault
+{
+    protected $_code;
+    protected $_encoding = 'UTF-8';
+    protected $_message;
+
+    protected $_internal = array(
+        404 => 'Unknown Error',
+
+        // 610 - 619 reflection errors
+        610 => 'Invalid method class',
+        611 => 'Unable to attach function or callback; not callable',
+        612 => 'Unable to load array; not an array',
+        613 => 'One or more method records are corrupt or otherwise unusable',
+
+        // 620 - 629 dispatch errors
+        620 => 'Method does not exist',
+        621 => 'Error instantiating class to invoke method',
+        622 => 'Method missing implementation',
+        623 => 'Calling parameters do not match signature',
+
+        // 630 - 639 request errors
+        630 => 'Unable to read request',
+        631 => 'Failed to parse request',
+        632 => 'Invalid request, no method passed; request must contain a \'methodName\' tag',
+        633 => 'Param must contain a value',
+        634 => 'Invalid method name',
+        635 => 'Invalid XML provided to request',
+        636 => 'Error creating xmlrpc value',
+
+        // 640 - 649 system.* errors
+        640 => 'Method does not exist',
+
+        // 650 - 659 response errors
+        650 => 'Invalid XML provided for response',
+        651 => 'Failed to parse response',
+        652 => 'Invalid response',
+        653 => 'Invalid XMLRPC value in response',
+    );
+
+    public function __construct($code = 404, $message = '')
+    {
+        $this->setCode($code);
+        $code = $this->getCode();
+
+        if (empty($message) && isset($this->_internal[$code])) {
+            $message = $this->_internal[$code];
+        } elseif (empty($message)) {
+            $message = 'Unknown error';
+        }
+        $this->setMessage($message);
+    }
+
+    public function setCode($code)
+    {
+        $this->_code = (int) $code;
+        return $this;
+    }
+
+    public function getCode()
+    {
+        return $this->_code;
+    }
+
+    public function setMessage($message)
+    {
+        $this->_message = (string) $message;
+        return $this;
+    }
+
+    public function getMessage()
+    {
+        return $this->_message;
+    }
+
+    public function setEncoding($encoding)
+    {
+        $this->_encoding = $encoding;
+        return $this;
+    }
+
+    public function getEncoding()
+    {
+        return $this->_encoding;
+    }
+
+    public function loadXml($fault)
+    {
+        if (!is_string($fault)) {
+            throw new IPF_Exception('Invalid XML provided to fault');
+        }
+
+        try {
+            $xml = @new SimpleXMLElement($fault);
+        } catch (Exception $e) {
+            // Not valid XML
+            throw new IPF_Exception('Failed to parse XML fault: ' .  $e->getMessage(), 500);
+        }
+
+        // Check for fault
+        if (!$xml->fault) {
+            // Not a fault
+            return false;
+        }
+
+        if (!$xml->fault->value->struct) {
+            // not a proper fault
+            throw new IPF_Exception('Invalid fault structure', 500);
+        }
+
+        $structXml = $xml->fault->value->asXML();
+        $structXml = preg_replace('/<\?xml version=.*?\?>/i', '', $structXml);
+        $struct    = IPF_XmlRpc_Value::getXmlRpcValue(trim($structXml), IPF_XmlRpc_Value::XML_STRING);
+        $struct    = $struct->getValue();
+
+        if (isset($struct['faultCode'])) {
+            $code = $struct['faultCode'];
+        }
+        if (isset($struct['faultString'])) {
+            $message = $struct['faultString'];
+        }
+
+        if (empty($code) && empty($message)) {
+            throw new IPF_Exception('Fault code and string required');
+        }
+
+        if (empty($code)) {
+            $code = '404';
+        }
+
+        if (empty($message)) {
+            if (isset($this->_internal[$code])) {
+                $message = $this->_internal[$code];
+            } else {
+                $message = 'Unknown Error';
+            }
+        }
+
+        $this->setCode($code);
+        $this->setMessage($message);
+
+        return true;
+    }
+
+    public static function isFault($xml)
+    {
+        $fault = new self();
+        try {
+            $isFault = $fault->loadXml($xml);
+        } catch (IPF_Exception $e) {
+            $isFault = false;
+        }
+
+        return $isFault;
+    }
+
+    public function saveXML()
+    {
+        // Create fault value
+        $faultStruct = array(
+            'faultCode'   => $this->getCode(),
+            'faultString' => $this->getMessage()
+        );
+        $value = IPF_XmlRpc_Value::getXmlRpcValue($faultStruct);
+        $valueDOM = new DOMDocument('1.0', $this->getEncoding());
+        $valueDOM->loadXML($value->saveXML());
+
+        // Build response XML
+        $dom  = new DOMDocument('1.0', 'ISO-8859-1');
+        $r    = $dom->appendChild($dom->createElement('methodResponse'));
+        $f    = $r->appendChild($dom->createElement('fault'));
+        $f->appendChild($dom->importNode($valueDOM->documentElement, 1));
+
+        return $dom->saveXML();
+    }
+
+    public function __toString()
+    {
+        return $this->saveXML();
+    }
+}
diff --git a/xmlrpc/request.php b/xmlrpc/request.php
new file mode 100644 (file)
index 0000000..39c4edc
--- /dev/null
@@ -0,0 +1,257 @@
+<?php
+
+class IPF_XmlRpc_Request
+{
+    protected $_encoding = 'UTF-8';
+    protected $_method;
+    protected $_xml;
+    protected $_params = array();
+    protected $_fault = null;
+    protected $_types = array();
+    protected $_xmlRpcParams = array();
+
+    public function __construct($method = null, $params = null)
+    {
+        if ($method !== null) {
+            $this->setMethod($method);
+        }
+
+        if ($params !== null) {
+            $this->setParams($params);
+        }
+    }
+
+    public function setEncoding($encoding)
+    {
+        $this->_encoding = $encoding;
+        return $this;
+    }
+
+    public function getEncoding()
+    {
+        return $this->_encoding;
+    }
+
+    public function setMethod($method)
+    {
+        if (!is_string($method) || !preg_match('/^[a-z0-9_.:\/]+$/i', $method)) {
+            $this->_fault = new IPF_XmlRpc_Fault(634, 'Invalid method name ("' . $method . '")');
+            $this->_fault->setEncoding($this->getEncoding());
+            return false;
+        }
+
+        $this->_method = $method;
+        return true;
+    }
+
+    public function getMethod()
+    {
+        return $this->_method;
+    }
+
+    public function addParam($value, $type = null)
+    {
+        $this->_params[] = $value;
+        if (null === $type) {
+            // Detect type if not provided explicitly
+            if ($value instanceof IPF_XmlRpc_Value) {
+                $type = $value->getType();
+            } else {
+                $xmlRpcValue = IPF_XmlRpc_Value::getXmlRpcValue($value);
+                $type        = $xmlRpcValue->getType();
+            }
+        }
+        $this->_types[]  = $type;
+        $this->_xmlRpcParams[] = array('value' => $value, 'type' => $type);
+    }
+
+    public function setParams()
+    {
+        $argc = func_num_args();
+        $argv = func_get_args();
+        if (0 == $argc) {
+            return;
+        }
+
+        if ((1 == $argc) && is_array($argv[0])) {
+            $params     = array();
+            $types      = array();
+            $wellFormed = true;
+            foreach ($argv[0] as $arg) {
+                if (!is_array($arg) || !isset($arg['value'])) {
+                    $wellFormed = false;
+                    break;
+                }
+                $params[] = $arg['value'];
+
+                if (!isset($arg['type'])) {
+                    $xmlRpcValue = IPF_XmlRpc_Value::getXmlRpcValue($arg['value']);
+                    $arg['type'] = $xmlRpcValue->getType();
+                }
+                $types[] = $arg['type'];
+            }
+            if ($wellFormed) {
+                $this->_xmlRpcParams = $argv[0];
+                $this->_params = $params;
+                $this->_types  = $types;
+            } else {
+                $this->_params = $argv[0];
+                $this->_types  = array();
+                $xmlRpcParams  = array();
+                foreach ($argv[0] as $arg) {
+                    if ($arg instanceof IPF_XmlRpc_Value) {
+                        $type = $arg->getType();
+                    } else {
+                        $xmlRpcValue = IPF_XmlRpc_Value::getXmlRpcValue($arg);
+                        $type        = $xmlRpcValue->getType();
+                    }
+                    $xmlRpcParams[] = array('value' => $arg, 'type' => $type);
+                    $this->_types[] = $type;
+                }
+                $this->_xmlRpcParams = $xmlRpcParams;
+            }
+            return;
+        }
+
+        $this->_params = $argv;
+        $this->_types  = array();
+        $xmlRpcParams  = array();
+        foreach ($argv as $arg) {
+            if ($arg instanceof IPF_XmlRpc_Value) {
+                $type = $arg->getType();
+            } else {
+                $xmlRpcValue = IPF_XmlRpc_Value::getXmlRpcValue($arg);
+                $type        = $xmlRpcValue->getType();
+            }
+            $xmlRpcParams[] = array('value' => $arg, 'type' => $type);
+            $this->_types[] = $type;
+        }
+        $this->_xmlRpcParams = $xmlRpcParams;
+    }
+
+    public function getParams()
+    {
+        return $this->_params;
+    }
+
+    public function getTypes()
+    {
+        return $this->_types;
+    }
+
+    public function loadXml($request)
+    {
+        if (!is_string($request)) {
+            $this->_fault = new IPF_XmlRpc_Fault(635);
+            $this->_fault->setEncoding($this->getEncoding());
+            return false;
+        }
+
+        try {
+            $xml = @new SimpleXMLElement($request);
+        } catch (Exception $e) {
+            // Not valid XML
+            $this->_fault = new IPF_XmlRpc_Fault(631);
+            $this->_fault->setEncoding($this->getEncoding());
+            return false;
+        }
+
+        // Check for method name
+        if (empty($xml->methodName)) {
+            // Missing method name
+            $this->_fault = new IPF_XmlRpc_Fault(632);
+            $this->_fault->setEncoding($this->getEncoding());
+            return false;
+        }
+
+        $this->_method = (string) $xml->methodName;
+
+        // Check for parameters
+        if (!empty($xml->params)) {
+            $types = array();
+            $argv  = array();
+            foreach ($xml->params->children() as $param) {
+                if (! $param->value instanceof SimpleXMLElement) {
+                    $this->_fault = new IPF_XmlRpc_Fault(633);
+                    $this->_fault->setEncoding($this->getEncoding());
+                    return false;
+                }
+
+                try {
+                    $param   = IPF_XmlRpc_Value::getXmlRpcValue($param->value, IPF_XmlRpc_Value::XML_STRING);
+                    $types[] = $param->getType();
+                    $argv[]  = $param->getValue();
+                } catch (Exception $e) {
+                    $this->_fault = new IPF_XmlRpc_Fault(636);
+                    $this->_fault->setEncoding($this->getEncoding());
+                    return false;
+                }
+            }
+
+            $this->_types  = $types;
+            $this->_params = $argv;
+        }
+
+        $this->_xml = $request;
+
+        return true;
+    }
+
+    public function isFault()
+    {
+        return $this->_fault instanceof IPF_XmlRpc_Fault;
+    }
+
+    public function getFault()
+    {
+        return $this->_fault;
+    }
+
+    protected function _getXmlRpcParams()
+    {
+        $params = array();
+        if (is_array($this->_xmlRpcParams)) {
+            foreach ($this->_xmlRpcParams as $param) {
+                $value = $param['value'];
+                $type  = isset($param['type']) ? $param['type'] : IPF_XmlRpc_Value::AUTO_DETECT_TYPE;
+
+                if (!$value instanceof IPF_XmlRpc_Value) {
+                    $value = IPF_XmlRpc_Value::getXmlRpcValue($value, $type);
+                }
+                $params[] = $value;
+            }
+        }
+
+        return $params;
+    }
+
+    public function saveXML()
+    {
+        $args   = $this->_getXmlRpcParams();
+        $method = $this->getMethod();
+
+        $dom = new DOMDocument('1.0', $this->getEncoding());
+        $mCall = $dom->appendChild($dom->createElement('methodCall'));
+        $mName = $mCall->appendChild($dom->createElement('methodName', $method));
+
+        if (is_array($args) && count($args)) {
+            $params = $mCall->appendChild($dom->createElement('params'));
+
+            foreach ($args as $arg) {
+                /* @var $arg IPF_XmlRpc_Value */
+                $argDOM = new DOMDocument('1.0', $this->getEncoding());
+                $argDOM->loadXML($arg->saveXML());
+
+                $param = $params->appendChild($dom->createElement('param'));
+                $param->appendChild($dom->importNode($argDOM->documentElement, 1));
+            }
+        }
+
+        return $dom->saveXML();
+    }
+
+    public function __toString()
+    {
+        return $this->saveXML();
+    }
+}
diff --git a/xmlrpc/request/http.php b/xmlrpc/request/http.php
new file mode 100644 (file)
index 0000000..f66114e
--- /dev/null
@@ -0,0 +1,57 @@
+<?php
+
+class IPF_XmlRpc_Request_Http extends IPF_XmlRpc_Request
+{
+    protected $_headers;
+    protected $_xml;
+    public function __construct()
+    {
+        $fh = fopen('php://input', 'r');
+        if (!$fh) {
+            $this->_fault = new IPF_Exception(630);
+            return;
+        }
+
+        $xml = '';
+        while (!feof($fh)) {
+            $xml .= fgets($fh);
+        }
+        fclose($fh);
+
+        $this->_xml = $xml;
+
+        $this->loadXml($xml);
+    }
+
+    public function getRawRequest()
+    {
+        return $this->_xml;
+    }
+
+    public function getHeaders()
+    {
+        if (null === $this->_headers) {
+            $this->_headers = array();
+            foreach ($_SERVER as $key => $value) {
+                if ('HTTP_' == substr($key, 0, 5)) {
+                    $header = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($key, 5)))));
+                    $this->_headers[$header] = $value;
+                }
+            }
+        }
+
+        return $this->_headers;
+    }
+
+    public function getFullRequest()
+    {
+        $request = '';
+        foreach ($this->getHeaders() as $key => $value) {
+            $request .= $key . ': ' . $value . "\n";
+        }
+
+        $request .= $this->_xml;
+
+        return $request;
+    }
+}
diff --git a/xmlrpc/request/stdin.php b/xmlrpc/request/stdin.php
new file mode 100644 (file)
index 0000000..0538d2b
--- /dev/null
@@ -0,0 +1,30 @@
+<?php
+
+class IPF_XmlRpc_Request_Stdin extends IPF_XmlRpc_Request
+{
+    protected $_xml;
+
+    public function __construct()
+    {
+        $fh = fopen('php://stdin', 'r');
+        if (!$fh) {
+            $this->_fault = new IPF_XmlRpc_Fault(630);
+            return;
+        }
+
+        $xml = '';
+        while (!feof($fh)) {
+            $xml .= fgets($fh);
+        }
+        fclose($fh);
+
+        $this->_xml = $xml;
+
+        $this->loadXml($xml);
+    }
+
+    public function getRawRequest()
+    {
+        return $this->_xml;
+    }
+}
diff --git a/xmlrpc/response.php b/xmlrpc/response.php
new file mode 100644 (file)
index 0000000..5f2f78a
--- /dev/null
@@ -0,0 +1,121 @@
+<?php
+
+class IPF_XmlRpc_Response
+{
+    protected $_return;
+    protected $_type;
+    protected $_encoding = 'UTF-8';
+    protected $_fault = null;
+
+    public function __construct($return = null, $type = null)
+    {
+        $this->setReturnValue($return, $type);
+    }
+
+    public function setEncoding($encoding)
+    {
+        $this->_encoding = $encoding;
+        return $this;
+    }
+
+    public function getEncoding()
+    {
+        return $this->_encoding;
+    }
+
+    public function setReturnValue($value, $type = null)
+    {
+        $this->_return = $value;
+        $this->_type = (string) $type;
+    }
+
+    public function getReturnValue()
+    {
+        return $this->_return;
+    }
+
+    protected function _getXmlRpcReturn()
+    {
+        return IPF_XmlRpc_Value::getXmlRpcValue($this->_return);
+    }
+
+    public function isFault()
+    {
+        return $this->_fault instanceof IPF_XmlRpc_Fault;
+    }
+
+    public function getFault()
+    {
+        return $this->_fault;
+    }
+
+    public function loadXml($response)
+    {
+        if (!is_string($response)) {
+            $this->_fault = new IPF_XmlRpc_Fault(650);
+            $this->_fault->setEncoding($this->getEncoding());
+            return false;
+        }
+
+        try {
+            $xml = @new SimpleXMLElement($response);
+        } catch (Exception $e) {
+            // Not valid XML
+            $this->_fault = new IPF_XmlRpc_Fault(651);
+            $this->_fault->setEncoding($this->getEncoding());
+            return false;
+        }
+
+        if (!empty($xml->fault)) {
+            // fault response
+            $this->_fault = new IPF_XmlRpc_Fault();
+            $this->_fault->setEncoding($this->getEncoding());
+            $this->_fault->loadXml($response);
+            return false;
+        }
+
+        if (empty($xml->params)) {
+            // Invalid response
+            $this->_fault = new IPF_XmlRpc_Fault(652);
+            $this->_fault->setEncoding($this->getEncoding());
+            return false;
+        }
+
+        try {
+            if (!isset($xml->params) || !isset($xml->params->param) || !isset($xml->params->param->value)) {
+                throw new IPF_Exception('Missing XML-RPC value in XML');
+            }
+            $valueXml = $xml->params->param->value->asXML();
+            $valueXml = preg_replace('/<\?xml version=.*?\?>/i', '', $valueXml);
+            $value = IPF_XmlRpc_Value::getXmlRpcValue(trim($valueXml), IPF_XmlRpc_Value::XML_STRING);
+        } catch (IPF_Exception $e) {
+            $this->_fault = new IPF_XmlRpc_Fault(653);
+            $this->_fault->setEncoding($this->getEncoding());
+            return false;
+        }
+
+        $this->setReturnValue($value->getValue());
+        return true;
+    }
+
+    public function saveXML()
+    {
+        $value = $this->_getXmlRpcReturn();
+        $valueDOM = new DOMDocument('1.0', $this->getEncoding());
+        $valueDOM->loadXML($value->saveXML());
+
+        $dom      = new DOMDocument('1.0', $this->getEncoding());
+        $response = $dom->appendChild($dom->createElement('methodResponse'));
+        $params   = $response->appendChild($dom->createElement('params'));
+        $param    = $params->appendChild($dom->createElement('param'));
+
+        $param->appendChild($dom->importNode($valueDOM->documentElement, true));
+
+        return $dom->saveXML();
+    }
+
+    public function __toString()
+    {
+        return $this->saveXML();
+    }
+}
diff --git a/xmlrpc/response/http.php b/xmlrpc/response/http.php
new file mode 100644 (file)
index 0000000..fa767b5
--- /dev/null
@@ -0,0 +1,12 @@
+<?php
+
+class IPF_XmlRpc_Response_Http extends IPF_XmlRpc_Response
+{
+    public function __toString()
+    {
+        if (!headers_sent()) {
+            header('Content-Type: text/xml; charset=' . strtolower($this->getEncoding()));
+        }
+        return parent::__toString();
+    }
+}
diff --git a/xmlrpc/server.php b/xmlrpc/server.php
new file mode 100644 (file)
index 0000000..a3a5a3a
--- /dev/null
@@ -0,0 +1,428 @@
+<?php
+
+class IPF_XmlRpc_Server
+{
+    protected $_encoding = 'UTF-8';
+    protected $_methods = array();
+    protected $_request = null;
+    protected $_responseClass = 'IPF_XmlRpc_Response_Http';
+
+    protected $_table = array();
+
+    protected $_typeMap = array(
+        'i4'               => 'i4',
+        'int'              => 'int',
+        'integer'          => 'int',
+        'double'           => 'double',
+        'float'            => 'double',
+        'real'             => 'double',
+        'boolean'          => 'boolean',
+        'bool'             => 'boolean',
+        'true'             => 'boolean',
+        'false'            => 'boolean',
+        'string'           => 'string',
+        'str'              => 'string',
+        'base64'           => 'base64',
+        'dateTime.iso8601' => 'dateTime.iso8601',
+        'date'             => 'dateTime.iso8601',
+        'time'             => 'dateTime.iso8601',
+        'time'             => 'dateTime.iso8601',
+        'array'            => 'array',
+        'struct'           => 'struct',
+        'null'             => 'nil',
+        'nil'              => 'nil',
+        'void'             => 'void',
+        'mixed'            => 'struct'
+    );
+
+    public function __construct()
+    {
+        // Setup system.* methods
+        $system = array(
+            'listMethods',
+            'methodHelp',
+            'methodSignature',
+            'multicall'
+        );
+
+        $class = IPF_Server_Reflection::reflectClass($this);
+        foreach ($system as $method) {
+            $reflection = new IPF_Server_Reflection_Method($class, new ReflectionMethod($this, $method), 'system');
+            $reflection->system = true;
+            $this->_methods[] = $reflection;
+        }
+
+        $this->_buildDispatchTable();
+    }
+
+    protected function _fixTypes(IPF_Server_Reflection_Function_Abstract $method)
+    {
+        foreach ($method->getPrototypes() as $prototype) {
+            foreach ($prototype->getParameters() as $param) {
+                $pType = $param->getType();
+                if (isset($this->_typeMap[$pType])) {
+                    $param->setType($this->_typeMap[$pType]);
+                } else {
+                    $param->setType('void');
+                }
+            }
+        }
+    }
+
+    protected function _buildDispatchTable()
+    {
+        $table      = array();
+        foreach ($this->_methods as $dispatchable) {
+            if ($dispatchable instanceof IPF_Server_Reflection_Function_Abstract) {
+                // function/method call
+                $ns   = $dispatchable->getNamespace();
+                $name = $dispatchable->getName();
+                $name = empty($ns) ? $name : $ns . '.' . $name;
+
+                if (isset($table[$name])) {
+                    throw new IPF_Exception('Duplicate method registered: ' . $name);
+                }
+                $table[$name] = $dispatchable;
+                $this->_fixTypes($dispatchable);
+
+                continue;
+            }
+
+            if ($dispatchable instanceof IPF_Server_Reflection_Class) {
+                foreach ($dispatchable->getMethods() as $method) {
+                    $ns   = $method->getNamespace();
+                    $name = $method->getName();
+                    $name = empty($ns) ? $name : $ns . '.' . $name;
+
+                    if (isset($table[$name])) {
+                        throw new IPF_Exception('Duplicate method registered: ' . $name);
+                    }
+                    $table[$name] = $method;
+                    $this->_fixTypes($method);
+                    continue;
+                }
+            }
+        }
+
+        $this->_table = $table;
+    }
+
+    public function setEncoding($encoding)
+    {
+        $this->_encoding = $encoding;
+        return $this;
+    }
+
+    public function getEncoding()
+    {
+        return $this->_encoding;
+    }
+
+    public function addFunction($function, $namespace = '')
+    {
+        if (!is_string($function) && !is_array($function)) {
+            throw new IPF_Exception('Unable to attach function; invalid', 611);
+        }
+
+        $argv = null;
+        if (2 < func_num_args()) {
+            $argv = func_get_args();
+            $argv = array_slice($argv, 2);
+        }
+
+        $function = (array) $function;
+        foreach ($function as $func) {
+            if (!is_string($func) || !function_exists($func)) {
+                throw new IPF_Exception('Unable to attach function; invalid', 611);
+            }
+            $this->_methods[] = IPF_Server_Reflection::reflectFunction($func, $argv, $namespace);
+        }
+
+        $this->_buildDispatchTable();
+    }
+
+    public function loadFunctions($array)
+    {
+        if (!is_array($array)) {
+            throw new IPF_Exception('Unable to load array; not an array', 612);
+        }
+
+        foreach ($array as $key => $value) {
+            if (!$value instanceof IPF_Server_Reflection_Function_Abstract
+                && !$value instanceof IPF_Server_Reflection_Class)
+            {
+                throw new IPF_Exception('One or more method records are corrupt or otherwise unusable', 613);
+            }
+
+            if ($value->system) {
+                unset($array[$key]);
+            }
+        }
+
+        foreach ($array as $dispatchable) {
+            $this->_methods[] = $dispatchable;
+        }
+
+        $this->_buildDispatchTable();
+    }
+
+    public function setPersistence($class = null)
+    {
+    }
+
+    public function setClass($class, $namespace = '', $argv = null)
+    {
+        if (is_string($class) && !class_exists($class)) {
+            if (!class_exists($class)) {
+                throw new IPF_Exception('Invalid method class', 610);
+            }
+        }
+
+        $argv = null;
+        if (3 < func_num_args()) {
+            $argv = func_get_args();
+            $argv = array_slice($argv, 3);
+        }
+
+        $this->_methods[] = IPF_Reflection::reflectClass($class, $argv, $namespace);
+        $this->_buildDispatchTable();
+    }
+
+    public function setRequest($request)
+    {
+        if (is_string($request) && class_exists($request)) {
+            $request = new $request();
+            if (!$request instanceof IPF_XmlRpc_Request) {
+                throw new IPF_Exception('Invalid request class');
+            }
+            $request->setEncoding($this->getEncoding());
+        } elseif (!$request instanceof IPF_XmlRpc_Request) {
+            throw new IPF_Exception('Invalid request object');
+        }
+
+        $this->_request = $request;
+        return $this;
+    }
+
+    public function getRequest()
+    {
+        return $this->_request;
+    }
+
+    public function fault($fault, $code = 404)
+    {
+        if (!$fault instanceof Exception) {
+            $fault = (string) $fault;
+            $fault = new IPF_Exception($fault, $code);
+        }
+        return IPF_XmlRpc_Server_Fault::getInstance($fault);
+    }
+
+    protected function _handle(IPF_XmlRpc_Request $request)
+    {
+        $method = $request->getMethod();
+
+        // Check for valid method
+        if (!isset($this->_table[$method])) {
+            throw new IPF_Exception('Method "' . $method . '" does not exist', 620);
+        }
+
+        $info     = $this->_table[$method];
+        $params   = $request->getParams();
+        $argv     = $info->getInvokeArguments();
+        if (0 < count($argv)) {
+            $params = array_merge($params, $argv);
+        }
+
+        // Check calling parameters against signatures
+        $matched    = false;
+        $sigCalled  = $request->getTypes();
+
+        $sigLength  = count($sigCalled);
+        $paramsLen  = count($params);
+        if ($sigLength < $paramsLen) {
+            for ($i = $sigLength; $i < $paramsLen; ++$i) {
+                $xmlRpcValue = IPF_XmlRpc_Value::getXmlRpcValue($params[$i]);
+                $sigCalled[] = $xmlRpcValue->getType();
+            }
+        }
+
+        $signatures = $info->getPrototypes();
+        foreach ($signatures as $signature) {
+            $sigParams = $signature->getParameters();
+            $tmpParams = array();
+            foreach ($sigParams as $param) {
+                $tmpParams[] = $param->getType();
+            }
+            if ($sigCalled === $tmpParams) {
+                $matched = true;
+                break;
+            }
+        }
+        if (!$matched) {
+            throw new IPF_Exception('Calling parameters do not match signature', 623);
+        }
+
+        if ($info instanceof IPF_Server_Reflection_Function) {
+            $func = $info->getName();
+            $return = call_user_func_array($func, $params);
+        } elseif (($info instanceof IPF_Server_Reflection_Method) && $info->system) {
+            // System methods
+            $return = $info->invokeArgs($this, $params);
+        } elseif ($info instanceof IPF_Server_Reflection_Method) {
+            // Get class
+            $class = $info->getDeclaringClass()->getName();
+
+            if ('static' == $info->isStatic()) {
+                // for some reason, invokeArgs() does not work the same as
+                // invoke(), and expects the first argument to be an object.
+                // So, using a callback if the method is static.
+                $return = call_user_func_array(array($class, $info->getName()), $params);
+            } else {
+                // Object methods
+                try {
+                    $object = $info->getDeclaringClass()->newInstance();
+                } catch (Exception $e) {
+                    throw new IPF_Exception('Error instantiating class ' . $class . ' to invoke method ' . $info->getName(), 621);
+                }
+
+                $return = $info->invokeArgs($object, $params);
+            }
+        } else {
+            throw new IPF_Exception('Method missing implementation ' . get_class($info), 622);
+        }
+
+        $response = new ReflectionClass($this->_responseClass);
+        return $response->newInstance($return);
+    }
+
+    public function handle(IPF_XmlRpc_Request $request = null)
+    {
+        // Get request
+        if ((null === $request) && (null === ($request = $this->getRequest()))) {
+            $request = new IPF_XmlRpc_Request_Http();
+            $request->setEncoding($this->getEncoding());
+        }
+
+        $this->setRequest($request);
+
+        if ($request->isFault()) {
+            $response = $request->getFault();
+        } else {
+            try {
+                $response = $this->_handle($request);
+            } catch (Exception $e) {
+                $response = $this->fault($e);
+            }
+        }
+
+        // Set output encoding
+        $response->setEncoding($this->getEncoding());
+
+        return $response;
+    }
+
+    public function setResponseClass($class)
+    {
+        if (class_exists($class)) {
+            $reflection = new ReflectionClass($class);
+            if ($reflection->isSubclassOf(new ReflectionClass('IPF_XmlRpc_Response'))) {
+                $this->_responseClass = $class;
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    public function getFunctions()
+    {
+        $return = array();
+        foreach ($this->_methods as $method) {
+            if ($method instanceof IPF_Server_Reflection_Class
+                && ($method->system))
+            {
+                continue;
+            }
+
+            $return[] = $method;
+        }
+
+        return $return;
+    }
+
+    public function listMethods()
+    {
+        return array_keys($this->_table);
+    }
+
+    public function methodHelp($method)
+    {
+        if (!isset($this->_table[$method])) {
+            throw new IPF_Exception('Method "' . $method . '"does not exist', 640);
+        }
+
+        return $this->_table[$method]->getDescription();
+    }
+
+    public function methodSignature($method)
+    {
+        if (!isset($this->_table[$method])) {
+            throw new IPF_Exception('Method "' . $method . '"does not exist', 640);
+        }
+        $prototypes = $this->_table[$method]->getPrototypes();
+
+        $signatures = array();
+        foreach ($prototypes as $prototype) {
+            $signature = array($prototype->getReturnType());
+            foreach ($prototype->getParameters() as $parameter) {
+                $signature[] = $parameter->getType();
+            }
+            $signatures[] = $signature;
+        }
+
+        return $signatures;
+    }
+
+    public function multicall($methods)
+    {
+        $responses = array();
+        foreach ($methods as $method) {
+            $fault = false;
+            if (!is_array($method)) {
+                $fault = $this->fault('system.multicall expects each method to be a struct', 601);
+            } elseif (!isset($method['methodName'])) {
+                $fault = $this->fault('Missing methodName', 602);
+            } elseif (!isset($method['params'])) {
+                $fault = $this->fault('Missing params', 603);
+            } elseif (!is_array($method['params'])) {
+                $fault = $this->fault('Params must be an array', 604);
+            } else {
+                if ('system.multicall' == $method['methodName']) {
+                    // don't allow recursive calls to multicall
+                    $fault = $this->fault('Recursive system.multicall forbidden', 605);
+                }
+            }
+
+            if (!$fault) {
+                try {
+                    $request = new IPF_XmlRpc_Request();
+                    $request->setMethod($method['methodName']);
+                    $request->setParams($method['params']);
+                    $response = $this->_handle($request);
+                    $responses[] = $response->getReturnValue();
+                } catch (Exception $e) {
+                    $fault = $this->fault($e);
+                }
+            }
+
+            if ($fault) {
+                $responses[] = array(
+                    'faultCode'   => $fault->getCode(),
+                    'faultString' => $fault->getMessage()
+                );
+            }
+        }
+        return $responses;
+    }
+}
diff --git a/xmlrpc/server/cache.php b/xmlrpc/server/cache.php
new file mode 100644 (file)
index 0000000..aa6c7e7
--- /dev/null
@@ -0,0 +1,60 @@
+<?php
+
+class IPF_XmlRpc_Server_Cache
+{
+    public static function save($filename, IPF_XmlRpc_Server $server)
+    {
+        if (!is_string($filename)
+            || (!file_exists($filename) && !is_writable(dirname($filename))))
+        {
+            return false;
+        }
+
+        // Remove system.* methods
+        $methods = $server->getFunctions();
+        foreach ($methods as $name => $method) {
+            if ($method->system) {
+                unset($methods[$name]);
+            }
+        }
+
+        // Store
+        if (0 === @file_put_contents($filename, serialize($methods))) {
+            return false;
+        }
+
+        return true;
+    }
+
+    public static function get($filename, IPF_XmlRpc_Server $server)
+    {
+        if (!is_string($filename)
+            || !file_exists($filename)
+            || !is_readable($filename))
+        {
+            return false;
+        }
+
+        if (false === ($dispatch = @file_get_contents($filename))) {
+            return false;
+        }
+
+        if (false === ($dispatchArray = @unserialize($dispatch))) {
+            return false;
+        }
+
+        $server->loadFunctions($dispatchArray);
+
+        return true;
+    }
+
+    public static function delete($filename)
+    {
+        if (is_string($filename) && file_exists($filename)) {
+            unlink($filename);
+            return true;
+        }
+
+        return false;
+    }
+}
diff --git a/xmlrpc/server/fault.php b/xmlrpc/server/fault.php
new file mode 100644 (file)
index 0000000..50db5ed
--- /dev/null
@@ -0,0 +1,95 @@
+<?php
+
+class IPF_XmlRpc_Server_Fault extends IPF_XmlRpc_Fault
+{
+    protected $_exception;
+    protected static $_faultExceptionClasses = array('IPF_Exception' => true);
+    protected static $_observers = array();
+
+    public function __construct(Exception $e)
+    {
+        $this->_exception = $e;
+        $code             = 404;
+        $message          = 'Unknown error';
+        $exceptionClass   = get_class($e);
+
+        foreach (array_keys(self::$_faultExceptionClasses) as $class) {
+            if ($e instanceof $class) {
+                $code    = $e->getCode();
+                $message = $e->getMessage();
+                break;
+            }
+        }
+
+        parent::__construct($code, $message);
+
+        // Notify exception observers, if present
+        if (!empty(self::$_observers)) {
+            foreach (array_keys(self::$_observers) as $observer) {
+                call_user_func(array($observer, 'observe'), $this);
+            }
+        }
+    }
+
+    public static function getInstance(Exception $e)
+    {
+        return new self($e);
+    }
+
+    public static function attachFaultException($classes)
+    {
+        if (!is_array($classes)) {
+            $classes = (array) $classes;
+        }
+
+        foreach ($classes as $class) {
+            if (is_string($class) && class_exists($class)) {
+                self::$_faultExceptionClasses[$class] = true;
+            }
+        }
+    }
+
+    public static function detachFaultException($classes)
+    {
+        if (!is_array($classes)) {
+            $classes = (array) $classes;
+        }
+
+        foreach ($classes as $class) {
+            if (is_string($class) && isset(self::$_faultExceptionClasses[$class])) {
+                unset(self::$_faultExceptionClasses[$class]);
+            }
+        }
+    }
+
+    public static function attachObserver($class)
+    {
+        if (!is_string($class)
+            || !class_exists($class)
+            || !is_callable(array($class, 'observe')))
+        {
+            return false;
+        }
+
+        if (!isset(self::$_observers[$class])) {
+            self::$_observers[$class] = true;
+        }
+
+        return true;
+    }
+
+    public static function detachObserver($class)
+    {
+        if (!isset(self::$_observers[$class])) {
+            return false;
+        }
+
+        unset(self::$_observers[$class]);
+        return true;
+    }
+
+    public function getException()
+    {
+        return $this->_exception;
+    }
+}
diff --git a/xmlrpc/value.php b/xmlrpc/value.php
new file mode 100644 (file)
index 0000000..5201bed
--- /dev/null
@@ -0,0 +1,240 @@
+<?php
+
+abstract class IPF_XmlRpc_Value
+{
+    protected $_value;
+    protected $_type;
+    protected $_as_xml;
+    protected $_as_dom;
+
+    const AUTO_DETECT_TYPE = 'auto_detect';
+    const XML_STRING = 'xml';
+
+    const XMLRPC_TYPE_I4       = 'i4';
+    const XMLRPC_TYPE_INTEGER  = 'int';
+    const XMLRPC_TYPE_DOUBLE   = 'double';
+    const XMLRPC_TYPE_BOOLEAN  = 'boolean';
+    const XMLRPC_TYPE_STRING   = 'string';
+    const XMLRPC_TYPE_DATETIME = 'dateTime.iso8601';
+    const XMLRPC_TYPE_BASE64   = 'base64';
+    const XMLRPC_TYPE_ARRAY    = 'array';
+    const XMLRPC_TYPE_STRUCT   = 'struct';
+    const XMLRPC_TYPE_NIL      = 'nil';
+
+    public function getType()
+    {
+        return $this->_type;
+    }
+
+    abstract public function getValue();
+    abstract public function saveXML();
+
+    public function getAsDOM()
+    {
+        if (!$this->_as_dom) {
+            $doc = new DOMDocument('1.0');
+            $doc->loadXML($this->saveXML());
+            $this->_as_dom = $doc->documentElement;
+        }
+
+        return $this->_as_dom;
+    }
+
+    protected function _stripXmlDeclaration(DOMDocument $dom)
+    {
+        return preg_replace('/<\?xml version="1.0"( encoding="[^\"]*")?\?>\n/u', '', $dom->saveXML());
+    }
+
+    public static function getXmlRpcValue($value, $type = self::AUTO_DETECT_TYPE)
+    {
+        switch ($type) {
+            case self::AUTO_DETECT_TYPE:
+                // Auto detect the XML-RPC native type from the PHP type of $value
+                return self::_phpVarToNativeXmlRpc($value);
+
+            case self::XML_STRING:
+                // Parse the XML string given in $value and get the XML-RPC value in it
+                return self::_xmlStringToNativeXmlRpc($value);
+
+            case self::XMLRPC_TYPE_I4:
+                // fall through to the next case
+            case self::XMLRPC_TYPE_INTEGER:
+                return new IPF_XmlRpc_Value_Integer($value);
+
+            case self::XMLRPC_TYPE_DOUBLE:
+                return new IPF_XmlRpc_Value_Double($value);
+
+            case self::XMLRPC_TYPE_BOOLEAN:
+                return new IPF_XmlRpc_Value_Boolean($value);
+
+            case self::XMLRPC_TYPE_STRING:
+                return new IPF_XmlRpc_Value_String($value);
+
+            case self::XMLRPC_TYPE_BASE64:
+                return new IPF_XmlRpc_Value_Base64($value);
+
+            case self::XMLRPC_TYPE_NIL:
+                return new IPF_XmlRpc_Value_Nil();
+
+            case self::XMLRPC_TYPE_DATETIME:
+                return new IPF_XmlRpc_Value_DateTime($value);
+
+            case self::XMLRPC_TYPE_ARRAY:
+                return new IPF_XmlRpc_Value_Array($value);
+
+            case self::XMLRPC_TYPE_STRUCT:
+                return new IPF_XmlRpc_Value_Struct($value);
+
+            default:
+                throw new IPF_Exception('Given type is not a '. __CLASS__ .' constant');
+        }
+    }
+
+    private static function _phpVarToNativeXmlRpc($value)
+    {
+        switch (gettype($value)) {
+            case 'object':
+                // Check to see if it's an XmlRpc value
+                if ($value instanceof IPF_XmlRpc_Value) {
+                    return $value;
+                }
+                
+                // Otherwise, we convert the object into a struct
+                $value = get_object_vars($value);
+                // Break intentionally omitted
+            case 'array':
+                // Default native type for a PHP array (a simple numeric array) is 'array'
+                $obj = 'IPF_XmlRpc_Value_Array';
+
+                // Determine if this is an associative array
+                if (!empty($value) && is_array($value) && (array_keys($value) !== range(0, count($value) - 1))) {
+                    $obj = 'IPF_XmlRpc_Value_Struct';
+                }
+                return new $obj($value);
+
+            case 'integer':
+                return new IPF_XmlRpc_Value_Integer($value);
+
+            case 'double':
+                return new IPF_XmlRpc_Value_Double($value);
+
+            case 'boolean':
+                return new IPF_XmlRpc_Value_Boolean($value);
+
+            case 'NULL':
+            case 'null':
+                return new IPF_XmlRpc_Value_Nil();
+
+            case 'string':
+                // Fall through to the next case
+            default:
+                // If type isn't identified (or identified as string), it treated as string
+                return new IPF_XmlRpc_Value_String($value);
+        }
+    }
+
+    private static function _xmlStringToNativeXmlRpc($simple_xml)
+    {
+        if (!$simple_xml instanceof SimpleXMLElement) {
+            try {
+                $simple_xml = @new SimpleXMLElement($simple_xml);
+            } catch (Exception $e) {
+                // The given string is not a valid XML
+                throw new IPF_Exception('Failed to create XML-RPC value from XML string: '.$e->getMessage(),$e->getCode());
+            }
+        }
+
+        // Get the key (tag name) and value from the simple xml object and convert the value to an XML-RPC native value
+        list($type, $value) = each($simple_xml);
+        if (!$type) {    // If no type was specified, the default is string
+            $type = self::XMLRPC_TYPE_STRING;
+        }
+
+        switch ($type) {
+            // All valid and known XML-RPC native values
+            case self::XMLRPC_TYPE_I4:
+                // Fall through to the next case
+            case self::XMLRPC_TYPE_INTEGER:
+                $xmlrpc_val = new IPF_XmlRpc_Value_Integer($value);
+                break;
+            case self::XMLRPC_TYPE_DOUBLE:
+                $xmlrpc_val = new IPF_XmlRpc_Value_Double($value);
+                break;
+            case self::XMLRPC_TYPE_BOOLEAN:
+                $xmlrpc_val = new IPF_XmlRpc_Value_Boolean($value);
+                break;
+            case self::XMLRPC_TYPE_STRING:
+                $xmlrpc_val = new IPF_XmlRpc_Value_String($value);
+                break;
+            case self::XMLRPC_TYPE_DATETIME:  // The value should already be in a iso8601 format
+                $xmlrpc_val = new IPF_XmlRpc_Value_DateTime($value);
+                break;
+            case self::XMLRPC_TYPE_BASE64:    // The value should already be base64 encoded
+                $xmlrpc_val = new IPF_XmlRpc_Value_Base64($value ,true);
+                break;
+            case self::XMLRPC_TYPE_NIL:    // The value should always be NULL
+                $xmlrpc_val = new IPF_XmlRpc_Value_Nil();
+                break;
+            case self::XMLRPC_TYPE_ARRAY:
+                // If the XML is valid, $value must be an SimpleXML element and contain the <data> tag
+                if (!$value instanceof SimpleXMLElement) {
+                    throw new IPF_Exception('XML string is invalid for XML-RPC native '. self::XMLRPC_TYPE_ARRAY .' type');
+                } 
+
+                // PHP 5.2.4 introduced a regression in how empty($xml->value) 
+                // returns; need to look for the item specifically
+                $data = null;
+                foreach ($value->children() as $key => $value) {
+                    if ('data' == $key) {
+                        $data = $value;
+                        break;
+                    }
+                }
+                
+                if (null === $data) {
+                    throw new IPF_Exception('Invalid XML for XML-RPC native '. self::XMLRPC_TYPE_ARRAY .' type: ARRAY tag must contain DATA tag');
+                }
+                $values = array();
+                // Parse all the elements of the array from the XML string
+                // (simple xml element) to IPF_XmlRpc_Value objects
+                foreach ($data->value as $element) {
+                    $values[] = self::_xmlStringToNativeXmlRpc($element);
+                }
+                $xmlrpc_val = new IPF_XmlRpc_Value_Array($values);
+                break;
+            case self::XMLRPC_TYPE_STRUCT:
+                // If the XML is valid, $value must be an SimpleXML
+                if ((!$value instanceof SimpleXMLElement)) {
+                    throw new IPF_Exception('XML string is invalid for XML-RPC native '. self::XMLRPC_TYPE_STRUCT .' type');
+                }
+                $values = array();
+                // Parse all the memebers of the struct from the XML string
+                // (simple xml element) to IPF_XmlRpc_Value objects
+                foreach ($value->member as $member) {
+                    // @todo? If a member doesn't have a <value> tag, we don't add it to the struct
+                    // Maybe we want to throw an exception here ?
+                    if ((!$member->value instanceof SimpleXMLElement) || empty($member->value)) {
+                        continue;
+                        //throw new IPF_XmlRpc_Value_Exception('Member of the '. self::XMLRPC_TYPE_STRUCT .' XML-RPC native type must contain a VALUE tag');
+                    }
+                    $values[(string)$member->name] = self::_xmlStringToNativeXmlRpc($member->value);
+                }
+                $xmlrpc_val = new IPF_XmlRpc_Value_Struct($values);
+                break;
+            default:
+                throw new IPF_Exception('Value type \''. $type .'\' parsed from the XML string is not a known XML-RPC native type');
+                break;
+        }
+        $xmlrpc_val->_setXML($simple_xml->asXML());
+
+        return $xmlrpc_val;
+    }
+
+    private function _setXML($xml)
+    {
+        $this->_as_xml = $xml;
+    }
+
+}
+
+
diff --git a/xmlrpc/value/array.php b/xmlrpc/value/array.php
new file mode 100644 (file)
index 0000000..ead3419
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+
+class IPF_XmlRpc_Value_Array extends IPF_XmlRpc_Value_Collection
+{
+    public function __construct($value)
+    {
+        $this->_type = self::XMLRPC_TYPE_ARRAY;
+        parent::__construct($value);
+    }
+
+    public function saveXML()
+    {
+        if (!$this->_as_xml) {   // The XML code was not calculated yet
+            $dom   = new DOMDocument('1.0');
+            $value = $dom->appendChild($dom->createElement('value'));
+            $array = $value->appendChild($dom->createElement('array'));
+            $data  = $array->appendChild($dom->createElement('data'));
+
+            if (is_array($this->_value)) {
+                foreach ($this->_value as $val) {
+                    /* @var $val IPF_XmlRpc_Value */
+                    $data->appendChild($dom->importNode($val->getAsDOM(), true));
+                }
+            }
+
+            $this->_as_dom = $value;
+            $this->_as_xml = $this->_stripXmlDeclaration($dom);
+        }
+
+        return $this->_as_xml;
+    }
+}
+
diff --git a/xmlrpc/value/base64.php b/xmlrpc/value/base64.php
new file mode 100644 (file)
index 0000000..0583f9f
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+
+class IPF_XmlRpc_Value_Base64 extends IPF_XmlRpc_Value_Scalar
+{
+    public function __construct($value, $already_encoded=false)
+    {
+        $this->_type = self::XMLRPC_TYPE_BASE64;
+
+        $value = (string)$value;    // Make sure this value is string
+        if (!$already_encoded) {
+            $value = base64_encode($value);     // We encode it in base64
+        }
+        $this->_value = $value;
+    }
+
+    public function getValue()
+    {
+        return base64_decode($this->_value);
+    }
+
+    public function saveXML()
+    {
+        if (! $this->_as_xml) {   // The XML was not generated yet
+            $dom   = new DOMDocument('1.0', 'UTF-8');
+            $value = $dom->appendChild($dom->createElement('value'));
+            $type  = $value->appendChild($dom->createElement($this->_type));
+            $type->appendChild($dom->createTextNode($this->_value));
+
+            $this->_as_dom = $value;
+            $this->_as_xml = $this->_stripXmlDeclaration($dom);
+        }
+
+        return $this->_as_xml;
+    }
+}
+
diff --git a/xmlrpc/value/boolean.php b/xmlrpc/value/boolean.php
new file mode 100644 (file)
index 0000000..c0cf52c
--- /dev/null
@@ -0,0 +1,31 @@
+<?php
+
+class IPF_XmlRpc_Value_Boolean extends IPF_XmlRpc_Value_Scalar
+{
+    public function __construct($value)
+    {
+        $this->_type = self::XMLRPC_TYPE_BOOLEAN;
+        $this->_value = (int)(bool)$value;
+    }
+
+    public function getValue()
+    {
+        return (bool)$this->_value;
+    }
+
+    public function saveXML()
+    {
+        if (! $this->_as_xml) {   // The XML was not generated yet
+            $dom   = new DOMDocument('1.0', 'UTF-8');
+            $value = $dom->appendChild($dom->createElement('value'));
+            $type  = $value->appendChild($dom->createElement($this->_type));
+            $type->appendChild($dom->createTextNode($this->_value));
+
+            $this->_as_dom = $value;
+            $this->_as_xml = $this->_stripXmlDeclaration($dom);
+        }
+
+        return $this->_as_xml;
+    }
+}
+
diff --git a/xmlrpc/value/collection.php b/xmlrpc/value/collection.php
new file mode 100644 (file)
index 0000000..a720f10
--- /dev/null
@@ -0,0 +1,32 @@
+<?php
+
+abstract class IPF_XmlRpc_Value_Collection extends IPF_XmlRpc_Value
+{
+    public function __construct($value)
+    {
+        $values = (array)$value;   // Make sure that the value is an array
+        foreach ($values as $key => $value) {
+            // If the elements of the given array are not IPF_XmlRpc_Value objects,
+            // we need to convert them as such (using auto-detection from PHP value)
+            if (!$value instanceof parent) {
+                $value = self::getXmlRpcValue($value, self::AUTO_DETECT_TYPE);
+            }
+            $this->_value[$key] = $value;
+        }
+    }
+
+    public function getValue()
+    {
+        $values = (array)$this->_value;
+        foreach ($values as $key => $value) {
+            /* @var $value IPF_XmlRpc_Value */
+            if (!$value instanceof parent) {
+                throw new IPF_Exception('Values of '. get_class($this) .' type must be IPF_XmlRpc_Value objects');
+            }
+            $values[$key] = $value->getValue();
+        }
+        return $values;
+    }
+
+}
+
diff --git a/xmlrpc/value/datetime.php b/xmlrpc/value/datetime.php
new file mode 100644 (file)
index 0000000..569cd75
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+
+class IPF_XmlRpc_Value_DateTime extends IPF_XmlRpc_Value_Scalar
+{
+    public function __construct($value)
+    {
+        $this->_type = self::XMLRPC_TYPE_DATETIME;
+
+        // If the value is not numeric, we try to convert it to a timestamp (using the strtotime function)
+        if (is_numeric($value)) {   // The value is numeric, we make sure it is an integer
+            $value = (int)$value;
+        } else {
+            $value = strtotime($value);
+            if ($value === false || $value == -1) { // cannot convert the value to a timestamp
+                throw new IPF_Exception('Cannot convert given value \''. $value .'\' to a timestamp');
+            }
+        }
+        $value = date('c', $value); // Convert the timestamp to iso8601 format
+
+        // Strip out TZ information and dashes
+        $value = preg_replace('/(\+|-)\d{2}:\d{2}$/', '', $value);
+        $value = str_replace('-', '', $value);
+
+        $this->_value = $value;
+    }
+
+    public function getValue()
+    {
+        return $this->_value;
+    }
+
+}
+
diff --git a/xmlrpc/value/double.php b/xmlrpc/value/double.php
new file mode 100644 (file)
index 0000000..e0a8536
--- /dev/null
@@ -0,0 +1,17 @@
+<?php
+
+class IPF_XmlRpc_Value_Double extends IPF_XmlRpc_Value_Scalar
+{
+    public function __construct($value)
+    {
+        $this->_type = self::XMLRPC_TYPE_DOUBLE;
+        $this->_value = sprintf('%f',(float)$value);    // Make sure this value is float (double) and without the scientific notation
+    }
+
+    public function getValue()
+    {
+        return (float)$this->_value;
+    }
+
+}
+
diff --git a/xmlrpc/value/integer.php b/xmlrpc/value/integer.php
new file mode 100644 (file)
index 0000000..5de4c8d
--- /dev/null
@@ -0,0 +1,17 @@
+<?php
+
+class IPF_XmlRpc_Value_Integer extends IPF_XmlRpc_Value_Scalar
+{
+    public function __construct($value)
+    {
+        $this->_type = self::XMLRPC_TYPE_INTEGER;
+        $this->_value = (int)$value;    // Make sure this value is integer
+    }
+
+    public function getValue()
+    {
+        return $this->_value;
+    }
+
+}
+
diff --git a/xmlrpc/value/nil.php b/xmlrpc/value/nil.php
new file mode 100644 (file)
index 0000000..e04c670
--- /dev/null
@@ -0,0 +1,30 @@
+<?php
+
+class IPF_XmlRpc_Value_Nil extends IPF_XmlRpc_Value_Scalar
+{
+    public function __construct()
+    {
+        $this->_type = self::XMLRPC_TYPE_NIL;
+        $this->_value = null;
+    }
+
+    public function getValue()
+    {
+        return null;
+    }
+
+    public function saveXML()
+    {
+        if (! $this->_as_xml) {   // The XML was not generated yet
+            $dom   = new DOMDocument('1.0', 'UTF-8');
+            $value = $dom->appendChild($dom->createElement('value'));
+            $type  = $value->appendChild($dom->createElement($this->_type));
+
+            $this->_as_dom = $value;
+            $this->_as_xml = $this->_stripXmlDeclaration($dom);
+        }
+
+        return $this->_as_xml;
+    }
+}
+
diff --git a/xmlrpc/value/scalar.php b/xmlrpc/value/scalar.php
new file mode 100644 (file)
index 0000000..a950fb5
--- /dev/null
@@ -0,0 +1,20 @@
+<?php
+
+abstract class IPF_XmlRpc_Value_Scalar extends IPF_XmlRpc_Value
+{
+    public function saveXML()
+    {
+        if (!$this->_as_xml) {   // The XML code was not calculated yet
+            $dom   = new DOMDocument('1.0');
+            $value = $dom->appendChild($dom->createElement('value'));
+            $type  = $value->appendChild($dom->createElement($this->_type));
+            $type->appendChild($dom->createTextNode($this->getValue()));
+
+            $this->_as_dom = $value;
+            $this->_as_xml = $this->_stripXmlDeclaration($dom);
+        }
+
+        return $this->_as_xml;
+    }
+}
+
diff --git a/xmlrpc/value/string.php b/xmlrpc/value/string.php
new file mode 100644 (file)
index 0000000..635293a
--- /dev/null
@@ -0,0 +1,24 @@
+<?php
+
+class IPF_XmlRpc_Value_String extends IPF_XmlRpc_Value_Scalar
+{
+    public function __construct($value)
+    {
+        $this->_type = self::XMLRPC_TYPE_STRING;
+
+        // Make sure this value is string and all XML characters are encoded
+        $this->_value = $this->_xml_entities($value);
+    }
+
+    public function getValue()
+    {
+        return html_entity_decode($this->_value, ENT_QUOTES, 'UTF-8');
+    }
+
+    private function _xml_entities($str)
+    {
+        return htmlentities($str, ENT_QUOTES, 'UTF-8');
+    }
+
+}
+
diff --git a/xmlrpc/value/struct.php b/xmlrpc/value/struct.php
new file mode 100644 (file)
index 0000000..f6ed6ce
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+
+class IPF_XmlRpc_Value_Struct extends IPF_XmlRpc_Value_Collection
+{
+    public function __construct($value)
+    {
+        $this->_type = self::XMLRPC_TYPE_STRUCT;
+        parent::__construct($value);
+    }
+
+    public function saveXML()
+    {
+        if (!$this->_as_xml) {   // The XML code was not calculated yet
+            $dom    = new DOMDocument('1.0');
+            $value  = $dom->appendChild($dom->createElement('value'));
+            $struct = $value->appendChild($dom->createElement('struct'));
+
+            if (is_array($this->_value)) {
+                foreach ($this->_value as $name => $val) {
+                    /* @var $val IPF_XmlRpc_Value */
+                    $member = $struct->appendChild($dom->createElement('member'));
+                    $member->appendChild($dom->createElement('name', $name));
+                    $member->appendChild($dom->importNode($val->getAsDOM(), 1));
+                }
+            }
+
+            $this->_as_dom = $value;
+            $this->_as_xml = $this->_stripXmlDeclaration($dom);
+        }
+
+        return $this->_as_xml;
+    }
+}
+