[ Index ]

PHP Cross Reference of Drupal 6 (yi-drupal)

title

Body

[close]

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

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


Generated: Mon Jul 9 18:01:44 2012 Cross-referenced by PHPXref 0.7