/**
  * Transforms XML data to array.
  *
  * @param string $xml XML data.
  * @param string[] $namespaces List of namespaces to include in parsing or empty to include all namespaces.
  * @return array
  */
 function ky_xml_to_array($xml, $namespaces = null)
 {
     $iter = 0;
     $arr = array();
     if (is_string($xml)) {
         $xml = new SimpleXMLElement($xml);
     }
     if (!$xml instanceof SimpleXMLElement) {
         return $arr;
     }
     if ($namespaces === null) {
         $namespaces = $xml->getDocNamespaces(true);
     }
     foreach ($xml->attributes() as $attributeName => $attributeValue) {
         $arr["_attributes"][$attributeName] = trim($attributeValue);
     }
     foreach ($namespaces as $namespace_prefix => $namespace_name) {
         foreach ($xml->attributes($namespace_prefix, true) as $attributeName => $attributeValue) {
             $arr["_attributes"][$namespace_prefix . ':' . $attributeName] = trim($attributeValue);
         }
     }
     $has_children = false;
     foreach ($xml->children() as $element) {
         /** @var $element SimpleXMLElement */
         $has_children = true;
         $elementName = $element->getName();
         if ($element->children()) {
             $arr[$elementName][] = ky_xml_to_array($element, $namespaces);
         } else {
             $shouldCreateArray = array_key_exists($elementName, $arr) && !is_array($arr[$elementName]);
             if ($shouldCreateArray) {
                 $arr[$elementName] = array($arr[$elementName]);
             }
             $shouldAddValueToArray = array_key_exists($elementName, $arr) && is_array($arr[$elementName]);
             if ($shouldAddValueToArray) {
                 $arr[$elementName][] = trim($element[0]);
             } else {
                 $arr[$elementName] = trim($element[0]);
             }
         }
         $iter++;
     }
     if (!$has_children) {
         $arr['_contents'] = trim($xml[0]);
     }
     return $arr;
 }
Exemple #2
0
 /**
  * Sends the request to Kayako server and returns parsed response.
  *
  * @param string $controller Kayako controller to call. Null to use default controller defined for object.
  * @param string $method HTTP verb.
  * @param array $parameters Optional. List of additional parameters (like object identifiers or search parameters).
  * @param array $data Optional. Data array with parameter name as key and parameter value as value.
  * @param array $files Optional. Array of files in form of: array('<parameter name>' => array('file_name' => '<file name>', 'contents' => '<file contents>'), ...).
  * @return array
  */
 protected function processRequest($controller, $method, $parameters = array(), $data = array(), $files = array())
 {
     $url = $this->getRequestData($controller, $method, $parameters, $data);
     $headers = array();
     $request_body = $this->buildPostBody($data, $files, $headers);
     $curl_options = array(CURLOPT_HEADER => false, CURLOPT_RETURNTRANSFER => true, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSL_VERIFYHOST => false, CURLOPT_CONNECTTIMEOUT => 2, CURLOPT_FORBID_REUSE => true, CURLOPT_FRESH_CONNECT => true, CURLOPT_HTTPHEADER => $headers, CURLOPT_URL => $url);
     switch ($method) {
         case self::METHOD_GET:
             break;
         case self::METHOD_POST:
             $curl_options[CURLOPT_POSTFIELDS] = $request_body;
             $curl_options[CURLOPT_POST] = true;
             break;
         case self::METHOD_PUT:
             if ($this->config->isPUTAsMemoryStream()) {
                 $fh = fopen('php://memory', 'rw');
                 fwrite($fh, $request_body);
                 rewind($fh);
                 $curl_options[CURLOPT_INFILE] = $fh;
                 $curl_options[CURLOPT_INFILESIZE] = strlen($request_body);
                 $curl_options[CURLOPT_PUT] = true;
             } else {
                 $curl_options[CURLOPT_CUSTOMREQUEST] = 'PUT';
                 $curl_options[CURLOPT_POSTFIELDS] = $request_body;
             }
             break;
         case self::METHOD_DELETE:
             $curl_options[CURLOPT_CUSTOMREQUEST] = 'DELETE';
             break;
     }
     $curl_options[CURLOPT_HTTPHEADER] = $headers;
     if ($this->config->isDebugEnabled()) {
         error_log('Sending REST request to Kayako:');
         error_log(sprintf('  %s: %s', $method, $curl_options[CURLOPT_URL]));
         if ($method === self::METHOD_POST || $method === self::METHOD_PUT) {
             error_log(sprintf('  Body: %s', $request_body));
         }
     }
     $curl_handle = curl_init();
     curl_setopt_array($curl_handle, $curl_options);
     $response = curl_exec($curl_handle);
     if ($this->config->isDebugEnabled()) {
         error_log('Response from Kayako server:');
         error_log($response);
     }
     //removing any output prior to proper XML response (ex. Kayako notices)
     $xml_start_pos = stripos($response, "<?xml");
     if ($xml_start_pos > 0) {
         $response = substr($response, $xml_start_pos);
     }
     if ($response === false) {
         throw new kyException(sprintf('CURL error: %s (%s)', curl_error($curl_handle), curl_errno($curl_handle)));
     }
     $http_status = curl_getinfo($curl_handle, CURLINFO_HTTP_CODE);
     if ($http_status != 200) {
         throw new kyException(sprintf("HTTP error: %s", $http_status));
     }
     curl_close($curl_handle);
     if ($method === self::METHOD_DELETE) {
         return null;
     }
     $result = ky_xml_to_array($response);
     if ($result === false) {
         throw new kyException("Error parsing XML response.");
     }
     if (count($result) === 1 && array_key_exists('_contents', $result) && strlen($result['_contents']) === 0) {
         $result = array();
     }
     return $result;
 }