/[drupal]/contributions/modules/cdn/cdn.module
ViewVC logotype

Contents of /contributions/modules/cdn/cdn.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.25 - (show annotations) (download) (as text)
Wed Jul 1 19:36:50 2009 UTC (4 months, 3 weeks ago) by wimleers
Branch: MAIN
CVS Tags: DRUPAL-6--1-1, HEAD
Changes since 1.24: +1 -26 lines
File MIME type: text/x-php
I forgot to remove the demo code. Pity.
1 <?php
2 // $Id: cdn.module,v 1.24 2009/07/01 11:35:31 wimleers Exp $
3
4 /**
5 * @file
6 * Implementation of the core hooks, defines, public and private functions.
7 */
8
9
10 define('CDN_DISABLED', 0);
11 define('CDN_DEBUG', 1);
12 define('CDN_ENABLED', 2);
13
14 // Permissions.
15 define('CDN_PERM_ACCESS_STATS', 'access per-page statistics');
16 define('CDN_PERM_ACCESS_DEBUG', 'access files on CDN when in debug mode');
17
18 // Variables and values.
19 define('CDN_MODE_VARIABLE', 'cdn_mode');
20 define('CDN_MODE_BASIC', 'basic');
21 define('CDN_MODE_ADVANCED', 'advanced');
22 define('CDN_STATUS_VARIABLE', 'cdn_status');
23 define('CDN_STATS_VARIABLE', 'cdn_stats');
24 define('CDN_DRUPAL_ROOT_VARIABLE', 'cdn_drupal_root');
25
26 // Variables for basic mode.
27 define('CDN_BASIC_URL_VARIABLE', 'cdn_basic_url');
28 define('CDN_BASIC_EXTENSIONS_VARIABLE', 'cdn_basic_extensions');
29 define('CDN_BASIC_EXTENSIONS_DEFAULT', '.css .js .ico .gif .jpg .jpeg .png .svg .otf .ttf .swf');
30
31 // Variables for advanced mode.
32 define('CDN_ADVANCED_SYNCED_FILES_DB_VARIABLE', 'cdn_advanced_synced_files_db');
33
34 // Hardcoded settings for accessing the daemon's metadata, to show statistics.
35 define('CDN_DAEMON_SYNCED_FILES_DB', 'synced_files.db');
36 define('CDN_DAEMON_PERSISTENT_DATA_DB', 'persistent_data.db');
37 define('CDN_DAEMON_FSMONITOR_DB', 'fsmonitor.db');
38 define('CDN_DAEMON_PID_FILE', 'daemon.pid');
39
40
41 //----------------------------------------------------------------------------
42 // Drupal core.
43
44 function custom_file_url_rewrite($path) {
45 $status = variable_get(CDN_STATUS_VARIABLE, CDN_DISABLED);
46 $mode = variable_get(CDN_MODE_VARIABLE, CDN_MODE_BASIC);
47 $stats = variable_get(CDN_STATS_VARIABLE, FALSE) && user_access(CDN_PERM_ACCESS_STATS);
48
49 if ($stats) {
50 require_once(drupal_get_path('module', 'cdn') . '/cdn.stats.inc');
51 }
52
53 if ($status == CDN_ENABLED || ($status == CDN_DEBUG && user_access(CDN_PERM_ACCESS_DEBUG))) {
54 if ($stats) {
55 $start = microtime();
56 }
57
58 // Depending on the mode, use a different function to get the URL.
59 if ($mode == CDN_MODE_BASIC) {
60 $cdn_url = cdn_basic_get_url($path);
61 $server = FALSE;
62 }
63 else {
64 list($cdn_url, $server) = cdn_advanced_get_url($path);
65 }
66
67 // If the user can access it, add this to the per-page statistics.
68 if ($stats) {
69 $end = microtime();
70 _cdn_devel_page_stats($path, $cdn_url, $server, $end - $start);
71 }
72
73 return $cdn_url;
74 }
75 else {
76 return FALSE;
77 }
78 }
79
80 /**
81 * Implementation of hook_menu().
82 */
83 function cdn_menu() {
84 $items['admin/settings/cdn'] = array(
85 'title' => 'CDN integration',
86 'description' => 'Configure various settings for CDN integration.',
87 'access arguments' => array('administer site configuration'),
88 'page callback' => 'drupal_get_form',
89 'page arguments' => array('cdn_admin_settings_form'),
90 'type' => MENU_NORMAL_ITEM,
91 'file' => 'cdn.admin.inc',
92 );
93
94 $items['admin/settings/cdn/settings'] = array(
95 'title' => 'Settings',
96 'access arguments' => array('administer site configuration'),
97 'weight' => -10,
98 'type' => MENU_DEFAULT_LOCAL_TASK,
99 'file' => 'cdn.admin.inc',
100 );
101 $items['admin/settings/cdn/basic'] = array(
102 'title' => 'Basic mode',
103 'description' => 'Basic mode settings.',
104 'access arguments' => array('administer site configuration'),
105 'page callback' => 'drupal_get_form',
106 'page arguments' => array('cdn_admin_basic_settings_form'),
107 'weight' => -8,
108 'type' => MENU_LOCAL_TASK,
109 'file' => 'cdn.admin.inc',
110 );
111 $items['admin/settings/cdn/advanced'] = array(
112 'title' => 'Advanced mode',
113 'description' => 'Advanced mode settings.',
114 'access arguments' => array('administer site configuration'),
115 'page callback' => 'drupal_get_form',
116 'page arguments' => array('cdn_admin_advanced_settings_form'),
117 'weight' => -6,
118 'type' => MENU_LOCAL_TASK,
119 'file' => 'cdn.admin.inc',
120 );
121 $items['admin/settings/cdn/other'] = array(
122 'title' => 'Other',
123 'description' => 'Other settings.',
124 'access arguments' => array('administer site configuration'),
125 'page callback' => 'drupal_get_form',
126 'page arguments' => array('cdn_admin_other_settings_form'),
127 'weight' => -4,
128 'type' => MENU_LOCAL_TASK,
129 'file' => 'cdn.admin.inc',
130 );
131
132 return $items;
133 }
134
135 /**
136 * Implementation of hook_perm().
137 */
138 function cdn_perm() {
139 return array(CDN_PERM_ACCESS_STATS, CDN_PERM_ACCESS_DEBUG);
140 }
141
142 /**
143 * Implementation of hook_theme().
144 */
145 function cdn_theme() {
146 return array(
147 'cdn_page_stats' => array(
148 'file' => 'theme.inc',
149 'arguments' => array(
150 $file_count => NULL,
151 $cdn_file_count => NULL,
152 $synced_files_per_server_count => NULL,
153 $total_time => NULL,
154 $synced_files => NULL,
155 $unsynced_files => NULL,
156 ),
157 ),
158 );
159 }
160
161 /**
162 * Implementation of hook_exit().
163 */
164 function cdn_exit($destination = NULL) {
165 require_once(drupal_get_path('module', 'cdn') . '/cdn.stats.inc');
166
167 // Try not to break non-HTML pages.
168 if (function_exists('drupal_get_headers')) {
169 $headers = drupal_get_headers();
170 $formats = array('xml', 'javascript', 'json', 'plain', 'image', 'application', 'csv', 'x-comma-separated-values');
171 foreach ($formats as $format) {
172 if (strstr($headers, $format)) {
173 return;
174 }
175 }
176 }
177
178 if (!$destination
179 && variable_get(CDN_STATUS_VARIABLE, CDN_DISABLED) != CDN_DISABLED
180 && variable_get(CDN_STATS_VARIABLE, FALSE)
181 && user_access(CDN_PERM_ACCESS_STATS))
182 {
183 list(
184 $file_count,
185 $cdn_file_count,
186 $synced_files_per_server_count,
187 $total_time,
188 $synced_files,
189 $unsynced_files,
190 ) = _cdn_devel_page_stats();
191 print theme('cdn_page_stats',
192 $file_count,
193 $cdn_file_count,
194 $synced_files_per_server_count,
195 $total_time,
196 $synced_files,
197 $unsynced_files
198 );
199 }
200 }
201
202 /**
203 * Implementation of hook_requirements().
204 */
205 function cdn_requirements($phase) {
206 $requirements = array();
207 $t = get_t();
208
209 switch ($phase) {
210 case 'install' :
211 case 'runtime' :
212 $status = variable_get(CDN_STATUS_VARIABLE, CDN_DISABLED);
213 $mode = variable_get(CDN_MODE_VARIABLE, CDN_MODE_BASIC);
214
215 $requirements['cdn']['title'] = $t('CDN integration');
216
217 // Set the basic info: disabled/debug/enabled.
218 if ($status == CDN_DISABLED) {
219 $requirements['cdn'] += array(
220 'description' => $t('CDN integration is disabled for all users.'),
221 'severity' => REQUIREMENT_WARNING,
222 'value' => $t('Disabled'),
223 );
224 }
225 elseif ($status == CDN_DEBUG) {
226 $requirements['cdn'] += array(
227 'description' => $t('CDN integration is only enabled for users with
228 the %cdn-debug-mode-permission permission',
229 array('%cdn-debug-mode-permission' => CDN_PERM_ACCESS_DEBUG)
230 ),
231 'severity' => REQUIREMENT_WARNING,
232 'value' => $t('In debug mode'),
233 );
234 }
235 else {
236 $requirements['cdn'] += array(
237 'description' => $t('CDN integration is enabled for all users.'),
238 'severity' => REQUIREMENT_OK,
239 'value' => $t('Enabled'),
240 );
241 }
242
243 // When CDN integration is enabled, add on more information.
244 if ($status != CDN_DISABLED) {
245 if ($mode == CDN_MODE_BASIC) {
246 $requirements['cdn']['value'] .= ' – '. t('basic mode');
247 }
248 else {
249 $requirements['cdn']['value'] .= ' – '. t('advanced mode');
250
251 $items = array();
252
253 $synced_files_db = variable_get(CDN_ADVANCED_SYNCED_FILES_DB_VARIABLE, FALSE);
254
255 if ($synced_files_db !== FALSE) {
256 $daemon_pid_file = str_replace(CDN_DAEMON_SYNCED_FILES_DB, CDN_DAEMON_PID_FILE, $synced_files_db);
257 $persistent_data_db = str_replace(CDN_DAEMON_SYNCED_FILES_DB, CDN_DAEMON_PERSISTENT_DATA_DB, $synced_files_db);
258 $drupal_root_path = variable_get(CDN_DRUPAL_ROOT_VARIABLE, realpath('.'));
259
260 $synced_files_db_exists = file_exists($synced_files_db);
261 $synced_files_db_readable = @fopen($synced_files_db, 'r');
262 $persistent_data_db_exists = file_exists($persistent_data_db);
263 $persistent_data_db_readable = @fopen($persistent_data_db, 'r');
264 $daemon_pid_file_exists = file_exists($daemon_pid_file);
265
266 $db = _cdn_advanced_get_db_connection();
267 if ($db !== FALSE) {
268 $input_file_mask = $drupal_root_path .'%';
269 $sql = "SELECT COUNT(*) AS count, server FROM synced_files WHERE input_file LIKE :input_file GROUP BY server";
270 $stmt = $db->prepare($sql);
271 $stmt->bindParam(':input_file', $input_file_mask, PDO::PARAM_STR);
272 $stmt->execute();
273 $result = $stmt->fetchAll();
274 $synced_file_stats = $result;
275 }
276
277 if ($persistent_data_db_exists && $persistent_data_db_readable) {
278 try {
279 $db = new PDO('sqlite:' . $persistent_data_db);
280 } catch(PDOException $e) {
281 $items[] = t("Could not connect to persistent data database.");
282 }
283 if ($db !== FALSE) {
284 $sql = "SELECT COUNT(*) FROM pipeline_queue";
285 $stmt = $db->prepare($sql);
286 $stmt->execute();
287 $result = $stmt->fetchAll();
288 $pipeline_queue_count = $result[0][0];
289
290 $sql = "SELECT COUNT(*) FROM pipeline_list";
291 $stmt = $db->prepare($sql);
292 $stmt->execute();
293 $result = $stmt->fetchAll();
294 $pipeline_list_count = $result[0][0];
295 }
296 }
297
298 $items[] = ($synced_files_db_exists) ? t('The synced files database exists.') : t("The synced files database doesn't exist.");
299 $items[] = ($synced_files_db_readable) ? t('The synced files database is readable.') : t("The synced files database isn't readable.");
300 if ($synced_files_db_readable) {
301 foreach ($synced_file_stats as $row) {
302 $items[] = t('!synced-file-count files have been synced to the %server server.', array('!synced-file-count' => $row['count'], '%server' => $row['server']));
303 }
304 }
305 else {
306 $items[] = t("Number of synced files is unknown.");
307 }
308 $items[] = ($daemon_pid_file_exists) ? t('The daemon is currently running.') : '<strong>' . t('The daemon is currently not running.') . '</strong>';
309 if (isset($pipeline_queue_count)) {
310 $items[] = t("!pipeline-queue-count files are waiting to be synced.", array('!pipeline-queue-count' => $pipeline_queue_count));
311 $items[] = t("!pipeline-list-count files are currently being synced.", array('!pipeline-list-count' => $pipeline_list_count));
312 }
313
314 // If either of these 3 checks failed, mark this requirement's
315 // severity as being an error.
316 if (!($synced_files_db_exists && $synced_files_db_readable && $daemon_pid_file_exists)) {
317 $requirements['cdn']['severity'] = REQUIREMENT_ERROR;
318 }
319 }
320 else {
321 $items[] = t('The synced files database setting has not yet been configured.');
322 $requirements['cdn']['severity'] = REQUIREMENT_ERROR;
323 }
324
325 $requirements['cdn']['description'] .= '<br />' . theme('item_list', $items);
326 }
327 }
328 }
329
330 return $requirements;
331 }
332
333
334 //----------------------------------------------------------------------------
335 // Public functions.
336
337 /**
338 * Gets the URL for a file when the basic mode is enabled.
339 *
340 * @param $path
341 * The path to get the URL for.
342 */
343 function cdn_basic_get_url($path) {
344 // Ensure the configuration is correct.
345 if (variable_get(CDN_BASIC_URL_VARIABLE, FALSE) === FALSE) {
346 return FALSE;
347 }
348
349 $extensions = str_replace(array(' ', '.'), array('|', '\.'), variable_get(CDN_BASIC_EXTENSIONS_VARIABLE, CDN_BASIC_EXTENSIONS_DEFAULT));
350
351 if (preg_match("/($extensions)$/", $path)) {
352 $base_path = base_path();
353 $cdn_url = variable_get(CDN_BASIC_URL_VARIABLE, 'http://yourcdn.com');
354 return $cdn_url . $base_path . $path;
355 }
356 else {
357 return FALSE;
358 }
359 }
360
361 /**
362 * Gets the URL for a file when the basic mode is enabled.
363 *
364 * @param $path
365 * The path to get the URL for.
366 */
367 function cdn_advanced_get_url($path) {
368 $db = _cdn_advanced_get_db_connection();
369
370 // In case no connection to the database could be made, pretend the file was
371 // not found in the synced files database.
372 if (!$db) {
373 return array(FALSE, FALSE);
374 }
375
376 // Get the real path to the file (resolves symbolic links).
377 $input_file = realpath('./' . $path);
378
379 // Retrieve the URLs of the file on the CDN.
380 $sql = "SELECT url, server FROM synced_files WHERE input_file = :input_file";
381 $stmt = $db->prepare($sql);
382 $stmt->bindParam(':input_file', $input_file, PDO::PARAM_STR);
383 $stmt->execute();
384 $servers = $stmt->fetchAll(PDO::FETCH_ASSOC);
385
386 // The file is not available from any server.
387 if (count($servers) == 0) {
388 $url = FALSE;
389 $server = FALSE;
390 }
391 // If the file is available from multiple servers, then allow a special
392 // function to pic the desired server. The decision can be made on any
393 // desired criteria: user's location, user's role, current date …
394 else if (count($servers) > 1 && function_exists('cdn_advanced_pick_server')) {
395 $picked_server = cdn_advanced_pick_server($servers);
396 $url = $picked_server['url'];
397 $server = $picked_server['server'];
398 }
399 // The file is available from at least one server, simply pick the first.
400 else {
401 $url = $servers[0]['url'];
402 $server = $servers[0]['server'];
403 }
404
405 return array($url, $server);
406 }
407
408
409 //----------------------------------------------------------------------------
410 // Private functions.
411
412 /**
413 * Get a connection to the database. The resulting PDO object is statically
414 * cached.
415 *
416 * @return
417 * A database connection (through PDO), or FALSE in case of failure.
418 */
419 function _cdn_advanced_get_db_connection() {
420 static $db;
421
422 $synced_files_db = variable_get(CDN_ADVANCED_SYNCED_FILES_DB_VARIABLE, FALSE);
423
424 if ($synced_files_db === FALSE || !file_exists($synced_files_db) || filesize($synced_files_db) == 0) {
425 $db = FALSE;
426 }
427 elseif (!isset($db)) {
428 try {
429 $db = new PDO('sqlite:' . variable_get(CDN_ADVANCED_SYNCED_FILES_DB_VARIABLE, ''));
430 } catch(PDOException $e) {
431 watchdog('cdn', t("Could not open synced files DB: %error.", array('%error' => $e)));
432 $db = FALSE;
433 }
434 }
435
436 return $db;
437 }

  ViewVC Help
Powered by ViewVC 1.1.2