You are here

private function AcsfInitCommands::patchHtaccess in Acquia Cloud Site Factory Connector 8.2

Patches the htaccess file to allow access to our apc_rebuild.php script.

We do not use the unix patch utility here, as it might be too fussy about line numbers and context. We want to ensure that our line is present in the .htaccess file in an appropriate place, without caring too much about the content of surrounding lines. There will be extreme cases where this patching can fail if modifications to the customer's .htaccess file cause it to be wildly different to stock Drupal 8. In this case, they can manually add the line, and we will accept that manual modification. This doesn't seem like a situation we need to handle until we have at least one case. If a customer was for some reason really sure that they did not want our line in their .htaccess file, then adding it verbatim, but commented-out would suffice.

Throws

\Drupal\acsf\AcsfInitHtaccessException If the function couldn't patch the .htaccess file.

1 call to AcsfInitCommands::patchHtaccess()
AcsfInitCommands::init in acsf_init/src/Commands/AcsfInitCommands.php
Make this repository compatible with Acquia Site Factory.

File

acsf_init/src/Commands/AcsfInitCommands.php, line 796

Class

AcsfInitCommands
Provides drush commands to set up a codebase for Acquia Cloud Site Factory.

Namespace

Drush\Commands

Code

private function patchHtaccess() {
  if ($this
    ->testHtaccessIsPatched()) {
    return;
  }
  $this
    ->output()
    ->writeln(dt('Patching .htaccess file.'));

  // All the lines we've scanned so far up until the marker line.
  $output_lines = [];

  // The output as a string.
  $output = '';

  // Iterate line-by-line until we reach the line which our rule MUST precede.
  $fp = fopen($this
    ->getHtaccessPath(), 'r+');
  $marker_found = FALSE;
  while (($line = fgets($fp, 4096)) !== FALSE) {
    $output_lines[] = $line;
    if (strpos($line, self::ACSF_HTACCESS_PATCH_MARKER) !== FALSE) {
      $marker_found = TRUE;

      // ... And then backtrack all the lines of comments that precede that
      // marker line.
      $marker_index = count($output_lines) - 1;
      while ($marker_index > 0 && preg_match('/^\\s*#.*$/', $output_lines[$marker_index - 1])) {
        $marker_index--;
      }
      if ($marker_index == 0) {

        // This should never happen - it could only happen if the entire
        // .htaccess file preceding the marker line were all comments.  We
        // cannot consider this valid, as the minimum requirements for
        // rewrites are not met.  We'd expect at a minimum
        // <IfModule mod_rewrite.c> ... RewriteEngine on.
        throw new AcsfInitHtaccessException('Reached the beginning of the file but was unable to find a place to insert the .htaccess patch.  The .htaccess file can be manually handled to fix this error.');
      }

      // Insert our patch with preceding comment, before the marker index,
      // i.e. after the first line seen which is not a comment.
      // Also, prepending 2 whitespaces before the htaccess patch
      // so that it's indented properly.
      array_splice($output_lines, $marker_index, 0, [
        self::ACSF_HTACCESS_PATCH_COMMENT . "\n",
        '  ' . self::ACSF_HTACCESS_PATCH . "\n",
      ]);
      $output = implode('', $output_lines);
      break;
    }
  }
  if (!$marker_found) {

    // We were unable to locate the marker that disallows access to PHP files
    // - it may have been modified which makes it impossible to locate.
    // Alternatively, it may have been removed entirely, which actually means
    // we don't need to patch the file at all. @see
    // drush_acsf_init_patch_htaccess() for info on how to convince the
    // verification to accept the file.
    throw new AcsfInitHtaccessException('Unable to locate the marker for patching the .htaccess file. This file will need manual patching to allow access to the apc_rebuild.php file.');
  }

  // Then append the rest of the file.
  while (($line = fgets($fp, 4096)) !== FALSE) {
    $output .= "{$line}";
  }
  file_put_contents($this
    ->getHtaccessPath(), $output);
  if ($this
    ->testHtaccessIsPatched()) {
    $this
      ->logger()
      ->info(dt('Successfully patched .htaccess file.'));
  }
  else {
    $this
      ->logger()
      ->error(dt('Failed to patch .htaccess file.'));
  }
}