/** * 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; }
/** * 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; }