[ Avaa Bypassed ]




Upload:

Command:

hmhc3928@18.223.239.65: ~ $
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing

namespace MailPoet\Mailer;

if (!defined('ABSPATH')) exit;


use MailPoet\Logging\LoggerFactory;
use MailPoet\Settings\SettingsController;

/**
 * @phpstan-type MailerLogError array{
 *    "error_code"?: non-empty-string,
 *    "error_message": string,
 *    "operation": string
 *   }
 * @phpstan-type MailerLogData array{
 *   "sent": array<string,int>,
 *   "started": int,
 *   "status": ?string,
 *   "retry_attempt": ?int,
 *   "retry_at": ?int,
 *   "error": ?MailerLogError,
 *   "transactional_email_last_error_at": ?int,
 *   "transactional_email_error_count": ?int,
 * }
 */

class MailerLog {
  const SETTING_NAME = 'mta_log';
  const STATUS_PAUSED = 'paused';
  const RETRY_ATTEMPTS_LIMIT = 3;
  const RETRY_INTERVAL = 120; // seconds

  /**
   * @param MailerLogData|null $mailerLog
   * @return MailerLogData
   */
  public static function getMailerLog(array $mailerLog = null): array {
    if ($mailerLog) return $mailerLog;
    $settings = SettingsController::getInstance();
    $mailerLog = $settings->get(self::SETTING_NAME);
    if (!$mailerLog) {
      $mailerLog = self::createMailerLog();
    }
    /**
     * The old "sent" entry was just the number of emails.
     * We need to update this entry to the new data structure.
     */
    $mailerLog['sent'] = is_numeric($mailerLog['sent']) ? [self::sentEntriesDate(time() - 1) => $mailerLog['sent']] : (array)$mailerLog['sent'];
    return $mailerLog;
  }

  /**
   * @return MailerLogData
   */
  public static function createMailerLog(): array {
    $mailerLog = [
      'sent' => [],
      'started' => time(),
      'status' => null,
      'retry_attempt' => null,
      'retry_at' => null,
      'error' => null,
      'transactional_email_last_error_at' => null,
      'transactional_email_error_count' => null,
    ];
    $settings = SettingsController::getInstance();
    $settings->set(self::SETTING_NAME, $mailerLog);
    return $mailerLog;
  }

  /**
   * @return MailerLogData
   */
  public static function resetMailerLog(): array {
    return self::createMailerLog();
  }

  /**
   * @param MailerLogData $mailerLog
   * @return MailerLogData
   */
  public static function updateMailerLog(array $mailerLog): array {
    $mailerLog = self::removeOutdatedSentInformationFromMailerlog($mailerLog);
    $settings = SettingsController::getInstance();
    $settings->set(self::SETTING_NAME, $mailerLog);
    return $mailerLog;
  }

  /**
   * @param MailerLogData|null $mailerLog
   * @return null
   * @throws \Exception
   */
  public static function enforceExecutionRequirements(array $mailerLog = null) {
    $mailerLog = self::getMailerLog($mailerLog);
    if ($mailerLog['retry_attempt'] === self::RETRY_ATTEMPTS_LIMIT) {
      $mailerLog = self::pauseSending($mailerLog);
    }
    if (self::isSendingPaused($mailerLog)) {
      throw new \Exception(__('Sending has been paused.', 'mailpoet'));
    }
    if (self::isSendingWaitingForRetry($mailerLog)) {
      throw new \Exception(__('Sending is waiting to be retried.', 'mailpoet'));
    } else {
      $mailerLog['retry_at'] = null;
      self::updateMailerLog($mailerLog);
    }

    // ensure that sending frequency has not been reached
    if (self::isSendingLimitReached($mailerLog)) {
      throw new \Exception(__('Sending frequency limit has been reached.', 'mailpoet'));
    }
    return null;
  }

  /**
   * @param MailerLogData $mailerLog
   * @return MailerLogData
   */
  public static function pauseSending($mailerLog): array {
    $mailerLog['status'] = self::STATUS_PAUSED;
    $mailerLog['retry_attempt'] = null;
    $mailerLog['retry_at'] = null;
    $mailerLog['transactional_email_last_error_at'] = null;
    $mailerLog['transactional_email_error_count'] = null;
    return self::updateMailerLog($mailerLog);
  }

  /**
   * @return MailerLogData
   */
  public static function resumeSending(): array {
    return self::resetMailerLog();
  }

  /**
   * Process error, doesn't increase retry_attempt so it will not block sending
   *
   * @param string $operation
   * @param string $errorMessage
   * @param int $retryInterval
   *
   * @throws \Exception
   */
  public static function processNonBlockingError(string $operation, string $errorMessage, int $retryInterval = self::RETRY_INTERVAL) {
    $mailerLog = self::getMailerLog();
    $mailerLog['retry_at'] = time() + $retryInterval;
    $mailerLog = self::setError($mailerLog, $operation, $errorMessage);
    self::updateMailerLog($mailerLog);
    self::enforceExecutionRequirements();
  }

  /**
   * Process error, increase retry_attempt and block sending if it goes above RETRY_INTERVAL
   *
   * @param string $operation
   * @param string $errorMessage
   * @param string $errorCode
   * @param bool $pauseSending
   *
   * @throws \Exception
   */
  public static function processError(
    string $operation,
    string $errorMessage,
    string $errorCode = null,
    bool $pauseSending = false,
    int $throttledBatchSize = null
  ) {
    $mailerLog = self::getMailerLog();
    if (!isset($throttledBatchSize) || $throttledBatchSize === 1) {
      $mailerLog['retry_attempt']++;
    }
    $mailerLog['retry_at'] = time() + self::RETRY_INTERVAL;
    $mailerLog = self::setError($mailerLog, $operation, $errorMessage, $errorCode);
    self::updateMailerLog($mailerLog);
    if ($pauseSending) {
      LoggerFactory::getInstance()->getLogger(LoggerFactory::TOPIC_SENDING)->error(
        'Email sending was paused due an error',
        [
          'error_message' => $errorMessage,
          'error_code' => $errorCode,
        ]
      );
      self::pauseSending($mailerLog);
    }
    self::enforceExecutionRequirements();
  }

  /**
   * Process error, increase transactional_email_error_count and pauses sending if it reaches retry limit
   * This method is meant to be used for processing errors when sending transactional emails
   * like: Confirmation Email, Preview email, Stats Notification etc.
   *
   * @throws \Exception
   */
  public static function processTransactionalEmailError(
    string $operation,
    string $errorMessage,
    ?string $errorCode = null
  ): void {
    $mailerLog = self::getMailerLog();
    $lastErrorTime = $mailerLog['transactional_email_last_error_at'] ?? null;
    $ignoreErrorThreshold = time() - (2 * 60); // 2 minutes ago
    // We want to log the error max one time per 2 minutes
    if ($lastErrorTime && $lastErrorTime > $ignoreErrorThreshold) {
      return;
    }
    $mailerLog = self::setError($mailerLog, $operation, $errorMessage, $errorCode);
    $mailerLog['transactional_email_last_error_at'] = time();
    $mailerLog['transactional_email_error_count'] = ($mailerLog['transactional_email_error_count'] ?? 0) + 1;
    self::updateMailerLog($mailerLog);
    if ($mailerLog['transactional_email_error_count'] >= self::RETRY_ATTEMPTS_LIMIT) {
      LoggerFactory::getInstance()->getLogger(LoggerFactory::TOPIC_SENDING)->error(
        'Email sending was paused due a transactional email error',
        [
          'error_message' => $errorMessage,
          'error_code' => $errorCode,
        ]
      );
      self::pauseSending($mailerLog);
    }
  }

  /**
   * @param MailerLogData $mailerLog
   * @param string $operation
   * @param string $errorMessage
   * @param string|null $errorCode
   * @return MailerLogData
   */
  public static function setError(
    array $mailerLog,
    string $operation,
    string $errorMessage,
    string $errorCode = null
  ): array {
    $mailerLog['error'] = [
      'operation' => $operation,
      'error_message' => $errorMessage,
    ];
    if ($errorCode) {
      $mailerLog['error']['error_code'] = $errorCode;
    }
    return $mailerLog;
  }

  /**
   * @param MailerLogData|null $mailerLog
   * @return MailerLogError|null
   */
  public static function getError(array $mailerLog = null): ?array {
    $mailerLog = self::getMailerLog($mailerLog);
    return isset($mailerLog['error']) ? $mailerLog['error'] : null;
  }

  /**
   * @return MailerLogData|null
   */
  public static function incrementSentCount(): ?array {
    $settings = SettingsController::getInstance();
    $mailerConfig = $settings->get(Mailer::MAILER_CONFIG_SETTING_NAME);
    $mailerLog = self::getMailerLog();

    // do not increment count if sending limit is reached
    if (self::isSendingLimitReached($mailerLog)) {
      return null;
    }
    // clear previous retry count, errors, etc.
    if ($mailerLog['error'] !== null) {
      $mailerLog = self::clearSendingErrorLog($mailerLog);
    }

    // do not enforce sending limit for MailPoet's sending method
    if ($mailerConfig['method'] === Mailer::METHOD_MAILPOET) {
      return null;
    }

    $time = self::sentEntriesDate();
    if (!isset($mailerLog['sent'][$time])) {
      $mailerLog['sent'][$time] = 0;
    }
    $mailerLog['sent'][$time]++;
    return self::updateMailerLog($mailerLog);
  }

  /**
   * @param MailerLogData $mailerLog
   * @return MailerLogData
   */
  public static function clearSendingErrorLog(array $mailerLog): array {
    $mailerLog['retry_attempt'] = null;
    $mailerLog['retry_at'] = null;
    $mailerLog['error'] = null;
    $mailerLog['transactional_email_last_error_at'] = null;
    $mailerLog['transactional_email_error_count'] = null;
    return self::updateMailerLog($mailerLog);
  }

  /**
   * @param MailerLogData|null $mailerLog
   * @return bool
   */
  public static function isSendingLimitReached(array $mailerLog = null): bool {
    $settings = SettingsController::getInstance();
    $mailerConfig = $settings->get(Mailer::MAILER_CONFIG_SETTING_NAME);
    // do not enforce sending limit for MailPoet's sending method
    if ($mailerConfig['method'] === Mailer::METHOD_MAILPOET) return false;
    $mailerLog = self::getMailerLog($mailerLog);

    if (empty($mailerConfig['frequency'])) {
      $defaultSettings = $settings->getAllDefaults();
      $mailerConfig['frequency'] = $defaultSettings['mta']['frequency'];
    }
    $frequencyInterval = (int)$mailerConfig['frequency']['interval'] * Mailer::SENDING_LIMIT_INTERVAL_MULTIPLIER;
    $frequencyLimit = (int)$mailerConfig['frequency']['emails'];
    $sent = self::sentSince($frequencyInterval, $mailerLog);
    return $sent >= $frequencyLimit;
  }

  /**
   * @param int|null $sinceSeconds
   * @param MailerLogData|null $mailerLog
   * @return int
   */
  public static function sentSince(int $sinceSeconds = null, array $mailerLog = null): int {

    if ($sinceSeconds === null) {
      $settings = SettingsController::getInstance();
      $mailerConfig = $settings->get(Mailer::MAILER_CONFIG_SETTING_NAME);
      if (empty($mailerConfig['frequency'])) {
        $defaultSettings = $settings->getAllDefaults();
        $mailerConfig['frequency'] = $defaultSettings['mta']['frequency'];
      }
      $sinceSeconds = (int)$mailerConfig['frequency']['interval'] * Mailer::SENDING_LIMIT_INTERVAL_MULTIPLIER;
    }
    $sinceDate = date('Y-m-d H:i:s', time() - $sinceSeconds);
    $mailerLog = self::getMailerLog($mailerLog);

    return (int)array_sum(
      array_filter(
        (array)$mailerLog['sent'],
        function($date) use ($sinceDate): bool {
          return $sinceDate <= $date;
        },
        \ARRAY_FILTER_USE_KEY
      )
    );
  }

  /**
   * Clears "sent" section of the mailer log from outdated entries.
   *
   * @param MailerLogData|null $mailerLog
   * @return MailerLogData
   */
  private static function removeOutdatedSentInformationFromMailerlog(array $mailerLog = null): array {

    $settings = SettingsController::getInstance();
    $mailerConfig = $settings->get(Mailer::MAILER_CONFIG_SETTING_NAME);
    $frequencyInterval = (int)$mailerConfig['frequency']['interval'] * Mailer::SENDING_LIMIT_INTERVAL_MULTIPLIER;
    $sinceDate = self::sentEntriesDate(time() - $frequencyInterval);
    $mailerLog = self::getMailerLog($mailerLog);

    $mailerLog['sent'] = array_filter(
      (array)$mailerLog['sent'],
      function($date) use ($sinceDate): bool {
        return $sinceDate <= $date;
      },
      \ARRAY_FILTER_USE_KEY
    );
    return $mailerLog;
  }

  /**
   * @param int|null $timestamp
   * @return string
   */
  private static function sentEntriesDate(int $timestamp = null): string {

    return date('Y-m-d H:i:s', $timestamp ?? time());
  }

  /**
   * @param MailerLogData|null $mailerLog
   * @return bool
   */
  public static function isSendingPaused(array $mailerLog = null): bool {
    $mailerLog = self::getMailerLog($mailerLog);
    return $mailerLog['status'] === self::STATUS_PAUSED;
  }

  /**
   * @param MailerLogData|null $mailerLog
   * @return bool
   */
  public static function isSendingWaitingForRetry(array $mailerLog = null): bool {
    $mailerLog = self::getMailerLog($mailerLog);
    $retryAt = $mailerLog['retry_at'] ?? null;
    return $retryAt && (time() <= $retryAt);
  }
}

Filemanager

Name Type Size Permission Actions
Methods Folder 0755
WordPress Folder 0755
Mailer.php File 2.65 KB 0644
MailerError.php File 2.53 KB 0644
MailerFactory.php File 5.67 KB 0644
MailerLog.php File 12.62 KB 0644
MetaInfo.php File 2.41 KB 0644
SubscriberError.php File 792 B 0644
index.php File 6 B 0644