Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
project
drupal
Commits
feb48454
Commit
feb48454
authored
Aug 29, 2009
by
Dries Buytaert
Browse files
- Patch
#499156
by Wim Leers: add hook_file_alter() so we can integrate with CDNs.
parent
0597c9e4
Changes
4
Hide whitespace changes
Inline
Side-by-side
includes/file.inc
View file @
feb48454
...
...
@@ -285,13 +285,23 @@ function file_stream_wrapper_get_instance_by_scheme($scheme) {
}
/**
* Creates
the
web
accessible URL
to
a stream.
* Creates
a
web
-
accessible URL
for
a stream
to an external or local file
.
*
* Compatibility: normal paths and stream wrappers.
* @see http://drupal.org/node/515192
*
* There are two kinds of local files:
* - "created files", i.e. those in the files directory (which is stored in
* the file_directory_path variable and can be retrieved using
* file_directory_path()). These are files that have either been uploaded by
* users or were generated automatically (for example through CSS
* aggregation).
* - "shipped files", i.e. those outside of the files directory, which ship as
* part of Drupal core or contributed modules or themes.
*
* @param $uri
* The URI to for which we need an external URL.
* The URI to a file for which we need an external URL, or the path to a
* shipped file.
* @return
* A string containing a URL that may be used to access the file.
* If the provided string already contains a preceding 'http', nothing is done
...
...
@@ -299,11 +309,15 @@ function file_stream_wrapper_get_instance_by_scheme($scheme) {
* found to generate an external URL, then FALSE will be returned.
*/
function
file_create_url
(
$uri
)
{
// Allow the URI to be altered, e.g. to serve a file from a CDN or static
// file server.
drupal_alter
(
'file_url'
,
$uri
);
$scheme
=
file_uri_scheme
(
$uri
);
if
(
!
$scheme
)
{
// If this is not a properly formatted stream
return the URI with the base
//
url
prepended.
// If this is not a properly formatted stream
, then it is a shipped file.
//
Therefor, return the URI with the base URL
prepended.
return
$GLOBALS
[
'base_url'
]
.
'/'
.
$uri
;
}
elseif
(
$scheme
==
'http'
||
$scheme
==
'https'
)
{
...
...
@@ -320,9 +334,6 @@ function file_create_url($uri) {
return
FALSE
;
}
}
// @todo Implement CDN integration hook stuff in this function.
// @see http://drupal.org/node/499156
}
/**
...
...
modules/simpletest/tests/file.test
View file @
feb48454
...
...
@@ -1878,6 +1878,26 @@ class FileDownloadTest extends FileTestCase {
parent
::
setUp
(
'file_test'
);
}
/**
* Test the public file transfer system.
*/
function
testPublicFileTransfer
()
{
// Test generating an URL to a created file.
$file
=
$this
->
createFile
();
$url
=
file_create_url
(
$file
->
uri
);
$this
->
assertEqual
(
$GLOBALS
[
'base_url'
]
.
'/'
.
file_directory_path
()
.
'/'
.
$file
->
filename
,
$url
,
t
(
'Correctly generated a URL for a created file.'
));
$this
->
drupalHead
(
$url
);
$this
->
assertResponse
(
200
,
t
(
'Confirmed that the generated URL is correct by downloading the created file.'
));
// Test generating an URL to a shipped file (i.e. a file that is part of
// Drupal core, a module or a theme, for example a JavaScript file).
$filepath
=
'misc/jquery.js'
;
$url
=
file_create_url
(
$filepath
);
$this
->
assertEqual
(
$GLOBALS
[
'base_url'
]
.
'/'
.
$filepath
,
$url
,
t
(
'Correctly generated a URL for a shipped file.'
));
$this
->
drupalHead
(
$url
);
$this
->
assertResponse
(
200
,
t
(
'Confirmed that the generated URL is correct by downloading the shipped file.'
));
}
/**
* Test the private file transfer system.
*/
...
...
@@ -1907,6 +1927,48 @@ class FileDownloadTest extends FileTestCase {
}
}
/**
* Tests for file URL rewriting.
*/
class
FileURLRewritingTest
extends
FileTestCase
{
public
static
function
getInfo
()
{
return
array
(
'name'
=>
t
(
'File URL rewriting'
),
'description'
=>
t
(
'Tests for file URL rewriting.'
),
'group'
=>
t
(
'File'
),
);
}
function
setUp
()
{
parent
::
setUp
(
'file_test'
);
variable_set
(
'file_test_hook_file_url_alter'
,
TRUE
);
}
/**
* Test the generating of rewritten shipped file URLs.
*/
function
testShippedFileURL
()
{
// Test generating an URL to a shipped file (i.e. a file that is part of
// Drupal core, a module or a theme, for example a JavaScript file).
$filepath
=
'misc/jquery.js'
;
$url
=
file_create_url
(
$filepath
);
$this
->
assertEqual
(
FILE_URL_TEST_CDN_1
.
'/'
.
$filepath
,
$url
,
t
(
'Correctly generated a URL for a shipped file.'
));
$filepath
=
'misc/favicon.ico'
;
$url
=
file_create_url
(
$filepath
);
$this
->
assertEqual
(
FILE_URL_TEST_CDN_2
.
'/'
.
$filepath
,
$url
,
t
(
'Correctly generated a URL for a shipped file.'
));
}
/**
* Test the generating of rewritten public created file URLs.
*/
function
testPublicCreatedFileURL
()
{
// Test generating an URL to a created file.
$file
=
$this
->
createFile
();
$url
=
file_create_url
(
$file
->
uri
);
$this
->
assertEqual
(
FILE_URL_TEST_CDN_2
.
'/'
.
file_directory_path
()
.
'/'
.
$file
->
filename
,
$url
,
t
(
'Correctly generated a URL for a created file.'
));
}
}
/**
* Tests for file_munge_filename() and file_unmunge_filename().
*/
...
...
modules/simpletest/tests/file_test.module
View file @
feb48454
...
...
@@ -9,6 +9,11 @@
* calling file_test_get_calls() or file_test_set_return().
*/
define
(
'FILE_URL_TEST_CDN_1'
,
'http://cdn1.example.com'
);
define
(
'FILE_URL_TEST_CDN_2'
,
'http://cdn2.example.com'
);
/**
* Implement hook_menu().
*/
...
...
@@ -264,6 +269,51 @@ function file_test_file_delete($file) {
_file_test_log_call
(
'delete'
,
array
(
$file
));
}
/**
* Implement hook_file_url_alter().
*/
function
file_test_file_url_alter
(
&
$uri
)
{
// Only run this hook when this variable is set. Otherwise, we'd have to add
// another hidden test module just for this hook.
if
(
!
variable_get
(
'file_test_hook_file_url_alter'
,
FALSE
))
{
return
;
}
$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
;
}
// Public created files.
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
(
array_key_exists
(
'extension'
,
$pathinfo
)
&&
in_array
(
$pathinfo
[
'extension'
],
$cdn_extensions
))
{
$uri
=
FILE_URL_TEST_CDN_1
.
'/'
.
$path
;
}
else
{
$uri
=
FILE_URL_TEST_CDN_2
.
'/'
.
$path
;
}
}
}
/**
* Helper class for testing the stream wrapper registry.
*
...
...
modules/system/system.api.php
View file @
feb48454
...
...
@@ -1449,6 +1449,67 @@ function hook_file_download($filepath) {
}
/**
* 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.
* If it does so, no other hook_file_url_alter() implementation will be
* allowed to further alter the path.
*
* @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
)
{
global
$user
;
// User 1 will always see the local file in this example.
if
(
$user
->
uid
==
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
;
}
// Public created files.
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
(
array_key_exists
(
'extension'
,
$pathinfo
)
&&
in_array
(
$pathinfo
[
'extension'
],
$cdn_extensions
))
{
$uri
=
$cdn1
.
'/'
.
$path
;
}
else
{
$uri
=
$cdn2
.
'/'
.
$path
;
}
}
}
/**
* Check installation requirements and do status reporting.
*
* This hook has two closely related uses, determined by the $phase argument:
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment