settings = $settings; $this->wp = $wp; $this->subscribersFeature = $subscribersFeature; $this->wooCommerceHelper = $wooCommerceHelper; $this->dataInconsistencyController = $dataInconsistencyController; $this->bridge = $bridge; $this->cronHelper = $cronHelper; } public function getData($maskApiKey = false) { return array_merge($this->getUserData(), $this->getSiteData($maskApiKey)); } public function getUserData() { $currentUser = WPFunctions::get()->wpGetCurrentUser(); $sender = $this->settings->get('sender', ['address' => null]); return [ 'name' => $currentUser->display_name, // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps 'email' => $sender['address'], ]; } public function getSiteData($maskApiKey = false) { global $wpdb; $dbVersion = $wpdb->get_var('SELECT @@VERSION'); $mta = $this->settings->get('mta'); $currentTheme = WPFunctions::get()->wpGetTheme(); $premiumKey = $this->settings->get(Bridge::PREMIUM_KEY_SETTING_NAME) ?: $this->settings->get(Bridge::API_KEY_SETTING_NAME); if ($maskApiKey) { $premiumKey = $this->maskApiKey($premiumKey); } $cronDaemonStatus = $this->cronHelper->getDaemon() ?? []; try { $cronPingUrl = $this->cronHelper->getCronUrl(CronDaemon::ACTION_PING); $cronPingResponse = $this->getCronPingResponse(); } catch (\Exception $e) { $cronPingUrl = __('Can‘t generate cron URL.', 'mailpoet') . ' (' . $e->getMessage() . ')'; $cronPingResponse = $cronPingUrl; } $mailerLog = MailerLog::getMailerLog(); $mailerLog['sent'] = MailerLog::sentSince(); $inconsistencyStatus = $this->dataInconsistencyController->getInconsistentDataStatus(); unset($inconsistencyStatus['total']); $pingBridgeResponse = $this->getBridgePingResponse(); $pingResponse = $this->wp->isWpError($pingBridgeResponse) ? $pingBridgeResponse->get_error_message() // @phpstan-ignore-line : $this->wp->wpRemoteRetrieveResponseCode($pingBridgeResponse) . ' HTTP status code'; $ApiKeyState = $this->settings->get(Bridge::API_KEY_STATE_SETTING_NAME . '.state'); $premiumKeyState = $this->settings->get(Bridge::PREMIUM_KEY_STATE_SETTING_NAME . '.state'); // the HelpScout Beacon API has a limit of 20 attribute-value pairs (https://developer.helpscout.com/beacon-2/web/javascript-api/#beacon-session-data) return [ 'PHP version' => PHP_VERSION, 'MailPoet Free version' => MAILPOET_VERSION, 'MailPoet Premium version' => (defined('MAILPOET_PREMIUM_VERSION')) ? MAILPOET_PREMIUM_VERSION : 'N/A', 'MailPoet Premium/MSS key' => $premiumKey, 'WordPress version' => $this->wp->getBloginfo('version'), 'Database version' => $dbVersion, 'Web server' => (!empty($_SERVER["SERVER_SOFTWARE"])) ? sanitize_text_field(wp_unslash($_SERVER["SERVER_SOFTWARE"])) : 'N/A', 'Server OS' => (function_exists('php_uname')) ? php_uname() : 'N/A', 'WP info' => $this->formatCompositeField([ 'WP_MEMORY_LIMIT' => WP_MEMORY_LIMIT, 'WP_MAX_MEMORY_LIMIT' => WP_MAX_MEMORY_LIMIT, 'WP_DEBUG' => WP_DEBUG, 'WordPress language' => $this->wp->getLocale(), 'WordPress timezone' => $this->wp->wpTimezoneString(), ]), 'PHP info' => $this->formatCompositeField([ 'PHP max_execution_time' => ini_get('max_execution_time'), 'PHP memory_limit' => ini_get('memory_limit'), 'PHP upload_max_filesize' => ini_get('upload_max_filesize'), 'PHP post_max_size' => ini_get('post_max_size'), ]), 'Multisite environment?' => (is_multisite() ? 'Yes' : 'No'), 'Current Theme' => $currentTheme->get('Name') . ' (version ' . $currentTheme->get('Version') . ')', 'Active Plugin names' => join(", ", $this->wp->getOption('active_plugins')), 'Sending Method' => $mta['method'], 'MailPoet Sending Service' => $this->formatCompositeField([ 'Is reachable' => $this->bridge->validateBridgePingResponse($pingBridgeResponse) ? 'Yes' : 'No', 'Ping response' => $pingResponse, 'API key state' => $ApiKeyState ?? 'Unset', 'Premium key state' => $premiumKeyState ?? 'Unset', ]), 'Sending Frequency' => sprintf( '%d emails every %d minutes', $mta['frequency']['emails'], $mta['frequency']['interval'] ), 'MailPoet sending info' => $this->formatCompositeField([ "Send all site's emails with" => ($this->settings->get('send_transactional_emails') ? 'current sending method' : 'default WordPress sending method'), 'Task Scheduler method' => $this->settings->get('cron_trigger.method'), 'Default FROM address' => $this->settings->get('sender.address'), 'Default Reply-To address' => $this->settings->get('reply_to.address'), 'Bounce Email Address' => $this->settings->get('bounce.address'), ]), 'MailPoet Cron / Action Scheduler' => $this->formatCompositeField([ 'Status' => $cronDaemonStatus['status'] ?? 'Unknown', 'Is reachable' => $this->cronHelper->validatePingResponse($cronPingResponse) ? 'Yes' : 'No', 'Ping URL' => $cronPingUrl, 'Ping response' => $cronPingResponse, 'Last run start' => isset($cronDaemonStatus['run_started_at']) ? date('Y-m-d H:i:s', $cronDaemonStatus['run_started_at']) : 'Unknown', 'Last run end' => isset($cronDaemonStatus['run_completed_at']) ? date('Y-m-d H:i:s', $cronDaemonStatus['run_completed_at']) : 'Unknown', 'Last seen error' => $cronDaemonStatus['last_error'] ?? 'None', ]), 'Total number of subscribers' => $this->subscribersFeature->getSubscribersCount(), 'Plugin installed at' => $this->settings->get('installed_at'), 'Installed via WooCommerce onboarding wizard' => $this->wooCommerceHelper->wasMailPoetInstalledViaWooCommerceOnboardingWizard(), 'Sending queue status' => $this->formatCompositeField([ 'Status' => $mailerLog['status'] ?? 'Unknown', 'Started at' => isset($mailerLog['started']) ? date('Y-m-d H:i:s', $mailerLog['started']) : 'Unknown', 'Emails sent' => $mailerLog['sent'], 'Retry attempts' => $mailerLog['retry_attempt'] ?? 0, 'Last seen error' => isset($mailerLog['error']) ? $mailerLog['error']['error_message'] . ' (' . $mailerLog['error']['operation'] . ')' : 'None', ]), 'Data inconsistency status' => $this->formatCompositeField($this->convertKeysToTitleCase($inconsistencyStatus)), ]; } public function getCronPingResponse(): string { if ($this->cachedCronPingResponse !== null) { return $this->cachedCronPingResponse; } $this->cachedCronPingResponse = $this->cronHelper->pingDaemon(); return $this->cachedCronPingResponse; } /** * @return array|\WP_Error */ public function getBridgePingResponse() { if ($this->cachedBridgePingResponse !== null) { return $this->cachedBridgePingResponse; } $this->cachedBridgePingResponse = $this->bridge->pingBridge(); return $this->cachedBridgePingResponse; } /** * @param $fields array of key-value pairs * @return string in the format "key1: value1 - key2: value2 - ..." */ private function formatCompositeField(array $fields) { if (empty($fields)) { return ''; } return implode(' - ', array_map(function ($key, $value) { return $key . ': ' . $value; }, array_keys($fields), array_values($fields))); } private function convertKeysToTitleCase(array $array): array { $result = []; foreach ($array as $key => $value) { $titleCaseKey = ucfirst(str_replace('_', ' ', $key)); $result[$titleCaseKey] = $value; } return $result; } protected function maskApiKey($key) { // the length of this particular key is an even number. // for odd lengths this method will change the total number of characters (which shouldn't be a problem in this context). $halfKeyLength = (int)(strlen($key ?? '') / 2); return substr($key ?? '', 0, $halfKeyLength) . str_repeat('*', $halfKeyLength); } }