formatter = $formatter; $this->archiveBuilder = $archiveBuilder; $this->debugLogger = $debugLogger; $this->errorLogger = $errorLogger; } /** * Send the developer log email. * * @param array $payload FeedbackTransport-built payload. * @param string $debugFilePath * @param string $oldDebugFilePath * @param string $zipFilePath * @param string $debugFilename * @return bool True if wp_mail() reported success. */ public function send( array $payload, string $debugFilePath, string $oldDebugFilePath, string $zipFilePath, string $debugFilename ): bool { $previouslySentLine = isset($payload['previously_sent_line']) && is_scalar($payload['previously_sent_line']) ? (int)$payload['previously_sent_line'] : 0; call_user_func($this->debugLogger, "Creating zip file of error log file. " . "Previously sent error line: " . $previouslySentLine); $logFileZip = $this->archiveBuilder->build($zipFilePath, $debugFilePath, $oldDebugFilePath, $this->diagnosticJournalPaths()); $subject = $this->formatter->buildSubject($payload); $body = $this->formatter->buildBody($payload, $subject, $debugFilename); $to = ABJ404_AUTHOR_EMAIL; $headers = array('Content-Type: text/html; charset=UTF-8'); $adminEmail = get_option('admin_email'); $headers[] = 'From: ' . (is_scalar($adminEmail) ? (string)$adminEmail : ''); $attachments = array(); if ($logFileZip !== '' && file_exists($logFileZip)) { $attachments[] = $logFileZip; } call_user_func($this->debugLogger, "Sending error log zip file as attachment."); $result = wp_mail($to, $subject, $body, $headers, $attachments); if ($logFileZip !== '' && file_exists($logFileZip)) { ABJ_404_Solution_FileSystemService::safeUnlink($logFileZip); } if ((bool)$result) { call_user_func($this->debugLogger, "Mail sent. Log zip file deleted."); } else { call_user_func($this->errorLogger, "wp_mail() returned false while sending the developer error/heartbeat log email. " . "Recipient: " . $to . ". Subject: " . $subject); } return (bool)$result; } /** * Both AJAX diagnostic journals, whole, for the archive. * * The support payload can only carry a ranked, budgeted excerpt of these; * the archive is the channel where a budget decision cannot lose evidence. * Each journal names its own files, so no path string is duplicated here. * * @return array */ private function diagnosticJournalPaths(): array { $paths = array(); if (class_exists('ABJ_404_Solution_CheckpointJournalReader')) { $paths = array_merge($paths, ABJ_404_Solution_CheckpointJournalReader::supportArchivePaths()); } if (class_exists('ABJ_404_Solution_AjaxTraceJournal')) { $paths = array_merge($paths, ABJ_404_Solution_AjaxTraceJournal::supportArchivePaths()); } return $paths; } }