contrib modules security updates
This commit is contained in:
@@ -66,6 +66,8 @@ class ParserCSVIterator implements Iterator {
|
||||
*/
|
||||
class ParserCSV {
|
||||
private $delimiter;
|
||||
private $fromEncoding;
|
||||
private $toEncoding;
|
||||
private $skipFirstLine;
|
||||
private $columnNames;
|
||||
private $timeout;
|
||||
@@ -73,9 +75,12 @@ class ParserCSV {
|
||||
private $startByte;
|
||||
private $lineLimit;
|
||||
private $lastLinePos;
|
||||
private $useMbString;
|
||||
|
||||
public function __construct() {
|
||||
$this->delimiter = ',';
|
||||
$this->fromEncoding = 'UTF-8';
|
||||
$this->toEncoding = 'UTF-8';
|
||||
$this->skipFirstLine = FALSE;
|
||||
$this->columnNames = FALSE;
|
||||
$this->timeout = FALSE;
|
||||
@@ -83,6 +88,10 @@ class ParserCSV {
|
||||
$this->startByte = 0;
|
||||
$this->lineLimit = 0;
|
||||
$this->lastLinePos = 0;
|
||||
ini_set('auto_detect_line_endings', TRUE);
|
||||
if (extension_loaded('mbstring') && variable_get('feeds_use_mbstring', TRUE)) {
|
||||
$this->useMbString = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,6 +102,18 @@ class ParserCSV {
|
||||
$this->delimiter = $delimiter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the source file encoding.
|
||||
*
|
||||
* By default, the encoding is UTF-8.
|
||||
*
|
||||
* @param string $encoding
|
||||
* The encoding to set.
|
||||
*/
|
||||
public function setEncoding($encoding) {
|
||||
$this->fromEncoding = $encoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this to TRUE if the parser should skip the first line of the CSV text,
|
||||
* which might be desired if the first line contains the column names.
|
||||
@@ -196,7 +217,7 @@ class ParserCSV {
|
||||
for ($lineIterator->rewind($this->startByte); $lineIterator->valid(); $lineIterator->next()) {
|
||||
|
||||
// Make really sure we've got lines without trailing newlines.
|
||||
$line = trim($lineIterator->current(), "\r\n");
|
||||
$line = trim($this->fixEncoding($lineIterator->current()), "\r\n");
|
||||
|
||||
// Skip empty lines.
|
||||
if (empty($line)) {
|
||||
@@ -236,7 +257,7 @@ class ParserCSV {
|
||||
}
|
||||
// Ok, so, on with fetching the next line, as mentioned above.
|
||||
$currentField .= "\n";
|
||||
$line = trim($lineIterator->current(), "\r\n");
|
||||
$line = trim($this->fixEncoding($lineIterator->current()), "\r\n");
|
||||
$currentIndex = 0;
|
||||
continue;
|
||||
}
|
||||
@@ -324,4 +345,38 @@ class ParserCSV {
|
||||
}
|
||||
return $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts encoding of input data.
|
||||
*
|
||||
* @param string $data
|
||||
* A chunk of data.
|
||||
*
|
||||
* @return string
|
||||
* The encoded data.
|
||||
*
|
||||
* @throws ParserCSVEncodingException
|
||||
* Thrown when a given encoding does not match.
|
||||
*/
|
||||
public function fixEncoding($data) {
|
||||
if ($this->useMbString) {
|
||||
if (mb_check_encoding($data, $this->fromEncoding)) {
|
||||
if ($this->toEncoding != $this->fromEncoding) {
|
||||
// Convert encoding. The conversion is to UTF-8 by default to prevent
|
||||
// SQL errors.
|
||||
$data = mb_convert_encoding($data, $this->toEncoding, $this->fromEncoding);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new ParserCSVEncodingException(t('Source file is not in %encoding encoding.', array('%encoding' => $this->fromEncoding)));
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception thrown when an encoding error occurs during parsing.
|
||||
*/
|
||||
class ParserCSVEncodingException extends Exception {}
|
||||
|
@@ -161,7 +161,7 @@ class PuSHSubscriber {
|
||||
if (isset($_SERVER['HTTP_X_HUB_SIGNATURE']) && ($sub = $this->subscription())) {
|
||||
$result = array();
|
||||
parse_str($_SERVER['HTTP_X_HUB_SIGNATURE'], $result);
|
||||
if (isset($result['sha1']) && $result['sha1'] == hash_hmac('sha1', $raw, $sub->secret)) {
|
||||
if (isset($result['sha1']) && $result['sha1'] === hash_hmac('sha1', $raw, $sub->secret)) {
|
||||
return $raw;
|
||||
}
|
||||
else {
|
||||
@@ -183,47 +183,44 @@ class PuSHSubscriber {
|
||||
* method handles the challenge.
|
||||
*/
|
||||
public function verifyRequest() {
|
||||
if (isset($_GET['hub_challenge'])) {
|
||||
/**
|
||||
* If a subscription is present, compare the verify token. If the token
|
||||
* matches, set the status on the subscription record and confirm
|
||||
* positive.
|
||||
*
|
||||
* If we cannot find a matching subscription and the hub checks on
|
||||
* 'unsubscribe' confirm positive.
|
||||
*
|
||||
* In all other cases confirm negative.
|
||||
*/
|
||||
if ($sub = $this->subscription()) {
|
||||
if ($_GET['hub_verify_token'] == $sub->post_fields['hub.verify_token']) {
|
||||
if ($_GET['hub_mode'] == 'subscribe' && $sub->status == 'subscribe') {
|
||||
$sub->status = 'subscribed';
|
||||
$sub->post_fields = array();
|
||||
$sub->save();
|
||||
$this->log('Verified "subscribe" request.');
|
||||
$verify = TRUE;
|
||||
}
|
||||
elseif ($_GET['hub_mode'] == 'unsubscribe' && $sub->status == 'unsubscribe') {
|
||||
$sub->status = 'unsubscribed';
|
||||
$sub->post_fields = array();
|
||||
$sub->save();
|
||||
$this->log('Verified "unsubscribe" request.');
|
||||
$verify = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif ($_GET['hub_mode'] == 'unsubscribe') {
|
||||
$this->log('Verified "unsubscribe" request.');
|
||||
$verify = TRUE;
|
||||
}
|
||||
if ($verify) {
|
||||
header('HTTP/1.1 200 "Found"', NULL, 200);
|
||||
print $_GET['hub_challenge'];
|
||||
drupal_exit();
|
||||
}
|
||||
if (!isset($_GET['hub_challenge'])) {
|
||||
return $this->rejectRequest();
|
||||
}
|
||||
header('HTTP/1.1 404 "Not Found"', NULL, 404);
|
||||
$this->log('Could not verify subscription.', 'error');
|
||||
|
||||
// Don't accept modes of 'subscribed' or 'unsubscribed'.
|
||||
if ($_GET['hub_mode'] !== 'subscribe' && $_GET['hub_mode'] !== 'unsubscribe') {
|
||||
return $this->rejectRequest();
|
||||
}
|
||||
|
||||
// No available subscription.
|
||||
if (!$sub = $this->subscription()) {
|
||||
return $this->rejectRequest();
|
||||
}
|
||||
|
||||
// Not what we asked for.
|
||||
if ($_GET['hub_mode'] !== $sub->status) {
|
||||
return $this->rejectRequest();
|
||||
}
|
||||
|
||||
// Wrong URL.
|
||||
if ($_GET['hub_topic'] !== $sub->topic) {
|
||||
return $this->rejectRequest();
|
||||
}
|
||||
|
||||
if ($sub->status === 'subscribe') {
|
||||
$sub->status = 'subscribed';
|
||||
$this->log('Verified "subscribe" request.');
|
||||
}
|
||||
else {
|
||||
$sub->status = 'unsubscribed';
|
||||
$this->log('Verified "unsubscribe" request.');
|
||||
}
|
||||
|
||||
$sub->post_fields = array();
|
||||
$sub->save();
|
||||
|
||||
header('HTTP/1.1 200 "Found"', NULL, 200);
|
||||
print check_plain($_GET['hub_challenge']);
|
||||
drupal_exit();
|
||||
}
|
||||
|
||||
@@ -244,7 +241,7 @@ class PuSHSubscriber {
|
||||
* @todo Make concurrency safe.
|
||||
*/
|
||||
protected function request($hub, $topic, $mode, $callback_url) {
|
||||
$secret = hash('sha1', uniqid(rand(), TRUE));
|
||||
$secret = drupal_random_key(40);
|
||||
$post_fields = array(
|
||||
'hub.callback' => $callback_url,
|
||||
'hub.mode' => $mode,
|
||||
@@ -252,7 +249,6 @@ class PuSHSubscriber {
|
||||
'hub.verify' => 'sync',
|
||||
'hub.lease_seconds' => '', // Permanent subscription.
|
||||
'hub.secret' => $secret,
|
||||
'hub.verify_token' => md5(session_id() . rand()),
|
||||
);
|
||||
$sub = new $this->subscription_class($this->domain, $this->subscriber_id, $hub, $topic, $secret, $mode, $post_fields);
|
||||
$sub->save();
|
||||
@@ -310,6 +306,16 @@ class PuSHSubscriber {
|
||||
protected function log($msg, $level = 'status') {
|
||||
$this->env->log("{$this->domain}:{$this->subscriber_id}\t$msg", $level);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rejects a request subscription request.
|
||||
*/
|
||||
protected function rejectRequest() {
|
||||
header('HTTP/1.1 404 "Not Found"', NULL, 404);
|
||||
$this->log('Could not verify subscription.', 'error');
|
||||
drupal_exit();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -19,12 +19,7 @@
|
||||
* stdClass The structured datas extracted from the feed.
|
||||
*/
|
||||
function common_syndication_parser_parse($string) {
|
||||
if (!defined('LIBXML_VERSION') || (version_compare(phpversion(), '5.1.0', '<'))) {
|
||||
@ $xml = simplexml_load_string($string, NULL);
|
||||
}
|
||||
else {
|
||||
@ $xml = simplexml_load_string($string, NULL, LIBXML_NOERROR | LIBXML_NOWARNING | LIBXML_NOCDATA);
|
||||
}
|
||||
@ $xml = simplexml_load_string($string, NULL, LIBXML_NOERROR | LIBXML_NOWARNING | LIBXML_NOCDATA);
|
||||
|
||||
// Got a malformed XML.
|
||||
if ($xml === FALSE || is_null($xml)) {
|
||||
@@ -43,18 +38,6 @@ function common_syndication_parser_parse($string) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cached version of the <var>$url</var>
|
||||
*/
|
||||
function _parser_common_syndication_cache_get($url) {
|
||||
$cache_file = _parser_common_syndication_sanitize_cache() . '/' . md5($url);
|
||||
if (file_exists($cache_file)) {
|
||||
$file_content = file_get_contents($cache_file);
|
||||
return unserialize($file_content);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the feed format of a SimpleXML parsed object structure.
|
||||
*
|
||||
@@ -182,16 +165,14 @@ function _parser_common_syndication_atom10_parse($feed_XML) {
|
||||
}
|
||||
}
|
||||
|
||||
$author_found = FALSE;
|
||||
$original_author = '';
|
||||
if (!empty($news->source->author->name)) {
|
||||
$original_author = "{$news->source->author->name}";
|
||||
$author_found = TRUE;
|
||||
}
|
||||
elseif (!empty($news->author->name)) {
|
||||
$original_author = "{$news->author->name}";
|
||||
$author_found = TRUE;
|
||||
}
|
||||
if (!empty($feed_XML->author->name) && !$author_found) {
|
||||
elseif (!empty($feed_XML->author->name)) {
|
||||
$original_author = "{$feed_XML->author->name}";
|
||||
}
|
||||
|
||||
@@ -262,9 +243,8 @@ function _parser_common_syndication_RDF10_parse($feed_XML) {
|
||||
'rss' => 'http://purl.org/rss/1.0/',
|
||||
);
|
||||
|
||||
// Get all namespaces declared in the feed element, with special handling
|
||||
// for PHP versions prior to 5.1.2 as they don't handle namespaces.
|
||||
$namespaces = version_compare(phpversion(), '5.1.2', '<') ? array() : $feed_XML->getNamespaces(TRUE);
|
||||
// Get all namespaces declared in the feed element.
|
||||
$namespaces = $feed_XML->getNamespaces(TRUE);
|
||||
|
||||
// Process the <rss:channel> resource containing feed metadata:
|
||||
foreach ($feed_XML->children($canonical_namespaces['rss'])->channel as $rss_channel) {
|
||||
@@ -379,11 +359,9 @@ function _parser_common_syndication_RSS20_parse($feed_XML) {
|
||||
|
||||
$category = $news->xpath('category');
|
||||
// Get children for current namespace.
|
||||
if (version_compare(phpversion(), '5.1.2', '>')) {
|
||||
$content = (array)$news->children($ns["content"]);
|
||||
$dc = (array)$news->children($ns["dc"]);
|
||||
$georss = (array)$news->children($ns["georss"]);
|
||||
}
|
||||
$content = (array)$news->children($ns["content"]);
|
||||
$dc = (array)$news->children($ns["dc"]);
|
||||
$georss = (array)$news->children($ns["georss"]);
|
||||
$news = (array) $news;
|
||||
$news['category'] = $category;
|
||||
|
||||
@@ -505,12 +483,25 @@ function _parser_common_syndication_RSS20_parse($feed_XML) {
|
||||
*/
|
||||
function _parser_common_syndication_parse_date($date_str) {
|
||||
// PHP < 5.3 doesn't like the GMT- notation for parsing timezones.
|
||||
$date_str = str_replace("GMT-", "-", $date_str);
|
||||
$date_str = str_replace("GMT+", "+", $date_str);
|
||||
$date_str = str_replace('GMT-', '-', $date_str);
|
||||
$date_str = str_replace('GMT+', '+', $date_str);
|
||||
$parsed_date = strtotime($date_str);
|
||||
|
||||
if ($parsed_date === FALSE || $parsed_date == -1) {
|
||||
$parsed_date = _parser_common_syndication_parse_w3cdtf($date_str);
|
||||
}
|
||||
|
||||
if (($parsed_date === FALSE || $parsed_date == -1)) {
|
||||
// PHP does not support the UT timezone. Fake it. The system that generated
|
||||
// this, Google Groups, probably meant UTC.
|
||||
$date_str = strtolower(trim($date_str));
|
||||
$last_three = substr($date_str, strlen($date_str) - 3, 3);
|
||||
|
||||
if ($last_three == ' ut') {
|
||||
$parsed_date = strtotime($date_str . 'c');
|
||||
}
|
||||
}
|
||||
|
||||
return $parsed_date === FALSE ? time() : $parsed_date;
|
||||
}
|
||||
|
||||
|
@@ -24,8 +24,10 @@ define('HTTP_REQUEST_PCRE_TAG_ATTRIBUTES', '/[\x09\x0A\x0B\x0C\x0D\x20]+([^\x09\
|
||||
class HRCurlException extends Exception {}
|
||||
|
||||
/**
|
||||
* Discover RSS or atom feeds at the given URL. If document in given URL is an
|
||||
* HTML document, function attempts to discover RSS or Atom feeds.
|
||||
* Discovers RSS or atom feeds at the given URL.
|
||||
*
|
||||
* If document in given URL is an HTML document, function attempts to discover
|
||||
* RSS or Atom feeds.
|
||||
*
|
||||
* @param string $url
|
||||
* The url of the feed to retrieve.
|
||||
@@ -36,7 +38,7 @@ class HRCurlException extends Exception {}
|
||||
* The discovered feed, or FALSE if the URL is not reachable or there was an
|
||||
* error.
|
||||
*/
|
||||
function http_request_get_common_syndication($url, $settings = NULL) {
|
||||
function http_request_get_common_syndication($url, $settings = array()) {
|
||||
|
||||
$accept_invalid_cert = isset($settings['accept_invalid_cert']) ? $settings['accept_invalid_cert'] : FALSE;
|
||||
$download = http_request_get($url, NULL, NULL, $accept_invalid_cert);
|
||||
@@ -47,12 +49,12 @@ function http_request_get_common_syndication($url, $settings = NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Drop the data into a seperate variable so all manipulations of the html
|
||||
// Drop the data into a separate variable so all manipulations of the html
|
||||
// will not effect the actual object that exists in the static cache.
|
||||
// @see http_request_get.
|
||||
$downloaded_string = $download->data;
|
||||
// If this happens to be a feed then just return the url.
|
||||
if (http_request_is_feed($download->headers['content-type'], $downloaded_string)) {
|
||||
if (isset($download->headers['content-type']) && http_request_is_feed($download->headers['content-type'], $downloaded_string)) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
@@ -77,11 +79,13 @@ function http_request_get_common_syndication($url, $settings = NULL) {
|
||||
* If the URL uses authentication, supply the password.
|
||||
* @param bool $accept_invalid_cert
|
||||
* Whether to accept invalid certificates.
|
||||
|
||||
* @param integer $timeout
|
||||
* Timeout in seconds to wait for an HTTP get request to finish.
|
||||
*
|
||||
* @return stdClass
|
||||
* An object that describes the data downloaded from $url.
|
||||
*/
|
||||
function http_request_get($url, $username = NULL, $password = NULL, $accept_invalid_cert = FALSE) {
|
||||
function http_request_get($url, $username = NULL, $password = NULL, $accept_invalid_cert = FALSE, $timeout = NULL) {
|
||||
// Intra-pagedownload cache, avoid to download the same content twice within
|
||||
// one page download (it's possible, compatible and parse calls).
|
||||
static $download_cache = array();
|
||||
@@ -89,12 +93,15 @@ function http_request_get($url, $username = NULL, $password = NULL, $accept_inva
|
||||
return $download_cache[$url];
|
||||
}
|
||||
|
||||
// Determine request timeout.
|
||||
$request_timeout = !empty($timeout) ? $timeout : variable_get('http_request_timeout', 30);
|
||||
|
||||
if (!$username && valid_url($url, TRUE)) {
|
||||
// Handle password protected feeds.
|
||||
$url_parts = parse_url($url);
|
||||
if (!empty($url_parts['user'])) {
|
||||
$password = $url_parts['pass'];
|
||||
$username = $url_parts['user'];
|
||||
$password = urldecode($url_parts['pass']);
|
||||
$username = urldecode($url_parts['user']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +110,7 @@ function http_request_get($url, $username = NULL, $password = NULL, $accept_inva
|
||||
// Only download and parse data if really needs refresh.
|
||||
// Based on "Last-Modified" and "If-Modified-Since".
|
||||
$headers = array();
|
||||
if ($cache = cache_get('feeds_http_download_' . md5($url))) {
|
||||
if ($cache = http_request_get_cache($url)) {
|
||||
$last_result = $cache->data;
|
||||
$last_headers = array_change_key_case($last_result->headers);
|
||||
|
||||
@@ -134,6 +141,7 @@ function http_request_get($url, $username = NULL, $password = NULL, $accept_inva
|
||||
if ($curl) {
|
||||
$headers[] = 'User-Agent: Drupal (+http://drupal.org/)';
|
||||
$result = new stdClass();
|
||||
$result->headers = array();
|
||||
|
||||
// Parse the URL and make sure we can handle the schema.
|
||||
// cURL can only support either http:// or https://.
|
||||
@@ -149,6 +157,7 @@ function http_request_get($url, $username = NULL, $password = NULL, $accept_inva
|
||||
case 'https':
|
||||
// Valid scheme.
|
||||
break;
|
||||
|
||||
default:
|
||||
$result->error = 'invalid schema ' . $uri['scheme'];
|
||||
$result->code = -1003;
|
||||
@@ -168,9 +177,26 @@ function http_request_get($url, $username = NULL, $password = NULL, $accept_inva
|
||||
curl_setopt($download, CURLOPT_HEADER, TRUE);
|
||||
curl_setopt($download, CURLOPT_RETURNTRANSFER, TRUE);
|
||||
curl_setopt($download, CURLOPT_ENCODING, '');
|
||||
curl_setopt($download, CURLOPT_TIMEOUT, variable_get('http_request_timeout', 30));
|
||||
curl_setopt($download, CURLOPT_TIMEOUT, $request_timeout);
|
||||
|
||||
$proxy_server = variable_get('proxy_server');
|
||||
|
||||
if ($proxy_server && _drupal_http_use_proxy($uri['host'])) {
|
||||
curl_setopt($download, CURLOPT_PROXY, $proxy_server);
|
||||
curl_setopt($download, CURLOPT_PROXYPORT, variable_get('proxy_port', 8080));
|
||||
|
||||
// Proxy user/password.
|
||||
if ($proxy_username = variable_get('proxy_username')) {
|
||||
$username_password = $proxy_username . ':' . variable_get('proxy_password', '');
|
||||
|
||||
curl_setopt($download, CURLOPT_PROXYUSERPWD, $username_password);
|
||||
curl_setopt($download, CURLOPT_PROXYAUTH, variable_get('proxy_auth_method', CURLAUTH_BASIC));
|
||||
}
|
||||
}
|
||||
|
||||
if ($accept_invalid_cert) {
|
||||
curl_setopt($download, CURLOPT_SSL_VERIFYPEER, 0);
|
||||
curl_setopt($download, CURLOPT_SSL_VERIFYHOST, 0);
|
||||
}
|
||||
$header = '';
|
||||
$data = curl_exec($download);
|
||||
@@ -179,18 +205,35 @@ function http_request_get($url, $username = NULL, $password = NULL, $accept_inva
|
||||
t('cURL error (@code) @error for @url', array(
|
||||
'@code' => curl_errno($download),
|
||||
'@error' => curl_error($download),
|
||||
'@url' => $url
|
||||
'@url' => $url,
|
||||
)), curl_errno($download)
|
||||
);
|
||||
}
|
||||
|
||||
// When using a proxy, remove extra data from the header which is not
|
||||
// considered by CURLINFO_HEADER_SIZE (possibly cURL bug).
|
||||
// This data is only added when to HTTP header when working with a proxy.
|
||||
// Example string added: <HTTP/1.0 200 Connection established\r\n\r\n>
|
||||
// This was fixed in libcurl version 7.30.0 (0x71e00) (April 12, 2013),
|
||||
// so this workaround only removes the proxy-added headers if we are using
|
||||
// an older version of libcurl.
|
||||
$curl_ver = curl_version();
|
||||
|
||||
if ($proxy_server && $curl_ver['version_number'] < 0x71e00 && _drupal_http_use_proxy($uri['host'])) {
|
||||
$http_header_break = "\r\n\r\n";
|
||||
$response = explode($http_header_break, $data);
|
||||
if (count($response) > 2) {
|
||||
$data = substr($data, strlen($response[0] . $http_header_break), strlen($data));
|
||||
}
|
||||
}
|
||||
|
||||
$header_size = curl_getinfo($download, CURLINFO_HEADER_SIZE);
|
||||
$header = substr($data, 0, $header_size - 1);
|
||||
$result->data = substr($data, $header_size);
|
||||
$headers = preg_split("/(\r\n){2}/", $header);
|
||||
$header_lines = preg_split("/\r\n|\n|\r/", end($headers));
|
||||
$result->headers = array();
|
||||
array_shift($header_lines); // skip HTTP response status
|
||||
// Skip HTTP response status.
|
||||
array_shift($header_lines);
|
||||
|
||||
while ($line = trim(array_shift($header_lines))) {
|
||||
list($header, $value) = explode(':', $line, 2);
|
||||
@@ -212,7 +255,8 @@ function http_request_get($url, $username = NULL, $password = NULL, $accept_inva
|
||||
}
|
||||
}
|
||||
else {
|
||||
$result = drupal_http_request($url, array('headers' => $headers, 'timeout' => variable_get('http_request_timeout', 30)));
|
||||
$result = drupal_http_request($url, array('headers' => $headers, 'timeout' => $request_timeout));
|
||||
$result->headers = isset($result->headers) ? $result->headers : array();
|
||||
}
|
||||
|
||||
$result->code = isset($result->code) ? $result->code : 200;
|
||||
@@ -227,13 +271,13 @@ function http_request_get($url, $username = NULL, $password = NULL, $accept_inva
|
||||
else {
|
||||
// It's a tragedy, this file must exist and contain good data.
|
||||
// In this case, clear cache and repeat.
|
||||
cache_clear_all('feeds_http_download_' . md5($url), 'cache');
|
||||
return http_request_get($url, $username, $password);
|
||||
http_request_clear_cache($url);
|
||||
return http_request_get($url, $username, $password, $accept_invalid_cert, $request_timeout);
|
||||
}
|
||||
}
|
||||
|
||||
// Set caches.
|
||||
cache_set('feeds_http_download_' . md5($url), $result);
|
||||
http_request_set_cache($url, $result);
|
||||
$download_cache[$url] = $result;
|
||||
|
||||
return $result;
|
||||
@@ -243,7 +287,7 @@ function http_request_get($url, $username = NULL, $password = NULL, $accept_inva
|
||||
* Decides if it's possible to use cURL or not.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if curl is available, FALSE otherwise.
|
||||
* TRUE if cURL may be used, FALSE otherwise.
|
||||
*/
|
||||
function http_request_use_curl() {
|
||||
// Allow site administrators to choose to not use cURL.
|
||||
@@ -251,29 +295,67 @@ function http_request_use_curl() {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Check availability of cURL on the system.
|
||||
$basedir = ini_get("open_basedir");
|
||||
return function_exists('curl_init') && !ini_get('safe_mode') && empty($basedir);
|
||||
// Check that the PHP cURL extension has been enabled.
|
||||
if (!extension_loaded('curl')) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// cURL below PHP 5.6.0 must not have open_basedir or safe_mode enabled.
|
||||
if (version_compare(PHP_VERSION, '5.6.0', '<')) {
|
||||
return !ini_get('safe_mode') && !ini_get('open_basedir');
|
||||
}
|
||||
|
||||
// cURL in PHP 5.6.0 and above re-enables CURLOPT_FOLLOWLOCATION with
|
||||
// open_basedir so there is no need to check for this.
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear cache for a specific URL.
|
||||
*
|
||||
* @param string $url
|
||||
* The URL to clear.
|
||||
*/
|
||||
function http_request_clear_cache($url) {
|
||||
cache_clear_all('feeds_http_download_' . md5($url), 'cache');
|
||||
cache_clear_all(hash('sha256', $url), 'cache_feeds_http');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cache for a specific URL.
|
||||
*
|
||||
* @param string $url
|
||||
* The URL to find the cached item.
|
||||
*
|
||||
* @return object|false
|
||||
* The cache or FALSE on failure.
|
||||
*/
|
||||
function http_request_get_cache($url) {
|
||||
return cache_get(hash('sha256', $url), 'cache_feeds_http');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cache for a specific URL.
|
||||
*
|
||||
* @param string $url
|
||||
* The URL to cache.
|
||||
* @param stdClass $result
|
||||
* The result of the HTTP request.
|
||||
*/
|
||||
function http_request_set_cache($url, stdClass $result) {
|
||||
cache_set(hash('sha256', $url), $result, 'cache_feeds_http');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the provided $content_type is a feed.
|
||||
*
|
||||
* @param string $content_type
|
||||
* The Content-Type header.
|
||||
* The Content-Type header.
|
||||
*
|
||||
* @param string $data
|
||||
* The actual data from the http request.
|
||||
* The actual data from the http request.
|
||||
*
|
||||
* @return bool
|
||||
* Returns TRUE if this is a parsable feed.
|
||||
* Returns TRUE if this is a parsable feed.
|
||||
*/
|
||||
function http_request_is_feed($content_type, $data) {
|
||||
$pos = strpos($content_type, ';');
|
||||
@@ -294,10 +376,10 @@ function http_request_is_feed($content_type, $data) {
|
||||
* Finds potential feed tags in the HTML document.
|
||||
*
|
||||
* @param string $html
|
||||
* The html string to search.
|
||||
* The html string to search.
|
||||
*
|
||||
* @return array
|
||||
* An array of href to feeds.
|
||||
* An array of href to feeds.
|
||||
*/
|
||||
function http_request_find_feeds($html) {
|
||||
$matches = array();
|
||||
@@ -313,7 +395,11 @@ function http_request_find_feeds($html) {
|
||||
preg_match_all(HTTP_REQUEST_PCRE_TAG_ATTRIBUTES, $link_tag, $attributes, PREG_SET_ORDER);
|
||||
foreach ($attributes as $attribute) {
|
||||
// Find the key value pairs, attribute[1] is key and attribute[2] is the
|
||||
// value.
|
||||
// value. However, if the link tag used single quotes, the value might
|
||||
// be in attribute[3] instead.
|
||||
if (empty($attribute[2])) {
|
||||
$attribute[2] = $attribute[3];
|
||||
}
|
||||
if (!empty($attribute[1]) && !empty($attribute[2])) {
|
||||
$candidate[drupal_strtolower($attribute[1])] = drupal_strtolower(decode_entities($attribute[2]));
|
||||
}
|
||||
@@ -355,27 +441,48 @@ function http_request_create_absolute_url($url, $base_url) {
|
||||
// Produces variables $scheme, $host, $user, $pass, $path, $query and
|
||||
// $fragment.
|
||||
$parsed_url = parse_url($base_url);
|
||||
if ($parsed_url === FALSE) {
|
||||
// Invalid $base_url.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$path = dirname($parsed_url['path']);
|
||||
$path = isset($parsed_url['path']) ? $parsed_url['path'] : '';
|
||||
if (strlen($path) > 0 && substr($path, -1) != '/') {
|
||||
// Path ends not with '/', so remove all before previous '/'.
|
||||
$path = dirname($path);
|
||||
}
|
||||
|
||||
// Adding to the existing path.
|
||||
$cparts = array();
|
||||
if ($url{0} == '/') {
|
||||
$cparts = array_filter(explode("/", $url));
|
||||
}
|
||||
else {
|
||||
// Backtracking from the existing path.
|
||||
$cparts = array_merge(array_filter(explode("/", $path)), array_filter(explode("/", $url)));
|
||||
foreach ($cparts as $i => $part) {
|
||||
if ($part == '.') {
|
||||
$cparts[$i] = NULL;
|
||||
}
|
||||
if ($part == '..') {
|
||||
$cparts[$i - 1] = NULL;
|
||||
$cparts[$i] = NULL;
|
||||
}
|
||||
}
|
||||
$cparts = array_filter($cparts);
|
||||
$path_cparts = array_filter(explode("/", $path));
|
||||
$url_cparts = array_filter(explode("/", $url));
|
||||
$cparts = array_merge($path_cparts, $url_cparts);
|
||||
}
|
||||
|
||||
$remove_parts = 0;
|
||||
// Start from behind.
|
||||
$reverse_cparts = array_reverse($cparts);
|
||||
foreach ($reverse_cparts as $i => &$part) {
|
||||
if ($part == '.') {
|
||||
$part = NULL;
|
||||
}
|
||||
elseif ($part == '..') {
|
||||
$part = NULL;
|
||||
$remove_parts++;
|
||||
}
|
||||
elseif ($remove_parts > 0) {
|
||||
// If the current part isn't "..", and we had ".." before, then delete
|
||||
// the part.
|
||||
$part = NULL;
|
||||
$remove_parts--;
|
||||
}
|
||||
}
|
||||
$cparts = array_filter(array_reverse($reverse_cparts));
|
||||
$path = implode("/", $cparts);
|
||||
|
||||
// Build the prefix to the path.
|
||||
|
Reference in New Issue
Block a user