/** * Send a HTTP request to a URI using cURL extension. * * @access public * @since 2.7.0 * * @param string $url * @param str|array $args Optional. Override the defaults. * @return array 'headers', 'body', 'cookies' and 'response' keys. */ function request($url, $args = array()) { $defaults = array('method' => 'GET', 'timeout' => 5, 'redirection' => 5, 'httpversion' => '1.0', 'blocking' => true, 'headers' => array(), 'body' => null, 'cookies' => array()); $r = nxt_parse_args($args, $defaults); if (isset($r['headers']['User-Agent'])) { $r['user-agent'] = $r['headers']['User-Agent']; unset($r['headers']['User-Agent']); } else { if (isset($r['headers']['user-agent'])) { $r['user-agent'] = $r['headers']['user-agent']; unset($r['headers']['user-agent']); } } // Construct Cookie: header if any cookies are set. nxt_Http::buildCookieHeader($r); // cURL extension will sometimes fail when the timeout is less than 1 as it may round down // to 0, which gives it unlimited timeout. if ($r['timeout'] > 0 && $r['timeout'] < 1) { $r['timeout'] = 1; } $handle = curl_init(); // cURL offers really easy proxy support. $proxy = new nxt_HTTP_Proxy(); if ($proxy->is_enabled() && $proxy->send_through_proxy($url)) { $isPHP5 = version_compare(PHP_VERSION, '5.0.0', '>='); if ($isPHP5) { curl_setopt($handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP); curl_setopt($handle, CURLOPT_PROXY, $proxy->host()); curl_setopt($handle, CURLOPT_PROXYPORT, $proxy->port()); } else { curl_setopt($handle, CURLOPT_PROXY, $proxy->host() . ':' . $proxy->port()); } if ($proxy->use_authentication()) { if ($isPHP5) { curl_setopt($handle, CURLOPT_PROXYAUTH, CURLAUTH_BASIC); } curl_setopt($handle, CURLOPT_PROXYUSERPWD, $proxy->authentication()); } } $is_local = isset($args['local']) && $args['local']; $ssl_verify = isset($args['sslverify']) && $args['sslverify']; if ($is_local) { $ssl_verify = apply_filters('https_local_ssl_verify', $ssl_verify); } elseif (!$is_local) { $ssl_verify = apply_filters('https_ssl_verify', $ssl_verify); } curl_setopt($handle, CURLOPT_URL, $url); curl_setopt($handle, CURLOPT_RETURNTRANSFER, true); curl_setopt($handle, CURLOPT_SSL_VERIFYHOST, $ssl_verify); curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, $ssl_verify); curl_setopt($handle, CURLOPT_USERAGENT, $r['user-agent']); curl_setopt($handle, CURLOPT_CONNECTTIMEOUT, $r['timeout']); curl_setopt($handle, CURLOPT_TIMEOUT, $r['timeout']); curl_setopt($handle, CURLOPT_MAXREDIRS, $r['redirection']); switch ($r['method']) { case 'HEAD': curl_setopt($handle, CURLOPT_NOBODY, true); break; case 'POST': curl_setopt($handle, CURLOPT_POST, true); curl_setopt($handle, CURLOPT_POSTFIELDS, $r['body']); break; } if (true === $r['blocking']) { curl_setopt($handle, CURLOPT_HEADER, true); } else { curl_setopt($handle, CURLOPT_HEADER, false); } // The option doesn't work with safe mode or when open_basedir is set. if (!ini_get('safe_mode') && !ini_get('open_basedir')) { curl_setopt($handle, CURLOPT_FOLLOWLOCATION, true); } if (!empty($r['headers'])) { // cURL expects full header strings in each element $headers = array(); foreach ($r['headers'] as $name => $value) { $headers[] = "{$name}: {$value}"; } curl_setopt($handle, CURLOPT_HTTPHEADER, $headers); } if ($r['httpversion'] == '1.0') { curl_setopt($handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); } else { curl_setopt($handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); } // Cookies are not handled by the HTTP API currently. Allow for plugin authors to handle it // themselves... Although, it is somewhat pointless without some reference. do_action_ref_array('http_api_curl', array(&$handle)); // We don't need to return the body, so don't. Just execute request and return. if (!$r['blocking']) { curl_exec($handle); curl_close($handle); return array('headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array()); } $theResponse = curl_exec($handle); if (!empty($theResponse)) { $parts = explode("\r\n\r\n", $theResponse); $headerLength = curl_getinfo($handle, CURLINFO_HEADER_SIZE); $theHeaders = trim(substr($theResponse, 0, $headerLength)); $theBody = substr($theResponse, $headerLength); if (false !== strrpos($theHeaders, "\r\n\r\n")) { $headerParts = explode("\r\n\r\n", $theHeaders); $theHeaders = $headerParts[count($headerParts) - 1]; } $theHeaders = nxt_Http::processHeaders($theHeaders); } else { if ($curl_error = curl_error($handle)) { return new nxt_Error('http_request_failed', $curl_error); } if (in_array(curl_getinfo($handle, CURLINFO_HTTP_CODE), array(301, 302))) { return new nxt_Error('http_request_failed', __('Too many redirects.')); } $theHeaders = array('headers' => array(), 'cookies' => array()); $theBody = ''; } $response = array(); $response['code'] = curl_getinfo($handle, CURLINFO_HTTP_CODE); $response['message'] = get_status_header_desc($response['code']); curl_close($handle); if (true === $r['decompress'] && true === nxt_Http_Encoding::should_decode($theHeaders['headers'])) { $theBody = nxt_Http_Encoding::decompress($theBody); } return array('headers' => $theHeaders['headers'], 'body' => $theBody, 'response' => $response, 'cookies' => $theHeaders['cookies']); }
/** * Send a HTTP request to a URI using cURL extension. * * @access public * @since 2.7.0 * * @param string $url * @param str|array $args Optional. Override the defaults. * @return array 'headers', 'body', 'response', 'cookies' and 'filename' keys. */ function request($url, $args = array()) { $defaults = array('method' => 'GET', 'timeout' => 5, 'redirection' => 5, 'httpversion' => '1.0', 'blocking' => true, 'headers' => array(), 'body' => null, 'cookies' => array()); $r = nxt_parse_args($args, $defaults); if (isset($r['headers']['User-Agent'])) { $r['user-agent'] = $r['headers']['User-Agent']; unset($r['headers']['User-Agent']); } else { if (isset($r['headers']['user-agent'])) { $r['user-agent'] = $r['headers']['user-agent']; unset($r['headers']['user-agent']); } } // Construct Cookie: header if any cookies are set. nxt_Http::buildCookieHeader($r); $handle = curl_init(); // cURL offers really easy proxy support. $proxy = new nxt_HTTP_Proxy(); if ($proxy->is_enabled() && $proxy->send_through_proxy($url)) { curl_setopt($handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP); curl_setopt($handle, CURLOPT_PROXY, $proxy->host()); curl_setopt($handle, CURLOPT_PROXYPORT, $proxy->port()); if ($proxy->use_authentication()) { curl_setopt($handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY); curl_setopt($handle, CURLOPT_PROXYUSERPWD, $proxy->authentication()); } } $is_local = isset($args['local']) && $args['local']; $ssl_verify = isset($args['sslverify']) && $args['sslverify']; if ($is_local) { $ssl_verify = apply_filters('https_local_ssl_verify', $ssl_verify); } elseif (!$is_local) { $ssl_verify = apply_filters('https_ssl_verify', $ssl_verify); } // CURLOPT_TIMEOUT and CURLOPT_CONNECTTIMEOUT expect integers. Have to use ceil since // a value of 0 will allow an unlimited timeout. $timeout = (int) ceil($r['timeout']); curl_setopt($handle, CURLOPT_CONNECTTIMEOUT, $timeout); curl_setopt($handle, CURLOPT_TIMEOUT, $timeout); curl_setopt($handle, CURLOPT_URL, $url); curl_setopt($handle, CURLOPT_RETURNTRANSFER, true); curl_setopt($handle, CURLOPT_SSL_VERIFYHOST, $ssl_verify === true ? 2 : false); curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, $ssl_verify); curl_setopt($handle, CURLOPT_USERAGENT, $r['user-agent']); curl_setopt($handle, CURLOPT_MAXREDIRS, $r['redirection']); switch ($r['method']) { case 'HEAD': curl_setopt($handle, CURLOPT_NOBODY, true); break; case 'POST': curl_setopt($handle, CURLOPT_POST, true); curl_setopt($handle, CURLOPT_POSTFIELDS, $r['body']); break; case 'PUT': curl_setopt($handle, CURLOPT_CUSTOMREQUEST, 'PUT'); curl_setopt($handle, CURLOPT_POSTFIELDS, $r['body']); break; } if (true === $r['blocking']) { curl_setopt($handle, CURLOPT_HEADERFUNCTION, array(&$this, 'stream_headers')); } curl_setopt($handle, CURLOPT_HEADER, false); // If streaming to a file open a file handle, and setup our curl streaming handler if ($r['stream']) { if (!nxt_DEBUG) { $stream_handle = @fopen($r['filename'], 'w+'); } else { $stream_handle = fopen($r['filename'], 'w+'); } if (!$stream_handle) { return new nxt_Error('http_request_failed', sprintf(__('Could not open handle for fopen() to %s'), $r['filename'])); } curl_setopt($handle, CURLOPT_FILE, $stream_handle); } // The option doesn't work with safe mode or when open_basedir is set. if (!ini_get('safe_mode') && !ini_get('open_basedir') && 0 !== $r['_redirection']) { curl_setopt($handle, CURLOPT_FOLLOWLOCATION, true); } if (!empty($r['headers'])) { // cURL expects full header strings in each element $headers = array(); foreach ($r['headers'] as $name => $value) { $headers[] = "{$name}: {$value}"; } curl_setopt($handle, CURLOPT_HTTPHEADER, $headers); } if ($r['httpversion'] == '1.0') { curl_setopt($handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); } else { curl_setopt($handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); } // Cookies are not handled by the HTTP API currently. Allow for plugin authors to handle it // themselves... Although, it is somewhat pointless without some reference. do_action_ref_array('http_api_curl', array(&$handle)); // We don't need to return the body, so don't. Just execute request and return. if (!$r['blocking']) { curl_exec($handle); curl_close($handle); return array('headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array()); } $theResponse = curl_exec($handle); $theBody = ''; $theHeaders = nxt_Http::processHeaders($this->headers); if (strlen($theResponse) > 0 && !is_bool($theResponse)) { // is_bool: when using $args['stream'], curl_exec will return (bool)true $theBody = $theResponse; } // If no response, and It's not a HEAD request with valid headers returned if (0 == strlen($theResponse) && ('HEAD' != $args['method'] || empty($this->headers))) { if ($curl_error = curl_error($handle)) { return new nxt_Error('http_request_failed', $curl_error); } if (in_array(curl_getinfo($handle, CURLINFO_HTTP_CODE), array(301, 302))) { return new nxt_Error('http_request_failed', __('Too many redirects.')); } } $this->headers = ''; $response = array(); $response['code'] = curl_getinfo($handle, CURLINFO_HTTP_CODE); $response['message'] = get_status_header_desc($response['code']); curl_close($handle); if ($r['stream']) { fclose($stream_handle); } // See #11305 - When running under safe mode, redirection is disabled above. Handle it manually. if (!empty($theHeaders['headers']['location']) && (ini_get('safe_mode') || ini_get('open_basedir')) && 0 !== $r['_redirection']) { if ($r['redirection']-- > 0) { return $this->request($theHeaders['headers']['location'], $r); } else { return new nxt_Error('http_request_failed', __('Too many redirects.')); } } if (true === $r['decompress'] && true === nxt_Http_Encoding::should_decode($theHeaders['headers'])) { $theBody = nxt_Http_Encoding::decompress($theBody); } return array('headers' => $theHeaders['headers'], 'body' => $theBody, 'response' => $response, 'cookies' => $theHeaders['cookies'], 'filename' => $r['filename']); }