[ PHPXref.com ] [ Generated: Sun Jul 20 19:13:40 2008 ] [ osCommRes 1.2.0 ]
[ Index ]     [ Variables ]     [ Functions ]     [ Classes ]     [ Constants ]     [ Statistics ]

title

Body

[close]

/includes/ -> xmlrpc.inc (source)

   1  <?php                    // -*-c++-*-
   2  // by Edd Dumbill (C) 1999-2001

   3  // <edd@usefulinc.com>

   4  // $Id: xmlrpc.inc,v 1.1 2004/03/08 21:21:16 schst Exp $

   5  
   6  
   7  // Copyright (c) 1999,2000,2001 Edd Dumbill.

   8  // All rights reserved.

   9  //

  10  // Redistribution and use in source and binary forms, with or without

  11  // modification, are permitted provided that the following conditions

  12  // are met:

  13  //

  14  //    * Redistributions of source code must retain the above copyright

  15  //      notice, this list of conditions and the following disclaimer.

  16  //

  17  //    * Redistributions in binary form must reproduce the above

  18  //      copyright notice, this list of conditions and the following

  19  //      disclaimer in the documentation and/or other materials provided

  20  //      with the distribution.

  21  //

  22  //    * Neither the name of the "XML-RPC for PHP" nor the names of its

  23  //      contributors may be used to endorse or promote products derived

  24  //      from this software without specific prior written permission.

  25  //

  26  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

  27  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

  28  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS

  29  // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE

  30  // REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

  31  // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES

  32  // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR

  33  // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)

  34  // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,

  35  // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)

  36  // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED

  37  // OF THE POSSIBILITY OF SUCH DAMAGE.

  38  
  39  if (!function_exists('xml_parser_create')) {
  40  // Win 32 fix. From: "Leo West" <lwest@imaginet.fr>

  41      if($WINDIR) {
  42          dl("php3_xml.dll");
  43      } else {
  44          dl("xml.so");
  45      }
  46  }
  47  
  48  $xmlrpcI4="i4";
  49  $xmlrpcInt="int";
  50  $xmlrpcBoolean="boolean";
  51  $xmlrpcDouble="double";
  52  $xmlrpcString="string";
  53  $xmlrpcDateTime="dateTime.iso8601";
  54  $xmlrpcBase64="base64";
  55  $xmlrpcArray="array";
  56  $xmlrpcStruct="struct";
  57  
  58  
  59  $xmlrpcTypes=array($xmlrpcI4 => 1,
  60                     $xmlrpcInt => 1,
  61                     $xmlrpcBoolean => 1,
  62                     $xmlrpcString => 1,
  63                     $xmlrpcDouble => 1,
  64                     $xmlrpcDateTime => 1,
  65                     $xmlrpcBase64 => 1,
  66                     $xmlrpcArray => 2,
  67                     $xmlrpcStruct => 3);
  68  
  69  $xmlEntities=array(     "amp" => "&",
  70                                       "quot" => '"',
  71                                       "lt" => "<",
  72                                       "gt" => ">",
  73                                       "apos" => "'");
  74  
  75  $xmlrpcerr["unknown_method"]=1;
  76  $xmlrpcstr["unknown_method"]="Unknown method";
  77  $xmlrpcerr["invalid_return"]=2;
  78  $xmlrpcstr["invalid_return"]="Invalid return payload: enabling debugging to examine incoming payload";
  79  $xmlrpcerr["incorrect_params"]=3;
  80  $xmlrpcstr["incorrect_params"]="Incorrect parameters passed to method";
  81  $xmlrpcerr["introspect_unknown"]=4;
  82  $xmlrpcstr["introspect_unknown"]="Can't introspect: method unknown";
  83  $xmlrpcerr["http_error"]=5;
  84  $xmlrpcstr["http_error"]="Didn't receive 200 OK from remote server.";
  85  $xmlrpcerr["no_data"]=6;
  86  $xmlrpcstr["no_data"]="No data received from server.";
  87  $xmlrpcerr["no_ssl"]=7;
  88  $xmlrpcstr["no_ssl"]="No SSL support compiled in.";
  89  $xmlrpcerr["curl_fail"]=8;
  90  $xmlrpcstr["curl_fail"]="CURL error";
  91  
  92  $xmlrpc_defencoding="UTF-8";
  93  
  94  $xmlrpcName="XML-RPC for PHP";
  95  $xmlrpcVersion="1.01";
  96  
  97  // let user errors start at 800

  98  $xmlrpcerruser=800; 
  99  // let XML parse errors start at 100

 100  $xmlrpcerrxml=100;
 101  
 102  // formulate backslashes for escaping regexp

 103  $xmlrpc_backslash=chr(92).chr(92);
 104  
 105  // used to store state during parsing

 106  // quick explanation of components:

 107  //   st - used to build up a string for evaluation

 108  //   ac - used to accumulate values

 109  //   qt - used to decide if quotes are needed for evaluation

 110  //   cm - used to denote struct or array (comma needed)

 111  //   isf - used to indicate a fault

 112  //   lv - used to indicate "looking for a value": implements

 113  //        the logic to allow values with no types to be strings

 114  //   params - used to store parameters in method calls

 115  //   method - used to store method name

 116  
 117  $_xh=array();
 118  
 119  function xmlrpc_entity_decode($string) {
 120    $top=split("&", $string);
 121    $op="";
 122    $i=0; 
 123    while($i<sizeof($top)) {
 124      if (ereg("^([#a-zA-Z0-9]+);", $top[$i], $regs)) {
 125        $op.=ereg_replace("^[#a-zA-Z0-9]+;",
 126                          xmlrpc_lookup_entity($regs[1]),
 127                                              $top[$i]);
 128      } else {
 129        if ($i==0) 
 130          $op=$top[$i]; 
 131        else
 132          $op.="&" . $top[$i];
 133      }
 134      $i++;
 135    }
 136    return $op;
 137  }
 138  
 139  function xmlrpc_lookup_entity($ent) {
 140    global $xmlEntities;
 141    
 142    if (isset($xmlEntities[strtolower($ent)]))
 143      return $xmlEntities[strtolower($ent)];
 144    if (ereg("^#([0-9]+)$", $ent, $regs))
 145      return chr($regs[1]);
 146    return "?";
 147  }
 148  
 149  function xmlrpc_se($parser, $name, $attrs) {
 150      global $_xh, $xmlrpcDateTime, $xmlrpcString;
 151      
 152      switch($name) {
 153      case "STRUCT":
 154      case "ARRAY":
 155        $_xh[$parser]['st'].="array(";
 156        $_xh[$parser]['cm']++;
 157          // this last line turns quoting off

 158          // this means if we get an empty array we'll 

 159          // simply get a bit of whitespace in the eval

 160          $_xh[$parser]['qt']=0;
 161        break;
 162      case "NAME":
 163        $_xh[$parser]['st'].="'"; $_xh[$parser]['ac']="";
 164        break;
 165      case "FAULT":
 166        $_xh[$parser]['isf']=1;
 167        break;
 168      case "PARAM":
 169        $_xh[$parser]['st']="";
 170        break;
 171      case "VALUE":
 172        $_xh[$parser]['st'].="new xmlrpcval("; 
 173          $_xh[$parser]['vt']=$xmlrpcString;
 174          $_xh[$parser]['ac']="";
 175          $_xh[$parser]['qt']=0;
 176        $_xh[$parser]['lv']=1;
 177        // look for a value: if this is still 1 by the

 178        // time we reach the first data segment then the type is string

 179        // by implication and we need to add in a quote

 180          break;
 181  
 182      case "I4":
 183      case "INT":
 184      case "STRING":
 185      case "BOOLEAN":
 186      case "DOUBLE":
 187      case "DATETIME.ISO8601":
 188      case "BASE64":
 189        $_xh[$parser]['ac']=""; // reset the accumulator

 190  
 191        if ($name=="DATETIME.ISO8601" || $name=="STRING") {
 192              $_xh[$parser]['qt']=1; 
 193              if ($name=="DATETIME.ISO8601")
 194                  $_xh[$parser]['vt']=$xmlrpcDateTime;
 195        } else if ($name=="BASE64") {
 196              $_xh[$parser]['qt']=2;
 197          } else {
 198              // No quoting is required here -- but

 199              // at the end of the element we must check

 200              // for data format errors.

 201              $_xh[$parser]['qt']=0;
 202        }
 203          break;
 204      case "MEMBER":
 205          $_xh[$parser]['ac']="";
 206        break;
 207      default:
 208          break;
 209      }
 210  
 211      if ($name!="VALUE") $_xh[$parser]['lv']=0;
 212  }
 213  
 214  function xmlrpc_ee($parser, $name) {
 215      global $_xh,$xmlrpcTypes,$xmlrpcString;
 216  
 217      switch($name) {
 218      case "STRUCT":
 219      case "ARRAY":
 220        if ($_xh[$parser]['cm'] && substr($_xh[$parser]['st'], -1) ==',') {
 221          $_xh[$parser]['st']=substr($_xh[$parser]['st'],0,-1);
 222        }
 223        $_xh[$parser]['st'].=")";    
 224        $_xh[$parser]['vt']=strtolower($name);
 225        $_xh[$parser]['cm']--;
 226        break;
 227      case "NAME":
 228        $_xh[$parser]['st'].= $_xh[$parser]['ac'] . "' => ";
 229        break;
 230      case "BOOLEAN":
 231          // special case here: we translate boolean 1 or 0 into PHP

 232          // constants true or false

 233          if ($_xh[$parser]['ac']=='1') 
 234              $_xh[$parser]['ac']="true";
 235          else 
 236              $_xh[$parser]['ac']="false";
 237          $_xh[$parser]['vt']=strtolower($name);
 238          // Drop through intentionally.

 239      case "I4":
 240      case "INT":
 241      case "STRING":
 242      case "DOUBLE":
 243      case "DATETIME.ISO8601":
 244      case "BASE64":
 245        if ($_xh[$parser]['qt']==1) {
 246              // we use double quotes rather than single so backslashification works OK

 247              $_xh[$parser]['st'].="\"". $_xh[$parser]['ac'] . "\""; 
 248          } else if ($_xh[$parser]['qt']==2) {
 249              $_xh[$parser]['st'].="base64_decode('". $_xh[$parser]['ac'] . "')"; 
 250          } else if ($name=="BOOLEAN") {
 251              $_xh[$parser]['st'].=$_xh[$parser]['ac'];
 252          } else {
 253              // we have an I4, INT or a DOUBLE

 254              // we must check that only 0123456789-.<space> are characters here

 255              if (!ereg("^\-?[0123456789 \t\.]+$", $_xh[$parser]['ac'])) {
 256                  // TODO: find a better way of throwing an error

 257                  // than this!

 258                  error_log("XML-RPC: non numeric value received in INT or DOUBLE");
 259                  $_xh[$parser]['st'].="ERROR_NON_NUMERIC_FOUND";
 260              } else {
 261                  // it's ok, add it on

 262                  $_xh[$parser]['st'].=$_xh[$parser]['ac'];
 263              }
 264          }
 265          $_xh[$parser]['ac']=""; $_xh[$parser]['qt']=0;
 266          $_xh[$parser]['lv']=3; // indicate we've found a value

 267        break;
 268      case "VALUE":
 269          // deal with a string value

 270          if (strlen($_xh[$parser]['ac'])>0 &&
 271                  $_xh[$parser]['vt']==$xmlrpcString) {
 272              $_xh[$parser]['st'].="\"". $_xh[$parser]['ac'] . "\""; 
 273          }
 274          // This if() detects if no scalar was inside <VALUE></VALUE>

 275          // and pads an empty "".

 276          if($_xh[$parser]['st'][strlen($_xh[$parser]['st'])-1] == '(') {
 277              $_xh[$parser]['st'].= '""';
 278          }
 279          $_xh[$parser]['st'].=", '" . $_xh[$parser]['vt'] . "')";
 280          if ($_xh[$parser]['cm']) $_xh[$parser]['st'].=",";
 281          break;
 282      case "MEMBER":
 283        $_xh[$parser]['ac']=""; $_xh[$parser]['qt']=0;
 284       break;
 285      case "DATA":
 286        $_xh[$parser]['ac']=""; $_xh[$parser]['qt']=0;
 287        break;
 288      case "PARAM":
 289        $_xh[$parser]['params'][]=$_xh[$parser]['st'];
 290        break;
 291      case "METHODNAME":
 292        $_xh[$parser]['method']=ereg_replace("^[\n\r\t ]+", "", 
 293                                                                                   $_xh[$parser]['ac']);
 294          break;
 295      case "BOOLEAN":
 296          // special case here: we translate boolean 1 or 0 into PHP

 297          // constants true or false

 298          if ($_xh[$parser]['ac']=='1') 
 299              $_xh[$parser]['ac']="true";
 300          else 
 301              $_xh[$parser]['ac']="false";
 302          $_xh[$parser]['vt']=strtolower($name);
 303          break;
 304      default:
 305          break;
 306      }
 307      // if it's a valid type name, set the type

 308      if (isset($xmlrpcTypes[strtolower($name)])) {
 309          $_xh[$parser]['vt']=strtolower($name);
 310      }
 311      
 312  }
 313  
 314  function xmlrpc_cd($parser, $data)
 315  {    
 316    global $_xh, $xmlrpc_backslash;
 317  
 318    //if (ereg("^[\n\r \t]+$", $data)) return;

 319    // print "adding [${data}]\n";

 320  
 321      if ($_xh[$parser]['lv']!=3) {
 322          // "lookforvalue==3" means that we've found an entire value

 323          // and should discard any further character data

 324          if ($_xh[$parser]['lv']==1) {  
 325              // if we've found text and we're just in a <value> then

 326              // turn quoting on, as this will be a string

 327              $_xh[$parser]['qt']=1; 
 328              // and say we've found a value

 329              $_xh[$parser]['lv']=2; 
 330          }
 331      // replace characters that eval would

 332      // do special things with

 333      $_xh[$parser]['ac'].=str_replace('$', '\$',
 334          str_replace('"', '\"', str_replace(chr(92),
 335              $xmlrpc_backslash, $data)));
 336      }
 337  }
 338  
 339  function xmlrpc_dh($parser, $data)
 340  {
 341    global $_xh;
 342    if (substr($data, 0, 1) == "&" && substr($data, -1, 1) == ";") {
 343          if ($_xh[$parser]['lv']==1) {  
 344              $_xh[$parser]['qt']=1; 
 345              $_xh[$parser]['lv']=2; 
 346          }
 347          $_xh[$parser]['ac'].=str_replace('$', '\$',
 348                  str_replace('"', '\"', str_replace(chr(92),
 349                      $xmlrpc_backslash, $data)));
 350    }
 351  }
 352  
 353  class xmlrpc_client {
 354    var $path;
 355    var $server;
 356    var $port;
 357    var $errno;
 358    var $errstring;
 359    var $debug=0;
 360    var $username="";
 361    var $password="";
 362    var $cert="";
 363    var $certpass="";
 364    
 365    function xmlrpc_client($path, $server, $port=0) {
 366      $this->port=$port; $this->server=$server; $this->path=$path;
 367    }
 368  
 369    function setDebug($in) {
 370          if ($in) { 
 371              $this->debug=1;
 372          } else {
 373              $this->debug=0;
 374          }
 375    }
 376  
 377    function setCredentials($u, $p) {
 378      $this->username=$u;
 379      $this->password=$p;
 380    }
 381  
 382    function setCertificate($cert, $certpass) {
 383      $this->cert = $cert;
 384      $this->certpass = $certpass;
 385    }
 386  
 387    function send($msg, $timeout=0, $method='http') {
 388      // where msg is an xmlrpcmsg

 389      $msg->debug=$this->debug;
 390   
 391      if ($method == 'https') {
 392        return $this->sendPayloadHTTPS($msg,
 393                       $this->server,
 394                       $this->port, $timeout,
 395                       $this->username, $this->password,
 396                       $this->cert,
 397                       $this->certpass);
 398      } else {
 399        return $this->sendPayloadHTTP10($msg, $this->server, $this->port,
 400                        $timeout, $this->username, 
 401                        $this->password);
 402      }
 403    }
 404  
 405    function sendPayloadHTTP10($msg, $server, $port, $timeout=0,
 406                   $username="", $password="") {
 407      if ($port==0) $port=80;
 408      if($timeout>0)
 409        $fp=fsockopen($server, $port,
 410              &$this->errno, &$this->errstr, $timeout);
 411      else
 412        $fp=fsockopen($server, $port,
 413              &$this->errno, &$this->errstr);
 414      if (!$fp) {   
 415        return 0;
 416      }
 417      // Only create the payload if it was not created previously

 418      if(empty($msg->payload)) $msg->createPayload();
 419      
 420      // thanks to Grant Rauscher <grant7@firstworld.net>

 421      // for this

 422      $credentials="";
 423      if ($username!="") {
 424        $credentials="Authorization: Basic " .
 425      base64_encode($username . ":" . $password) . "\r\n";
 426      }
 427      
 428      $op= "POST " . $this->path. " HTTP/1.0\r\nUser-Agent: PHP XMLRPC 1.0\r\n" .
 429        "Host: ". $this->server  . "\r\n" .
 430        $credentials . 
 431        "Content-Type: text/xml\r\nContent-Length: " .
 432        strlen($msg->payload) . "\r\n\r\n" .
 433        $msg->payload;
 434      
 435      if (!fputs($fp, $op, strlen($op))) {
 436        $this->errstr="Write error";
 437        return 0;
 438      }
 439      $resp=$msg->parseResponseFile($fp);
 440      fclose($fp);
 441      return $resp;
 442    }
 443  
 444    // contributed by Justin Miller <justin@voxel.net>

 445    // requires curl to be built into PHP

 446    function sendPayloadHTTPS($msg, $server, $port, $timeout=0,
 447                  $username="", $password="", $cert="",
 448                  $certpass="") {
 449      global $xmlrpcerr, $xmlrpcstr;
 450      if ($port == 0) $port = 443;
 451      
 452      // Only create the payload if it was not created previously

 453      if(empty($msg->payload)) $msg->createPayload();
 454      
 455      if (!function_exists("curl_init")) {
 456        $r=new xmlrpcresp(0, $xmlrpcerr["no_ssl"],
 457              $xmlrpcstr["no_ssl"]);
 458        return $r;
 459      }
 460  
 461      $curl = curl_init("https://" . $server . ':' . $port .
 462                $this->path);
 463      
 464      curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
 465      // results into variable

 466      if ($this->debug) {
 467        curl_setopt($curl, CURLOPT_VERBOSE, 1);
 468      }
 469      curl_setopt($curl, CURLOPT_USERAGENT, 'PHP XMLRPC 1.0');
 470      // required for XMLRPC

 471      curl_setopt($curl, CURLOPT_POST, 1);
 472      // post the data

 473      curl_setopt($curl, CURLOPT_POSTFIELDS, $msg->payload);
 474      // the data

 475      curl_setopt($curl, CURLOPT_HEADER, 1);
 476      // return the header too

 477      curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: text/xml'));
 478      // required for XMLRPC

 479      if ($timeout) curl_setopt($curl, CURLOPT_TIMEOUT, $timeout == 1 ? 1 :
 480                    $timeout - 1);
 481      // timeout is borked

 482      if ($username && $password) curl_setopt($curl, CURLOPT_USERPWD,
 483                          "$username:$password"); 
 484      // set auth stuff

 485      if ($cert) curl_setopt($curl, CURLOPT_SSLCERT, $cert);
 486      // set cert file

 487      if ($certpass) curl_setopt($curl, CURLOPT_SSLCERTPASSWD,
 488                     $certpass);                    
 489      // set cert password

 490      
 491      $result = curl_exec($curl);
 492      
 493      if (!$result) {
 494        $resp=new xmlrpcresp(0, 
 495                 $xmlrpcerr["curl_fail"],
 496                 $xmlrpcstr["curl_fail"]. ": ". 
 497                 curl_error($curl));
 498      } else {
 499        $resp = $msg->parseResponse($result);
 500      }
 501      curl_close($curl);
 502      return $resp;
 503    }
 504  
 505  } // end class xmlrpc_client

 506  
 507  class xmlrpcresp {
 508    var $xv;
 509    var $fn;
 510    var