contrib modules security updates
This commit is contained in:
@@ -15,6 +15,10 @@ class FeedsNotExistingException extends Exception {
|
||||
* Base class for configurable classes. Captures configuration handling, form
|
||||
* handling and distinguishes between in-memory configuration and persistent
|
||||
* configuration.
|
||||
*
|
||||
* Due to the magic method __get(), protected properties from this class and
|
||||
* from classes that extend this class will be publicly readable (but not
|
||||
* writeable).
|
||||
*/
|
||||
abstract class FeedsConfigurable {
|
||||
|
||||
@@ -44,17 +48,20 @@ abstract class FeedsConfigurable {
|
||||
protected $disabled;
|
||||
|
||||
/**
|
||||
* Instantiate a FeedsConfigurable object.
|
||||
* Instantiates a FeedsConfigurable object.
|
||||
*
|
||||
* Don't use directly, use feeds_importer() or feeds_plugin()
|
||||
* instead.
|
||||
* Don't use directly, use feeds_importer() or feeds_plugin() instead.
|
||||
*
|
||||
* @see feeds_importer()
|
||||
* @see feeds_plugin()
|
||||
*/
|
||||
public static function instance($class, $id) {
|
||||
// This is useful at least as long as we're developing.
|
||||
if (empty($id)) {
|
||||
throw new Exception(t('Empty configuration identifier.'));
|
||||
if (!strlen($id)) {
|
||||
throw new InvalidArgumentException(t('Empty configuration identifier.'));
|
||||
}
|
||||
static $instances = array();
|
||||
|
||||
$instances = &drupal_static(__METHOD__, array());
|
||||
|
||||
if (!isset($instances[$class][$id])) {
|
||||
$instances[$class][$id] = new $class($id);
|
||||
}
|
||||
@@ -136,8 +143,13 @@ abstract class FeedsConfigurable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Override magic method __get(). Make sure that $this->config goes through
|
||||
* getConfig().
|
||||
* Overrides magic method __get().
|
||||
*
|
||||
* - Makes sure that external reads of FeedsConfigurable::config go through
|
||||
* ::getConfig();
|
||||
* - Makes private and protected properties from this class and protected
|
||||
* properties from child classes publicly readable.
|
||||
* - Prevents warnings when accessing non-existent properties.
|
||||
*/
|
||||
public function __get($name) {
|
||||
if ($name == 'config') {
|
||||
@@ -169,6 +181,17 @@ abstract class FeedsConfigurable {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the configurable has a config form.
|
||||
*
|
||||
* @return bool
|
||||
* True if the configurable has a config form, and false if not.
|
||||
*/
|
||||
public function hasConfigForm() {
|
||||
$form_state = array();
|
||||
return (bool) $this->configForm($form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return configuration form for this object. The keys of the configuration
|
||||
* form must match the keys of the array returned by configDefaults().
|
||||
@@ -202,6 +225,16 @@ abstract class FeedsConfigurable {
|
||||
drupal_set_message(t('Your changes have been saved.'));
|
||||
feeds_cache_clear(FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of required modules.
|
||||
*
|
||||
* @return array
|
||||
* The modules that this configurable requires.
|
||||
*/
|
||||
public function dependencies() {
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -265,6 +298,8 @@ function feeds_form_submit($form, &$form_state) {
|
||||
|
||||
/**
|
||||
* Helper for Feeds validate and submit callbacks.
|
||||
*
|
||||
* @todo This is all terrible. Remove.
|
||||
*/
|
||||
function _feeds_form_helper($form, &$form_state, $action) {
|
||||
$method = $form['#feeds_form_method'] . $action;
|
||||
@@ -277,12 +312,13 @@ function _feeds_form_helper($form, &$form_state, $action) {
|
||||
// This will re-initialize all of the plugins anyway, causing some tricky
|
||||
// saving issues in certain cases.
|
||||
// See http://drupal.org/node/1672880.
|
||||
|
||||
if ($class == variable_get('feeds_importer_class', 'FeedsImporter')) {
|
||||
$form['#configurable'] = feeds_importer($id);
|
||||
}
|
||||
else {
|
||||
$form['#configurable'] = feeds_plugin($class, $id);
|
||||
$importer = feeds_importer($id);
|
||||
$plugin_key = $importer->config[$form['#configurable']->pluginType()]['plugin_key'];
|
||||
$form['#configurable'] = feeds_plugin($plugin_key, $id);
|
||||
}
|
||||
|
||||
if (method_exists($form['#configurable'], $method)) {
|
||||
|
@@ -54,49 +54,6 @@ class FeedsImporter extends FeedsConfigurable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove items older than $time.
|
||||
*
|
||||
* @param $time
|
||||
* All items older than REQUEST_TIME - $time will be deleted. If not
|
||||
* given, internal processor settings will be used.
|
||||
*
|
||||
* @return
|
||||
* FEEDS_BATCH_COMPLETE if the expiry process finished. A decimal between
|
||||
* 0.0 and 0.9 periodic if expiry is still in progress.
|
||||
*
|
||||
* @throws
|
||||
* Throws Exception if an error occurs when expiring items.
|
||||
*/
|
||||
public function expire($time = NULL) {
|
||||
return $this->processor->expire($time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule all periodic tasks for this importer.
|
||||
*/
|
||||
public function schedule() {
|
||||
$this->scheduleExpire();
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule expiry of items.
|
||||
*/
|
||||
public function scheduleExpire() {
|
||||
$job = array(
|
||||
'type' => $this->id,
|
||||
'period' => 0,
|
||||
'periodic' => TRUE,
|
||||
);
|
||||
if (FEEDS_EXPIRE_NEVER != $this->processor->expiryTime()) {
|
||||
$job['period'] = 3600;
|
||||
JobScheduler::get('feeds_importer_expire')->set($job);
|
||||
}
|
||||
else {
|
||||
JobScheduler::get('feeds_importer_expire')->remove($job);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Report how many items *should* be created on one page load by this
|
||||
* importer.
|
||||
@@ -155,23 +112,17 @@ class FeedsImporter extends FeedsConfigurable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete configuration. Removes configuration information
|
||||
* from database, does not delete configuration itself.
|
||||
* Deletes configuration.
|
||||
*
|
||||
* Removes configuration information from database, does not delete
|
||||
* configuration itself.
|
||||
*/
|
||||
public function delete() {
|
||||
db_delete('feeds_importer')
|
||||
->condition('id', $this->id)
|
||||
->execute();
|
||||
$job = array(
|
||||
'type' => $this->id,
|
||||
'id' => 0,
|
||||
);
|
||||
if ($this->export_type & EXPORT_IN_CODE) {
|
||||
feeds_reschedule($this->id);
|
||||
}
|
||||
else {
|
||||
JobScheduler::get('feeds_importer_expire')->remove($job);
|
||||
}
|
||||
|
||||
feeds_reschedule($this->id);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -320,6 +271,17 @@ class FeedsImporter extends FeedsConfigurable {
|
||||
}
|
||||
parent::configFormSubmit($values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements FeedsConfigurable::dependencies().
|
||||
*/
|
||||
public function dependencies() {
|
||||
$dependencies = parent::dependencies();
|
||||
foreach ($this->plugin_types as $plugin_type) {
|
||||
$dependencies = array_merge($dependencies, $this->$plugin_type->dependencies());
|
||||
}
|
||||
return $dependencies;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -6,7 +6,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Distinguish exceptions occuring when handling locks.
|
||||
* Distinguish exceptions occurring when handling locks.
|
||||
*/
|
||||
class FeedsLockException extends Exception {}
|
||||
|
||||
@@ -18,6 +18,7 @@ define('FEEDS_FETCH', 'fetch');
|
||||
define('FEEDS_PARSE', 'parse');
|
||||
define('FEEDS_PROCESS', 'process');
|
||||
define('FEEDS_PROCESS_CLEAR', 'process_clear');
|
||||
define('FEEDS_PROCESS_EXPIRE', 'process_expire');
|
||||
|
||||
/**
|
||||
* Declares an interface for a class that defines default values and form
|
||||
@@ -86,9 +87,16 @@ class FeedsState {
|
||||
public $created;
|
||||
public $updated;
|
||||
public $deleted;
|
||||
public $unpublished;
|
||||
public $blocked;
|
||||
public $skipped;
|
||||
public $failed;
|
||||
|
||||
/**
|
||||
* IDs of entities to be removed.
|
||||
*/
|
||||
public $removeList;
|
||||
|
||||
/**
|
||||
* Constructor, initialize variables.
|
||||
*/
|
||||
@@ -98,6 +106,8 @@ class FeedsState {
|
||||
$this->created =
|
||||
$this->updated =
|
||||
$this->deleted =
|
||||
$this->unpublished =
|
||||
$this->blocked =
|
||||
$this->skipped =
|
||||
$this->failed = 0;
|
||||
}
|
||||
@@ -124,7 +134,7 @@ class FeedsState {
|
||||
$this->progress = FEEDS_BATCH_COMPLETE;
|
||||
}
|
||||
elseif ($total) {
|
||||
$this->progress = $progress / $total;
|
||||
$this->progress = (float) $progress / $total;
|
||||
if ($this->progress == FEEDS_BATCH_COMPLETE && $total != $progress) {
|
||||
$this->progress = 0.99;
|
||||
}
|
||||
@@ -178,13 +188,18 @@ class FeedsSource extends FeedsConfigurable {
|
||||
// Timestamp when this source was imported the last time.
|
||||
protected $imported;
|
||||
|
||||
// Holds an exception object in case an exception occurs during importing.
|
||||
protected $exception;
|
||||
|
||||
/**
|
||||
* Instantiate a unique object per class/id/feed_nid. Don't use
|
||||
* directly, use feeds_source() instead.
|
||||
*/
|
||||
public static function instance($importer_id, $feed_nid) {
|
||||
$class = variable_get('feeds_source_class', 'FeedsSource');
|
||||
static $instances = array();
|
||||
|
||||
$instances = &drupal_static(__METHOD__, array());
|
||||
|
||||
if (!isset($instances[$class][$importer_id][$feed_nid])) {
|
||||
$instances[$class][$importer_id][$feed_nid] = new $class($importer_id, $feed_nid);
|
||||
}
|
||||
@@ -273,6 +288,7 @@ class FeedsSource extends FeedsConfigurable {
|
||||
*/
|
||||
public function schedule() {
|
||||
$this->scheduleImport();
|
||||
$this->scheduleExpire();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -285,19 +301,44 @@ class FeedsSource extends FeedsConfigurable {
|
||||
if (is_numeric($fetcher_period)) {
|
||||
$period = $fetcher_period;
|
||||
}
|
||||
$period = $this->progressImporting() === FEEDS_BATCH_COMPLETE ? $period : 0;
|
||||
$job = array(
|
||||
'type' => $this->id,
|
||||
'id' => $this->feed_nid,
|
||||
// Schedule as soon as possible if a batch is active.
|
||||
'period' => $period,
|
||||
'periodic' => TRUE,
|
||||
);
|
||||
if ($period != FEEDS_SCHEDULE_NEVER) {
|
||||
if ($period == FEEDS_SCHEDULE_NEVER && $this->progressImporting() === FEEDS_BATCH_COMPLETE) {
|
||||
JobScheduler::get('feeds_source_import')->remove($job);
|
||||
}
|
||||
elseif ($this->progressImporting() === FEEDS_BATCH_COMPLETE) {
|
||||
JobScheduler::get('feeds_source_import')->set($job);
|
||||
}
|
||||
else {
|
||||
JobScheduler::get('feeds_source_import')->remove($job);
|
||||
// Feed is not fully imported yet, so we put this job back in the queue
|
||||
// immediately for further processing.
|
||||
$queue = DrupalQueue::get('feeds_source_import');
|
||||
$queue->createItem($job);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule background expire tasks.
|
||||
*/
|
||||
public function scheduleExpire() {
|
||||
// Schedule as soon as possible if a batch is active.
|
||||
$period = $this->progressExpiring() === FEEDS_BATCH_COMPLETE ? 3600 : 0;
|
||||
|
||||
$job = array(
|
||||
'type' => $this->id,
|
||||
'id' => $this->feed_nid,
|
||||
'period' => $period,
|
||||
'periodic' => TRUE,
|
||||
);
|
||||
if ($this->importer->processor->expiryTime() == FEEDS_EXPIRE_NEVER) {
|
||||
JobScheduler::get('feeds_source_expire')->remove($job);
|
||||
}
|
||||
else {
|
||||
JobScheduler::get('feeds_source_expire')->set($job);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,6 +380,7 @@ class FeedsSource extends FeedsConfigurable {
|
||||
try {
|
||||
// If fetcher result is empty, we are starting a new import, log.
|
||||
if (empty($this->fetcher_result)) {
|
||||
module_invoke_all('feeds_before_import', $this);
|
||||
$this->state[FEEDS_START] = time();
|
||||
}
|
||||
|
||||
@@ -355,27 +397,91 @@ class FeedsSource extends FeedsConfigurable {
|
||||
|
||||
// Process.
|
||||
$this->importer->processor->process($this, $parser_result);
|
||||
|
||||
// Import finished without exceptions, so unset any potentially previously
|
||||
// recorded exceptions.
|
||||
unset($this->exception);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
// Do nothing.
|
||||
// $e is stored and re-thrown once we've had a chance to log our progress.
|
||||
// Set the exception so that other modules can check if an exception
|
||||
// occurred in hook_feeds_after_import().
|
||||
$this->exception = $e;
|
||||
}
|
||||
$this->releaseLock();
|
||||
|
||||
// Clean up.
|
||||
$result = $this->progressImporting();
|
||||
if ($result == FEEDS_BATCH_COMPLETE || isset($e)) {
|
||||
$this->imported = time();
|
||||
$this->log('import', 'Imported in !s s', array('!s' => $this->imported - $this->state[FEEDS_START]), WATCHDOG_INFO);
|
||||
$this->log('import', 'Imported in @s seconds.', array('@s' => $this->imported - $this->state[FEEDS_START]), WATCHDOG_INFO);
|
||||
module_invoke_all('feeds_after_import', $this);
|
||||
unset($this->fetcher_result, $this->state);
|
||||
}
|
||||
$this->save();
|
||||
|
||||
$this->releaseLock();
|
||||
|
||||
if (isset($e)) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports a fetcher result all at once in memory.
|
||||
*
|
||||
* @param FeedsFetcherResult $fetcher_result
|
||||
* The fetcher result to process.
|
||||
*
|
||||
* @throws Exception
|
||||
* Thrown if an error occurs when importing.
|
||||
*/
|
||||
public function pushImport(FeedsFetcherResult $fetcher_result) {
|
||||
// Since locks only work during a request, check if an import is active.
|
||||
if (!empty($this->fetcher_result) || !empty($this->state)) {
|
||||
throw new RuntimeException('The feed is currently importing.');
|
||||
}
|
||||
|
||||
$this->acquireLock();
|
||||
$start = time();
|
||||
|
||||
try {
|
||||
module_invoke_all('feeds_before_import', $this);
|
||||
|
||||
// Parse.
|
||||
do {
|
||||
$parser_result = $this->importer->parser->parse($this, $fetcher_result);
|
||||
module_invoke_all('feeds_after_parse', $this, $parser_result);
|
||||
|
||||
// Process.
|
||||
$this->importer->processor->process($this, $parser_result);
|
||||
|
||||
} while ($this->progressParsing() !== FEEDS_BATCH_COMPLETE);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
// $e is stored and re-thrown once we've had a chance to log our progress.
|
||||
// Set the exception so that other modules can check if an exception
|
||||
// occurred in hook_feeds_after_import().
|
||||
$this->exception = $e;
|
||||
}
|
||||
|
||||
module_invoke_all('feeds_after_import', $this);
|
||||
|
||||
$this->imported = time();
|
||||
$this->log('import', 'Imported in @s seconds.', array('@s' => $this->imported - $start), WATCHDOG_INFO);
|
||||
|
||||
unset($this->fetcher_result, $this->state);
|
||||
|
||||
$this->save();
|
||||
|
||||
$this->releaseLock();
|
||||
|
||||
if (isset($e)) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all items from a feed.
|
||||
*
|
||||
@@ -398,7 +504,7 @@ class FeedsSource extends FeedsConfigurable {
|
||||
$this->importer->processor->clear($this);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
// Do nothing.
|
||||
// $e is stored and re-thrown once we've had a chance to log our progress.
|
||||
}
|
||||
$this->releaseLock();
|
||||
|
||||
@@ -415,6 +521,26 @@ class FeedsSource extends FeedsConfigurable {
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all expired items from a feed.
|
||||
*/
|
||||
public function expire() {
|
||||
$this->acquireLock();
|
||||
try {
|
||||
$result = $this->importer->processor->expire($this);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
// Will throw after the lock is released.
|
||||
}
|
||||
$this->releaseLock();
|
||||
|
||||
if (isset($e)) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report progress as float between 0 and 1. 1 = FEEDS_BATCH_COMPLETE.
|
||||
*/
|
||||
@@ -449,6 +575,13 @@ class FeedsSource extends FeedsConfigurable {
|
||||
return $this->state(FEEDS_PROCESS_CLEAR)->progress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report progress on expiry.
|
||||
*/
|
||||
public function progressExpiring() {
|
||||
return $this->state(FEEDS_PROCESS_EXPIRE)->progress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a state object for a given stage. Lazy instantiates new states.
|
||||
*
|
||||
@@ -526,6 +659,9 @@ class FeedsSource extends FeedsConfigurable {
|
||||
if (!empty($record->state)) {
|
||||
$this->state = unserialize($record->state);
|
||||
}
|
||||
if (!is_array($this->state)) {
|
||||
$this->state = array();
|
||||
}
|
||||
if (!empty($record->fetcher_result)) {
|
||||
$this->fetcher_result = unserialize($record->fetcher_result);
|
||||
}
|
||||
@@ -552,6 +688,7 @@ class FeedsSource extends FeedsConfigurable {
|
||||
'id' => $this->feed_nid,
|
||||
);
|
||||
JobScheduler::get('feeds_source_import')->remove($job);
|
||||
JobScheduler::get('feeds_source_expire')->remove($job);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -722,4 +859,13 @@ class FeedsSource extends FeedsConfigurable {
|
||||
protected function releaseLock() {
|
||||
lock_release("feeds_source_{$this->id}_{$this->feed_nid}");
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements FeedsConfigurable::dependencies().
|
||||
*/
|
||||
public function dependencies() {
|
||||
$dependencies = parent::dependencies();
|
||||
return array_merge($dependencies, $this->importer()->dependencies());
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user