Skip to content

Drupal

IniGet

Evaluate a PHP ini setting.

Class: Drutiny\Audit\Drupal\IniGet
Extends: Drutiny\Audit\AbstractComparison
Package: drutiny/drutiny

Parameters

Name Type Description Default
setting string The name of the ini setting to check. null
value mixed The local value of the ini setting to compare for. null
comp_type string The comparison operator to use for the comparison. null

Tokens

Name Type Description Default
setting string The name of the ini setting to check. null
value mixed The local value of the ini setting to compare for. null
comp_type string The comparison operator to use for the comparison. null
Source
  public function audit(Sandbox $sandbox)
  {
    $ini = $this->sandbox->drush()->evaluate(function () {
      return ini_get_all();
    });
    $setting = $sandbox->getParameter('setting');

    if (!isset($ini[$setting])) {
      return FALSE;
    }

    return $this->compare($sandbox->getParameter('value'), $ini[$setting]['local_value'], $sandbox);
  }

LargeDrupalFiles

Identify files larger than a specfied size. Pass if no matching files found.

Class: Drutiny\Audit\Drupal\LargeDrupalFiles
Extends: Drutiny\Audit
Package: drutiny/drutiny

Policies

These are the policies that use this class:

Name Title
Drupal:largeFiles Large Drupal Files

Parameters

Name Type Description Default
max_size integer Report files larger than this value measured in bytes. 10000000

Tokens

Name Type Description Default
max_size integer Report files larger than this value measured in bytes. 10000000
total integer Total number of large files found null
too_many_files integer Text to display if there are more than 10 files found. null
files integer A list of up to 10 files that are too large. null
plural string This variable will contain an 's' if there is more than one issue found. ''
Source
  public function audit(Sandbox $sandbox) {
    $max_size = (int) $sandbox->getParameter('max_size', 10000000);
    $sandbox->setParameter('readable_max_size', $max_size / 1000 / 1000 . ' MB');
    $query = "SELECT fm.uri, fm.filesize, (SELECT COUNT(*) FROM file_usage fu WHERE fu.fid = fm.fid) as 'usage' FROM file_managed fm WHERE fm.filesize >= @size ORDER BY fm.filesize DESC";
    $query = strtr($query, ['@size' => $max_size]);
    $output = $sandbox->drush()->sqlQuery($query);

    if (empty($output)) {
      return TRUE;
    }

    $records = is_array($output) ? $output : explode("\n", $output);
    $rows = array();
    foreach ($records as $record) {
      // Ignore record if it contains message about adding RSA key to known hosts.
      if (strpos($record, '(RSA) to the list of known hosts') != FALSE) {
        continue;
      }

      // Create the columns
      $parts = explode("\t", $record);
      $rows[] = [
        'uri' => $parts[0],
        'size' => number_format((float) $parts[1] / 1000 / 1000, 2) . ' MB',
        'usage' => ($parts[2] == 0) ? 'No' : 'Yes'
      ];
    }
    $totalRows = count($rows);

    if ($totalRows < 1) {
      return TRUE;
    }
    $sandbox->setParameter('total', $totalRows);

    // Reduce the number of rows to 10
    $rows = array_slice($rows, 0, 10);
    $too_many_files = ($totalRows > 10) ? "Only the first 10 files are displayed." : "";

    $sandbox->setParameter('too_many_files', $too_many_files);
    $sandbox->setParameter('files', $rows);
    $sandbox->setParameter('plural', $totalRows > 1 ? 's' : '');

    return Audit::FAIL;
  }

ModuleEnabled

Generic module is enabled check.

Class: Drutiny\Audit\Drupal\ModuleEnabled
Extends: Drutiny\Audit
Package: drutiny/drutiny

This class can remediate failed audits.

Policies

These are the policies that use this class:

Name Title
Drupal:SyslogEnabled Syslog
Drupal:Security:UserEmueration User Enumeration
Acquia:SiteFactory:ThemeEnabled Acquia Cloud Site Factory Theme
Acquia:PurgeEnabled Acquia Purge Enabled
Acquia:SiteFactoryOpenID Acquia Cloud Site Factory OpenID
Acquia:SiteFactory:Variables Acquia Cloud Site Factory Variables
Acquia:MemcacheEnabled Memcache module enabled
Acquia:StageFileProxy Serving files from production on development environments
Acquia:SPIEnabled Acquia SPI
Acquia:AgentEnabled Acquia Agent
Acquia:SiteFactory:Pingdom Acquia Cloud Site Factory Pingdom
Acquia:SiteFactoryDuplication Acquia Cloud Site Factory Duplication
Acquia:ACSF Acquia Cloud Site Factory
Acquia:Connected Acquia Connector
Drupal-7:SecurePagesEnabled Secure Pages Enabled
Drupal-8:PurgeEnabled Purge module enabled
Drupal-8:MemcacheEnabled Memcache module enabled

Parameters

Name Type Description Default
module string The module to check is enabled. null

Tokens

Name Type Description Default
module string The module to check is enabled. null
Source
  public function audit(Sandbox $sandbox)
  {

    $module = $sandbox->getParameter('module');
    $info = $sandbox->drush(['format' => 'json'])->pmList();

    if (!isset($info[$module])) {
      return FALSE;
    }

    $status = strtolower($info[$module]['status']);

    return ($status == 'enabled');
  }

ModuleUpdateStatus

Look for modules with available updates.

Class: Drutiny\Audit\Drupal\ModuleUpdateStatus
Extends: Drutiny\Audit
Package: drutiny/drutiny

Policies

These are the policies that use this class:

Name Title
Drupal:moduleUpdates Module updates

Tokens

Name Type Description Default
updates array Description of module updates available. null
Source
  public function audit(Sandbox $sandbox) {
    $output = $sandbox->drush()->pmUpdatestatus('--format=json');
    $lines = explode(PHP_EOL, $output);
    $lines = array_map('trim', $lines);

    // Output can often contain non-json output which needs to be filtered out.
    while ($line = array_shift($lines)) {
      if ($line == "{") {
        array_unshift($lines, $line);
        break;
      }
    }
    $json = implode(PHP_EOL, $lines);
    $modules = json_decode($json, TRUE);

    $issues = [];

    foreach ($modules as $name => $info) {

      if (isset($info['recommended_major']) && $info['existing_major'] != $info['recommended_major']) {
        $issues[] = $info;
      }
      elseif ($info['existing_version'] != $info['recommended']) {
        $issues[] = $info;
      }
    }

    $sandbox->setParameter('updates', $issues);

    if (!count($issues)) {
      return TRUE;
    }

    $sec_updates = array_filter($issues, function ($info) {
      return strpos($info['status_msg'], 'SECURITY') !== FALSE;
    });

    // Pure failure if all issues are security ones.
    if (count($sec_updates) === count($issues)) {
      return FALSE;
    }
    // Security updates and normal updates available.
    elseif (count($sec_updates)) {
      return Audit::WARNING_FAIL;
    }

    // Just normal updates available.
    return Audit::WARNING;
  }

ModuleVersion

Check the version of Drupal project in a site.

Class: Drutiny\Audit\Drupal\ModuleVersion
Extends: Drutiny\Audit
Package: drutiny/drutiny

Policies

These are the policies that use this class:

Name Title
Drupal-7:SA-CORE-2013-003 CSS Aggregation

Parameters

Name Type Description Default
module string The module to version information for null
version string The static version to check against. null
comparator string How to compare the version (greaterThan, greaterThanOrEqualTo, lessThan etc. See https://github.com/composer/semver) greaterThanOrEqualTo

Tokens

Name Type Description Default
module string The module to version information for null
version string The static version to check against. null
comparator string How to compare the version (greaterThan, greaterThanOrEqualTo, lessThan etc. See https://github.com/composer/semver) greaterThanOrEqualTo
Source
  public function audit(Sandbox $sandbox)
  {
    $module = $sandbox->getParameter('module');
    $version = $sandbox->getParameter('version');
    $comparator_method = $sandbox->getParameter('comparator');

    if (!method_exists("Composer\Semver\Comparator", $comparator_method)) {
      throw new \Exception("Comparator method not available: $comparator_method");
    }

    $info = $sandbox->drush(['format' => 'json'])->pmList();

    if (!isset($info[$module])) {
      return Audit::NOT_APPLICABLE;
    }

    $current_version = strtolower($info[$module]['version']);
    $sandbox->setParameter('current_version', $current_version);

    $sandbox->logger()->info("$comparator_method($current_version, $version)");

    return call_user_func("Composer\Semver\Comparator::$comparator_method", $current_version, $version);
  }

PhpLint

Run PHP lint over PHP files in a directory.

Class: Drutiny\Audit\Drupal\PhpLint
Extends: Drutiny\Audit
Package: drutiny/drutiny

Policies

These are the policies that use this class:

Name Title
Drupal:LintTheme Lint PHP files in Theme

Parameters

Name Type Description Default
path string The path where to lint PHP files. '%root'

Tokens

Name Type Description Default
path string The path where to lint PHP files. '%root'
errors array An array of parse errors found. { }
Source
  public function audit(Sandbox $sandbox) {
    // find src/ -name \*.php -exec php -l {} \; 2>&1 | grep 'PHP Parse error:'
    $path = $sandbox->getParameter('path', '%root');
    $stat = $sandbox->drush(['format' => 'json'])->status();

    $path = strtr($path, $stat['%paths']);

    $errors = $sandbox->exec("find $path -name \*.php -exec php -l {} \; 2>&1 | grep 'PHP Parse error:' || true");
    $errors = array_filter(explode(PHP_EOL, $errors));
    $sandbox->setParameter('errors', $errors);
    return count($errors) == 0;
  }

SqlResultAudit

Audit the first row returned from a SQL query.

Class: Drutiny\Audit\Drupal\SqlResultAudit
Extends: Drutiny\Audit\AbstractAnalysis
Package: drutiny/drutiny

Policies

These are the policies that use this class:

Name Title
Drupal:AnonSession Anonymous sessions
Database:Fulltext Database fulltext indexing
Drupal-8:ContentOwnedByAnonymous Content Owned By Drupal's Anonymous User

Parameters

Name Type Description Default
query string The SQL query to run. Can use other parameters for variable replacement. null
expression string An expression language expression to evaluate a successful auditable outcome. true

Tokens

Name Type Description Default
query string The SQL query to run. Can use other parameters for variable replacement. null
expression string An expression language expression to evaluate a successful auditable outcome. true
result string The comparison operator to use for the comparison. null
results string The record set. null
Source
  public function gather(Sandbox $sandbox)
  {
    $query = $sandbox->getParameter('query');

    $tokens = [];
    foreach ($sandbox->getParameterTokens() as $key => $value) {
        $tokens[':' . $key] = $value;
    }
    foreach ($sandbox->drush(['format' => 'json'])->status() as $key => $value) {
      if (!is_array($value)) {
        $tokens[':' . $key] = $value;
      }
      // TODO: Support array values.
    }
    $query = strtr($query, $tokens);

    if (!preg_match_all('/^SELECT( DISTINCT)? (.*) FROM/', $query, $fields)) {
      throw new \Exception("Could not parse fields from SQL query: $query.");
    }
    $fields = array_map('trim', explode(',', $fields[2][0]));
    foreach ($fields as &$field) {
      if ($idx = strpos($field, ' as ')) {
        $field = substr($field, $idx + 4);
      }
      elseif (preg_match('/[ \(\)]/', $field)) {
        throw new \Exception("SQL query contains an non-table field without an alias: '$field.'");
      }
    }

    $output = $sandbox->drush()->sqlq($query);
    $results = [];

    while ($line = array_shift($output))
    {
      $values = array_map('trim', explode("\t", $line));
      $results[] = array_combine($fields, $values);
    }

    $sandbox->setParameter('count', count($results));
    $sandbox->setParameter('results', $results);

    $row = array_shift($results);

    $sandbox->setParameter('first_row', $row);
  }
  final public function audit(Sandbox $sandbox)
  {
    $this->gather($sandbox);

    $expressionLanguage = new ExpressionLanguage($sandbox);

    $variables  = $sandbox->getParameterTokens();
    $sandbox->logger()->debug(__CLASS__ . ': ' . Yaml::dump($variables));

    $expression = $sandbox->getParameter('not_applicable', 'false');
    $sandbox->logger()->debug(__CLASS__ . ': ' . $expression);
    if (@$expressionLanguage->evaluate($expression, $variables)) {
      return self::NOT_APPLICABLE;
    }

    $expression = $sandbox->getParameter('expression', 'true');
    $sandbox->logger()->info(__CLASS__ . ': ' . $expression);
    return @$expressionLanguage->evaluate($expression, $variables);
  }

StatusInformation

Drush Status Information

Class: Drutiny\Audit\Drupal\StatusInformation
Extends: Drutiny\Audit
Package: drutiny/drutiny

Tokens

Name Type Description Default
status array The status object returned by drush. null
Source
  public function audit(Sandbox $sandbox) {
    $stat = $sandbox->drush(['format' => 'json'])->status();
    $sandbox->setParameter('status', $stat);

    return Audit::NOTICE;
  }

UpdateDBStatus

Ensure all module updates have been applied.

Class: Drutiny\Audit\Drupal\UpdateDBStatus
Extends: Drutiny\Audit
Package: drutiny/drutiny

Policies

These are the policies that use this class:

Name Title
Drupal:updates Database updates
Source
  public function audit(Sandbox $sandbox) {
    $output = $sandbox->drush()->updb('-n');

    if (strpos($output, self::AFFIRMATIVE_UPDATES_STRING) !== FALSE) {

      $lines = array_filter(explode(PHP_EOL, $output));
      $updates = [];
      while (strpos(current($lines), self::AFFIRMATIVE_UPDATES_STRING) === FALSE) {
        preg_match("/\s*([\w\s]*\w)\s+(\d+)\s+(.*)/", current($lines), $matches);
        list(, $module, $revision, $message) = $matches;
        $updates[] = [
          'module' => $module,
          'revision' => $revision,
          'message' => $message
        ];
        next($lines);
      }
      $sandbox->setParameter('updates', $updates);
      return FALSE;
    }
    return TRUE;
  }