Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.
   1  <?php
   2  
   3  /**
   4   * Parses string hash files. File format is as such:
   5   *
   6   *      DefaultKeyValue
   7   *      KEY: Value
   8   *      KEY2: Value2
   9   *      --MULTILINE-KEY--
  10   *      Multiline
  11   *      value.
  12   *
  13   * Which would output something similar to:
  14   *
  15   *      array(
  16   *          'ID' => 'DefaultKeyValue',
  17   *          'KEY' => 'Value',
  18   *          'KEY2' => 'Value2',
  19   *          'MULTILINE-KEY' => "Multiline\nvalue.\n",
  20   *      )
  21   *
  22   * We use this as an easy to use file-format for configuration schema
  23   * files, but the class itself is usage agnostic.
  24   *
  25   * You can use ---- to forcibly terminate parsing of a single string-hash;
  26   * this marker is used in multi string-hashes to delimit boundaries.
  27   */
  28  class HTMLPurifier_StringHashParser
  29  {
  30  
  31      /**
  32       * @type string
  33       */
  34      public $default = 'ID';
  35  
  36      /**
  37       * Parses a file that contains a single string-hash.
  38       * @param string $file
  39       * @return array
  40       */
  41      public function parseFile($file)
  42      {
  43          if (!file_exists($file)) {
  44              return false;
  45          }
  46          $fh = fopen($file, 'r');
  47          if (!$fh) {
  48              return false;
  49          }
  50          $ret = $this->parseHandle($fh);
  51          fclose($fh);
  52          return $ret;
  53      }
  54  
  55      /**
  56       * Parses a file that contains multiple string-hashes delimited by '----'
  57       * @param string $file
  58       * @return array
  59       */
  60      public function parseMultiFile($file)
  61      {
  62          if (!file_exists($file)) {
  63              return false;
  64          }
  65          $ret = array();
  66          $fh = fopen($file, 'r');
  67          if (!$fh) {
  68              return false;
  69          }
  70          while (!feof($fh)) {
  71              $ret[] = $this->parseHandle($fh);
  72          }
  73          fclose($fh);
  74          return $ret;
  75      }
  76  
  77      /**
  78       * Internal parser that acepts a file handle.
  79       * @note While it's possible to simulate in-memory parsing by using
  80       *       custom stream wrappers, if such a use-case arises we should
  81       *       factor out the file handle into its own class.
  82       * @param resource $fh File handle with pointer at start of valid string-hash
  83       *            block.
  84       * @return array
  85       */
  86      protected function parseHandle($fh)
  87      {
  88          $state   = false;
  89          $single  = false;
  90          $ret     = array();
  91          do {
  92              $line = fgets($fh);
  93              if ($line === false) {
  94                  break;
  95              }
  96              $line = rtrim($line, "\n\r");
  97              if (!$state && $line === '') {
  98                  continue;
  99              }
 100              if ($line === '----') {
 101                  break;
 102              }
 103              if (strncmp('--#', $line, 3) === 0) {
 104                  // Comment
 105                  continue;
 106              } elseif (strncmp('--', $line, 2) === 0) {
 107                  // Multiline declaration
 108                  $state = trim($line, '- ');
 109                  if (!isset($ret[$state])) {
 110                      $ret[$state] = '';
 111                  }
 112                  continue;
 113              } elseif (!$state) {
 114                  $single = true;
 115                  if (strpos($line, ':') !== false) {
 116                      // Single-line declaration
 117                      list($state, $line) = explode(':', $line, 2);
 118                      $line = trim($line);
 119                  } else {
 120                      // Use default declaration
 121                      $state  = $this->default;
 122                  }
 123              }
 124              if ($single) {
 125                  $ret[$state] = $line;
 126                  $single = false;
 127                  $state  = false;
 128              } else {
 129                  $ret[$state] .= "$line\n";
 130              }
 131          } while (!feof($fh));
 132          return $ret;
 133      }
 134  }
 135  
 136  // vim: et sw=4 sts=4