You are here

responsive_favicons.module in Responsive Favicons 7

Same filename and directory in other branches
  1. 8 responsive_favicons.module

Responsive favicons module file.

File

responsive_favicons.module
View source
<?php

/**
 * @file
 * Responsive favicons module file.
 */

/**
 * Implements hook_help().
 */
function responsive_favicons_help($path, $arg) {
  switch ($path) {
    case 'admin/help#responsive_favicons':
      $readme_file = dirname(__FILE__) . '/README.txt';
      if (file_exists($readme_file)) {
        $readme = file_get_contents($readme_file);
      }
      if (!isset($readme)) {
        return '';
      }

      // Markdown is optionally supported if you already have it installed.
      if (module_exists('markdown')) {
        $filters = module_invoke('markdown', 'filter_info');
        $info = $filters['filter_markdown'];
        if (function_exists($info['process callback'])) {
          $function = $info['process callback'];
          $output = filter_xss_admin($function($readme, NULL));
        }
        else {
          $output = '<pre>' . check_plain($readme) . '</pre>';
        }
      }
      else {
        $output = '<pre>' . check_plain($readme) . '</pre>';
      }
      return $output;
  }
}

/**
 * Implements hook_permission().
 */
function responsive_favicons_permission() {
  return array(
    'administer responsive favicons' => array(
      'title' => t('Administer responsive favicons'),
    ),
  );
}

/**
 * Implements hook_menu().
 */
function responsive_favicons_menu() {

  // List of icons to redirect.
  // Note, in order for these to work alter the fast404 pattern to allow these
  // requests to hit Drupal. Please see the README for more information.
  $icons = array(
    'apple-touch-icon.png',
    'apple-touch-icon-precomposed.png',
    'browserconfig.xml',
  );

  // Try to avoid clashing with the favicon module.
  if (!module_exists('favicon')) {
    $icons[] = 'favicon.ico';
  }
  foreach ($icons as $icon) {
    $items[$icon] = array(
      'page callback' => 'responsive_favicons_get_file',
      'page arguments' => array(
        $icon,
      ),
      'delivery callback' => 'responsive_favicons_deliver_file',
      'access callback' => TRUE,
      'type' => MENU_CALLBACK,
      'file' => 'responsive_favicons.delivery.inc',
    );
  }
  $items['admin/config/user-interface/responsive_favicons'] = array(
    'title' => 'Responsive favicons',
    'description' => 'Configure responsive favicons',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'responsive_favicons_config_page',
    ),
    'access callback' => 'user_access',
    'access arguments' => array(
      'administer responsive favicons',
    ),
    'type' => MENU_NORMAL_ITEM,
    'file' => 'responsive_favicons.admin.inc',
  );
  return $items;
}

/**
 * Implements hook_page_build().
 *
 * Adds responsive favicons to HTML head. A trailing newline is added to ensure
 * the next tag in the HTML head section starts on the next line.
 */
function responsive_favicons_page_build(&$page) {
  $tags = responsive_favicons_load_all_icons();
  if (!empty($tags['found'])) {
    $html = array(
      '#type' => 'markup',
      '#markup' => implode(PHP_EOL, $tags['found']) . PHP_EOL,
    );
    drupal_add_html_head($html, 'responsive_favicons');
  }
}

/**
 * Implements hook_html_head_alter().
 */
function responsive_favicons_html_head_alter(&$head_elements) {
  $favicon_remove_default = variable_get('responsive_favicons_remove_default', 0);
  if (empty($head_elements['responsive_favicons']) || $favicon_remove_default == 0) {
    return;
  }

  // Remove the default favicon from the head section.
  foreach ($head_elements as $key => $element) {
    if (!empty($element['#attributes'])) {
      if (array_key_exists('rel', $element['#attributes'])) {
        if ($element['#attributes']['rel'] === 'shortcut icon') {
          unset($head_elements[$key]);
        }
      }
    }
  }
}

/**
 * Load the responsive favicons that are valid.
 */
function responsive_favicons_load_all_icons() {
  $icons =& drupal_static(__FUNCTION__);
  if (!isset($icons)) {
    if ($cached = cache_get('responsive_favicons_icons', 'cache')) {
      $icons = $cached->data;
    }
    else {
      $responsive_favicon_tags = variable_get('responsive_favicons_tags', '');
      if (empty($responsive_favicon_tags)) {
        $icons = array(
          'found' => array(),
          'missing' => array(),
        );
      }
      else {
        $html = implode(PHP_EOL, $responsive_favicon_tags);
        $icons = _responsive_favicons_validate_tags($html);
        if (empty($icons['missing'])) {
          cache_set('responsive_favicons_icons', $icons, 'cache');
        }
      }
    }
  }
  return $icons;
}

/**
 * Helper function to check whether responsive favicon files exist and are
 * readable. This function also strips any pasted content that is not a link
 * or a meta tag.
 *
 * @param string $html
 *   html tag
 * @return array $missing_files
 */
function _responsive_favicons_validate_tags($html) {
  global $base_path;
  $found = array();
  $missing = array();
  $dom = new DOMDocument();
  $dom
    ->loadHTML($html);

  // DRUPAL_ROOT contains the sub directory of the Drupal install (if present),
  // in our case we do not want this as $file_path already contains this.
  $docroot = preg_replace('/' . preg_quote($base_path, '/') . '$/', '/', DRUPAL_ROOT);

  // Find all the apple touch icons.
  $tags = $dom
    ->getElementsByTagName('link');
  foreach ($tags as $tag) {
    $url_path = _responsive_favicons_normalise_path($tag
      ->getAttribute('href'));
    $file_path = parse_url($url_path, PHP_URL_PATH);
    $tag
      ->setAttribute('href', $url_path);
    if (file_exists($docroot . $file_path) && is_readable($docroot . $file_path)) {
      $found[] = $dom
        ->saveXML($tag);
    }
    else {
      $missing[] = $dom
        ->saveXML($tag);
    }
  }

  // Find any Windows 8 meta tags.
  $tags = $dom
    ->getElementsByTagName('meta');
  foreach ($tags as $tag) {
    $name = $tag
      ->getAttribute('name');

    // We only validate the image file.
    if ($name === 'msapplication-TileImage') {
      $file_path = _responsive_favicons_normalise_path($tag
        ->getAttribute('content'));
      $tag
        ->setAttribute('content', $file_path);
      if (file_exists($docroot . $file_path) && is_readable($docroot . $file_path)) {
        $found[] = $dom
          ->saveXML($tag);
      }
      else {
        $missing[] = $dom
          ->saveXML($tag);
      }
    }
    else {
      $found[] = $dom
        ->saveXML($tag);
    }
  }
  return array(
    'found' => $found,
    'missing' => $missing,
  );
}

/**
 * Help to normalise the path to the icons.
 *
 * @param $file_path
 *   The filename of the icon.
 * @return string
 *   The full relative path to the icon within public files.
 */
function _responsive_favicons_normalise_path($file_path) {
  global $base_path;

  // Remove absolute URLs.
  if (url_is_external($file_path)) {
    $file_path = str_replace($base_path, '', $file_path);
  }

  // There appears to be no sane way of getting a relative path to a file, so
  // this is the best for now.
  // @see https://www.drupal.org/node/837794#comment-9124435
  $wrapper = file_stream_wrapper_get_instance_by_uri('public://');
  if ($wrapper instanceof DrupalLocalStreamWrapper) {
    $relative_path = $wrapper
      ->getDirectoryPath() . '/' . variable_get('responsive_favicons_path', 'favicons') . $file_path;
  }
  return $base_path . $relative_path;
}

Functions

Namesort descending Description
responsive_favicons_help Implements hook_help().
responsive_favicons_html_head_alter Implements hook_html_head_alter().
responsive_favicons_load_all_icons Load the responsive favicons that are valid.
responsive_favicons_menu Implements hook_menu().
responsive_favicons_page_build Implements hook_page_build().
responsive_favicons_permission Implements hook_permission().
_responsive_favicons_normalise_path Help to normalise the path to the icons.
_responsive_favicons_validate_tags Helper function to check whether responsive favicon files exist and are readable. This function also strips any pasted content that is not a link or a meta tag.