PageRenderTime 21ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://gitlab.com/haque.mdmanzurul/modx-improve-carolyn
PHP | 298 lines | 155 code | 25 blank | 118 comment | 36 complexity | 2b30f837fc263c0c7bf57c397681ae65 MD5 | raw file
  1. <?php
  2. /**
  3. * @package modx
  4. * @subpackage rest
  5. */
  6. require_once dirname(__FILE__) . '/modrestclient.class.php';
  7. /**
  8. * Handles REST requests through a cURL-based client
  9. *
  10. * @deprecated To be removed in 2.3. See modRest instead.
  11. *
  12. * @package modx
  13. * @subpackage rest
  14. */
  15. class modRestCurlClient extends modRestClient {
  16. /**
  17. * @param modX $modx A reference to the modX object
  18. * @param array $config An array of configuration options
  19. */
  20. function __construct(modX &$modx,array $config = array()) {
  21. parent::__construct($modx, $config);
  22. $this->config = array_merge(array(
  23. ),$this->config);
  24. }
  25. /**
  26. * Extends modRestClient::request to provide cURL specific request handling
  27. *
  28. * @param string $host The host of the REST server.
  29. * @param string $path The path to request to on the REST server.
  30. * @param string $method The HTTP method to use for the request. May be GET,
  31. * PUT or POST.
  32. * @param array $params An array of parameters to send with the request.
  33. * @param array $options An array of options to pass to the request.
  34. * @return modRestResponse The response object.
  35. */
  36. public function request($host,$path,$method = 'GET',array $params = array(),array $options = array()) {
  37. /* start our cURL connection */
  38. $ch = curl_init();
  39. /* setup request */
  40. $this->setUrl($ch,$host,$path,$method,$params,$options);
  41. $this->setAuth($ch,$options);
  42. $this->setProxy($ch,$options);
  43. $this->setOptions($ch,$options);
  44. /* execute request */
  45. $result = trim(curl_exec($ch));
  46. /* make sure to close connection */
  47. curl_close($ch);
  48. return $result;
  49. }
  50. /**
  51. * Configure and set the URL to use, along with any request parameters.
  52. *
  53. * @param resource $ch The cURL connection resource
  54. * @param string $host The host to send the request to
  55. * @param string $path The path of the request
  56. * @param string $method The method of the request (GET/POST)
  57. * @param array $params An array of request parameters to attach to the URL
  58. * @param array $options An array of options when setting the URL
  59. * @return boolean Whether or not the URL was set
  60. * @see modRestClient::request for parameter documentation.
  61. */
  62. public function setUrl($ch,$host,$path,$method = 'GET',array $params = array(),array $options = array()) {
  63. $q = http_build_query($params);
  64. switch ($method) {
  65. case 'GET':
  66. $path .= (strpos($host,'?') === false ? '?' : '&').$q;
  67. break;
  68. case 'POST':
  69. curl_setopt($ch,CURLOPT_POST,1);
  70. $contentType = $this->modx->getOption('contentType',$options,'xml');
  71. switch ($contentType) {
  72. case 'json':
  73. $json = $this->modx->toJSON($params);
  74. curl_setopt($ch,CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
  75. curl_setopt($ch,CURLOPT_POSTFIELDS,$json);
  76. break;
  77. case 'xml':
  78. curl_setopt($ch,CURLOPT_HTTPHEADER, array('Content-Type: application/xml'));
  79. $xml = modRestArrayToXML::toXML($params,!empty($options['rootNode']) ? $options['rootNode'] : 'request');
  80. curl_setopt($ch,CURLOPT_POSTFIELDS,$xml);
  81. break;
  82. default:
  83. curl_setopt($ch,CURLOPT_POSTFIELDS,$params);
  84. break;
  85. }
  86. break;
  87. }
  88. /* prevent invalid xhtml ampersands in request path and strip unnecessary ampersands from the end of the url */
  89. $url = rtrim(str_replace('&amp;', '&', $host.$path), '&');
  90. return curl_setopt($ch, CURLOPT_URL,$url);
  91. }
  92. /**
  93. * Set up cURL-specific options
  94. *
  95. * @param resource $ch The cURL connection resource
  96. * @param array $options An array of options
  97. */
  98. public function setOptions($ch,array $options = array()) {
  99. /* always return us the result */
  100. curl_setopt($ch, CURLOPT_RETURNTRANSFER, !empty($options['curlopt_returntransfer']) ? $options['curlopt_returntransfer'] : 1);
  101. /* we dont want header gruft */
  102. curl_setopt($ch, CURLOPT_HEADER, !empty($options['curlopt_header']) ? $options['curlopt_header'] : 0);
  103. /* change the request type to HEAD, mostly used in conjunction with curlopt_header to reduce transfer size in remote file checks */
  104. curl_setopt($ch, CURLOPT_NOBODY, !empty($options['curlopt_nobody']) ? $options['curlopt_nobody'] : 0);
  105. /* attempt to retrieve the modification date of the remote document for use with curl_getinfo() */
  106. curl_setopt($ch, CURLOPT_FILETIME, !empty($options['curlopt_filetime']) ? $options['curlopt_filetime'] : 0);
  107. /* default timeout to 30 seconds */
  108. curl_setopt($ch, CURLOPT_TIMEOUT, !empty($options['curlopt_timeout']) ? $options['curlopt_timeout'] : $this->config[modRestClient::OPT_TIMEOUT]);
  109. /* disable verifypeer since it's not helpful on most environments */
  110. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, !empty($options['curlopt_ssl_verifypeer']) ? $options['curlopt_ssl_verifypeer'] : 0);
  111. /* send a useragent to allow proper responses */
  112. curl_setopt($ch, CURLOPT_USERAGENT, !empty($options['curlopt_useragent']) ? $options['curlopt_useragent'] : $this->config[modRestClient::OPT_USERAGENT]);
  113. /* send a custom referer if provided */
  114. if (!empty($options['curlopt_referer'])) { curl_setopt($ch, CURLOPT_REFERER, $options['curlopt_referer']); }
  115. /* handle upload options */
  116. if (!empty($options['curlopt_usrpwd'])) { curl_setopt($ch, CURLOPT_USERPWD, $options['curlopt_usrpwd']); }
  117. if (!empty($options['curlopt_upload'])) { curl_setopt($ch, CURLOPT_UPLOAD, $options['curlopt_upload']); }
  118. if (!empty($options['curlopt_infile'])) { curl_setopt($ch, CURLOPT_INFILE, $options['curlopt_infile']); }
  119. if (!empty($options['curlopt_infilesize'])) { curl_setopt($ch, CURLOPT_INFILESIZE, $options['curlopt_infilesize']); }
  120. if (!empty($options['curlopt_file']) ) { curl_setopt($ch, CURLOPT_FILE, $options['curlopt_file']); } // directly write to file
  121. /* close connection, connection is not pooled to reuse */
  122. curl_setopt($ch, CURLOPT_FORBID_REUSE, !empty($options['curlopt_forbid_reuse']) ? $options['curlopt_forbid_reuse'] : 0);
  123. /* force the use of a new connection instead of a cached one */
  124. curl_setopt($ch, CURLOPT_FRESH_CONNECT, !empty($options['curlopt_fresh_connect']) ? $options['curlopt_fresh_connect'] : 0);
  125. /* can only use follow location if safe_mode and open_basedir are off */
  126. $safeMode = ini_get('safe_mode');
  127. $openBasedir = ini_get('open_basedir');
  128. if (empty($safeMode) && empty($openBasedir)) {
  129. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, !empty($options['curlopt_followlocation']) ? $options['curlopt_followlocation'] : 1);
  130. }
  131. }
  132. /**
  133. * Set up authentication configuration , if specified, to be used with REST request.
  134. *
  135. * @param resource $ch The cURL connection resource.
  136. * @param array $options An array of options
  137. * @return boolean True if authentication was used.
  138. */
  139. public function setAuth($ch,array $options = array()) {
  140. $auth = false;
  141. if (!empty($options[modRestClient::OPT_USERPWD])) {
  142. $options[modRestClient::OPT_AUTHTYPE] = $this->modx->getOption(modRestClient::OPT_AUTHTYPE,$options,'BASIC');
  143. switch ($options[modRestClient::OPT_AUTHTYPE]) {
  144. case 'ANY': curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY); break;
  145. case 'ANYSAFE': curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANYSAFE); break;
  146. case 'DIGEST': curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST); break;
  147. case 'GSSNEGOTIATE': curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_GSSNEGOTIATE); break;
  148. case 'NTLM': curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_NTLM); break;
  149. default: case 'BASIC': curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); break;
  150. }
  151. $auth = curl_setopt($ch, CURLOPT_USERPWD, !empty($options[modRestClient::OPT_USERPWD]) ? $options[modRestClient::OPT_USERPWD] : 'username:password');
  152. }
  153. return $auth;
  154. }
  155. /**
  156. * Set up proxy configuration , if specified, to be used with REST request.
  157. *
  158. * @param resource $ch The cURL connection resource.
  159. * @param array $options An array of options
  160. * @return boolean True if the proxy was setup.
  161. */
  162. public function setProxy($ch,array $options = array()) {
  163. $proxyEnabled = false;
  164. /* if proxy is set, attempt to use it */
  165. $proxyHost = $this->modx->getOption('proxy_host',null,'');
  166. if (!empty($proxyHost)) {
  167. $proxyEnabled = curl_setopt($ch, CURLOPT_PROXY,$proxyHost);
  168. $proxyPort = $this->modx->getOption('proxy_port',null,'');
  169. if (!empty($proxyPort)) {
  170. curl_setopt($ch, CURLOPT_PROXYPORT,$proxyPort);
  171. }
  172. $proxyUserpwd = $this->modx->getOption('proxy_username',null,'');
  173. if (!empty($proxyUserpwd)) {
  174. $proxyAuthType = $this->modx->getOption('proxy_auth_type',null,'BASIC');
  175. $proxyAuthType = $proxyAuthType == 'NTLM' ? CURLAUTH_NTLM : CURLAUTH_BASIC;
  176. curl_setopt($ch, CURLOPT_PROXYAUTH,$proxyAuthType);
  177. $proxyPassword = $this->modx->getOption('proxy_password',null,'');
  178. if (!empty($proxyPassword)) $proxyUserpwd .= ':'.$proxyPassword;
  179. curl_setopt($ch, CURLOPT_PROXYUSERPWD,$proxyUserpwd);
  180. }
  181. }
  182. return $proxyEnabled;
  183. }
  184. }
  185. if (!class_exists('modRestArrayToXML')) {
  186. /**
  187. * Utility class for array-to-XML transformations.
  188. *
  189. * @package modx
  190. * @subpackage rest
  191. */
  192. class modRestArrayToXML {
  193. /**
  194. * The main function for converting to an XML document.
  195. * Pass in a multi dimensional array and this recrusively loops through and builds up an XML document.
  196. *
  197. * @param array $data
  198. * @param string $rootNodeName - what you want the root node to be - defaultsto data.
  199. * @param SimpleXMLElement $xml - should only be used recursively
  200. * @return string XML
  201. */
  202. public static function toXML( $data, $rootNodeName = 'ResultSet', &$xml=null ) {
  203. // turn off compatibility mode as simple xml throws a wobbly if you don't.
  204. if ( ini_get('zend.ze1_compatibility_mode') == 1 ) ini_set ( 'zend.ze1_compatibility_mode', 0 );
  205. if ( is_null( $xml ) ) $xml = simplexml_load_string('<?xml version="1.0" encoding="UTF-8" standalone="yes"?><'.$rootNodeName.'></'.$rootNodeName.'>');
  206. // loop through the data passed in.
  207. foreach( $data as $key => $value ) {
  208. // no numeric keys in our xml please!
  209. if ( is_numeric( $key ) ) {
  210. $numeric = 1;
  211. $key = $rootNodeName;
  212. }
  213. // delete any char not allowed in XML element names
  214. $key = preg_replace('/[^a-z0-9\-\_\.\:]/i', '', $key);
  215. // if there is another array found recrusively call this function
  216. if ( is_array( $value ) ) {
  217. $node = modRestArrayToXML::isAssoc( $value ) || $numeric ? $xml->addChild( $key ) : $xml;
  218. // recrusive call.
  219. if ( $numeric ) $key = 'anon';
  220. modRestArrayToXML::toXml( $value, $key, $node );
  221. } else {
  222. // add single node.
  223. $value = htmlentities( $value );
  224. $xml->addChild( $key, $value );
  225. }
  226. }
  227. // pass back as XML
  228. //return $xml->asXML();
  229. // if you want the XML to be formatted, use the below instead to return the XML
  230. $doc = new DOMDocument('1.0');
  231. $doc->preserveWhiteSpace = false;
  232. $doc->loadXML( $xml->asXML() );
  233. $doc->formatOutput = true;
  234. return $doc->saveXML();
  235. }
  236. /**
  237. * Convert an XML document to a multi dimensional array
  238. * Pass in an XML document (or SimpleXMLElement object) and this recrusively loops through and builds a representative array
  239. *
  240. * @param string $xml - XML document - can optionally be a SimpleXMLElement object
  241. * @return array ARRAY
  242. */
  243. public static function toArray( $xml ) {
  244. if ( is_string( $xml ) ) $xml = new SimpleXMLElement( $xml );
  245. $children = $xml->children();
  246. if ( !$children ) return (string) $xml;
  247. $arr = array();
  248. foreach ( $children as $key => $node ) {
  249. $node = modRestArrayToXML::toArray( $node );
  250. // support for 'anon' non-associative arrays
  251. if ( $key == 'anon' ) $key = count( $arr );
  252. // if the node is already set, put it into an array
  253. if ( isset( $arr[$key] ) ) {
  254. if ( !is_array( $arr[$key] ) || $arr[$key][0] == null ) $arr[$key] = array( $arr[$key] );
  255. $arr[$key][] = $node;
  256. } else {
  257. $arr[$key] = $node;
  258. }
  259. }
  260. return $arr;
  261. }
  262. /**
  263. * Determine if a variable is an associative array
  264. *
  265. * @static
  266. * @param mixed $array The variable to check
  267. * @return boolean True if is an array
  268. */
  269. public static function isAssoc( $array ) {
  270. return (is_array($array) && 0 !== count(array_diff_key($array, array_keys(array_keys($array)))));
  271. }
  272. }
  273. }