| 1 |
// $Id: README.txt,v 1.17 2008/02/17 20:19:01 wimleers Exp $ |
$Id$ |
| 2 |
|
|
| 3 |
Description |
Description |
| 4 |
----------- |
----------- |
| 5 |
The aim of this module to provide easy Content Delivery Network integration |
The aim of this module to provide easy Content Delivery Network integration |
| 6 |
for Drupal sites. Obviously it has to patch Drupal core to rewrite the URLs, |
for Drupal sites. Obviously it has to patch Drupal core to rewrite the URLs. |
| 7 |
not only to serve them from another domain, but also to make the filenames |
URLs must be rewritten to be able to actually serve the files from a CDN. |
|
unique. |
|
| 8 |
|
|
| 9 |
It has synchronization plugins, so it allows you to use any protocol or |
It provides two modes: basic and advanced. |
|
algorithm to synchronize your files. Currently however, only one plugin is |
|
|
available: FTP. Since proper usage of a CDN demands unique filenames for each |
|
|
version of a file, we can optimize a lot: to validate a file on the CDN while |
|
|
synchronizing, we must only know if it 1) exists and 2) has the correct size. |
|
| 10 |
|
|
| 11 |
Which files and directories should be synchronized can be configured very |
In basic mode, only "Origin Pull" CDNs are supported. These are CDNs that only |
| 12 |
precisely. Consult the README for details about that. |
require you to replace the domain name (and possibly base path) with another |
| 13 |
|
domain name. The CDN will then automatically fetch (pull) the files from your |
| 14 |
The FTP synchronization plugin allows you to use a $15 per month CDN (thus |
server (the origin). |
| 15 |
making CDNs accessible to /a lot/ of Drupal users) with no effort after the |
|
| 16 |
installation! |
In advanced mode, you must install and configure the daemon I wrote as part of |
| 17 |
For those who know of the infamous YSlow test: if you install and configure |
my bachelor thesis. This allows for much more advanced setups: files can be |
| 18 |
this module and apply the core patch that also adds Javascript aggregation, |
processed before they are synced and your CDN doesn't *have* to support |
| 19 |
you will score 98. Almost the maximum! The remainder of points is due to the |
Origin Pull, any push method is fine. Push always uses transfer protocols, |
| 20 |
lack Javascript minification (compression). |
either well-established ones (e.g. FTP) or custom ones (e.g. Amazon S3). It is |
| 21 |
|
thanks to this abstraction layer that it can be used for *any* CDN, thereby |
| 22 |
This module was developed for http://driverpacks.net/. |
avoiding vendor lock-in. |
| 23 |
|
|
| 24 |
|
This module was written as part of the bachelor thesis [1] of Wim Leers at |
| 25 |
Aren't CDN's so expensive only big companies can afford them? |
Hasselt University [3]. |
| 26 |
------------------------------------------------------------- |
|
| 27 |
Not anymore (in order of best price-value ratio): |
[1] http://wimleers.com/tags/bachelor-thesis |
| 28 |
|
[2] http://uhasselt.be/ |
| 29 |
1) CacheFly, http://cachefly.com/, starts at USD 15 for 30 GB per month |
|
| 30 |
|
|
| 31 |
2) Influxis, http://influxis.com/, starts at USD 10 for 1 GB per month |
Supported CDNs |
| 32 |
|
-------------- |
| 33 |
|
- Basic mode: any Origin Pull CDN. |
| 34 |
|
- Advanced mode: any Origin Pull CDN and any push CDN that supports FTP. |
| 35 |
|
Support for other transfer protocols is welcomed and encouraged: your |
| 36 |
|
patches are welcome! Amazon S3 and Amazon CloudFront are also supported. |
| 37 |
|
|
| 38 |
|
|
| 39 |
Installation |
Installation |
| 40 |
------------ |
------------ |
| 41 |
1) Place this module in your modules directory (this will usually be |
1) Apply the Drupal core patch (patches/drupal6.patch). Instructions can be |
| 42 |
"sites/all/modules/"). |
found at http://drupal.org/patch/apply. |
|
|
|
|
2) Enable the module. |
|
| 43 |
|
|
| 44 |
3) Apply the Drupal core patch. See below. |
2) Place this module directory in your "modules" folder (this will usually be |
| 45 |
|
"sites/all/modules/"). Don't install your module in Drupal core's "modules" |
| 46 |
|
folder, since that will cause problems and is bad practice in general. If |
| 47 |
|
"sites/all/modules" doesn't exist yet, just create it. |
| 48 |
|
|
| 49 |
|
3) Enable the module. |
| 50 |
|
|
| 51 |
|
4) Visit "admin/settings/cdn" to learn about the various settings. |
| 52 |
|
|
| 53 |
|
5) If you want to use advanced mode, install and configure the daemon first. |
| 54 |
|
You can install it by performing an svn checkout from |
| 55 |
|
svn://wimleers.com/school/bachelor-thesis/code/daemon |
| 56 |
|
Then follow the instructions in the included INSTALL.txt and README.txt. |
| 57 |
|
Use the config.xml file that is included in this module and modify it to |
| 58 |
|
comply with your setup and to suit your needs. |
| 59 |
|
|
| 60 |
|
6) Go to admin/reports/status. The CDN integration module will report its |
| 61 |
|
status here. If you've enabled advanced mode and have set up the daemon, |
| 62 |
|
you will see some basic stats here as well, and you can check here to see |
| 63 |
|
if the daemon is currently running. |
| 64 |
|
|
| 65 |
|
|
| 66 |
|
When using multiple servers: picking a specific one based on some criteria |
| 67 |
|
-------------------------------------------------------------------------- |
| 68 |
|
For this purpose, you can implement the cdn_advanced_pick_server() function: |
| 69 |
|
/** |
| 70 |
|
* Implementation of cdn_advanced_pick_server(). |
| 71 |
|
*/ |
| 72 |
|
function cdn_advanced_pick_server($servers_for_file) { |
| 73 |
|
// The data that you get - one nested array per server from which the file |
| 74 |
|
// can be served: |
| 75 |
|
// $servers_for_file[0] = array('url' => 'http://cdn1.com/image.jpg', 'server' => 'cdn1.com') |
| 76 |
|
// $servers_for_file[1] = array('url' => 'http://cdn2.net/image.jpg', 'server' => 'cdn2.net') |
| 77 |
|
|
| 78 |
|
$which = your_logic_to_pick_a_server(); |
| 79 |
|
|
| 80 |
|
// Return one of the nested arrays. |
| 81 |
|
return $servers_for_file[$which]; |
| 82 |
|
} |
| 83 |
|
|
| 84 |
|
So to get the default behavior (pick the first server found), one would write: |
| 85 |
|
/** |
| 86 |
|
* Implementation of cdn_advanced_pick_server(). |
| 87 |
|
*/ |
| 88 |
|
function cdn_advanced_pick_server($servers_for_file) { |
| 89 |
|
return $servers_for_file[0]; |
| 90 |
|
} |
| 91 |
|
|
| 92 |
|
|
| 93 |
|
Supporting the CDN integration module in your modules |
| 94 |
|
----------------------------------------------------- |
| 95 |
|
It's very easy to support the CDN integration module in your module. Simply |
| 96 |
|
create a variable function, e.g.: |
| 97 |
|
$file_create_url = (module_exists('cdn')) ? 'file_create_url' : 'url'; |
| 98 |
|
|
| 99 |
4) Apply the theme patch to every theme. See below. |
Then create all file URLs using this variable function. E.g. |
| 100 |
|
$file_url = $file_create_url(drupal_get_path('module', 'episodes') .'/lib/episodes.js'); |
|
5) Read how to configure the CDN synchronization filters. See below. |
|
|
|
|
|
6) Configure the $conf array in settings.php See below. |
|
|
|
|
|
7) Copy cdn_cron.php to your Drupal root directory. |
|
|
|
|
|
8) Configure cdn_cron.php like Drupal's cron.php. See http://drupal.org/cron. |
|
|
|
|
|
9) Go to admin/logs/status. If the CDN integration module is installed |
|
|
correctly or not, it will report so here. |
|
|
|
|
|
|
|
|
Usage |
|
|
----- |
|
|
When the module is installed properly (see step 9 of the installation), you |
|
|
can check the site-wide statistics at admin/settings/cdn. At that same page, |
|
|
you can enable the per-page statistics as well. This will show the number of |
|
|
files served from the CDN at the bottom of each page, as well as a list of |
|
|
files that haven't been synchronized to the CDN yet, to users with the |
|
|
"administer site configuration" permission. |
|
|
|
|
|
|
|
|
Applying the Drupal core patch |
|
|
------------------------------ |
|
|
You *must* apply this patch! It has been created against Drupal 5.5. |
|
|
|
|
|
First, change the directory to the Drupal root directory. |
|
|
|
|
|
You can apply the included Drupal core patch like this: |
|
|
patch -p0 < d5_file_url_rewrite.patch |
|
|
|
|
|
To undo the patch: |
|
|
patch -p0 -R < d5_file_url_rewrite.patch |
|
|
|
|
|
Note: there is also a patch that combines the CDN integration core patch with |
|
|
the JS aggregation. It's included in this module because if you apply both |
|
|
patches separately, you will get a conflict. This patch also sets the default |
|
|
location for drupal.js and jquery.js to the footer of the page, and defaults |
|
|
calls to drupal_add_js() to the footer as well. |
|
|
|
|
|
|
|
|
Applying the theme patch |
|
|
------------------------ |
|
|
You *must* apply this patch to *every* theme that's being used on your |
|
|
website! Note that the provided patch only works for Garland. You'll have to |
|
|
apply similar changes (i.e. wrap the URL in a file_url() call) to the themes |
|
|
you're using. |
|
|
|
|
|
Repeat this process for every theme: first, change the directory to the |
|
|
directory of the theme. Applying the patch is identical to the example above, |
|
|
only with a different filename. |
|
|
|
|
|
|
|
|
Setting up CDN synchronization filters |
|
|
-------------------------------------- |
|
|
First of all: each filter works *recursively*! Now, the explanations: |
|
|
- paths: This is an array of paths (each path being relative to the Drupal |
|
|
root directory) on which this filter should be applied. |
|
|
- pattern: Regular expression that will be used to filter the files in each |
|
|
directory. Like the $mask parameter in file_scan_directory(). |
|
|
- ignored_dirs: Array of directories that should be ignored in each directory. |
|
|
Like the $nomask parameter in file_scan_directory(). |
|
|
- unique: Determines how the uniqueness will be applied. You can set it to |
|
|
'filename', which will alter the filename, or 'common parent |
|
|
directory', which will alter the path of the file. The latter is |
|
|
strongly recommended for themes, since it will not break URLs in |
|
|
CSS files. |
|
|
- unique_method: The method that should be used to generate unique filenames. |
|
|
Currently supported: 'none' (no unique filename!), 'mtime' |
|
|
(the file's mtime property), 'md5' (md5 hash of the file) or |
|
|
'md5 of mtimes' (md5 hash of the concatenated mtimes of a set |
|
|
of files). This last option is only available if you have set |
|
|
the unique property to 'common parent directory'. |
|
|
|
|
|
|
|
|
Configuring the $conf array in settings.php |
|
|
------------------------------------------- |
|
|
This is my configuration: |
|
|
|
|
|
$conf = array( |
|
|
// CDN integration module settings. |
|
|
'cdn_url' => 'http://wimleers.cachefly.com/wimleers.com', |
|
|
'cdn_sync_filters' => array( |
|
|
// Add all Javascript, CSS, image and flash files from the most common |
|
|
// directories in Drupal. |
|
|
0 => array( |
|
|
'paths' => array('misc', 'profiles', 'modules', 'sites/all/modules', 'sites/default/modules'), |
|
|
'pattern' => '.*\.(ico|js|css|gif|png|jpg|jpeg|svg|swf)$', |
|
|
'ignored_dirs' => array('CVS'), |
|
|
'unique' => 'filename', |
|
|
'unique_method' => 'mtime', |
|
|
), |
|
|
|
|
|
// We want to add *everything* in the files directory. Except for the |
|
|
// files in the CSS and JS directory, because they need other treatment: |
|
|
// we assume that files in this directory don't change, so we can use |
|
|
// non-unique filenames, resulting in nicer filenames when they're |
|
|
// downloaded. |
|
|
1 => array( |
|
|
'paths' => array('sites/wimleers.com/files'), |
|
|
'pattern' => '.*', |
|
|
'ignored_dirs' => array('CVS', 'css', 'js'), |
|
|
'unique_method' => 'none', |
|
|
), |
|
|
|
|
|
// Add all files in the files/css directory, *but* update the URLs in the |
|
|
// files. This is only necessary if we use CSS aggregation. |
|
|
2 => array( |
|
|
'paths' => array('sites/wimleers.com/files/css'), |
|
|
'pattern' => '.*', |
|
|
'ignored_dirs' => array('CVS'), |
|
|
'unique' => 'filename', |
|
|
'unique_method' => 'mtime', |
|
|
'update_urls_in_files' => TRUE, |
|
|
), |
|
|
|
|
|
// Add all files in the files/js directory, *but* update the URLs in the |
|
|
// files. This is only necessary if we use JS aggregation. |
|
|
3 => array( |
|
|
'paths' => array('sites/wimleers.com/files/js'), |
|
|
'pattern' => '.*', |
|
|
'ignored_dirs' => array('CVS'), |
|
|
'unique' => 'filename', |
|
|
'unique_method' => 'mtime', |
|
|
'update_urls_in_files' => TRUE, |
|
|
), |
|
|
|
|
|
// Add all Javascript, CSS, image and font files from our themes. But |
|
|
// make sure the URLs don't break when CSS aggregation is disabled, by |
|
|
// using the "common parent directory" unique level and the "md5 of mtimes" |
|
|
// uniqueness method. We can revert to normal values if we have CSS |
|
|
// aggregation enabled. |
|
|
4 => array( |
|
|
'paths' => array('sites/default/themes/garland-customized'), |
|
|
'pattern' => '.*\.(js|css|gif|png|jpg|jpeg|otf)$', // We *include* css files, because some (e.g. fix-ie.css) are not included in the aggregation. |
|
|
'ignored_dirs' => array('CVS'), |
|
|
'unique' => 'common parent directory', |
|
|
'unique_method' => 'md5 of mtimes', |
|
|
), |
|
|
), |
|
|
'cdn_sync_method' => 'ftp', |
|
|
'cdn_sync_method_settings' => array( |
|
|
'host' => 'ftp.cachefly.com', |
|
|
'remote_path' => 'wimleers.com', |
|
|
'port' => 21, |
|
|
'user' => 'user', |
|
|
'pass' => 'pass', |
|
|
), |
|
|
); |
|
| 101 |
|
|
| 102 |
|
|
| 103 |
Author |
Author |
| 104 |
------ |
------ |
| 105 |
Wim Leers |
Wim Leers ~ http://wimleers.com/ |
|
|
|
|
* mail: work@wimleers.com |
|
|
* website: http://wimleers.com/work |
|
| 106 |
|
|
| 107 |
The author can be contacted for paid customizations of this module as well as |
This module was written as part of the bachelor thesis of Wim Leers at |
| 108 |
Drupal consulting, development and installation. |
Hasselt University. |