From 4232ce1b6e59f8279968d3e157e86f472232d75d Mon Sep 17 00:00:00 2001 From: Daniel Thee Roperto Date: Thu, 10 Nov 2016 15:03:07 +1100 Subject: [PATCH] Issue #22 - Auto-detect mime types. --- .../controllers/maintenance_static_page.php | 56 +++++++++++++------ file.php | 11 +++- .../maintenance_static_page_test.php | 22 ++++++++ 3 files changed, 70 insertions(+), 19 deletions(-) diff --git a/classes/local/controllers/maintenance_static_page.php b/classes/local/controllers/maintenance_static_page.php index ad5b2e4..55ae182 100644 --- a/classes/local/controllers/maintenance_static_page.php +++ b/classes/local/controllers/maintenance_static_page.php @@ -28,6 +28,7 @@ namespace auth_outage\local\controllers; use auth_outage\local\outage; use coding_exception; use DOMDocument; +use finfo; use invalid_parameter_exception; use invalid_state_exception; use moodle_url; @@ -61,7 +62,8 @@ class maintenance_static_page { } else if (PHPUNIT_TEST) { $html = ''; } else { - $html = self::file_get_contents($CFG->wwwroot.'/auth/outage/info.php?auth_outage_hide_warning=1&id='.$outage->id); + $data = self::file_get_data($CFG->wwwroot.'/auth/outage/info.php?auth_outage_hide_warning=1&id='.$outage->id); + $html = $data['contents']; } return self::create_from_html($html); @@ -97,13 +99,33 @@ class maintenance_static_page { * @param string $file File to get. * @return string Contents of $file or an empty string if failed. */ - private static function file_get_contents($file) { - $contents = @file_get_contents($file); + private static function file_get_data($file) { + if (self::is_url($file)) { + $curl = curl_init(); + curl_setopt($curl, CURLOPT_URL, $file); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + $contents = curl_exec($curl); + $mime = curl_getinfo($curl, CURLINFO_CONTENT_TYPE); + curl_close($curl); + } else { + $contents = @file_get_contents($file); + $mime = (new finfo(FILEINFO_MIME_TYPE))->buffer($contents); // Not perfect, but try guessing it. + } if ($contents === false) { debugging('Cannot fetch: '.$file); - return ''; // Better a broken link than halting the generation. + $contents = ''; + $mime = 'unknown'; } - return $contents; + return ['contents' => $contents, 'mime' => $mime]; + } + + /** + * Checks if the given string starts with "http://" or "https://". + * @param $url + * @return bool + */ + private static function is_url($url) { + return (bool)preg_match('#^http(s)?://#', $url); } /** @var DOMDocument */ @@ -269,7 +291,7 @@ class maintenance_static_page { if (($rel != 'stylesheet') || ($href == '')) { continue; } - $filename = $this->save_url_file($href, 'css'); + $filename = $this->save_url_file($href); if (is_null($filename)) { $url = $href; // Skipped, use original URL. } else { @@ -299,7 +321,7 @@ class maintenance_static_page { if (($rel != 'shortcut icon') || ($href == '')) { continue; } - $link->setAttribute('href', $this->generate_file_url($href, 'png')); // Works for most image formats. + $link->setAttribute('href', $this->generate_file_url($href)); // Works for most image formats. } } @@ -314,18 +336,17 @@ class maintenance_static_page { if ($src == '') { continue; } - $link->setAttribute('src', $this->generate_file_url($src, 'png')); // Works for most image formats. + $link->setAttribute('src', $this->generate_file_url($src)); // Works for most image formats. } } /** * Saves the content of the URL into a file, returning the new URL. * @param string $url Input URL. - * @param string $type Type of file. * @return string Output URL. */ - private function generate_file_url($url, $type) { - $filename = $this->save_url_file($url, $type); + private function generate_file_url($url) { + $filename = $this->save_url_file($url); if (is_null($filename)) { return $url; // Skipped, use original URL. } @@ -344,13 +365,12 @@ class maintenance_static_page { /** * Saves the content of the URL into a file, returning the local filename. * @param string $url Input URL. - * @param string $type Type of file. * @return string|null Output filename or null if skipped. */ - private function save_url_file($url, $type) { + private function save_url_file($url) { global $CFG; - if (!preg_match('#^http(s)?://#', $url)) { + if (!self::is_url($url)) { debugging('Found a relative url ('.$url.') -- is it using moodle_url()?'); return null; // Leave hardcoded URLs as it is. } @@ -364,10 +384,12 @@ class maintenance_static_page { $url = str_replace($CFG->wwwroot, $CFG->dirroot, $url); } - $contents = self::file_get_contents($url); - $filename = sha1($contents).'.'.$type; + $data = self::file_get_data($url); + + $mime = trim(base64_encode($data['mime']), '='); + $filename = sha1($data['contents']).'.'.$mime; $filepath = $this->get_resources_folder().'/'.$filename; - file_put_contents($filepath, $contents); + file_put_contents($filepath, $data['contents']); if ($this->preview) { $filename = 'preview/'.$filename; diff --git a/file.php b/file.php index b12ec9e..725640c 100644 --- a/file.php +++ b/file.php @@ -28,13 +28,20 @@ */ // File should have at least 3 characters as we will check the extension below. -if (!isset($_GET['file']) || (strlen($_GET['file']) < 3)) { +if (!isset($_GET['file'])) { http_response_code(400); die('Missing file parameter.'); } +$parts = explode('.', $_GET['file']); +if (count($parts) != 2) { + http_response_code(400); + die('Invalid file requested.'); +} +$mime = base64_decode($parts[1]); + // Detect type, we only support css or PNG images. -header('Content-Type: '.(substr($_GET['file'], -3) == 'css' ? 'text/css' : 'image/png')); +header('Content-Type: '.$mime); // Use cache. $lifetime = 60 * 60 * 24; // 1 day. diff --git a/tests/phpunit/local/controllers/maintenance_static_page_test.php b/tests/phpunit/local/controllers/maintenance_static_page_test.php index 9d3f9ce..61255c8 100644 --- a/tests/phpunit/local/controllers/maintenance_static_page_test.php +++ b/tests/phpunit/local/controllers/maintenance_static_page_test.php @@ -159,6 +159,28 @@ class maintenance_static_page_test extends auth_outage_base_testcase { self::assertFileNotExists($file); } + public function test_createdfile() { + global $CFG; + + $link = $this->get_fixture_path('catalyst.png'); + $html = "\n". + 'Title'. + 'Content'; + $page = maintenance_static_page::create_from_html($html); + $page->set_preview(true); + $page->generate(); + $generated = trim(file_get_contents($page->get_template_file())); + + // This checks if content is correct and mime type is correct from the encoded name. + $file = $page->get_resources_folder().'/ff7f7f87a26a908fc72930eaefb6b57306361d16.aW1hZ2UvcG5n'; + self::assertFileExists($file); + + // We can still assert the contents really match, not just the hash. + $found = file_get_contents($file); + $expected = file_get_contents($CFG->dirroot.'/auth/outage/tests/phpunit/local/controllers/fixtures/catalyst.png'); + self::assertSame($found, $expected); + } + /** * Gets a fixture file for this test case. * @param $file