Projet

Général

Profil

Paste
Télécharger (26,6 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / piwik / piwik.module @ 147616a8

1
<?php
2

    
3
/**
4
 * @file
5
 * Drupal Module: Piwik
6
 *
7
 * Adds the required Javascript to all your Drupal pages to allow tracking by
8
 * the Piwik statistics package.
9
 *
10
 * @author: Alexander Hass <http://drupal.org/user/85918>
11
 */
12

    
13
/**
14
 * Define the default file extension list that should be tracked as download.
15
 */
16
define('PIWIK_TRACKFILES_EXTENSIONS', '7z|aac|arc|arj|asf|asx|avi|bin|csv|doc(x|m)?|dot(x|m)?|exe|flv|gif|gz|gzip|hqx|jar|jpe?g|js|mp(2|3|4|e?g)|mov(ie)?|msi|msp|pdf|phps|png|ppt(x|m)?|pot(x|m)?|pps(x|m)?|ppam|sld(x|m)?|thmx|qtm?|ra(m|r)?|sea|sit|tar|tgz|torrent|txt|wav|wma|wmv|wpd|xls(x|m|b)?|xlt(x|m)|xlam|xml|z|zip');
17

    
18
/**
19
 * Define default path exclusion list to remove tracking from admin pages,
20
 * see http://drupal.org/node/34970 for more information.
21
 */
22
define('PIWIK_PAGES', "admin\nadmin/*\nbatch\nnode/add*\nnode/*/*\nuser/*/*");
23

    
24
/**
25
 * Implements hook_help().
26
 */
27
function piwik_help($path, $arg) {
28
  switch ($path) {
29
    case 'admin/config/system/piwik':
30
      return t('<a href="@pk_url">Piwik - Web analytics</a> is an open source (GPL license) web analytics software. It gives interesting reports on your website visitors, your popular pages, the search engines keywords they used, the language they speak... and so much more. Piwik aims to be an open source alternative to Google Analytics.', array('@pk_url' => 'http://www.piwik.org/'));
31
  }
32
}
33

    
34
/**
35
 * Implements hook_theme().
36
 */
37
function piwik_theme() {
38
  return array(
39
    'piwik_admin_custom_var_table' => array(
40
      'render element' => 'form',
41
    ),
42
  );
43
}
44

    
45
/**
46
 * Implements hook_permission().
47
 */
48
function piwik_permission() {
49
  return array(
50
    'administer piwik' => array(
51
      'title' => t('Administer Piwik'),
52
      'description' => t('Perform maintenance tasks for Piwik.'),
53
    ),
54
    'opt-in or out of tracking' => array(
55
      'title' => t('Opt-in or out of tracking'),
56
      'description' => t('Allow users to decide if tracking code will be added to pages or not.'),
57
    ),
58
    'use PHP for tracking visibility' => array(
59
      'title' => t('Use PHP for tracking visibility'),
60
      'description' => t('Enter PHP code in the field for tracking visibility settings.'),
61
      'restrict access' => TRUE,
62
    ),
63
    'add JS snippets for piwik' => array(
64
      'title' => t('Add JavaScript snippets'),
65
      'description' => 'Enter JavaScript code snippets for advanced Piwik functionality.',
66
      'restrict access' => TRUE,
67
    ),
68
  );
69
}
70

    
71
/**
72
 * Implements hook_menu().
73
 */
74
function piwik_menu() {
75
  $items['admin/config/system/piwik'] = array(
76
    'title' => 'Piwik',
77
    'description' => 'Configure the settings used to generate your Piwik tracking code.',
78
    'page callback' => 'drupal_get_form',
79
    'page arguments' => array('piwik_admin_settings_form'),
80
    'access arguments' => array('administer piwik'),
81
    'type' => MENU_NORMAL_ITEM,
82
    'file' => 'piwik.admin.inc',
83
  );
84

    
85
  return $items;
86
}
87

    
88
/**
89
 * Implements hook_page_alter() to insert JavaScript to the appropriate scope/region of the page.
90
 */
91
function piwik_page_alter(&$page) {
92
  global $user;
93

    
94
  $id = variable_get('piwik_site_id', '');
95

    
96
  // Get page status code for visibility filtering.
97
  $status = drupal_get_http_header('Status');
98
  $trackable_status_codes = array(
99
    '403 Forbidden',
100
    '404 Not Found',
101
  );
102

    
103
  // 1. Check if the piwik account number has a value.
104
  // 2. Track page views based on visibility value.
105
  // 3. Check if we should track the currently active user's role.
106
  if (preg_match('/^\d{1,}$/', $id) && (_piwik_visibility_pages() || in_array($status, $trackable_status_codes)) && _piwik_visibility_user($user)) {
107

    
108
    $url_http = variable_get('piwik_url_http', '');
109
    $url_https = variable_get('piwik_url_https', '');
110
    $scope = variable_get('piwik_js_scope', 'header');
111

    
112
    $set_custom_url = '';
113
    $set_document_title = '';
114
    $set_custom_data = array();
115

    
116
    // Add link tracking.
117
    $link_settings = array();
118
    $link_settings['trackMailto'] = variable_get('piwik_trackmailto', 1);
119

    
120
    if (module_exists('colorbox') && ($track_colorbox = variable_get('piwik_trackcolorbox', 1))) {
121
      $link_settings['trackColorbox'] = $track_colorbox;
122
    }
123

    
124
    drupal_add_js(array('piwik' => $link_settings), 'setting');
125
    drupal_add_js(drupal_get_path('module', 'piwik') . '/piwik.js');
126

    
127
    // Piwik can show a tree view of page titles that represents the site structure
128
    // if setDocumentTitle() provides the page titles as a "/" delimited list.
129
    // This may makes it easier to browse through the statistics of page titles
130
    // on larger sites.
131
    if (variable_get('piwik_page_title_hierarchy', FALSE) == TRUE) {
132
      $titles = _piwik_get_hierarchy_titles();
133

    
134
      if (variable_get('piwik_page_title_hierarchy_exclude_home', TRUE)) {
135
        // Remove the "Home" item from the titles to flatten the tree view.
136
        array_shift($titles);
137
      }
138

    
139
      // Remove all empty titles.
140
      $titles = array_filter($titles);
141

    
142
      if (!empty($titles)) {
143
        // Encode title, at least to keep "/" intact.
144
        $titles = array_map('rawurlencode', $titles);
145

    
146
        $set_document_title = drupal_json_encode(implode('/', $titles));
147
      }
148
    }
149

    
150
    // Add messages tracking.
151
    $message_events = '';
152
    if ($message_types = variable_get('piwik_trackmessages', array())) {
153
      $message_types = array_values(array_filter($message_types));
154
      $status_heading = array(
155
        'status' => t('Status message'),
156
        'warning' => t('Warning message'),
157
        'error' => t('Error message'),
158
      );
159

    
160
      foreach (drupal_get_messages(NULL, FALSE) as $type => $messages) {
161
        // Track only the selected message types.
162
        if (in_array($type, $message_types)) {
163
          foreach ($messages as $message) {
164
            $message_events .= '_paq.push(["trackEvent", ' . drupal_json_encode(t('Messages')) . ', ' . drupal_json_encode($status_heading[$type]) . ', ' . drupal_json_encode(strip_tags($message)) . ']);';
165
          }
166
        }
167
      }
168
    }
169

    
170
    // If this node is a translation of another node, pass the original
171
    // node instead.
172
    if (module_exists('translation') && variable_get('piwik_translation_set', 0)) {
173
      // Check we have a node object, it supports translation, and its
174
      // translated node ID (tnid) doesn't match its own node ID.
175
      $node = menu_get_object();
176
      if ($node && translation_supported_type($node->type) && !empty($node->tnid) && ($node->tnid != $node->nid)) {
177
        $source_node = node_load($node->tnid);
178
        $languages = language_list();
179
        $set_custom_url = drupal_json_encode(url('node/' . $source_node->nid, array('language' => $languages[$source_node->language], 'absolute' => TRUE)));
180
      }
181
    }
182

    
183
    // Track access denied (403) and file not found (404) pages.
184
    if ($status == '403 Forbidden') {
185
      $set_document_title = '"403/URL = " + encodeURIComponent(document.location.pathname+document.location.search) + "/From = " + encodeURIComponent(document.referrer)';
186
    }
187
    elseif ($status == '404 Not Found') {
188
      $set_document_title = '"404/URL = " + encodeURIComponent(document.location.pathname+document.location.search) + "/From = " + encodeURIComponent(document.referrer)';
189
    }
190

    
191
    // #2693595: User has entered an invalid login and clicked on forgot
192
    // password link. This link contains the username or email address and may
193
    // get send to Google if we do not override it. Override only if 'name'
194
    // query param exists. Last custom url condition, this need to win.
195
    //
196
    // URLs to protect are:
197
    // - user/password?name=username
198
    // - user/password?name=foo@example.com
199
    if (arg(0) == 'user' && arg(1) == 'password' && array_key_exists('name', drupal_get_query_parameters())) {
200
      $set_custom_url = drupal_json_encode(url('user/password'));
201
    }
202

    
203
    // Add custom variables.
204
    $piwik_custom_vars = variable_get('piwik_custom_var', array());
205
    $custom_variable = '';
206
    for ($i = 1; $i < 6; $i++) {
207
      $custom_var_name = !empty($piwik_custom_vars['slots'][$i]['name']) ? $piwik_custom_vars['slots'][$i]['name'] : '';
208
      if (!empty($custom_var_name)) {
209
        $custom_var_value = !empty($piwik_custom_vars['slots'][$i]['value']) ? $piwik_custom_vars['slots'][$i]['value'] : '';
210
        $custom_var_scope = !empty($piwik_custom_vars['slots'][$i]['scope']) ? $piwik_custom_vars['slots'][$i]['scope'] : 'visit';
211

    
212
        $types = array();
213
        $node = menu_get_object();
214
        if (is_object($node)) {
215
          $types += array('node' => $node);
216
        }
217
        $custom_var_name = token_replace($custom_var_name, $types, array('clear' => TRUE));
218
        $custom_var_value = token_replace($custom_var_value, $types, array('clear' => TRUE));
219

    
220
        // Suppress empty custom names and/or variables.
221
        if (!drupal_strlen(trim($custom_var_name)) || !drupal_strlen(trim($custom_var_value))) {
222
          continue;
223
        }
224

    
225
        // Custom variables names and values are limited to 200 characters in
226
        // length. It is recommended to store values that are as small as
227
        // possible to ensure that the Piwik Tracking request URL doesn't go
228
        // over the URL limit for the webserver or browser.
229
        $custom_var_name = rtrim(substr($custom_var_name, 0, 200));
230
        $custom_var_value = rtrim(substr($custom_var_value, 0, 200));
231

    
232
        $custom_var_name = drupal_json_encode($custom_var_name);
233
        $custom_var_value = drupal_json_encode($custom_var_value);
234
        $custom_var_scope = drupal_json_encode($custom_var_scope);
235
        $custom_variable .= "_paq.push(['setCustomVariable', $i, $custom_var_name, $custom_var_value, $custom_var_scope]);";
236
      }
237
    }
238

    
239
    // Add any custom code snippets if specified.
240
    $codesnippet_before = variable_get('piwik_codesnippet_before', '');
241
    $codesnippet_after = variable_get('piwik_codesnippet_after', '');
242

    
243
    // Build tracker code. See http://piwik.org/docs/javascript-tracking/#toc-asynchronous-tracking
244
    $script = 'var _paq = _paq || [];';
245
    $script .= '(function(){';
246
    $script .= 'var u=(("https:" == document.location.protocol) ? "' . check_url($url_https) . '" : "' . check_url($url_http) . '");';
247
    $script .= '_paq.push(["setSiteId", ' . drupal_json_encode(variable_get('piwik_site_id', '')) . ']);';
248
    $script .= '_paq.push(["setTrackerUrl", u+"piwik.php"]);';
249

    
250
    // Track logged in users across all devices.
251
    if (variable_get('piwik_trackuserid', 0) && user_is_logged_in()) {
252
      // The USER_ID value should be a unique, persistent, and non-personally
253
      // identifiable string identifier that represents a user or signed-in
254
      // account across devices.
255
      $script .= '_paq.push(["setUserId", ' . drupal_json_encode(piwik_user_id_hash($user->uid)) . ']);';
256
    }
257

    
258
    // Set custom data.
259
    if (!empty($set_custom_data)) {
260
      foreach ($set_custom_data as $custom_data) {
261
        $script .= '_paq.push(["setCustomData", ' . $custom_data . ']);';
262
      }
263
    }
264
    // Set custom url.
265
    if (!empty($set_custom_url)) {
266
      $script .= '_paq.push(["setCustomUrl", ' . $set_custom_url . ']);';
267
    }
268
    // Set custom document title.
269
    if (!empty($set_document_title)) {
270
      $script .= '_paq.push(["setDocumentTitle", ' . $set_document_title . ']);';
271
    }
272

    
273
    // Custom file download extensions.
274
    if ((variable_get('piwik_track', 1)) && !(variable_get('piwik_trackfiles_extensions', PIWIK_TRACKFILES_EXTENSIONS) == PIWIK_TRACKFILES_EXTENSIONS)) {
275
      $script .= '_paq.push(["setDownloadExtensions", ' . drupal_json_encode(variable_get('piwik_trackfiles_extensions', PIWIK_TRACKFILES_EXTENSIONS)) . ']);';
276
    }
277

    
278
    // Disable tracking for visitors who have opted out from tracking via DNT (Do-Not-Track) header.
279
    if (variable_get('piwik_privacy_donottrack', 1)) {
280
      $script .= '_paq.push(["setDoNotTrack", 1]);';
281
    }
282

    
283
    // Domain tracking type.
284
    global $cookie_domain;
285
    $domain_mode = variable_get('piwik_domain_mode', 0);
286

    
287
    // Per RFC 2109, cookie domains must contain at least one dot other than the
288
    // first. For hosts such as 'localhost' or IP Addresses we don't set a cookie domain.
289
    if ($domain_mode == 1 && count(explode('.', $cookie_domain)) > 2 && !is_numeric(str_replace('.', '', $cookie_domain))) {
290
      $script .= '_paq.push(["setCookieDomain", ' . drupal_json_encode($cookie_domain) . ']);';
291
    }
292

    
293
    // Ordering $custom_variable before $codesnippet_before allows users to add
294
    // custom code snippets that may use deleteCustomVariable() and/or getCustomVariable().
295
    if (!empty($custom_variable)) {
296
      $script .= $custom_variable;
297
    }
298
    if (!empty($codesnippet_before)) {
299
      $script .= $codesnippet_before;
300
    }
301

    
302
    // Site search tracking support.
303
    // NOTE: It's recommended not to call trackPageView() on the Site Search Result page.
304
    if (module_exists('search') && variable_get('piwik_site_search', FALSE) && arg(0) == 'search' && $keys = piwik_search_get_keys()) {
305
      // Parameters:
306
      // 1. Search keyword searched for. Example: "Banana"
307
      // 2. Search category selected in your search engine. If you do not need
308
      //    this, set to false. Example: "Organic Food"
309
      // 3. Number of results on the Search results page. Zero indicates a
310
      //    'No Result Search Keyword'. Set to false if you don't know.
311
      //
312
      // hook_preprocess_search_results() is not executed if search result is
313
      // empty. Make sure the counter is set to 0 if there are no results.
314
      $script .= '_paq.push(["trackSiteSearch", ' . drupal_json_encode($keys) . ', false, (window.piwik_search_results) ? window.piwik_search_results : 0]);';
315
    }
316
    else {
317
      $script .= '_paq.push(["trackPageView"]);';
318
    }
319

    
320
    // Add link tracking.
321
    if (variable_get('piwik_track', 1)) {
322
      // Disable tracking of links with ".no-tracking" and ".colorbox" classes.
323
      $ignore_classes = array(
324
        'no-tracking',
325
        'colorbox',
326
      );
327
      // Disable the download & outlink tracking for specific CSS classes.
328
      // Custom code snippets with 'setIgnoreClasses' will override the value.
329
      // http://developer.piwik.org/api-reference/tracking-javascript#disable-the-download-amp-outlink-tracking-for-specific-css-classes
330
      $script .= '_paq.push(["setIgnoreClasses", ' . drupal_json_encode($ignore_classes) . ']);';
331

    
332
      // Enable download & outlink link tracking.
333
      $script .= '_paq.push(["enableLinkTracking"]);';
334
    }
335

    
336
    if (!empty($message_events)) {
337
      $script .= $message_events;
338
    }
339
    if (!empty($codesnippet_after)) {
340
      $script .= $codesnippet_after;
341
    }
342

    
343
    $script .= 'var d=document,';
344
    $script .= 'g=d.createElement("script"),';
345
    $script .= 's=d.getElementsByTagName("script")[0];';
346
    $script .= 'g.type="text/javascript";';
347
    $script .= 'g.defer=true;';
348
    $script .= 'g.async=true;';
349

    
350
    // Should a local cached copy of the tracking code be used?
351
    if (variable_get('piwik_cache', 0) && $url = _piwik_cache($url_http . 'piwik.js')) {
352
      // A dummy query-string is added to filenames, to gain control over
353
      // browser-caching. The string changes on every update or full cache
354
      // flush, forcing browsers to load a new copy of the files, as the
355
      // URL changed.
356
      $query_string = '?' . variable_get('css_js_query_string', '0');
357

    
358
      $script .= 'g.src="' . $url . $query_string . '";';
359
    }
360
    else {
361
      $script .= 'g.src=u+"piwik.js";';
362
    }
363

    
364
    $script .= 's.parentNode.insertBefore(g,s);';
365
    $script .= '})();';
366

    
367
    // Add tracker code to scope.
368
    drupal_add_js($script, array('scope' => $scope, 'type' => 'inline'));
369
  }
370
}
371

    
372
/**
373
 * Generate user id hash to implement USER_ID.
374
 *
375
 * The USER_ID value should be a unique, persistent, and non-personally
376
 * identifiable string identifier that represents a user or signed-in
377
 * account across devices.
378
 *
379
 * @param int $uid
380
 *   User id.
381
 *
382
 * @return string
383
 *   User id hash.
384
 */
385
function piwik_user_id_hash($uid) {
386
  return drupal_hmac_base64($uid, drupal_get_private_key() . drupal_get_hash_salt());
387
}
388

    
389
/**
390
 * Implements hook_field_extra_fields().
391
 */
392
function piwik_field_extra_fields() {
393
  $extra['user']['user']['form']['piwik'] = array(
394
    'label' => t('Piwik configuration'),
395
    'description' => t('Piwik module form element.'),
396
    'weight' => 3,
397
  );
398

    
399
  return $extra;
400
}
401

    
402
/**
403
 * Implement hook_form_FORM_ID_alter().
404
 *
405
 * Allow users to decide if tracking code will be added to pages or not.
406
 */
407
function piwik_form_user_profile_form_alter(&$form, &$form_state) {
408
  $account = $form['#user'];
409
  $category = $form['#user_category'];
410

    
411
  if ($category == 'account' && user_access('opt-in or out of tracking') && ($custom = variable_get('piwik_custom', 0)) != 0 && _piwik_visibility_roles($account)) {
412
    $form['piwik'] = array(
413
      '#type' => 'fieldset',
414
      '#title' => t('Piwik configuration'),
415
      '#weight' => 3,
416
      '#collapsible' => TRUE,
417
      '#tree' => TRUE
418
    );
419

    
420
    switch ($custom) {
421
      case 1:
422
        $description = t('Users are tracked by default, but you are able to opt out.');
423
        break;
424

    
425
      case 2:
426
        $description = t('Users are <em>not</em> tracked by default, but you are able to opt in.');
427
        break;
428
    }
429

    
430
    $form['piwik']['custom'] = array(
431
      '#type' => 'checkbox',
432
      '#title' => t('Enable user tracking'),
433
      '#description' => $description,
434
      '#default_value' => isset($account->data['piwik']['custom']) ? $account->data['piwik']['custom'] : ($custom == 1),
435
    );
436

    
437
    return $form;
438
  }
439
}
440

    
441
/**
442
 * Implements hook_user_presave().
443
 */
444
function piwik_user_presave(&$edit, $account, $category) {
445
  if (isset($edit['piwik']['custom'])) {
446
    $edit['data']['piwik']['custom'] = $edit['piwik']['custom'];
447
  }
448
}
449

    
450
/**
451
 * Implements hook_cron().
452
 */
453
function piwik_cron() {
454
  // Regenerate the piwik.js every day.
455
  if (REQUEST_TIME - variable_get('piwik_last_cache', 0) >= 86400 && variable_get('piwik_cache', 0)) {
456
    _piwik_cache(variable_get('piwik_url_http', '') . 'piwik.js', TRUE);
457
    variable_set('piwik_last_cache', REQUEST_TIME);
458
  }
459
}
460

    
461
/**
462
 * Implements hook_preprocess_search_results().
463
 *
464
 * Collects and adds the number of search results to the head.
465
 */
466
function piwik_preprocess_search_results(&$variables) {
467
  // There is no search result $variable available that hold the number of items
468
  // found. But the pager item mumber can tell the number of search results.
469
  global $pager_total_items;
470

    
471
  drupal_add_js('window.piwik_search_results = ' . intval($pager_total_items[0]) . ';', array('type' => 'inline', 'group' => JS_LIBRARY-1));
472
}
473

    
474
/**
475
 * Download/Synchronize/Cache tracking code file locally.
476
 *
477
 * @param $location
478
 *   The full URL to the external javascript file.
479
 * @param $sync_cached_file
480
 *   Synchronize tracking code and update if remote file have changed.
481
 * @return mixed
482
 *   The path to the local javascript file on success, boolean FALSE on failure.
483
 */
484
function _piwik_cache($location, $sync_cached_file = FALSE) {
485
  $path = 'public://piwik';
486
  $file_destination = $path . '/' . basename($location);
487

    
488
  if (!file_exists($file_destination) || $sync_cached_file) {
489
    // Download the latest tracking code.
490
    $result = drupal_http_request($location);
491

    
492
    if ($result->code == 200) {
493
      if (file_exists($file_destination)) {
494
        // Synchronize tracking code and and replace local file if outdated.
495
        $data_hash_local = drupal_hash_base64(file_get_contents($file_destination));
496
        $data_hash_remote = drupal_hash_base64($result->data);
497
        // Check that the files directory is writable.
498
        if ($data_hash_local != $data_hash_remote && file_prepare_directory($path)) {
499
          // Save updated tracking code file to disk.
500
          file_unmanaged_save_data($result->data, $file_destination, FILE_EXISTS_REPLACE);
501
          // Based on Drupal Core drupal_build_css_cache().
502
          if (variable_get('css_gzip_compression', TRUE) && variable_get('clean_url', 0) && extension_loaded('zlib')) {
503
            file_unmanaged_save_data(gzencode($result->data, 9, FORCE_GZIP), $file_destination . '.gz', FILE_EXISTS_REPLACE);
504
          }
505
          watchdog('piwik', 'Locally cached tracking code file has been updated.', array(), WATCHDOG_INFO);
506

    
507
          // Change query-strings on css/js files to enforce reload for all users.
508
          _drupal_flush_css_js();
509
        }
510
      }
511
      else {
512
        // Check that the files directory is writable.
513
        if (file_prepare_directory($path, FILE_CREATE_DIRECTORY)) {
514
          // There is no need to flush JS here as core refreshes JS caches
515
          // automatically, if new files are added.
516
          file_unmanaged_save_data($result->data, $file_destination, FILE_EXISTS_REPLACE);
517
          if (variable_get('css_gzip_compression', TRUE) && variable_get('clean_url', 0) && extension_loaded('zlib')) {
518
            file_unmanaged_save_data(gzencode($result->data, 9, FORCE_GZIP), $file_destination . '.gz', FILE_EXISTS_REPLACE);
519
          }
520
          watchdog('piwik', 'Locally cached tracking code file has been saved.', array(), WATCHDOG_INFO);
521

    
522
          // Return the local JS file path.
523
          return file_create_url($file_destination);
524
        }
525
      }
526
    }
527
  }
528
  else {
529
    // Return the local JS file path.
530
    return file_create_url($file_destination);
531
  }
532
}
533

    
534
/**
535
 * Delete cached files and directory.
536
 */
537
function piwik_clear_js_cache() {
538
  $path = 'public://piwik';
539
  if (file_prepare_directory($path)) {
540
    file_scan_directory($path, '/.*/', array('callback' => 'file_unmanaged_delete'));
541
    drupal_rmdir($path);
542

    
543
    // Change query-strings on css/js files to enforce reload for all users.
544
    _drupal_flush_css_js();
545

    
546
    watchdog('piwik', 'Local cache has been purged.', array(), WATCHDOG_INFO);
547
  }
548
}
549

    
550
/**
551
 * Helper function for grabbing search keys. Function is missing in D7.
552
 *
553
 * http://api.drupal.org/api/function/search_get_keys/6
554
 */
555
function piwik_search_get_keys() {
556
  static $return;
557
  if (!isset($return)) {
558
    // Extract keys as remainder of path
559
    // Note: support old GET format of searches for existing links.
560
    $path = explode('/', $_GET['q'], 3);
561
    $keys = empty($_REQUEST['keys']) ? '' : $_REQUEST['keys'];
562
    $return = count($path) == 3 ? $path[2] : $keys;
563
  }
564
  return $return;
565
}
566

    
567
/**
568
 * Tracking visibility check for an user object.
569
 *
570
 * @param $account
571
 *   A user object containing an array of roles to check.
572
 * @return boolean
573
 *   A decision on if the current user is being tracked by Piwik.
574
 */
575
function _piwik_visibility_user($account) {
576

    
577
  $enabled = FALSE;
578

    
579
  // Is current user a member of a role that should be tracked?
580
  if (_piwik_visibility_roles($account)) {
581

    
582
    // Use the user's block visibility setting, if necessary.
583
    if (($custom = variable_get('piwik_custom', 0)) != 0) {
584
      if ($account->uid && isset($account->data['piwik']['custom'])) {
585
        $enabled = $account->data['piwik']['custom'];
586
      }
587
      else {
588
        $enabled = ($custom == 1);
589
      }
590
    }
591
    else {
592
      $enabled = TRUE;
593
    }
594

    
595
  }
596

    
597
  return $enabled;
598
}
599

    
600
/**
601
 * Based on visibility setting this function returns TRUE if GA code should
602
 * be added for the current role and otherwise FALSE.
603
 */
604
function _piwik_visibility_roles($account) {
605

    
606
  $visibility = variable_get('piwik_visibility_roles', 0);
607
  $enabled = $visibility;
608
  $roles = variable_get('piwik_roles', array());
609

    
610
  if (array_sum($roles) > 0) {
611
    // One or more roles are selected.
612
    foreach (array_keys($account->roles) as $rid) {
613
      // Is the current user a member of one of these roles?
614
      if (isset($roles[$rid]) && $rid == $roles[$rid]) {
615
        // Current user is a member of a role that should be tracked/excluded from tracking.
616
        $enabled = !$visibility;
617
        break;
618
      }
619
    }
620
  }
621
  else {
622
    // No role is selected for tracking, therefore all roles should be tracked.
623
    $enabled = TRUE;
624
  }
625

    
626
  return $enabled;
627
}
628

    
629
/**
630
 * Based on visibility setting this function returns TRUE if GA code should
631
 * be added to the current page and otherwise FALSE.
632
 */
633
function _piwik_visibility_pages() {
634
  static $page_match;
635

    
636
  // Cache visibility setting in hook_init for hook_footer.
637
  if (!isset($page_match)) {
638

    
639
    $visibility = variable_get('piwik_visibility_pages', 0);
640
    $setting_pages = variable_get('piwik_pages', PIWIK_PAGES);
641

    
642
    // Match path if necessary.
643
    if (!empty($setting_pages)) {
644
      // Convert path to lowercase. This allows comparison of the same path
645
      // with different case. Ex: /Page, /page, /PAGE.
646
      $pages = drupal_strtolower($setting_pages);
647
      if ($visibility < 2) {
648
        // Convert the Drupal path to lowercase
649
        $path = drupal_strtolower(drupal_get_path_alias($_GET['q']));
650
        // Compare the lowercase internal and lowercase path alias (if any).
651
        $page_match = drupal_match_path($path, $pages);
652
        if ($path != $_GET['q']) {
653
          $page_match = $page_match || drupal_match_path($_GET['q'], $pages);
654
        }
655
        // When $visibility has a value of 0, the tracking code is displayed on
656
        // all pages except those listed in $pages. When set to 1, it
657
        // is displayed only on those pages listed in $pages.
658
        $page_match = !($visibility xor $page_match);
659
      }
660
      elseif (module_exists('php')) {
661
        $page_match = php_eval($setting_pages);
662
      }
663
      else {
664
        $page_match = FALSE;
665
      }
666
    }
667
    else {
668
      $page_match = TRUE;
669
    }
670

    
671
  }
672
  return $page_match;
673
}
674

    
675
/**
676
 * Get the page titles trail for the current page.
677
 *
678
 * Based on menu_get_active_breadcrumb().
679
 *
680
 * @return array
681
 *   All page titles, including current page.
682
 */
683
function _piwik_get_hierarchy_titles() {
684
  $titles = array();
685

    
686
  // No breadcrumb for the front page.
687
  if (drupal_is_front_page()) {
688
    return $titles;
689
  }
690

    
691
  $item = menu_get_item();
692
  if (!empty($item['access'])) {
693
    $active_trail = menu_get_active_trail();
694

    
695
    // Allow modules to alter the breadcrumb, if possible, as that is much
696
    // faster than rebuilding an entirely new active trail.
697
    drupal_alter('menu_breadcrumb', $active_trail, $item);
698

    
699
    // Remove the tab root (parent) if the current path links to its parent.
700
    // Normally, the tab root link is included in the breadcrumb, as soon as we
701
    // are on a local task or any other child link. However, if we are on a
702
    // default local task (e.g., node/%/view), then we do not want the tab root
703
    // link (e.g., node/%) to appear, as it would be identical to the current
704
    // page. Since this behavior also needs to work recursively (i.e., on
705
    // default local tasks of default local tasks), and since the last non-task
706
    // link in the trail is used as page title (see menu_get_active_title()),
707
    // this condition cannot be cleanly integrated into menu_get_active_trail().
708
    // menu_get_active_trail() already skips all links that link to their parent
709
    // (commonly MENU_DEFAULT_LOCAL_TASK). In order to also hide the parent link
710
    // itself, we always remove the last link in the trail, if the current
711
    // router item links to its parent.
712
    if (($item['type'] & MENU_LINKS_TO_PARENT) == MENU_LINKS_TO_PARENT) {
713
      array_pop($active_trail);
714
    }
715

    
716
    foreach ($active_trail as $parent) {
717
      $titles[] = $parent['title'];
718
    }
719
  }
720

    
721
  return $titles;
722
}