PageRenderTime 37ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 0ms

/core/model/modx/rest/modrestcurlclient.class.php

https://github.com/gbds/revolution
PHP | 251 lines | 145 code | 26 blank | 80 comment | 30 complexity | fc14dd163f54a5fee965413db4e16146 MD5 | raw file
  1. <?php
  2. /**
  3. * @package modx
  4. * @subpackage rest
  5. */
  6. require_once dirname(__FILE__) . '/modrestclient.class.php';
  7. /**
  8. * @package modx
  9. * @subpackage rest
  10. */
  11. class modRestCurlClient extends modRestClient {
  12. function __construct(modX &$modx,array $config = array()) {
  13. parent::__construct($modx, $config);
  14. $this->config = array_merge(array(
  15. ),$this->config);
  16. }
  17. /**
  18. * Extends modRestClient::request to provide cURL specific request handling
  19. *
  20. * {@inheritdoc}
  21. */
  22. public function request($host,$path,$method = 'GET',array $params = array(),array $options = array()) {
  23. /* start our cURL connection */
  24. $ch = curl_init();
  25. /* setup request */
  26. $this->setUrl($ch,$host,$path,$method,$params,$options);
  27. $this->setAuth($ch,$options);
  28. $this->setProxy($ch,$options);
  29. $this->setOptions($ch,$options);
  30. /* execute request */
  31. $result = trim(curl_exec($ch));
  32. /* make sure to close connection */
  33. curl_close($ch);
  34. return $result;
  35. }
  36. /**
  37. * Configure and set the URL to use, along with any request parameters.
  38. *
  39. * @param resource $ch The cURL connection resource
  40. * @see modRestClient::request for parameter documentation.
  41. */
  42. public function setUrl($ch,$host,$path,$method = 'GET',array $params = array(),array $options = array()) {
  43. $q = http_build_query($params);
  44. switch ($method) {
  45. case 'GET':
  46. $path .= '?'.$q;
  47. break;
  48. case 'POST':
  49. curl_setopt($ch,CURLOPT_POST,1);
  50. $contentType = $this->modx->getOption('contentType',$options,'xml');
  51. switch ($contentType) {
  52. case 'json':
  53. $json = $this->modx->toJSON($params);
  54. curl_setopt($ch,CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
  55. curl_setopt($ch,CURLOPT_POSTFIELDS,$json);
  56. break;
  57. case 'xml':
  58. curl_setopt($ch,CURLOPT_HTTPHEADER, array('Content-Type: application/xml'));
  59. $xml = ArrayToXML::toXML($params,!empty($options['rootNode']) ? $options['rootNode'] : 'request');
  60. curl_setopt($ch,CURLOPT_POSTFIELDS,$xml);
  61. break;
  62. default:
  63. curl_setopt($ch,CURLOPT_POSTFIELDS,$params);
  64. break;
  65. }
  66. break;
  67. }
  68. /* prevent invalid xhtml ampersands in request path */
  69. $url = str_replace('&amp;', '&', $host.$path);
  70. return curl_setopt($ch, CURLOPT_URL,$url);
  71. }
  72. /**
  73. * Set up cURL-specific options
  74. *
  75. * @param resource $ch The cURL connection resource
  76. * @param array $options An array of options
  77. */
  78. public function setOptions($ch,array $options = array()) {
  79. /* always return us the result */
  80. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  81. /* we dont want header gruft */
  82. curl_setopt($ch, CURLOPT_HEADER, 0);
  83. /* default timeout to 30 seconds */
  84. curl_setopt($ch, CURLOPT_TIMEOUT,$this->config[modRestClient::OPT_TIMEOUT]);
  85. /* disable verifypeer since it's not helpful on most environments */
  86. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
  87. /* send a useragent to allow proper responses */
  88. curl_setopt($ch, CURLOPT_USERAGENT,$this->config[modRestCurlClient::OPT_USERAGENT]);
  89. /* can only use follow location if safe_mode and open_basedir are off */
  90. $safeMode = ini_get('safe_mode');
  91. $openBasedir = ini_get('open_basedir');
  92. if (empty($safeMode) && empty($openBasedir)) {
  93. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
  94. }
  95. }
  96. /**
  97. * Set up authentication configuration , if specified, to be used with REST request.
  98. *
  99. * @param resource $ch The cURL connection resource.
  100. * @param array $options An array of options
  101. * @return boolean True if authentication was used.
  102. */
  103. public function setAuth($ch,array $options = array()) {
  104. $auth = false;
  105. if (!empty($options[modRestClient::OPT_USERPWD])) {
  106. $options[modRestClient::OPT_AUTHTYPE] = $this->modx->getOption(modRestClient::OPT_AUTHTYPE,$options,'BASIC');
  107. switch ($options[modRestClient::OPT_AUTHTYPE]) {
  108. case 'ANY': curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY); break;
  109. case 'ANYSAFE': curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANYSAFE); break;
  110. case 'DIGEST': curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST); break;
  111. case 'GSSNEGOTIATE': curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_GSSNEGOTIATE); break;
  112. case 'NTLM': curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_NTLM); break;
  113. default: case 'BASIC': curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); break;
  114. }
  115. $auth = curl_setopt($ch, CURLOPT_USERPWD, !empty($options[modRestClient::OPT_USERPWD]) ? $options[modRestClient::OPT_USERPWD] : 'username:password');
  116. }
  117. return $auth;
  118. }
  119. /**
  120. * Set up proxy configuration , if specified, to be used with REST request.
  121. *
  122. * @param resource $ch The cURL connection resource.
  123. * @param array $options An array of options
  124. * @return boolean True if the proxy was setup.
  125. */
  126. public function setProxy($ch,array $options = array()) {
  127. $proxyEnabled = false;
  128. /* if proxy is set, attempt to use it */
  129. $proxyHost = $this->modx->getOption('proxy_host',null,'');
  130. if (!empty($proxyHost)) {
  131. $proxyEnabled = curl_setopt($ch, CURLOPT_PROXY,$proxyHost);
  132. $proxyPort = $this->modx->getOption('proxy_port',null,'');
  133. if (!empty($proxyPort)) {
  134. curl_setopt($ch, CURLOPT_PROXYPORT,$proxyPort);
  135. }
  136. $proxyUserpwd = $this->modx->getOption('proxy_username',null,'');
  137. if (!empty($proxyUserpwd)) {
  138. $proxyAuthType = $this->modx->getOption('proxy_auth_type',null,'BASIC');
  139. $proxyAuthType = $proxyAuthType == 'NTLM' ? CURLAUTH_NTLM : CURLAUTH_BASIC;
  140. curl_setopt($ch, CURLOPT_PROXYAUTH,$proxyAuthType);
  141. $proxyPassword = $this->modx->getOption('proxy_password',null,'');
  142. if (!empty($proxyPassword)) $proxyUserpwd .= ':'.$proxyPassword;
  143. curl_setopt($ch, CURLOPT_PROXYUSERPWD,$proxyUserpwd);
  144. }
  145. }
  146. return $proxyEnabled;
  147. }
  148. }
  149. if (!class_exists('ArrayToXML')) {
  150. class ArrayToXML {
  151. /**
  152. * The main function for converting to an XML document.
  153. * Pass in a multi dimensional array and this recrusively loops through and builds up an XML document.
  154. *
  155. * @param array $data
  156. * @param string $rootNodeName - what you want the root node to be - defaultsto data.
  157. * @param SimpleXMLElement $xml - should only be used recursively
  158. * @return string XML
  159. */
  160. public static function toXML( $data, $rootNodeName = 'ResultSet', &$xml=null ) {
  161. // turn off compatibility mode as simple xml throws a wobbly if you don't.
  162. if ( ini_get('zend.ze1_compatibility_mode') == 1 ) ini_set ( 'zend.ze1_compatibility_mode', 0 );
  163. if ( is_null( $xml ) ) $xml = simplexml_load_string('<?xml version="1.0" encoding="UTF-8" standalone="yes"?><'.$rootNodeName.'></'.$rootNodeName.'>');
  164. // loop through the data passed in.
  165. foreach( $data as $key => $value ) {
  166. // no numeric keys in our xml please!
  167. if ( is_numeric( $key ) ) {
  168. $numeric = 1;
  169. $key = $rootNodeName;
  170. }
  171. // delete any char not allowed in XML element names
  172. $key = preg_replace('/[^a-z0-9\-\_\.\:]/i', '', $key);
  173. // if there is another array found recrusively call this function
  174. if ( is_array( $value ) ) {
  175. $node = ArrayToXML::isAssoc( $value ) || $numeric ? $xml->addChild( $key ) : $xml;
  176. // recrusive call.
  177. if ( $numeric ) $key = 'anon';
  178. ArrayToXML::toXml( $value, $key, $node );
  179. } else {
  180. // add single node.
  181. $value = htmlentities( $value );
  182. $xml->addChild( $key, $value );
  183. }
  184. }
  185. // pass back as XML
  186. //return $xml->asXML();
  187. // if you want the XML to be formatted, use the below instead to return the XML
  188. $doc = new DOMDocument('1.0');
  189. $doc->preserveWhiteSpace = false;
  190. $doc->loadXML( $xml->asXML() );
  191. $doc->formatOutput = true;
  192. return $doc->saveXML();
  193. }
  194. /**
  195. * Convert an XML document to a multi dimensional array
  196. * Pass in an XML document (or SimpleXMLElement object) and this recrusively loops through and builds a representative array
  197. *
  198. * @param string $xml - XML document - can optionally be a SimpleXMLElement object
  199. * @return array ARRAY
  200. */
  201. public static function toArray( $xml ) {
  202. if ( is_string( $xml ) ) $xml = new SimpleXMLElement( $xml );
  203. $children = $xml->children();
  204. if ( !$children ) return (string) $xml;
  205. $arr = array();
  206. foreach ( $children as $key => $node ) {
  207. $node = ArrayToXML::toArray( $node );
  208. // support for 'anon' non-associative arrays
  209. if ( $key == 'anon' ) $key = count( $arr );
  210. // if the node is already set, put it into an array
  211. if ( isset( $arr[$key] ) ) {
  212. if ( !is_array( $arr[$key] ) || $arr[$key][0] == null ) $arr[$key] = array( $arr[$key] );
  213. $arr[$key][] = $node;
  214. } else {
  215. $arr[$key] = $node;
  216. }
  217. }
  218. return $arr;
  219. }
  220. // determine if a variable is an associative array
  221. public static function isAssoc( $array ) {
  222. return (is_array($array) && 0 !== count(array_diff_key($array, array_keys(array_keys($array)))));
  223. }
  224. }
  225. }