OSDN Git Service

XML-RPC for PHP Unspecified PHP Code Execution Vulnerability
authorkimitake <kimitake@1ca29b6e-896d-4ea0-84a5-967f57386b96>
Tue, 16 Aug 2005 05:26:18 +0000 (05:26 +0000)
committerkimitake <kimitake@1ca29b6e-896d-4ea0-84a5-967f57386b96>
Tue, 16 Aug 2005 05:26:18 +0000 (05:26 +0000)
git-svn-id: https://svn.sourceforge.jp/svnroot/nucleus-jp/nucleus-jp/branches/branch-3-2@118 1ca29b6e-896d-4ea0-84a5-967f57386b96

euc/nucleus/libs/xmlrpc.inc.php
euc/nucleus/libs/xmlrpcs.inc.php
utf8/nucleus/libs/xmlrpc.inc.php
utf8/nucleus/libs/xmlrpcs.inc.php

index 83eb888..c0966ee 100755 (executable)
@@ -1,8 +1,8 @@
 <?php                                  // -*-c++-*-\r
 // by Edd Dumbill (C) 1999-2002\r
 // <edd@usefulinc.com>\r
-// $Id: xmlrpc.inc.php,v 1.4.2.2 2005-07-03 05:16:44 kimitake Exp $\r
-// $NucleusJP: xmlrpc.inc.php,v 1.4.2.1 2005/06/30 21:23:01 kimitake Exp $\r
+// $Id: xmlrpc.inc.php,v 1.4.2.3 2005-08-16 05:25:58 kimitake Exp $\r
+// $NucleusJP: xmlrpc.inc.php,v 1.4.2.2 2005/07/03 05:16:44 kimitake Exp $\r
 \r
 // Copyright (c) 1999,2000,2002 Edd Dumbill.\r
 // All rights reserved.\r
@@ -58,6 +58,7 @@
                global $xmlrpcI4;\r
                global $xmlrpcInt;\r
                global $xmlrpcDouble;\r
+               global $xmlrpcBoolean;\r
                global $xmlrpcString;\r
                global $xmlrpcDateTime;\r
                global $xmlrpcBase64;\r
                $xmlrpcStruct   => 3\r
        );\r
 \r
+       $xmlrpc_valid_parents = array(\r
+               'BOOLEAN' => array('VALUE'),\r
+               'I4' => array('VALUE'),\r
+               'INT' => array('VALUE'),\r
+               'STRING' => array('VALUE'),\r
+               'DOUBLE' => array('VALUE'),\r
+               'DATETIME.ISO8601' => array('VALUE'),\r
+               'BASE64' => array('VALUE'),\r
+               'ARRAY' => array('VALUE'),\r
+               'STRUCT' => array('VALUE'),\r
+               'PARAM' => array('PARAMS'),\r
+               'METHODNAME' => array('METHODCALL'),            \r
+               'PARAMS' => array('METHODCALL', 'METHODRESPONSE'),\r
+               'MEMBER' => array('STRUCT'),\r
+               'NAME' => array('MEMBER'),\r
+               'DATA' => array('ARRAY'),\r
+               'FAULT' => array('METHODRESPONSE'),\r
+               'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT'),\r
+       );\r
+\r
        $xmlEntities=array(\r
                'amp'  => '&',\r
                'quot' => '"',\r
        $xmlrpcstr['no_ssl']='No SSL support compiled in.';\r
        $xmlrpcerr['curl_fail']=8;\r
        $xmlrpcstr['curl_fail']='CURL error';\r
-\r
+       $xmlrpcerr['invalid_request']=15;\r
+       $xmlrpcstr['invalid_request']='Invalid request payload';\r
 \r
        $xmlrpcerr['multicall_notstruct'] = 9;\r
        $xmlrpcstr['multicall_notstruct'] = 'system.multicall expected struct';\r
        $xmlrpc_internalencoding='ISO-8859-1';\r
 \r
        $xmlrpcName='XML-RPC for PHP';\r
-       $xmlrpcVersion='1.1.1';\r
+       $xmlrpcVersion='1.2';\r
 \r
        // let user errors start at 800\r
        $xmlrpcerruser=800;\r
 \r
        // used to store state during parsing\r
        // quick explanation of components:\r
-       //   st - used to build up a string for evaluation\r
        //   ac - used to accumulate values\r
-       //   qt - used to decide if quotes are needed for evaluation\r
-       //   cm - used to denote struct or array (comma needed)\r
        //   isf - used to indicate a fault\r
        //   lv - used to indicate "looking for a value": implements\r
        //        the logic to allow values with no types to be strings\r
        //   params - used to store parameters in method calls\r
        //   method - used to store method name\r
+       //   stack - array with genealogy of xml elements names:\r
+       //           used to validate nesting of xmlrpc elements\r
 \r
        $_xh=array();\r
 \r
 \r
        function xmlrpc_se($parser, $name, $attrs)\r
        {\r
-               global $_xh, $xmlrpcDateTime, $xmlrpcString;\r
+               global $_xh, $xmlrpcDateTime, $xmlrpcString, $xmlrpc_valid_parents;\r
+\r
+               // if invalid xmlrpc already detected, skip all processing\r
+               if ($_xh[$parser]['isf'] < 2)\r
+               {\r
+\r
+               // check for correct element nesting\r
+               // top level element can only be of 2 types\r
+               if (count($_xh[$parser]['stack']) == 0)\r
+               {\r
+                       if ($name != 'METHODRESPONSE' && $name != 'METHODCALL')\r
+                       {\r
+                               $_xh[$parser]['isf'] = 2;\r
+                               $_xh[$parser]['isf_reason'] = 'missing top level xmlrpc element';\r
+                               return;\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       // not top level element: see if parent is OK\r
+                       if (!in_array($_xh[$parser]['stack'][0], $xmlrpc_valid_parents[$name]))\r
+                       {\r
+                               $_xh[$parser]['isf'] = 2;\r
+                               $_xh[$parser]['isf_reason'] = "xmlrpc element $name cannot be child of {$_xh[$parser]['stack'][0]}";\r
+                               return;\r
+                       }\r
+               }\r
 \r
                switch($name)\r
                {\r
                        case 'STRUCT':\r
                        case 'ARRAY':\r
-                               $_xh[$parser]['st'].='array(';\r
-                               $_xh[$parser]['cm']++;\r
+                               //$_xh[$parser]['st'].='array(';\r
+                               //$_xh[$parser]['cm']++;\r
                                // this last line turns quoting off\r
                                // this means if we get an empty array we'll\r
                                // simply get a bit of whitespace in the eval\r
-                               $_xh[$parser]['qt']=0;\r
+                               //$_xh[$parser]['qt']=0;\r
+\r
+                               // create an empty array to hold child values, and push it onto appropriate stack\r
+                               $cur_val = array();\r
+                               $cur_val['values'] = array();\r
+                               $cur_val['type'] = $name;\r
+                               array_unshift($_xh[$parser]['valuestack'], $cur_val);\r
                                break;\r
+                       case 'METHODNAME':\r
                        case 'NAME':\r
-                               $_xh[$parser]['st'].='"';\r
+                               //$_xh[$parser]['st'].='"';\r
                                $_xh[$parser]['ac']='';\r
                                break;\r
                        case 'FAULT':\r
                                $_xh[$parser]['isf']=1;\r
                                break;\r
                        case 'PARAM':\r
-                               $_xh[$parser]['st']='';\r
+                               //$_xh[$parser]['st']='';\r
+                               // clear value, so we can check later if no value will passed for this param/member\r
+                               $_xh[$parser]['value']=null;\r
                                break;\r
                        case 'VALUE':\r
-                               $_xh[$parser]['st'].='new xmlrpcval(';\r
-                               $_xh[$parser]['vt']=$xmlrpcString;\r
+                               //$_xh[$parser]['st'].='new xmlrpcval(';\r
+                               // look for a value: if this is still true by the\r
+                               // time we reach the end tag for value then the type is string\r
+                               // by implication\r
+                               $_xh[$parser]['vt']='value';\r
                                $_xh[$parser]['ac']='';\r
-                               $_xh[$parser]['qt']=0;\r
+                               //$_xh[$parser]['qt']=0;\r
                                $_xh[$parser]['lv']=1;\r
-                               // look for a value: if this is still 1 by the\r
-                               // time we reach the first data segment then the type is string\r
-                               // by implication and we need to add in a quote\r
                                break;\r
                        case 'I4':\r
                        case 'INT':\r
                        case 'DOUBLE':\r
                        case 'DATETIME.ISO8601':\r
                        case 'BASE64':\r
-                               $_xh[$parser]['ac']=''; // reset the accumulator\r
+                               if ($_xh[$parser]['vt']!='value')\r
+                               {\r
+                                       //two data elements inside a value: an error occurred!\r
+                                       $_xh[$parser]['isf'] = 2;\r
+                                       $_xh[$parser]['isf_reason'] = "$name element following a {$_xh[$parser]['vt']} element inside a single value";\r
+                                       return;\r
+                               }\r
+\r
+                               // reset the accumulator\r
+                               $_xh[$parser]['ac']='';\r
 \r
-                               if ($name=='DATETIME.ISO8601' || $name=='STRING')\r
+                               /*if ($name=='DATETIME.ISO8601' || $name=='STRING')\r
                                {\r
                                        $_xh[$parser]['qt']=1;\r
                                        if ($name=='DATETIME.ISO8601')\r
                                        // at the end of the element we must check\r
                                        // for data format errors.\r
                                        $_xh[$parser]['qt']=0;\r
-                               }\r
+                               }*/\r
                                break;\r
                        case 'MEMBER':\r
-                               $_xh[$parser]['ac']='';\r
+                               //$_xh[$parser]['ac']='';\r
+                               // avoid warnings later on if no NAME is found before VALUE inside\r
+                               // a struct member predefining member name as NULL\r
+                               $_xh[$parser]['valuestack'][0]['name'] = '';\r
+                               // clear value, so we can check later if no value will passed for this param/member\r
+                               $_xh[$parser]['value']=null;\r
+                               break;\r
+                       case 'DATA':\r
+                       case 'METHODCALL':\r
+                       case 'METHODRESPONSE':\r
+                       case 'PARAMS':\r
+                               // valid elements that add little to processing\r
                                break;\r
                        default:\r
+                               /// INVALID ELEMENT: RAISE ISF so that it is later recognized!!!\r
+                               $_xh[$parser]['isf'] = 2;\r
+                               $_xh[$parser]['isf_reason'] = "found not-xmlrpc xml element $name";\r
                                break;\r
                }\r
 \r
+               // Save current element name to stack, to validate nesting\r
+               array_unshift($_xh[$parser]['stack'], $name);\r
+\r
                if ($name!='VALUE')\r
                {\r
                        $_xh[$parser]['lv']=0;\r
                }\r
        }\r
+       }\r
 \r
        function xmlrpc_ee($parser, $name)\r
        {\r
-               global $_xh,$xmlrpcTypes,$xmlrpcString;\r
+               global $_xh,$xmlrpcTypes,$xmlrpcString,$xmlrpcDateTime;\r
+\r
+               if ($_xh[$parser]['isf'] < 2)\r
+               {\r
+\r
+               // push this element name from stack\r
+               // NB: if XML validates, correct opening/closing is guaranteed and\r
+               // we do not have to check for $name == $curr_elem.\r
+               // we also checked for proper nesting at start of elements...\r
+               $curr_elem = array_shift($_xh[$parser]['stack']);               \r
 \r
                switch($name)\r
                {\r
                        case 'STRUCT':\r
                        case 'ARRAY':\r
-                               if ($_xh[$parser]['cm'] && substr($_xh[$parser]['st'], -1) ==',')\r
-                               {\r
-                                       $_xh[$parser]['st']=substr($_xh[$parser]['st'],0,-1);\r
-                               }\r
-                               $_xh[$parser]['st'].=')';\r
+                               //if ($_xh[$parser]['cm'] && substr($_xh[$parser]['st'], -1) ==',')\r
+                               //{\r
+                               //      $_xh[$parser]['st']=substr($_xh[$parser]['st'],0,-1);\r
+                               //}\r
+                               //$_xh[$parser]['st'].=')';\r
+\r
+                               // fetch out of stack array of values, and promote it to current value\r
+                               $cur_val = array_shift($_xh[$parser]['valuestack']);\r
+                               $_xh[$parser]['value'] = $cur_val['values'];\r
+\r
                                $_xh[$parser]['vt']=strtolower($name);\r
-                               $_xh[$parser]['cm']--;\r
+                               //$_xh[$parser]['cm']--;\r
                                break;\r
                        case 'NAME':\r
-                               $_xh[$parser]['st'].= $_xh[$parser]['ac'] . '" => ';\r
+                               //$_xh[$parser]['st'].= $_xh[$parser]['ac'] . '" => ';\r
+                               $_xh[$parser]['valuestack'][0]['name'] = $_xh[$parser]['ac'];\r
                                break;\r
                        case 'BOOLEAN':\r
-                               // special case here: we translate boolean 1 or 0 into PHP\r
-                               // constants true or false\r
-                               // NB: this simple checks helps a lot sanitizing input, ie no\r
-                               // security problems around here\r
-                               if ($_xh[$parser]['ac']=='1')\r
-                               {\r
-                                       $_xh[$parser]['ac']='true';\r
-                               }\r
-                               else\r
-                               {\r
-                                       $_xh[$parser]['ac']='false';\r
-                               }\r
-                               $_xh[$parser]['vt']=strtolower($name);\r
-                               // Drop through intentionally.\r
                        case 'I4':\r
                        case 'INT':\r
                        case 'STRING':\r
                        case 'DOUBLE':\r
                        case 'DATETIME.ISO8601':\r
                        case 'BASE64':\r
-                               if ($_xh[$parser]['qt']==1)\r
+                               $_xh[$parser]['vt']=strtolower($name);\r
+                               //if ($_xh[$parser]['qt']==1)                   \r
+                               if ($name=='STRING')\r
                                {\r
                                        // we use double quotes rather than single so backslashification works OK\r
-                                       $_xh[$parser]['st'].='"'. $_xh[$parser]['ac'] . '"';\r
+                                       //$_xh[$parser]['st'].='"'. $_xh[$parser]['ac'] . '"';\r
+                                       $_xh[$parser]['value']=$_xh[$parser]['ac'];\r
+                               }\r
+                               elseif ($name=='DATETIME.ISO8601')\r
+                               {\r
+                                       $_xh[$parser]['vt']=$xmlrpcDateTime;\r
+                                       $_xh[$parser]['value']=$_xh[$parser]['ac'];\r
                                }\r
-                               elseif ($_xh[$parser]['qt']==2)\r
+                               elseif ($name=='BASE64')\r
                                {\r
-                                       $_xh[$parser]['st'].='base64_decode("'. $_xh[$parser]['ac'] . '")';\r
+                                       //$_xh[$parser]['st'].='base64_decode("'. $_xh[$parser]['ac'] . '")';\r
+\r
+                                       ///@todo check for failure of base64 decoding / catch warnings\r
+                                       $_xh[$parser]['value']=base64_decode($_xh[$parser]['ac']);\r
                                }\r
                                elseif ($name=='BOOLEAN')\r
                                {\r
-                                       $_xh[$parser]['st'].=$_xh[$parser]['ac'];\r
+                                       // special case here: we translate boolean 1 or 0 into PHP\r
+                                       // constants true or false\r
+                                       // NB: this simple checks helps a lot sanitizing input, ie no\r
+                                       // security problems around here\r
+                                       if ($_xh[$parser]['ac']=='1')\r
+                                       {\r
+                                               //$_xh[$parser]['ac']='true';   \r
+                                               $_xh[$parser]['value']=true;\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               //$_xh[$parser]['ac']='false';\r
+                                               // log if receiveing something strange, even though we set the value to false anyway\r
+                                               if ($_xh[$parser]['ac']!='0')\r
+                                                       error_log('XML-RPC: invalid value received in BOOLEAN: '.$_xh[$parser]['ac']);\r
+                                               $_xh[$parser]['value']=false;\r
+                                       }\r
+                                       //$_xh[$parser]['st'].=$_xh[$parser]['ac'];\r
                                }\r
                                elseif ($name=='DOUBLE')\r
                                {\r
                                                // TODO: find a better way of throwing an error\r
                                                // than this!\r
                                                error_log('XML-RPC: non numeric value received in DOUBLE: '.$_xh[$parser]['ac']);\r
-                                               $_xh[$parser]['st'].="'ERROR_NON_NUMERIC_FOUND'";\r
+                                               //$_xh[$parser]['st'].="'ERROR_NON_NUMERIC_FOUND'";\r
+                                               $_xh[$parser]['value']='ERROR_NON_NUMERIC_FOUND';\r
                                        }\r
                                        else\r
                                        {\r
                                                // it's ok, add it on\r
-                                               $_xh[$parser]['st'].=(double)$_xh[$parser]['ac'];\r
+                                               //$_xh[$parser]['st'].=(double)$_xh[$parser]['ac'];\r
+                                               $_xh[$parser]['value']=(double)$_xh[$parser]['ac'];\r
                                        }\r
                                }\r
                                else\r
                                                // TODO: find a better way of throwing an error\r
                                                // than this!\r
                                                error_log('XML-RPC: non numeric value received in INT: '.$_xh[$parser]['ac']);\r
-                                               $_xh[$parser]['st'].="'ERROR_NON_NUMERIC_FOUND'";\r
+                                               //$_xh[$parser]['st'].="'ERROR_NON_NUMERIC_FOUND'";\r
+                                               $_xh[$parser]['value']='ERROR_NON_NUMERIC_FOUND';\r
                                        }\r
                                        else\r
                                        {\r
                                                // it's ok, add it on\r
-                                               $_xh[$parser]['st'].=(int)$_xh[$parser]['ac'];\r
+                                               //$_xh[$parser]['st'].=(int)$_xh[$parser]['ac'];\r
+                                               $_xh[$parser]['value']=(int)$_xh[$parser]['ac'];\r
                                        }\r
                                }\r
                                $_xh[$parser]['ac']='';\r
-                               $_xh[$parser]['qt']=0;\r
+                               //$_xh[$parser]['qt']=0;\r
                                $_xh[$parser]['lv']=3; // indicate we've found a value\r
                                break;\r
                        case 'VALUE':\r
-                               // deal with a string value\r
-                               if (strlen($_xh[$parser]['ac'])>0 &&\r
+                               // This if() detects if no scalar was inside <VALUE></VALUE>\r
+                               if ($_xh[$parser]['vt']=='value')\r
+                               {\r
+                                       $_xh[$parser]['value']=$_xh[$parser]['ac'];\r
+                                       $_xh[$parser]['vt']=$xmlrpcString;\r
+                               }\r
+                               /*if (strlen($_xh[$parser]['ac'])>0 &&\r
                                        $_xh[$parser]['vt']==$xmlrpcString)\r
                                {\r
                                        $_xh[$parser]['st'].='"'. $_xh[$parser]['ac'] . '"';\r
                                if ($_xh[$parser]['cm'])\r
                                {\r
                                        $_xh[$parser]['st'].=',';\r
+                               }*/\r
+\r
+                               // build the xmlrpc val out of the data received, and substitute it\r
+                               $temp = new xmlrpcval($_xh[$parser]['value'], $_xh[$parser]['vt']);\r
+                               // check if we are inside an array or struct:\r
+                               // if value just built is inside an array, let's move it into array on the stack\r
+                               if (count($_xh[$parser]['valuestack']) && $_xh[$parser]['valuestack'][0]['type']=='ARRAY')\r
+                               {\r
+                                       $_xh[$parser]['valuestack'][0]['values'][] = $temp;\r
+                               }\r
+                               else\r
+                               {\r
+                               $_xh[$parser]['value'] = $temp;\r
                                }\r
                                break;\r
                        case 'MEMBER':\r
                                $_xh[$parser]['ac']='';\r
-                               $_xh[$parser]['qt']=0;\r
+                               //$_xh[$parser]['qt']=0;\r
+                               // add to array in the stack the last element built\r
+                               // unless no VALUE was found\r
+                               if ($_xh[$parser]['value'])\r
+                                       $_xh[$parser]['valuestack'][0]['values'][$_xh[$parser]['valuestack'][0]['name']] = $_xh[$parser]['value'];\r
+                               else\r
+                                       error_log('XML-RPC: missing VALUE inside STRUCT in received xml');\r
                                break;\r
                        case 'DATA':\r
                                $_xh[$parser]['ac']='';\r
-                               $_xh[$parser]['qt']=0;\r
+                               //$_xh[$parser]['qt']=0;\r
                                break;\r
                        case 'PARAM':\r
-                               $_xh[$parser]['params'][]=$_xh[$parser]['st'];\r
+                               //$_xh[$parser]['params'][]=$_xh[$parser]['st'];\r
+                               if ($_xh[$parser]['value'])\r
+                                       $_xh[$parser]['params'][]=$_xh[$parser]['value'];\r
+                               else\r
+                                       error_log('XML-RPC: missing VALUE inside PARAM in received xml');\r
                                break;\r
                        case 'METHODNAME':\r
                                $_xh[$parser]['method']=ereg_replace("^[\n\r\t ]+", '', $_xh[$parser]['ac']);\r
                                break;\r
-                       // BOOLEAN HAS BEEN ENUMERATED ABOVE!\r
-                       /*case 'BOOLEAN':\r
-                               // special case here: we translate boolean 1 or 0 into PHP\r
-                               // constants true or false\r
-                               if ($_xh[$parser]['ac']=='1')\r
-                               {\r
-                                       $_xh[$parser]['ac']='true';\r
-                               }\r
-                               else\r
-                               {\r
-                                       $_xh[$parser]['ac']='false';\r
-                                       $_xh[$parser]['vt']=strtolower($name);\r
-                               }\r
-                               break;*/\r
+                       case 'PARAMS':\r
+                       case 'FAULT':\r
+                       case 'METHODCALL':\r
+                       case 'METHORESPONSE':\r
+                               break;\r
                        default:\r
+                               // End of INVALID ELEMENT!\r
+                               // shall we add an assert here for unreachable code???\r
                                break;\r
                }\r
                // if it's a valid type name, set the type\r
-               if (isset($xmlrpcTypes[strtolower($name)]))\r
+               /*if (isset($xmlrpcTypes[strtolower($name)]))\r
                {\r
                        $_xh[$parser]['vt']=strtolower($name);\r
+               }*/\r
+\r
                }\r
        }\r
 \r
                //if (ereg("^[\n\r \t]+$", $data)) return;\r
                // print "adding [${data}]\n";\r
 \r
+               // skip processing if xml fault already detected\r
+               if ($_xh[$parser]['isf'] < 2)\r
+               {\r
                if ($_xh[$parser]['lv']!=3)\r
                {\r
                        // "lookforvalue==3" means that we've found an entire value\r
                        {\r
                                // if we've found text and we're just in a <value> then\r
                                // turn quoting on, as this will be a string\r
-                               $_xh[$parser]['qt']=1;\r
+                                       //$_xh[$parser]['qt']=1;\r
                                // and say we've found a value\r
                                $_xh[$parser]['lv']=2;\r
                        }\r
                        {\r
                                $_xh[$parser]['ac'] = '';\r
                        }\r
-                       $_xh[$parser]['ac'].=str_replace('$', '\$', str_replace('"', '\"', str_replace(chr(92),$xmlrpc_backslash, $data)));\r
+                               //$_xh[$parser]['ac'].=str_replace('$', '\$', str_replace('"', '\"', str_replace(chr(92),$xmlrpc_backslash, $data)));\r
+                               $_xh[$parser]['ac'].=$data;\r
+                       }\r
                }\r
        }\r
 \r
        function xmlrpc_dh($parser, $data)\r
        {\r
                global $_xh, $xmlrpc_backslash;\r
+\r
+               // skip processing if xml fault already detected\r
+               if ($parser[$_xh]['isf'] < 2)\r
+               {\r
                if (substr($data, 0, 1) == '&' && substr($data, -1, 1) == ';')\r
                {\r
                        if ($_xh[$parser]['lv']==1)\r
                        {\r
-                               $_xh[$parser]['qt']=1;\r
+                                       //$_xh[$parser]['qt']=1;\r
                                $_xh[$parser]['lv']=2;\r
                        }\r
-                       $_xh[$parser]['ac'].=str_replace('$', '\$', str_replace('"', '\"', str_replace(chr(92),$xmlrpc_backslash, $data)));\r
+                               //$_xh[$parser]['ac'].=str_replace('$', '\$', str_replace('"', '\"', str_replace(chr(92),$xmlrpc_backslash, $data)));\r
+                               $_xh[$parser]['ac'].=$data;\r
+                       }\r
                }\r
        }\r
 \r
 \r
                function serialize()\r
                {\r
-                       global $xmlrpc_defencoding;\r
                        $result = "<methodResponse>\n";\r
                        if ($this->errno)\r
                        {\r
 </member>\r
 <member>\r
 <name>faultString</name>\r
-<value><string>' . mb_convert_encoding(xmlrpc_encode_entitites($this->errstr), $xmlrpc_defencoding, _CHARSET) . '</string></value>\r
+<value><string>' . xmlrpc_encode_entitites($this->errstr) . '</string></value>\r
 </member>\r
 </struct>\r
 </value>\r
                        $_xh=array();\r
                        $_xh[$parser]=array();\r
                        $_xh[$parser]['headers'] = array();\r
+                       $_xh[$parser]['stack'] = array();\r
+                       $_xh[$parser]['valuestack'] = array();\r
 \r
                        // separate HTTP headers from data\r
                        if (ereg("^HTTP", $data))\r
                        if ($bd)\r
                                $data = substr($data, 0, $bd);\r
 \r
-                       $_xh[$parser]['st']='';\r
-                       $_xh[$parser]['cm']=0;\r
+                       //$_xh[$parser]['st']='';\r
+                       //$_xh[$parser]['cm']=0;\r
                        $_xh[$parser]['isf']=0;\r
+                       $_xh[$parser]['isf_reason']=0;\r
                        $_xh[$parser]['ac']='';\r
-                       $_xh[$parser]['qt']='';\r
+                       //$_xh[$parser]['qt']='';\r
 \r
                        xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);\r
                        // G. Giunta 2005/02/13: PHP internally uses ISO-8859-1, so we have to tell\r
                                return $r;\r
                        }\r
                        xml_parser_free($parser);\r
+\r
+                       if ($_xh[$parser]['isf'] > 1)\r
+                       {\r
                        if ($this->debug)\r
                        {\r
-                               print "<PRE>---EVALING---[" .\r
-                               strlen($_xh[$parser]['st']) . " chars]---\n" .\r
-                               htmlspecialchars($_xh[$parser]['st']) . ";\n---END---</PRE>";\r
+                                       ///@todo echo something for user?\r
+                               }\r
+\r
+                               $r = new xmlrpcresp(0, $xmlrpcerr['invalid_return'],\r
+                               $xmlrpcstr['invalid_return'] . ' ' . $_xh[$parser]['isf_reason']);\r
                        }\r
-                       if (strlen($_xh[$parser]['st'])==0)\r
+                       //else if (strlen($_xh[$parser]['st'])==0)\r
+                       else if (!is_object($_xh[$parser]['value']))\r
                        {\r
                                // then something odd has happened\r
                                // and it's time to generate a client side error\r
                        }\r
                        else\r
                        {\r
-                               $allOK=0;\r
-                               @eval('$v=' . $_xh[$parser]['st'] . '; $allOK=1;');\r
-                               if (!$allOK)\r
+\r
+                               if ($this->debug)\r
                                {\r
-                                       $r = new xmlrpcresp(0, $xmlrpcerr['invalid_return'], $xmlrpcstr['invalid_return']);\r
+                                       //print "<PRE>---EVALING---[" .\r
+                                       //strlen($_xh[$parser]['st']) . " chars]---\n" .\r
+                                       //htmlspecialchars($_xh[$parser]['st']) . ";\n---END---</PRE>";\r
+                                       print "<PRE>---PARSED---\n" ;\r
+                                       var_dump($_xh[$parser]['value']);\r
+                                       print "\n---END---</PRE>";\r
                                }\r
-                               else\r
+\r
+                               //$allOK=0;\r
+                               //@eval('$v=' . $_xh[$parser]['st'] . '; $allOK=1;');\r
+                               //if (!$allOK)\r
+                               //{\r
+                               //      $r = new xmlrpcresp(0, $xmlrpcerr['invalid_return'], $xmlrpcstr['invalid_return']);\r
+                               //}\r
+                               //else\r
+                               $v = $_xh[$parser]['value'];\r
                                if ($_xh[$parser]['isf'])\r
                                {\r
                                        $errno_v = $v->structmem('faultCode');\r
 \r
                function addScalar($val, $type='string')\r
                {\r
-                       global $xmlrpcTypes, $xmlrpcBoolean, $xmlrpc_defencoding;\r
+                       global $xmlrpcTypes, $xmlrpcBoolean;\r
 \r
                        if ($this->mytype==1)\r
                        {\r
                {\r
                        $rs='';\r
                        global $xmlrpcTypes, $xmlrpcBase64, $xmlrpcString,\r
-                       $xmlrpcBoolean, $xmlrpc_defencoding;\r
+                       $xmlrpcBoolean;\r
                        switch(@$xmlrpcTypes[$typ])\r
                        {\r
                                case 3:\r
                                                        // $rs.="<${typ}>" . htmlentities($val). "</${typ}>";\r
                                                        \r
                                                        // N. Leenheer 2005/6/30: Use CDATA instead... \r
-                                                       $rs.="<${typ}><![CDATA[" . mb_convert_encoding($val, $xmlrpc_defencoding, _CHARSET). "]]></${typ}>";\r
+                                                       $rs.="<${typ}><![CDATA[" . $val. "]]></${typ}>";\r
                                                        break;\r
                                                default:\r
                                                        $rs.="<${typ}>${val}</${typ}>";\r
                                @reset($t);\r
                                while(list($id,$cont) = @each($t))\r
                                {\r
-                                       eval('$b->'.$id.' = $cont;');\r
+                                       //eval('$b->'.$id.' = $cont;');\r
+                                       @$b->$id = $cont;\r
                                }\r
                        }\r
                        // end contrib\r
index 761dc47..87a8687 100755 (executable)
@@ -1,8 +1,8 @@
 <?php\r
 // by Edd Dumbill (C) 1999-2002\r
 // <edd@usefulinc.com>\r
-// $Id: xmlrpcs.inc.php,v 1.4.2.1 2005-06-30 21:23:01 kimitake Exp $\r
-// $NucleusJP$\r
+// $Id: xmlrpcs.inc.php,v 1.4.2.2 2005-08-16 05:25:58 kimitake Exp $\r
+// $NucleusJP: xmlrpcs.inc.php,v 1.4.2.1 2005/06/30 21:23:01 kimitake Exp $\r
 \r
 // Copyright (c) 1999,2000,2002 Edd Dumbill.\r
 // All rights reserved.\r
                        $parser = xml_parser_create($xmlrpc_defencoding);\r
 \r
                        $_xh[$parser]=array();\r
-                       $_xh[$parser]['st']='';\r
-                       $_xh[$parser]['cm']=0;\r
+                       //$_xh[$parser]['st']='';\r
+                       //$_xh[$parser]['cm']=0;\r
                        $_xh[$parser]['isf']=0;\r
+                       $_xh[$parser]['isf_reason']='';\r
                        $_xh[$parser]['params']=array();\r
+                       $_xh[$parser]['stack']=array();\r
+                       $_xh[$parser]['valuestack'] = array();\r
                        $_xh[$parser]['method']='';\r
 \r
                        // decompose incoming XML into request structure\r
                                xml_parser_free($parser);\r
                        }\r
                        else\r
+                       if ($_xh[$parser]['isf'])\r
                        {\r
                                xml_parser_free($parser);\r
+                               $r=new xmlrpcresp(0,\r
+                                       $xmlrpcerr['invalid_request'],\r
+                                       $xmlrpcstr['invalid_request'] . ' ' . $_xh[$parser]['isf_reason']);\r
+                       }\r
+                       else\r
+                       {\r
+                               xml_parser_free($parser);\r
+\r
                                $m=new xmlrpcmsg($_xh[$parser]['method']);\r
                                // now add parameters in\r
                                $plist='';\r
-                               $allOK = 1;\r
+                               //$allOK = 1;\r
                                for($i=0; $i<sizeof($_xh[$parser]['params']); $i++)\r
                                {\r
                                        //print "<!-- " . $_xh[$parser]['params'][$i]. "-->\n";\r
                                        $plist.="$i - " .  $_xh[$parser]['params'][$i]. ";\n";\r
-                                       $allOK = 0;\r
-                                       @eval('$m->addParam(' . $_xh[$parser]['params'][$i]. '); $allOK=1;');\r
-                                       if (!$allOK)\r
-                                       {\r
-                                               break;\r
-                                       }\r
+                                       //$allOK = 0;\r
+                                       //@eval('$m->addParam(' . $_xh[$parser]['params'][$i]. '); $allOK=1;');\r
+                                       @$m->addParam($_xh[$parser]['params'][$i]);\r
+                                       //if (!$allOK)\r
+                                       //{\r
+                                       //      break;\r
+                                       //}\r
                                }\r
                                // uncomment this to really see what the server's getting!\r
                                // xmlrpc_debugmsg($plist);\r
-                               if (!$allOK)\r
-                               {\r
-                                       $r = new xmlrpcresp(0,\r
-                                               $xmlrpcerr['incorrect_params'],\r
-                                               $xmlrpcstr['incorrect_params'] . ": xml error in param " . $i);\r
-                               }\r
-                               else\r
-                               {\r
+                               //if (!$allOK)\r
+                               //{\r
+                               //      $r = new xmlrpcresp(0,\r
+                               //              $xmlrpcerr['incorrect_params'],\r
+                               //              $xmlrpcstr['incorrect_params'] . ": xml error in param " . $i);\r
+                               //}\r
+                               //else\r
+                               //{\r
                                        $r = $this->execute($m);\r
-                               }\r
+                               //}\r
                        }\r
                        return $r;\r
                }\r
index 93ef2f1..df3dce7 100755 (executable)
@@ -1,8 +1,8 @@
 <?php                                  // -*-c++-*-\r
 // by Edd Dumbill (C) 1999-2002\r
 // <edd@usefulinc.com>\r
-// $Id: xmlrpc.inc.php,v 1.4.4.1 2005-06-30 21:19:18 kimitake Exp $\r
-// $NucleusJP$\r
+// $Id: xmlrpc.inc.php,v 1.4.4.2 2005-08-16 05:26:18 kimitake Exp $\r
+// $NucleusJP: xmlrpc.inc.php,v 1.4.2.2 2005/07/03 05:16:44 kimitake Exp $\r
 \r
 // Copyright (c) 1999,2000,2002 Edd Dumbill.\r
 // All rights reserved.\r
@@ -58,6 +58,7 @@
                global $xmlrpcI4;\r
                global $xmlrpcInt;\r
                global $xmlrpcDouble;\r
+               global $xmlrpcBoolean;\r
                global $xmlrpcString;\r
                global $xmlrpcDateTime;\r
                global $xmlrpcBase64;\r
                $xmlrpcStruct   => 3\r
        );\r
 \r
+       $xmlrpc_valid_parents = array(\r
+               'BOOLEAN' => array('VALUE'),\r
+               'I4' => array('VALUE'),\r
+               'INT' => array('VALUE'),\r
+               'STRING' => array('VALUE'),\r
+               'DOUBLE' => array('VALUE'),\r
+               'DATETIME.ISO8601' => array('VALUE'),\r
+               'BASE64' => array('VALUE'),\r
+               'ARRAY' => array('VALUE'),\r
+               'STRUCT' => array('VALUE'),\r
+               'PARAM' => array('PARAMS'),\r
+               'METHODNAME' => array('METHODCALL'),            \r
+               'PARAMS' => array('METHODCALL', 'METHODRESPONSE'),\r
+               'MEMBER' => array('STRUCT'),\r
+               'NAME' => array('MEMBER'),\r
+               'DATA' => array('ARRAY'),\r
+               'FAULT' => array('METHODRESPONSE'),\r
+               'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT'),\r
+       );\r
+\r
        $xmlEntities=array(\r
                'amp'  => '&',\r
                'quot' => '"',\r
        $xmlrpcstr['no_ssl']='No SSL support compiled in.';\r
        $xmlrpcerr['curl_fail']=8;\r
        $xmlrpcstr['curl_fail']='CURL error';\r
-\r
+       $xmlrpcerr['invalid_request']=15;\r
+       $xmlrpcstr['invalid_request']='Invalid request payload';\r
 \r
        $xmlrpcerr['multicall_notstruct'] = 9;\r
        $xmlrpcstr['multicall_notstruct'] = 'system.multicall expected struct';\r
        $xmlrpc_internalencoding='ISO-8859-1';\r
 \r
        $xmlrpcName='XML-RPC for PHP';\r
-       $xmlrpcVersion='1.1.1';\r
+       $xmlrpcVersion='1.2';\r
 \r
        // let user errors start at 800\r
        $xmlrpcerruser=800;\r
 \r
        // used to store state during parsing\r
        // quick explanation of components:\r
-       //   st - used to build up a string for evaluation\r
        //   ac - used to accumulate values\r
-       //   qt - used to decide if quotes are needed for evaluation\r
-       //   cm - used to denote struct or array (comma needed)\r
        //   isf - used to indicate a fault\r
        //   lv - used to indicate "looking for a value": implements\r
        //        the logic to allow values with no types to be strings\r
        //   params - used to store parameters in method calls\r
        //   method - used to store method name\r
+       //   stack - array with genealogy of xml elements names:\r
+       //           used to validate nesting of xmlrpc elements\r
 \r
        $_xh=array();\r
 \r
 \r
        function xmlrpc_se($parser, $name, $attrs)\r
        {\r
-               global $_xh, $xmlrpcDateTime, $xmlrpcString;\r
+               global $_xh, $xmlrpcDateTime, $xmlrpcString, $xmlrpc_valid_parents;\r
+\r
+               // if invalid xmlrpc already detected, skip all processing\r
+               if ($_xh[$parser]['isf'] < 2)\r
+               {\r
+\r
+               // check for correct element nesting\r
+               // top level element can only be of 2 types\r
+               if (count($_xh[$parser]['stack']) == 0)\r
+               {\r
+                       if ($name != 'METHODRESPONSE' && $name != 'METHODCALL')\r
+                       {\r
+                               $_xh[$parser]['isf'] = 2;\r
+                               $_xh[$parser]['isf_reason'] = 'missing top level xmlrpc element';\r
+                               return;\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       // not top level element: see if parent is OK\r
+                       if (!in_array($_xh[$parser]['stack'][0], $xmlrpc_valid_parents[$name]))\r
+                       {\r
+                               $_xh[$parser]['isf'] = 2;\r
+                               $_xh[$parser]['isf_reason'] = "xmlrpc element $name cannot be child of {$_xh[$parser]['stack'][0]}";\r
+                               return;\r
+                       }\r
+               }\r
 \r
                switch($name)\r
                {\r
                        case 'STRUCT':\r
                        case 'ARRAY':\r
-                               $_xh[$parser]['st'].='array(';\r
-                               $_xh[$parser]['cm']++;\r
+                               //$_xh[$parser]['st'].='array(';\r
+                               //$_xh[$parser]['cm']++;\r
                                // this last line turns quoting off\r
                                // this means if we get an empty array we'll\r
                                // simply get a bit of whitespace in the eval\r
-                               $_xh[$parser]['qt']=0;\r
+                               //$_xh[$parser]['qt']=0;\r
+\r
+                               // create an empty array to hold child values, and push it onto appropriate stack\r
+                               $cur_val = array();\r
+                               $cur_val['values'] = array();\r
+                               $cur_val['type'] = $name;\r
+                               array_unshift($_xh[$parser]['valuestack'], $cur_val);\r
                                break;\r
+                       case 'METHODNAME':\r
                        case 'NAME':\r
-                               $_xh[$parser]['st'].='"';\r
+                               //$_xh[$parser]['st'].='"';\r
                                $_xh[$parser]['ac']='';\r
                                break;\r
                        case 'FAULT':\r
                                $_xh[$parser]['isf']=1;\r
                                break;\r
                        case 'PARAM':\r
-                               $_xh[$parser]['st']='';\r
+                               //$_xh[$parser]['st']='';\r
+                               // clear value, so we can check later if no value will passed for this param/member\r
+                               $_xh[$parser]['value']=null;\r
                                break;\r
                        case 'VALUE':\r
-                               $_xh[$parser]['st'].='new xmlrpcval(';\r
-                               $_xh[$parser]['vt']=$xmlrpcString;\r
+                               //$_xh[$parser]['st'].='new xmlrpcval(';\r
+                               // look for a value: if this is still true by the\r
+                               // time we reach the end tag for value then the type is string\r
+                               // by implication\r
+                               $_xh[$parser]['vt']='value';\r
                                $_xh[$parser]['ac']='';\r
-                               $_xh[$parser]['qt']=0;\r
+                               //$_xh[$parser]['qt']=0;\r
                                $_xh[$parser]['lv']=1;\r
-                               // look for a value: if this is still 1 by the\r
-                               // time we reach the first data segment then the type is string\r
-                               // by implication and we need to add in a quote\r
                                break;\r
                        case 'I4':\r
                        case 'INT':\r
                        case 'DOUBLE':\r
                        case 'DATETIME.ISO8601':\r
                        case 'BASE64':\r
-                               $_xh[$parser]['ac']=''; // reset the accumulator\r
+                               if ($_xh[$parser]['vt']!='value')\r
+                               {\r
+                                       //two data elements inside a value: an error occurred!\r
+                                       $_xh[$parser]['isf'] = 2;\r
+                                       $_xh[$parser]['isf_reason'] = "$name element following a {$_xh[$parser]['vt']} element inside a single value";\r
+                                       return;\r
+                               }\r
+\r
+                               // reset the accumulator\r
+                               $_xh[$parser]['ac']='';\r
 \r
-                               if ($name=='DATETIME.ISO8601' || $name=='STRING')\r
+                               /*if ($name=='DATETIME.ISO8601' || $name=='STRING')\r
                                {\r
                                        $_xh[$parser]['qt']=1;\r
                                        if ($name=='DATETIME.ISO8601')\r
                                        // at the end of the element we must check\r
                                        // for data format errors.\r
                                        $_xh[$parser]['qt']=0;\r
-                               }\r
+                               }*/\r
                                break;\r
                        case 'MEMBER':\r
-                               $_xh[$parser]['ac']='';\r
+                               //$_xh[$parser]['ac']='';\r
+                               // avoid warnings later on if no NAME is found before VALUE inside\r
+                               // a struct member predefining member name as NULL\r
+                               $_xh[$parser]['valuestack'][0]['name'] = '';\r
+                               // clear value, so we can check later if no value will passed for this param/member\r
+                               $_xh[$parser]['value']=null;\r
+                               break;\r
+                       case 'DATA':\r
+                       case 'METHODCALL':\r
+                       case 'METHODRESPONSE':\r
+                       case 'PARAMS':\r
+                               // valid elements that add little to processing\r
                                break;\r
                        default:\r
+                               /// INVALID ELEMENT: RAISE ISF so that it is later recognized!!!\r
+                               $_xh[$parser]['isf'] = 2;\r
+                               $_xh[$parser]['isf_reason'] = "found not-xmlrpc xml element $name";\r
                                break;\r
                }\r
 \r
+               // Save current element name to stack, to validate nesting\r
+               array_unshift($_xh[$parser]['stack'], $name);\r
+\r
                if ($name!='VALUE')\r
                {\r
                        $_xh[$parser]['lv']=0;\r
                }\r
        }\r
+       }\r
 \r
        function xmlrpc_ee($parser, $name)\r
        {\r
-               global $_xh,$xmlrpcTypes,$xmlrpcString;\r
+               global $_xh,$xmlrpcTypes,$xmlrpcString,$xmlrpcDateTime;\r
+\r
+               if ($_xh[$parser]['isf'] < 2)\r
+               {\r
+\r
+               // push this element name from stack\r
+               // NB: if XML validates, correct opening/closing is guaranteed and\r
+               // we do not have to check for $name == $curr_elem.\r
+               // we also checked for proper nesting at start of elements...\r
+               $curr_elem = array_shift($_xh[$parser]['stack']);               \r
 \r
                switch($name)\r
                {\r
                        case 'STRUCT':\r
                        case 'ARRAY':\r
-                               if ($_xh[$parser]['cm'] && substr($_xh[$parser]['st'], -1) ==',')\r
-                               {\r
-                                       $_xh[$parser]['st']=substr($_xh[$parser]['st'],0,-1);\r
-                               }\r
-                               $_xh[$parser]['st'].=')';\r
+                               //if ($_xh[$parser]['cm'] && substr($_xh[$parser]['st'], -1) ==',')\r
+                               //{\r
+                               //      $_xh[$parser]['st']=substr($_xh[$parser]['st'],0,-1);\r
+                               //}\r
+                               //$_xh[$parser]['st'].=')';\r
+\r
+                               // fetch out of stack array of values, and promote it to current value\r
+                               $cur_val = array_shift($_xh[$parser]['valuestack']);\r
+                               $_xh[$parser]['value'] = $cur_val['values'];\r
+\r
                                $_xh[$parser]['vt']=strtolower($name);\r
-                               $_xh[$parser]['cm']--;\r
+                               //$_xh[$parser]['cm']--;\r
                                break;\r
                        case 'NAME':\r
-                               $_xh[$parser]['st'].= $_xh[$parser]['ac'] . '" => ';\r
+                               //$_xh[$parser]['st'].= $_xh[$parser]['ac'] . '" => ';\r
+                               $_xh[$parser]['valuestack'][0]['name'] = $_xh[$parser]['ac'];\r
                                break;\r
                        case 'BOOLEAN':\r
-                               // special case here: we translate boolean 1 or 0 into PHP\r
-                               // constants true or false\r
-                               // NB: this simple checks helps a lot sanitizing input, ie no\r
-                               // security problems around here\r
-                               if ($_xh[$parser]['ac']=='1')\r
-                               {\r
-                                       $_xh[$parser]['ac']='true';\r
-                               }\r
-                               else\r
-                               {\r
-                                       $_xh[$parser]['ac']='false';\r
-                               }\r
-                               $_xh[$parser]['vt']=strtolower($name);\r
-                               // Drop through intentionally.\r
                        case 'I4':\r
                        case 'INT':\r
                        case 'STRING':\r
                        case 'DOUBLE':\r
                        case 'DATETIME.ISO8601':\r
                        case 'BASE64':\r
-                               if ($_xh[$parser]['qt']==1)\r
+                               $_xh[$parser]['vt']=strtolower($name);\r
+                               //if ($_xh[$parser]['qt']==1)                   \r
+                               if ($name=='STRING')\r
                                {\r
                                        // we use double quotes rather than single so backslashification works OK\r
-                                       $_xh[$parser]['st'].='"'. $_xh[$parser]['ac'] . '"';\r
+                                       //$_xh[$parser]['st'].='"'. $_xh[$parser]['ac'] . '"';\r
+                                       $_xh[$parser]['value']=$_xh[$parser]['ac'];\r
+                               }\r
+                               elseif ($name=='DATETIME.ISO8601')\r
+                               {\r
+                                       $_xh[$parser]['vt']=$xmlrpcDateTime;\r
+                                       $_xh[$parser]['value']=$_xh[$parser]['ac'];\r
                                }\r
-                               elseif ($_xh[$parser]['qt']==2)\r
+                               elseif ($name=='BASE64')\r
                                {\r
-                                       $_xh[$parser]['st'].='base64_decode("'. $_xh[$parser]['ac'] . '")';\r
+                                       //$_xh[$parser]['st'].='base64_decode("'. $_xh[$parser]['ac'] . '")';\r
+\r
+                                       ///@todo check for failure of base64 decoding / catch warnings\r
+                                       $_xh[$parser]['value']=base64_decode($_xh[$parser]['ac']);\r
                                }\r
                                elseif ($name=='BOOLEAN')\r
                                {\r
-                                       $_xh[$parser]['st'].=$_xh[$parser]['ac'];\r
+                                       // special case here: we translate boolean 1 or 0 into PHP\r
+                                       // constants true or false\r
+                                       // NB: this simple checks helps a lot sanitizing input, ie no\r
+                                       // security problems around here\r
+                                       if ($_xh[$parser]['ac']=='1')\r
+                                       {\r
+                                               //$_xh[$parser]['ac']='true';   \r
+                                               $_xh[$parser]['value']=true;\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               //$_xh[$parser]['ac']='false';\r
+                                               // log if receiveing something strange, even though we set the value to false anyway\r
+                                               if ($_xh[$parser]['ac']!='0')\r
+                                                       error_log('XML-RPC: invalid value received in BOOLEAN: '.$_xh[$parser]['ac']);\r
+                                               $_xh[$parser]['value']=false;\r
+                                       }\r
+                                       //$_xh[$parser]['st'].=$_xh[$parser]['ac'];\r
                                }\r
                                elseif ($name=='DOUBLE')\r
                                {\r
                                                // TODO: find a better way of throwing an error\r
                                                // than this!\r
                                                error_log('XML-RPC: non numeric value received in DOUBLE: '.$_xh[$parser]['ac']);\r
-                                               $_xh[$parser]['st'].="'ERROR_NON_NUMERIC_FOUND'";\r
+                                               //$_xh[$parser]['st'].="'ERROR_NON_NUMERIC_FOUND'";\r
+                                               $_xh[$parser]['value']='ERROR_NON_NUMERIC_FOUND';\r
                                        }\r
                                        else\r
                                        {\r
                                                // it's ok, add it on\r
-                                               $_xh[$parser]['st'].=(double)$_xh[$parser]['ac'];\r
+                                               //$_xh[$parser]['st'].=(double)$_xh[$parser]['ac'];\r
+                                               $_xh[$parser]['value']=(double)$_xh[$parser]['ac'];\r
                                        }\r
                                }\r
                                else\r
                                                // TODO: find a better way of throwing an error\r
                                                // than this!\r
                                                error_log('XML-RPC: non numeric value received in INT: '.$_xh[$parser]['ac']);\r
-                                               $_xh[$parser]['st'].="'ERROR_NON_NUMERIC_FOUND'";\r
+                                               //$_xh[$parser]['st'].="'ERROR_NON_NUMERIC_FOUND'";\r
+                                               $_xh[$parser]['value']='ERROR_NON_NUMERIC_FOUND';\r
                                        }\r
                                        else\r
                                        {\r
                                                // it's ok, add it on\r
-                                               $_xh[$parser]['st'].=(int)$_xh[$parser]['ac'];\r
+                                               //$_xh[$parser]['st'].=(int)$_xh[$parser]['ac'];\r
+                                               $_xh[$parser]['value']=(int)$_xh[$parser]['ac'];\r
                                        }\r
                                }\r
                                $_xh[$parser]['ac']='';\r
-                               $_xh[$parser]['qt']=0;\r
+                               //$_xh[$parser]['qt']=0;\r
                                $_xh[$parser]['lv']=3; // indicate we've found a value\r
                                break;\r
                        case 'VALUE':\r
-                               // deal with a string value\r
-                               if (strlen($_xh[$parser]['ac'])>0 &&\r
+                               // This if() detects if no scalar was inside <VALUE></VALUE>\r
+                               if ($_xh[$parser]['vt']=='value')\r
+                               {\r
+                                       $_xh[$parser]['value']=$_xh[$parser]['ac'];\r
+                                       $_xh[$parser]['vt']=$xmlrpcString;\r
+                               }\r
+                               /*if (strlen($_xh[$parser]['ac'])>0 &&\r
                                        $_xh[$parser]['vt']==$xmlrpcString)\r
                                {\r
                                        $_xh[$parser]['st'].='"'. $_xh[$parser]['ac'] . '"';\r
                                if ($_xh[$parser]['cm'])\r
                                {\r
                                        $_xh[$parser]['st'].=',';\r
+                               }*/\r
+\r
+                               // build the xmlrpc val out of the data received, and substitute it\r
+                               $temp = new xmlrpcval($_xh[$parser]['value'], $_xh[$parser]['vt']);\r
+                               // check if we are inside an array or struct:\r
+                               // if value just built is inside an array, let's move it into array on the stack\r
+                               if (count($_xh[$parser]['valuestack']) && $_xh[$parser]['valuestack'][0]['type']=='ARRAY')\r
+                               {\r
+                                       $_xh[$parser]['valuestack'][0]['values'][] = $temp;\r
+                               }\r
+                               else\r
+                               {\r
+                               $_xh[$parser]['value'] = $temp;\r
                                }\r
                                break;\r
                        case 'MEMBER':\r
                                $_xh[$parser]['ac']='';\r
-                               $_xh[$parser]['qt']=0;\r
+                               //$_xh[$parser]['qt']=0;\r
+                               // add to array in the stack the last element built\r
+                               // unless no VALUE was found\r
+                               if ($_xh[$parser]['value'])\r
+                                       $_xh[$parser]['valuestack'][0]['values'][$_xh[$parser]['valuestack'][0]['name']] = $_xh[$parser]['value'];\r
+                               else\r
+                                       error_log('XML-RPC: missing VALUE inside STRUCT in received xml');\r
                                break;\r
                        case 'DATA':\r
                                $_xh[$parser]['ac']='';\r
-                               $_xh[$parser]['qt']=0;\r
+                               //$_xh[$parser]['qt']=0;\r
                                break;\r
                        case 'PARAM':\r
-                               $_xh[$parser]['params'][]=$_xh[$parser]['st'];\r
+                               //$_xh[$parser]['params'][]=$_xh[$parser]['st'];\r
+                               if ($_xh[$parser]['value'])\r
+                                       $_xh[$parser]['params'][]=$_xh[$parser]['value'];\r
+                               else\r
+                                       error_log('XML-RPC: missing VALUE inside PARAM in received xml');\r
                                break;\r
                        case 'METHODNAME':\r
                                $_xh[$parser]['method']=ereg_replace("^[\n\r\t ]+", '', $_xh[$parser]['ac']);\r
                                break;\r
-                       // BOOLEAN HAS BEEN ENUMERATED ABOVE!\r
-                       /*case 'BOOLEAN':\r
-                               // special case here: we translate boolean 1 or 0 into PHP\r
-                               // constants true or false\r
-                               if ($_xh[$parser]['ac']=='1')\r
-                               {\r
-                                       $_xh[$parser]['ac']='true';\r
-                               }\r
-                               else\r
-                               {\r
-                                       $_xh[$parser]['ac']='false';\r
-                                       $_xh[$parser]['vt']=strtolower($name);\r
-                               }\r
-                               break;*/\r
+                       case 'PARAMS':\r
+                       case 'FAULT':\r
+                       case 'METHODCALL':\r
+                       case 'METHORESPONSE':\r
+                               break;\r
                        default:\r
+                               // End of INVALID ELEMENT!\r
+                               // shall we add an assert here for unreachable code???\r
                                break;\r
                }\r
                // if it's a valid type name, set the type\r
-               if (isset($xmlrpcTypes[strtolower($name)]))\r
+               /*if (isset($xmlrpcTypes[strtolower($name)]))\r
                {\r
                        $_xh[$parser]['vt']=strtolower($name);\r
+               }*/\r
+\r
                }\r
        }\r
 \r
                //if (ereg("^[\n\r \t]+$", $data)) return;\r
                // print "adding [${data}]\n";\r
 \r
+               // skip processing if xml fault already detected\r
+               if ($_xh[$parser]['isf'] < 2)\r
+               {\r
                if ($_xh[$parser]['lv']!=3)\r
                {\r
                        // "lookforvalue==3" means that we've found an entire value\r
                        {\r
                                // if we've found text and we're just in a <value> then\r
                                // turn quoting on, as this will be a string\r
-                               $_xh[$parser]['qt']=1;\r
+                                       //$_xh[$parser]['qt']=1;\r
                                // and say we've found a value\r
                                $_xh[$parser]['lv']=2;\r
                        }\r
                        {\r
                                $_xh[$parser]['ac'] = '';\r
                        }\r
-                       $_xh[$parser]['ac'].=str_replace('$', '\$', str_replace('"', '\"', str_replace(chr(92),$xmlrpc_backslash, $data)));\r
+                               //$_xh[$parser]['ac'].=str_replace('$', '\$', str_replace('"', '\"', str_replace(chr(92),$xmlrpc_backslash, $data)));\r
+                               $_xh[$parser]['ac'].=$data;\r
+                       }\r
                }\r
        }\r
 \r
        function xmlrpc_dh($parser, $data)\r
        {\r
                global $_xh, $xmlrpc_backslash;\r
+\r
+               // skip processing if xml fault already detected\r
+               if ($parser[$_xh]['isf'] < 2)\r
+               {\r
                if (substr($data, 0, 1) == '&' && substr($data, -1, 1) == ';')\r
                {\r
                        if ($_xh[$parser]['lv']==1)\r
                        {\r
-                               $_xh[$parser]['qt']=1;\r
+                                       //$_xh[$parser]['qt']=1;\r
                                $_xh[$parser]['lv']=2;\r
                        }\r
-                       $_xh[$parser]['ac'].=str_replace('$', '\$', str_replace('"', '\"', str_replace(chr(92),$xmlrpc_backslash, $data)));\r
+                               //$_xh[$parser]['ac'].=str_replace('$', '\$', str_replace('"', '\"', str_replace(chr(92),$xmlrpc_backslash, $data)));\r
+                               $_xh[$parser]['ac'].=$data;\r
+                       }\r
                }\r
        }\r
 \r
                        $_xh=array();\r
                        $_xh[$parser]=array();\r
                        $_xh[$parser]['headers'] = array();\r
+                       $_xh[$parser]['stack'] = array();\r
+                       $_xh[$parser]['valuestack'] = array();\r
 \r
                        // separate HTTP headers from data\r
                        if (ereg("^HTTP", $data))\r
                        if ($bd)\r
                                $data = substr($data, 0, $bd);\r
 \r
-                       $_xh[$parser]['st']='';\r
-                       $_xh[$parser]['cm']=0;\r
+                       //$_xh[$parser]['st']='';\r
+                       //$_xh[$parser]['cm']=0;\r
                        $_xh[$parser]['isf']=0;\r
+                       $_xh[$parser]['isf_reason']=0;\r
                        $_xh[$parser]['ac']='';\r
-                       $_xh[$parser]['qt']='';\r
+                       //$_xh[$parser]['qt']='';\r
 \r
                        xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);\r
                        // G. Giunta 2005/02/13: PHP internally uses ISO-8859-1, so we have to tell\r
                                return $r;\r
                        }\r
                        xml_parser_free($parser);\r
+\r
+                       if ($_xh[$parser]['isf'] > 1)\r
+                       {\r
                        if ($this->debug)\r
                        {\r
-                               print "<PRE>---EVALING---[" .\r
-                               strlen($_xh[$parser]['st']) . " chars]---\n" .\r
-                               htmlspecialchars($_xh[$parser]['st']) . ";\n---END---</PRE>";\r
+                                       ///@todo echo something for user?\r
+                               }\r
+\r
+                               $r = new xmlrpcresp(0, $xmlrpcerr['invalid_return'],\r
+                               $xmlrpcstr['invalid_return'] . ' ' . $_xh[$parser]['isf_reason']);\r
                        }\r
-                       if (strlen($_xh[$parser]['st'])==0)\r
+                       //else if (strlen($_xh[$parser]['st'])==0)\r
+                       else if (!is_object($_xh[$parser]['value']))\r
                        {\r
                                // then something odd has happened\r
                                // and it's time to generate a client side error\r
                        }\r
                        else\r
                        {\r
-                               $allOK=0;\r
-                               @eval('$v=' . $_xh[$parser]['st'] . '; $allOK=1;');\r
-                               if (!$allOK)\r
+\r
+                               if ($this->debug)\r
                                {\r
-                                       $r = new xmlrpcresp(0, $xmlrpcerr['invalid_return'], $xmlrpcstr['invalid_return']);\r
+                                       //print "<PRE>---EVALING---[" .\r
+                                       //strlen($_xh[$parser]['st']) . " chars]---\n" .\r
+                                       //htmlspecialchars($_xh[$parser]['st']) . ";\n---END---</PRE>";\r
+                                       print "<PRE>---PARSED---\n" ;\r
+                                       var_dump($_xh[$parser]['value']);\r
+                                       print "\n---END---</PRE>";\r
                                }\r
-                               else\r
+\r
+                               //$allOK=0;\r
+                               //@eval('$v=' . $_xh[$parser]['st'] . '; $allOK=1;');\r
+                               //if (!$allOK)\r
+                               //{\r
+                               //      $r = new xmlrpcresp(0, $xmlrpcerr['invalid_return'], $xmlrpcstr['invalid_return']);\r
+                               //}\r
+                               //else\r
+                               $v = $_xh[$parser]['value'];\r
                                if ($_xh[$parser]['isf'])\r
                                {\r
                                        $errno_v = $v->structmem('faultCode');\r
                                @reset($t);\r
                                while(list($id,$cont) = @each($t))\r
                                {\r
-                                       eval('$b->'.$id.' = $cont;');\r
+                                       //eval('$b->'.$id.' = $cont;');\r
+                                       @$b->$id = $cont;\r
                                }\r
                        }\r
                        // end contrib\r
index 3c669a7..e0abd16 100755 (executable)
@@ -1,8 +1,8 @@
 <?php\r
 // by Edd Dumbill (C) 1999-2002\r
 // <edd@usefulinc.com>\r
-// $Id: xmlrpcs.inc.php,v 1.5.2.1 2005-06-30 21:19:18 kimitake Exp $\r
-// $NucleusJP$\r
+// $Id: xmlrpcs.inc.php,v 1.5.2.2 2005-08-16 05:26:18 kimitake Exp $\r
+// $NucleusJP: xmlrpcs.inc.php,v 1.4.2.1 2005/06/30 21:23:01 kimitake Exp $\r
 \r
 // Copyright (c) 1999,2000,2002 Edd Dumbill.\r
 // All rights reserved.\r
                        $parser = xml_parser_create($xmlrpc_defencoding);\r
 \r
                        $_xh[$parser]=array();\r
-                       $_xh[$parser]['st']='';\r
-                       $_xh[$parser]['cm']=0;\r
+                       //$_xh[$parser]['st']='';\r
+                       //$_xh[$parser]['cm']=0;\r
                        $_xh[$parser]['isf']=0;\r
+                       $_xh[$parser]['isf_reason']='';\r
                        $_xh[$parser]['params']=array();\r
+                       $_xh[$parser]['stack']=array();\r
+                       $_xh[$parser]['valuestack'] = array();\r
                        $_xh[$parser]['method']='';\r
 \r
                        // decompose incoming XML into request structure\r
                                xml_parser_free($parser);\r
                        }\r
                        else\r
+                       if ($_xh[$parser]['isf'])\r
                        {\r
                                xml_parser_free($parser);\r
+                               $r=new xmlrpcresp(0,\r
+                                       $xmlrpcerr['invalid_request'],\r
+                                       $xmlrpcstr['invalid_request'] . ' ' . $_xh[$parser]['isf_reason']);\r
+                       }\r
+                       else\r
+                       {\r
+                               xml_parser_free($parser);\r
+\r
                                $m=new xmlrpcmsg($_xh[$parser]['method']);\r
                                // now add parameters in\r
                                $plist='';\r
-                               $allOK = 1;\r
+                               //$allOK = 1;\r
                                for($i=0; $i<sizeof($_xh[$parser]['params']); $i++)\r
                                {\r
                                        //print "<!-- " . $_xh[$parser]['params'][$i]. "-->\n";\r
                                        $plist.="$i - " .  $_xh[$parser]['params'][$i]. ";\n";\r
-                                       $allOK = 0;\r
-                                       @eval('$m->addParam(' . $_xh[$parser]['params'][$i]. '); $allOK=1;');\r
-                                       if (!$allOK)\r
-                                       {\r
-                                               break;\r
-                                       }\r
+                                       //$allOK = 0;\r
+                                       //@eval('$m->addParam(' . $_xh[$parser]['params'][$i]. '); $allOK=1;');\r
+                                       @$m->addParam($_xh[$parser]['params'][$i]);\r
+                                       //if (!$allOK)\r
+                                       //{\r
+                                       //      break;\r
+                                       //}\r
                                }\r
                                // uncomment this to really see what the server's getting!\r
                                // xmlrpc_debugmsg($plist);\r
-                               if (!$allOK)\r
-                               {\r
-                                       $r = new xmlrpcresp(0,\r
-                                               $xmlrpcerr['incorrect_params'],\r
-                                               $xmlrpcstr['incorrect_params'] . ": xml error in param " . $i);\r
-                               }\r
-                               else\r
-                               {\r
+                               //if (!$allOK)\r
+                               //{\r
+                               //      $r = new xmlrpcresp(0,\r
+                               //              $xmlrpcerr['incorrect_params'],\r
+                               //              $xmlrpcstr['incorrect_params'] . ": xml error in param " . $i);\r
+                               //}\r
+                               //else\r
+                               //{\r
                                        $r = $this->execute($m);\r
-                               }\r
+                               //}\r
                        }\r
                        return $r;\r
                }\r