fixed: encodes boolean and double type values for the requests
[plcapi.git] / php / plc_api.php
index 4850bfa..0c2187e 100644 (file)
@@ -8,10 +8,24 @@
 // Mark Huang <mlhuang@cs.princeton.edu>
 // Copyright (C) 2005-2006 The Trustees of Princeton University
 //
-// $Id$
-// $URL$
-//
-//
+
+//ini_set('error_reporting', 1);
+
+/*
+ * May 2017 - Ciro Scognamiglio <c.scognamiglio@cslash.net>
+ *
+ * xmlrpc php module is not compatible anymore with the PLCAPI class,
+ * if the package phpxmlrpc is installed in the same dir it will be used instead
+ *
+ * https://github.com/gggeek/phpxmlrpc
+ *
+ * If the package is not found the php module XML-RPC is used if available
+ *
+ */
+if (file_exists(__DIR__ . '/phpxmlrpc/src/Autoloader.php')) {
+    include_once __DIR__ . '/phpxmlrpc/src/Autoloader.php';
+    PhpXmlRpc\Autoloader::register();
+}
 
 require_once 'plc_config.php';
 
@@ -43,6 +57,35 @@ class PLCAPI
     $this->multicall = false;
   }
 
+  function rec_join ($arg) {
+    if ( is_array($arg) ) {
+        $ret = "";
+        foreach ( $arg as $i ) {
+            $l = $this->rec_join($i);
+            # ignore html code.
+            if ( $l[0] != "<" ) { $ret .= $l . ", "; }
+        }
+        return $ret;
+    } else {
+        settype($arg, "string");
+        return $arg;
+    }
+  }
+
+  function backtrace_php () {
+    $backtrace = debug_backtrace();
+    $msg = "";
+    $len = count($backtrace);
+    $cnt = 1;
+    foreach( array_reverse($backtrace) as $line ) {
+        $msg .= "File '". $line['file'] . "' line " . $line['line'] . "\n";
+        $msg .= "    " . $line['function'] . "( "  . $this->rec_join($line['args']) . ")\n";
+        $cnt += 1;
+        if ( $cnt == $len ) { break; }
+    }
+    return $msg;
+  }
+
   function error_log($error_msg, $backtrace_level = 1)
   {
     $backtrace = debug_backtrace();
@@ -53,7 +96,12 @@ class PLCAPI
     if ($file) $error_line .= ' in file ' . $file;
     if ($line) $error_line .= ' on line ' . $line;
     $this->errors[] = $error_line;
-    error_log($error_line);
+    # TODO: setup a config variable for more detailed stack traces, for API errors.
+    if ( TRUE ){
+      error_log($error_line);
+    } else {
+       error_log($this->backtrace_php());
+    }
   }
 
   function error()
@@ -84,11 +132,114 @@ class PLCAPI
                                'params' => $args);
       return NULL;
     } else {
-      return $this->internal_call ($method, $args, 3);
+      return $this->internal_call($method, $args, 3);
+    }
+  }
+
+  /*
+   * Use PhpXmlRpc\Value before encoding the request
+   */
+  function xmlrpcValue($value) {
+      switch(gettype($value)) {
+          case 'array':
+              $members = array();
+              foreach($value as $vk => $vv) {
+                  $members[$vk] = $this->xmlrpcValue($vv);
+              }
+
+              if (array_key_exists(0, $value)) {
+                  return new PhpXmlRpc\Value(
+                      $members,
+                      'array'
+                  );
+              } else {
+                  return new PhpXmlRpc\Value(
+                      $members,
+                      'struct'
+                  );
+              }
+
+              break;
+          case 'double':
+              return new PhpXmlRpc\Value($value, 'double');
+              break;
+          case 'boolean':
+              return new PhpXmlRpc\Value($value, 'boolean');
+              break;
+          case 'NULL':
+          case 'null':
+              return new PhpXmlRpc\Value(null, 'null');
+              break;
+          case 'integer':
+              return new PhpXmlRpc\Value($value, 'int');
+              break;
+          default:
+            if (empty($value)) {
+                return new PhpXmlRpc\Value(null, 'null');
+            } else {
+                return new PhpXmlRpc\Value($value);
+            }
+
+              break;
+      }
+  }
+
+    function internal_call($method, $args = NULL, $backtrace_level = 2)
+    {
+        if (class_exists('PhpXmlRpc\\PhpXmlRpc')) {
+            return $this->internal_call_phpxmlrpc($method, $args, $backtrace_level);
+        } else {
+            return $this->internal_call_xmlrpc($method, $args, $backtrace_level);
+        }
     }
+
+  /*
+   * the new internal call, will use PhpXmlRpc
+   */
+  function internal_call_phpxmlrpc($method, $args = NULL, $backtrace_level = 2)
+  {
+
+
+      PhpXmlRpc\PhpXmlRpc::$xmlrpc_null_extension = true;
+
+      if ($this->port == 443) {
+          $url = 'https://';
+      } else {
+          $url = 'http://';
+      }
+
+      // Set the URL for the request
+      $url .= $this->server . ':' . $this->port . '/' . $this->path;
+
+      $client = new PhpXmlRpc\Client($url);
+      $client->setSSLVerifyPeer(false);
+      /*
+       * 1 -> not verify CN
+       * 2 -> verify CN (default)
+       */
+      $client->setSSLVerifyHost(1);
+
+      $values = $this->xmlrpcValue($args);
+
+      $response = $client->send(new PhpXmlRpc\Request($method, $values));
+
+
+      if (!$response->faultCode()) {
+          $encoder = new PhpXmlRpc\Encoder();
+          $v = $encoder->decode($response->value());
+
+          return $v;
+      } else {
+          $this->error_log("An error occurred [" . $response->faultCode() . "] ".
+              $response->faultString());
+          return NULL;
+      }
   }
 
-  function internal_call($method, $args = NULL, $backtrace_level = 2)
+  /*
+   * The original internal call that uses php XML-RPC
+   */
+  function internal_call_xmlrpc($method, $args = NULL, $backtrace_level = 2)
   {
     $curl = curl_init();
 
@@ -112,7 +263,7 @@ class PLCAPI
     // Marshal the XML-RPC request as a POST variable. <nil/> is an
     // extension to the XML-RPC spec that is supported in our custom
     // version of xmlrpc.so via the 'allow_null' output_encoding key.
-    $request = xmlrpc_encode_request($method, $args, array('allow_null' => TRUE));
+    $request = xmlrpc_encode_request($method, $args, array('null_extension'));
     curl_setopt($curl, CURLOPT_POSTFIELDS, $request);
 
     // Construct the HTTP header
@@ -162,14 +313,19 @@ class PLCAPI
     $this->multicall = true;
   }
 
+  function xmlrpc_is_fault($arr)
+    {
+        // check if xmlrpc_is_fault exists
+        return is_array($arr) && array_key_exists('faultCode', $arr) && array_key_exists('faultString', $arr);
+    }
   function commit()
   {
     if (!empty ($this->calls)) {
       $ret = array();
-      $results = $this->internal_call ('system.multicall', array ($this->calls));
+      $results = $this->internal_call('system.multicall', array ($this->calls));
       foreach ($results as $result) {
         if (is_array($result)) {
-          if (xmlrpc_is_fault($result)) {
+          if ($this->xmlrpc_is_fault($result)) {
             $this->error_log('Fault Code ' . $result['faultCode'] . ': ' .
                              $result['faultString'], 1, true);
             $ret[] = NULL;