diff --git a/classes/local/controllers/maintenance_static_page_generator.php b/classes/local/controllers/maintenance_static_page_generator.php index 75abc12..5d7dcd2 100644 --- a/classes/local/controllers/maintenance_static_page_generator.php +++ b/classes/local/controllers/maintenance_static_page_generator.php @@ -83,6 +83,7 @@ public function generate() { $this->update_link_favicon(); $this->update_images(); $this->remove_configured_css_selectors(); + $this->update_inline_background_images(); $html = $this->dom->saveHTML(); if (trim($html) == '') { @@ -150,6 +151,27 @@ public function get_urls_from_stylesheet($contents) { return $matches; } + /** + * Retrieves a URL from inline style using regular expressions. + * + * @param string $style Content of the style attribute + * @param string &$pattern Pattern used for matching URL + * @return array Array containing match + */ + public function get_url_from_inline_style($style, &$pattern) { + /* + * The pattern should match the attribute values that + * go as 'url(xxxxx)', but make sure 'url(data:xxxxx)' is not + * rewritten. Must be case insensitive to match 'URL(xxxxx)'. + * It should be possible to specify other background attributes as + * 'background: color url(xxxxx) no-repeat'. + */ + $pattern = '/url\s*\(\s*[\'"]?(?![\'"]?data:)([^\s\'"]+)[\'"]?\s*\)/i'; + preg_match($pattern, $style, $match); + return $match; + } + + /** * Checks for urls inside filename. * @@ -218,6 +240,31 @@ private function update_images() { } } + /** + * Fetch and fixes all inline background images. + */ + private function update_inline_background_images() { + global $CFG; + $xpath = new \DOMXPath($this->dom); + $elements = $xpath->query("//*[@style]"); + + foreach ($elements as $element) { + $style = $element->getAttribute("style"); + $matches = $this->get_url_from_inline_style($style, $pattern); + if (isset($matches[1])) { + // Allow incomplete URLs in style, assume it is from moodle root. + if (maintenance_static_page_io::is_url($matches[1])) { + $fullurl = $matches[1]; + } else { + $fullurl = (string) new moodle_url($matches[1]); + } + $newurl = $this->io->generate_file_url($fullurl); + $updated = preg_replace($pattern, ' url('.$newurl.') ', $style); + $element->setAttribute('style', $updated); + } + } + } + /** * Remove from DOM the CSS selectores defined in the plugin settings. */ diff --git a/tests/phpunit/local/controllers/maintenance_static_page_test.php b/tests/phpunit/local/controllers/maintenance_static_page_test.php index 8922dce..ecdbed4 100644 --- a/tests/phpunit/local/controllers/maintenance_static_page_test.php +++ b/tests/phpunit/local/controllers/maintenance_static_page_test.php @@ -193,6 +193,60 @@ public function test_updatelinkfavicon() { self::assertStringContainsString('www.example.com/moodle/auth/outage/file.php?file=', $generated); } + + /** + * Data provider for test_update_inline_background_images + * @return array + */ + public function test_update_inline_background_images_provider() { + return [ + // Empty string. + ["", false], + // URLs that should be retrieved. + ["color: #FF00FF; background: lightblue url(/pluginfile.php/1/theme_custom/banner/251298630/0001.png) no-repeat", true], + ["background: lightblue url(https://www.example.com/moodle/pluginfile.php/1/theme_custom/banner/251298630/0001.png) no-repeat", true], + ["background:url('https://www.example.com/moodle/pluginfile.php/1/theme_custom/banner/251298630/0001.png')", true], + ["background-image : url( /pix/help.png);", true], + ["background-image: url ('/pix/help.png')", true], + // URLs that should not be retrieved. + ["background-image:url(data:image/gif;base64,R0lGODlhYADIAP=)", false], + ["background-image:url('data:image/gif;base64,R0lGODlhYADIAP=')", false] + ]; + } + + /** + * Tests update_inline_background_images() method to update the background images. + * + * @dataProvider test_update_inline_background_images_provider + * @param string $stylecontent Content of the style to test + * @param bool $rewrite Flag if URL should be rewritten + * @throws coding_exception + */ + public function test_update_inline_background_images($stylecontent, $rewrite) { + global $CFG; + $this->resetAfterTest(true); + $generator = new maintenance_static_page_generator(new DOMDocument(), new maintenance_static_page_io()); + + $html = '\n'. + 'Title'. + '
Content
'; + + // Temporarily disable debugging to prevent errors because file does not exist + $debuglevel = $CFG->debug; + $CFG->debug = ''; + $generated = $this->generated_page_html($html); + // Restore debugging level + $CFG->debug = $debuglevel; + $matches = $generator->get_url_from_inline_style($stylecontent, $pattern); + if ($rewrite) { + self::assertStringNotContainsString($matches[1], $generated); + self::assertStringContainsString('www.example.com/moodle/auth/outage/file.php?file=', $generated); + self::assertIsArray($matches); + } else { + self::assertStringContainsString($stylecontent, $generated); + } + } + /** * Test update preview path to file.php style link. */