FINAL suepr merge step : added all modules to this super repos

This commit is contained in:
Bachir Soussi Chiadmi
2015-04-19 16:46:59 +02:00
7585 changed files with 1723356 additions and 18 deletions

View File

@@ -0,0 +1,779 @@
<?php
/**
* Build status page.
*/
function prod_check_status() {
drupal_set_title(t('Production check status'));
$output = '';
// Execute all functions per set as defined in the functions array in
// _prod_check_functions().
$functions = _prod_check_functions();
// Not needed here.
unset($functions['prod_mon']);
unset($functions['perf_data']);
foreach ($functions as $set => $data) {
$result = array();
foreach ($data['functions'] as $function => $title) {
$check = call_user_func($function);
if (is_array($check) && !empty($check)) {
$result = array_merge($result, $check);
}
}
$output .= '<h2>' . t($data['title']) . '</h2>' . "\n";
$output .= '<div class="description"><p><em>' . t($data['description']) . '</em></p></div>' . "\n";
$output .= theme('prod_check_status_report', array('requirements' => $result));
}
return $output;
}
/**
* Build settings form.
*/
function prod_check_settings_form($form, &$form_state) {
drupal_set_title(t('Production check settings'));
$form = array();
// Add stylesheets & CSS.
$base = drupal_get_path('module', 'prod_check');
$form['#attached'] = array(
'css' => array(
'type' => 'file',
'data' => $base . '/css/prod-check.css',
),
'js' => array(
array (
'type' => 'file',
'data' => $base . '/js/jquery.equalheights.js',
),
array (
'type' => 'file',
'data' => $base . '/js/jquery.maskedinput.min.js',
),
array (
'type' => 'file',
'data' => $base . '/js/prod-check.js',
),
),
);
// E-mail settings.
$form['prod_check_general'] = array(
'#type' => 'fieldset',
'#title' => t('General settings'),
'#description' => t('Settings to allow certain checks to function properly.'),
'#collapsible' => FALSE,
);
$form['prod_check_general']['prod_check_sitemail'] = array(
'#type' => 'textfield',
'#title' => t('Mail check'),
'#default_value' => variable_get('prod_check_sitemail', ''),
'#size' => 60,
'#description' => t('Enter (part of) the e-mail address you always <strong>use when developing</strong> a website. This is used in a regular expression in the "Site e-mail", Contact and Webform modules check.'),
'#required' => FALSE,
);
if (module_exists('dblog')) {
$form['prod_check_general']['prod_check_dblog_php'] = array(
'#type' => 'select',
'#title' => t('Minimal watchdog severity for PHP errors'),
'#default_value' => variable_get('prod_check_dblog_php', WATCHDOG_WARNING),
'#options' => watchdog_severity_levels(),
'#description' => t('Select the severity level from which to start reporting PHP errors being logged to the watchdog table.'),
'#required' => TRUE,
);
$form['prod_check_general']['prod_check_dblog_php_threshold'] = array(
'#type' => 'textfield',
'#title' => t('Threshold for PHP errors'),
'#size' => 2,
'#default_value' => variable_get('prod_check_dblog_php_threshold', 1),
'#description' => t('Enter the number of times a PHP error needs to occur before reporting a problem. E.g. entering 3 here will allow 2 occurences of the exact same PHP error without an error being reported.'),
'#required' => TRUE,
);
}
$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')),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
// Cache full count threshold
$form['prod_check_apc']['prod_check_apc_expunge'] = array(
'#type' => 'textfield',
'#title' => t('APC 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.'),
'#required' => FALSE,
);
// APC user.
$form['prod_check_apc']['prod_check_apcuser'] = array(
'#type' => 'textfield',
'#title' => t('APC advanced features username'),
'#default_value' => variable_get('prod_check_apcuser', 'apc'),
'#size' => 60,
'#description' => t('The username for logging in to the APC settings page.'),
'#required' => FALSE,
);
// APC password.
$form['prod_check_apc']['prod_check_apcpass'] = array(
'#type' => 'password_confirm',
'#title' => t('APC advanced features password'),
'#size' => 60,
'#description' => t('The password for logging in to the APC settings page.'),
'#required' => FALSE,
);
// Disabled module settings
$form['prod_check_disabled'] = array(
'#type' => 'fieldset',
'#title' => t('Disabled modules'),
'#description' => t('You can choose to disable checking for updates for disabled modules here.'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
$form['prod_check_disabled']['prod_check_exclude_disabled_modules'] = array(
'#type' => 'checkbox',
'#title' => t("Don't check for updates for disabled modules"),
'#default_value' => variable_get('prod_check_exclude_disabled_modules', 0),
'#description' => t('When checked, only enabled modules will be reported. Note that this can cause some modules that are used but not enabled (f.e. APC, memcache, domain,...) to get skipped. See the documentation on how to add disabled modules on a whitelist.'),
'#required' => FALSE,
);
$modules = implode(', ', _prod_check_get_disabled_modules_whitelist());
$form['prod_check_disabled']['prod_check_disabled_modules_whitelist'] = array(
'#markup' => t('Currently these modules will be forcefully checked even when they are disabled: %modules', array('%modules' => $modules)),
);
// XMLRPC settings.
$form['prod_check_xmlrpc'] = array(
'#type' => 'fieldset',
'#title' => t('Production monitor integration.'),
'#description' => t('You can set up integration with the Production monitor module here.'),
'#collapsible' => FALSE,
);
$form['prod_check_xmlrpc']['prod_check_enable_xmlrpc'] = array(
'#type' => 'checkbox',
'#title' => t('Enable XMLRPC API'),
'#default_value' => variable_get('prod_check_enable_xmlrpc', 0),
'#description' => t('Tick this box if you would like to the module to open up the XMLRPC api so that it can be queried externally to supply information to a base site for monitoring purposes.'),
'#ajax' => array(
'callback' => 'prod_check_enable_xmlrpc',
'wrapper' => 'prod-check-xmlrpc',
'effect' => 'fade',
),
'#required' => FALSE,
);
// The #value here is necessary for the markup field to be rendered :-(
$form['prod_check_xmlrpc']['xmlrpc'] = array(
'#type' => 'markup',
'#prefix' => '<div id="prod-check-xmlrpc">',
'#suffix' => '</div>',
);
// Only show when the checkbox above is selected.
if (!isset($form_state['values']['prod_check_enable_xmlrpc'])) {
$form_state['values']['prod_check_enable_xmlrpc'] = variable_get('prod_check_enable_xmlrpc', 0);
}
if ($form_state['values']['prod_check_enable_xmlrpc']) {
$form['prod_check_xmlrpc']['xmlrpc']['prod_check_xmlrpc_key'] = array(
'#type' => 'textfield',
'#title' => t('API key'),
'#default_value' => variable_get('prod_check_xmlrpc_key', prod_check_generate_key()),
'#maxlength' => 128,
'#size' => 60,
'#description' => t('Enter a key here to ensure secure transfer of data over the API. Use a mixture of alphanumeric and special characters for increased security.'),
'#required' => FALSE,
);
$form['prod_check_xmlrpc']['xmlrpc']['prod_check_module_list_day'] = array(
'#type' => 'select',
'#title' => t('Report module list every'),
'#options' => array(t('Sunday'), t('Monday'), t('Tuesday'), t('Wednesday'), t('Thursday'), t('Friday'), t('Saturday')),
'#default_value' => variable_get('prod_check_module_list_day', 0),
'#description' => t('Defines which day the module list will be fetchable by Production monitor for an update status check.'),
'#required' => FALSE,
);
$form['prod_check_xmlrpc']['xmlrpc']['prod_check_module_list_time'] = array(
'#type' => 'textfield',
'#title' => t('at this time'),
'#default_value' => variable_get('prod_check_module_list_time', '03:00'),
'#maxlength' => 5,
'#size' => 5,
'#description' => t('Defines what time (HH:MM) the module list will be fetchable by Production monitor for an update status check.'),
'#required' => FALSE,
);
// See http://drupal.org/node/1058896#comment-5594076 .
if (variable_get('prod_check_module_list_lastrun', 0) != -1) {
$form['prod_check_xmlrpc']['xmlrpc']['reset'] = array(
'#prefix' => '<div class="clear">',
'#type' => 'submit',
'#value' => t('Force immediate module list reporting'),
'#postfix' => '</div>',
);
}
else {
$form['prod_check_xmlrpc']['xmlrpc']['reset'] = array(
'#markup' => '<div class="description clear">' . t('Production monitor will fetch the module list on next cron run or when manually invoked for this site!') . '</div>',
);
}
}
// Nagios settings.
if (module_exists('nagios')) {
$form['prod_check_nagios'] = array(
'#type' => 'fieldset',
'#title' => t('Nagios integration.'),
'#description' => t('You can set up integration with the !link module here.', prod_check_link_array('Nagios', 'http://drupal.org/project/nagios')),
'#collapsible' => FALSE,
);
$form['prod_check_nagios']['prod_check_enable_nagios'] = array(
'#type' => 'checkbox',
'#title' => t('Enable Nagios integration'),
'#description' => t('Tick this box if you want to enable integration with Nagios. The !link module is required for this to function.', array('!link' => l(t('Nagios'), 'http://drupal.org/project/nagios', array('attributes' => array('title' => t('Nagios')))))),
'#default_value' => variable_get('prod_check_enable_nagios', 0),
'#ajax' => array(
'callback' => 'prod_check_enable_nagios',
'wrapper' => 'prod-check-nagios',
'effect' => 'fade',
),
'#required' => FALSE,
);
// The #value here is necessary for the markup field to be rendered :-(
$form['prod_check_nagios']['nagios'] = array(
'#type' => 'markup',
'#prefix' => '<div id="prod-check-nagios">',
'#suffix' => '</div>',
);
// Only show when the checkbox above is selected.
if (!isset($form_state['values']['prod_check_enable_nagios'])) {
$form_state['values']['prod_check_enable_nagios'] = variable_get('prod_check_enable_nagios', 0);
}
// TODO: find a way to detect when this is rendered so we can adjust the
// prod-check.js and apply equalheights/width
if ($form_state['values']['prod_check_enable_nagios']) {
$form['prod_check_nagios']['nagios']['settings'] = _prod_check_functions_as_form();
$options = variable_get('prod_check_nagios_checks', array());
if (!empty($options)) {
// Just to increase readability of the source here.
$monitor_settings = &$form['prod_check_nagios']['nagios']['settings']['prod_check_settings']['monitor_settings'];
// Set default values to last saved state
foreach (element_children($monitor_settings) as $set) {
if (isset($options[$set])) {
$monitor_settings[$set]['#default_value'] = $options[$set];
}
else {
// No settings available, so uncheck all.
$monitor_settings[$set]['#default_value'] = array();
}
}
}
$form['prod_check_nagios']['nagios']['settings']['prod_check_nagios_unique'] = array(
'#type' => 'select',
'#title' => t('When Nagios unique ID not recieved'),
'#description' => t('Select what should happen when the Nagios unique ID is not recieved by the nagios page.'),
'#options' => array(
'default' => t('default Nagios module behavior'),
'404' => t('throw a 404 error'),
'home' => t('redirect to homepege'),
),
'#default_value' => variable_get('prod_check_nagios_unique', 'default'),
'#required' => FALSE,
);
$form['prod_check_nagios']['nagios']['settings']['prod_check_nagios_takeover'] = array(
'#markup' => '<p>' . t(
'If you want prod_check to take over the Nagios status page, you can edit the !settings and enter %callback. Only then will the setting above have any effect!',
array(
'!settings' => l(t('Nagios page callback'), 'admin/config/system/nagios'),
'%callback' => 'prod_check_nagios_status_page',
)
) .'</p>',
);
$form['prod_check_nagios']['nagios']['settings']['prod_check_nagios_verbose'] = array(
'#type' => 'checkbox',
'#title' => t('Show verbose status info'),
'#description' => t('Tick this box if you want to see detailed information about every check. Useful for debugging or first setup, but <strong>not recommended for production use!</strong>'),
'#default_value' => variable_get('prod_check_nagios_verbose', 0),
'#required' => FALSE,
);
}
}
// Submit buttons.
// Markup field for proper styling.
$form['buttons'] = array(
'#type' => 'markup',
'#prefix' => '<div class="form-actions">',
'#suffix' => '</div>',
);
$form['buttons']['submit'] = array(
'#type' => 'submit',
'#value' => t('Save configuration'),
);
$form['buttons']['reset'] = array(
'#type' => 'submit',
'#value' => t('Reset to defaults'),
);
return $form;
}
/**
* Parse the functions array and return a form fieldset with different sets of
* checkboxes so it can be inserted 'as is' in another form array for rendering.
* This is primlarily still here for integration with Nagios. Though not in use
* now since Nagios would create far too much needless variables in my personal
* opinion. It's left in for easy future integration with the
* hook_nagios_settings().
*/
function _prod_check_functions_as_form($compatibility = 'all') {
$form = array();
$form['prod_check_settings'] = array(
'#type' => 'fieldset',
'#title' => t('Configure what data you wish to monitor with <strong>Nagios</strong> for this site.'),
'#collapsible' => TRUE,
'#collapsed' => FALSE,
);
$form['prod_check_settings']['monitor_settings'] = array(
'#type' => 'markup',
'#prefix' => '<div id="prod-check-settings">',
'#suffix' => '</div>',
'#tree' => TRUE,
);
$i = 1;
$functions = _prod_check_functions();
if ($compatibility == 'all') {
unset($functions['prod_mon']);
unset($functions['perf_data']);
}
foreach ($functions as $set => $data) {
$rest = $i % 2;
$form['prod_check_settings']['monitor_settings'][$set] = array(
'#type' => 'checkboxes',
'#title' => t($data['title']),
'#description' => t($data['description']),
'#options' => $data['functions'],
'#default_value' => array_keys($data['functions']),
'#prefix' => '<div class="prod-check-settings ' . (($rest) ? 'odd' : 'even') . '">',
'#suffix' => '</div>',
);
$i++;
}
return $form;
}
/**
* Callback to add xmlrpc settings.
*/
function prod_check_enable_xmlrpc($form, &$form_state) {
return $form['prod_check_xmlrpc']['xmlrpc'];
}
/**
* Callback to add nagios settings.
*/
function prod_check_enable_nagios($form, &$form_state) {
return $form['prod_check_nagios']['nagios'];
}
/**
* Validation for settings form.
*/
function prod_check_settings_form_validate($form, &$form_state) {
// Had to add CSS again here since it was lost on form errors. Weird, doesn't
// seem logical...
$base = drupal_get_path('module', 'prod_check');
drupal_add_css($base . '/css/prod-check.css');
drupal_add_js($base . '/js/jquery.equalheights.js', 'module', 'header');
drupal_add_js($base . '/js/jquery.maskedinput.min.js', 'module', 'header');
drupal_add_js($base . '/js/prod-check.js', 'module', 'header');
if (module_exists('dblog')) {
if (!is_numeric($form_state['values']['prod_check_dblog_php_threshold'])) {
form_set_error('prod_check_dblog_php_threshold', t('The PHP error threshold should be numeric!'));
}
}
if ($form_state['values']['prod_check_enable_xmlrpc']) {
if (empty($form_state['values']['prod_check_xmlrpc_key'])) {
form_set_error('prod_check_xmlrpc_key', t('When enabling the XPLRPC API, you <strong>must</strong> enter an API key!'));
}
}
if (!empty($form_state['values']['prod_check_module_list_time'])) {
// This check in case JavaScript is not enabled / malfunctioning.
if (strpos($form_state['values']['prod_check_module_list_time'], ':') != 2) {
form_set_error('prod_check_module_list_time', t('Time must be input in 24 hour format: HH:MM!'));
}
else {
$time = explode(':', $form_state['values']['prod_check_module_list_time']);
if (intval($time[0]) > 23) {
form_set_error('prod_check_module_list_time', t('Hours must range from 00 (midnight) to 23!'));
}
if (intval($time[1]) > 59) {
form_set_error('prod_check_module_list_time', t('Minutes must range from 00 to 59!'));
}
}
}
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!'));
}
if (isset($form_state['values']['prod_check_enable_nagios']) && $form_state['values']['prod_check_enable_nagios']) {
$checks = array();
foreach ($form_state['values']['monitor_settings'] as $set => $data) {
foreach ($data as $check => $value) {
if ($value) {
$checks[$set][] = $value;
}
}
}
if (empty($checks)) {
form_set_error('monitor_settings', t('When enabling Nagios support, you <strong>must</strong> tick at least one of the checkboxes!'));
}
}
}
/**
* Submit for settings form.
*
* TODO: is it better to split all of these in separate functions and use
* buttons with the #submit property? The latter is better readability wise I
* guess.
*/
function prod_check_settings_form_submit($form, &$form_state) {
switch ($form_state['values']['op']) {
case t('Force immediate module list reporting'):
variable_set('prod_check_module_list_lastrun', -1);
break;
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.
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'])) {
variable_set('prod_check_apcpass', $form_state['values']['prod_check_apcpass']);
}
else {
variable_set('prod_check_apcpass', 'password');
}
variable_set('prod_check_exclude_disabled_modules', $form_state['values']['prod_check_exclude_disabled_modules']);
if ($form_state['values']['prod_check_enable_xmlrpc']) {
// Enable.
variable_set('prod_check_enable_xmlrpc', $form_state['values']['prod_check_enable_xmlrpc']);
variable_set('prod_check_xmlrpc_key', $form_state['values']['prod_check_xmlrpc_key']);
variable_set('prod_check_module_list_day', $form_state['values']['prod_check_module_list_day']);
variable_set('prod_check_module_list_time', $form_state['values']['prod_check_module_list_time']);
}
else {
// Disable.
variable_set('prod_check_enable_xmlrpc', 0);
}
// This is why we didn't use a system_settings_form().
if (isset($form_state['values']['prod_check_enable_nagios']) && $form_state['values']['prod_check_enable_nagios']) {
$checks = array();
foreach ($form_state['values']['monitor_settings'] as $set => $data) {
foreach ($data as $check => $value) {
if ($value) {
$checks[$set][] = $value;
}
}
}
// Enable.
variable_set('prod_check_enable_nagios', $form_state['values']['prod_check_enable_nagios']);
variable_set('prod_check_nagios_checks', $checks);
variable_set('prod_check_nagios_unique', $form_state['values']['prod_check_nagios_unique']);
variable_set('prod_check_nagios_verbose', $form_state['values']['prod_check_nagios_verbose']);
}
else {
// Disable.
variable_set('prod_check_enable_nagios', 0);
}
drupal_set_message(t('The configuration options have been saved.'));
break;
case t('Reset to defaults'):
// This beats multiple variable_del() calls.
// Don't delete prod_check_module_list_lastrun!
// DELETE FROM {variable} WHERE name LIKE "prod_check\_%" AND name <> "prod_check_module_list_lastrun"'
db_delete('variable')
->condition('name', 'prod_check\_%', 'LIKE')
->condition('name', 'prod_check_module_list_lastrun', '<>')
->execute();
cache_clear_all('variables', 'cache_bootstrap');
drupal_set_message(t('The configuration options have been reset to their default values.'));
break;
}
}
/**
* Setup site for production mode.
*/
function prod_check_prod_mode_form() {
drupal_set_title(t('Switch to production mode'));
$form = array();
// Put this in hook_help() first but some themes hide the help text. It's too
// important to be hidden, so moved it here.
$form['help'] = array(
'#markup' => '<p>' . t('Submitting this form will switch this website to <em>production mode</em>. This means that various settings will be adjusted in order to fix most of the problems reported on the status page. <strong>Some modules will be disabled as well!</strong>') . '</p>',
);
$form['site_mail'] = array(
'#type' => 'textfield',
'#title' => t('Site e-mail address'),
'#description' => t('This field is optional and will be used to setup the default e-mail address of this site. <strong>Currently set to %mail.</strong>', array('%mail' => variable_get('site_mail', '[not set]'))),
);
if (module_exists('webform')) {
$form['webform_default_from_address'] = array(
'#type' => 'textfield',
'#title' => t('Webform default from e-mail address'),
'#description' => t('This field is optional and will be used to setup the default from e-mail address for <em>Webform</em>. <strong>Currently set to %mail.</strong>', array('%mail' => variable_get('webform_default_from_address', '[not set]'))),
);
}
if (module_exists('googleanalytics')) {
$form['googleanalytics_account'] = array(
'#type' => 'textfield',
'#title' => t('Google Analytics Web Property ID'),
'#description' => t('This field is optional and will be used to setup the <em>Google Analytics</em> account. <strong>Currently set to %account.</strong>', array('%account' => variable_get('googleanalytics_account', '[not set]'))),
);
}
$form['block_cache'] = array(
'#type' => 'checkbox',
'#title' => t('Enable <em>Block cache</em>'),
'#description' => t("If ticked, this will enable block caching. <strong>This can cause unwanted results if custom blocks don't handle caching well!</strong>"),
);
if (module_exists('dblog')) {
$form['dblog'] = array(
'#type' => 'checkbox',
'#title' => t('Disable <em>Database logging</em>'),
'#description' => t('If ticked, this will disable the <em>dblog</em> module wich could generate too much overhead on high traffic sites.'),
);
}
$form['nagios'] = array(
'#type' => 'checkbox',
'#title' => t('Enable <em>Nagios</em>'),
'#description' => t('If ticked, this will enable the <em>Nagios</em> monitoring module if it is present.'),
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Enable production mode'),
);
return $form;
}
/**
* Setup site for production mode: validation.
*/
function prod_check_prod_mode_form_validate($form, &$form_state) {
$checks = array('site_mail', 'webform_default_from_address');
foreach ($checks as $field) {
if (!empty($form_state['values'][$field])) {
if (!valid_email_address($form_state['values'][$field])) {
form_set_error($field, t('The e-mail address %mail is not valid.', array('%mail' => $form_state['values'][$field])));
}
}
}
// Google analytics.
if (!empty($form_state['values']['googleanalytics_account'])) {
if (!preg_match('/^UA-\d{4,}-\d+$/', $form_state['values']['googleanalytics_account'])) {
form_set_error('googleanalytics_account', t('A valid Google Analytics Web Property ID is case sensitive and formatted like UA-xxxxxxx-yy.'));
}
}
}
// TODO: add confirm form here? In the form of:
// The following actions will be performed: [...] Are you sure you want to
// continue?
/**
* Setup site for production mode: submit.
*/
function prod_check_prod_mode_form_submit($form, &$form_state) {
// Adjust settings.
$variables = prod_check_prod_mode_settings($form_state['values']);
drupal_set_message(t('The following settings have been changed: %variables.', array('%variables' => implode(', ', array_keys($variables)))));
// Enable / disable modules.
$modules = prod_check_prod_mode_modules($form_state['values']);
if (!empty($modules['disable'])) {
drupal_set_message(t('The following modules have been <strong>disabled</strong>: %modules.', array('%modules' => implode(', ', $modules['disable']))));
}
if (!empty($modules['enable'])) {
drupal_set_message(t('The following modules have been <strong>enabled</strong>: %modules.', array('%modules' => implode(', ', $modules['enable']))));
}
$form_state['redirect'] = 'admin/reports/prod-check';
}
/**
* Helper function to adjust settings. Also used by Drush.
*/
function prod_check_prod_mode_settings($options) {
$variables = array(
// Error messages to display.
'error_level' => ERROR_REPORTING_HIDE,
// Cache pages for anonymous users.
'cache' => 1,
// Aggregate and compress CSS files.
'preprocess_css' => 1,
// Aggregate JavaScript files.
'preprocess_js' => 1,
);
// No page compression when running Varnish.
if (!module_exists('varnish') && !module_exists('steroids')) {
// Compress cached pages.
$variables['page_compression'] = 1;
}
// Site e-mail address.
if (isset($options['site_mail']) && !empty($options['site_mail'])) {
$variables['site_mail'] = $options['site_mail'];
}
// Webform default from e-mail address.
if (isset($options['webform_default_from_address']) && !empty($options['webform_default_from_address'])) {
$variables['webform_default_from_address'] = $options['webform_default_from_address'];
}
// Google analytics account.
if (isset($options['googleanalytics_account']) && !empty($options['googleanalytics_account'])) {
$variables['googleanalytics_account'] = $options['googleanalytics_account'];
}
// Cache blocks.
if (isset($options['block_cache']) && !empty($options['block_cache'])) {
$variables['block_cache'] = 1;
}
// Set variables. Wanted to do this in one query, but that was impossible due
// to the fact that it is possible a variable does not exist in the database
// yet and still have a value. Damn that default value in variable_get()!
foreach ($variables as $variable => $value) {
variable_set($variable, $value);
}
// Clear caches like the system_performance_settings() form does.
drupal_clear_css_cache();
drupal_clear_js_cache();
// Instead of calling system_clear_page_cache_submit()
cache_clear_all('*', 'cache_page', TRUE);
return $variables;
}
/**
* Helper function to enable / disable modules. Also used by Drush.
*/
function prod_check_prod_mode_modules($options) {
$modules['disable'] = array(
'devel',
'devel_generate',
'devel_node_access',
'devel_themer',
'update',
);
if (isset($options['dblog']) && $options['dblog']) {
$modules['disable'][] = 'dblog';
}
// We do this primarily to prepare feedback to the user. module_disable() will
// do a module_exists() check as well but only provides feedback using
// watchdog().
foreach ($modules['disable'] as $id => $module) {
if (!module_exists($module)) {
unset($modules['disable'][$id]);
}
}
if (!empty($modules['disable'])) {
module_disable($modules['disable']);
}
$modules['enable'] = array();
if ($options['nagios']) {
$modules['enable'][] = 'nagios';
}
// We cannot check if a module is available on the file system. At least,
// there is not a function in Drupal that I know of to do this and I could not
// find one. Hence this approach, until there's a better way.
if (!empty($modules['enable'])) {
module_enable($modules['enable']);
foreach($modules['enable'] as $id => $module) {
if (!module_exists($module)) {
unset($modules['enable'][$id]);
}
}
}
return $modules;
}
/**
* 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;
}
/**
* Integration of the Memcache status page.
*/
function prod_check_memcache() {
global $conf;
if (isset($conf['memcache_servers'])) {
global $MEMCACHE_SERVERS;
$MEMCACHE_SERVERS = array_keys($conf['memcache_servers']);
include(drupal_get_path('module', 'prod_check') . '/includes/prod_check.memcache.inc');
}
else {
print 'No memcache servers found in settings.php.';
}
exit;
}
/**
* Generate default key if none is present.
*/
function prod_check_generate_key($length = 25) {
$chars = 'abcdefghijklmnopqrstuxyvwzABCDEFGHIJKLMNOPQRSTUXYVWZ+-*#&@!?';
$size = strlen($chars);
$key = '';
for ($i = 0; $i < $length; $i++) {
$key .= $chars[rand(0, $size - 1)];
}
return $key;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,906 @@
<?php
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2004 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.0 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_0.txt. |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Harun Yayli <harunyayli at gmail.com> |
+----------------------------------------------------------------------+
*/
$VERSION='$Id: memcache.php 310129 2011-04-11 04:44:27Z hradtke $';
//define('ADMIN_USERNAME','memcache'); // Admin Username
//define('ADMIN_PASSWORD','password'); // Admin Password
define('DATE_FORMAT','Y/m/d H:i:s');
define('GRAPH_SIZE',200);
define('MAX_ITEM_DUMP',50);
//$MEMCACHE_SERVERS[] = 'mymemcache-server1:11211'; // add more as an array
//$MEMCACHE_SERVERS[] = 'mymemcache-server2:11211'; // add more as an array
////////// END OF DEFAULT CONFIG AREA /////////////////////////////////////////////////////////////
///////////////// Password protect ////////////////////////////////////////////////////////////////
//Section below commented to make this work for the Drupal 'Prod check' module
//See also http://drupal.org/node/1860504
/*if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW']) ||
$_SERVER['PHP_AUTH_USER'] != ADMIN_USERNAME ||$_SERVER['PHP_AUTH_PW'] != ADMIN_PASSWORD) {
Header("WWW-Authenticate: Basic realm=\"Memcache Login\"");
Header("HTTP/1.0 401 Unauthorized");
echo <<<EOB
<html><body>
<h1>Rejected!</h1>
<big>Wrong Username or Password!</big>
</body></html>
EOB;
exit;
}*/
///////////MEMCACHE FUNCTIONS /////////////////////////////////////////////////////////////////////
function get_host_port_from_server($server){
$values = explode(':', $server);
if (($values[0] == 'unix') && (!is_numeric( $values[1]))) {
return array($server, 0);
}
else {
//return values;
//Line above modified to make this work for the Drupal 'Prod check' module
return $values;
}
}
function sendMemcacheCommands($command){
global $MEMCACHE_SERVERS;
$result = array();
foreach($MEMCACHE_SERVERS as $server){
$strs = get_host_port_from_server($server);
$host = $strs[0];
$port = $strs[1];
$result[$server] = sendMemcacheCommand($host,$port,$command);
}
return $result;
}
function sendMemcacheCommand($server,$port,$command){
$s = @fsockopen($server,$port);
if (!$s){
die("Cant connect to:".$server.':'.$port);
}
fwrite($s, $command."\r\n");
$buf='';
while ((!feof($s))) {
$buf .= fgets($s, 256);
if (strpos($buf,"END\r\n")!==false){ // stat says end
break;
}
if (strpos($buf,"DELETED\r\n")!==false || strpos($buf,"NOT_FOUND\r\n")!==false){ // delete says these
break;
}
if (strpos($buf,"OK\r\n")!==false){ // flush_all says ok
break;
}
}
fclose($s);
return parseMemcacheResults($buf);
}
function parseMemcacheResults($str){
$res = array();
$lines = explode("\r\n",$str);
$cnt = count($lines);
for($i=0; $i< $cnt; $i++){
$line = $lines[$i];
$l = explode(' ',$line,3);
if (count($l)==3){
$res[$l[0]][$l[1]]=$l[2];
if ($l[0]=='VALUE'){ // next line is the value
$res[$l[0]][$l[1]] = array();
list ($flag,$size)=explode(' ',$l[2]);
$res[$l[0]][$l[1]]['stat']=array('flag'=>$flag,'size'=>$size);
$res[$l[0]][$l[1]]['value']=$lines[++$i];
}
}elseif($line=='DELETED' || $line=='NOT_FOUND' || $line=='OK'){
return $line;
}
}
return $res;
}
function dumpCacheSlab($server,$slabId,$limit){
list($host,$port) = get_host_port_from_server($server);
$resp = sendMemcacheCommand($host,$port,'stats cachedump '.$slabId.' '.$limit);
return $resp;
}
function flushServer($server){
list($host,$port) = get_host_port_from_server($server);
$resp = sendMemcacheCommand($host,$port,'flush_all');
return $resp;
}
function getCacheItems(){
$items = sendMemcacheCommands('stats items');
$serverItems = array();
$totalItems = array();
foreach ($items as $server=>$itemlist){
$serverItems[$server] = array();
$totalItems[$server]=0;
if (!isset($itemlist['STAT'])){
continue;
}
$iteminfo = $itemlist['STAT'];
foreach($iteminfo as $keyinfo=>$value){
if (preg_match('/items\:(\d+?)\:(.+?)$/',$keyinfo,$matches)){
$serverItems[$server][$matches[1]][$matches[2]] = $value;
if ($matches[2]=='number'){
$totalItems[$server] +=$value;
}
}
}
}
return array('items'=>$serverItems,'counts'=>$totalItems);
}
function getMemcacheStats($total=true){
$resp = sendMemcacheCommands('stats');
if ($total){
$res = array();
foreach($resp as $server=>$r){
foreach($r['STAT'] as $key=>$row){
if (!isset($res[$key])){
$res[$key]=null;
}
switch ($key){
case 'pid':
$res['pid'][$server]=$row;
break;
case 'uptime':
$res['uptime'][$server]=$row;
break;
case 'time':
$res['time'][$server]=$row;
break;
case 'version':
$res['version'][$server]=$row;
break;
case 'pointer_size':
$res['pointer_size'][$server]=$row;
break;
case 'rusage_user':
$res['rusage_user'][$server]=$row;
break;
case 'rusage_system':
$res['rusage_system'][$server]=$row;
break;
case 'curr_items':
$res['curr_items']+=$row;
break;
case 'total_items':
$res['total_items']+=$row;
break;
case 'bytes':
$res['bytes']+=$row;
break;
case 'curr_connections':
$res['curr_connections']+=$row;
break;
case 'total_connections':
$res['total_connections']+=$row;
break;
case 'connection_structures':
$res['connection_structures']+=$row;
break;
case 'cmd_get':
$res['cmd_get']+=$row;
break;
case 'cmd_set':
$res['cmd_set']+=$row;
break;
case 'get_hits':
$res['get_hits']+=$row;
break;
case 'get_misses':
$res['get_misses']+=$row;
break;
case 'evictions':
$res['evictions']+=$row;
break;
case 'bytes_read':
$res['bytes_read']+=$row;
break;
case 'bytes_written':
$res['bytes_written']+=$row;
break;
case 'limit_maxbytes':
$res['limit_maxbytes']+=$row;
break;
case 'threads':
$res['rusage_system'][$server]=$row;
break;
}
}
}
return $res;
}
return $resp;
}
//////////////////////////////////////////////////////
//
// don't cache this page
//
header("Cache-Control: no-store, no-cache, must-revalidate"); // HTTP/1.1
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache"); // HTTP/1.0
function duration($ts) {
global $time;
$years = (int)((($time - $ts)/(7*86400))/52.177457);
$rem = (int)(($time-$ts)-($years * 52.177457 * 7 * 86400));
$weeks = (int)(($rem)/(7*86400));
$days = (int)(($rem)/86400) - $weeks*7;
$hours = (int)(($rem)/3600) - $days*24 - $weeks*7*24;
$mins = (int)(($rem)/60) - $hours*60 - $days*24*60 - $weeks*7*24*60;
$str = '';
if($years==1) $str .= "$years year, ";
if($years>1) $str .= "$years years, ";
if($weeks==1) $str .= "$weeks week, ";
if($weeks>1) $str .= "$weeks weeks, ";
if($days==1) $str .= "$days day,";
if($days>1) $str .= "$days days,";
if($hours == 1) $str .= " $hours hour and";
if($hours>1) $str .= " $hours hours and";
if($mins == 1) $str .= " 1 minute";
else $str .= " $mins minutes";
return $str;
}
// create graphics
//
function graphics_avail() {
return extension_loaded('gd');
}
function bsize($s) {
foreach (array('','K','M','G') as $i => $k) {
if ($s < 1024) break;
$s/=1024;
}
return sprintf("%5.1f %sBytes",$s,$k);
}
// create menu entry
function menu_entry($ob,$title) {
global $PHP_SELF;
if ($ob==$_GET['op']){
return "<li><a class=\"child_active\" href=\"$PHP_SELF&op=$ob\">$title</a></li>";
}
return "<li><a class=\"active\" href=\"$PHP_SELF&op=$ob\">$title</a></li>";
}
function getHeader(){
$header = <<<EOB
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head><title>MEMCACHE INFO</title>
<style type="text/css"><!--
body { background:white; font-size:100.01%; margin:0; padding:0; }
body,p,td,th,input,submit { font-size:0.8em;font-family:arial,helvetica,sans-serif; }
* html body {font-size:0.8em}
* html p {font-size:0.8em}
* html td {font-size:0.8em}
* html th {font-size:0.8em}
* html input {font-size:0.8em}
* html submit {font-size:0.8em}
td { vertical-align:top }
a { color:black; font-weight:none; text-decoration:none; }
a:hover { text-decoration:underline; }
div.content { padding:1em 1em 1em 1em; position:absolute; width:97%; z-index:100; }
h1.memcache { background:rgb(153,153,204); margin:0; padding:0.5em 1em 0.5em 1em; }
* html h1.memcache { margin-bottom:-7px; }
h1.memcache a:hover { text-decoration:none; color:rgb(90,90,90); }
h1.memcache span.logo {
background:rgb(119,123,180);
color:black;
border-right: solid black 1px;
border-bottom: solid black 1px;
font-style:italic;
font-size:1em;
padding-left:1.2em;
padding-right:1.2em;
text-align:right;
display:block;
width:130px;
}
h1.memcache span.logo span.name { color:white; font-size:0.7em; padding:0 0.8em 0 2em; }
h1.memcache span.nameinfo { color:white; display:inline; font-size:0.4em; margin-left: 3em; }
h1.memcache div.copy { color:black; font-size:0.4em; position:absolute; right:1em; }
hr.memcache {
background:white;
border-bottom:solid rgb(102,102,153) 1px;
border-style:none;
border-top:solid rgb(102,102,153) 10px;
height:12px;
margin:0;
margin-top:1px;
padding:0;
}
ol,menu { margin:1em 0 0 0; padding:0.2em; margin-left:1em;}
ol.menu li { display:inline; margin-right:0.7em; list-style:none; font-size:85%}
ol.menu a {
background:rgb(153,153,204);
border:solid rgb(102,102,153) 2px;
color:white;
font-weight:bold;
margin-right:0em;
padding:0.1em 0.5em 0.1em 0.5em;
text-decoration:none;
margin-left: 5px;
}
ol.menu a.child_active {
background:rgb(153,153,204);
border:solid rgb(102,102,153) 2px;
color:white;
font-weight:bold;
margin-right:0em;
padding:0.1em 0.5em 0.1em 0.5em;
text-decoration:none;
border-left: solid black 5px;
margin-left: 0px;
}
ol.menu span.active {
background:rgb(153,153,204);
border:solid rgb(102,102,153) 2px;
color:black;
font-weight:bold;
margin-right:0em;
padding:0.1em 0.5em 0.1em 0.5em;
text-decoration:none;
border-left: solid black 5px;
}
ol.menu span.inactive {
background:rgb(193,193,244);
border:solid rgb(182,182,233) 2px;
color:white;
font-weight:bold;
margin-right:0em;
padding:0.1em 0.5em 0.1em 0.5em;
text-decoration:none;
margin-left: 5px;
}
ol.menu a:hover {
background:rgb(193,193,244);
text-decoration:none;
}
div.info {
background:rgb(204,204,204);
border:solid rgb(204,204,204) 1px;
margin-bottom:1em;
}
div.info h2 {
background:rgb(204,204,204);
color:black;
font-size:1em;
margin:0;
padding:0.1em 1em 0.1em 1em;
}
div.info table {
border:solid rgb(204,204,204) 1px;
border-spacing:0;
width:100%;
}
div.info table th {
background:rgb(204,204,204);
color:white;
margin:0;
padding:0.1em 1em 0.1em 1em;
}
div.info table th a.sortable { color:black; }
div.info table tr.tr-0 { background:rgb(238,238,238); }
div.info table tr.tr-1 { background:rgb(221,221,221); }
div.info table td { padding:0.3em 1em 0.3em 1em; }
div.info table td.td-0 { border-right:solid rgb(102,102,153) 1px; white-space:nowrap; }
div.info table td.td-n { border-right:solid rgb(102,102,153) 1px; }
div.info table td h3 {
color:black;
font-size:1.1em;
margin-left:-0.3em;
}
.td-0 a , .td-n a, .tr-0 a , tr-1 a {
text-decoration:underline;
}
div.graph { margin-bottom:1em }
div.graph h2 { background:rgb(204,204,204);; color:black; font-size:1em; margin:0; padding:0.1em 1em 0.1em 1em; }
div.graph table { border:solid rgb(204,204,204) 1px; color:black; font-weight:normal; width:100%; }
div.graph table td.td-0 { background:rgb(238,238,238); }
div.graph table td.td-1 { background:rgb(221,221,221); }
div.graph table td { padding:0.2em 1em 0.4em 1em; }
div.div1,div.div2 { margin-bottom:1em; width:35em; }
div.div3 { position:absolute; left:40em; top:1em; width:580px; }
//div.div3 { position:absolute; left:37em; top:1em; right:1em; }
div.sorting { margin:1.5em 0em 1.5em 2em }
.center { text-align:center }
.aright { position:absolute;right:1em }
.right { text-align:right }
.ok { color:rgb(0,200,0); font-weight:bold}
.failed { color:rgb(200,0,0); font-weight:bold}
span.box {
border: black solid 1px;
border-right:solid black 2px;
border-bottom:solid black 2px;
padding:0 0.5em 0 0.5em;
margin-right:1em;
}
span.green { background:#60F060; padding:0 0.5em 0 0.5em}
span.red { background:#D06030; padding:0 0.5em 0 0.5em }
div.authneeded {
background:rgb(238,238,238);
border:solid rgb(204,204,204) 1px;
color:rgb(200,0,0);
font-size:1.2em;
font-weight:bold;
padding:2em;
text-align:center;
}
input {
background:rgb(153,153,204);
border:solid rgb(102,102,153) 2px;
color:white;
font-weight:bold;
margin-right:1em;
padding:0.1em 0.5em 0.1em 0.5em;
}
//-->
</style>
</head>
<body>
<div class="head">
<h1 class="memcache">
<span class="logo"><a href="http://pecl.php.net/package/memcache">memcache</a></span>
<span class="nameinfo">memcache.php by <a href="http://livebookmark.net">Harun Yayli</a></span>
</h1>
<hr class="memcache">
</div>
<div class=content>
EOB;
return $header;
}
function getFooter(){
global $VERSION;
$footer = '</div><!-- Based on apc.php '.$VERSION.'--></body>
</html>
';
return $footer;
}
function getMenu(){
global $PHP_SELF;
echo "<ol class=menu>";
if ($_GET['op']!=4){
echo <<<EOB
<li><a href="$PHP_SELF&op={$_GET['op']}">Refresh Data</a></li>
EOB;
}
else {
echo <<<EOB
<li><a href="$PHP_SELF&op=2}">Back</a></li>
EOB;
}
echo
menu_entry(1,'View Host Stats'),
menu_entry(2,'Variables');
echo <<<EOB
</ol>
<br/>
EOB;
}
// TODO, AUTH
$_GET['op'] = !isset($_GET['op'])? '1':$_GET['op'];
//$PHP_SELF= isset($_SERVER['PHP_SELF']) ? htmlentities(strip_tags($_SERVER['PHP_SELF'],'')) : '';
//Line above modified to make this work for the Drupal 'Prod check' module
global $PHP_SELF;
$PHP_SELF= isset($_GET['q']) ? base_path() . htmlentities(strip_tags($_GET['q'],'')) : '';
$PHP_SELF=$PHP_SELF.'?';
$time = time();
// sanitize _GET
foreach($_GET as $key=>$g){
$_GET[$key]=htmlentities($g);
}
// singleout
// when singleout is set, it only gives details for that server.
if (isset($_GET['singleout']) && $_GET['singleout']>=0 && $_GET['singleout'] <count($MEMCACHE_SERVERS)){
$MEMCACHE_SERVERS = array($MEMCACHE_SERVERS[$_GET['singleout']]);
}
// display images
if (isset($_GET['IMG'])){
$memcacheStats = getMemcacheStats();
$memcacheStatsSingle = getMemcacheStats(false);
if (!graphics_avail()) {
exit(0);
}
function fill_box($im, $x, $y, $w, $h, $color1, $color2,$text='',$placeindex='') {
global $col_black;
$x1=$x+$w-1;
$y1=$y+$h-1;
imagerectangle($im, $x, $y1, $x1+1, $y+1, $col_black);
if($y1>$y) imagefilledrectangle($im, $x, $y, $x1, $y1, $color2);
else imagefilledrectangle($im, $x, $y1, $x1, $y, $color2);
imagerectangle($im, $x, $y1, $x1, $y, $color1);
if ($text) {
if ($placeindex>0) {
if ($placeindex<16)
{
$px=5;
$py=$placeindex*12+6;
imagefilledrectangle($im, $px+90, $py+3, $px+90-4, $py-3, $color2);
imageline($im,$x,$y+$h/2,$px+90,$py,$color2);
imagestring($im,2,$px,$py-6,$text,$color1);
} else {
if ($placeindex<31) {
$px=$x+40*2;
$py=($placeindex-15)*12+6;
} else {
$px=$x+40*2+100*intval(($placeindex-15)/15);
$py=($placeindex%15)*12+6;
}
imagefilledrectangle($im, $px, $py+3, $px-4, $py-3, $color2);
imageline($im,$x+$w,$y+$h/2,$px,$py,$color2);
imagestring($im,2,$px+2,$py-6,$text,$color1);
}
} else {
imagestring($im,4,$x+5,$y1-16,$text,$color1);
}
}
}
function fill_arc($im, $centerX, $centerY, $diameter, $start, $end, $color1,$color2,$text='',$placeindex=0) {
$r=$diameter/2;
$w=deg2rad((360+$start+($end-$start)/2)%360);
if (function_exists("imagefilledarc")) {
// exists only if GD 2.0.1 is avaliable
imagefilledarc($im, $centerX+1, $centerY+1, $diameter, $diameter, $start, $end, $color1, IMG_ARC_PIE);
imagefilledarc($im, $centerX, $centerY, $diameter, $diameter, $start, $end, $color2, IMG_ARC_PIE);
imagefilledarc($im, $centerX, $centerY, $diameter, $diameter, $start, $end, $color1, IMG_ARC_NOFILL|IMG_ARC_EDGED);
} else {
imagearc($im, $centerX, $centerY, $diameter, $diameter, $start, $end, $color2);
imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($start)) * $r, $centerY + sin(deg2rad($start)) * $r, $color2);
imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($start+1)) * $r, $centerY + sin(deg2rad($start)) * $r, $color2);
imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($end-1)) * $r, $centerY + sin(deg2rad($end)) * $r, $color2);
imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($end)) * $r, $centerY + sin(deg2rad($end)) * $r, $color2);
imagefill($im,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2, $color2);
}
if ($text) {
if ($placeindex>0) {
imageline($im,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$diameter, $placeindex*12,$color1);
imagestring($im,4,$diameter, $placeindex*12,$text,$color1);
} else {
imagestring($im,4,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$text,$color1);
}
}
}
$size = GRAPH_SIZE; // image size
$image = imagecreate($size+50, $size+10);
$col_white = imagecolorallocate($image, 0xFF, 0xFF, 0xFF);
$col_red = imagecolorallocate($image, 0xD0, 0x60, 0x30);
$col_green = imagecolorallocate($image, 0x60, 0xF0, 0x60);
$col_black = imagecolorallocate($image, 0, 0, 0);
imagecolortransparent($image,$col_white);
switch ($_GET['IMG']){
case 1: // pie chart
$tsize=$memcacheStats['limit_maxbytes'];
$avail=$tsize-$memcacheStats['bytes'];
$x=$y=$size/2;
$angle_from = 0;
$fuzz = 0.000001;
foreach($memcacheStatsSingle as $serv=>$mcs) {
$free = $mcs['STAT']['limit_maxbytes']-$mcs['STAT']['bytes'];
$used = $mcs['STAT']['bytes'];
if ($free>0){
// draw free
$angle_to = ($free*360)/$tsize;
$perc =sprintf("%.2f%%", ($free *100) / $tsize) ;
fill_arc($image,$x,$y,$size,$angle_from,$angle_from + $angle_to ,$col_black,$col_green,$perc);
$angle_from = $angle_from + $angle_to ;
}
if ($used>0){
// draw used
$angle_to = ($used*360)/$tsize;
$perc =sprintf("%.2f%%", ($used *100) / $tsize) ;
fill_arc($image,$x,$y,$size,$angle_from,$angle_from + $angle_to ,$col_black,$col_red, '('.$perc.')' );
$angle_from = $angle_from+ $angle_to ;
}
}
break;
case 2: // hit miss
$hits = ($memcacheStats['get_hits']==0) ? 1:$memcacheStats['get_hits'];
$misses = ($memcacheStats['get_misses']==0) ? 1:$memcacheStats['get_misses'];
$total = $hits + $misses ;
fill_box($image, 30,$size,50,-$hits*($size-21)/$total,$col_black,$col_green,sprintf("%.1f%%",$hits*100/$total));
fill_box($image,130,$size,50,-max(4,($total-$hits)*($size-21)/$total),$col_black,$col_red,sprintf("%.1f%%",$misses*100/$total));
break;
}
header("Content-type: image/png");
imagepng($image);
exit;
}
echo getHeader();
echo getMenu();
switch ($_GET['op']) {
case 1: // host stats
$phpversion = phpversion();
$memcacheStats = getMemcacheStats();
$memcacheStatsSingle = getMemcacheStats(false);
$mem_size = $memcacheStats['limit_maxbytes'];
$mem_used = $memcacheStats['bytes'];
$mem_avail= $mem_size-$mem_used;
$startTime = time()-array_sum($memcacheStats['uptime']);
$curr_items = $memcacheStats['curr_items'];
$total_items = $memcacheStats['total_items'];
$hits = ($memcacheStats['get_hits']==0) ? 1:$memcacheStats['get_hits'];
$misses = ($memcacheStats['get_misses']==0) ? 1:$memcacheStats['get_misses'];
$sets = $memcacheStats['cmd_set'];
$req_rate = sprintf("%.2f",($hits+$misses)/($time-$startTime));
$hit_rate = sprintf("%.2f",($hits)/($time-$startTime));
$miss_rate = sprintf("%.2f",($misses)/($time-$startTime));
$set_rate = sprintf("%.2f",($sets)/($time-$startTime));
echo <<< EOB
<div class="info div1"><h2>General Cache Information</h2>
<table cellspacing=0><tbody>
<tr class=tr-1><td class=td-0>PHP Version</td><td>$phpversion</td></tr>
EOB;
echo "<tr class=tr-0><td class=td-0>Memcached Host". ((count($MEMCACHE_SERVERS)>1) ? 's':'')."</td><td>";
$i=0;
if (!isset($_GET['singleout']) && count($MEMCACHE_SERVERS)>1){
foreach($MEMCACHE_SERVERS as $server){
echo ($i+1).'. <a href="'.$PHP_SELF.'&singleout='.$i++.'">'.$server.'</a><br/>';
}
}
else{
echo '1.'.$MEMCACHE_SERVERS[0];
}
if (isset($_GET['singleout'])){
echo '<a href="'.$PHP_SELF.'">(all servers)</a><br/>';
}
echo "</td></tr>\n";
echo "<tr class=tr-1><td class=td-0>Total Memcache Cache</td><td>".bsize($memcacheStats['limit_maxbytes'])."</td></tr>\n";
echo <<<EOB
</tbody></table>
</div>
<div class="info div1"><h2>Memcache Server Information</h2>
EOB;
foreach($MEMCACHE_SERVERS as $server){
echo '<table cellspacing=0><tbody>';
echo '<tr class=tr-1><td class=td-1>'.$server.'</td><td><a href="'.$PHP_SELF.'&server='.array_search($server,$MEMCACHE_SERVERS).'&op=6">[<b>Flush this server</b>]</a></td></tr>';
echo '<tr class=tr-0><td class=td-0>Start Time</td><td>',date(DATE_FORMAT,$memcacheStatsSingle[$server]['STAT']['time']-$memcacheStatsSingle[$server]['STAT']['uptime']),'</td></tr>';
echo '<tr class=tr-1><td class=td-0>Uptime</td><td>',duration($memcacheStatsSingle[$server]['STAT']['time']-$memcacheStatsSingle[$server]['STAT']['uptime']),'</td></tr>';
echo '<tr class=tr-0><td class=td-0>Memcached Server Version</td><td>'.$memcacheStatsSingle[$server]['STAT']['version'].'</td></tr>';
echo '<tr class=tr-1><td class=td-0>Used Cache Size</td><td>',bsize($memcacheStatsSingle[$server]['STAT']['bytes']),'</td></tr>';
echo '<tr class=tr-0><td class=td-0>Total Cache Size</td><td>',bsize($memcacheStatsSingle[$server]['STAT']['limit_maxbytes']),'</td></tr>';
echo '</tbody></table>';
}
echo <<<EOB
</div>
<div class="graph div3"><h2>Host Status Diagrams</h2>
<table cellspacing=0><tbody>
EOB;
$size='width='.(GRAPH_SIZE+50).' height='.(GRAPH_SIZE+10);
echo <<<EOB
<tr>
<td class=td-0>Cache Usage</td>
<td class=td-1>Hits &amp; Misses</td>
</tr>
EOB;
echo
graphics_avail() ?
'<tr>'.
"<td class=td-0><img alt=\"\" $size src=\"$PHP_SELF&IMG=1&".(isset($_GET['singleout'])? 'singleout='.$_GET['singleout'].'&':'')."$time\"></td>".
"<td class=td-1><img alt=\"\" $size src=\"$PHP_SELF&IMG=2&".(isset($_GET['singleout'])? 'singleout='.$_GET['singleout'].'&':'')."$time\"></td></tr>\n"
: "",
'<tr>',
'<td class=td-0><span class="green box">&nbsp;</span>Free: ',bsize($mem_avail).sprintf(" (%.1f%%)",$mem_avail*100/$mem_size),"</td>\n",
'<td class=td-1><span class="green box">&nbsp;</span>Hits: ',$hits.sprintf(" (%.1f%%)",$hits*100/($hits+$misses)),"</td>\n",
'</tr>',
'<tr>',
'<td class=td-0><span class="red box">&nbsp;</span>Used: ',bsize($mem_used ).sprintf(" (%.1f%%)",$mem_used *100/$mem_size),"</td>\n",
'<td class=td-1><span class="red box">&nbsp;</span>Misses: ',$misses.sprintf(" (%.1f%%)",$misses*100/($hits+$misses)),"</td>\n";
echo <<< EOB
</tr>
</tbody></table>
<br/>
<div class="info"><h2>Cache Information</h2>
<table cellspacing=0><tbody>
<tr class=tr-0><td class=td-0>Current Items(total)</td><td>$curr_items ($total_items)</td></tr>
<tr class=tr-1><td class=td-0>Hits</td><td>{$hits}</td></tr>
<tr class=tr-0><td class=td-0>Misses</td><td>{$misses}</td></tr>
<tr class=tr-1><td class=td-0>Request Rate (hits, misses)</td><td>$req_rate cache requests/second</td></tr>
<tr class=tr-0><td class=td-0>Hit Rate</td><td>$hit_rate cache requests/second</td></tr>
<tr class=tr-1><td class=td-0>Miss Rate</td><td>$miss_rate cache requests/second</td></tr>
<tr class=tr-0><td class=td-0>Set Rate</td><td>$set_rate cache requests/second</td></tr>
</tbody></table>
</div>
EOB;
break;
case 2: // variables
$m=0;
$cacheItems= getCacheItems();
$items = $cacheItems['items'];
$totals = $cacheItems['counts'];
$maxDump = MAX_ITEM_DUMP;
foreach($items as $server => $entries) {
echo <<< EOB
<div class="info"><table cellspacing=0><tbody>
<tr><th colspan="2">$server</th></tr>
<tr><th>Slab Id</th><th>Info</th></tr>
EOB;
foreach($entries as $slabId => $slab) {
$dumpUrl = $PHP_SELF.'&op=2&server='.(array_search($server,$MEMCACHE_SERVERS)).'&dumpslab='.$slabId;
echo
"<tr class=tr-$m>",
"<td class=td-0><center>",'<a href="',$dumpUrl,'">',$slabId,'</a>',"</center></td>",
"<td class=td-last><b>Item count:</b> ",$slab['number'],'<br/><b>Age:</b>',duration($time-$slab['age']),'<br/> <b>Evicted:</b>',((isset($slab['evicted']) && $slab['evicted']==1)? 'Yes':'No');
if ((isset($_GET['dumpslab']) && $_GET['dumpslab']==$slabId) && (isset($_GET['server']) && $_GET['server']==array_search($server,$MEMCACHE_SERVERS))){
echo "<br/><b>Items: item</b><br/>";
$items = dumpCacheSlab($server,$slabId,$slab['number']);
// maybe someone likes to do a pagination here :)
$i=1;
foreach($items['ITEM'] as $itemKey=>$itemInfo){
$itemInfo = trim($itemInfo,'[ ]');
echo '<a href="',$PHP_SELF,'&op=4&server=',(array_search($server,$MEMCACHE_SERVERS)),'&key=',base64_encode($itemKey).'">',$itemKey,'</a>';
if ($i++ % 10 == 0) {
echo '<br/>';
}
elseif ($i!=$slab['number']+1){
echo ',';
}
}
}
echo "</td></tr>";
$m=1-$m;
}
echo <<<EOB
</tbody></table>
</div><hr/>
EOB;
}
break;
break;
case 4: //item dump
if (!isset($_GET['key']) || !isset($_GET['server'])){
echo "No key set!";
break;
}
// I'm not doing anything to check the validity of the key string.
// probably an exploit can be written to delete all the files in key=base64_encode("\n\r delete all").
// somebody has to do a fix to this.
$theKey = htmlentities(base64_decode($_GET['key']));
$theserver = $MEMCACHE_SERVERS[(int)$_GET['server']];
list($h,$p) = get_host_port_from_server($theserver);
$r = sendMemcacheCommand($h,$p,'get '.$theKey);
echo <<<EOB
<div class="info"><table cellspacing=0><tbody>
<tr><th>Server<th>Key</th><th>Value</th><th>Delete</th></tr>
EOB;
if (!isset($r['VALUE'])) {
echo "<tr><td class=td-0>",$theserver,"</td><td class=td-0>",$theKey,
"</td><td>[The requested item was not found or has expired]</td>",
"<td></td>","</tr>";
}
else {
echo "<tr><td class=td-0>",$theserver,"</td><td class=td-0>",$theKey,
" <br/>flag:",$r['VALUE'][$theKey]['stat']['flag'],
" <br/>Size:",bsize($r['VALUE'][$theKey]['stat']['size']),
"</td><td>",chunk_split($r['VALUE'][$theKey]['value'],40),"</td>",
'<td><a href="',$PHP_SELF,'&op=5&server=',(int)$_GET['server'],'&key=',base64_encode($theKey),"\">Delete</a></td>","</tr>";
}
echo <<<EOB
</tbody></table>
</div><hr/>
EOB;
break;
case 5: // item delete
if (!isset($_GET['key']) || !isset($_GET['server'])){
echo "No key set!";
break;
}
$theKey = htmlentities(base64_decode($_GET['key']));
$theserver = $MEMCACHE_SERVERS[(int)$_GET['server']];
list($h,$p) = get_host_port_from_server($theserver);
$r = sendMemcacheCommand($h,$p,'delete '.$theKey);
echo 'Deleting '.$theKey.':'.$r;
break;
case 6: // flush server
$theserver = $MEMCACHE_SERVERS[(int)$_GET['server']];
$r = flushServer($theserver);
echo 'Flush '.$theserver.":".$r;
break;
}
echo getFooter();
?>

View File

@@ -0,0 +1,53 @@
<?php
/**
* Returns HTML for the status report.
*
* @param $variables
* An associative array containing:
* - requirements: An array of requirements.
*
* @ingroup themeable
*/
function theme_prod_check_status_report($variables) {
$requirements = $variables['requirements'];
$severities = array(
PROD_CHECK_REQUIREMENT_INFO => array(
'title' => t('Info'),
'class' => 'info',
),
PROD_CHECK_REQUIREMENT_OK => array(
'title' => t('OK'),
'class' => 'ok',
),
PROD_CHECK_REQUIREMENT_WARNING => array(
'title' => t('Warning'),
'class' => 'warning',
),
PROD_CHECK_REQUIREMENT_ERROR => array(
'title' => t('Error'),
'class' => 'error',
),
);
$output = '<table class="system-status-report">';
foreach ($requirements as $requirement) {
if (empty($requirement['#type'])) {
$severity = $severities[isset($requirement['severity']) ? (int) $requirement['severity'] : 0];
$severity['icon'] = '<div title="' . $severity['title'] . '"><span class="element-invisible">' . $severity['title'] . '</span></div>';
// Output table row(s)
if (!empty($requirement['description'])) {
$output .= '<tr class="' . $severity['class'] . ' merge-down"><td class="status-icon">' . $severity['icon'] . '</td><td class="status-title">' . $requirement['title'] . '</td><td class="status-value">' . $requirement['value'] . '</td></tr>';
$output .= '<tr class="' . $severity['class'] . ' merge-up"><td colspan="3" class="status-description">' . $requirement['description'] . '</td></tr>';
}
else {
$output .= '<tr class="' . $severity['class'] . '"><td class="status-icon">' . $severity['icon'] . '</td><td class="status-title">' . $requirement['title'] . '</td><td class="status-value">' . $requirement['value'] . '</td></tr>';
}
}
}
$output .= '</table>';
return $output;
}

View File

@@ -0,0 +1,230 @@
<?php
/**
* ALL code here is taken from the Drupal core's update module. prod_check
* recommends that you turn this module off, so we provide the VERY BASIC
* functionality to get a list of the installed modules with version info and
* transfer this to prod_monitor over XMLRPC (alot of data here!) so that
* prod_monitor can do all the update checking locally.
* This approach was chosen over this approach:
*
* module_load_include('module', 'update', 'update');
*
* if ($available = update_get_available(TRUE)) {
* $data['modules'] = update_calculate_project_data($available);
* }
*
* This way, we might just as well turn on the update module and periodically
* download the results. It's just not efficient...
* Also note that passing TRUE to update_get_available() will bypass (refresh)
* the caches, essentially the same as we do in _prod_check_module_list().
* See inline comments there for more info.
*/
/**
* Taken from Core: modules/update/update.compare.inc, line 81
*
* Populate an array of project data.
*
* This iterates over a list of the installed modules or themes and groups
* them by project and status. A few parts of this function assume that
* enabled modules and themes are always processed first, and if disabled
* modules or themes are being processed (there is a setting to control if
* disabled code should be included in the Available updates report or not),
* those are only processed after $projects has been populated with
* information about the enabled code. 'Hidden' modules and themes are always
* ignored. This function also records the latest change time on the .info
* files for each module or theme, which is important data which is used when
* deciding if the cached available update data should be invalidated.
*
* @param $projects
* Reference to the array of project data of what's installed on this site.
* @param $list
* Array of data to process to add the relevant info to the $projects array.
* @param $project_type
* The kind of data in the list (can be 'module' or 'theme').
* @param $status
* Boolean that controls what status (enabled or disabled) to process out of
* the $list and add to the $projects array.
*
* @see update_get_projects()
*/
function _prod_check_process_info_list(&$projects, $list, $project_type, $status) {
foreach ($list as $file) {
// A disabled base theme of an enabled sub-theme still has all of its code
// run by the sub-theme, so we include it in our "enabled" projects list.
if ($status && !$file->status && !empty($file->sub_themes)) {
foreach ($file->sub_themes as $key => $name) {
// Build a list of enabled sub-themes.
if ($list[$key]->status) {
$file->enabled_sub_themes[$key] = $name;
}
}
// If there are no enabled subthemes, we should ignore this base theme
// for the enabled case. If the site is trying to display disabled
// themes, we'll catch it then.
if (empty($file->enabled_sub_themes)) {
continue;
}
}
// Otherwise, just add projects of the proper status to our list.
elseif ($file->status != $status) {
continue;
}
// Skip if the .info file is broken.
if (empty($file->info)) {
continue;
}
// Skip if it's a hidden module or theme.
if (!empty($file->info['hidden'])) {
continue;
}
// If the .info doesn't define the 'project', try to figure it out.
if (!isset($file->info['project'])) {
$file->info['project'] = _prod_check_get_project_name($file);
}
// If we still don't know the 'project', give up.
if (empty($file->info['project'])) {
continue;
}
// If we don't already know it, grab the change time on the .info file
// itself. Note: we need to use the ctime, not the mtime (modification
// time) since many (all?) tar implementations will go out of their way to
// set the mtime on the files it creates to the timestamps recorded in the
// tarball. We want to see the last time the file was changed on disk,
// which is left alone by tar and correctly set to the time the .info file
// was unpacked.
if (!isset($file->info['_info_file_ctime'])) {
$info_filename = dirname($file->uri) . '/' . $file->name . '.info';
$file->info['_info_file_ctime'] = filectime($info_filename);
}
if (!isset($file->info['datestamp'])) {
$file->info['datestamp'] = 0;
}
$project_name = $file->info['project'];
// Figure out what project type we're going to use to display this module
// or theme. If the project name is 'drupal', we don't want it to show up
// under the usual "Modules" section, we put it at a special "Drupal Core"
// section at the top of the report.
if ($project_name == 'drupal') {
$project_display_type = 'core';
}
else {
$project_display_type = $project_type;
}
if (empty($status) && empty($file->enabled_sub_themes)) {
// If we're processing disabled modules or themes, append a suffix.
// However, we don't do this to a a base theme with enabled
// subthemes, since we treat that case as if it is enabled.
$project_display_type .= '-disabled';
}
// Add a list of sub-themes that "depend on" the project and a list of base
// themes that are "required by" the project.
if ($project_name == 'drupal') {
// Drupal core is always required, so this extra info would be noise.
$sub_themes = array();
$base_themes = array();
}
else {
// Add list of enabled sub-themes.
$sub_themes = !empty($file->enabled_sub_themes) ? $file->enabled_sub_themes : array();
// Add list of base themes.
$base_themes = !empty($file->base_themes) ? $file->base_themes : array();
}
if (!isset($projects[$project_name])) {
// Only process this if we haven't done this project, since a single
// project can have multiple modules or themes.
$projects[$project_name] = array(
'name' => $project_name,
// Only save attributes from the .info file we care about so we do not
// bloat our RAM usage needlessly.
'info' => _prod_check_filter_project_info($file->info),
'datestamp' => $file->info['datestamp'],
'includes' => array($file->name => $file->info['name']),
'project_type' => $project_display_type,
'project_status' => $status,
'sub_themes' => $sub_themes,
'base_themes' => $base_themes,
);
}
elseif ($projects[$project_name]['project_type'] == $project_display_type) {
// Only add the file we're processing to the 'includes' array for this
// project if it is of the same type and status (which is encoded in the
// $project_display_type). This prevents listing all the disabled
// modules included with an enabled project if we happen to be checking
// for disabled modules, too.
$projects[$project_name]['includes'][$file->name] = $file->info['name'];
$projects[$project_name]['info']['_info_file_ctime'] = max($projects[$project_name]['info']['_info_file_ctime'], $file->info['_info_file_ctime']);
$projects[$project_name]['datestamp'] = max($projects[$project_name]['datestamp'], $file->info['datestamp']);
if (!empty($sub_themes)) {
$projects[$project_name]['sub_themes'] += $sub_themes;
}
if (!empty($base_themes)) {
$projects[$project_name]['base_themes'] += $base_themes;
}
}
elseif (empty($status)) {
// If we have a project_name that matches, but the project_display_type
// does not, it means we're processing a disabled module or theme that
// belongs to a project that has some enabled code. In this case, we add
// the disabled thing into a separate array for separate display.
$projects[$project_name]['disabled'][$file->name] = $file->info['name'];
}
}
}
/**
* Taken from Core: modules/update/update.compare.inc, line 238
*
* Given a $file object (as returned by system_get_files_database()), figure
* out what project it belongs to.
*
* @see system_get_files_database()
*/
function _prod_check_get_project_name($file) {
$project_name = '';
if (isset($file->info['project'])) {
$project_name = $file->info['project'];
}
elseif (isset($file->info['package']) && (strpos($file->info['package'], 'Core') === 0)) {
$project_name = 'drupal';
}
return $project_name;
}
/**
* Taken from Core: modules/update/update.compare.inc, line 684
*
* Filter the project .info data to only save attributes we need.
*
* @param array $info
* Array of .info file data as returned by drupal_parse_info_file().
*
* @return
* Array of .info file data we need for the Update manager.
*
* @see _prod_check_process_info_list()
*/
function _prod_check_filter_project_info($info) {
$whitelist = array(
'_info_file_ctime',
'datestamp',
'major',
'name',
'package',
'project',
'project status url',
'version',
);
return array_intersect_key($info, drupal_map_assoc($whitelist));
}