/** * Alter the URL to a file. * * This hook is called from file_create_url(), and is called fairly * frequently (10+ times per page), depending on how many files there are in a * given page. * If CSS and JS aggregation are disabled, this can become very frequently * (50+ times per page) so performance is critical. * * This function should alter the URI, if it wants to rewrite the file URL. * * @param $uri * The URI to a file for which we need an external URL, or the path to a * shipped file. */ function hook_file_url_alter(&$uri) { $user = \Drupal::currentUser(); // User 1 will always see the local file in this example. if ($user->id() == 1) { return; } $cdn1 = 'http://cdn1.example.com'; $cdn2 = 'http://cdn2.example.com'; $cdn_extensions = array('css', 'js', 'gif', 'jpg', 'jpeg', 'png'); // Most CDNs don't support private file transfers without a lot of hassle, // so don't support this in the common case. $schemes = array('public'); $scheme = file_uri_scheme($uri); // Only serve shipped files and public created files from the CDN. if (!$scheme || in_array($scheme, $schemes)) { // Shipped files. if (!$scheme) { $path = $uri; } else { $wrapper = file_stream_wrapper_get_instance_by_scheme($scheme); $path = $wrapper->getDirectoryPath() . '/' . file_uri_target($uri); } // Clean up Windows paths. $path = str_replace('\\', '/', $path); // Serve files with one of the CDN extensions from CDN 1, all others from // CDN 2. $pathinfo = pathinfo($path); if (isset($pathinfo['extension']) && in_array($pathinfo['extension'], $cdn_extensions)) { $uri = $cdn1 . '/' . $path; } else { $uri = $cdn2 . '/' . $path; } } }
/** * Test read-only specific behavior. */ function testReadOnlyBehavior() { // Generate a test file $filename = $this->randomMachineName(); $site_path = $this->container->get('site.path'); $filepath = $site_path . '/files/' . $filename; file_put_contents($filepath, $filename); // Generate a read-only stream wrapper instance $uri = $this->scheme . '://' . $filename; file_stream_wrapper_get_instance_by_scheme($this->scheme); // Attempt to open a file in read/write mode $handle = @fopen($uri, 'r+'); $this->assertFalse($handle, 'Unable to open a file for reading and writing with the read-only stream wrapper.'); // Attempt to open a file in binary read mode $handle = fopen($uri, 'rb'); $this->assertTrue($handle, 'Able to open a file for reading in binary mode with the read-only stream wrapper.'); $this->assertTrue(fclose($handle), 'Able to close file opened in binary mode using the read_only stream wrapper.'); // Attempt to open a file in text read mode $handle = fopen($uri, 'rt'); $this->assertTrue($handle, 'Able to open a file for reading in text mode with the read-only stream wrapper.'); $this->assertTrue(fclose($handle), 'Able to close file opened in text mode using the read_only stream wrapper.'); // Attempt to open a file in read mode $handle = fopen($uri, 'r'); $this->assertTrue($handle, 'Able to open a file for reading with the read-only stream wrapper.'); // Attempt to change file permissions $this->assertFalse(@chmod($uri, 0777), 'Unable to change file permissions when using read-only stream wrapper.'); // Attempt to acquire an exclusive lock for writing $this->assertFalse(@flock($handle, LOCK_EX | LOCK_NB), 'Unable to acquire an exclusive lock using the read-only stream wrapper.'); // Attempt to obtain a shared lock $this->assertTrue(flock($handle, LOCK_SH | LOCK_NB), 'Able to acquire a shared lock using the read-only stream wrapper.'); // Attempt to release a shared lock $this->assertTrue(flock($handle, LOCK_UN | LOCK_NB), 'Able to release a shared lock using the read-only stream wrapper.'); // Attempt to truncate the file $this->assertFalse(@ftruncate($handle, 0), 'Unable to truncate using the read-only stream wrapper.'); // Attempt to write to the file $this->assertFalse(@fwrite($handle, $this->randomMachineName()), 'Unable to write to file using the read-only stream wrapper.'); // Attempt to flush output to the file $this->assertFalse(@fflush($handle), 'Unable to flush output to file using the read-only stream wrapper.'); // Attempt to close the stream. (Suppress errors, as fclose triggers fflush.) $this->assertTrue(fclose($handle), 'Able to close file using the read_only stream wrapper.'); // Test the rename() function $this->assertFalse(@rename($uri, $this->scheme . '://newname.txt'), 'Unable to rename files using the read-only stream wrapper.'); // Test the unlink() function $this->assertTrue(@drupal_unlink($uri), 'Able to unlink file using read-only stream wrapper.'); $this->assertTrue(file_exists($filepath), 'Unlink File was not actually deleted.'); // Test the mkdir() function by attempting to create a directory. $dirname = $this->randomMachineName(); $dir = $site_path . '/files/' . $dirname; $readonlydir = $this->scheme . '://' . $dirname; $this->assertFalse(@drupal_mkdir($readonlydir, 0775, 0), 'Unable to create directory with read-only stream wrapper.'); // Create a temporary directory for testing purposes $this->assertTrue(drupal_mkdir($dir), 'Test directory created.'); // Test the rmdir() function by attempting to remove the directory. $this->assertFalse(@drupal_rmdir($readonlydir), 'Unable to delete directory with read-only stream wrapper.'); // Remove the temporary directory. drupal_rmdir($dir); }
/** * Returns an array of route objects. * * @return \Symfony\Component\Routing\Route[] * An array of route objects. */ public function routes() { $routes = array(); // Generate image derivatives of publicly available files. If clean URLs are // disabled image derivatives will always be served through the menu system. // If clean URLs are enabled and the image derivative already exists, PHP // will be bypassed. $directory_path = file_stream_wrapper_get_instance_by_scheme('public')->getDirectoryPath(); $routes['image.style_public'] = new Route('/' . $directory_path . '/styles/{image_style}/{scheme}', array('_controller' => 'Drupal\\image\\Controller\\ImageStyleDownloadController::deliver'), array('_access' => 'TRUE')); return $routes; }
/** * Test the URI and target functions. */ function testUriFunctions() { $config = \Drupal::config('system.file'); $instance = file_stream_wrapper_get_instance_by_uri($this->scheme . '://foo'); $this->assertEqual($this->classname, get_class($instance), 'Got correct class type for dummy URI.'); $instance = file_stream_wrapper_get_instance_by_uri('public://foo'); $this->assertEqual('Drupal\\Core\\StreamWrapper\\PublicStream', get_class($instance), 'Got correct class type for public URI.'); // Test file_uri_target(). $this->assertEqual(file_uri_target('public://foo/bar.txt'), 'foo/bar.txt', 'Got a valid stream target from public://foo/bar.txt.'); $this->assertFalse(file_uri_target('foo/bar.txt'), 'foo/bar.txt is not a valid stream.'); // Test file_build_uri() and // Drupal\Core\StreamWrapper\LocalStream::getDirectoryPath(). $this->assertEqual(file_build_uri('foo/bar.txt'), 'public://foo/bar.txt', 'Expected scheme was added.'); $this->assertEqual(file_stream_wrapper_get_instance_by_scheme('public')->getDirectoryPath(), PublicStream::basePath(), 'Expected default directory path was returned.'); $this->assertEqual(file_stream_wrapper_get_instance_by_scheme('temporary')->getDirectoryPath(), $config->get('path.temporary'), 'Expected temporary directory path was returned.'); $config->set('default_scheme', 'private')->save(); $this->assertEqual(file_build_uri('foo/bar.txt'), 'private://foo/bar.txt', 'Got a valid URI from foo/bar.txt.'); }
/** * Test the URI and target functions. */ function testUriFunctions() { $config = \Drupal::config('system.file'); $instance = file_stream_wrapper_get_instance_by_uri($this->scheme . '://foo'); $this->assertEqual($this->classname, get_class($instance), 'Got correct class type for dummy URI.'); $instance = file_stream_wrapper_get_instance_by_uri('public://foo'); $this->assertEqual('Drupal\\Core\\StreamWrapper\\PublicStream', get_class($instance), 'Got correct class type for public URI.'); // Test file_uri_target(). $this->assertEqual(file_uri_target('public://foo/bar.txt'), 'foo/bar.txt', 'Got a valid stream target from public://foo/bar.txt.'); $this->assertEqual(file_uri_target('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='), 'image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==', t('Got a valid stream target from a data URI.')); $this->assertFalse(file_uri_target('foo/bar.txt'), 'foo/bar.txt is not a valid stream.'); $this->assertFalse(file_uri_target('public://'), 'public:// has no target.'); $this->assertFalse(file_uri_target('data:'), 'data: has no target.'); // Test file_build_uri() and // Drupal\Core\StreamWrapper\LocalStream::getDirectoryPath(). $this->assertEqual(file_build_uri('foo/bar.txt'), 'public://foo/bar.txt', 'Expected scheme was added.'); $this->assertEqual(file_stream_wrapper_get_instance_by_scheme('public')->getDirectoryPath(), PublicStream::basePath(), 'Expected default directory path was returned.'); $this->assertEqual(file_stream_wrapper_get_instance_by_scheme('temporary')->getDirectoryPath(), $config->get('path.temporary'), 'Expected temporary directory path was returned.'); $config->set('default_scheme', 'private')->save(); $this->assertEqual(file_build_uri('foo/bar.txt'), 'private://foo/bar.txt', 'Got a valid URI from foo/bar.txt.'); }
/** * {@inheritdoc} */ public function processInbound($path, Request $request) { $directory_path = file_stream_wrapper_get_instance_by_scheme('public')->getDirectoryPath(); if (strpos($path, $directory_path . '/styles/') === 0) { $path_prefix = $directory_path . '/styles/'; } elseif (strpos($path, 'system/files/styles/') === 0) { $path_prefix = 'system/files/styles/'; } else { return $path; } // Strip out path prefix. $rest = preg_replace('|^' . $path_prefix . '|', '', $path); // Get the image style, scheme and path. if (substr_count($rest, '/') >= 2) { list($image_style, $scheme, $file) = explode('/', $rest, 3); // Set the file as query parameter. $request->query->set('file', $file); return $path_prefix . $image_style . '/' . $scheme; } else { return $path; } }
/** * Returns the full path to a directory where backups should be written. */ public function getBackupDir() { return file_stream_wrapper_get_instance_by_scheme('temporary')->getDirectoryPath(); }
/** * Test the URI and target functions. */ function testUriFunctions() { $config = $this->config('system.file'); $instance = file_stream_wrapper_get_instance_by_uri($this->scheme . '://foo'); $this->assertEqual($this->classname, get_class($instance), 'Got correct class type for dummy URI.'); $instance = file_stream_wrapper_get_instance_by_uri('public://foo'); $this->assertEqual('Drupal\\Core\\StreamWrapper\\PublicStream', get_class($instance), 'Got correct class type for public URI.'); // Test file_uri_target(). $this->assertEqual(file_uri_target('public://foo/bar.txt'), 'foo/bar.txt', 'Got a valid stream target from public://foo/bar.txt.'); $this->assertEqual(file_uri_target('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='), 'image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==', t('Got a valid stream target from a data URI.')); $this->assertFalse(file_uri_target('foo/bar.txt'), 'foo/bar.txt is not a valid stream.'); $this->assertFalse(file_uri_target('public://'), 'public:// has no target.'); $this->assertFalse(file_uri_target('data:'), 'data: has no target.'); // Test file_build_uri() and // Drupal\Core\StreamWrapper\LocalStream::getDirectoryPath(). $this->assertEqual(file_build_uri('foo/bar.txt'), 'public://foo/bar.txt', 'Expected scheme was added.'); $this->assertEqual(file_stream_wrapper_get_instance_by_scheme('public')->getDirectoryPath(), PublicStream::basePath(), 'Expected default directory path was returned.'); $this->assertEqual(file_stream_wrapper_get_instance_by_scheme('temporary')->getDirectoryPath(), $config->get('path.temporary'), 'Expected temporary directory path was returned.'); $config->set('default_scheme', 'private')->save(); $this->assertEqual(file_build_uri('foo/bar.txt'), 'private://foo/bar.txt', 'Got a valid URI from foo/bar.txt.'); // Test file_create_url() // TemporaryStream::getExternalUrl() uses Url::fromRoute(), which needs // route information to work. $this->installSchema('system', 'router'); $this->container->get('router.builder')->rebuild(); $this->assertTrue(strpos(file_create_url('temporary://test.txt'), 'system/temporary?file=test.txt'), 'Temporary external URL correctly built.'); $this->assertTrue(strpos(file_create_url('public://test.txt'), Settings::get('file_public_path') . '/test.txt'), 'Public external URL correctly built.'); $this->assertTrue(strpos(file_create_url('private://test.txt'), 'system/files/test.txt'), 'Private external URL correctly built.'); }
/** * Reset the cookie file so that it refers to the specified user. * * @param $uid User id to set as the active session. */ function sessionReset($uid = 0) { // Close the internal browser. $this->curlClose(); $this->loggedInUser = FALSE; // Change cookie file for user. $this->cookieFile = file_stream_wrapper_get_instance_by_scheme('temporary')->getDirectoryPath() . '/cookie.' . $uid . '.txt'; $this->additionalCurlOptions[CURLOPT_COOKIEFILE] = $this->cookieFile; $this->additionalCurlOptions[CURLOPT_COOKIESESSION] = TRUE; $this->drupalGet('session-test/get'); $this->assertResponse(200, 'Session test module is correctly enabled.', 'Session'); }
/** * Test file_url_transform_relative(). */ function testRelativeFileURL() { // Disable file_test.module's hook_file_url_alter() implementation. \Drupal::state()->set('file_test.hook_file_url_alter', NULL); // Create a mock Request for file_url_transform_relative(). $request = Request::create($GLOBALS['base_url']); $this->container->get('request_stack')->push($request); \Drupal::setContainer($this->container); // Shipped file. $filepath = 'core/assets/vendor/jquery/jquery.js'; $url = file_create_url($filepath); $this->assertIdentical(base_path() . $filepath, file_url_transform_relative($url)); // Managed file. $uri = $this->createUri(); $url = file_create_url($uri); $public_directory_path = file_stream_wrapper_get_instance_by_scheme('public')->getDirectoryPath(); $this->assertIdentical(base_path() . $public_directory_path . '/' . rawurlencode(drupal_basename($uri)), file_url_transform_relative($url)); }
/** * Test file_create_url(). */ function testFileCreateUrl() { // Tilde (~) is excluded from this test because it is encoded by // rawurlencode() in PHP 5.2 but not in PHP 5.3, as per RFC 3986. // @see http://www.php.net/manual/function.rawurlencode.php#86506 $basename = " -._!\$'\"()*@[]?&+%#,;=:\n" . "%23%25%26%2B%2F%3F" . "éøïвβ中國書۞"; // Characters from various non-ASCII alphabets. $basename_encoded = '%20-._%21%24%27%22%28%29%2A%40%5B%5D%3F%26%2B%25%23%2C%3B%3D%3A__' . '%2523%2525%2526%252B%252F%253F' . '%C3%A9%C3%B8%C3%AF%D0%B2%CE%B2%E4%B8%AD%E5%9C%8B%E6%9B%B8%DB%9E'; // Public files should not be served by Drupal, so their URLs should not be // generated by url(), whereas private files should be served by Drupal, so // their URLs should be generated by url(). The difference is most apparent // when $script_path is not empty (i.e., when not using clean URLs). $clean_url_settings = array('clean' => '', 'unclean' => 'index.php/'); foreach ($clean_url_settings as $clean_url_setting => $script_path) { $clean_urls = $clean_url_setting == 'clean'; $request = $this->prepareRequestForGenerator($clean_urls); $base_path = $request->getSchemeAndHttpHost() . $request->getBasePath(); $this->checkUrl('public', '', $basename, $base_path . '/' . file_stream_wrapper_get_instance_by_scheme('public')->getDirectoryPath() . '/' . $basename_encoded); $this->checkUrl('private', '', $basename, $base_path . '/' . $script_path . 'system/files/' . $basename_encoded); } }
/** * Test file_create_url(). */ function testFileCreateUrl() { // Tilde (~) is excluded from this test because it is encoded by // rawurlencode() in PHP 5.2 but not in PHP 5.3, as per RFC 3986. // @see http://www.php.net/manual/function.rawurlencode.php#86506 $basename = " -._!\$'\"()*@[]?&+%#,;=:\n" . "%23%25%26%2B%2F%3F" . "éøïвβ中國書۞"; // Characters from various non-ASCII alphabets. $basename_encoded = '%20-._%21%24%27%22%28%29%2A%40%5B%5D%3F%26%2B%25%23%2C%3B%3D%3A__' . '%2523%2525%2526%252B%252F%253F' . '%C3%A9%C3%B8%C3%AF%D0%B2%CE%B2%E4%B8%AD%E5%9C%8B%E6%9B%B8%DB%9E'; // Public files should not be served by Drupal, so their URLs should not be // routed through Drupal, whereas private files should be served by Drupal, // so they need to be. The difference is most apparent when $script_path // is not empty (i.e., when not using clean URLs). $clean_url_settings = array('clean' => '', 'unclean' => 'index.php/'); foreach ($clean_url_settings as $clean_url_setting => $script_path) { $clean_urls = $clean_url_setting == 'clean'; $request = $this->prepareRequestForGenerator($clean_urls); $base_path = $request->getSchemeAndHttpHost() . $request->getBasePath(); $this->checkUrl('public', '', $basename, $base_path . '/' . file_stream_wrapper_get_instance_by_scheme('public')->getDirectoryPath() . '/' . $basename_encoded); $this->checkUrl('private', '', $basename, $base_path . '/' . $script_path . 'system/files/' . $basename_encoded); } $this->assertEqual(file_create_url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='), 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==', t('Generated URL matches expected URL.')); }