maintenance-1.0.0-beta1/src/Maintenance.php

src/Maintenance.php
<?php

namespace Drupal\maintenance;

use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Path\CurrentPathStack;
use Drupal\Core\Path\PathMatcherInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Site\MaintenanceMode;
use Drupal\Core\Site\MaintenanceModeInterface;
use Drupal\Core\State\StateInterface;
use Symfony\Component\HttpFoundation\RequestStack;

/**
 * Custom implementation of the core MaintenanceMode service.
 *
 * Adds support for IP, route, and query string exemptions during
 * maintenance mode.
 */
class Maintenance extends MaintenanceMode implements MaintenanceModeInterface {

  use MaintenanceStringHelperTrait;

  /**
   * The Request Stack.
   *
   * @var \Symfony\Component\HttpFoundation\RequestStack
   */
  protected RequestStack $requestStack;

  /**
   * Path matcher service for checking route patterns.
   *
   * @var \Drupal\Core\Path\PathMatcherInterface
   */
  protected PathMatcherInterface $pathMatcher;

  /**
   * Current path stack for alias-aware path resolution.
   *
   * @var \Drupal\Core\Path\CurrentPathStack
   */
  protected CurrentPathStack $currentPathStack;

  /**
   * The custom maintenance manager service.
   *
   * @var \Drupal\maintenance\MaintenanceManagerInterface
   */
  protected MaintenanceManagerInterface $maintenance;

  /**
   * Constructs a new Maintenance object.
   *
   * @param \Drupal\Core\State\StateInterface $state
   *   The state service for site-wide flags.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The configuration factory.
   * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
   *   Stack for retrieving the current HTTP request.
   * @param \Drupal\Core\Path\PathMatcherInterface $path_matcher
   *   Matches current request path against wildcard paths.
   * @param \Drupal\Core\Path\CurrentPathStack $current_path
   *   Provides access to the aliased and internal paths.
   * @param \Drupal\maintenance\MaintenanceManagerInterface $maintenance
   *   The custom maintenance manager service.
   */
  public function __construct(
    StateInterface $state,
    ConfigFactoryInterface $config_factory,
    RequestStack $request_stack,
    PathMatcherInterface $path_matcher,
    CurrentPathStack $current_path,
    MaintenanceManagerInterface $maintenance,
  ) {
    parent::__construct($state, $config_factory);
    $this->requestStack = $request_stack;
    $this->pathMatcher = $path_matcher;
    $this->currentPathStack = $current_path;
    $this->maintenance = $maintenance;
  }

  /**
   * {@inheritdoc}
   */
  public function exempt(AccountInterface $account): bool {
    // Grant immediate exemption if the user has the required permission.
    if ($account->hasPermission('access site in maintenance mode')) {
      return TRUE;
    }

    // Check exemption rules in a logical order: IP, URL, then query string.
    return $this->isIpExempt() || $this->isUrlExempt() || $this->isQueryExempt();
  }

  /**
   * Checks if client's IP is exempt from maintenance mode.
   *
   * Exemption is based on the IP visibility setting:
   * - visibility = 0:
   *     Allow access to listed IPs (deny others).
   * - visibility = 1:
   *     Show maintenance page only to listed IPs (allow others).
   *
   * @return bool
   *   TRUE if the client IP is exempt, FALSE otherwise.
   */
  protected function isIpExempt(): bool {
    // Get configured IP addresses.
    $ips = $this->maintenance->getAllowedIps();

    // Skip IP filter if no IPs configured.
    if (empty($ips)) {
      return FALSE;
    }

    // Get IP visibility setting.
    $visibility = (int) $this->maintenance->getConfig()->get('ip.visibility');

    // Get client IP from current request.
    $request = $this->requestStack->getCurrentRequest();
    $client_ip = $request->getClientIp();

    // Check IP match or CIDR range.
    $match = in_array($client_ip, $ips, TRUE) || $this->maintenance->isCidrMatch($client_ip);

    // Apply visibility: 0=allow listed, 1=show to listed.
    return $visibility === 0 ? $match : !$match;
  }

  /**
   * Checks if current URL path is exempt from maintenance mode.
   *
   * Exemption is based on the page visibility setting:
   * - visibility = 0:
   *     Allow access to listed pages (deny others).
   * - visibility = 1:
   *     Show maintenance page only on listed pages (allow others).
   *
   * @return bool
   *   TRUE if the current path is exempt, FALSE otherwise.
   */
  protected function isUrlExempt(): bool {
    // Get configured exempt URLs.
    $urls = $this->maintenance->getAllowedUrls();

    // Skip URL filter if no URLs configured.
    if (empty($urls)) {
      return FALSE;
    }

    // Get page visibility setting.
    $visibility = (int) $this->maintenance->getConfig()->get('page.visibility');

    // Convert URLs to newline-separated string.
    $urls_string = implode("\n", $urls);

    // Get actual and alias paths from request.
    $request = $this->requestStack->getCurrentRequest();
    $actual_path = $request->getPathInfo();
    $alias_path = $this->currentPathStack->getPath();

    // Check if path or alias matches exempt URLs.
    $match = $this->pathMatcher->matchPath($actual_path, $urls_string) ||
             $this->pathMatcher->matchPath($alias_path, $urls_string);

    // Apply visibility: 0=allow listed, 1=show to listed.
    return $visibility === 0 ? $match : !$match;
  }

  /**
   * Checks if query string grants exemption from maintenance mode.
   *
   * If a configured query string key is present in the request or session,
   * the user is exempt from maintenance mode.
   *
   * @return bool
   *   TRUE if query string matches, FALSE otherwise.
   */
  protected function isQueryExempt(): bool {
    // Get configured query string.
    $key = $this->maintenance->getConfig()->get('query.strings') ?? '';

    // Return FALSE if no query string configured.
    if (empty($key) || !is_string($key)) {
      return FALSE;
    }

    // Get current request.
    $request = $this->requestStack->getCurrentRequest();

    // Check if the exemption key was previously stored in the session.
    if (isset($_SESSION['maintenance']) && $_SESSION['maintenance'] == $key) {
      return TRUE;
    }

    // If query has the key, store in session and allow access.
    if ($request->query->has($key)) {
      $_SESSION['maintenance_exempt'] = $key;
      return TRUE;
    }

    // Query key not found, access is not exempted.
    return FALSE;
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc