Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.
   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  namespace tool_brickfield\local\htmlchecker\reporters;
  18  
  19  use tool_brickfield\local\htmlchecker\brickfield_accessibility;
  20  use tool_brickfield\local\htmlchecker\brickfield_accessibility_reporter;
  21  
  22  /**
  23   * Returns the entire document marked-up to highlight problems.
  24   *
  25   * @package    tool_brickfield
  26   * @copyright  2020 onward: Brickfield Education Labs, www.brickfield.ie
  27   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  28   */
  29  class report_demo extends brickfield_accessibility_reporter {
  30  
  31      /**
  32       * @var array An array of the classnames to be associated with items
  33       */
  34      public $classnames = [
  35          brickfield_accessibility::BA_TEST_SEVERE => 'testlevel_severe',
  36          brickfield_accessibility::BA_TEST_MODERATE => 'testlevel_moderate',
  37          brickfield_accessibility::BA_TEST_SUGGESTION => 'testlevel_suggestion',
  38      ];
  39  
  40      /**
  41       * The get_report method - we iterate through every test item and
  42       * add additional attributes to build the report UI.
  43       * @return string A fully-formed HTML document.
  44       */
  45      public function get_report(): string {
  46          $problems = $this->guideline->get_report();
  47          if (is_array($problems)) {
  48              foreach ($problems as $testname => $test) {
  49                  if (!isset($this->options->display_level) ||
  50                      ($this->options->display_level >= $test['severity'] && is_array($test))) {
  51                      foreach ($test as $problem) {
  52                          if (is_object($problem) && property_exists($problem, 'element') && is_object($problem->element)) {
  53                              $existing = $problem->element->getAttribute('style');
  54                              $problem->element->setAttribute('style',
  55                                  $existing .'; border: 2px solid red;');
  56                              if (isset($this->options->image_url)) {
  57                                  $image = $this->dom->createElement('img');
  58                                  $image = $problem->element->parentNode->insertBefore($image, $problem->element);
  59                                  $image->setAttribute('alt', $testname);
  60                                  if ($problem->message) {
  61                                      $image->setAttribute('title', $problem->message);
  62                                  }
  63                                  $image->setAttribute('src', $this->options->image_url[$test['severity']]);
  64                              }
  65                          }
  66                      }
  67                  }
  68              }
  69          }
  70          return $this->complete_urls($this->dom->saveHTML(), implode('/', $this->path));
  71      }
  72  
  73  
  74      /**
  75       * Finds the final postion of a needle in the haystack.
  76       *
  77       * @param mixed $haystack
  78       * @param mixed $needle
  79       * @param mixed $occurance
  80       * @param int $pos
  81       * @return false|int
  82       */
  83      public function strnpos($haystack, $needle, $occurance, int $pos = 0) {
  84          for ($i = 1; $i <= $occurance; $i++) {
  85              $pos = strpos($haystack, $needle, $pos) + 1;
  86          }
  87          return $pos - 1;
  88      }
  89  
  90      /**
  91       * A helper function for completeURLs. Parses a URL into an the scheme, host, and path
  92       * @param string $url The URL to parse
  93       * @return array An array that includes the scheme, host, and path of the URL
  94       */
  95      public function parse_url(string $url): array {
  96          $pattern = "/^(?:(http[s]?):\/\/(?:(.*):(.*)@)?([^\/]+))?((?:[\/])?(?:[^\.]*?)?(?:[\/])?)?(?:([^\/^\.]+)\." .
  97              "([^\?]+))?(?:\?(.+))?$/i";
  98          preg_match($pattern, $url, $matches);
  99  
 100          $uriparts["scheme"] = $matches[1];
 101          $uriparts["host"] = $matches[4];
 102          $uriparts["path"] = $matches[5];
 103  
 104          return $uriparts;
 105      }
 106  
 107      /**
 108       * Turns all relative links to absolute links so that the page can be rendered correctly.
 109       * @param string $html A complete HTML document
 110       * @param string $url The absolute URL to the document
 111       * @return string A HTML document with all the relative links converted to absolute links
 112       */
 113      public function complete_urls(string $html, string $url) {
 114          $uriparts = $this->parse_url($url);
 115          $path = trim($uriparts["path"], "/");
 116          $hosturl = trim($uriparts["host"], "/");
 117  
 118          $host = $uriparts["scheme"]."://".$hosturl."/".$path."/";
 119          $hostnopath = $uriparts["scheme"]."://".$hosturl."/";
 120  
 121          // Proxifies local META redirects.
 122          $html = preg_replace('@<META HTTP-EQUIV(.*)URL=/@',
 123              "<META HTTP-EQUIV\$1URL=".$_SERVER['PHP_SELF']."?url=".$hostnopath, $html);
 124  
 125          // Make sure the host doesn't end in '//'.
 126          $host = rtrim($host, '/')."/";
 127  
 128          // Replace '//' with 'http://'.
 129          $pattern = "#(?<=\"|'|=)\/\/#"; // The '|=' is experimental as it's probably not necessary.
 130          $html = preg_replace($pattern, "http://", $html);
 131  
 132          // Fully qualifies '"/'.
 133          $html = preg_replace("#\"\/#", "\"".$host, $html);
 134  
 135          // Fully qualifies "'/".
 136          $html = preg_replace("#\'\/#", "\'".$host, $html);
 137  
 138          // Matches [src|href|background|action]="/ because in the following pattern the '/' shouldn't stay.
 139          $html = preg_replace("#(src|href|background|action)(=\"|='|=(?!'|\"))\/#i", "\$1\$2".$hostnopath, $html);
 140          $html = preg_replace("#(href|src|background|action)(=\"|=(?!'|\")|=')(?!http|ftp|https|\"|'|javascript:|mailto:)#i",
 141              "\$1\$2".$host, $html);
 142  
 143          // Points all form actions back to the proxy.
 144          $html = preg_replace('/<form.+?action=\s*(["\']?)([^>\s"\']+)\\1[^>]*>/i',
 145              "<form action=\"{$_SERVER['PHP_SELF']}\"><input type=\"hidden\" name=\"original_url\" value=\"$2\">", $html);
 146  
 147          // Matches '/[any assortment of chars or nums]/../'.
 148          $html = preg_replace("#\/(\w*?)\/\.\.\/(.*?)>#ims", "/\$2>", $html);
 149  
 150          // Matches '/./'.
 151          $html = preg_replace("#\/\.\/(.*?)>#ims", "/\$1>", $html);
 152  
 153          // Handles CSS2 imports.
 154          if (strpos($html, "import url(\"http") == false && (strpos($html, "import \"http") == false)
 155              && strpos($html, "import url(\"www") == false && (strpos($html, "import \"www") == false)) {
 156              $pattern = "#import .(.*?).;#ims";
 157              $mainurl = substr($host, 0, $this->strnpos($host, "/", 3));
 158              $replace = "import '".$mainurl."\$1';";
 159              $html = preg_replace($pattern, $replace, $html);
 160          }
 161          return $html;
 162      }
 163  }