Przeglądaj źródła

upadated colorbox andd prod_check

Bachir Soussi Chiadmi 8 lat temu
rodzic
commit
0ba0c21bb9
27 zmienionych plików z 2088 dodań i 255 usunięć
  1. 32 14
      sites/all/modules/contrib/dev/prod_check/README.txt
  2. 26 13
      sites/all/modules/contrib/dev/prod_check/includes/prod_check.admin.inc
  3. 502 0
      sites/all/modules/contrib/dev/prod_check/includes/prod_check.opcache.data_sample.inc
  4. 748 0
      sites/all/modules/contrib/dev/prod_check/includes/prod_check.opcache.inc
  5. 2 2
      sites/all/modules/contrib/dev/prod_check/prod_check.api.php
  6. 91 0
      sites/all/modules/contrib/dev/prod_check/prod_check.dbconnect.php
  7. 4 4
      sites/all/modules/contrib/dev/prod_check/prod_check.drush.inc
  8. 3 3
      sites/all/modules/contrib/dev/prod_check/prod_check.info
  9. 3 3
      sites/all/modules/contrib/dev/prod_check/prod_check.install
  10. 1 4
      sites/all/modules/contrib/dev/prod_check/prod_check.module
  11. 260 46
      sites/all/modules/contrib/dev/prod_check/prod_monitor/includes/prod_monitor.admin.inc
  12. 18 3
      sites/all/modules/contrib/dev/prod_check/prod_monitor/includes/prod_monitor.theme.inc
  13. 17 4
      sites/all/modules/contrib/dev/prod_check/prod_monitor/includes/prod_monitor.update.inc
  14. 41 0
      sites/all/modules/contrib/dev/prod_check/prod_monitor/prod_monitor.api.php
  15. 134 82
      sites/all/modules/contrib/dev/prod_check/prod_monitor/prod_monitor.drush.inc
  16. 3 3
      sites/all/modules/contrib/dev/prod_check/prod_monitor/prod_monitor.info
  17. 22 23
      sites/all/modules/contrib/dev/prod_check/prod_monitor/prod_monitor.install
  18. 137 41
      sites/all/modules/contrib/dev/prod_check/prod_monitor/prod_monitor.module
  19. 1 1
      sites/all/modules/contrib/theming/colorbox/README.txt
  20. 15 0
      sites/all/modules/contrib/theming/colorbox/colorbox.api.php
  21. 4 4
      sites/all/modules/contrib/theming/colorbox/colorbox.info
  22. 3 0
      sites/all/modules/contrib/theming/colorbox/colorbox.module
  23. 11 0
      sites/all/modules/contrib/theming/colorbox/colorbox.theme.inc
  24. 1 1
      sites/all/modules/contrib/theming/colorbox/js/colorbox.js
  25. 1 1
      sites/all/modules/contrib/theming/colorbox/js/colorbox_inline.js
  26. 1 1
      sites/all/modules/contrib/theming/colorbox/js/colorbox_load.js
  27. 7 2
      sites/all/modules/contrib/theming/colorbox/views/colorbox_handler_field_colorbox.inc

+ 32 - 14
sites/all/modules/contrib/dev/prod_check/README.txt

@@ -113,6 +113,20 @@ Production monitor
 6. If you wish to fetch the data immediately, check the appropriate box and save
  the settings. Good to go!
 
+Cron setup
+----------
+To automatically check the site status and/or module updates on cron, you will
+need to install drush and configure the following tasks in the crontab:
+
+# Check ALL sites for updates, once a day starting at 0100H at night.
+0 1 * * *    /path/to/drush -r /path/to/docroot prod-monitor-updates -y --quiet
+# Fetch ALL site data every five minutes (or whatever you please obviously).
+0/5 * * * *    /path/to/drush -r /path/to/docroot  prod-monitor-fetch -y --quiet
+
+Obviously, the time and frequency of these cron jobs is at your discretion.
+Do note that, depending on the number of sites you have configured, the crons
+may be running for quite some time, especially the module update checking job!
+
 Upgrading
 ---------
 When upgrading Production monitor to a newer version, always run update.php to
@@ -123,9 +137,9 @@ Nagios
 ------
 1. Download and install the Nagios module from http://drupal.org/project/nagios
  as per its readme instructions
-2. Enable Nagios support in the prod_check module on /admin/settings/prod-check
+2. Enable Nagios support in the prod_check module on /admin/config/system/prod-check
  by ticking the appropriate box.
-3. Untick the checboxes for those items you do not whish to be monitored by
+3. Untick the checkboxes for those items you do not whish to be monitored by
  Nagios.
 4. Save the settings and you're good to go!
 
@@ -172,7 +186,7 @@ For Production monitor, these commands are available:
   $ drush prod-monitor-fetch [id]
   $ drush prod-monitor-flush [id]
   $ drush prod-monitor-delete [id]
-  $ drush prod-monitor-updates [id] (--check)
+  $ drush prod-monitor-updates [id] (--check, --security-only)
 
 or their aliases:
 
@@ -180,7 +194,7 @@ or their aliases:
   $ drush pmon-fe [id]
   $ drush pmon-fl [id]
   $ drush pmon-rm [id]
-  $ drush pmon-up [id] (--check)
+  $ drush pmon-up [id] (--check, --security-only)
 
 The id parameter is optional for the prod-monitor command. The best usage is to
 first get a list of sites:
@@ -200,16 +214,19 @@ You can pass multiple ID's by separating them with spaces:
 
 The prod-monitor-updates command acts on one id only!
 
-APC
----
+APC/OPcache
+-----------
 Production Check complains about APC not being installed or misconfigured. What
 is APC you wonder? Well, APC is an opcode caching mechanism that will pre-com-
 pile PHP files and keep them stored in memory. The full manual can be found
 here: http://php.net/manual/en/book.apc.php .
-For Drupal sites, it is important to tune APC in order to achieve maximum per-
-formance there. Drupal uses a massive amount of files and therefore you should
-assign a proper amount of RAM to APC. For a dedicated setup 64Mb should be
-sufficient, in shared setups, you should easily double that!
+PHP version 5.5 comes bundled with an alternative to APC named OPcache. The full
+manual can be found here: http://php.net/manual/en/book.opcache.php .
+
+For Drupal sites, it is important to tune APC/OPcache in order to achieve
+maximum performance there. Drupal uses a massive amount of files and therefore
+you should assign a proper amount of RAM to APC/OPcache. For a dedicated setup
+64Mb should be sufficient, in shared setups, you will need to multiply that!
 To tune your setup, you can use the aforementioned hidden link provided by
 Production check. You can see the memory usage there, verify your settings and
 much more.
@@ -219,6 +236,7 @@ extension (drupal.org CVS did not seem to accept files with .ini extension?).
 
 Note: This 'hidden link' makes use of the APC supplied PHP code and is subject
 to the PHP license: http://www.php.net/license/3_01.txt .
+The OPcache variant is taken from https://github.com/rlerdorf/opcache-status .
 
 
 Updates
@@ -233,8 +251,8 @@ Cron is NOT used to do this, since we want to keep the transfer to a minimum.
 Hidden link
 ===========
 Production check adds some 'hidden links' to the site where you can check the
-APC, Memcache and DB status of your site. These pages can be found on:
-  /admin/reports/status/apc
+APC/OPcache, Memcache and DB status of your site. These pages can be found on:
+  /admin/reports/status/apc-opc
   /admin/reports/status/memcache
   /admin/reports/status/database
 
@@ -251,8 +269,8 @@ The detailed report page
 The page is divided into 4 sections:
 
  - Settings: checks various Drupal settings
- - Server: checks that are 'outside of Drupal' such as APC and wether or not you
-           have removed the release note files from the root.
+ - Server: checks that are 'outside of Drupal' such as APC/OPcache and wether or
+           not you have removed the release note files from the root.
  - Performance: checks relevant to the performance settings in Drupal such as
                 page / block caching.
  - Modules: checks if certain modules are on / off

+ 26 - 13
sites/all/modules/contrib/dev/prod_check/includes/prod_check.admin.inc

@@ -97,8 +97,8 @@ function prod_check_settings_form($form, &$form_state) {
 
   $form['prod_check_apc'] = array(
     '#type' => 'fieldset',
-    '#title' => t('Advanced APC settings'),
-    '#description' => t('These settings are used in the !link functionality.', prod_check_link_array('advanced APC', 'admin/reports/status/apc')),
+    '#title' => t('Advanced APC/OPcache settings'),
+    '#description' => t('These settings are used in the !link functionality.', prod_check_link_array('advanced APC', 'admin/reports/status/apc-opc')),
     '#collapsible' => TRUE,
     '#collapsed' => TRUE,
   );
@@ -106,7 +106,7 @@ function prod_check_settings_form($form, &$form_state) {
   // Cache full count threshold
   $form['prod_check_apc']['prod_check_apc_expunge'] = array(
     '#type' => 'textfield',
-    '#title' => t('APC cache full count threshold'),
+    '#title' => t('APC/OPcache cache full count threshold'),
     '#default_value' => variable_get('prod_check_apc_expunge', 0),
     '#size' => 2,
     '#description' => t('Issue a critical error when the cache full count is greater than the number entered here.'),
@@ -293,7 +293,7 @@ function prod_check_settings_form($form, &$form_state) {
             '!settings' => l(t('Nagios page callback'), 'admin/config/system/nagios'),
             '%callback' => 'prod_check_nagios_status_page',
           )
-        ) .'</p>',
+        ) . '</p>',
       );
 
       $form['prod_check_nagios']['nagios']['settings']['prod_check_nagios_verbose'] = array(
@@ -428,7 +428,7 @@ function prod_check_settings_form_validate($form, &$form_state) {
   }
 
   if (!is_numeric($form_state['values']['prod_check_apc_expunge'])) {
-    form_set_error('prod_check_apc_expunge', t('APC Cache full count threshold should be numeric!'));
+    form_set_error('prod_check_apc_expunge', t('APC/OPcache Cache full count threshold should be numeric!'));
   }
 
   if (isset($form_state['values']['prod_check_enable_nagios']) && $form_state['values']['prod_check_enable_nagios']) {
@@ -461,9 +461,11 @@ function prod_check_settings_form_submit($form, &$form_state) {
     case t('Save configuration'):
       variable_set('prod_check_sitemail', $form_state['values']['prod_check_sitemail']);
       // PHP errors.
-      variable_set('prod_check_dblog_php', $form_state['values']['prod_check_dblog_php']);
-      variable_set('prod_check_dblog_php_threshold', $form_state['values']['prod_check_dblog_php_threshold']);
-      // APC.
+      if (module_exists('dblog')) {
+        variable_set('prod_check_dblog_php', $form_state['values']['prod_check_dblog_php']);
+        variable_set('prod_check_dblog_php_threshold', $form_state['values']['prod_check_dblog_php_threshold']);
+      }
+      // APC/OPcache.
       variable_set('prod_check_apc_expunge', $form_state['values']['prod_check_apc_expunge']);
       variable_set('prod_check_apcuser', $form_state['values']['prod_check_apcuser']);
       if (!empty($form_state['values']['prod_check_apcpass'])) {
@@ -1031,11 +1033,22 @@ function _prod_check_dbstatus_pgsql($db_name, $details) {
 /**
  * Integration of the APC status page.
  */
-function prod_check_apc() {
-  define('ADMIN_USERNAME', variable_get('prod_check_apcuser', 'apc'));
-  define('ADMIN_PASSWORD', variable_get('prod_check_apcpass', 'password'));
-  include(drupal_get_path('module', 'prod_check') . '/includes/prod_check.apc.inc');
-  exit;
+function prod_check_apc_opc() {
+  // APC.
+  if (function_exists('apc_cache_info')) {
+    define('ADMIN_USERNAME', variable_get('prod_check_apcuser', 'apc'));
+    define('ADMIN_PASSWORD', variable_get('prod_check_apcpass', 'password'));
+    include(drupal_get_path('module', 'prod_check') . '/includes/prod_check.apc.inc');
+    exit;
+  }
+  // OPcache.
+  elseif (function_exists('opcache_get_status')) {
+    include(drupal_get_path('module', 'prod_check') . '/includes/prod_check.opcache.inc');
+    exit;
+  }
+  else {
+    return t('APC nor OPcache is installed on this webserver!');
+  }
 }
 
 /**

+ 502 - 0
sites/all/modules/contrib/dev/prod_check/includes/prod_check.opcache.data_sample.inc

@@ -0,0 +1,502 @@
+<?php
+function opcache_get_status() {
+	return array (
+		'opcache_enabled' => true,
+		'cache_full' => false,
+		'memory_usage' =>
+		array (
+			'used_memory' => 12028872,
+			'free_memory' => 4235696,
+			'wasted_memory' => 512648,
+			'current_wasted_percentage' => 3.0556201934814,
+		),
+		'opcache_statistics' =>
+		array (
+			'num_cached_scripts' => 59,
+			'num_cached_keys' => 78,
+			'max_cached_keys' => 223,
+			'hits' => 66817,
+			'last_restart_time' => 0,
+			'misses' => 126,
+			'blacklist_misses' => 0,
+			'blacklist_miss_ratio' => 0,
+			'opcache_hit_rate' => 99.81178017119,
+			'oom_restarts' => 0,
+			'manual_restarts' => 0,
+			'hash_restarts' => 0,
+		),
+		'scripts' =>
+		array (
+			'/var/www/phpweb/manual/en/toc/faq.inc' =>
+			array (
+				'full_path' => '/var/www/phpweb/manual/en/toc/faq.inc',
+				'hits' => 9,
+				'memory_consumption' => 5680,
+				'last_used' => 'Sat Mar 16 12:16:31 2013',
+				'last_used_timestamp' => 1363461391,
+				'timestamp' => 1363345905,
+			),
+			'/var/www/phpweb/downloads.php' =>
+			array (
+				'full_path' => '/var/www/phpweb/downloads.php',
+				'hits' => 86,
+				'memory_consumption' => 9488,
+				'last_used' => 'Sat Mar 16 12:03:47 2013',
+				'last_used_timestamp' => 1363460627,
+				'timestamp' => 1355102402,
+			),
+			'/var/www/phpweb/include/languages.inc' =>
+			array (
+				'full_path' => '/var/www/phpweb/include/languages.inc',
+				'hits' => 5605,
+				'memory_consumption' => 16984,
+				'last_used' => 'Sat Mar 16 12:16:31 2013',
+				'last_used_timestamp' => 1363461391,
+				'timestamp' => 1362994804,
+			),
+			'/var/www/phpweb/include/header.inc' =>
+			array (
+				'full_path' => '/var/www/phpweb/include/header.inc',
+				'hits' => 9,
+				'memory_consumption' => 20352,
+				'last_used' => 'Sat Mar 16 12:16:31 2013',
+				'last_used_timestamp' => 1363461391,
+				'timestamp' => 1357938001,
+			),
+			'/var/www/phpweb/manual/en/toc/getting-started.inc' =>
+			array (
+				'full_path' => '/var/www/phpweb/manual/en/toc/getting-started.inc',
+				'hits' => 9,
+				'memory_consumption' => 1936,
+				'last_used' => 'Sat Mar 16 12:16:31 2013',
+				'last_used_timestamp' => 1363461391,
+				'timestamp' => 1363345409,
+			),
+			'/var/www/phpweb/manual/en/faq.php' =>
+			array (
+				'full_path' => '/var/www/phpweb/manual/en/faq.php',
+				'hits' => 122,
+				'memory_consumption' => 5152,
+				'last_used' => 'Sat Mar 16 12:06:15 2013',
+				'last_used_timestamp' => 1363460775,
+				'timestamp' => 1363345906,
+			),
+			'/var/www/phpweb/include/footer.inc' =>
+			array (
+				'full_path' => '/var/www/phpweb/include/footer.inc',
+				'hits' => 9,
+				'memory_consumption' => 1976,
+				'last_used' => 'Sat Mar 16 12:16:31 2013',
+				'last_used_timestamp' => 1363461391,
+				'timestamp' => 1347648001,
+			),
+			'/var/www/phpweb/include/site.inc' =>
+			array (
+				'full_path' => '/var/www/phpweb/include/site.inc',
+				'hits' => 5605,
+				'memory_consumption' => 63488,
+				'last_used' => 'Sat Mar 16 12:16:31 2013',
+				'last_used_timestamp' => 1363461391,
+				'timestamp' => 1354724402,
+			),
+			'/var/www/phpweb/include/mirrors.inc' =>
+			array (
+				'full_path' => '/var/www/phpweb/include/mirrors.inc',
+				'hits' => 5605,
+				'memory_consumption' => 96160,
+				'last_used' => 'Sat Mar 16 12:16:31 2013',
+				'last_used_timestamp' => 1363461391,
+				'timestamp' => 1363419613,
+			),
+			'/var/www/phpweb/manual/en/toc/refs.basic.vartype.inc' =>
+			array (
+				'full_path' => '/var/www/phpweb/manual/en/toc/refs.basic.vartype.inc',
+				'hits' => 9,
+				'memory_consumption' => 5032,
+				'last_used' => 'Sat Mar 16 12:16:31 2013',
+				'last_used_timestamp' => 1363461391,
+				'timestamp' => 1363345844,
+			),
+			'/var/www/phpweb/include/layout.inc' =>
+			array (
+				'full_path' => '/var/www/phpweb/include/layout.inc',
+				'hits' => 5605,
+				'memory_consumption' => 145704,
+				'last_used' => 'Sat Mar 16 12:16:31 2013',
+				'last_used_timestamp' => 1363461391,
+				'timestamp' => 1356610801,
+			),
+			'/var/www/phpweb/sites.php' =>
+			array (
+				'full_path' => '/var/www/phpweb/sites.php',
+				'hits' => 73,
+				'memory_consumption' => 2024,
+				'last_used' => 'Sat Mar 16 12:10:10 2013',
+				'last_used_timestamp' => 1363461010,
+				'timestamp' => 1354724402,
+			),
+			'/var/www/phpweb/search.php' =>
+			array (
+				'full_path' => '/var/www/phpweb/search.php',
+				'hits' => 3083,
+				'memory_consumption' => 19728,
+				'last_used' => 'Sat Mar 16 12:16:31 2013',
+				'last_used_timestamp' => 1363461391,
+				'timestamp' => 1347648005,
+			),
+			'/var/www/phpweb/manual/en/toc/langref.inc' =>
+			array (
+				'full_path' => '/var/www/phpweb/manual/en/toc/langref.inc',
+				'hits' => 49,
+				'memory_consumption' => 7416,
+				'last_used' => 'Sat Mar 16 12:16:31 2013',
+				'last_used_timestamp' => 1363461391,
+				'timestamp' => 1363345411,
+			),
+			'/var/www/phpweb/manual/en/toc/index.inc' =>
+			array (
+				'full_path' => '/var/www/phpweb/manual/en/toc/index.inc',
+				'hits' => 132,
+				'memory_consumption' => 4680,
+				'last_used' => 'Sat Mar 16 12:16:31 2013',
+				'last_used_timestamp' => 1363461391,
+				'timestamp' => 1363345409,
+			),
+			'/var/www/phpweb/docs.php' =>
+			array (
+				'full_path' => '/var/www/phpweb/docs.php',
+				'hits' => 73,
+				'memory_consumption' => 4536,
+				'last_used' => 'Sat Mar 16 12:04:36 2013',
+				'last_used_timestamp' => 1363460676,
+				'timestamp' => 1347648000,
+			),
+			'/var/www/phpweb/include/shared-manual.inc' =>
+			array (
+				'full_path' => '/var/www/phpweb/include/shared-manual.inc',
+				'hits' => 122,
+				'memory_consumption' => 107688,
+				'last_used' => 'Sat Mar 16 12:06:15 2013',
+				'last_used_timestamp' => 1363460775,
+				'timestamp' => 1357938001,
+			),
+			'/var/www/phpweb/include/mozopensearch.inc' =>
+			array (
+				'full_path' => '/var/www/phpweb/include/mozopensearch.inc',
+				'hits' => 14,
+				'memory_consumption' => 1232,
+				'last_used' => 'Sat Mar 16 12:00:34 2013',
+				'last_used_timestamp' => 1363460434,
+				'timestamp' => 1347648001,
+			),
+			'/var/www/phpweb/include/ip-to-country.inc' =>
+			array (
+				'full_path' => '/var/www/phpweb/include/ip-to-country.inc',
+				'hits' => 5605,
+				'memory_consumption' => 21840,
+				'last_used' => 'Sat Mar 16 12:16:31 2013',
+				'last_used_timestamp' => 1363461391,
+				'timestamp' => 1347648001,
+			),
+			'/var/www/phpweb/include/version.inc' =>
+			array (
+				'full_path' => '/var/www/phpweb/include/version.inc',
+				'hits' => 775,
+				'memory_consumption' => 7880,
+				'last_used' => 'Sat Mar 16 12:16:31 2013',
+				'last_used_timestamp' => 1363461391,
+				'timestamp' => 1363321202,
+			),
+			'/var/www/phpweb/include/errors.inc' =>
+			array (
+				'full_path' => '/var/www/phpweb/include/errors.inc',
+				'hits' => 691,
+				'memory_consumption' => 59888,
+				'last_used' => 'Sat Mar 16 12:10:33 2013',
+				'last_used_timestamp' => 1363461033,
+				'timestamp' => 1347648001,
+			),
+			'/var/www/phpweb/include/countries.inc' =>
+			array (
+				'full_path' => '/var/www/phpweb/include/countries.inc',
+				'hits' => 5605,
+				'memory_consumption' => 31184,
+				'last_used' => 'Sat Mar 16 12:16:31 2013',
+				'last_used_timestamp' => 1363461391,
+				'timestamp' => 1363419614,
+			),
+			'/var/www/phpweb/error.php' =>
+			array (
+				'full_path' => '/var/www/phpweb/error.php',
+				'hits' => 691,
+				'memory_consumption' => 61952,
+				'last_used' => 'Sat Mar 16 12:10:33 2013',
+				'last_used_timestamp' => 1363461033,
+				'timestamp' => 1347648000,
+			),
+			'/var/www/phpweb/manual/en/toc/refs.basic.text.inc' =>
+			array (
+				'full_path' => '/var/www/phpweb/manual/en/toc/refs.basic.text.inc',
+				'hits' => 9,
+				'memory_consumption' => 3312,
+				'last_used' => 'Sat Mar 16 12:16:31 2013',
+				'last_used_timestamp' => 1363461391,
+				'timestamp' => 1363345831,
+			),
+			'/var/www/phpweb/include/loadavg.inc' =>
+			array (
+				'full_path' => '/var/www/phpweb/include/loadavg.inc',
+				'hits' => 3775,
+				'memory_consumption' => 12184,
+				'last_used' => 'Sat Mar 16 12:16:31 2013',
+				'last_used_timestamp' => 1363461391,
+				'timestamp' => 1354738801,
+			),
+			'/var/www/phpweb/include/prepend.inc' =>
+			array (
+				'full_path' => '/var/www/phpweb/include/prepend.inc',
+				'hits' => 5605,
+				'memory_consumption' => 23432,
+				'last_used' => 'Sat Mar 16 12:16:31 2013',
+				'last_used_timestamp' => 1363461391,
+				'timestamp' => 1347648001,
+			),
+			'/var/www/phpweb/o.php' =>
+			array (
+				'full_path' => '/var/www/phpweb/o.php',
+				'hits' => 1,
+				'memory_consumption' => 13424,
+				'last_used' => 'Sat Mar 16 18:11:21 2013',
+				'last_used_timestamp' => 1363482681,
+				'timestamp' => 1363482654,
+			),
+			'/var/www/phpweb/include/pregen-events.inc' =>
+			array (
+				'full_path' => '/var/www/phpweb/include/pregen-events.inc',
+				'hits' => 1141,
+				'memory_consumption' => 840,
+				'last_used' => 'Sat Mar 16 12:15:07 2013',
+				'last_used_timestamp' => 1363461307,
+				'timestamp' => 1363419615,
+			),
+			'/var/www/phpweb/opcache.php' =>
+			array (
+				'full_path' => '/var/www/phpweb/opcache.php',
+				'hits' => 0,
+				'memory_consumption' => 13944,
+				'last_used' => 'Sun Mar 17 01:22:31 2013',
+				'last_used_timestamp' => 1363508551,
+				'timestamp' => 1363508542,
+			),
+			'/var/www/phpweb/manual/en/toc/refs.calendar.inc' =>
+			array (
+				'full_path' => '/var/www/phpweb/manual/en/toc/refs.calendar.inc',
+				'hits' => 9,
+				'memory_consumption' => 2264,
+				'last_used' => 'Sat Mar 16 12:16:31 2013',
+				'last_used_timestamp' => 1363461391,
+				'timestamp' => 1363345437,
+			),
+			'/var/www/phpweb/manual/en/toc/security.inc' =>
+			array (
+				'full_path' => '/var/www/phpweb/manual/en/toc/security.inc',
+				'hits' => 19,
+				'memory_consumption' => 5352,
+				'last_used' => 'Sat Mar 16 12:16:31 2013',
+				'last_used_timestamp' => 1363461391,
+				'timestamp' => 1363345419,
+			),
+			'/var/www/phpweb/include/pregen-news.inc' =>
+			array (
+				'full_path' => '/var/www/phpweb/include/pregen-news.inc',
+				'hits' => 1161,
+				'memory_consumption' => 57896,
+				'last_used' => 'Sat Mar 16 12:16:31 2013',
+				'last_used_timestamp' => 1363461391,
+				'timestamp' => 1363419615,
+			),
+			'/var/www/phpweb/my.php' =>
+			array (
+				'full_path' => '/var/www/phpweb/my.php',
+				'hits' => 34,
+				'memory_consumption' => 22640,
+				'last_used' => 'Sat Mar 16 12:15:15 2013',
+				'last_used_timestamp' => 1363461315,
+				'timestamp' => 1354724402,
+			),
+			'/var/www/phpweb/include/pregen-confs.inc' =>
+			array (
+				'full_path' => '/var/www/phpweb/include/pregen-confs.inc',
+				'hits' => 678,
+				'memory_consumption' => 1400,
+				'last_used' => 'Sat Mar 16 12:02:49 2013',
+				'last_used_timestamp' => 1363460569,
+				'timestamp' => 1363419615,
+			),
+			'/var/www/index.php' =>
+			array (
+				'full_path' => '/var/www/index.php',
+				'hits' => 1,
+				'memory_consumption' => 744,
+				'last_used' => 'Sat Mar 16 12:01:20 2013',
+				'last_used_timestamp' => 1363460480,
+				'timestamp' => 1358644238,
+			),
+			'/var/www/phpweb/index-stable.php' =>
+			array (
+				'full_path' => '/var/www/phpweb/index-stable.php',
+				'hits' => 679,
+				'memory_consumption' => 22208,
+				'last_used' => 'Sat Mar 16 12:02:49 2013',
+				'last_used_timestamp' => 1363460569,
+				'timestamp' => 1347648003,
+			),
+			'/var/www/phpweb/conferences/index.php' =>
+			array (
+				'full_path' => '/var/www/phpweb/conferences/index.php',
+				'hits' => 462,
+				'memory_consumption' => 3872,
+				'last_used' => 'Sat Mar 16 12:15:07 2013',
+				'last_used_timestamp' => 1363461307,
+				'timestamp' => 1347648000,
+			),
+			'/var/www/phpweb/support.php' =>
+			array (
+				'full_path' => '/var/www/phpweb/support.php',
+				'hits' => 73,
+				'memory_consumption' => 1912,
+				'last_used' => 'Sat Mar 16 12:06:40 2013',
+				'last_used_timestamp' => 1363460800,
+				'timestamp' => 1347648005,
+			),
+			'/var/www/phpweb/op.php' =>
+			array (
+				'full_path' => '/var/www/phpweb/op.php',
+				'hits' => 0,
+				'memory_consumption' => 1448,
+				'last_used' => 'Sun Mar 17 01:34:33 2013',
+				'last_used_timestamp' => 1363509273,
+				'timestamp' => 1363509263,
+			),
+			'/var/www/phpweb/include/posttohost.inc' =>
+			array (
+				'full_path' => '/var/www/phpweb/include/posttohost.inc',
+				'hits' => 342,
+				'memory_consumption' => 3824,
+				'last_used' => 'Sat Mar 16 12:09:18 2013',
+				'last_used_timestamp' => 1363460958,
+				'timestamp' => 1347648001,
+			),
+			'/var/www/phpweb/include/langchooser.inc' =>
+			array (
+				'full_path' => '/var/www/phpweb/include/langchooser.inc',
+				'hits' => 5605,
+				'memory_consumption' => 23784,
+				'last_used' => 'Sat Mar 16 12:16:31 2013',
+				'last_used_timestamp' => 1363461391,
+				'timestamp' => 1347648001,
+			),
+			'/var/www/phpweb/include/manual-lookup.inc' =>
+			array (
+				'full_path' => '/var/www/phpweb/include/manual-lookup.inc',
+				'hits' => 624,
+				'memory_consumption' => 26648,
+				'last_used' => 'Sat Mar 16 12:10:33 2013',
+				'last_used_timestamp' => 1363461033,
+				'timestamp' => 1354750802,
+			),
+			'/var/www/phpweb/mailing-lists.php' =>
+			array (
+				'full_path' => '/var/www/phpweb/mailing-lists.php',
+				'hits' => 342,
+				'memory_consumption' => 31576,
+				'last_used' => 'Sat Mar 16 12:09:18 2013',
+				'last_used_timestamp' => 1363460958,
+				'timestamp' => 1361200802,
+			),
+			'/var/www/phpweb/include/last_updated.inc' =>
+			array (
+				'full_path' => '/var/www/phpweb/include/last_updated.inc',
+				'hits' => 5605,
+				'memory_consumption' => 840,
+				'last_used' => 'Sat Mar 16 12:16:31 2013',
+				'last_used_timestamp' => 1363461391,
+				'timestamp' => 1363419675,
+			),
+			'/var/www/phpweb/include/email-validation.inc' =>
+			array (
+				'full_path' => '/var/www/phpweb/include/email-validation.inc',
+				'hits' => 342,
+				'memory_consumption' => 9168,
+				'last_used' => 'Sat Mar 16 12:09:18 2013',
+				'last_used_timestamp' => 1363460958,
+				'timestamp' => 1362175205,
+			),
+			'/var/www/phpweb/index.php' =>
+			array (
+				'full_path' => '/var/www/phpweb/index.php',
+				'hits' => 679,
+				'memory_consumption' => 1840,
+				'last_used' => 'Sat Mar 16 12:02:49 2013',
+				'last_used_timestamp' => 1363460569,
+				'timestamp' => 1347648003,
+			),
+		),
+	);
+}
+
+function opcache_get_configuration() {
+	return array (
+		'directives' =>
+		array (
+			'opcache.enable' => true,
+			'opcache.enable_cli' => false,
+			'opcache.use_cwd' => true,
+			'opcache.validate_timestamps' => true,
+			'opcache.inherited_hack' => true,
+			'opcache.dups_fix' => false,
+			'opcache.revalidate_path' => false,
+			'opcache.log_verbosity_level' => 4,
+			'opcache.memory_consumption' => 16777216,
+			'opcache.interned_strings_buffer' => 8,
+			'opcache.max_accelerated_files' => 200,
+			'opcache.max_wasted_percentage' => 0.05,
+			'opcache.consistency_checks' => 0,
+			'opcache.force_restart_timeout' => 180,
+			'opcache.revalidate_freq' => 0,
+			'opcache.preferred_memory_model' => '',
+			'opcache.blacklist_filename' => '/etc/zo_blacklist.txt',
+			'opcache.max_file_size' => 0,
+			'opcache.error_log' => '',
+			'opcache.protect_memory' => false,
+			'opcache.save_comments' => true,
+			'opcache.load_comments' => true,
+			'opcache.fast_shutdown' => true,
+			'opcache.enable_file_override' => false,
+			'opcache.optimization_level' => 4294967295,
+		),
+		'version' =>
+		array (
+			'version' => '7.0.1-dev',
+			'opcache_product_name' => 'Zend Optimizer+',
+		),
+		'blacklist' =>
+		array (
+			0 => '/var/www/www.php.net/manual/es',
+			1 => '/var/www/www.php.net/manual/it',
+			2 => '/var/www/www.php.net/manual/bg',
+			3 => '/var/www/www.php.net/manual/fa',
+			4 => '/var/www/www.php.net/manual/fr',
+			5 => '/var/www/www.php.net/manual/kr',
+			6 => '/var/www/www.php.net/manual/pt_BR',
+			7 => '/var/www/www.php.net/manual/tr',
+			8 => '/var/www/www.php.net/manual/de',
+			9 => '/var/www/www.php.net/manual/ro',
+			10 => '/var/www/www.php.net/manual/ru',
+			11 => '/var/www/www.php.net/manual/zh',
+			12 => '/var/www/www.php.net/manual/ja',
+			13 => '/var/www/www.php.net/manual/pl',
+			14 => '/var/www/www.php.net/manual/sr',
+		),
+	);
+}

+ 748 - 0
sites/all/modules/contrib/dev/prod_check/includes/prod_check.opcache.inc

@@ -0,0 +1,748 @@
+<?php
+
+/**
+ * Taken from https://github.com/rlerdorf/opcache-status
+ */
+
+define('THOUSAND_SEPARATOR',true);
+
+if (!extension_loaded('Zend OPcache')) {
+    echo '<div style="background-color: #F2DEDE; color: #B94A48; padding: 1em;">You do not have the Zend OPcache extension loaded, sample data is being shown instead.</div>';
+    require 'prod_check.opcache.data_sample.inc';
+}
+
+class OpCacheDataModel
+{
+    private $_configuration;
+    private $_status;
+    private $_d3Scripts = array();
+
+    public function __construct()
+    {
+        $this->_configuration = opcache_get_configuration();
+        $this->_status = opcache_get_status();
+    }
+
+    public function getPageTitle()
+    {
+        return 'PHP ' . phpversion() . " with OpCache {$this->_configuration['version']['version']}";
+    }
+
+    public function getStatusDataRows()
+    {
+        $rows = array();
+        foreach ($this->_status as $key => $value) {
+            if ($key === 'scripts') {
+                continue;
+            }
+
+            if (is_array($value)) {
+                foreach ($value as $k => $v) {
+                    if ($v === false) {
+                        $value = 'false';
+                    }
+                    if ($v === true) {
+                        $value = 'true';
+                    }
+                    if ($k === 'used_memory' || $k === 'free_memory' || $k === 'wasted_memory') {
+                        $v = $this->_size_for_humans(
+                            $v
+                        );
+                    }
+                    if ($k === 'current_wasted_percentage' || $k === 'opcache_hit_rate') {
+                        $v = number_format(
+                                $v,
+                                2
+                            ) . '%';
+                    }
+                    if ($k === 'blacklist_miss_ratio') {
+                        $v = number_format($v, 2) . '%';
+                    }
+                    if ($k === 'start_time' || $k === 'last_restart_time') {
+                        $v = ($v ? date(DATE_RFC822, $v) : 'never');
+                    }
+                    if (THOUSAND_SEPARATOR === true && is_int($v)) {
+                        $v = number_format($v);
+                    }
+
+                    $rows[] = "<tr><th>$k</th><td>$v</td></tr>\n";
+                }
+                continue;
+            }
+            if ($value === false) {
+                $value = 'false';
+            }
+            if ($value === true) {
+                $value = 'true';
+            }
+            $rows[] = "<tr><th>$key</th><td>$value</td></tr>\n";
+        }
+
+        return implode("\n", $rows);
+    }
+
+    public function getConfigDataRows()
+    {
+        $rows = array();
+        foreach ($this->_configuration['directives'] as $key => $value) {
+            if ($value === false) {
+                $value = 'false';
+            }
+            if ($value === true) {
+                $value = 'true';
+            }
+            if ($key == 'opcache.memory_consumption') {
+                $value = $this->_size_for_humans($value);
+            }
+            $rows[] = "<tr><th>$key</th><td>$value</td></tr>\n";
+        }
+
+        return implode("\n", $rows);
+    }
+
+    public function getScriptStatusRows()
+    {
+        foreach ($this->_status['scripts'] as $key => $data) {
+            $dirs[dirname($key)][basename($key)] = $data;
+            $this->_arrayPset($this->_d3Scripts, $key, array(
+                'name' => basename($key),
+                'size' => $data['memory_consumption'],
+            ));
+        }
+
+        asort($dirs);
+
+        $basename = '';
+        while (true) {
+            if (count($this->_d3Scripts) !=1) break;
+            $basename .= DIRECTORY_SEPARATOR . key($this->_d3Scripts);
+            $this->_d3Scripts = reset($this->_d3Scripts);
+        }
+
+        $this->_d3Scripts = $this->_processPartition($this->_d3Scripts, $basename);
+        $id = 1;
+
+        $rows = array();
+        foreach ($dirs as $dir => $files) {
+            $count = count($files);
+            $file_plural = $count > 1 ? 's' : null;
+            $m = 0;
+            foreach ($files as $file => $data) {
+                $m += $data["memory_consumption"];
+            }
+            $m = $this->_size_for_humans($m);
+
+            if ($count > 1) {
+                $rows[] = '<tr>';
+                $rows[] = "<th class=\"clickable\" id=\"head-{$id}\" colspan=\"3\" onclick=\"toggleVisible('#head-{$id}', '#row-{$id}')\">{$dir} ({$count} file{$file_plural}, {$m})</th>";
+                $rows[] = '</tr>';
+            }
+
+            foreach ($files as $file => $data) {
+                $rows[] = "<tr id=\"row-{$id}\">";
+                $rows[] = "<td>" . $this->_format_value($data["hits"]) . "</td>";
+                $rows[] = "<td>" . $this->_size_for_humans($data["memory_consumption"]) . "</td>";
+                $rows[] = $count > 1 ? "<td>{$file}</td>" : "<td>{$dir}/{$file}</td>";
+                $rows[] = '</tr>';
+            }
+
+            ++$id;
+        }
+
+        return implode("\n", $rows);
+    }
+
+    public function getScriptStatusCount()
+    {
+        return count($this->_status["scripts"]);
+    }
+
+    public function getGraphDataSetJson()
+    {
+        $dataset = array();
+        $dataset['memory'] = array(
+            $this->_status['memory_usage']['used_memory'],
+            $this->_status['memory_usage']['free_memory'],
+            $this->_status['memory_usage']['wasted_memory'],
+        );
+
+        $dataset['keys'] = array(
+            $this->_status['opcache_statistics']['num_cached_keys'],
+            $this->_status['opcache_statistics']['max_cached_keys'] - $this->_status['opcache_statistics']['num_cached_keys'],
+            0
+        );
+
+        $dataset['hits'] = array(
+            $this->_status['opcache_statistics']['misses'],
+            $this->_status['opcache_statistics']['hits'],
+            0,
+        );
+
+        $dataset['restarts'] = array(
+            $this->_status['opcache_statistics']['oom_restarts'],
+            $this->_status['opcache_statistics']['manual_restarts'],
+            $this->_status['opcache_statistics']['hash_restarts'],
+        );
+
+        if (THOUSAND_SEPARATOR === true) {
+            $dataset['TSEP'] = 1;
+        } else {
+            $dataset['TSEP'] = 0;
+        }
+
+        return json_encode($dataset);
+    }
+
+    public function getHumanUsedMemory()
+    {
+        return $this->_size_for_humans($this->getUsedMemory());
+    }
+
+    public function getHumanFreeMemory()
+    {
+        return $this->_size_for_humans($this->getFreeMemory());
+    }
+
+    public function getHumanWastedMemory()
+    {
+        return $this->_size_for_humans($this->getWastedMemory());
+    }
+
+    public function getUsedMemory()
+    {
+        return $this->_status['memory_usage']['used_memory'];
+    }
+
+    public function getFreeMemory()
+    {
+        return $this->_status['memory_usage']['free_memory'];
+    }
+
+    public function getWastedMemory()
+    {
+        return $this->_status['memory_usage']['wasted_memory'];
+    }
+
+    public function getWastedMemoryPercentage()
+    {
+        return number_format($this->_status['memory_usage']['current_wasted_percentage'], 2);
+    }
+
+    public function getD3Scripts()
+    {
+        return $this->_d3Scripts;
+    }
+
+    private function _processPartition($value, $name = null)
+    {
+        if (array_key_exists('size', $value)) {
+            return $value;
+        }
+
+        $array = array('name' => $name,'children' => array());
+
+        foreach ($value as $k => $v) {
+            $array['children'][] = $this->_processPartition($v, $k);
+        }
+
+        return $array;
+    }
+
+    private function _format_value($value)
+    {
+        if (THOUSAND_SEPARATOR === true) {
+            return number_format($value);
+        } else {
+            return $value;
+        }
+    }
+
+    private function _size_for_humans($bytes)
+    {
+        if ($bytes > 1048576) {
+            return sprintf('%.2f&nbsp;MB', $bytes / 1048576);
+        } else {
+            if ($bytes > 1024) {
+                return sprintf('%.2f&nbsp;kB', $bytes / 1024);
+            } else {
+                return sprintf('%d&nbsp;bytes', $bytes);
+            }
+        }
+    }
+
+    // Borrowed from Laravel
+    private function _arrayPset(&$array, $key, $value)
+    {
+        if (is_null($key)) return $array = $value;
+        $keys = explode(DIRECTORY_SEPARATOR, ltrim($key, DIRECTORY_SEPARATOR));
+        while (count($keys) > 1) {
+            $key = array_shift($keys);
+            if ( ! isset($array[$key]) || ! is_array($array[$key])) {
+                $array[$key] = array();
+            }
+            $array =& $array[$key];
+        }
+        $array[array_shift($keys)] = $value;
+        return $array;
+    }
+
+}
+
+$dataModel = new OpCacheDataModel();
+?>
+<!DOCTYPE html>
+<meta charset="utf-8">
+<html>
+<head>
+    <style>
+        body {
+            font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
+            margin: 0;
+            padding: 0;
+        }
+
+        #container {
+            width: 1024px;
+            margin: auto;
+            position: relative;
+        }
+
+        h1 {
+            padding: 10px 0;
+        }
+
+        table {
+            border-collapse: collapse;
+        }
+
+        tbody tr:nth-child(even) {
+            background-color: #eee;
+        }
+
+        p.capitalize {
+            text-transform: capitalize;
+        }
+
+        .tabs {
+            position: relative;
+            float: left;
+            width: 60%;
+        }
+
+        .tab {
+            float: left;
+        }
+
+        .tab label {
+            background: #eee;
+            padding: 10px 12px;
+            border: 1px solid #ccc;
+            margin-left: -1px;
+            position: relative;
+            left: 1px;
+        }
+
+        .tab [type=radio] {
+            display: none;
+        }
+
+        .tab th, .tab td {
+            padding: 8px 12px;
+        }
+
+        .content {
+            position: absolute;
+            top: 28px;
+            left: 0;
+            background: white;
+            border: 1px solid #ccc;
+            height: 450px;
+            width: 100%;
+            overflow: auto;
+        }
+
+        .content table {
+            width: 100%;
+        }
+
+        .content th, .tab:nth-child(3) td {
+            text-align: left;
+        }
+
+        .content td {
+            text-align: right;
+        }
+
+        .clickable {
+            cursor: pointer;
+        }
+
+        [type=radio]:checked ~ label {
+            background: white;
+            border-bottom: 1px solid white;
+            z-index: 2;
+        }
+
+        [type=radio]:checked ~ label ~ .content {
+            z-index: 1;
+        }
+
+        #graph {
+            float: right;
+            width: 40%;
+            position: relative;
+        }
+
+        #graph > form {
+            position: absolute;
+            right: 60px;
+            top: -20px;
+        }
+
+        #graph > svg {
+            position: absolute;
+            top: 0;
+            right: 0;
+        }
+
+        #stats {
+            position: absolute;
+            right: 125px;
+            top: 145px;
+        }
+
+        #stats th, #stats td {
+            padding: 6px 10px;
+            font-size: 0.8em;
+        }
+
+        #partition {
+            position: absolute;
+            width: 100%;
+            height: 100%;
+            z-index: 10;
+            top: 0;
+            left: 0;
+            background: #ddd;
+            display: none;
+        }
+
+        #close-partition {
+            display: none;
+            position: absolute;
+            z-index: 20;
+            right: 15px;
+            top: 15px;
+            background: #f9373d;
+            color: #fff;
+            padding: 12px 15px;
+        }
+
+        #close-partition:hover {
+            background: #D32F33;
+            cursor: pointer;
+        }
+
+        #partition rect {
+            stroke: #fff;
+            fill: #aaa;
+            fill-opacity: 1;
+        }
+
+        #partition rect.parent {
+            cursor: pointer;
+            fill: steelblue;
+        }
+
+        #partition text {
+            pointer-events: none;
+        }
+
+        label {
+            cursor: pointer;
+        }
+    </style>
+    <script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.0.1/d3.v3.min.js"></script>
+    <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
+    <script>
+        var hidden = {};
+        function toggleVisible(head, row) {
+            if (!hidden[row]) {
+                d3.selectAll(row).transition().style('display', 'none');
+                hidden[row] = true;
+                d3.select(head).transition().style('color', '#ccc');
+            } else {
+                d3.selectAll(row).transition().style('display');
+                hidden[row] = false;
+                d3.select(head).transition().style('color', '#000');
+            }
+        }
+    </script>
+    <title><?php echo $dataModel->getPageTitle(); ?></title>
+</head>
+
+<body>
+    <div id="container">
+        <h1><?php echo $dataModel->getPageTitle(); ?></h1>
+
+        <div class="tabs">
+
+            <div class="tab">
+                <input type="radio" id="tab-status" name="tab-group-1" checked>
+                <label for="tab-status">Status</label>
+                <div class="content">
+                    <table>
+                        <?php echo $dataModel->getStatusDataRows(); ?>
+                    </table>
+                </div>
+            </div>
+
+            <div class="tab">
+                <input type="radio" id="tab-config" name="tab-group-1">
+                <label for="tab-config">Configuration</label>
+                <div class="content">
+                    <table>
+                        <?php echo $dataModel->getConfigDataRows(); ?>
+                    </table>
+                </div>
+            </div>
+
+            <div class="tab">
+                <input type="radio" id="tab-scripts" name="tab-group-1">
+                <label for="tab-scripts">Scripts (<?php echo $dataModel->getScriptStatusCount(); ?>)</label>
+                <div class="content">
+                    <table style="font-size:0.8em;">
+                        <tr>
+                            <th width="10%">Hits</th>
+                            <th width="20%">Memory</th>
+                            <th width="70%">Path</th>
+                        </tr>
+                        <?php echo $dataModel->getScriptStatusRows(); ?>
+                    </table>
+                </div>
+            </div>
+
+            <div class="tab">
+                <input type="radio" id="tab-visualise" name="tab-group-1">
+                <label for="tab-visualise">Visualise Partition</label>
+                <div class="content"></div>
+            </div>
+
+        </div>
+
+        <div id="graph">
+            <form>
+                <label><input type="radio" name="dataset" value="memory" checked> Memory</label>
+                <label><input type="radio" name="dataset" value="keys"> Keys</label>
+                <label><input type="radio" name="dataset" value="hits"> Hits</label>
+                <label><input type="radio" name="dataset" value="restarts"> Restarts</label>
+            </form>
+
+            <div id="stats"></div>
+        </div>
+    </div>
+
+    <div id="close-partition">&#10006; Close Visualisation</div>
+    <div id="partition"></div>
+
+    <script>
+        var dataset = <?php echo $dataModel->getGraphDataSetJson(); ?>;
+
+        var width = 400,
+            height = 400,
+            radius = Math.min(width, height) / 2,
+            colours = ['#B41F1F', '#1FB437', '#ff7f0e'];
+
+        d3.scale.customColours = function() {
+            return d3.scale.ordinal().range(colours);
+        };
+
+        var colour = d3.scale.customColours();
+        var pie = d3.layout.pie().sort(null);
+
+        var arc = d3.svg.arc().innerRadius(radius - 20).outerRadius(radius - 50);
+        var svg = d3.select("#graph").append("svg")
+                    .attr("width", width)
+                    .attr("height", height)
+                    .append("g")
+                    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
+
+        var path = svg.selectAll("path")
+                      .data(pie(dataset.memory))
+                      .enter().append("path")
+                      .attr("fill", function(d, i) { return colour(i); })
+                      .attr("d", arc)
+                      .each(function(d) { this._current = d; }); // store the initial values
+
+        d3.selectAll("input").on("change", change);
+        set_text("memory");
+
+        function set_text(t) {
+            if (t === "memory") {
+                d3.select("#stats").html(
+                    "<table><tr><th style='background:#B41F1F;'>Used</th><td><?php echo $dataModel->getHumanUsedMemory()?></td></tr>"+
+                    "<tr><th style='background:#1FB437;'>Free</th><td><?php echo $dataModel->getHumanFreeMemory()?></td></tr>"+
+                    "<tr><th style='background:#ff7f0e;' rowspan=\"2\">Wasted</th><td><?php echo $dataModel->getHumanWastedMemory()?></td></tr>"+
+                    "<tr><td><?php echo $dataModel->getWastedMemoryPercentage()?>%</td></tr></table>"
+                );
+            } else if (t === "keys") {
+                d3.select("#stats").html(
+                    "<table><tr><th style='background:#B41F1F;'>Cached keys</th><td>"+format_value(dataset[t][0])+"</td></tr>"+
+                    "<tr><th style='background:#1FB437;'>Free Keys</th><td>"+format_value(dataset[t][1])+"</td></tr></table>"
+                );
+            } else if (t === "hits") {
+                d3.select("#stats").html(
+                    "<table><tr><th style='background:#B41F1F;'>Misses</th><td>"+format_value(dataset[t][0])+"</td></tr>"+
+                    "<tr><th style='background:#1FB437;'>Cache Hits</th><td>"+format_value(dataset[t][1])+"</td></tr></table>"
+                );
+            } else if (t === "restarts") {
+                d3.select("#stats").html(
+                    "<table><tr><th style='background:#B41F1F;'>Memory</th><td>"+dataset[t][0]+"</td></tr>"+
+                    "<tr><th style='background:#1FB437;'>Manual</th><td>"+dataset[t][1]+"</td></tr>"+
+                    "<tr><th style='background:#ff7f0e;'>Keys</th><td>"+dataset[t][2]+"</td></tr></table>"
+                );
+            }
+        }
+
+        function change() {
+            // Filter out any zero values to see if there is anything left
+            var remove_zero_values = dataset[this.value].filter(function(value) {
+                return value > 0;
+            });
+
+            // Skip if the value is undefined for some reason
+            if (typeof dataset[this.value] !== 'undefined' && remove_zero_values.length > 0) {
+                $('#graph').find('> svg').show();
+                path = path.data(pie(dataset[this.value])); // update the data
+                path.transition().duration(750).attrTween("d", arcTween); // redraw the arcs
+            // Hide the graph if we can't draw it correctly, not ideal but this works
+            } else {
+                $('#graph').find('> svg').hide();
+            }
+
+            set_text(this.value);
+        }
+
+        function arcTween(a) {
+            var i = d3.interpolate(this._current, a);
+            this._current = i(0);
+            return function(t) {
+                return arc(i(t));
+            };
+        }
+
+        function size_for_humans(bytes) {
+            if (bytes > 1048576) {
+                return (bytes/1048576).toFixed(2) + ' MB';
+            } else if (bytes > 1024) {
+                return (bytes/1024).toFixed(2) + ' KB';
+            } else return bytes + ' bytes';
+        }
+
+        function format_value(value) {
+            if (dataset["TSEP"] == 1) {
+                return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
+            } else {
+                return value;
+            }
+        }
+
+        var w = window.innerWidth,
+            h = window.innerHeight,
+            x = d3.scale.linear().range([0, w]),
+            y = d3.scale.linear().range([0, h]);
+
+        var vis = d3.select("#partition")
+                    .style("width", w + "px")
+                    .style("height", h + "px")
+                    .append("svg:svg")
+                    .attr("width", w)
+                    .attr("height", h);
+
+        var partition = d3.layout.partition()
+                .value(function(d) { return d.size; });
+
+        root = JSON.parse('<?php echo json_encode($dataModel->getD3Scripts()); ?>');
+
+        var g = vis.selectAll("g")
+                   .data(partition.nodes(root))
+                   .enter().append("svg:g")
+                   .attr("transform", function(d) { return "translate(" + x(d.y) + "," + y(d.x) + ")"; })
+                   .on("click", click);
+
+        var kx = w / root.dx,
+                ky = h / 1;
+
+        g.append("svg:rect")
+         .attr("width", root.dy * kx)
+         .attr("height", function(d) { return d.dx * ky; })
+         .attr("class", function(d) { return d.children ? "parent" : "child"; });
+
+        g.append("svg:text")
+         .attr("transform", transform)
+         .attr("dy", ".35em")
+         .style("opacity", function(d) { return d.dx * ky > 12 ? 1 : 0; })
+         .text(function(d) { return d.name; })
+
+        d3.select(window)
+          .on("click", function() { click(root); })
+
+        function click(d) {
+            if (!d.children) return;
+
+            kx = (d.y ? w - 40 : w) / (1 - d.y);
+            ky = h / d.dx;
+            x.domain([d.y, 1]).range([d.y ? 40 : 0, w]);
+            y.domain([d.x, d.x + d.dx]);
+
+            var t = g.transition()
+                     .duration(d3.event.altKey ? 7500 : 750)
+                     .attr("transform", function(d) { return "translate(" + x(d.y) + "," + y(d.x) + ")"; });
+
+            t.select("rect")
+             .attr("width", d.dy * kx)
+             .attr("height", function(d) { return d.dx * ky; });
+
+            t.select("text")
+             .attr("transform", transform)
+             .style("opacity", function(d) { return d.dx * ky > 12 ? 1 : 0; });
+
+            d3.event.stopPropagation();
+        }
+
+        function transform(d) {
+            return "translate(8," + d.dx * ky / 2 + ")";
+        }
+
+        $(document).ready(function() {
+
+            function handleVisualisationToggle(close) {
+
+                $('#partition, #close-partition').fadeToggle();
+
+                // Is the visualisation being closed? If so show the status tab again
+                if (close) {
+
+                    $('#tab-visualise').removeAttr('checked');
+                    $('#tab-status').trigger('click');
+
+                }
+
+            }
+
+            $('label[for="tab-visualise"], #close-partition').on('click', function() {
+
+                handleVisualisationToggle(($(this).attr('id') === 'close-partition'));
+
+            });
+
+            $(document).keyup(function(e) {
+
+                if (e.keyCode == 27) handleVisualisationToggle(true);
+
+            });
+
+        });
+    </script>
+</body>
+</html>

+ 2 - 2
sites/all/modules/contrib/dev/prod_check/prod_check.api.php

@@ -71,7 +71,7 @@ function my_module_additional_check($caller = 'internal') {
   $title = 'My modules settings';
   $setting1 = t('Enable debug info');
   $setting2 = t('Disable debug info');
-  $path = 'admin/settings/my-module-settings-page';
+  $path = 'admin/config/system/my-module-settings-page';
   if ($caller != 'internal') {
     $path = PRODCHECK_BASEURL . $path;
   }
@@ -85,7 +85,7 @@ function my_module_additional_check($caller = 'internal') {
     '#description_ok'  => prod_check_ok_title($title, $path),
     '#description_nok' => t('Your !link settings are set to %setting1, they should be set to %setting2 on a producion environment!',
       array(
-        '!link' => '<em>'.l(t($title), $path, array('attributes' => array('title' => t($title)))).'</em>',
+        '!link' => '<em>' . l(t($title), $path, array('attributes' => array('title' => t($title)))) . '</em>',
         '%setting1' => $setting1,
         '%setting2' => $setting2,
       )

+ 91 - 0
sites/all/modules/contrib/dev/prod_check/prod_check.dbconnect.php

@@ -0,0 +1,91 @@
+<?php
+
+/**
+ * @file
+ * Simple database connection check that can be placed anywhere within a Drupal
+ * installation. Does NOT need to be in the root where index.php resides!
+ */
+
+/**
+ * Locate the actual Drupal root. Based on drush_locate_root().
+ */
+function locate_root() {
+  $drupal_root = FALSE;
+
+  $start_path = isset($_SERVER['PWD']) ? $_SERVER['PWD'] : '';
+  if (empty($start_path)) {
+    $start_path = getcwd();
+  }
+
+  foreach (array(TRUE, FALSE) as $follow_symlinks) {
+    $path = $start_path;
+    if ($follow_symlinks && is_link($path)) {
+      $path = realpath($path);
+    }
+    // Check the start path.
+    if (valid_root($path)) {
+      $drupal_root = $path;
+      break;
+    }
+    else {
+      // Move up dir by dir and check each.
+      while ($path = shift_path_up($path)) {
+        if ($follow_symlinks && is_link($path)) {
+          $path = realpath($path);
+        }
+        if (valid_root($path)) {
+          $drupal_root = $path;
+          break 2;
+        }
+      }
+    }
+  }
+
+  return $drupal_root;
+}
+
+/**
+ * Based on the DrupalBoot*::valid_root() from Drush.
+ */
+function valid_root($path) {
+  if (!empty($path) && is_dir($path) && file_exists($path . '/index.php')) {
+    $candidate = 'includes/common.inc';
+    if (file_exists($path . '/' . $candidate) && file_exists($path . '/misc/drupal.js')) {
+      return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+/**
+ * Based on _drush_shift_path_up().
+ */
+function shift_path_up($path) {
+  if (empty($path)) {
+    return FALSE;
+  }
+  $path = explode('/', $path);
+  // Move one directory up.
+  array_pop($path);
+  return implode('/', $path);
+}
+
+/**
+ * Do the actual database connection check.
+ */
+define('DRUPAL_ROOT', locate_root());
+require_once DRUPAL_ROOT . '/includes/bootstrap.inc';
+drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE);
+
+$result = db_query('SELECT COUNT(filename) FROM {system}')->fetchField();
+
+if ($result) {
+  $msg = 'OK';
+  http_response_code(200);
+}
+else {
+  http_response_code(500);
+  $msg = 'NOK';
+}
+
+exit($msg);

+ 4 - 4
sites/all/modules/contrib/dev/prod_check/prod_check.drush.inc

@@ -44,14 +44,14 @@ function drush_prod_check_status() {
 
   foreach ($functions as $set => $data) {
     $rows[] = array('');
-    $rows[] = array("\033[1m".dt($data['title'])."\033[0m");
+    $rows[] = array("\033[1m" . dt($data['title'])."\033[0m");
     foreach ($data['functions'] as $function => $title) {
       $result = call_user_func($function);
       $func = ltrim($function, '_');
       if (is_array($result) && !empty($result)) {
         $rows[] = array(
           $result[$func]['title'],
-          "\033[".$severity[$result[$func]['severity']].'m'.strip_tags($result[$func]['value'])."\033[0m",
+          "\033[" . $severity[$result[$func]['severity']] . 'm' . strip_tags($result[$func]['value']) . "\033[0m",
         );
         if ($error < $result[$func]['severity']) {
           $error = $result[$func]['severity'];
@@ -59,12 +59,12 @@ function drush_prod_check_status() {
       }
     }
   }
-  drush_print("\033[1m".dt('Production Check status')."\033[0m", 1);
+  drush_print("\033[1m" . dt('Production Check status')."\033[0m", 1);
   drush_print_table($rows);
   if ($error > 0) {
     // Would be cool if we could prefix the admin path with http://<host>/ so it
     // will become a clickable link in some terminals. Any ideas?
-    drush_print("\033[1m".dt('Some errors were reported!')."\033[0m ".dt('Check the full status page on')." \033[1m".'admin/reports/prod-check'."\033[0m ".dt('for details.'));
+    drush_print("\033[1m" . dt('Some errors were reported!') . "\033[0m " . dt('Check the full status page on') . " \033[1m" . 'admin/reports/prod-check' . "\033[0m " . dt('for details.'));
   }
 }
 

+ 3 - 3
sites/all/modules/contrib/dev/prod_check/prod_check.info

@@ -4,9 +4,9 @@ package = Monitoring
 core = 7.x
 configure = admin/config/system/prod-check
 
-; Information added by  packaging script on 2013-11-25
-version = "7.x-1.8"
+; Information added by Drupal.org packaging script on 2015-08-04
+version = "7.x-1.9"
 core = "7.x"
 project = "prod_check"
-datestamp = "1385405033"
+datestamp = "1438700931"
 

+ 3 - 3
sites/all/modules/contrib/dev/prod_check/prod_check.install

@@ -31,15 +31,15 @@ function prod_check_requirements($phase) {
           'title' => t('Production check'),
           'value' => t('Site e-mail check not properly configured.'),
           'severity' => REQUIREMENT_WARNING,
-          'description' => t('You have not changed the e-mail address on the prod-check !link. The Site e-mail check will not function properly. Please read the README.txt file.', prod_check_link_array('settings page', 'admin/settings/prod-check')),
+          'description' => t('You have not changed the e-mail address on the prod-check !link. The Site e-mail check will not function properly. Please read the README.txt file.', prod_check_link_array('settings page', 'admin/config/system/prod-check')),
         );
       }
       if (function_exists('apc_cache_info') && variable_get('prod_check_apcpass', 'password') == 'password') {
-        $requirements['prod_check_apc'] = array(
+        $requirements['prod_check_apc_opc'] = array(
           'title' => t('Production check'),
           'value' => t('APC password not configured.'),
           'severity' => REQUIREMENT_WARNING,
-          'description' => t('You have not !link for the APC status page. The page will function, but advanced options require that you set a password. Please read the README.txt file.', prod_check_link_array('changed the password', 'admin/settings/prod-check')),
+          'description' => t('You have not !link for the APC status page. The page will function, but advanced options require that you set a password. Please read the README.txt file.', prod_check_link_array('changed the password', 'admin/config/system/prod-check')),
         );
       }
       $nagios = variable_get('prod_check_enable_nagios', 0);

Plik diff jest za duży
+ 1 - 4
sites/all/modules/contrib/dev/prod_check/prod_check.module


+ 260 - 46
sites/all/modules/contrib/dev/prod_check/prod_monitor/includes/prod_monitor.admin.inc

@@ -4,8 +4,15 @@
  * Build status page.
  */
 function prod_monitor_status($id) {
-  $site = _prod_monitor_get_site($id, TRUE);
-  drupal_set_title(t('Production monitor status for') .' '. _prod_monitor_sanitize_url($site['url']));
+  $site = _prod_monitor_get_site($id, 'all');
+
+  if (!$site) {
+    // See https://api.drupal.org/api/drupal/includes!common.inc/function/drupal_not_found/7
+    return MENU_NOT_FOUND;
+  }
+
+
+  drupal_set_title(t('Production monitor status for') . ' ' . _prod_monitor_sanitize_url($site['url']));
 
   $functions = $site['settings']['functions'];
   $nodata = t('No data recieved yet.');
@@ -25,24 +32,25 @@ function prod_monitor_status($id) {
   // Display results of all checks.
   foreach ($functions as $set => $data) {
     if (isset($site['data'][$set])) {
-      $output .= '<h2>'.t($data['title']).'</h2>'."\n";
-      $output .= '<div class="description"><p><em>'.t($data['description']).'</em></p></div>'."\n";
+      $output .= '<h2>' . t($data['title']) . '</h2>' . "\n";
+      $output .= '<div class="description"><p><em>' . t($data['description']) . '</em></p></div>'."\n";
       if (!empty($site['data'][$set])) {
         $output .= theme('prod_monitor_status_report', array('requirements' => $site['data'][$set]));
       }
       else  {
-        $output .= '<p>'.$nodata.'</p><p>&nbsp;</p>';
+        $output .= '<p>' . $nodata . '</p><p>&nbsp;</p>';
       }
     }
   }
 
   if (empty($output)) {
-    $output = '<p>'.$nodata.'</p><p>&nbsp;</p>';
+    $output = '<p>' . $nodata . '</p><p>&nbsp;</p>';
   }
 
   // TODO: do not use drupal_render but change this so that hook_page_alter can
   // be used as well.
-  $output .= drupal_render(drupal_get_form('_prod_monitor_update_data_form', $id, $site));
+  $form = drupal_get_form('_prod_monitor_update_data_form', $id, $site);
+  $output .= drupal_render($form);
 
   return $output;
 }
@@ -51,30 +59,54 @@ function prod_monitor_status($id) {
  * Helper function to provide general status block on status overview page
  */
 function _prod_monitor_status_general($prod_mon, $modules) {
-  // TODO: Should we hide the rows for which no data is being retrieved?
-  $cron = t('Unknown');
-  if (isset($prod_mon['prod_check_cron_last'])) {
-    $cron = format_date($prod_mon['prod_check_cron_last'], 'large');
-  }
-
   $updates = _prod_monitor_generate_updates_link($modules['id'], $modules['updates']);
 
-  $output = '<h2>'.t('Overall status').'</h2>'."\n";
+  $output = '<h2>' . t('Overall status') . '</h2>' . "\n";
   $rows = array(
     array(
       array('data' => t('Drupal core version'), 'header' => TRUE),
       $modules['projects']['drupal']['info']['version'],
     ),
-    array(
+  );
+
+  if (isset($prod_mon['prod_check_cron_last'])) {
+    $rows[] = array(
       array('data' => t('Last cron run'), 'header' => TRUE),
-      $cron,
-    ),
-    array(
-      array('data' => t('Update status'), 'header' => TRUE),
-      $updates,
-    ),
+      format_date($prod_mon['prod_check_cron_last'], 'large'),
+    );
+  }
+
+  // Add dbconnect check info if configured.
+  if (isset($prod_mon['prod_check_dbconnect'])) {
+    $dbconnect = $prod_mon['prod_check_dbconnect'];
+    $class = array();
+    $title = t('DB connection status');
+    if (stripos($dbconnect, '200') === FALSE) {
+      $class = array('error');
+      $title = '<strong>' . $title . '</strong>';
+      $dbconnect = '<strong>' . $dbconnect . '</strong>';
+    }
+
+    $rows[] = array(
+      'data' => array(
+        array(
+          'data' => $title, 'header' => TRUE,
+          'class' => $class,
+        ),
+        array(
+          'data' => $dbconnect,
+          'class' => $class,
+        ),
+      ),
+      'class' => $class,
+    );
+  }
+
+  $rows[] = array(
+    array('data' => t('Update status'), 'header' => TRUE),
+    $updates,
   );
-  $output .= theme('table', array('header' => array(), 'rows' => $rows));
+  $output .= theme('table', array('prod_monitor_id' => 'status_general', 'header' => array(), 'rows' => $rows));
 
   return $output;
 }
@@ -99,7 +131,7 @@ function _prod_monitor_generate_updates_link($id, $update_status) {
         $title = t('Security risk!');
         break;
     }
-    $updates = array('data' => '<strong>'.l($title, 'admin/reports/prod-monitor/site/'.$id.'/view/updates', array('attributes' => array('title' => $title, 'class' => $class))).'</strong>', 'class' => $class);
+    $updates = array('data' => '<strong>' . l($title, 'admin/reports/prod-monitor/site/' . $id . '/view/updates', array('attributes' => array('title' => $title, 'class' => $class))) . '</strong>', 'class' => $class);
   }
 
   return $updates;
@@ -109,10 +141,10 @@ function _prod_monitor_generate_updates_link($id, $update_status) {
  * Callback for performance page.
  */
 function prod_monitor_performance($data) {
-  drupal_set_title(t('Performance logs for') .' '. _prod_monitor_get_url($data['id']));
+  drupal_set_title(t('Performance logs for') . ' ' . _prod_monitor_get_url($data['id']));
 
   // TODO: add 'get stats now' button.
-  //$site = _prod_monitor_get_site($id, TRUE);
+  //$site = _prod_monitor_get_site($id, 'all');
 
   return array(
     'performance_data' => array(
@@ -130,7 +162,7 @@ function prod_monitor_updates($modules) {
 
   $id = $modules['id'];
 
-  drupal_set_title(t('Module update status for') .' '. _prod_monitor_get_url($id));
+  drupal_set_title(t('Module update status for') . ' ' . _prod_monitor_get_url($id));
 
   // Only show a report if the available updates have been fetched!
   if (!empty($modules) && !empty($modules['projects']) && !empty($modules['available'])) {
@@ -149,7 +181,7 @@ function prod_monitor_updates($modules) {
                     'No information is available about potential new releases for currently installed modules and themes. To check for updates, you may need to !cron or you can !check. Please note that checking for available updates can take a long time, so please be patient.',
                     array(
                       '!cron' => l(t('run cron'), 'admin/reports/status/run-cron', array('attributes' => array('title' => t('run cron')), 'query' => $destination)),
-                      '!check' => l(t('check manually'), 'admin/reports/prod-monitor/site/'.$id.'/update-check', array('attributes' => array('title' => t('check manually')))),
+                      '!check' => l(t('check manually'), 'admin/reports/prod-monitor/site/' . $id . '/update-check', array('attributes' => array('title' => t('check manually')))),
                     )
                   )
       )
@@ -179,7 +211,7 @@ function prod_monitor_updates_check($id) {
   else {
     drupal_set_message(t('No module data available: cannot check for updates!'), 'error');
   }
-  drupal_goto('admin/reports/prod-monitor/site/'.$id.'/view/updates');
+  drupal_goto('admin/reports/prod-monitor/site/' . $id . '/view/updates');
 }
 
 /**
@@ -188,18 +220,27 @@ function prod_monitor_updates_check($id) {
 function prod_monitor_overview_form($form, &$form_state, $edit = FALSE) {
   drupal_set_title(t('Production monitor settings'));
   $base = drupal_get_path('module', 'prod_monitor');
-  drupal_add_css($base.'/css/prod-monitor.css', 'file');
-  drupal_add_js($base.'/js/jquery.equalheights.js', 'file');
-  drupal_add_js($base.'/js/prod-monitor.js', 'file');
+  drupal_add_css($base . '/css/prod-monitor.css', 'file');
+  drupal_add_js($base . '/js/jquery.equalheights.js', 'file');
+  drupal_add_js($base . '/js/prod-monitor.js', 'file');
 
   $form = array();
 
   $collapsed = FALSE;
 
   if (!$edit) {
+    // Button to initiate our fetch all batcher.
+    $form['fetch_all_submit'] = array(
+      '#weight' => -100,
+      '#type' => 'submit',
+      '#value' => t('Fetch all'),
+      '#submit' => array('prod_monitor_fetch_all_submit'),
+      '#limit_validation_errors' => array(),
+    );
+
     // Add new site situation.
     $sites = _prod_monitor_get_sites();
-    $api_key = $url = '';
+    $dbconnect_path = $api_key = $url = '';
     $options = array();
     $button = t('Get settings');
     if (!empty($sites)) {
@@ -211,6 +252,7 @@ function prod_monitor_overview_form($form, &$form_state, $edit = FALSE) {
     if (!empty($form_state['storage']['get_settings'])) {
       // Second step of add new site situation.
       $api_key = $form_state['values']['api_key'];
+      $dbconnect_path = $form_state['values']['dbconnect_path'];
       $url = $form_state['values']['url'];
       $button = t('Add site');
       $collapsed = FALSE;
@@ -227,6 +269,7 @@ function prod_monitor_overview_form($form, &$form_state, $edit = FALSE) {
     }
     drupal_set_title(t('Production monitor settings for !url', array('!url' => _prod_monitor_sanitize_url($url))));
     $api_key = $site['settings']['api_key'];
+    $dbconnect_path = $site['settings']['dbconnect_path'];
     $options = $site['settings']['checks'];
     if (isset($site['settings']['checks']['perf_data'])) {
       $perf_enabled = $site['settings']['checks']['perf_data'];
@@ -255,7 +298,7 @@ function prod_monitor_overview_form($form, &$form_state, $edit = FALSE) {
 
   $form['sites']['api_key'] = array(
     '#type' => 'textfield',
-    '#title' => t('The website\'s API key'),
+    '#title' => t("The website's API key"),
     '#default_value' => $api_key,
     '#description' => t('Enter the API key you have configured for this site using the <em>Production check</em> module.'),
     '#size' => 60,
@@ -263,6 +306,15 @@ function prod_monitor_overview_form($form, &$form_state, $edit = FALSE) {
     '#required' => TRUE,
   );
 
+  $form['sites']['dbconnect_path'] = array(
+    '#type' => 'textfield',
+    '#title' => t('DB connect check script'),
+    '#default_value' => $dbconnect_path,
+    '#description' => t('Enter the relative path, starting from the Drupal root, to the <em>prod_check.dbconnect.php</em> on the remote site. This wil usually be something like sites/all/modules/contrib/prod_check/prod_check.dbconnect.php . <strong>Leave empty if you do not want do enable this check!</strong>'),
+    '#size' => 60,
+    '#maxlength' => 512,
+  );
+
   // Only show on second step of add form or when editing.
   if (!empty($form_state['storage']['get_settings']) || $edit) {
     // Get the settings from the remote site. We always do this when the form is
@@ -303,7 +355,7 @@ function prod_monitor_overview_form($form, &$form_state, $edit = FALSE) {
           '#description' => t($data['description']),
           '#options' => $data['functions'],
           '#default_value' => array_keys($data['functions']),
-          '#prefix' => '<div class="prod-check-settings '.(($rest) ? 'odd' : 'even').'">',
+          '#prefix' => '<div class="prod-check-settings ' . (($rest) ? 'odd' : 'even') . '">',
           '#suffix' => '</div>',
         );
         $i++;
@@ -398,8 +450,8 @@ function _prod_monitor_overview_form_table($sites) {
     $view = t('View');
     $flush = t('Flush');
     if ($site_info['data']) {
-      $view = l(t('View'), 'admin/reports/prod-monitor/site/'.$id, array('attributes' => array('title' => t('View'))));
-      $flush = l(t('Flush'), 'admin/reports/prod-monitor/site/'.$id.'/flush', array('attributes' => array('title' => t('Flush'))));
+      $view = l(t('View'), 'admin/reports/prod-monitor/site/' . $id, array('attributes' => array('title' => t('View'))));
+      $flush = l(t('Flush'), 'admin/reports/prod-monitor/site/' . $id . '/flush', array('attributes' => array('title' => t('Flush'))));
     }
 
     $update_status = _prod_monitor_get_update_status($id);
@@ -407,7 +459,7 @@ function _prod_monitor_overview_form_table($sites) {
 
     if (!empty($site_info['status'])) {
       $title = t(ucwords($site_info['status']));
-      $status = array('data' => '<strong>'.l($title, 'admin/reports/prod-monitor/site/'.$id, array('attributes' => array('title' => $title, 'class' => $site_info['status']))).'</strong>', 'class' => array($site_info['status']));
+      $status = array('data' => '<strong>' . l($title, 'admin/reports/prod-monitor/site/' . $id, array('attributes' => array('title' => $title, 'class' => $site_info['status']))) . '</strong>', 'class' => array($site_info['status']));
     }
     else {
       $status = '';
@@ -424,17 +476,17 @@ function _prod_monitor_overview_form_table($sites) {
         (!$site_info['lastupdate']) ? t('Not yet updated.') : $site_info['lastupdate'],
         /* Compose links. */
         $view,
-        l(t('Edit'), 'admin/reports/prod-monitor/site/'.$id.'/edit', array('query' => $home, 'attributes' => array('title' => t('Edit')))),
-        l(t('Fetch data'), 'admin/reports/prod-monitor/site/'.$id.'/fetch', array('attributes' => array('title' => t('Fetch & View')))),
+        l(t('Edit'), 'admin/reports/prod-monitor/site/' . $id . '/edit', array('query' => $home, 'attributes' => array('title' => t('Edit')))),
+        l(t('Fetch data'), 'admin/reports/prod-monitor/site/' . $id . '/fetch', array('attributes' => array('title' => t('Fetch & View')))),
         $flush,
-        l(t('Delete'), 'admin/reports/prod-monitor/site/'.$id.'/delete', array('attributes' => array('title' => t('Delete')))),
+        l(t('Delete'), 'admin/reports/prod-monitor/site/' . $id . '/delete', array('attributes' => array('title' => t('Delete')))),
       ),
       'class' => array($site_info['status']),
     );
     $rows[] = $row;
   }
 
-  return theme('table', array('header' => $headers, 'rows' => $rows));
+  return theme('table', array('prod_monitor_id' => 'overview_form', 'header' => $headers, 'rows' => $rows));
 }
 
 /**
@@ -501,6 +553,8 @@ function prod_monitor_overview_form_submit($form, &$form_state) {
       $site->settings = serialize(
         array(
           'api_key' => $form_state['values']['api_key'],
+          // Trim spaces and / from left and right side.
+          'dbconnect_path' => trim($form_state['values']['dbconnect_path'], ' /'),
           'functions' => $form_state['storage']['functions'],
           'checks' => $checks,
         )
@@ -511,9 +565,12 @@ function prod_monitor_overview_form_submit($form, &$form_state) {
       if ($result) {
         drupal_set_message(t('Website %url correctly saved.', array('%url' => $site->url)));
         if ($form_state['values']['fetch']) {
-          $site_info = _prod_monitor_get_site($site->id, TRUE);
+          $site_info = _prod_monitor_get_site($site->id, 'all');
+          // First: all checks.
           _prod_monitor_retrieve_data($site->id, $site_info, TRUE);
-          $form_state['redirect'] = 'admin/reports/prod-monitor/site/'.$site->id;
+          // MUST be second because of the status update!
+          _prod_monitor_db_connect_check($site->id, $site_info);
+          $form_state['redirect'] = 'admin/reports/prod-monitor/site/' . $site->id;
         }
       }
       else {
@@ -523,13 +580,81 @@ function prod_monitor_overview_form_submit($form, &$form_state) {
   }
 }
 
+/**
+ * Submit handler for the fetch all button.
+ */
+function prod_monitor_fetch_all_submit($form, &$form_state) {
+  _prod_monitor_fetch_all_data_batcher_create();
+}
+
+/**
+ * Function to create the batch process. Also used in Drush!
+ */
+function _prod_monitor_fetch_all_data_batcher_create($fetch_only = FALSE, $update_only = FALSE, $msg = TRUE) {
+  $title = t('Fetching all site data and checking for updates...');
+
+  if ($fetch_only) {
+    $title = t('Fetching all site data...');
+  }
+  if ($update_only) {
+    $title = t('Checking for updates...');
+  }
+
+  $batch = array(
+    'operations' => array(
+      array('prod_monitor_fetch_all_data_batcher', array($fetch_only, $update_only, $msg)),
+    ),
+    'title' => $title,
+    'file' => drupal_get_path('module', 'prod_monitor') . '/includes/prod_monitor.admin.inc',
+  );
+  batch_set($batch);
+}
+
+/**
+ * Batch fetching of all site info.
+ */
+function prod_monitor_fetch_all_data_batcher($fetch_only, $update_only, $msg, &$context) {
+  $sandbox = &$context['sandbox'];
+  if (empty($context['sandbox'])) {
+    $sandbox['sites'] = array_keys(_prod_monitor_get_sites());
+    $sandbox['count'] = count($sandbox['sites']);
+  }
+
+  // Get site info.
+  $id = array_shift($sandbox['sites']);
+  $site_info = _prod_monitor_get_site($id, 'all');
+
+  if (!$update_only) {
+    // First: all checks.
+    _prod_monitor_retrieve_data($id, $site_info, $msg);
+    // MUST be second because of the status update!
+    _prod_monitor_db_connect_check($id, $site_info);
+  }
+
+  if (!$fetch_only) {
+    // Module update status.
+    $modules = prod_monitor_load($id);
+    if (!empty($modules) && !empty($modules['projects'])) {
+      module_load_include('inc', 'prod_monitor', 'includes/prod_monitor.update');
+      _prod_monitor_update_refresh($id, $modules['projects'], $modules['sitekey']);
+      _prod_monitor_calculate_project_data($id, $modules['projects'], $modules['available']);
+    }
+  }
+
+  $context['message'] = t('Updating data for %url', array('%url' => $site_info['url']));
+  $context['finished'] = empty($sandbox['sites']) ? 1 : (1 - count($sandbox['sites']) / $sandbox['count']);
+}
+
 /**
  * Callback to fetch site data
  */
 function prod_monitor_fetch_data($id) {
-  $site_info = _prod_monitor_get_site($id, TRUE);
+  $site_info = _prod_monitor_get_site($id, 'all');
+  // First: all checks.
   _prod_monitor_retrieve_data($id, $site_info, TRUE);
-  drupal_goto('admin/reports/prod-monitor/site/'.$id);
+  // MUST be second because of the status update!
+  _prod_monitor_db_connect_check($id, $site_info);
+  drupal_goto('admin/reports/prod-monitor/site/' . $id);
 }
 
 /**
@@ -550,7 +675,7 @@ function prod_monitor_flush_form($form, &$form_state, $id) {
     '#value' => $url,
   );
 
-  return confirm_form($form, t('Are you sure you wish to delete all fetched data for %url?', array('%url' => $url)), 'admin/reports/prod-monitor', t('Note that the module update status data will not be flushed!').'<br />'.t('This action cannot be undone.'));
+  return confirm_form($form, t('Are you sure you wish to delete all fetched data for %url?', array('%url' => $url)), 'admin/reports/prod-monitor', t('Note that the module update status data will not be flushed!') . '<br />' . t('This action cannot be undone.'));
 }
 
 /**
@@ -634,6 +759,95 @@ function _prod_monitor_update_data_form($form, $form_state, $id, $site_info) {
 }
 
 function _prod_monitor_update_data_form_submit($form, &$form_state) {
+  // First: all checks.
   _prod_monitor_retrieve_data($form_state['values']['site_id'], $form_state['values']['site_info'], TRUE);
+  // MUST be second because of the status update!
+  _prod_monitor_db_connect_check($form_state['values']['site_id'], $form_state['values']['site_info']);
 }
 
+/**
+ * Callback for module lookup form.
+ *
+ */
+function prod_monitor_module_lookup_form($form, &$form_state) {
+  $form = array();
+
+  // Show results.
+  if (isset($form_state['projects'])) {
+
+    $module = $form_state['values']['module'];
+
+    $rows = array();
+    foreach ($form_state['projects'] as $id => $project) {
+
+      $application = db_select('prod_monitor_sites', 'pms')->fields('pms', array('url'))->condition('id', $id)->execute()->fetchField();
+      $version = $project['info']['version'];
+
+      $rows[] = array(
+        $application,
+        $version,
+        l(t('View'), 'admin/reports/prod-monitor/site/' . $id),
+      );
+    }
+    $form['title'] = array(
+      '#theme' => 'html_tag',
+      '#tag' => 'h2',
+      '#value' => t('Applications where %module is used', array('%module' => $module)),
+    );
+    $form['table'] = array(
+      '#theme' => 'table',
+      '#rows' => $rows,
+      '#header' => array(t('Application'), t('Version'), t('View')),
+    );
+
+    $form['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Perform another lookup'),
+    );
+  }
+  // Show lookup form.
+  else {
+    $form['module'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Module name'),
+      '#required' => TRUE,
+    );
+    $form['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Fetch Applications'),
+    );
+  }
+
+  return $form;
+}
+
+/**
+ * Submission handler for module lookup form
+ */
+function prod_monitor_module_lookup_form_submit(&$form, &$form_state) {
+  if (isset($form_state['values']['module'])) {
+
+    $projects = db_select('prod_monitor_site_modules', 'psm')
+    ->fields('psm', array('id', 'projects'))
+    ->condition('projects', '%' . db_like($form_state['values']['module']) . '%', 'LIKE')
+    ->execute()->fetchAllAssoc('id');
+
+    $form_state['rebuild'] = TRUE;
+
+    if ($projects && !empty($projects)) {
+      foreach($projects as $project) {
+
+        $modules = unserialize($project->projects);
+        if (isset($modules[$form_state['values']['module']])) {
+          $form_state['projects'][$project->id] = $modules[$form_state['values']['module']];
+        }
+      }
+    }
+    if (!isset($form_state['projects'])) {
+      drupal_set_message(t('No projects found for :module', array(':module' => $form_state['values']['module'])));
+    }
+  }
+  else {
+    unset($form_state['projects']);
+  }
+}

+ 18 - 3
sites/all/modules/contrib/dev/prod_check/prod_monitor/includes/prod_monitor.theme.inc

@@ -1,5 +1,20 @@
 <?php
 
+/**
+ * Implements hook_preprocess_prod_monitor_update_report().
+ */
+function prod_monitor_preprocess_prod_monitor_update_report(&$vars) {
+  if (is_array($vars['data'])) {
+    foreach (array_keys($vars['data']) as $module_id) {
+
+      // When ignoring a module, we'll give a reason.
+      if (isset($vars['data'][$module_id]['ignored'])) {
+        $vars['data'][$module_id]['reason'] = t('Being ignored');
+      }
+    }
+  }
+}
+
 /**
  * Returns HTML for the project status report.
  *
@@ -15,12 +30,12 @@ function theme_prod_monitor_update_report($variables) {
   $data = $variables['data'];
 
   if (!is_array($data)) {
-    $output = '<p>'. $data .'</p>';
+    $output = '<p>' . $data . '</p>';
     return $output;
   }
 
   $output = '<div class="update checked">'. ($last ? t('Last checked: @time ago', array('@time' => format_interval(time() - $last))) : t('Last checked: never'));
-  $output .= ' <span class="check-manually">('. l(t('Check manually'), 'admin/reports/prod-monitor/site/'.$id.'/update-check') .')</span>';
+  $output .= ' <span class="check-manually">('. l(t('Check manually'), 'admin/reports/prod-monitor/site/' . $id . '/update-check') . ')</span>';
   $output .= "</div>\n";
 
   $header = array();
@@ -226,7 +241,7 @@ function theme_prod_monitor_update_report($variables) {
     if (!empty($rows[$type_name])) {
       ksort($rows[$type_name]);
       $output .= "\n<h3>" . $type_label . "</h3>\n";
-      $output .= theme('table', array('header' => $header, 'rows' => $rows[$type_name], 'attributes' => array('class' => array('update'))));
+      $output .= theme('table', array('prod_monitor_id' => 'update_report', 'header' => $header, 'rows' => $rows[$type_name], 'attributes' => array('class' => array('update'))));
     }
   }
   drupal_add_css(drupal_get_path('module', 'update') . '/update.css');

+ 17 - 4
sites/all/modules/contrib/dev/prod_check/prod_monitor/includes/prod_monitor.update.inc

@@ -29,7 +29,7 @@ function _prod_monitor_update_refresh($id, $projects, $site_key) {
   // As replacement for DRUPAL_CORE_COMPATIBILITY since prod_check and
   // prod_monitor should be site independant.
   $core = explode('.', $projects['drupal']['info']['version']);
-  $core = $core[0].'.x';
+  $core = $core[0] . '.x';
 
   $max_fetch_attempts = UPDATE_MAX_FETCH_ATTEMPTS;
 
@@ -65,10 +65,10 @@ function _prod_monitor_update_refresh($id, $projects, $site_key) {
       }
     }
     $modules->available = serialize($available);
-    watchdog('prod_monitor', 'Attempted to fetch information about all available new releases and updates for %link.', array('%link' => _prod_monitor_get_url($id)), WATCHDOG_NOTICE, l(t('view'), 'admin/reports/prod-monitor/site/'.$id.'/view/updates'));
+    watchdog('prod_monitor', 'Fetched information about all available new releases and updates for %link.', array('%link' => _prod_monitor_get_url($id)), WATCHDOG_NOTICE, l(t('view'), 'admin/reports/prod-monitor/site/' . $id . '/view/updates'));
   }
   else {
-    watchdog('prod_monitor', 'Unable to fetch any information about available new releases and updates for %link.', array('%link' => _prod_monitor_get_url($id)), WATCHDOG_ERROR, l(t('view'), 'admin/reports/prod-monitor/site/'.$id.'/view/updates'));
+    watchdog('prod_monitor', 'Unable to fetch any information about available new releases and updates for %link.', array('%link' => _prod_monitor_get_url($id)), WATCHDOG_ERROR, l(t('view'), 'admin/reports/prod-monitor/site/' . $id . '/view/updates'));
   }
   // Whether this worked or not, we did just (try to) check for updates.
   $modules->lastupdate = time();
@@ -99,7 +99,7 @@ function _prod_monitor_update_refresh($id, $projects, $site_key) {
 function _prod_monitor_update_build_fetch_url($project, $site_key = '', $core) {
   $name = $project['name'];
   $url = _prod_monitor_update_get_fetch_url_base($project);
-  $url .= '/'. $name .'/'. $core;
+  $url .= '/' . $name . '/' . $core;
   // Only append a site_key and the version information if we have a site_key
   // in the first place, and if this is not a disabled module or theme. We do
   // not want to record usage statistics for disabled code.
@@ -169,6 +169,19 @@ function _prod_monitor_calculate_project_data($id, $projects, $available) {
     }
   }
 
+  // Handle the ignored modules.
+  if (($ignored = _prod_monitor_get_site_ignored($id))
+    && !empty($ignored['updates'])) {
+    foreach ($ignored['updates'] as $project_name) {
+      if (isset($projects[$project_name])) {
+        $projects[$project_name]['ignored'] = TRUE;
+        $projects[$project_name]['status'] = UPDATE_UNKNOWN;
+      }
+    }
+  }
+
+  drupal_alter('prod_monitor_project_data', $id, $projects, $available);
+
   // Check if we need to flag a security update warning.
   // Prepare object to store generated data to DB.
   $modules = new stdClass();

+ 41 - 0
sites/all/modules/contrib/dev/prod_check/prod_monitor/prod_monitor.api.php

@@ -0,0 +1,41 @@
+<?php
+/**
+ * @file
+ * Documentation on api functions for prod_monitor.
+ *
+ * @ingroup prod_monitor
+ * @{
+ */
+
+/**
+ * Implements hook_prod_monitor_ignore().
+ *
+ * Allows modules to specify certain ignore directives, currently
+ * a list of modules whose update status should be ignored.
+ *
+ * @see _prod_monitor_get_site_ignored().
+ * @see _prod_monitor_calculate_project_data().
+ */
+function hook_prod_monitor_ignore($site_id) {
+  $ignore = array('updates' => array());
+  
+  // Ignore this module (suppress warnings) because we cannot do anything
+  // about it's update status as it has been abandoned and we are not going
+  // to stop using it.
+  if ($site_id == 12) {
+    $ignore['updates'][] = 'node_embed';
+  }
+
+  return $ignore;
+}
+
+/**
+ * Implements hook_prod_monitor_project_data_alter().
+ *
+ * Allows modules to alter the data being calculated for a project.
+ *
+ * @see _prod_monitor_calculate_project_data().
+ */
+function hook_prod_monitor_project_data_alter($site_id, &$data, $available) {
+
+}

+ 134 - 82
sites/all/modules/contrib/dev/prod_check/prod_monitor/prod_monitor.drush.inc

@@ -15,14 +15,15 @@ function prod_monitor_drush_command() {
     ),
   );
   $items['prod-monitor-updates'] = array(
-    'callback' => '_drush_prod_monitor_updates',
+    'callback' => 'drush_prod_monitor_updates',
     'description' => 'Display the update module status page',
     'aliases' => array('pmon-up'),
     'arguments' => array(
       'id' => 'ID of the site to view module updates for.',
     ),
     'options' => array(
-      '--check' => 'Check for module updates.'
+      'check' => 'Check for module updates.',
+      'security-only' => 'Only show modules that have security updates available.',
     ),
   );
   $items['prod-monitor-fetch'] = array(
@@ -58,21 +59,39 @@ function prod_monitor_drush_command() {
  */
 function drush_prod_monitor_fetch() {
   $args = func_get_args();
-  foreach($args as $arg) {
-    $site = _prod_monitor_get_site($arg);
-    if (!empty($site['url'])) {
-      $result = _prod_monitor_retrieve_data($arg, $site);
-      $site['url'] = _prod_monitor_sanitize_url(rtrim($site['url'], '/'));
-      if ($result === FALSE) {
-        drush_print("\033[1;31m".dt('Error:')." \033[0m".dt('Unable to fetch data for').' '.$site['url'].'!');
+
+  // Fetch ALL.
+  if (empty($args)) {
+    if (!drush_confirm(dt('Do you really want to fetch the data for ALL remote sites?'))) {
+      drush_set_error('prod_monitor', dt('Aborting.'));
+      return;
+    }
+    else {
+      module_load_include('inc', 'prod_monitor', 'includes/prod_monitor.admin');
+      // Batch process data fetching.
+      _prod_monitor_fetch_all_data_batcher_create(TRUE, FALSE, FALSE);
+      drush_backend_batch_process();
+    }
+  }
+  // Fetch one or more sites as requested.
+  else {
+    foreach($args as $arg) {
+      $site = _prod_monitor_get_site($arg);
+      if (!empty($site['url'])) {
+        $result = _prod_monitor_retrieve_data($arg, $site);
+        $site['url'] = _prod_monitor_sanitize_url(rtrim($site['url'], '/'));
+        if ($result === FALSE) {
+          drush_print("\033[1;31m" . dt('Error:') . " \033[0m" . dt('Unable to fetch data for') . ' ' . $site['url'] . '!');
+        }
+        else {
+          _prod_monitor_db_connect_check($arg, $site);
+          drush_print(dt('Sucessfully fetched data for') . ' ' . $site['url'] . '.');
+        }
       }
       else {
-        drush_print(dt('Sucessfully fetched data for').' '.$site['url'].'.');
+        drush_print("\033[1;31m" . dt('Error:') . " \033[0m" . dt('No site found with ID') . ' ' . $arg . '!');
       }
     }
-    else {
-      drush_print("\033[1;31m".dt('Error:')." \033[0m".dt('No site found with ID').' '.$arg.'!');
-    }
   }
 }
 
@@ -84,19 +103,19 @@ function drush_prod_monitor_flush() {
   foreach ($args as $arg) {
     $url = _prod_monitor_get_url($arg);
     if (!empty($url)) {
-      if (!drush_confirm(dt('Do you really want to flush all data for').' '.$url.'?')) {
+      if (!drush_confirm(dt('Do you really want to flush all data for') . ' ' . $url . '?')) {
         drush_die('Aborting.');
       }
       $result = _prod_monitor_flush_data($arg);
       if ($result === FALSE) {
-        drush_print("\033[1;31m".dt('Error:')." \033[0m".dt('Unable to flush data!'));
+        drush_print("\033[1;31m" . dt('Error:') . " \033[0m" . dt('Unable to flush data!'));
       }
       else {
         drush_print(dt('Stored data successfully flushed.'));
       }
     }
     else {
-      drush_print("\033[1;31m".dt('Error:')." \033[0m".dt('No site found with ID').' '.$arg.'!');
+      drush_print("\033[1;31m" . dt('Error:') . " \033[0m" . dt('No site found with ID') . ' ' . $arg . '!');
     }
   }
 }
@@ -109,19 +128,19 @@ function drush_prod_monitor_delsite() {
   foreach ($args as $arg) {
     $url = _prod_monitor_get_url($arg);
     if (!empty($url)) {
-      if (!drush_confirm(dt("Do you really want to delete").' '.$url.' '.dt('and all its data?'))) {
+      if (!drush_confirm(dt("Do you really want to delete") . ' ' . $url . ' ' . dt('and all its data?'))) {
         drush_die('Aborting.');
       }
       $result = _prod_monitor_delete_site($arg);
       if ($result === FALSE) {
-        drush_print("\033[1;31m".dt('Error:')." \033[0m".dt('Unable to delete') . $url .'!');
+        drush_print("\033[1;31m" . dt('Error:') . " \033[0m" . dt('Unable to delete') . $url . '!');
       }
       else {
         drush_print(dt('Website successfully deleted.'));
       }
     }
     else {
-      drush_print("\033[1;31m".dt('Error:')." \033[0m".dt('No site found with ID').' '.$arg.'!');
+      drush_print("\033[1;31m" . dt('Error:') . " \033[0m" . dt('No site found with ID') . ' ' . $arg . '!');
     }
   }
 }
@@ -135,7 +154,7 @@ function drush_prod_monitor_statusdetail() {
   if (empty($args)) {
     _drush_prod_monitor_overview();
   }
-  else if (is_numeric($args[0])) {
+  elseif (is_numeric($args[0])) {
     _drush_prod_monitor_detail($args[0]);
   }
 }
@@ -158,7 +177,7 @@ function _drush_prod_monitor_overview() {
     dt('Last update'),
     dt('Status'),
   ));
-  
+
   // TODO: check why the colour coding messes up the tabs for the table
   // Worked around this by placing the status column last
   foreach ($sites as $id => $site_info) {
@@ -168,10 +187,10 @@ function _drush_prod_monitor_overview() {
       (!$site_info['data']) ? dt('Empty') : t('Stored'),
       $site_info['added'],
       (!$site_info['lastupdate']) ? dt('Not yet updated') : $site_info['lastupdate'],
-      "\033[".$severity[$site_info['status']].'m'.ucwords($site_info['status'])."\033[0m",
+      "\033[" . $severity[$site_info['status']] . 'm' . ucwords($site_info['status']) . "\033[0m",
     );
   }
-  drush_print("\033[1m".dt('Production Monitor status')."\033[0m\n", 1);
+  drush_print("\033[1m" . dt('Production Monitor status') . "\033[0m\n", 1);
   if (count($rows) > 1) {
     drush_print_table($rows, TRUE);
     drush_print(dt('Use drush prod-monitor [id] to view the details of a specific site.'));
@@ -182,9 +201,9 @@ function _drush_prod_monitor_overview() {
 }
 
 function _drush_prod_monitor_detail($id) {
-  $site = _prod_monitor_get_site($id, TRUE);
+  $site = _prod_monitor_get_site($id, 'all');
   if (!isset($site['url'])) {
-    drush_print("\033[1;31m".dt('Error:')." \033[0m".dt('No site found with ID').' '.$id.'!');
+    drush_print("\033[1;31m" . dt('Error:') . " \033[0m" . dt('No site found with ID') . ' ' . $id . '!');
     return;
   }
 
@@ -219,7 +238,7 @@ function _drush_prod_monitor_detail($id) {
     $updates = $color . $title . "\033[0m";
 
     // Construct block
-    $block[] = array("\033[1m".dt('Overall status')."\033[0m");
+    $block[] = array("\033[1m" . dt('Overall status') . "\033[0m");
     $block[] = array(
       dt('Drupal core version'),
       $modules['projects']['drupal']['info']['version'],
@@ -254,12 +273,12 @@ function _drush_prod_monitor_detail($id) {
   foreach ($functions as $set => $data) {
     if (isset($site['data'][$set])) {
       $rows[] = array('');
-      $rows[] = array("\033[1m".dt($data['title'])."\033[0m");
+      $rows[] = array("\033[1m" . dt($data['title']) . "\033[0m");
       if (!empty($site['data'][$set])) {
         foreach ($site['data'][$set] as $check => $result) {
           $rows[] = array(
             $result['title'],
-            "\033[".$severity[$result['severity']].'m'.strip_tags($result['value'])."\033[0m",
+            "\033[" . $severity[$result['severity']] . 'm' . strip_tags($result['value']) . "\033[0m",
           );
           if ($error < $result['severity']) {
             $error = $result['severity'];
@@ -273,7 +292,7 @@ function _drush_prod_monitor_detail($id) {
   }
 
   // Actual printing.
-  drush_print("\033[1m".dt('Production Monitor status for').' '._prod_monitor_sanitize_url($url)."\033[0m", 1);
+  drush_print("\033[1m" . dt('Production Monitor status for') . ' ' . _prod_monitor_sanitize_url($url) . "\033[0m", 1);
   if (!empty($block)) {
     drush_print_table($block);
   }
@@ -286,76 +305,109 @@ function _drush_prod_monitor_detail($id) {
   if ($error > 0) {
     // Would be cool if we could prefix the admin path with http://<host>/ so it
     // will become a clickable link in some terminals. Any ideas?
-    drush_print("\033[1m".dt('Some errors were reported!')."\033[0m ".dt('Check the full status page on')." \033[1m".'admin/reports/prod-monitor/'.$id.'/view'."\033[0m ".dt('for details.'));
+    drush_print("\033[1m" . dt('Some errors were reported!') . "\033[0m " . dt('Check the full status page on') . " \033[1m" . 'admin/reports/prod-monitor/' . $id . '/view' . "\033[0m " . dt('for details.'));
   }
 }
 
 /**
  * Update status page callback.
  */
-function _drush_prod_monitor_updates() {
+function drush_prod_monitor_updates() {
   $id = func_get_args();
-  if (empty($id)) {
-    drush_set_error('prod_monitor', dt('You must provide a site ID!'));
-    return;
-  }
-  $id = $id['0'];
 
-  // Get module info.
-  $modules = _prod_monitor_get_site_modules($id);
-  $url = _prod_monitor_get_url($id);
-  if (empty($modules)) {
-    if (empty($url)) {
-      drush_set_error('prod_monitor', dt('No site found with ID').' '. $id .'!');
+  // Fetch ALL.
+  if (empty($id)) {
+    if (!drush_confirm(dt('Do you really want to check ALL sites for module updates?'))) {
+      drush_set_error('prod_monitor', dt('Aborting.'));
       return;
     }
     else {
-      drush_set_error('prod_monitor', dt('No module data found for') .' '. $url.'!');
-      return;
+      module_load_include('inc', 'prod_monitor', 'includes/prod_monitor.admin');
+      // Batch process update checking.
+      _prod_monitor_fetch_all_data_batcher_create(FALSE, TRUE, FALSE);
+      drush_backend_batch_process();
     }
   }
-  else if (empty($modules['available'])) {
-    drush_set_error('prod_monitor', dt('No update data found for') .' '. $url.'!');
-    // No data, ask for refresh.
-    _drush_prod_monitor_update_refresh($id, $modules);
-  }
+  // Fetch the site as requested.
+  else {
+    $id = $id['0'];
 
-  // Refresh if user asked for it.
-  if (drush_get_option('check')) {
-    _drush_prod_monitor_update_refresh($id, $modules);
-  }
+    // Get module info.
+    $modules = _prod_monitor_get_site_modules($id);
+    $url = _prod_monitor_get_url($id);
+    if (empty($modules)) {
+      if (empty($url)) {
+        drush_set_error('prod_monitor', dt('No site found with ID') . ' ' . $id . '!');
+        return;
+      }
+      else {
+        drush_set_error('prod_monitor', dt('No module data found for') . ' ' . $url . '!');
+        return;
+      }
+    }
+    elseif (empty($modules['available'])) {
+      drush_set_error('prod_monitor', dt('No update data found for') . ' ' . $url . '!');
+      // No data, ask for refresh.
+      _drush_prod_monitor_update_refresh($id, $modules);
+    }
 
-  $last = $modules['lastupdate'];
-  module_load_include('inc', 'prod_monitor', 'includes/prod_monitor.update');
-  $projects = _prod_monitor_calculate_project_data($id, $modules['projects'], $modules['available']);
-  // Cleanup.
-  unset($modules);
+    // Refresh if user asked for it.
+    if (drush_get_option('check')) {
+      _drush_prod_monitor_update_refresh($id, $modules);
+    }
+
+    $security_only = drush_get_option('security-only');
+
+    $last = $modules['lastupdate'];
+    module_load_include('inc', 'prod_monitor', 'includes/prod_monitor.update');
+    $projects = _prod_monitor_calculate_project_data($id, $modules['projects'], $modules['available']);
+    // Cleanup.
+    unset($modules);
+
+    // Table headers.
+    $rows[] = array(dt('Name'), dt('Installed version'), dt('Proposed version'), dt('Status'));
 
-  // Table headers.
-  $rows[] = array(dt('Name'), dt('Installed version'), dt('Proposed version'), dt('Status'));
-
-  // Process releases, notifying user of status and building a list of proposed updates
-  drush_include_engine('update_info', 'drupal', NULL, DRUSH_BASE_PATH . '/commands/pm/update_info');
-  drush_include(DRUSH_BASE_PATH . '/commands/pm', 'updatecode.pm');
-  $updateable = pm_project_filter($projects, $rows);
-
-  // Pipe preparation
-  if (drush_get_context('DRUSH_PIPE')) {
-    $pipe = "";
-    foreach($projects as $project){
-      $pipe .= $project['name']. " ";
-      $pipe .= $project['existing_version']. " ";
-      $pipe .= $project['candidate_version']. " ";
-      $pipe .= str_replace(' ', '-', pm_update_filter($project)). "\n";
+    // Process releases, notifying user of status and building a list of proposed updates
+    drush_include_engine('update_info', 'drupal', NULL, DRUSH_BASE_PATH . '/commands/pm/update_info');
+    drush_include(DRUSH_BASE_PATH . '/commands/pm', 'updatecode.pm');
+    foreach ($projects as $project) {
+      // Only show security updates if the user requested it.
+      if ($security_only && $project['status'] !== UPDATE_NOT_SECURE) {
+        continue;
+      }
+      // Add color to the status.
+      $color = "\033[0m";
+      switch ($project['status']) {
+        case UPDATE_CURRENT:
+          $color = "\033[1;32m";
+          break;
+        case UPDATE_NOT_CURRENT:
+          $color = "\033[1;33m";
+          break;
+        case UPDATE_NOT_SECURE:
+          $color = "\033[1;31m";
+          break;
+      }
+      // Translate status to readable name and fill 'candidate_version'.
+      $status = pm_update_filter($project);
+      // Generate row.
+      $rows[] = array(
+        $project['name'],
+        $project['existing_version'],
+        $project['candidate_version'],
+        $color . $status . "\033[0m",
+      );
     }
-    drush_print_pipe($pipe);
-    // Automatically curtail update process if in pipe mode
-    $updateable = FALSE;
-  }
 
-  drush_print("\033[1m".dt('Module update status for').' '.$url."\033[0m", 1);
-  drush_print(dt('Update information last refreshed:') .' '. ($last  ? format_date($last) : dt('Never'))."\n", 1);
-  drush_print_table($rows, TRUE);
+    drush_print("\033[1m" . dt('Module update status for') . ' ' . $url . "\033[0m", 1);
+    drush_print(dt('Update information last refreshed:') . ' ' . ($last  ? format_date($last) : dt('Never')) . "\n", 1);
+    if (count($rows) > 1) {
+      drush_print_table($rows, TRUE);
+    }
+    else {
+      drush_print("\033[1m" . dt('No updates to show!') . "\033[0m", 1);
+    }
+  }
 }
 
 /**
@@ -375,7 +427,7 @@ function _drush_prod_monitor_update_refresh($id, &$modules) {
       $modules['lastupdate'] = time();
     }
     else {
-      drush_set_error('prod_monitor', dt('Failed to refres update status information for') .' '. $url.'!');
+      drush_set_error('prod_monitor', dt('Failed to refres update status information for') . ' ' . $url . '!');
       drush_die('Aborting.');
     }
   }

+ 3 - 3
sites/all/modules/contrib/dev/prod_check/prod_monitor/prod_monitor.info

@@ -4,9 +4,9 @@ package = Monitoring
 core = 7.x
 configure = admin/reports/prod-monitor
 
-; Information added by  packaging script on 2013-11-25
-version = "7.x-1.8"
+; Information added by Drupal.org packaging script on 2015-08-04
+version = "7.x-1.9"
 core = "7.x"
 project = "prod_check"
-datestamp = "1385405033"
+datestamp = "1438700931"
 

+ 22 - 23
sites/all/modules/contrib/dev/prod_check/prod_monitor/prod_monitor.install

@@ -149,29 +149,6 @@ function prod_monitor_schema() {
   );
 }
 
-/**
- * Implementation of hook_requirements().
- */
-function prod_monitor_requirements($phase) {
-  $requirements = array();
-  
-  switch ($phase) {
-    case 'install':
-      if (module_exists('update')) {
-        $requirements['prod_monitor_update'] = array(
-          'title' => t('Production monitor'),
-          'value' => t('Update manager enabled.'),
-          'severity' => REQUIREMENT_ERROR,
-          'description' => t('You have enabled <em>Update manager</em>. You have to disable this module before enabling Production monitor!'),
-        );
-      }
-      break;
-  }
-
-  return $requirements;
-}
-
-
 /**
  * Implementation of hook_uninstall().
  */
@@ -294,3 +271,25 @@ function prod_check_update_7103() {
     )
   );
 }
+
+/**
+ * Add new dbconnect_path setting to database to prevent warnings.
+ */
+function prod_check_update_7104() {
+  $table = 'prod_monitor_sites';
+
+  // Fetch all settings.
+  $result = db_select($table, 'psm')
+    ->fields('psm', array('id', 'settings'))
+    ->execute();
+
+  // Update all sites to add new setting.
+  foreach ($result as $site) {
+    $settings = unserialize($site->settings);
+    $settings['dbconnect_path'] = '';
+    $site->settings = serialize($settings);
+
+    // Write to DB.
+    drupal_write_record($table, $site, array('id'));
+  }
+}

+ 137 - 41
sites/all/modules/contrib/dev/prod_check/prod_monitor/prod_monitor.module

@@ -13,21 +13,24 @@ define('PROD_MONITOR_REQUIREMENT_WARNING', 1);
 define('PROD_MONITOR_REQUIREMENT_ERROR', 2);
 
 /**
- * We do the same here for the update module constants: redefine them so that we
- * do not need to run the update module entirely!
+ * We don't want to load the Update module just to be able to run Production
+ * Monitor, so we copy the constants from Update. But we need to check them all
+ * so that we don't get notices if Update is already running.
  */
-define('UPDATE_DEFAULT_URL', 'http://updates.drupal.org/release-history');
-define('UPDATE_NOT_SECURE', 1);
-define('UPDATE_REVOKED', 2);
-define('UPDATE_NOT_SUPPORTED', 3);
-define('UPDATE_NOT_CURRENT', 4);
-define('UPDATE_CURRENT', 5);
-define('UPDATE_NOT_CHECKED', -1);
-define('UPDATE_UNKNOWN', -2);
-define('UPDATE_NOT_FETCHED', -3);
-define('UPDATE_FETCH_PENDING', -4);
-define('UPDATE_MAX_FETCH_ATTEMPTS', 2);
-define('UPDATE_MAX_FETCH_TIME', 5);
+if (!module_exists('update')) {
+  define('UPDATE_DEFAULT_URL', 'http://updates.drupal.org/release-history');
+  define('UPDATE_NOT_SECURE', 1);
+  define('UPDATE_REVOKED', 2);
+  define('UPDATE_NOT_SUPPORTED', 3);
+  define('UPDATE_NOT_CURRENT', 4);
+  define('UPDATE_CURRENT', 5);
+  define('UPDATE_NOT_CHECKED', -1);
+  define('UPDATE_UNKNOWN', -2);
+  define('UPDATE_NOT_FETCHED', -3);
+  define('UPDATE_FETCH_PENDING', -4);
+  define('UPDATE_MAX_FETCH_ATTEMPTS', 2);
+  define('UPDATE_MAX_FETCH_TIME', 5);
+}
 
 /**
  * Implementation of hook_help().
@@ -36,24 +39,29 @@ function prod_monitor_help($path, $arg) {
   $output = '';
   switch ($path) {
     case 'admin/help#prod_monitor':
-      $output .= '<p>'.t('Production monitor is a module that can connect to the <strong>Production check</strong> module using <strong>XMLRPC</strong> and an <strong>API key</strong>. It will retrieve all specified data from the remote site to create a satus page and monitoring facility in a central place.').'<br />';
-      $output .= t('You can add multiple sites and configure per site what data you wish (not) to monitor, allowing you to setup a central Drupal site that will monitor all of your sites that have the <em>Production check</em> module with <em>XMLRPC</em> enabled.').'<br />';
-      $output .= t('The <strong>data retrieval</strong> mechanism can be called <strong>manually</strong> and is integrated with the <strong>cron</strong>, so you get a fresh update of data each cron run.').'</p>';
+      $output .= '<p>' . t('Production monitor is a module that can connect to the <strong>Production check</strong> module using <strong>XMLRPC</strong> and an <strong>API key</strong>. It will retrieve all specified data from the remote site to create a satus page and monitoring facility in a central place.') . '<br />';
+      $output .= t('You can add multiple sites and configure per site what data you wish (not) to monitor, allowing you to setup a central Drupal site that will monitor all of your sites that have the <em>Production check</em> module with <em>XMLRPC</em> enabled.') . '<br />';
+      $output .= t('The <strong>data retrieval</strong> mechanism can be called <strong>manually</strong> and is integrated with the <strong>cron</strong>, so you get a fresh update of data each cron run.') . '</p>';
       break;
     case 'admin/reports/prod-monitor':
-      $output .= '<p><strong>'.t('Site overview table').'</strong><br />';
-      $output .= t('The overview table gives you an overview of what sites you have added together with their status. The status will be the highest error detected in the retrieved data set.').'<br />';
-      $output .= t('The per site functions <strong>View</strong>, <strong>Edit</strong>, <strong>Fetch data</strong>, <strong>Flush</strong> and <strong>Delete</strong> should be self explanatory.').'</p>';
+      $output .= '<p><strong>' . t('Site overview table') . '</strong><br />';
+      $output .= t('The overview table gives you an overview of what sites you have added together with their status. The status will be the highest error detected in the retrieved data set.') . '<br />';
+      $output .= t('The per site functions <strong>View</strong>, <strong>Edit</strong>, <strong>Fetch data</strong>, <strong>Flush</strong> and <strong>Delete</strong> should be self explanatory.') . '</p>';
       // No break!
     case 'admin/reports/prod-monitor/site/%/edit':
-      $output .= '<p><strong>'.t('Website URL & API key').'</strong><br />';
-      $output .= t('To add a site, enter it\'s <strong>full url</strong>, including the protocol, but omitting the <em>xmlrpc.php</em> part and the <strong>API key</strong> that you have configured for it using the <strong>Production check</strong> module. Now click the <strong>Get settings</strong> button.').'<br />';
-      $output .= t('All of the checks that the <em>Production check</em> module can perform are fetched from the remote site and presented as an array of checkboxes. Finally you can configure what exactly you wish to monitor for this site, then hit the <strong>Add site</strong> button.').'<br />';
-      $output .= t('Each time you edit a site, the settings are fetched from the remote server so that any new checks that might have been added to the <em>Production check</em> module there are always up to date in the monitoring section.').'<br />';      $output .= t('<strong>Fetch data immediately</strong> does exactly what it says and fetches all the configured data from the remote site and will direct you to the report page.').'</p>';
+      $output .= '<p><strong>' . t('Website URL & API key') . '</strong><br />';
+      $output .= t("To add a site, enter it's <strong>full url</strong>, including the protocol, but omitting the <em>xmlrpc.php</em> part and the <strong>API key</strong> that you have configured for it using the <strong>Production check</strong> module. Now click the <strong>Get settings</strong> button.") . '<br />';
+      $output .= t('All of the checks that the <em>Production check</em> module can perform are fetched from the remote site and presented as an array of checkboxes. Finally you can configure what exactly you wish to monitor for this site, then hit the <strong>Add site</strong> button.') . '<br />';
+      $output .= t('Each time you edit a site, the settings are fetched from the remote server so that any new checks that might have been added to the <em>Production check</em> module there are always up to date in the monitoring section.') . '<br />';
+      $output .= t('<strong>Fetch data immediately</strong> does exactly what it says and fetches all the configured data from the remote site and will direct you to the report page.') . '</p>';
+      break;
+    case 'admin/reports/prod-monitor/module-lookup':
+      $output .= '<p><strong>' . t('Module name') . '</strong><br />';
+      $output .= t("Enter (part of) the module's machine name to see what sites are using the module.") . '<br />';
       break;
     case 'admin/reports/prod-monitor/site/%':
     case 'admin/reports/prod-monitor/site/%/view':
-      $output .= '<p>'.t('This is an overview of all checks performed by the <em>Production check</em> module and their status <strong>on the remote site</strong>. You can click the links inside the report to jump to the module\'s settings page, or to go to the project page of a module, in case you need to download it for installation.').'</p>';
+      $output .= '<p>' . t("This is an overview of all checks performed by the <em>Production check</em> module and their status <strong>on the remote site</strong>. You can click the links inside the report to jump to the module's settings page, or to go to the project page of a module, in case you need to download it for installation.") . '</p>';
       break;
   }
   return $output;
@@ -89,6 +97,25 @@ function prod_monitor_menu() {
     'file' => 'includes/prod_monitor.admin.inc',
   );
 
+  // Default primary tab (callback for this is it's parent path).
+  $items['admin/reports/prod-monitor/overview'] = array(
+    'title' => 'Overview',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => 0,
+   );
+
+  $items['admin/reports/prod-monitor/module-lookup'] = array(
+    'title' => 'Module lookup',
+    'description' => 'Searches monitored applications for module versions.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('prod_monitor_module_lookup_form'),
+    'access callback' => 'user_access',
+    'access arguments' => array('access production monitor'),
+    'type' => MENU_LOCAL_TASK,
+    'file' => 'includes/prod_monitor.admin.inc',
+    'weight' => 1,
+  );
+
   // This hook_menu() thing, still can't fully see the logic in it. However,
   // this here is what I want to achieve. It would be nice to see the /view/ bit
   // in the path dissapear, that would finish it entirely. I'll settle for this
@@ -330,8 +357,10 @@ function prod_monitor_cron() {
   foreach ($sites as $id => $site_info) {
     $elapsed = time() - $cron_start;
     if ($elapsed < $time_limit) {
-      //TODO: add module status update check here.
+      // First: all checks.
       _prod_monitor_retrieve_data($id, $site_info);
+      // MUST be second because of the status update!
+      _prod_monitor_db_connect_check($id, $site_info);
       $process++;
     }
     else {
@@ -367,7 +396,7 @@ function _prod_monitor_retrieve_functions($url, $api_key, $msg = TRUE) {
       'error'
     );
   }
-  else if ($msg) {
+  elseif ($msg) {
     drupal_set_message(t('Settings form updated, please adjust your settings.'));
   }
 
@@ -469,7 +498,7 @@ function _prod_monitor_retrieve_data($id, $site_info, $msg = FALSE) {
             );
           }
         }
-        else if ($msg) {
+        elseif ($msg) {
           drupal_set_message(t('Module data for %link successfully updated.', array('%link' => $site_info['url'])));
         }
       }
@@ -495,7 +524,7 @@ function _prod_monitor_retrieve_data($id, $site_info, $msg = FALSE) {
               );
             }
           }
-          else if ($msg) {
+          elseif ($msg) {
             drupal_set_message(t('Performance data for %link successfully updated.', array('%link' => $site_info['url'])));
           }
         }
@@ -504,6 +533,42 @@ function _prod_monitor_retrieve_data($id, $site_info, $msg = FALSE) {
   }
 }
 
+/**
+  * Perform separate dbconnect check. We cannot incorporate this at the side of
+  * prod_check as this would make no sense at all when the DB is down.
+ */
+function _prod_monitor_db_connect_check($id, $site_info) {
+  // Execute only if setup properly.
+  if (empty($site_info['settings']['dbconnect_path'])) {
+    return;
+  }
+
+  // Do the check.
+  $dbconnect_path = rtrim($site_info['url'], '/') . '/' . $site_info['settings']['dbconnect_path'];
+  $response = drupal_http_request($dbconnect_path);
+  if ($response->code !== '200' && $response->data !== 'OK') {
+    // Update status to notify the user of the problem!
+    $site_info['status'] = PROD_MONITOR_REQUIREMENT_ERROR;
+    $response->data = 'NOK';
+  }
+
+  // ALWAYS get stored site data as it should have been updated right before
+  // calling this function!
+  $site_data = _prod_monitor_get_site($id, 'data');
+  // Add data to site and save.
+  $site_data['data']['prod_mon']['prod_check_dbconnect'] = $response->code . ' ' . $response->data;
+
+  // Store site data
+  $site = new stdClass();
+  $site->id = $id;
+  if (isset($site_info['status'])) {
+    $site->status = $site_info['status'];
+  }
+  $site->data = serialize($site_data['data']);
+  $site->lastupdate = REQUEST_TIME;
+  $result = drupal_write_record('prod_monitor_sites', $site, array('id'));
+}
+
 /**
  * Helper function to get all sites.
  */
@@ -526,7 +591,7 @@ function _prod_monitor_get_sites($start_id = FALSE) {
     if (!empty($row->data)) {
       foreach ($row->data as $set => $checks) {
         foreach ($checks as $check => $results) {
-          $status = ($results['severity'] > $status) ? $results['severity'] : $status;
+          $status = (isset($results['severity']) && $results['severity'] > $status) ? $results['severity'] : $status;
         }
       }
       $data_status = TRUE;
@@ -561,21 +626,33 @@ function _prod_monitor_get_sites($start_id = FALSE) {
  *
  * @param $id
  *  int site id.
- * @param $all
- *  Boolean whether or not to return all fields or just the url and settings.
+ * @param $type
+ *  String the amount of data to be returned.
  */
-function _prod_monitor_get_site($id, $all = FALSE) {
-  if (!$all) {
-    $site = db_query("SELECT url, settings FROM {prod_monitor_sites} WHERE id = :id", array(':id' => $id))->fetchAssoc();
-  }
-  else {
-    $site = db_query("SELECT * FROM {prod_monitor_sites} WHERE id = :id", array(':id' => $id))->fetchAssoc();
+function _prod_monitor_get_site($id, $type = 'settings') {
+  switch ($type) {
+    case 'settings':
+      $site = db_query("SELECT url, settings FROM {prod_monitor_sites} WHERE id = :id", array(':id' => $id))->fetchAssoc();
+      break;
+    case 'all':
+      $site = db_query("SELECT * FROM {prod_monitor_sites} WHERE id = :id", array(':id' => $id))->fetchAssoc();
+      break;
+    case 'data':
+      $site = db_query("SELECT data FROM {prod_monitor_sites} WHERE id = :id", array(':id' => $id))->fetchAssoc();
+      break;
   }
 
   if (!empty($site)) {
-    $site['settings'] = unserialize($site['settings']);
-    if ($all) {
-      $site['data'] = unserialize($site['data']);
+    switch ($type) {
+      case 'all':
+        $site['data'] = unserialize($site['data']);
+        // No break!
+      case 'settings':
+        $site['settings'] = unserialize($site['settings']);
+        break;
+      case 'data':
+        $site['data'] = unserialize($site['data']);
+        break;
     }
   }
 
@@ -607,6 +684,25 @@ function _prod_monitor_get_site_modules($id, $exists = FALSE) {
   return $modules;
 }
 
+/**
+ * Returns an array of ignored directives by site id.
+ *
+ * @param  int $id The site id.
+ *
+ * @return array
+ *   - updates array List of project names, whose update status we'll ignore.
+ */
+function _prod_monitor_get_site_ignored($id) {
+  $ignored = &drupal_static(__FUNCTION__, array());
+  if (!array_key_exists($id, $ignored)) {
+    $ignored[$id] = module_invoke_all('prod_monitor_ignore', $id) + array(
+      'updates' => array(),
+    );
+  }
+
+  return $ignored[$id];
+}
+
 /**
  * Helper function to get the module status of a site by ID.
  *

+ 1 - 1
sites/all/modules/contrib/theming/colorbox/README.txt

@@ -89,7 +89,7 @@ Make any CSS adjustments to your "colorbox_mycolorbox.css" file.
 Load images from custom links in a Colorbox:
 --------------------------------------------
 
-Add the class "colorbox" to the link and point the src to the image
+Add the class "colorbox" to the link and point its href attribute to the image
 you want to display in the Colorbox.
 
 

+ 15 - 0
sites/all/modules/contrib/theming/colorbox/colorbox.api.php

@@ -27,3 +27,18 @@ function hook_colorbox_settings_alter(&$settings, &$style) {
     $style = 'mystyle';
   }
 }
+
+/**
+ * Allows to override activation of Colobox for the current URL.
+ *
+ * @param $active
+ *   A boolean indicating whether colorbox should be active for the current
+ *   URL or not.
+ */
+function hook_colorbox_active_alter(&$active) {
+  $path = drupal_get_path_alias($_GET['q']);
+  if (drupal_match_path($path, 'admin/config/colorbox_test')) {
+    // Enable colorbox for this URL.
+    $active = TRUE;
+  }
+}

+ 4 - 4
sites/all/modules/contrib/theming/colorbox/colorbox.info

@@ -1,14 +1,14 @@
 name = Colorbox
 description = A light-weight, customizable lightbox plugin for jQuery 1.4.3+.
-dependencies[] = libraries (2.x)
+dependencies[] = libraries (>=2.x)
 core = 7.x
 configure = admin/config/media/colorbox
 
 files[] = views/colorbox_handler_field_colorbox.inc
 
-; Information added by Drupal.org packaging script on 2014-09-12
-version = "7.x-2.8"
+; Information added by Drupal.org packaging script on 2015-10-01
+version = "7.x-2.10"
 core = "7.x"
 project = "colorbox"
-datestamp = "1410514129"
+datestamp = "1443691449"
 

+ 3 - 0
sites/all/modules/contrib/theming/colorbox/colorbox.module

@@ -152,6 +152,9 @@ function _colorbox_active() {
   }
   $page_match = variable_get('colorbox_visibility', 0) == 0 ? !$page_match : $page_match;
 
+  // Allow other modules to change the state of colorbox for the current URL.
+  drupal_alter('colorbox_active', $page_match);
+
   return $page_match;
 }
 

+ 11 - 0
sites/all/modules/contrib/theming/colorbox/colorbox.theme.inc

@@ -17,6 +17,7 @@
  * @ingroup themeable
  */
 function theme_colorbox_image_formatter($variables) {
+  static $gallery_token = NULL;
   $item = $variables['item'];
   $entity_type = $variables['entity_type'];
   $entity = $variables['entity'];
@@ -123,6 +124,16 @@ function theme_colorbox_image_formatter($variables) {
       $gallery_id = '';
   }
 
+  // If gallery id is not empty add unique per-request token to avoid images being added manually to galleries.
+  if (!empty($gallery_id)) {
+    // Check if gallery token has alrady been set, we need to reuse the token for the whole request.
+    if (is_null($gallery_token)) {
+      // We use a short token since randomness is not critical.
+      $gallery_token = drupal_random_key(8);
+    }
+    $gallery_id = $gallery_id . '-' . $gallery_token;
+  }
+
   if ($style_name = $settings['colorbox_image_style']) {
     $path = image_style_url($style_name, $image['path']);
   }

+ 1 - 1
sites/all/modules/contrib/theming/colorbox/js/colorbox.js

@@ -2,7 +2,7 @@
 
 Drupal.behaviors.initColorbox = {
   attach: function (context, settings) {
-    if (!$.isFunction($.colorbox)) {
+    if (!$.isFunction($.colorbox) || typeof settings.colorbox === 'undefined') {
       return;
     }
 

+ 1 - 1
sites/all/modules/contrib/theming/colorbox/js/colorbox_inline.js

@@ -2,7 +2,7 @@
 
 Drupal.behaviors.initColorboxInline = {
   attach: function (context, settings) {
-    if (!$.isFunction($.colorbox)) {
+    if (!$.isFunction($.colorbox) || typeof settings.colorbox === 'undefined') {
       return;
     }
     $.urlParam = function(name, url){

+ 1 - 1
sites/all/modules/contrib/theming/colorbox/js/colorbox_load.js

@@ -2,7 +2,7 @@
 
 Drupal.behaviors.initColorboxLoad = {
   attach: function (context, settings) {
-    if (!$.isFunction($.colorbox)) {
+    if (!$.isFunction($.colorbox) || typeof settings.colorbox === 'undefined') {
       return;
     }
     $.urlParams = function (url) {

+ 7 - 2
sites/all/modules/contrib/theming/colorbox/views/colorbox_handler_field_colorbox.inc

@@ -162,10 +162,15 @@ If you would like to have the characters %5B and %5D please use the html entity
     $tokens = $this->get_render_tokens($this->options['alter']);
     $popup = filter_xss_admin($this->options['popup']);
     $caption = filter_xss_admin($this->options['caption']);
-    $gallery = drupal_html_class($this->options['custom_gid']);
+    $gallery = filter_xss_admin($this->options['custom_gid']);
     $popup = strtr($popup, $tokens);
     $caption = strtr($caption, $tokens);
-    $gallery = strtr($gallery, $tokens);
+    $gallery = drupal_html_class(strtr($gallery, $tokens));
+
+    // Return nothing if popup is empty.
+    if (empty($popup)) {
+      return;
+    }
 
     $width = $this->options['width'] ? $this->options['width'] : '';
     $height = $this->options['height'] ? $this->options['height'] : '';

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików