PageRenderTime 54ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/wp-admin/includes/cm/class/transport.php

https://bitbucket.org/Cmastris/shields-buildings
PHP | 352 lines | 265 code | 69 blank | 18 comment | 38 complexity | 93ec9260c9e9a93f32606451c9a23b89 MD5 | raw file
Possible License(s): MIT
  1. <?php
  2. defined('CS_REST_GET') or define('CS_REST_GET', 'GET');
  3. defined('CS_REST_POST') or define('CS_REST_POST', 'POST');
  4. defined('CS_REST_PUT') or define('CS_REST_PUT', 'PUT');
  5. defined('CS_REST_DELETE') or define('CS_REST_DELETE', 'DELETE');
  6. if (false === defined('CS_REST_SOCKET_TIMEOUT')) {
  7. define('CS_REST_SOCKET_TIMEOUT', 10);
  8. }
  9. if (false === defined('CS_REST_CALL_TIMEOUT')) {
  10. define('CS_REST_CALL_TIMEOUT', 10);
  11. }
  12. if(!function_exists("CS_REST_TRANSPORT_get_available")) {
  13. function CS_REST_TRANSPORT_get_available($requires_ssl, $log) {
  14. if(function_exists('curl_init') && function_exists('curl_exec')) {
  15. return new CS_REST_CurlTransport($log);
  16. } else if(CS_REST_TRANSPORT_can_use_raw_socket($requires_ssl)) {
  17. return new CS_REST_SocketTransport($log);
  18. } else {
  19. $log->log_message('No transport is available', __FUNCTION__, CS_REST_LOG_ERROR);
  20. trigger_error('No transport is available.'.
  21. ($requires_ssl ? ' Try using non-secure (http) mode or ' : ' Please ').
  22. 'ensure the cURL extension is loaded', E_USER_ERROR);
  23. }
  24. }
  25. }
  26. if(!function_exists("CS_REST_TRANSPORT_can_use_raw_socket")) {
  27. function CS_REST_TRANSPORT_can_use_raw_socket($requires_ssl) {
  28. if(function_exists('fsockopen')) {
  29. if($requires_ssl) {
  30. return extension_loaded('openssl');
  31. }
  32. return true;
  33. }
  34. return false;
  35. }
  36. }
  37. if (!class_exists('CS_REST_BaseTransport')) {
  38. class CS_REST_BaseTransport {
  39. var $_log;
  40. function __construct($log) {
  41. $this->_log = $log;
  42. }
  43. function split_and_inflate($response, $may_be_compressed) {
  44. $ra = explode("\r\n\r\n", $response);
  45. $result = array_pop($ra);
  46. $headers = array_pop($ra);
  47. if($may_be_compressed && preg_match('/^Content-Encoding:\s+gzip\s+$/im', $headers)) {
  48. $original_length = strlen($response);
  49. $result = gzinflate(substr($result, 10, -8));
  50. $this->_log->log_message('Inflated gzipped response: '.$original_length.' bytes ->'.
  51. strlen($result).' bytes', get_class(), CS_REST_LOG_VERBOSE);
  52. }
  53. return array($headers, $result);
  54. }
  55. }
  56. }
  57. /**
  58. * Provide HTTP request functionality via cURL extensions
  59. *
  60. * @author tobyb
  61. * @since 1.0
  62. */
  63. if (!class_exists('CS_REST_CurlTransport')) {
  64. class CS_REST_CurlTransport extends CS_REST_BaseTransport {
  65. var $_curl_zlib;
  66. function __construct($log) {
  67. parent::__construct($log);
  68. $curl_version = curl_version();
  69. $this->_curl_zlib = isset($curl_version['libz_version']);
  70. }
  71. /**
  72. * @return string The type of transport used
  73. */
  74. function get_type() {
  75. return 'cURL';
  76. }
  77. function make_call($call_options) {
  78. $ch = curl_init();
  79. curl_setopt($ch, CURLOPT_URL, $call_options['route']);
  80. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  81. curl_setopt($ch, CURLOPT_HEADER, true);
  82. $headers = array();
  83. $headers[] = 'Content-Type: '.$call_options['contentType'];
  84. if (array_key_exists('authdetails', $call_options) &&
  85. isset($call_options['authdetails'])) {
  86. if (array_key_exists('username', $call_options['authdetails']) &&
  87. array_key_exists('password', $call_options['authdetails'])) {
  88. # Authenticating using basic auth for retrieving user's API key.
  89. curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
  90. curl_setopt($ch, CURLOPT_USERPWD, $call_options['authdetails']['username'].':'.$call_options['authdetails']['password']);
  91. } elseif (array_key_exists('access_token', $call_options['authdetails'])) {
  92. # Authenticating using OAuth.
  93. $access_token = $call_options['authdetails']['access_token'];
  94. $headers[] = 'Authorization: Bearer '.$access_token;
  95. } elseif (array_key_exists('api_key', $call_options['authdetails'])) {
  96. # Authenticating using an API key.
  97. curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
  98. $api_key = $call_options['authdetails']['api_key'];
  99. curl_setopt($ch, CURLOPT_USERPWD, $api_key.':nopass');
  100. }
  101. }
  102. curl_setopt($ch, CURLOPT_USERAGENT, $call_options['userAgent']);
  103. curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, CS_REST_SOCKET_TIMEOUT);
  104. curl_setopt($ch, CURLOPT_TIMEOUT, CS_REST_CALL_TIMEOUT);
  105. $inflate_response = false;
  106. if($this->_curl_zlib) {
  107. $this->_log->log_message('curl+zlib support available. Requesting gzipped response.',
  108. get_class($this), CS_REST_LOG_VERBOSE);
  109. curl_setopt($ch, CURLOPT_ENCODING, 'gzip');
  110. } else if(function_exists('gzinflate')) {
  111. $headers[] = 'Accept-Encoding: gzip';
  112. $inflate_response = true;
  113. }
  114. if($call_options['protocol'] === 'https') {
  115. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
  116. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
  117. if(strlen(ini_get('curl.cainfo')) === 0) {
  118. curl_setopt($ch, CURLOPT_CAINFO, dirname(__FILE__).'/cacert.pem');
  119. }
  120. }
  121. switch($call_options['method']) {
  122. case CS_REST_PUT:
  123. curl_setopt($ch, CURLOPT_CUSTOMREQUEST, CS_REST_PUT);
  124. $headers[] = 'Content-Length: '.strlen($call_options['data']);
  125. curl_setopt($ch, CURLOPT_POSTFIELDS, $call_options['data']);
  126. break;
  127. case CS_REST_POST:
  128. curl_setopt($ch, CURLOPT_POST, true);
  129. curl_setopt($ch, CURLOPT_POSTFIELDS, isset($call_options['data']) ? $call_options['data'] : '');
  130. break;
  131. case CS_REST_DELETE:
  132. curl_setopt($ch, CURLOPT_CUSTOMREQUEST, CS_REST_DELETE);
  133. break;
  134. }
  135. if(count($headers) > 0) {
  136. curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  137. }
  138. $response = curl_exec($ch);
  139. if(!$response && $response !== '') {
  140. $this->_log->log_message('Error making request with curl_error: '.curl_errno($ch),
  141. get_class($this), CS_REST_LOG_ERROR);
  142. require_once dirname(__FILE__).'/exceptions.php';
  143. throw new CurlException(curl_error($ch), curl_errno($ch));
  144. }
  145. list( $headers, $result ) = $this->split_and_inflate($response, $inflate_response);
  146. $this->_log->log_message('API Call Info for '.$call_options['method'].' '.
  147. curl_getinfo($ch, CURLINFO_EFFECTIVE_URL).': '.curl_getinfo($ch, CURLINFO_SIZE_UPLOAD).
  148. ' bytes uploaded. '.curl_getinfo($ch, CURLINFO_SIZE_DOWNLOAD).' bytes downloaded'.
  149. ' Total time (seconds): '.curl_getinfo($ch, CURLINFO_TOTAL_TIME),
  150. get_class($this), CS_REST_LOG_VERBOSE);
  151. $result = array(
  152. 'code' => curl_getinfo($ch, CURLINFO_HTTP_CODE),
  153. 'response' => $result
  154. );
  155. curl_close($ch);
  156. return $result;
  157. }
  158. }
  159. }
  160. if (!class_exists('CS_REST_SocketWrapper')) {
  161. class CS_REST_SocketWrapper {
  162. var $socket;
  163. function open($domain, $port) {
  164. $this->socket = fsockopen($domain, $port, $errno, $errstr, CS_REST_SOCKET_TIMEOUT);
  165. if(!$this->socket) {
  166. die('Error making request with '.$errno.': '.$errstr);
  167. return false;
  168. } else if(function_exists('stream_set_timeout')) {
  169. stream_set_timeout($this->socket, CS_REST_SOCKET_TIMEOUT);
  170. }
  171. return true;
  172. }
  173. function write($data) {
  174. fwrite($this->socket, $data);
  175. }
  176. function read() {
  177. ob_start();
  178. fpassthru($this->socket);
  179. return ob_get_clean();
  180. }
  181. function close() {
  182. fclose($this->socket);
  183. }
  184. }
  185. }
  186. if (!class_exists('CS_REST_SocketTransport')) {
  187. class CS_REST_SocketTransport extends CS_REST_BaseTransport {
  188. var $_socket_wrapper;
  189. function __construct($log, $socket_wrapper = NULL) {
  190. parent::__construct($log);
  191. if(is_null($socket_wrapper)) {
  192. $socket_wrapper = new CS_REST_SocketWrapper();
  193. }
  194. $this->_socket_wrapper = $socket_wrapper;
  195. }
  196. /**
  197. * @return string The type of transport used
  198. */
  199. function get_type() {
  200. return 'Socket';
  201. }
  202. function make_call($call_options) {
  203. $start_host = strpos($call_options['route'], $call_options['host']);
  204. $host_len = strlen($call_options['host']);
  205. $domain = substr($call_options['route'], $start_host, $host_len);
  206. $host = $domain;
  207. $path = substr($call_options['route'], $start_host + $host_len);
  208. $protocol = substr($call_options['route'], 0, $start_host);
  209. $port = 80;
  210. $this->_log->log_message('Creating socket to '.$domain.' over '.$protocol.' for request to '.$path,
  211. get_class($this), CS_REST_LOG_VERBOSE);
  212. if($protocol === 'https://') {
  213. $domain = 'ssl://'.$domain;
  214. $port = 443;
  215. }
  216. if($this->_socket_wrapper->open($domain, $port)) {
  217. $inflate_response = function_exists('gzinflate');
  218. $request = $this->_build_request($call_options, $host, $path, $inflate_response);
  219. $this->_log->log_message('Sending <pre>'.$request.'</pre> down the socket',
  220. get_class($this), CS_REST_LOG_VERBOSE);
  221. $this->_socket_wrapper->write($request);
  222. $response = $this->_socket_wrapper->read();
  223. $this->_socket_wrapper->close();
  224. $this->_log->log_message('API Call Info for '.$call_options['method'].' '.
  225. $call_options['route'].': '.strlen($request).
  226. ' bytes uploaded. '.strlen($response).' bytes downloaded',
  227. get_class($this), CS_REST_LOG_VERBOSE);
  228. list( $headers, $result ) = $this->split_and_inflate($response, $inflate_response);
  229. $this->_log->log_message('Received headers <pre>'.$headers.'</pre>',
  230. get_class($this), CS_REST_LOG_VERBOSE);
  231. return array(
  232. 'code' => $this->_get_status_code($headers),
  233. 'response' => trim($result)
  234. );
  235. }
  236. }
  237. function _get_status_code($headers) {
  238. if (preg_match('%^\s*HTTP/1\.1 (?P<code>\d{3})%', $headers, $regs)) {
  239. $this->_log->log_message('Got HTTP Status Code: '.$regs['code'],
  240. get_class($this), CS_REST_LOG_VERBOSE);
  241. return $regs['code'];
  242. }
  243. $this->_log->log_message('Failed to get HTTP status code from request headers <pre>'.$headers.'</pre>',
  244. get_class($this), CS_REST_LOG_ERROR);
  245. trigger_error('Failed to get HTTP status code from request', E_USER_ERROR);
  246. }
  247. function _build_request($call_options, $host, $path, $accept_gzip) {
  248. $request_auth_details = '';
  249. if (array_key_exists('authdetails', $call_options)) {
  250. if (array_key_exists('username', $call_options['authdetails']) &&
  251. array_key_exists('password', $call_options['authdetails'])) {
  252. # Authenticating using basic auth for retrieving user's API key.
  253. $request_auth_details .= 'Authorization: Basic '.base64_encode($call_options['authdetails']['username'].':'.$call_options['authdetails']['password'])."\n";
  254. } elseif (array_key_exists('access_token', $call_options['authdetails'])) {
  255. # Authenticating using OAuth.
  256. $access_token = $call_options['authdetails']['access_token'];
  257. $request_auth_details .= 'Authorization: Bearer '.$access_token."\n";
  258. } elseif (array_key_exists('api_key', $call_options['authdetails'])) {
  259. # Authenticating using an API key.
  260. $api_key = $call_options['authdetails']['api_key'];
  261. $request_auth_details .= 'Authorization: Basic '.base64_encode($api_key.':nopass')."\n";
  262. }
  263. }
  264. $request =
  265. $call_options['method'].' '.$path." HTTP/1.1\n".
  266. 'Host: '.$host."\n".
  267. $request_auth_details.
  268. 'User-Agent: '.$call_options['userAgent']."\n".
  269. "Connection: Close\n".
  270. 'Content-Type: '.$call_options['contentType']."\n";
  271. if($accept_gzip) {
  272. $request .=
  273. "Accept-Encoding: gzip\n";
  274. }
  275. if(isset($call_options['data'])) {
  276. $request .=
  277. 'Content-Length: '.strlen($call_options['data'])."\n\n".
  278. $call_options['data'];
  279. }
  280. return $request."\n\n";
  281. }
  282. }
  283. }