[ Index ]

PHP Cross Reference of Drupal 6 (gatewave)

title

Body

[close]

/modules/update/ -> update.fetch.inc (source)

   1  <?php
   2  // $Id: update.fetch.inc,v 1.7.2.7 2009/07/21 08:59:12 goba Exp $
   3  
   4  /**
   5   * @file
   6   * Code required only when fetching information about available updates.
   7   */
   8  
   9  /**
  10   * Callback to manually check the update status without cron.
  11   */
  12  function update_manual_status() {
  13    if (_update_refresh()) {
  14      drupal_set_message(t('Attempted to fetch information about all available new releases and updates.'));
  15    }
  16    else {
  17      drupal_set_message(t('Unable to fetch any information about available new releases and updates.'), 'error');
  18    }
  19    drupal_goto('admin/reports/updates');
  20  }
  21  
  22  /**
  23   * Fetch project info via XML from a central server.
  24   */
  25  function _update_refresh() {
  26    static $fail = array();
  27    global $base_url;
  28    module_load_include('inc', 'update', 'update.compare');
  29  
  30    // Since we're fetching new available update data, we want to clear
  31    // our cache of both the projects we care about, and the current update
  32    // status of the site. We do *not* want to clear the cache of available
  33    // releases just yet, since that data (even if it's stale) can be useful
  34    // during update_get_projects(); for example, to modules that implement
  35    // hook_system_info_alter() such as cvs_deploy.
  36    _update_cache_clear('update_project_projects');
  37    _update_cache_clear('update_project_data');
  38  
  39    $available = array();
  40    $data = array();
  41    $site_key = md5($base_url . drupal_get_private_key());
  42    $projects = update_get_projects();
  43  
  44    // Now that we have the list of projects, we should also clear our cache of
  45    // available release data, since even if we fail to fetch new data, we need
  46    // to clear out the stale data at this point.
  47    _update_cache_clear('update_available_releases');
  48    $max_fetch_attempts = variable_get('update_max_fetch_attempts', UPDATE_MAX_FETCH_ATTEMPTS);
  49    
  50    foreach ($projects as $key => $project) {
  51      $url = _update_build_fetch_url($project, $site_key);
  52      $fetch_url_base = _update_get_fetch_url_base($project);
  53      if (empty($fail[$fetch_url_base]) || count($fail[$fetch_url_base]) < $max_fetch_attempts) {
  54        $xml = drupal_http_request($url);
  55        if (isset($xml->data)) {
  56          $data[] = $xml->data;
  57        }
  58        else {
  59          // Connection likely broken; prepare to give up.
  60          $fail[$fetch_url_base][$key] = 1;
  61        }
  62      }
  63      else {
  64        // Didn't bother trying to fetch.
  65        $fail[$fetch_url_base][$key] = 1;
  66      }
  67    }
  68  
  69    if ($data) {
  70      $parser = new update_xml_parser;
  71      $available = $parser->parse($data);
  72    }
  73    if (!empty($available) && is_array($available)) {
  74      // Record the projects where we failed to fetch data.
  75      foreach ($fail as $fetch_url_base => $failures) {
  76        foreach ($failures as $key => $value) {
  77          $available[$key]['project_status'] = 'not-fetched';
  78        }
  79      }
  80      $frequency = variable_get('update_check_frequency', 1);
  81      _update_cache_set('update_available_releases', $available, time() + (60 * 60 * 24 * $frequency));
  82      watchdog('update', 'Attempted to fetch information about all available new releases and updates.', array(), WATCHDOG_NOTICE, l(t('view'), 'admin/reports/updates'));
  83    }
  84    else {
  85      watchdog('update', 'Unable to fetch any information about available new releases and updates.', array(), WATCHDOG_ERROR, l(t('view'), 'admin/reports/updates'));
  86    }
  87    // Whether this worked or not, we did just (try to) check for updates.
  88    variable_set('update_last_check', time());
  89    return $available;
  90  }
  91  
  92  /**
  93   * Generates the URL to fetch information about project updates.
  94   *
  95   * This figures out the right URL to use, based on the project's .info file
  96   * and the global defaults. Appends optional query arguments when the site is
  97   * configured to report usage stats.
  98   *
  99   * @param $project
 100   *   The array of project information from update_get_projects().
 101   * @param $site_key
 102   *   The anonymous site key hash (optional).
 103   *
 104   * @see update_refresh()
 105   * @see update_get_projects()
 106   */
 107  function _update_build_fetch_url($project, $site_key = '') {
 108    $name = $project['name'];
 109    $url = _update_get_fetch_url_base($project);
 110    $url .= '/'. $name .'/'. DRUPAL_CORE_COMPATIBILITY;
 111    // Only append a site_key and the version information if we have a site_key
 112    // in the first place, and if this is not a disabled module or theme. We do
 113    // not want to record usage statistics for disabled code.
 114    if (!empty($site_key) && (strpos($project['project_type'], 'disabled') === FALSE)) {
 115      $url .= (strpos($url, '?') === TRUE) ? '&' : '?';
 116      $url .= 'site_key=';
 117      $url .= rawurlencode($site_key);
 118      if (!empty($project['info']['version'])) {
 119        $url .= '&version=';
 120        $url .= rawurlencode($project['info']['version']);
 121      }
 122    }
 123    return $url;
 124  }
 125  
 126  /**
 127   * Return the base of the URL to fetch available update data for a project.
 128   *
 129   * @param $project
 130   *   The array of project information from update_get_projects().
 131   * @return
 132   *   The base of the URL used for fetching available update data. This does
 133   *   not include the path elements to specify a particular project, version,
 134   *   site_key, etc.
 135   *
 136   * @see _update_build_fetch_url()
 137   */
 138  function _update_get_fetch_url_base($project) {
 139    return isset($project['info']['project status url']) ? $project['info']['project status url'] : variable_get('update_fetch_url', UPDATE_DEFAULT_URL);
 140  }
 141  
 142  /**
 143   * Perform any notifications that should be done once cron fetches new data.
 144   *
 145   * This method checks the status of the site using the new data and depending
 146   * on the configuration of the site, notifies administrators via email if there
 147   * are new releases or missing security updates.
 148   *
 149   * @see update_requirements()
 150   */
 151  function _update_cron_notify() {
 152    include_once  './includes/install.inc';
 153    $status = update_requirements('runtime');
 154    $params = array();
 155    $notify_all = (variable_get('update_notification_threshold', 'all') == 'all');
 156    foreach (array('core', 'contrib') as $report_type) {
 157      $type = 'update_'. $report_type;
 158      if (isset($status[$type]['severity'])
 159          && ($status[$type]['severity'] == REQUIREMENT_ERROR || ($notify_all && $status[$type]['reason'] == UPDATE_NOT_CURRENT))) {
 160        $params[$report_type] = $status[$type]['reason'];
 161      }
 162    }
 163    if (!empty($params)) {
 164      $notify_list = variable_get('update_notify_emails', '');
 165      if (!empty($notify_list)) {
 166        $default_language = language_default();
 167        foreach ($notify_list as $target) {
 168          if ($target_user = user_load(array('mail' => $target))) {
 169            $target_language = user_preferred_language($target_user);
 170          }
 171          else {
 172            $target_language = $default_language;
 173          }
 174          drupal_mail('update', 'status_notify', $target, $target_language, $params);
 175        }
 176      }
 177    }
 178  }
 179  
 180  /**
 181   * XML Parser object to read Drupal's release history info files.
 182   * This uses PHP4's lame XML parsing, but it works.
 183   */
 184  class update_xml_parser {
 185    var $projects = array();
 186    var $current_project;
 187    var $current_release;
 188    var $current_term;
 189    var $current_tag;
 190    var $current_object;
 191  
 192    /**
 193     * Parse an array of XML data files.
 194     */
 195    function parse($data) {
 196      foreach ($data as $datum) {
 197        $parser = xml_parser_create();
 198        xml_set_object($parser, $this);
 199        xml_set_element_handler($parser, 'start', 'end');
 200        xml_set_character_data_handler($parser, "data");
 201        xml_parse($parser, $datum);
 202        xml_parser_free($parser);
 203      }
 204      return $this->projects;
 205    }
 206  
 207    function start($parser, $name, $attr) {
 208      $this->current_tag = $name;
 209      switch ($name) {
 210        case 'PROJECT':
 211          unset($this->current_object);
 212          $this->current_project = array();
 213          $this->current_object = &$this->current_project;
 214          break;
 215        case 'RELEASE':
 216          unset($this->current_object);
 217          $this->current_release = array();
 218          $this->current_object = &$this->current_release;
 219          break;
 220        case 'TERM':
 221          unset($this->current_object);
 222          $this->current_term = array();
 223          $this->current_object = &$this->current_term;
 224          break;
 225      }
 226    }
 227  
 228    function end($parser, $name) {
 229      switch ($name) {
 230        case 'PROJECT':
 231          unset($this->current_object);
 232          $this->projects[$this->current_project['short_name']] = $this->current_project;
 233          $this->current_project = array();
 234          break;
 235        case 'RELEASE':
 236          unset($this->current_object);
 237          $this->current_project['releases'][$this->current_release['version']] = $this->current_release;
 238          break;
 239        case 'RELEASES':
 240          $this->current_object = &$this->current_project;
 241          break;
 242        case 'TERM':
 243          unset($this->current_object);
 244          $term_name = $this->current_term['name'];
 245          if (!isset($this->current_release['terms'])) {
 246            $this->current_release['terms'] = array();
 247          }
 248          if (!isset($this->current_release['terms'][$term_name])) {
 249            $this->current_release['terms'][$term_name] = array();
 250          }
 251          $this->current_release['terms'][$term_name][] = $this->current_term['value'];
 252          break;
 253        case 'TERMS':
 254          $this->current_object = &$this->current_release;
 255          break;
 256        default:
 257          $this->current_object[strtolower($this->current_tag)] = trim($this->current_object[strtolower($this->current_tag)]);
 258          $this->current_tag = '';
 259      }
 260    }
 261  
 262    function data($parser, $data) {
 263      if ($this->current_tag && !in_array($this->current_tag, array('PROJECT', 'RELEASE', 'RELEASES', 'TERM', 'TERMS'))) {
 264        $tag = strtolower($this->current_tag);
 265        if (isset($this->current_object[$tag])) {
 266          $this->current_object[$tag] .= $data;
 267        }
 268        else {
 269          $this->current_object[$tag] = $data;
 270        }
 271      }
 272    }
 273  }


Generated: Thu Mar 24 11:18:33 2011 Cross-referenced by PHPXref 0.7