updated plugin `WP Mail SMTP` version 2.1.1

This commit is contained in:
KawaiiPunk 2020-06-20 17:12:03 +00:00 committed by Gitium
parent 04443ddae8
commit 12dae937d6
193 changed files with 20688 additions and 1869 deletions

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 871 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1 @@
<svg aria-hidden="true" data-prefix="fas" data-icon="check-circle" class="svg-inline--fa fa-check-circle fa-w-16" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="#2ecc71" d="M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z"/></svg>

After

Width:  |  Height:  |  Size: 560 B

View File

@ -0,0 +1 @@
<svg aria-hidden="true" data-prefix="far" data-icon="exclamation-circle" class="svg-inline--fa fa-exclamation-circle fa-w-16" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="#e74c3c" d="M256 8C119.043 8 8 119.083 8 256c0 136.997 111.043 248 248 248s248-111.003 248-248C504 119.083 392.957 8 256 8zm0 448c-110.532 0-200-89.431-200-200 0-110.495 89.472-200 200-200 110.491 0 200 89.471 200 200 0 110.53-89.431 200-200 200zm42-104c0 23.159-18.841 42-42 42s-42-18.841-42-42 18.841-42 42-42 42 18.841 42 42zm-81.37-211.401l6.8 136c.319 6.387 5.591 11.401 11.985 11.401h41.17c6.394 0 11.666-5.014 11.985-11.401l6.8-136c.343-6.854-5.122-12.599-11.985-12.599h-54.77c-6.863 0-12.328 5.745-11.985 12.599z"/></svg>

After

Width:  |  Height:  |  Size: 724 B

View File

@ -0,0 +1 @@
<svg aria-hidden="true" data-prefix="fas" data-icon="exclamation-circle" class="svg-inline--fa fa-exclamation-circle fa-w-16" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="#f1c40f" d="M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zm-248 50c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"/></svg>

After

Width:  |  Height:  |  Size: 598 B

View File

@ -168,6 +168,7 @@ WPMailSMTP.Admin.Settings = WPMailSMTP.Admin.Settings || ( function( document, w
} );
app.triggerExitNotice();
app.beforeSaveChecks();
},
education: {
@ -178,6 +179,7 @@ WPMailSMTP.Admin.Settings = WPMailSMTP.Admin.Settings || ( function( document, w
escapeKey: true,
animationBounce: 1,
theme: 'modern',
type: 'blue',
animateFromElement: false,
draggable: false,
closeIcon: true,
@ -263,6 +265,54 @@ WPMailSMTP.Admin.Settings = WPMailSMTP.Admin.Settings || ( function( document, w
$( 'form', $settingPages ).on( 'submit', function() {
app.pluginSettingsChanged = false;
} );
},
/**
* Perform any checks before the settings are saved.
*
* Checks:
* - warn users if they try to save the settings with the default (PHP) mailer selected.
*
* @since 2.1.0
*/
beforeSaveChecks: function() {
$( 'form', app.pageHolder ).on( 'submit', function() {
if ( $( '.wp-mail-smtp-mailer input:checked', app.pageHolder ).val() === 'mail' ) {
var $thisForm = $( this );
$.alert( {
backgroundDismiss: false,
escapeKey: false,
animationBounce: 1,
theme: 'modern',
type: 'orange',
animateFromElement: false,
draggable: false,
closeIcon: false,
useBootstrap: false,
icon: '"></i><img src="' + wp_mail_smtp.plugin_url + '/assets/images/font-awesome/exclamation-circle-solid-orange.svg" style="width: 40px; height: 40px;" alt="' + wp_mail_smtp.default_mailer_notice.icon_alt + '"><i class="',
title: wp_mail_smtp.default_mailer_notice.title,
content: wp_mail_smtp.default_mailer_notice.content,
boxWidth: '550px',
buttons: {
confirm: {
text: wp_mail_smtp.default_mailer_notice.save_button,
btnClass: 'btn-confirm',
keys: [ 'enter' ],
action: function() {
$thisForm.off( 'submit' ).submit();
}
},
cancel: {
text: wp_mail_smtp.default_mailer_notice.cancel_button,
},
}
} );
return false;
}
} );
}
};

File diff suppressed because one or more lines are too long

View File

@ -3,7 +3,7 @@ Contributors: wpforms, jaredatch, smub, slaFFik
Tags: smtp, wp mail smtp, wordpress smtp, gmail smtp, sendgrid smtp, mailgun smtp, mail, mailer, phpmailer, wp_mail, email, mailgun, sengrid, gmail, pepipost, sendinblue, wp smtp
Requires at least: 4.9
Tested up to: 5.4
Stable tag: 2.0.1
Stable tag: 2.1.1
Requires PHP: 5.5.0
The most popular WordPress SMTP and PHP Mailer plugin. Trusted by over 1 million sites.
@ -62,7 +62,7 @@ SMTP.com is a recommended transactional email service.
With over 22 years of email delivery expertise, SMTP.com has been around for almost as long as email itself. They are known among internet providers as one of the most reliable senders on the internet.
Their easy integration process lets you start sending emails in minutes and benefit from years of experience. SMTP.com provides users 10,000 free emails the first 30 days.
Their easy integration process lets you start sending emails in minutes and benefit from years of experience. SMTP.com provides users 50,000 free emails the first 30 days.
Read our <a href="https://wpmailsmtp.com/docs/how-to-set-up-the-smtp-com-mailer-in-wp-mail-smtp" rel="friend">SMTP.com documentation</a> for more details.
@ -229,6 +229,24 @@ By all means please contact us to discuss features or options you'd like to see
== Changelog ==
= 2.1.1 - 2020-06-08 =
* Changed: Remove current automatic default reply-to address and add WP filter `wp_mail_smtp_processor_set_default_reply_to` for setting default reply-to addresses.
* Changed: Improve description for several options with links to an article about how to properly use constants.
* Fixed: PHP parse error connected to Monolog library on PHP versions < 7.x.
= 2.1.0 - 2020-06-04 =
* Added: Async/scheduled tasks management support.
* Added: New warning notification for selecting the "Default (none)" mailer and saving the plugin settings.
* Changed: Set the original From Email as Reply-To address if it was overwritten by the Force From Email option.
* Changed: The Force From Email option is now enabled by default, for new plugin installs.
* Changed: Reply-To header is now set when not provided, equals to From Name/Email.
* Fixed: Display a non-empty PHPMailer error when some non-SMTP mailers generate errors.
* Fixed: Display a more accurate message, when the "channel - not found" error is triggered by SMTP.com API.
* Fixed: Save and display debug errors for the "Other SMTP" mailer.
* Fixed: Improve the debug details for the "Invalid address (setFrom)" error in the Email Test tab.
* Fixed: Improve the debug details for SMTP CA verification fail, Gmail Guzzle requirements, and Gmail invalid grant errors.
* Fixed: Improve the uninstall cleanup procedure.
= 2.0.1 - 2020-05-07 =
* Changed: Improved description of the "Do Not Send" plugin option.
* Fixed: Due to Pepipost API changes we now convert new lines so they are preserved in plain text emails.

View File

@ -13,20 +13,26 @@ use WPMailSMTP\Options;
class Area {
/**
* Slug of the admin area page.
*
* @since 1.0.0
*
* @var string Slug of the admin area page.
* @var string
*/
const SLUG = 'wp-mail-smtp';
/**
* Admin page unique hook.
*
* @since 1.0.0
*
* @var string Admin page unique hook.
* @var string
*/
public $hook;
/**
* List of admin area pages.
*
* @since 1.0.0
*
* @var PageAbstract[]
@ -34,11 +40,13 @@ class Area {
private $pages;
/**
* List of official registered pages.
*
* @since 1.5.0
*
* @var array List of official registered pages.
* @var array
*/
public static $pages_registered = array( 'general', 'logs', 'about' );
public static $pages_registered = [ 'general', 'logs', 'about' ];
/**
* Area constructor.
@ -46,6 +54,7 @@ class Area {
* @since 1.0.0
*/
public function __construct() {
$this->hooks();
}
@ -57,34 +66,39 @@ class Area {
protected function hooks() {
// Add the Settings link to a plugin on Plugins page.
add_filter( 'plugin_action_links_' . plugin_basename( WPMS_PLUGIN_FILE ), array( $this, 'add_plugin_action_link' ), 10, 1 );
add_filter( 'plugin_action_links_' . plugin_basename( WPMS_PLUGIN_FILE ), [ $this, 'add_plugin_action_link' ], 10, 1 );
// Add the options page.
add_action( 'admin_menu', array( $this, 'add_admin_options_page' ) );
add_action( 'admin_menu', [ $this, 'add_admin_options_page' ] );
// Register on load Email Log admin menu hook.
add_action( 'load-wp-mail-smtp_page_wp-mail-smtp-logs', [ $this, 'maybe_redirect_email_log_menu_to_email_log_settings_tab' ] );
// Admin footer text.
add_filter( 'admin_footer_text', array( $this, 'get_admin_footer' ), 1, 2 );
add_filter( 'admin_footer_text', [ $this, 'get_admin_footer' ], 1, 2 );
// Enqueue admin area scripts and styles.
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) );
add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
// Process the admin page forms actions.
add_action( 'admin_init', array( $this, 'process_actions' ) );
add_action( 'admin_init', [ $this, 'process_actions' ] );
// Display custom notices based on the error/success codes.
add_action( 'admin_init', array( $this, 'display_custom_auth_notices' ) );
add_action( 'admin_init', [ $this, 'display_custom_auth_notices' ] );
// Display notice instructing the user to complete plugin setup.
add_action( 'admin_init', array( $this, 'display_setup_notice' ) );
add_action( 'admin_init', [ $this, 'display_setup_notice' ] );
// Outputs the plugin admin header.
add_action( 'in_admin_header', array( $this, 'display_admin_header' ), 100 );
add_action( 'in_admin_header', [ $this, 'display_admin_header' ], 100 );
// Hide all unrelated to the plugin notices on the plugin admin pages.
add_action( 'admin_print_scripts', array( $this, 'hide_unrelated_notices' ) );
add_action( 'admin_print_scripts', [ $this, 'hide_unrelated_notices' ] );
// Process all AJAX requests.
add_action( 'wp_ajax_wp_mail_smtp_ajax', array( $this, 'process_ajax' ) );
add_action( 'wp_ajax_wp_mail_smtp_ajax', [ $this, 'process_ajax' ] );
( new Review() )->hooks();
}
/**
@ -107,8 +121,7 @@ class Area {
switch ( $error ) {
case 'google_access_denied':
WP::add_admin_notice(
/* translators: %s - error code, returned by Google API. */
WP::add_admin_notice( /* translators: %s - error code, returned by Google API. */
sprintf( esc_html__( 'There was an error while processing the authentication request: %s. Please try again.', 'wp-mail-smtp' ), '<code>' . $error . '</code>' ),
WP::ADMIN_NOTICE_ERROR
);
@ -169,15 +182,14 @@ class Area {
// Display notice informing user further action is needed.
WP::add_admin_notice(
sprintf(
wp_kses(
/* translators: %s - Mailer anchor link. */
wp_kses( /* translators: %s - Mailer anchor link. */
__( 'Thanks for using WP Mail SMTP! To complete the plugin setup and start sending emails, <strong>please select and configure your <a href="%s">Mailer</a></strong>.', 'wp-mail-smtp' ),
array(
'a' => array(
'href' => array(),
),
'strong' => array(),
)
[
'a' => [
'href' => [],
],
'strong' => [],
]
),
wp_mail_smtp()->get_admin()->get_admin_page_url( self::SLUG . '#wp-mail-smtp-setting-row-mailer' )
),
@ -232,6 +244,26 @@ class Area {
}
}
/**
* Redirect the "Email Log" WP menu link to the "Email Log" setting tab for lite version of the plugin.
*
* @since 2.1.0
*/
public function maybe_redirect_email_log_menu_to_email_log_settings_tab() {
/**
* The Email Logs object to be used for loading the Email Log page.
*
* @var \WPMailSMTP\Admin\PageAbstract $logs
*/
$logs = $this->generate_display_logs_object();
if ( $logs instanceof \WPMailSMTP\Admin\Pages\Logs ) {
wp_safe_redirect( $logs->get_link() );
exit;
}
}
/**
* Enqueue admin area scripts and styles.
*
@ -269,6 +301,19 @@ class Area {
array(
'text_provider_remove' => esc_html__( 'Are you sure you want to reset the current provider connection? You will need to immediately create a new one to be able to send emails.', 'wp-mail-smtp' ),
'text_settings_not_saved' => esc_html__( 'Changes that you made to the settings are not saved!', 'wp-mail-smtp' ),
'default_mailer_notice' => array(
'title' => esc_html__( 'Heads up!', 'wp-mail-smtp' ),
'content' => wp_kses(
__( '<p>The Default (PHP) mailer is currently selected, but is not recommended because in most cases it does not resolve email delivery issues.</p><p>Please consider selecting and configuring one of the other mailers.</p>', 'wp-mail-smtp' ),
array(
'p' => true,
)
),
'save_button' => esc_html__( 'Save Settings', 'wp-mail-smtp' ),
'cancel_button' => esc_html__( 'Cancel', 'wp-mail-smtp' ),
'icon_alt' => esc_html__( 'Warning icon', 'wp-mail-smtp' ),
),
'plugin_url' => wp_mail_smtp()->plugin_url,
'education' => array(
'upgrade_icon_lock' => '<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="lock" class="svg-inline--fa fa-lock fa-w-14" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M400 224h-24v-72C376 68.2 307.8 0 224 0S72 68.2 72 152v72H48c-26.5 0-48 21.5-48 48v192c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V272c0-26.5-21.5-48-48-48zm-104 0H152v-72c0-39.7 32.3-72 72-72s72 32.3 72 72v72z"></path></svg>',
'upgrade_title' => esc_html__( '%name% is a PRO Feature', 'wp-mail-smtp' ),
@ -469,9 +514,12 @@ class Area {
break;
case self::SLUG . '-logs':
$logs_class = apply_filters( 'wp_mail_smtp_admin_display_get_logs_fqcn', '\WPMailSMTP\Admin\Pages\Logs' );
/** @var \WPMailSMTP\Admin\PageAbstract $logs */
$logs = new $logs_class();
/**
* The Email Logs object to be used for loading the Email Log page.
*
* @var \WPMailSMTP\Admin\PageAbstract $logs
*/
$logs = $this->generate_display_logs_object();
$is_archive = wp_mail_smtp()->is_pro() && wp_mail_smtp()->pro->get_logs()->is_archive();
?>
@ -500,6 +548,20 @@ class Area {
<?php
}
/**
* Generate the appropriate Email Log page object used for displaying the Email Log page.
*
* @since 2.1.0
*
* @return \WPMailSMTP\Admin\PageAbstract
*/
public function generate_display_logs_object() {
$logs_class = apply_filters( 'wp_mail_smtp_admin_display_get_logs_fqcn', \WPMailSMTP\Admin\Pages\Logs::class );
return new $logs_class();
}
/**
* Display General page tabs.
*

View File

@ -1,124 +1,137 @@
<?php
namespace WPMailSMTP\Admin\Pages;
use WPMailSMTP\Admin\PageAbstract;
/**
* Class ControlTab is a placeholder for Pro Email Control tab settings.
* Displays an upsell.
*
* @since 1.6.0
*/
class ControlTab extends PageAbstract {
/**
* @since 1.6.0
*
* @var string Slug of a tab.
*/
protected $slug = 'control';
/**
* @inheritdoc
*/
public function get_label() {
return esc_html__( 'Email Controls', 'wp-mail-smtp' );
}
/**
* @inheritdoc
*/
public function get_title() {
return $this->get_label();
}
/**
* @inheritdoc
*/
public function display() {
$features = array(
array(
'image' => 'comments.png',
'title' => esc_html__( 'Comment Notifications', 'wp-mail-smtp' ),
'desc' => esc_html__( 'Manage emails sent when comments are published or awaiting moderation.', 'wp-mail-smtp' ),
),
array(
'image' => 'admin.png',
'title' => esc_html__( 'Site Admin Email Change Notifications', 'wp-mail-smtp' ),
'desc' => esc_html__( 'Manage emails sent when site admin\'s account has been changed.', 'wp-mail-smtp' ),
),
array(
'image' => 'users.png',
'title' => esc_html__( 'User Change Notifications', 'wp-mail-smtp' ),
'desc' => esc_html__( 'Limit emails triggered by password changed/reset, email changed, and more.', 'wp-mail-smtp' ),
),
array(
'image' => 'personal.png',
'title' => esc_html__( 'Personal Data Requests Notifications', 'wp-mail-smtp' ),
'desc' => esc_html__( 'Control emails for data requests and data removal actions.', 'wp-mail-smtp' ),
),
array(
'image' => 'update.png',
'title' => esc_html__( 'Automatic Update Notifications', 'wp-mail-smtp' ),
'desc' => esc_html__( 'Manage emails sent by the core automatic update process.', 'wp-mail-smtp' ),
),
array(
'image' => 'user_new.png',
'title' => esc_html__( 'New User Notifications', 'wp-mail-smtp' ),
'desc' => esc_html__( 'Toggle emails sent to both user and site administrator about new user accounts.', 'wp-mail-smtp' ),
),
)
?>
<div class="wp-mail-smtp-page-upsell">
<h2><?php esc_html_e( 'Unlock Email Controls', 'wp-mail-smtp' ); ?></h2>
<h3>
<?php esc_html_e( 'Email Controls allows you to granularly manage emails sent by WordPress.', 'wp-mail-smtp' ); ?>
</h3>
<div class="wp-mail-smtp-page-upsell-content">
<div class="wp-mail-smtp-page-upsell-features">
<?php foreach ( $features as $feature ) : ?>
<div class="wp-mail-smtp-page-upsell-feature">
<div class="wp-mail-smtp-page-upsell-feature-image">
<img src="<?php echo esc_url( wp_mail_smtp()->assets_url . '/images/control/' . $feature['image'] ); ?>" alt="">
</div>
<div class="wp-mail-smtp-page-upsell-feature-content">
<h4><?php echo esc_html( $feature['title'] ); ?></h4>
<p><?php echo esc_html( $feature['desc'] ); ?></p>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<div class="wp-mail-smtp-page-upsell-button">
<a href="https://wpmailsmtp.com/lite-upgrade/?discount=LITEUPGRADE&amp;utm_source=WordPress&amp;utm_medium=logs&amp;utm_campaign=liteplugin"
class="wp-mail-smtp-btn wp-mail-smtp-btn-lg wp-mail-smtp-btn-orange" target="_blank" rel="noopener noreferrer">
<?php esc_html_e( 'Upgrade to WP Mail SMTP Pro', 'wp-mail-smtp' ); ?>
</a>
</div>
</div>
<?php
}
/**
* Not used as we display an upsell.
*
* @since 1.6.0
*
* @param array $data
*/
public function process_post( $data ) {
}
}
<?php
namespace WPMailSMTP\Admin\Pages;
use WPMailSMTP\Admin\PageAbstract;
/**
* Class ControlTab is a placeholder for Pro Email Control tab settings.
* Displays an upsell.
*
* @since 1.6.0
*/
class ControlTab extends PageAbstract {
/**
* @since 1.6.0
*
* @var string Slug of a tab.
*/
protected $slug = 'control';
/**
* @inheritdoc
*/
public function get_label() {
return esc_html__( 'Email Controls', 'wp-mail-smtp' );
}
/**
* @inheritdoc
*/
public function get_title() {
return $this->get_label();
}
/**
* {@inheritdoc}
*
* @since 2.1.0 Replaced images with SVGs.
*/
public function display() {
$features = [
[
'svg' => '<svg xmlns="http://www.w3.org/2000/svg" focusable="false" viewBox="0 0 64 64"><path class="st0" d="M39.1,35.5H18l-9.2,6.9c-0.5,0.4-1.2,0.3-1.5-0.2c-0.1-0.2-0.2-0.4-0.2-0.6v-6c-3.9,0-7.1-3.2-7.1-7.1V10.7c0-3.9,3.2-7.1,7.1-7.1h32c3.9,0,7.1,3.2,7.1,7.1v17.8C46.2,32.4,43,35.5,39.1,35.5C39.1,35.5,39.1,35.5,39.1,35.5z"/><path class="st1" d="M64,28.4v17.8c0,3.9-3.2,7.1-7.1,7.1h-3.6v6c0,0.6-0.5,1.1-1.1,1.1c-0.2,0-0.5-0.1-0.6-0.2l-9.2-6.9h-14c-3.9,0-7.1-3.2-7.1-7.1v-7.1h17.8c5.9,0,10.7-4.8,10.7-10.7v-7.1h7.1C60.8,21.3,64,24.5,64,28.4z"/></svg>',
'title' => esc_html__( 'Comment Notifications', 'wp-mail-smtp' ),
'desc' => esc_html__( 'Manage emails sent when comments are published or awaiting moderation.', 'wp-mail-smtp' ),
],
[
'svg' => '<svg xmlns="http://www.w3.org/2000/svg" focusable="false" viewBox="0 0 64 64"><path class="st0" d="M63.6 45.2l-2.6-1.5c0.3-1.4 0.3-2.9 0-4.3l2.6-1.5c0.3-0.2 0.4-0.5 0.3-0.9 -0.7-2.1-1.8-4.1-3.3-5.7 -0.2-0.3-0.6-0.3-0.9-0.1l-2.6 1.5c-1.1-0.9-2.3-1.7-3.7-2.1v-3c0-0.3-0.2-0.6-0.6-0.7 -2.2-0.5-4.4-0.5-6.6 0 -0.3 0.1-0.6 0.4-0.6 0.7v3c-1.4 0.5-2.6 1.2-3.7 2.1l-2.6-1.5c-0.3-0.2-0.7-0.1-0.9 0.1C37 33 35.9 35 35.2 37.1c-0.1 0.3 0 0.7 0.3 0.9l2.6 1.5c-0.3 1.4-0.3 2.9 0 4.3l-2.6 1.5c-0.3 0.2-0.4 0.5-0.3 0.9 0.7 2.1 1.8 4.1 3.3 5.7 0.2 0.3 0.6 0.3 0.9 0.1l2.6-1.5c1.1 0.9 2.3 1.7 3.7 2.1v3c0 0.3 0.2 0.6 0.6 0.7 2.2 0.5 4.4 0.5 6.6 0 0.3-0.1 0.6-0.4 0.6-0.7v-3c1.4-0.5 2.6-1.2 3.7-2.1l2.6 1.5c0.3 0.2 0.7 0.1 0.9-0.1 1.5-1.6 2.7-3.6 3.3-5.7C64.1 45.7 63.9 45.4 63.6 45.2zM49.6 46.5c-2.7 0-4.9-2.2-4.9-4.9s2.2-4.9 4.9-4.9c2.7 0 4.9 2.2 4.9 4.9S52.3 46.5 49.6 46.5z"/><path class="st1" d="M42.5 55.6v-0.9c-0.2-0.1-0.5-0.3-0.7-0.4l-0.8 0.5c-1.6 0.9-3.6 0.6-4.9-0.7 -1.8-2-3.2-4.4-4-7 -0.6-1.8 0.2-3.7 1.8-4.6l0.8-0.5c0-0.3 0-0.5 0-0.8L34 40.8c-1.6-0.9-2.3-2.8-1.8-4.6 0.1-0.3 0.2-0.6 0.3-0.9 -0.4 0-0.8-0.1-1.1-0.1h-1.7c-4.6 2.1-10 2.1-14.6 0h-1.7C6 35.2 0 41.2 0 48.6v4.2c0 2.7 2.2 4.8 4.8 4.8l0 0H40c1 0 1.9-0.3 2.7-0.9C42.6 56.4 42.5 56 42.5 55.6zM22.4 32c7.1 0 12.8-5.7 12.8-12.8S29.5 6.4 22.4 6.4 9.6 12.1 9.6 19.2 15.3 32 22.4 32z"/></svg>',
'title' => esc_html__( 'Site Admin Email Change Notifications', 'wp-mail-smtp' ),
'desc' => esc_html__( 'Manage emails sent when site admin\'s account has been changed.', 'wp-mail-smtp' ),
],
[
'svg' => '<svg xmlns="http://www.w3.org/2000/svg" focusable="false" viewBox="0 0 64 64"><path class="st0" d="M9.6 28.8c3.5 0 6.4-2.9 6.4-6.4S13.1 16 9.6 16s-6.4 2.9-6.4 6.4S6.1 28.8 9.6 28.8zM57.6 32h-6.4c-1.7 0-3.3 0.7-4.5 1.9 4.1 2.2 6.9 6.3 7.5 10.9h6.6c1.8 0 3.2-1.4 3.2-3.2v-3.2C64 34.9 61.1 32 57.6 32zM6.4 32C2.9 32 0 34.9 0 38.4v3.2c0 1.8 1.4 3.2 3.2 3.2h6.6c0.6-4.6 3.4-8.7 7.5-10.9 -1.2-1.2-2.8-1.9-4.5-1.9H6.4zM54.4 28.8c3.5 0 6.4-2.9 6.4-6.4S57.9 16 54.4 16 48 18.9 48 22.4 50.9 28.8 54.4 28.8z"/><path class="st1" d="M39.7 35.2h-0.8c-2.1 1-4.5 1.6-6.8 1.6 -2.5 0-4.8-0.6-6.9-1.6h-0.8c-6.4 0-11.5 5.2-11.5 11.5v2.9c0 2.7 2.1 4.8 4.8 4.8h28.8c2.6 0 4.8-2.2 4.8-4.8v-2.9C51.2 40.4 46 35.2 39.7 35.2zM32 32c6.2 0 11.2-5 11.2-11.2S38.2 9.6 32 9.6s-11.2 5-11.2 11.2C20.8 27 25.8 32 32 32L32 32z"/></svg>',
'title' => esc_html__( 'User Change Notifications', 'wp-mail-smtp' ),
'desc' => esc_html__( 'Limit emails triggered by password changed/reset, email changed, and more.', 'wp-mail-smtp' ),
],
[
'svg' => '<svg xmlns="http://www.w3.org/2000/svg" focusable="false" viewBox="0 0 64 64"><path class="st0" d="M35.9 52.6L32 60l-3.9-7.4L30 44l-2.2-4.5c2.8 0.6 5.7 0.6 8.5 0L34 44 35.9 52.6zM32 35.9c8.8 0 16-7.1 16-15.9 -0.9 0.2-1.9 0.4-3 0.5v0.8c0 0-0.8 0.4-0.9 0.8 -0.5 1.6-1 3.3-2.2 4.5 -1.4 1.3-6.5 3-8.7-3.4 -0.4-1.1-2.1-1.1-2.5 0 -2.3 6.8-7.6 4.4-8.7 3.4 -1.3-1.2-1.7-2.9-2.2-4.5 -0.1-0.3-0.9-0.8-0.9-0.8v-0.8c-1.1-0.2-2.1-0.3-3-0.5C16 28.8 23.2 35.9 32 35.9z"/><path class="st1" d="M19 20.5v0.8c0 0 0.8 0.5 0.9 0.8 0.5 1.6 1 3.3 2.2 4.5 1.1 1 6.4 3.4 8.7-3.4 0.4-1.1 2.1-1.1 2.5 0 2.2 6.4 7.3 4.7 8.7 3.4 1.3-1.2 1.7-2.9 2.2-4.5 0.1-0.4 0.9-0.8 0.9-0.8v-0.8c6.6-1 11-2.7 11-4.6 0-1.7-3.4-3.3-8.8-4.3 -1.2-4-3.3-8-5-10.1C41 0 39-0.4 37.2 0.4l-3.5 1.7c-1.1 0.6-2.5 0.6-3.6 0l-3.5-1.7C25-0.4 23 0 21.8 1.5c-1.7 2.1-3.8 6.1-5 10.1 -5.4 1-8.8 2.5-8.8 4.3C8 17.8 12.3 19.6 19 20.5zM52 38.5l3-7.8c0.4-1-0.1-2.2-1.2-2.6 -0.2-0.1-0.5-0.1-0.7-0.1h-4L32 60 14.9 27.9H11c-1.1 0-2 0.9-2 2 0 0.3 0.1 0.5 0.2 0.8l3.2 7.5c-5.2 3-8.4 8.5-8.4 14.5V58c0 3.3 2.7 6 6 6l0 0H54c3.3 0 6-2.7 6-6l0 0v-5.2C60.1 46.9 57 41.5 52 38.5L52 38.5z"/></svg>',
'title' => esc_html__( 'Personal Data Requests Notifications', 'wp-mail-smtp' ),
'desc' => esc_html__( 'Control emails for data requests and data removal actions.', 'wp-mail-smtp' ),
],
[
'svg' => '<svg xmlns="http://www.w3.org/2000/svg" focusable="false" viewBox="0 0 64 64"><path class="st0" d="M0 57.6V40.3c0-1.7 1.4-3.1 3.1-3.1h17.3c2.8 0 4.1 3.3 2.2 5.3l-5.4 5.4c4 3.8 9.3 5.9 14.8 5.8 10 0 18.6-6.9 21-16.4 0.2-0.7 0.8-1.2 1.5-1.2h7.4c0.9 0 1.5 0.7 1.5 1.5 0 0.1 0 0.2 0 0.3C60.7 52.8 47.6 64 32 64c-8.2 0-16.2-3.2-22.1-8.9l-4.6 4.6C3.3 61.7 0 60.3 0 57.6z"/><path class="st1" d="M0.6 26C3.3 11.2 16.4 0 32 0c8.2 0 16.2 3.2 22.1 8.9l4.6-4.6C60.7 2.3 64 3.7 64 6.5v17.3c0 1.7-1.4 3.1-3.1 3.1H43.6c-2.8 0-4.1-3.3-2.2-5.3l5.4-5.4c-4-3.8-9.3-5.9-14.8-5.8 -10 0-18.6 6.9-21 16.4 -0.2 0.7-0.8 1.2-1.5 1.2H2.1c-0.9 0-1.5-0.7-1.5-1.5C0.5 26.2 0.5 26.1 0.6 26z"/></svg>',
'title' => esc_html__( 'Automatic Update Notifications', 'wp-mail-smtp' ),
'desc' => esc_html__( 'Manage emails sent by the core automatic update process.', 'wp-mail-smtp' ),
],
[
'svg' => '<svg xmlns="http://www.w3.org/2000/svg" focusable="false" viewBox="0 0 64 64"><path class="st0" d="M64 28.8V32c0 0.9-0.7 1.6-1.6 1.6H56V40c0 0.9-0.7 1.6-1.6 1.6h-3.2c-0.9 0-1.6-0.7-1.6-1.6v-6.4h-6.4c-0.9 0-1.6-0.7-1.6-1.6v-3.2c0-0.9 0.7-1.6 1.6-1.6h6.4v-6.4c0-0.9 0.7-1.6 1.6-1.6h3.2c0.9 0 1.6 0.7 1.6 1.6v6.4h6.4C63.3 27.2 64 27.9 64 28.8z"/><path class="st1" d="M22.4 32c7.1 0 12.8-5.7 12.8-12.8S29.5 6.4 22.4 6.4 9.6 12.1 9.6 19.2 15.3 32 22.4 32zM31.4 35.2h-1.7c-4.6 2.1-9.9 2.1-14.6 0h-1.7C6 35.2 0 41.2 0 48.6v4.2c0 2.7 2.2 4.8 4.8 4.8l0 0H40c2.7 0 4.8-2.1 4.8-4.8l0 0v-4.2C44.8 41.2 38.8 35.2 31.4 35.2z"/></svg>',
'title' => esc_html__( 'New User Notifications', 'wp-mail-smtp' ),
'desc' => esc_html__( 'Toggle emails sent to both user and site administrator about new user accounts.', 'wp-mail-smtp' ),
],
];
$allowed_svg_html = [
'svg' => [
'xmlns' => [],
'focusable' => [],
'viewbox' => [],
],
'path' => [
'class' => [],
'd' => [],
],
];
?>
<div class="wp-mail-smtp-page-upsell">
<h2><?php esc_html_e( 'Unlock Email Controls', 'wp-mail-smtp' ); ?></h2>
<h3>
<?php esc_html_e( 'Email Controls allows you to granularly manage emails sent by WordPress.', 'wp-mail-smtp' ); ?>
</h3>
<div class="wp-mail-smtp-page-upsell-content">
<div class="wp-mail-smtp-page-upsell-features">
<?php foreach ( $features as $feature ) : ?>
<div class="wp-mail-smtp-page-upsell-feature">
<div class="wp-mail-smtp-page-upsell-feature-image">
<?php echo wp_kses( $feature['svg'], $allowed_svg_html ); ?>
</div>
<div class="wp-mail-smtp-page-upsell-feature-content">
<h4><?php echo esc_html( $feature['title'] ); ?></h4>
<p><?php echo esc_html( $feature['desc'] ); ?></p>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<div class="wp-mail-smtp-page-upsell-button">
<a href="https://wpmailsmtp.com/lite-upgrade/?discount=LITEUPGRADE&amp;utm_source=WordPress&amp;utm_medium=logs&amp;utm_campaign=liteplugin"
class="wp-mail-smtp-btn wp-mail-smtp-btn-lg wp-mail-smtp-btn-orange" target="_blank" rel="noopener noreferrer">
<?php esc_html_e( 'Upgrade to WP Mail SMTP Pro', 'wp-mail-smtp' ); ?>
</a>
</div>
</div>
<?php
}
/**
* Not used as we display an upsell.
*
* @since 1.6.0
*
* @param array $data
*/
public function process_post( $data ) {
}
}

View File

@ -1,85 +1,69 @@
<?php
namespace WPMailSMTP\Admin\Pages;
use WPMailSMTP\Admin\Area;
use WPMailSMTP\Admin\PageAbstract;
/**
* Class Logs
*/
class Logs extends PageAbstract {
/**
* @since 1.5.0
*
* @var string Slug of a page.
*/
protected $slug = 'logs';
/**
* Get the page/tab link.
*
* @since 1.5.0
*
* @return string
*/
public function get_link() {
return add_query_arg(
'page',
Area::SLUG . '-' . $this->slug,
admin_url( 'admin.php' )
);
}
/**
* @inheritdoc
*/
public function get_label() {
return esc_html__( 'Email Log', 'wp-mail-smtp' );
}
/**
* @inheritdoc
*/
public function get_title() {
return $this->get_label();
}
/**
* @inheritdoc
*/
public function display() {
?>
<div class="wp-mail-smtp-page-title">
<h1 class="page-title">
<?php echo esc_html( $this->get_label() ); ?>
</h1>
</div>
<div class="wp-mail-smtp-page-upsell">
<h2><?php esc_html_e( 'Unlock Email Logging', 'wp-mail-smtp' ); ?></h2>
<h3>
<?php esc_html_e( 'Keep track of every email sent from your WordPress site with email logging.', 'wp-mail-smtp' ); ?><br>
<?php esc_html_e( 'Troubleshoot sending issues, recover lost emails, and more!', 'wp-mail-smtp' ); ?>
</h3>
<div class="wp-mail-smtp-page-upsell-images">
<img src="<?php echo esc_url( wp_mail_smtp()->assets_url . '/images/logs/archive.png' ); ?>" alt="<?php esc_attr_e( 'Logs Archive Page Screenshot', 'wp-mail-smtp' ); ?>">
<img src="<?php echo esc_url( wp_mail_smtp()->assets_url . '/images/logs/single.png' ); ?>" alt="<?php esc_attr_e( 'Logs Single Page Screenshot', 'wp-mail-smtp' ); ?>">
</div>
<div class="wp-mail-smtp-page-upsell-button">
<a href="https://wpmailsmtp.com/lite-upgrade/?discount=LITEUPGRADE&amp;utm_source=WordPress&amp;utm_medium=logs&amp;utm_campaign=liteplugin" class="wp-mail-smtp-btn wp-mail-smtp-btn-lg wp-mail-smtp-btn-orange wp-mail-smtp-upgrade-modal" target="_blank" rel="noopener noreferrer">
<?php esc_html_e( 'Upgrade to WP Mail SMTP Pro', 'wp-mail-smtp' ); ?>
</a>
</div>
</div>
<?php
}
}
<?php
namespace WPMailSMTP\Admin\Pages;
use WPMailSMTP\Admin\Area;
use WPMailSMTP\Admin\PageAbstract;
/**
* Class Logs
*
* @since 1.5.0
*/
class Logs extends PageAbstract {
/**
* Slug of a page.
*
* @since 1.5.0
*
* @var string
*/
protected $slug = 'logs';
/**
* Get the page/tab link.
*
* @since 1.5.0
* @since 2.1.0 Changed the URL to point to the email log settings tab.
*
* @return string
*/
public function get_link() {
return add_query_arg(
'tab',
$this->slug,
admin_url( 'admin.php?page=' . Area::SLUG )
);
}
/**
* Link label of a tab.
*
* @since 1.5.0
*
* @return string
*/
public function get_label() {
return esc_html__( 'Email Log', 'wp-mail-smtp' );
}
/**
* Title of a tab.
*
* @since 1.5.0
*
* @return string
*/
public function get_title() {
return $this->get_label();
}
/**
* Tab content.
*
* @since 2.1.0 Moved the display content to the email log settings tab.
*/
public function display() {}
}

View File

@ -1,73 +1,85 @@
<?php
namespace WPMailSMTP\Admin\Pages;
use WPMailSMTP\Admin\Area;
use WPMailSMTP\Admin\PageAbstract;
/**
* Class LogsTab is a placeholder for Lite users and redirects them to Email Log page.
*
* @since 1.6.0
*/
class LogsTab extends PageAbstract {
/**
* Part of the slug of a tab.
*
* @since 1.6.0
*
* @var string
*/
protected $slug = 'logs';
/**
* @inheritdoc
*
* @since 1.6.0
*/
public function get_label() {
return esc_html__( 'Email Log', 'wp-mail-smtp' );
}
/**
* @inheritdoc
*
* @since 1.6.0
*/
public function get_title() {
return $this->get_label();
}
/**
* Custom URL for this tab, redirects to Email Log page.
*
* @since 1.6.0
*
* @return string
*/
public function get_link() {
return wp_mail_smtp()->get_admin()->get_admin_page_url( Area::SLUG . '-' . $this->slug );
}
/**
* Not used as we are simply redirecting users.
*
* @since 1.6.0
*/
public function display() {
}
/**
* Not used as we are simply redirecting users.
*
* @since 1.6.0
*
* @param array $data
*/
public function process_post( $data ) {
}
}
<?php
namespace WPMailSMTP\Admin\Pages;
use WPMailSMTP\Admin\PageAbstract;
/**
* Class LogsTab is a placeholder for Lite users and redirects them to Email Log page.
*
* @since 1.6.0
*/
class LogsTab extends PageAbstract {
/**
* Part of the slug of a tab.
*
* @since 1.6.0
*
* @var string
*/
protected $slug = 'logs';
/**
* @inheritdoc
*
* @since 1.6.0
*/
public function get_label() {
return esc_html__( 'Email Log', 'wp-mail-smtp' );
}
/**
* @inheritdoc
*
* @since 1.6.0
*/
public function get_title() {
return $this->get_label();
}
/**
* Display the upsell content for the Email Log feature.
*
* @since 1.6.0
* @since 2.1.0 Moved the display content from the email log page (WP admin menu "Email Log" page).
*/
public function display() {
?>
<div class="wp-mail-smtp-page-upsell">
<h2><?php esc_html_e( 'Unlock Email Logging', 'wp-mail-smtp' ); ?></h2>
<h3>
<?php esc_html_e( 'Keep track of every email sent from your WordPress site with email logging.', 'wp-mail-smtp' ); ?><br>
<?php esc_html_e( 'Troubleshoot sending issues, recover lost emails, and more!', 'wp-mail-smtp' ); ?>
</h3>
<div class="wp-mail-smtp-page-upsell-images">
<img src="<?php echo esc_url( wp_mail_smtp()->assets_url . '/images/logs/archive.png' ); ?>" alt="<?php esc_attr_e( 'Logs Archive Page Screenshot', 'wp-mail-smtp' ); ?>">
<img src="<?php echo esc_url( wp_mail_smtp()->assets_url . '/images/logs/single.png' ); ?>" alt="<?php esc_attr_e( 'Logs Single Page Screenshot', 'wp-mail-smtp' ); ?>">
</div>
<div class="wp-mail-smtp-page-upsell-button">
<a href="https://wpmailsmtp.com/lite-upgrade/?discount=LITEUPGRADE&amp;utm_source=WordPress&amp;utm_medium=logs&amp;utm_campaign=liteplugin" class="wp-mail-smtp-btn wp-mail-smtp-btn-lg wp-mail-smtp-btn-orange wp-mail-smtp-upgrade-modal" target="_blank" rel="noopener noreferrer">
<?php esc_html_e( 'Upgrade to WP Mail SMTP Pro', 'wp-mail-smtp' ); ?>
</a>
</div>
</div>
<?php
}
/**
* Not used as we are simply redirecting users.
*
* @since 1.6.0
*
* @param array $data
*/
public function process_post( $data ) {
}
}

View File

@ -88,19 +88,22 @@ class MiscTab extends PageAbstract {
'<code>wp-config.php</code>'
);
} else {
printf( /* translators: %s - file to put that constant in. */
esc_html__( 'If you want to enable this option using constants, put the lines below to your %s file:', 'wp-mail-smtp' ),
'<code>wp-config.php</code>'
printf(
wp_kses( /* translators: %s - The URL to the constants support article. */
__( 'Please read this <a href="%s" target="_blank" rel="noopener noreferrer">support article</a> if you want to enable this option using constants.', 'wp-mail-smtp' ),
[
'a' => [
'href' => [],
'target' => [],
'rel' => [],
],
]
),
'https://wpmailsmtp.com/docs/how-to-secure-smtp-settings-by-using-constants/'
);
}
?>
</p>
<?php if ( ! $options->is_const_defined( 'general', 'do_not_send' ) ) : ?>
<pre>
define( 'WPMS_ON', true );
define( 'WPMS_DO_NOT_SEND', true );
</pre>
<?php endif; ?>
</div>
</div>

View File

@ -98,12 +98,12 @@ class TestTab extends PageAbstract {
$disabled = '';
$help_text = '';
if (
! wp_mail_smtp()->get_providers()->get_mailer(
Options::init()->get( 'mail', 'mailer' ),
wp_mail_smtp()->get_processor()->get_phpmailer()
)->is_mailer_complete()
) {
$mailer = wp_mail_smtp()->get_providers()->get_mailer(
Options::init()->get( 'mail', 'mailer' ),
wp_mail_smtp()->get_processor()->get_phpmailer()
);
if ( ! $mailer || ! $mailer->is_mailer_complete() ) {
$btn = 'wp-mail-smtp-btn-red';
$disabled = 'disabled';
@ -435,6 +435,18 @@ Lead Developer, WP Mail SMTP';
$mailer_text .= $mailer->get_debug_info();
}
$phpmailer_error = $phpmailer->ErrorInfo; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
// Append any PHPMailer errors to the mailer debug (except SMTP mailer, which has the full error output below).
if (
! empty( $phpmailer_error ) &&
! $options->is_mailer_smtp()
) {
$mailer_text .= '<br><br><strong>PHPMailer Debug:</strong><br>' .
wp_strip_all_tags( $phpmailer_error ) .
'<br>';
}
/*
* General Debug.
*/
@ -486,137 +498,163 @@ Lead Developer, WP Mail SMTP';
$smtp_port = $options->get( 'smtp', 'port' );
$smtp_encryption = $options->get( 'smtp', 'encryption' );
$details = array(
$details = [
// [any] - cURL error 60/77.
array(
[
'mailer' => 'any',
'errors' => array(
array( 'cURL error 60' ),
array( 'cURL error 77' ),
),
'description' => array(
'errors' => [
[ 'cURL error 60' ],
[ 'cURL error 77' ],
],
'description' => [
'<strong>' . esc_html__( 'SSL certificate issue.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'This means your web server cannot reliably make secure connections (make requests to HTTPS sites).', 'wp-mail-smtp' ),
esc_html__( 'Typically this error is returned when web server is not configured properly.', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
esc_html__( 'Contact your web hosting provider and inform them your site has an issue with SSL certificates.', 'wp-mail-smtp' ),
esc_html__( 'The exact error you can provide them is in the Error log, available at the bottom of this page.', 'wp-mail-smtp' ),
esc_html__( 'Ask them to resolve the issue then try again.', 'wp-mail-smtp' ),
),
),
],
],
// [any] - cURL error 6/7.
array(
[
'mailer' => 'any',
'errors' => array(
array( 'cURL error 6' ),
array( 'cURL error 7' ),
),
'description' => array(
'errors' => [
[ 'cURL error 6' ],
[ 'cURL error 7' ],
],
'description' => [
'<strong>' . esc_html__( 'Could not connect to host.', 'wp-mail-smtp' ) . '</strong>',
! empty( $smtp_host )
? sprintf(
/* translators: %s - SMTP host address. */
? sprintf( /* translators: %s - SMTP host address. */
esc_html__( 'This means your web server was unable to connect to %s.', 'wp-mail-smtp' ),
$smtp_host
)
: esc_html__( 'This means your web server was unable to connect to the host server.', 'wp-mail-smtp' ),
esc_html__( 'Typically this error is returned your web server is blocking the connections or the SMTP host denying the request.', 'wp-mail-smtp' ),
),
'steps' => array(
sprintf(
/* translators: %s - SMTP host address. */
],
'steps' => [
sprintf( /* translators: %s - SMTP host address. */
esc_html__( 'Contact your web hosting provider and ask them to verify your server can connect to %s. Additionally, ask them if a firewall or security policy may be preventing the connection.', 'wp-mail-smtp' ),
$smtp_host
),
esc_html__( 'If using "Other SMTP" Mailer, triple check your SMTP settings including host address, email, and password.', 'wp-mail-smtp' ),
esc_html__( 'If using "Other SMTP" Mailer, contact your SMTP host to confirm they are accepting outside connections with the settings you have configured (address, username, port, security, etc).', 'wp-mail-smtp' ),
),
),
],
],
// [any] - cURL error XX (other).
array(
[
'mailer' => 'any',
'errors' => array(
array( 'cURL error' ),
),
'description' => array(
'errors' => [
[ 'cURL error' ],
],
'description' => [
'<strong>' . esc_html__( 'Could not connect to your host.', 'wp-mail-smtp' ) . '</strong>',
! empty( $smtp_host )
? sprintf(
/* translators: %s - SMTP host address. */
? sprintf( /* translators: %s - SMTP host address. */
esc_html__( 'This means your web server was unable to connect to %s.', 'wp-mail-smtp' ),
$smtp_host
)
: esc_html__( 'This means your web server was unable to connect to the host server.', 'wp-mail-smtp' ),
esc_html__( 'Typically this error is returned when web server is not configured properly.', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
esc_html__( 'Contact your web hosting provider and inform them you are having issues making outbound connections.', 'wp-mail-smtp' ),
esc_html__( 'The exact error you can provide them is in the Error log, available at the bottom of this page.', 'wp-mail-smtp' ),
esc_html__( 'Ask them to resolve the issue then try again.', 'wp-mail-smtp' ),
),
),
],
],
// [smtp] - SMTP Error: Count not authenticate.
array(
[
'mailer' => 'smtp',
'errors' => array(
array( 'SMTP Error: Could not authenticate.' ),
),
'description' => array(
'errors' => [
[ 'SMTP Error: Could not authenticate.' ],
],
'description' => [
'<strong>' . esc_html__( 'Could not authenticate your SMTP account.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'This means we were able to connect to your SMTP host, but were not able to proceed using the email/password in the settings.', 'wp-mail-smtp' ),
esc_html__( 'Typically this error is returned when the email or password is not correct or is not what the SMTP host is expecting.', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
esc_html__( 'Triple check your SMTP settings including host address, email, and password. If you have recently reset your password you will need to update the settings.', 'wp-mail-smtp' ),
esc_html__( 'Contact your SMTP host to confirm you are using the correct username and password.', 'wp-mail-smtp' ),
esc_html__( 'Verify with your SMTP host that your account has permissions to send emails using outside connections.', 'wp-mail-smtp' ),
),
),
],
],
// [smtp] - Sending bulk email, hitting rate limit.
array(
[
'mailer' => 'smtp',
'errors' => array(
array( 'We do not authorize the use of this system to transport unsolicited' ),
),
'description' => array(
'errors' => [
[ 'We do not authorize the use of this system to transport unsolicited' ],
],
'description' => [
'<strong>' . esc_html__( 'Error due to unsolicited and/or bulk e-mail.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'This means the connection to your SMTP host was made successfully, but the host rejected the email.', 'wp-mail-smtp' ),
esc_html__( 'Typically this error is returned when you are sending too many e-mails or e-mails that have been identified as spam.', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
esc_html__( 'Check the emails that are sending are sending individually. Example: email is not sending to 30 recipients. You can install any WordPress e-mail logging plugin to do that.', 'wp-mail-smtp' ),
esc_html__( 'Contact your SMTP host to ask about sending/rate limits.', 'wp-mail-smtp' ),
esc_html__( 'Verify with them your SMTP account is in good standing and your account has not been flagged.', 'wp-mail-smtp' ),
),
),
],
],
// [smtp] - Unauthenticated senders not allowed.
array(
[
'mailer' => 'smtp',
'errors' => array(
array( 'Unauthenticated senders not allowed' ),
),
'description' => array(
'errors' => [
[ 'Unauthenticated senders not allowed' ],
],
'description' => [
'<strong>' . esc_html__( 'Unauthenticated senders are not allowed.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'This means the connection to your SMTP host was made successfully, but you should enable Authentication and provide correct Username and Password.', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
esc_html__( 'Go to WP Mail SMTP plugin Settings page.', 'wp-mail-smtp' ),
esc_html__( 'Enable Authentication', 'wp-mail-smtp' ),
esc_html__( 'Enter correct SMTP Username (usually this is an email address) and Password in the appropriate fields.', 'wp-mail-smtp' ),
),
),
// [smtp] - SMTP connect() failed.
array(
],
],
// [smtp] - certificate verify failed.
// Has to be defined before "SMTP connect() failed" error, since this is a more specific error,
// which contains the "SMTP connect() failed" error message as well.
[
'mailer' => 'smtp',
'errors' => array(
array( 'SMTP connect() failed' ),
),
'description' => array(
'errors' => [
[ 'certificate verify failed' ],
],
'description' => [
'<strong>' . esc_html__( 'Misconfigured server certificate.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'This means OpenSSL on your server isn\'t able to verify the host certificate.', 'wp-mail-smtp' ),
esc_html__( 'There are a few reasons why this is happening. It could be that the host certificate is misconfigured, or this server\'s OpenSSL is using an outdated CA bundle.', 'wp-mail-smtp' ),
],
'steps' => [
esc_html__( 'Verify that the host\'s SSL certificate is valid.', 'wp-mail-smtp' ),
sprintf(
wp_kses( /* translators: %s - URL to the PHP openssl manual */
__( 'Contact your hosting support, show them the "full Error Log for debugging" below and share this <a href="%s" target="_blank" rel="noopener noreferrer">link</a> with them.', 'wp-mail-smtp' ),
[
'a' => [
'href' => [],
'target' => [],
'rel' => [],
],
]
),
'https://www.php.net/manual/en/migration56.openssl.php'
),
],
],
// [smtp] - SMTP connect() failed.
[
'mailer' => 'smtp',
'errors' => [
[ 'SMTP connect() failed' ],
],
'description' => [
'<strong>' . esc_html__( 'Could not connect to the SMTP host.', 'wp-mail-smtp' ) . '</strong>',
! empty( $smtp_host )
? sprintf(
/* translators: %s - SMTP host address. */
? sprintf( /* translators: %s - SMTP host address. */
esc_html__( 'This means your web server was unable to connect to %s.', 'wp-mail-smtp' ),
$smtp_host
)
@ -625,22 +663,21 @@ Lead Developer, WP Mail SMTP';
'-' . esc_html__( 'SMTP settings are incorrect (wrong port, security setting, incorrect host).', 'wp-mail-smtp' ) . '<br>' .
'-' . esc_html__( 'Your web server is blocking the connection.', 'wp-mail-smtp' ) . '<br>' .
'-' . esc_html__( 'Your SMTP host is rejecting the connection.', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
esc_html__( 'Triple check your SMTP settings including host address, email, and password, port, and security.', 'wp-mail-smtp' ),
sprintf(
wp_kses(
/* translators: %1$s - SMTP host address, %2$s - SMTP port, %3$s - SMTP encryption. */
wp_kses( /* translators: %1$s - SMTP host address, %2$s - SMTP port, %3$s - SMTP encryption. */
__( 'Contact your web hosting provider and ask them to verify your server can connect to %1$s on port %2$s using %3$s encryption. Additionally, ask them if a firewall or security policy may be preventing the connection - many shared hosts block certain ports.<br><strong>Note: this is the most common cause of this issue.</strong>', 'wp-mail-smtp' ),
array(
'a' => array(
'href' => array(),
'rel' => array(),
'target' => array(),
),
'strong' => array(),
'br' => array(),
)
[
'a' => [
'href' => [],
'rel' => [],
'target' => [],
],
'strong' => [],
'br' => [],
]
),
$smtp_host,
$smtp_port,
@ -648,281 +685,332 @@ Lead Developer, WP Mail SMTP';
),
esc_html__( 'Contact your SMTP host to confirm you are using the correct username and password.', 'wp-mail-smtp' ),
esc_html__( 'Verify with your SMTP host that your account has permissions to send emails using outside connections.', 'wp-mail-smtp' ),
),
),
],
],
// [mailgun] - Please activate your Mailgun account.
array(
[
'mailer' => 'mailgun',
'errors' => array(
array( 'Please activate your Mailgun account' ),
),
'description' => array(
'errors' => [
[ 'Please activate your Mailgun account' ],
],
'description' => [
'<strong>' . esc_html__( 'Mailgun failed.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'It seems that you forgot to activate your Mailgun account.', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
esc_html__( 'Check your inbox you used to create a Mailgun account. Click the activation link in an email from Mailgun.', 'wp-mail-smtp' ),
esc_html__( 'If you do not see activation email, go to your Mailgun control panel and resend the activation email.', 'wp-mail-smtp' ),
),
),
],
],
// [mailgun] - Forbidden.
array(
[
'mailer' => 'mailgun',
'errors' => array(
array( 'Forbidden' ),
),
'description' => array(
'errors' => [
[ 'Forbidden' ],
],
'description' => [
'<strong>' . esc_html__( 'Mailgun failed.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'Typically this error is because there is an issue with your Mailgun settings, in many cases the API key.', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
esc_html__( 'Verify your API key is correct.', 'wp-mail-smtp' ),
esc_html__( 'Go to your Mailgun account and view your API key.', 'wp-mail-smtp' ),
esc_html__( 'Note that the API key includes the "key" prefix, so make sure that it is in the WP Mail SMTP Mailgun API setting.', 'wp-mail-smtp' ),
),
),
],
],
// [mailgun] - Free accounts are for test purposes only.
array(
[
'mailer' => 'mailgun',
'errors' => array(
array( 'Free accounts are for test purposes only' ),
),
'description' => array(
'errors' => [
[ 'Free accounts are for test purposes only' ],
],
'description' => [
'<strong>' . esc_html__( 'Mailgun failed.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'Your Mailgun account does not have access to send emails.', 'wp-mail-smtp' ),
esc_html__( 'Typically this error is because you have not set up and/or complete domain name verification for your Mailgun account.', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
sprintf(
wp_kses(
/* translators: %s - Mailgun documentation URL. */
wp_kses( /* translators: %s - Mailgun documentation URL. */
__( 'Go to our how-to guide for setting up <a href="%s" target="_blank" rel="noopener noreferrer">Mailgun with WP Mail SMTP</a>.', 'wp-mail-smtp' ),
array(
'a' => array(
'href' => array(),
'rel' => array(),
'target' => array(),
),
)
[
'a' => [
'href' => [],
'rel' => [],
'target' => [],
],
]
),
'https://wpmailsmtp.com/docs/how-to-set-up-the-mailgun-mailer-in-wp-mail-smtp/'
),
esc_html__( 'Complete the steps in section "2. Verify Your Domain".', 'wp-mail-smtp' ),
),
),
],
],
// [gmail] - 401: Login Required.
array(
[
'mailer' => 'gmail',
'errors' => array(
array( '401', 'Login Required' ),
),
'description' => array(
'errors' => [
[ '401', 'Login Required' ],
],
'description' => [
'<strong>' . esc_html__( 'Google API Error.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'You have not properly configured Gmail mailer.', 'wp-mail-smtp' ),
esc_html__( 'Make sure that you have clicked the "Allow plugin to send emails using your Google account" button under Gmail settings.', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
esc_html__( 'Go to plugin Settings page and click the "Allow plugin to send emails using your Google account" button.', 'wp-mail-smtp' ),
esc_html__( 'After the click you should be redirected to a Gmail authorization screen, where you will be asked a permission to send emails on your behalf.', 'wp-mail-smtp' ),
esc_html__( 'Please click "Agree", if you see that button. If not - you will need to enable less secure apps first:', 'wp-mail-smtp' )
. '<ul>'
. '<li>' .
sprintf(
wp_kses(
/* translators: %s - Google support article URL. */
wp_kses( /* translators: %s - Google support article URL. */
__( 'if you are using regular Gmail account, please <a href="%s" target="_blank" rel="noopener noreferrer">read this article</a> to proceed.', 'wp-mail-smtp' ),
array(
'a' => array(
'href' => array(),
'target' => array(),
'rel' => array(),
),
)
[
'a' => [
'href' => [],
'target' => [],
'rel' => [],
],
]
),
'https://support.google.com/accounts/answer/6010255?hl=en'
)
. '</li>'
. '<li>' .
sprintf(
wp_kses(
/* translators: %s - Google support article URL. */
wp_kses( /* translators: %s - Google support article URL. */
__( 'if you are using G Suite, please <a href="%s" target="_blank" rel="noopener noreferrer">read this article</a> to proceed.', 'wp-mail-smtp' ),
array(
'a' => array(
'href' => array(),
'target' => array(),
'rel' => array(),
),
)
[
'a' => [
'href' => [],
'target' => [],
'rel' => [],
],
]
),
'https://support.google.com/cloudidentity/answer/6260879?hl=en'
)
. '</li>'
. '</ul>',
),
),
],
],
// [gmail] - 400: Recipient address required.
array(
[
'mailer' => 'gmail',
'errors' => array(
array( '400', 'Recipient address required' ),
),
'description' => array(
'errors' => [
[ '400', 'Recipient address required' ],
],
'description' => [
'<strong>' . esc_html__( 'Google API Error.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'Typically this error is because address the email was sent to is invalid or was empty.', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
esc_html__( 'Check the "Send To" email address used and confirm it is a valid email and was not empty.', 'wp-mail-smtp' ),
sprintf(
/* translators: 1 - correct email address example. 2 - incorrect email address example. */
sprintf( /* translators: 1 - correct email address example. 2 - incorrect email address example. */
esc_html__( 'It should be something like this: %1$s. These are incorrect values: %2$s.', 'wp-mail-smtp' ),
'<code>info@example.com</code>',
'<code>info@localhost</code>, <code>info@192.168.1.1</code>'
),
esc_html__( 'Make sure that the generated email has a TO header, useful when you are responsible for email creation.', 'wp-mail-smtp' ),
),
),
],
],
// [gmail] - Token has been expired or revoked.
array(
[
'mailer' => 'gmail',
'errors' => array(
array( 'invalid_grant', 'Token has been expired or revoked' ),
),
'description' => array(
'errors' => [
[ 'invalid_grant', 'Token has been expired or revoked' ],
],
'description' => [
'<strong>' . esc_html__( 'Google API Error.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'Unfortunately, this error can be due to many different reasons.', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
sprintf(
wp_kses(
/* translators: %s - Blog article URL. */
wp_kses( /* translators: %s - Blog article URL. */
__( 'Please <a href="%s" target="_blank" rel="noopener noreferrer">read this article</a> to learn more about what can cause this error and how it can be resolved.', 'wp-mail-smtp' ),
array(
'a' => array(
'href' => array(),
'target' => array(),
'rel' => array(),
),
)
[
'a' => [
'href' => [],
'target' => [],
'rel' => [],
],
]
),
'https://blog.timekit.io/google-oauth-invalid-grant-nightmare-and-how-to-fix-it-9f4efaf1da35'
),
),
),
],
],
// [gmail] - Code was already redeemed.
array(
[
'mailer' => 'gmail',
'errors' => array(
array( 'invalid_grant', 'Code was already redeemed' ),
),
'description' => array(
'errors' => [
[ 'invalid_grant', 'Code was already redeemed' ],
],
'description' => [
'<strong>' . esc_html__( 'Google API Error.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'Authentication code that Google returned to you has already been used on your previous auth attempt.', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
esc_html__( 'Make sure that you are not trying to manually clean up the plugin options to retry the "Allow..." step.', 'wp-mail-smtp' ),
esc_html__( 'Reinstall the plugin with clean plugin data turned on on Misc page. This will remove all the plugin options and you will be safe to retry.', 'wp-mail-smtp' ),
esc_html__( 'Make sure there is no aggressive caching on site admin area pages or try to clean cache between attempts.', 'wp-mail-smtp' ),
),
),
],
],
// [gmail] - 400: Mail service not enabled.
array(
[
'mailer' => 'gmail',
'errors' => array(
array( '400', 'Mail service not enabled' ),
),
'description' => array(
'errors' => [
[ '400', 'Mail service not enabled' ],
],
'description' => [
'<strong>' . esc_html__( 'Google API Error.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'There are various reasons for that, please review the steps below.', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
sprintf(
wp_kses(
/* translators: %s - Google G Suite Admin area URL. */
wp_kses( /* translators: %s - Google G Suite Admin area URL. */
__( 'Make sure that your G Suite trial period has not expired. You can check the status <a href="%s" target="_blank" rel="noopener noreferrer">here</a>.', 'wp-mail-smtp' ),
array(
'a' => array(
'href' => array(),
'rel' => array(),
'target' => array(),
),
)
[
'a' => [
'href' => [],
'rel' => [],
'target' => [],
],
]
),
'https://admin.google.com'
),
sprintf(
wp_kses(
/* translators: %s - Google G Suite Admin area URL. */
wp_kses( /* translators: %s - Google G Suite Admin area URL. */
__( 'Make sure that Gmail app in your G Suite is actually enabled. You can check that in Apps list in <a href="%s" target="_blank" rel="noopener noreferrer">G Suite Admin</a> area.', 'wp-mail-smtp' ),
array(
'a' => array(
'href' => array(),
'rel' => array(),
'target' => array(),
),
)
[
'a' => [
'href' => [],
'rel' => [],
'target' => [],
],
]
),
'https://admin.google.com'
),
sprintf(
wp_kses(
/* translators: %s - Google Developers Console URL. */
wp_kses( /* translators: %s - Google Developers Console URL. */
__( 'Make sure that you have Gmail API enabled, and you can do that <a href="%s" target="_blank" rel="noopener noreferrer">here</a>.', 'wp-mail-smtp' ),
array(
'a' => array(
'href' => array(),
'rel' => array(),
'target' => array(),
),
)
[
'a' => [
'href' => [],
'rel' => [],
'target' => [],
],
]
),
'https://console.developers.google.com/'
),
),
),
],
],
// [gmail] - 403: Project X is not found and cannot be used for API calls.
array(
[
'mailer' => 'gmail',
'errors' => array(
array( '403', 'is not found and cannot be used for API calls' ),
),
'description' => array(
'errors' => [
[ '403', 'is not found and cannot be used for API calls' ],
],
'description' => [
'<strong>' . esc_html__( 'Google API Error.', 'wp-mail-smtp' ) . '</strong>',
),
'steps' => array(
],
'steps' => [
esc_html__( 'Make sure that the used Client ID/Secret correspond to a proper project that has Gmail API enabled.', 'wp-mail-smtp' ),
sprintf(
wp_kses(
/* translators: %s - Gmail documentation URL. */
wp_kses( /* translators: %s - Gmail documentation URL. */
esc_html__( 'Please follow our <a href="%s" target="_blank" rel="noopener noreferrer">Gmail tutorial</a> to be sure that all the correct project and data is applied.', 'wp-mail-smtp' ),
array(
'a' => array(
'href' => array(),
'rel' => array(),
'target' => array(),
),
)
[
'a' => [
'href' => [],
'rel' => [],
'target' => [],
],
]
),
'https://wpmailsmtp.com/docs/how-to-set-up-the-gmail-mailer-in-wp-mail-smtp/'
),
),
),
],
],
// [gmail] - The OAuth client was disabled.
array(
[
'mailer' => 'gmail',
'errors' => array(
array( 'disabled_client', 'The OAuth client was disabled' ),
),
'description' => array(
'errors' => [
[ 'disabled_client', 'The OAuth client was disabled' ],
],
'description' => [
'<strong>' . esc_html__( 'Google API Error.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'You may have added a new API to a project', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
esc_html__( 'Make sure that the used Client ID/Secret correspond to a proper project that has Gmail API enabled.', 'wp-mail-smtp' ),
esc_html__( 'Try to use a separate project for your emails, so the project has only 1 Gmail API in it enabled. You will need to remove the old project and create a new one from scratch.', 'wp-mail-smtp' ),
),
),
);
],
],
// [SMTP.com] - The "channel - not found" issue.
[
'mailer' => 'smtpcom',
'errors' => [
[ 'channel - not found' ],
],
'description' => [
'<strong>' . esc_html__( 'SMTP.com API Error.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'Your Sender Name option is incorrect.', 'wp-mail-smtp' ),
],
'steps' => [
esc_html__( 'Please make sure you entered an accurate Sender Name in WP Mail SMTP plugin settings.', 'wp-mail-smtp' ),
],
],
// [gmail] - GuzzleHttp requires cURL, the allow_url_fopen ini setting, or a custom HTTP handler.
[
'mailer' => 'gmail',
'errors' => [
[ 'GuzzleHttp requires cURL, the allow_url_fopen ini setting, or a custom HTTP handler' ],
],
'description' => [
'<strong>' . esc_html__( 'GuzzleHttp requirements.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'GuzzleHttp requires cURL, the allow_url_fopen ini setting, or a custom HTTP handler.', 'wp-mail-smtp' ),
],
'steps' => [
esc_html__( 'Edit your php.ini file on your hosting server.', 'wp-mail-smtp' ),
esc_html__( '(Recommended) Enable PHP extension: cURL, by adding "extension=curl" to the php.ini file (without the quotation marks) OR', 'wp-mail-smtp' ),
esc_html__( '(If cURL can\'t be enabled on your hosting server) Enable PHP setting: allow_url_fopen, by adding "allow_url_fopen = On" to the php.ini file (without the quotation marks)', 'wp-mail-smtp' ),
esc_html__( 'If you don\'t know how to do the above we strongly suggest contacting your hosting support and provide them the "full Error Log for debugging" below and these steps. They should be able to fix this issue for you.', 'wp-mail-smtp' ),
],
],
];
/**
* [any] - PHP 7.4.x and PCRE library issues.
*
* @see https://wordpress.org/support/topic/cant-send-emails-using-php-7-4/
*/
if (
version_compare( phpversion(), '7.4', '>=' ) &&
defined( 'PCRE_VERSION' ) &&
version_compare( PCRE_VERSION, '10.0', '>' ) &&
version_compare( PCRE_VERSION, '10.32', '<=' )
) {
$details[] = [
'mailer' => 'any',
'errors' => [
[ 'Invalid address: (setFrom)' ],
],
'description' => [
'<strong>' . esc_html__( 'PCRE library issue', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'It looks like your server is running PHP version 7.4.x with an outdated PCRE library (libpcre2) that has a known issue with email address validation.', 'wp-mail-smtp' ),
esc_html__( 'There is a known issue with PHP version 7.4.x, when using libpcre2 library version lower than 10.33.', 'wp-mail-smtp' ),
],
'steps' => [
esc_html__( 'Contact your web hosting provider and inform them you are having issues with libpcre2 library on PHP 7.4.', 'wp-mail-smtp' ),
esc_html__( 'They should be able to resolve this issue for you.', 'wp-mail-smtp' ),
esc_html__( 'For a quick fix, until your web hosting resolves this, you can downgrade to PHP version 7.3 on your server.', 'wp-mail-smtp' ),
],
];
}
// Error detection logic.
foreach ( $details as $data ) {
@ -953,27 +1041,27 @@ Lead Developer, WP Mail SMTP';
}
// Return defaults.
return array(
'description' => array(
return [
'description' => [
'<strong>' . esc_html__( 'An issue was detected.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'This means your test email was unable to be sent.', 'wp-mail-smtp' ),
esc_html__( 'Typically this error is returned for one of the following reasons:', 'wp-mail-smtp' ),
'- ' . esc_html__( 'Plugin settings are incorrect (wrong SMTP settings, invalid Mailer configuration, etc).', 'wp-mail-smtp' ) . '<br>' .
'- ' . esc_html__( 'Your web server is blocking the connection.', 'wp-mail-smtp' ) . '<br>' .
'- ' . esc_html__( 'Your host is rejecting the connection.', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
esc_html__( 'Triple check the plugin settings, consider reconfiguring to make sure everything is correct (eg bad copy and paste).', 'wp-mail-smtp' ),
wp_kses(
__( 'Contact your web hosting provider and ask them to verify your server can make outside connections. Additionally, ask them if a firewall or security policy may be preventing the connection - many shared hosts block certain ports.<br><strong>Note: this is the most common cause of this issue.</strong>', 'wp-mail-smtp' ),
array(
'strong' => array(),
'br' => array(),
)
[
'strong' => [],
'br' => [],
]
),
esc_html__( 'Try using a different mailer.', 'wp-mail-smtp' ),
),
);
],
];
}
/**

View File

@ -0,0 +1,203 @@
<?php
namespace WPMailSMTP\Admin;
use WPMailSMTP\Options;
/**
* Class for admin notice requesting plugin review.
*
* @since 2.1.0
*/
class Review {
/**
* The name of the WP option for the review notice data.
*
* Data attributes:
* - time
* - dismissed
*
* @since 2.1.0
*/
const NOTICE_OPTION = 'wp_mail_smtp_review_notice';
/**
* Days the plugin waits before displaying a review request.
*
* @since 2.1.0
*/
const WAIT_PERIOD = 14;
/**
* Initialize hooks.
*
* @since 2.1.0
*/
public function hooks() {
add_action( 'admin_notices', array( $this, 'review_request' ) );
add_action( 'wp_ajax_wp_mail_smtp_review_dismiss', array( $this, 'review_dismiss' ) );
}
/**
* Add admin notices as needed for reviews.
*
* @since 2.1.0
*/
public function review_request() {
// Only consider showing the review request to admin users.
if ( ! is_super_admin() ) {
return;
}
// Verify that we can do a check for reviews.
$review = get_option( self::NOTICE_OPTION );
$time = time();
$load = false;
if ( empty( $review ) ) {
$review = [
'time' => $time,
'dismissed' => false,
];
update_option( self::NOTICE_OPTION, $review );
} else {
// Check if it has been dismissed or not.
if ( isset( $review['dismissed'] ) && ! $review['dismissed'] ) {
$load = true;
}
}
// If we cannot load, return early.
if ( ! $load ) {
return;
}
$this->review();
}
/**
* Maybe show review request.
*
* @since 2.1.0
*/
private function review() {
// Get the currently selected mailer.
$mailer = Options::init()->get( 'mail', 'mailer' );
// Skip if the default mailer is selected.
if ( $mailer === 'mail' ) {
return;
}
// Fetch when plugin was initially activated.
$activated = get_option( 'wp_mail_smtp_activated_time' );
// Skip if the plugin activated time is not set.
if ( empty( $activated ) ) {
return;
}
// Check if mailer setup is complete.
$mailer_setup_complete = wp_mail_smtp()
->get_providers()
->get_mailer( $mailer, wp_mail_smtp()->get_processor()->get_phpmailer() )
->is_mailer_complete();
// Skip if the mailer is not set or the plugin is active for less then a defined number of days.
if ( ! $mailer_setup_complete || ( $activated + ( DAY_IN_SECONDS * self::WAIT_PERIOD ) ) > time() ) {
return;
}
// We have a candidate! Output a review message.
?>
<div class="notice notice-info is-dismissible wp-mail-smtp-review-notice">
<div class="wp-mail-smtp-review-step wp-mail-smtp-review-step-1">
<p><?php esc_html_e( 'Are you enjoying WP Mail SMTP?', 'wp-mail-smtp' ); ?></p>
<p>
<a href="#" class="wp-mail-smtp-review-switch-step" data-step="3"><?php esc_html_e( 'Yes', 'wp-mail-smtp' ); ?></a><br />
<a href="#" class="wp-mail-smtp-review-switch-step" data-step="2"><?php esc_html_e( 'Not Really', 'wp-mail-smtp' ); ?></a>
</p>
</div>
<div class="wp-mail-smtp-review-step wp-mail-smtp-review-step-2" style="display: none">
<p><?php esc_html_e( 'We\'re sorry to hear you aren\'t enjoying WP Mail SMTP. We would love a chance to improve. Could you take a minute and let us know what we can do better?', 'wp-mail-smtp' ); ?></p>
<p>
<a href="https://wpmailsmtp.com/plugin-feedback/" class="wp-mail-smtp-dismiss-review-notice wp-mail-smtp-review-out" target="_blank" rel="noopener noreferrer">
<?php esc_html_e( 'Give Feedback', 'wp-mail-smtp' ); ?>
</a><br>
<a href="#" class="wp-mail-smtp-dismiss-review-notice" target="_blank" rel="noopener noreferrer">
<?php esc_html_e( 'No thanks', 'wp-mail-smtp' ); ?>
</a>
</p>
</div>
<div class="wp-mail-smtp-review-step wp-mail-smtp-review-step-3" style="display: none">
<p><?php esc_html_e( 'Thats awesome! Could you please do me a BIG favor and give it a 5-star rating on WordPress to help us spread the word and boost our motivation?', 'wp-mail-smtp' ); ?></p>
<p><strong><?php echo wp_kses( __( '~ Jared Atchison<br>Lead Developer, WP Mail SMTP', 'wp-mail-smtp' ), [ 'br' => [] ] ); ?></strong></p>
<p>
<a href="https://wordpress.org/support/plugin/wp-mail-smtp/reviews/?filter=5#new-post" class="wp-mail-smtp-dismiss-review-notice wp-mail-smtp-review-out" target="_blank" rel="noopener noreferrer">
<?php esc_html_e( 'Ok, you deserve it', 'wp-mail-smtp' ); ?>
</a><br>
<a href="#" class="wp-mail-smtp-dismiss-review-notice" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Nope, maybe later', 'wp-mail-smtp' ); ?></a><br>
<a href="#" class="wp-mail-smtp-dismiss-review-notice" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'I already did', 'wp-mail-smtp' ); ?></a>
</p>
</div>
</div>
<script type="text/javascript">
jQuery( document ).ready( function ( $ ) {
$( document ).on( 'click', '.wp-mail-smtp-dismiss-review-notice, .wp-mail-smtp-review-notice button', function( e ) {
if ( ! $( this ).hasClass( 'wp-mail-smtp-review-out' ) ) {
e.preventDefault();
}
$.post( ajaxurl, { action: 'wp_mail_smtp_review_dismiss' } );
$( '.wp-mail-smtp-review-notice' ).remove();
} );
$( document ).on( 'click', '.wp-mail-smtp-review-switch-step', function( e ) {
e.preventDefault();
var target = parseInt( $( this ).attr( 'data-step' ), 10 );
if ( target ) {
var $notice = $( this ).closest( '.wp-mail-smtp-review-notice' );
var $review_step = $notice.find( '.wp-mail-smtp-review-step-' + target );
if ( $review_step.length > 0 ) {
$notice.find( '.wp-mail-smtp-review-step:visible' ).fadeOut( function() {
$review_step.fadeIn();
} );
}
}
} );
} );
</script>
<?php
}
/**
* Dismiss the review admin notice.
*
* @since 2.1.0
*/
public function review_dismiss() {
$review = get_option( self::NOTICE_OPTION, [] );
$review['time'] = time();
$review['dismissed'] = true;
update_option( self::NOTICE_OPTION, $review );
if ( is_super_admin() && is_multisite() ) {
$site_list = get_sites();
foreach ( (array) $site_list as $site ) {
switch_to_blog( $site->blog_id );
update_option( self::NOTICE_OPTION, $review );
restore_current_blog();
}
}
wp_send_json_success();
}
}

View File

@ -95,6 +95,9 @@ class Core {
*/
public function hooks() {
// Action Scheduler requires a special early loading procedure.
add_action( 'plugins_loaded', array( $this, 'load_action_scheduler' ), -10 );
// Activation hook.
register_activation_hook( WPMS_PLUGIN_FILE, array( $this, 'activate' ) );
@ -107,6 +110,9 @@ class Core {
add_action( 'init', array( $this, 'init' ) );
// Initialize Action Scheduler tasks.
add_action( 'init', array( $this, 'get_tasks' ), 5 );
add_action( 'plugins_loaded', array( $this, 'get_pro' ) );
}
@ -188,6 +194,25 @@ class Core {
return $this->pro;
}
/**
* Get/Load the Tasks code of the plugin.
*
* @since 2.1.0
*
* @return \WPMailSMTP\Tasks\Tasks
*/
public function get_tasks() {
static $tasks;
if ( ! isset( $tasks ) ) {
$tasks = apply_filters( 'wp_mail_smtp_core_get_tasks', new Tasks\Tasks() );
$tasks->init();
}
return $tasks;
}
/**
* This method allows to overwrite certain core WP functions, because it's fired:
* - after `muplugins_loaded` hook,
@ -573,6 +598,13 @@ class Core {
// Save default options, only once.
Options::init()->set( Options::get_defaults(), true );
/**
* Store the timestamp of first plugin activation.
*
* @since 2.1.0
*/
add_option( 'wp_mail_smtp_activated_time', time(), '', false );
}
/**
@ -689,4 +721,16 @@ class Core {
return (bool) apply_filters( 'wp_mail_smtp_is_white_labeled', false );
}
/**
* Require the action scheduler in an early plugins_loaded hook (-10).
*
* @see https://actionscheduler.org/usage/#load-order
*
* @since 2.1.0
*/
public function load_action_scheduler() {
require_once $this->plugin_path . '/vendor/woocommerce/action-scheduler/action-scheduler.php';
}
}

View File

@ -1,145 +1,154 @@
<?php
namespace WPMailSMTP;
// Load PHPMailer class, so we can subclass it.
if ( ! class_exists( 'PHPMailer', false ) ) {
require_once ABSPATH . WPINC . '/class-phpmailer.php';
}
/**
* Class MailCatcher replaces the \PHPMailer and modifies the email sending logic.
* Thus, we can use other mailers API to do what we need, or stop emails completely.
*
* @since 1.0.0
*/
class MailCatcher extends \PHPMailer {
/**
* Callback Action function name.
*
* The function that handles the result of the send email action.
* It is called out by send() for each email sent.
*
* @since 1.3.0
*
* @var string
*/
public $action_function = '\WPMailSMTP\Processor::send_callback';
/**
* Modify the default send() behaviour.
* For those mailers, that relies on PHPMailer class - call it directly.
* For others - init the correct provider and process it.
*
* @since 1.0.0
* @since 1.4.0 Process "Do Not Send" option, but always allow test email.
*
* @throws \phpmailerException When sending via PhpMailer fails for some reason.
*
* @return bool
*/
public function send() {
$options = new Options();
$mail_mailer = sanitize_key( $options->get( 'mail', 'mailer' ) );
$is_emailing_blocked = false;
if ( wp_mail_smtp()->is_blocked() ) {
$is_emailing_blocked = true;
}
// Always allow a test email - check for the specific header.
foreach ( (array) $this->getCustomHeaders() as $header ) {
if (
! empty( $header[0] ) &&
! empty( $header[1] ) &&
$header[0] === 'X-Mailer-Type' &&
trim( $header[1] ) === 'WPMailSMTP/Admin/Test'
) {
$is_emailing_blocked = false;
}
};
// Do not send emails if admin desired that.
if ( $is_emailing_blocked ) {
return false;
}
// Define a custom header, that will be used to identify the plugin and the mailer.
$this->XMailer = 'WPMailSMTP/Mailer/' . $mail_mailer . ' ' . WPMS_PLUGIN_VER;
// Use the default PHPMailer, as we inject our settings there for certain providers.
if (
$mail_mailer === 'mail' ||
$mail_mailer === 'smtp' ||
$mail_mailer === 'pepipost'
) {
try {
// Prepare all the headers.
if ( ! $this->preSend() ) {
return false;
}
// Allow to hook after all the preparation before the actual sending.
do_action( 'wp_mail_smtp_mailcatcher_smtp_send_before', $this );
return $this->postSend();
} catch ( \phpmailerException $e ) {
$this->mailHeader = '';
$this->setError( $e->getMessage() );
if ( $this->exceptions ) {
throw $e;
}
return false;
}
}
// We need this so that the \PHPMailer class will correctly prepare all the headers.
$this->Mailer = 'mail';
// Prepare everything (including the message) for sending.
if ( ! $this->preSend() ) {
return false;
}
$mailer = wp_mail_smtp()->get_providers()->get_mailer( $mail_mailer, $this );
if ( ! $mailer ) {
return false;
}
if ( ! $mailer->is_php_compatible() ) {
return false;
}
/*
* Send the actual email.
* We reuse everything, that was preprocessed for usage in \PHPMailer.
*/
$mailer->send();
$is_sent = $mailer->is_email_sent();
// Allow to perform any actions with the data.
do_action( 'wp_mail_smtp_mailcatcher_send_after', $mailer, $this );
return $is_sent;
}
/**
* Returns all custom headers.
* In older versions of \PHPMailer class this method didn't exist.
* As we support WordPress 3.6+ - we need to make sure this method is always present.
*
* @since 1.5.0
*
* @return array
*/
public function getCustomHeaders() {
return $this->CustomHeader;
}
}
<?php
namespace WPMailSMTP;
// Load PHPMailer class, so we can subclass it.
if ( ! class_exists( 'PHPMailer', false ) ) {
require_once ABSPATH . WPINC . '/class-phpmailer.php';
}
/**
* Class MailCatcher replaces the \PHPMailer and modifies the email sending logic.
* Thus, we can use other mailers API to do what we need, or stop emails completely.
*
* @since 1.0.0
*/
class MailCatcher extends \PHPMailer {
/**
* Callback Action function name.
*
* The function that handles the result of the send email action.
* It is called out by send() for each email sent.
*
* @since 1.3.0
*
* @var string
*/
public $action_function = '\WPMailSMTP\Processor::send_callback';
/**
* Modify the default send() behaviour.
* For those mailers, that relies on PHPMailer class - call it directly.
* For others - init the correct provider and process it.
*
* @since 1.0.0
* @since 1.4.0 Process "Do Not Send" option, but always allow test email.
*
* @throws \phpmailerException When sending via PhpMailer fails for some reason.
*
* @return bool
*/
public function send() {
$options = new Options();
$mail_mailer = sanitize_key( $options->get( 'mail', 'mailer' ) );
$is_emailing_blocked = false;
if ( wp_mail_smtp()->is_blocked() ) {
$is_emailing_blocked = true;
}
// Always allow a test email - check for the specific header.
foreach ( (array) $this->getCustomHeaders() as $header ) {
if (
! empty( $header[0] ) &&
! empty( $header[1] ) &&
$header[0] === 'X-Mailer-Type' &&
trim( $header[1] ) === 'WPMailSMTP/Admin/Test'
) {
$is_emailing_blocked = false;
}
};
// Do not send emails if admin desired that.
if ( $is_emailing_blocked ) {
return false;
}
// Define a custom header, that will be used to identify the plugin and the mailer.
$this->XMailer = 'WPMailSMTP/Mailer/' . $mail_mailer . ' ' . WPMS_PLUGIN_VER;
// Use the default PHPMailer, as we inject our settings there for certain providers.
if (
$mail_mailer === 'mail' ||
$mail_mailer === 'smtp' ||
$mail_mailer === 'pepipost'
) {
try {
// Prepare all the headers.
if ( ! $this->preSend() ) {
return false;
}
// Allow to hook after all the preparation before the actual sending.
do_action( 'wp_mail_smtp_mailcatcher_smtp_send_before', $this );
return $this->postSend();
} catch ( \phpmailerException $e ) {
$this->mailHeader = '';
$this->setError( $e->getMessage() );
// Set the debug error, but not for default PHP mailer.
if ( $mail_mailer !== 'mail' ) {
Debug::set(
'Mailer: ' . esc_html( wp_mail_smtp()->get_providers()->get_options( $mail_mailer )->get_title() ) . PHP_EOL .
$e->getMessage()
);
}
if ( $this->exceptions ) {
throw $e;
}
return false;
}
}
// We need this so that the \PHPMailer class will correctly prepare all the headers.
$this->Mailer = 'mail';
// Prepare everything (including the message) for sending.
if ( ! $this->preSend() ) {
return false;
}
$mailer = wp_mail_smtp()->get_providers()->get_mailer( $mail_mailer, $this );
if ( ! $mailer ) {
return false;
}
if ( ! $mailer->is_php_compatible() ) {
return false;
}
/*
* Send the actual email.
* We reuse everything, that was preprocessed for usage in \PHPMailer.
*/
$mailer->send();
$is_sent = $mailer->is_email_sent();
// Allow to perform any actions with the data.
do_action( 'wp_mail_smtp_mailcatcher_send_after', $mailer, $this );
return $is_sent;
}
/**
* Returns all custom headers.
* In older versions of \PHPMailer class this method didn't exist.
* As we support WordPress 3.6+ - we need to make sure this method is always present.
*
* @since 1.5.0
*
* @return array
*/
public function getCustomHeaders() {
return $this->CustomHeader;
}
}

View File

@ -1,257 +1,401 @@
<?php
namespace WPMailSMTP;
/**
* Class Migration helps migrate all plugin options saved into DB to a new storage location.
*
* @since 1.0.0
*/
class Migration {
/**
* All old values for pre 1.0 version of a plugin.
*
* @since 1.0.0
*
* @var array
*/
protected $old_keys = array(
'pepipost_ssl',
'pepipost_port',
'pepipost_pass',
'pepipost_user',
'smtp_pass',
'smtp_user',
'smtp_auth',
'smtp_ssl',
'smtp_port',
'smtp_host',
'mail_set_return_path',
'mailer',
'mail_from_name',
'mail_from',
'wp_mail_smtp_am_notifications_hidden',
);
/**
* Old values, taken from $old_keys options.
*
* @since 1.0.0
*
* @var array
*/
protected $old_values = array();
/**
* Converted array of data from previous option values.
*
* @since 1.0.0
*
* @var array
*/
protected $new_values = array();
/**
* Migration constructor.
*
* @since 1.0.0
*/
public function __construct() {
if ( $this->is_migrated() ) {
return;
}
$this->old_values = $this->get_old_values();
$this->new_values = $this->get_converted_options();
Options::init()->set( $this->new_values, true );
// Removing all old options will be enabled some time in the future.
// $this->clean_deprecated_data();
}
/**
* Whether we already migrated or not.
*
* @since 1.0.0
*
* @return bool
*/
protected function is_migrated() {
$is_migrated = false;
$new_values = get_option( Options::META_KEY, array() );
if ( ! empty( $new_values ) ) {
$is_migrated = true;
}
return $is_migrated;
}
/**
* Get all old values from DB.
*
* @since 1.0.0
*
* @return array
*/
protected function get_old_values() {
$old_values = array();
foreach ( $this->old_keys as $old_key ) {
$value = get_option( $old_key, '' );
if ( ! empty( $value ) ) {
$old_values[ $old_key ] = $value;
}
}
return $old_values;
}
/**
* Convert old values from key=>value to a multidimensional array of data.
*
* @since 1.0.0
*/
protected function get_converted_options() {
$converted = array();
foreach ( $this->old_keys as $old_key ) {
$old_value = isset( $this->old_values[ $old_key ] ) ? $this->old_values[ $old_key ] : '';
switch ( $old_key ) {
case 'pepipost_user':
case 'pepipost_pass':
case 'pepipost_port':
case 'pepipost_ssl':
// Do not migrate pepipost options if it's not activated at the moment.
if ( isset( $this->old_values['mailer'] ) && $this->old_values['mailer'] === 'pepipost' ) {
$shortcut = explode( '_', $old_key );
if ( $old_key === 'pepipost_ssl' ) {
$converted[ $shortcut[0] ]['encryption'] = $old_value;
} else {
$converted[ $shortcut[0] ][ $shortcut[1] ] = $old_value;
}
}
break;
case 'smtp_host':
case 'smtp_port':
case 'smtp_ssl':
case 'smtp_auth':
case 'smtp_user':
case 'smtp_pass':
$shortcut = explode( '_', $old_key );
if ( $old_key === 'smtp_ssl' ) {
$converted[ $shortcut[0] ]['encryption'] = $old_value;
} elseif ( $old_key === 'smtp_auth' ) {
$converted[ $shortcut[0] ][ $shortcut[1] ] = ( $old_value === 'true' ? 'yes' : 'no' );
} else {
$converted[ $shortcut[0] ][ $shortcut[1] ] = $old_value;
}
break;
case 'mail_from':
$converted['mail']['from_email'] = $old_value;
break;
case 'mail_from_name':
$converted['mail']['from_name'] = $old_value;
break;
case 'mail_set_return_path':
$converted['mail']['return_path'] = ( $old_value === 'true' );
break;
case 'mailer':
$converted['mail']['mailer'] = $old_value;
break;
case 'wp_mail_smtp_am_notifications_hidden':
$converted['general']['am_notifications_hidden'] = ( isset( $old_value ) && $old_value === 'true' );
break;
}
}
$converted = $this->get_converted_constants_options( $converted );
return $converted;
}
/**
* Some users use constants in wp-config.php to define values.
* We need to prioritize them and reapply data to options.
* Use only those that are actually defined.
*
* @since 1.0.0
*
* @param array $converted
*
* @return array
*/
protected function get_converted_constants_options( $converted ) {
// Are we configured via constants?
if ( ! defined( 'WPMS_ON' ) || ! WPMS_ON ) {
return $converted;
}
/*
* Mail settings.
*/
if ( defined( 'WPMS_MAIL_FROM' ) ) {
$converted['mail']['from_email'] = WPMS_MAIL_FROM;
}
if ( defined( 'WPMS_MAIL_FROM_NAME' ) ) {
$converted['mail']['from_name'] = WPMS_MAIL_FROM_NAME;
}
if ( defined( 'WPMS_MAILER' ) ) {
$converted['mail']['mailer'] = WPMS_MAILER;
}
if ( defined( 'WPMS_SET_RETURN_PATH' ) ) {
$converted['mail']['return_path'] = WPMS_SET_RETURN_PATH;
}
/*
* SMTP settings.
*/
if ( defined( 'WPMS_SMTP_HOST' ) ) {
$converted['smtp']['host'] = WPMS_SMTP_HOST;
}
if ( defined( 'WPMS_SMTP_PORT' ) ) {
$converted['smtp']['port'] = WPMS_SMTP_PORT;
}
if ( defined( 'WPMS_SSL' ) ) {
$converted['smtp']['ssl'] = WPMS_SSL;
}
if ( defined( 'WPMS_SMTP_AUTH' ) ) {
$converted['smtp']['auth'] = WPMS_SMTP_AUTH;
}
if ( defined( 'WPMS_SMTP_USER' ) ) {
$converted['smtp']['user'] = WPMS_SMTP_USER;
}
if ( defined( 'WPMS_SMTP_PASS' ) ) {
$converted['smtp']['pass'] = WPMS_SMTP_PASS;
}
return $converted;
}
/**
* Delete all old values that are stored separately each.
*
* @since 1.0.0
*/
protected function clean_deprecated_data() {
foreach ( $this->old_keys as $old_key ) {
delete_option( $old_key );
}
}
}
<?php
namespace WPMailSMTP;
use WPMailSMTP\Tasks\Meta;
/**
* Class Migration helps migrate plugin options, DB tables and more.
*
* @since 1.0.0 Migrate all plugin options saved from separate WP options into one.
* @since 2.1.0 Major overhaul of this class to use DB migrations (or any other migrations per version).
*/
class Migration {
/**
* Version of the latest migration.
*
* @since 2.1.0
*/
const VERSION = 2;
/**
* Option key where we save the current migration version.
*
* @since 2.1.0
*/
const OPTION_NAME = 'wp_mail_smtp_migration_version';
/**
* Current migration version, received from self::OPTION_NAME WP option
*
* @since 2.1.0
*
* @var int
*/
protected $cur_ver;
/**
* All old values for pre 1.0 version of a plugin.
*
* @since 1.0.0
*
* @var array
*/
protected $old_keys = array(
'pepipost_ssl',
'pepipost_port',
'pepipost_pass',
'pepipost_user',
'smtp_pass',
'smtp_user',
'smtp_auth',
'smtp_ssl',
'smtp_port',
'smtp_host',
'mail_set_return_path',
'mailer',
'mail_from_name',
'mail_from',
'wp_mail_smtp_am_notifications_hidden',
);
/**
* Old values, taken from $old_keys options.
*
* @since 1.0.0
*
* @var array
*/
protected $old_values = array();
/**
* Converted array of data from previous option values.
*
* @since 1.0.0
*
* @var array
*/
protected $new_values = array();
/**
* Migration constructor.
*
* @since 1.0.0
* @since 2.1.0 Redefined constructor - major overhaul.
*/
public function __construct() {
$this->cur_ver = self::get_cur_version();
$this->maybe_migrate();
}
/**
* Static on purpose, to get current migration version without __construct() and validation.
*
* @since 2.1.0
*
* @return int
*/
public static function get_cur_version() {
return (int) get_option( self::OPTION_NAME, 0 );
}
/**
* Run the migration if needed.
*
* @since 2.1.0
*/
protected function maybe_migrate() {
if ( ! is_admin() ) {
return;
}
if ( version_compare( $this->cur_ver, self::VERSION, '<' ) ) {
$this->run( self::VERSION );
}
}
/**
* Actual migration launcher.
*
* @since 2.1.0
*
* @param int $version The version of migration to run.
*/
protected function run( $version ) {
$function_version = (int) $version;
if ( method_exists( $this, 'migrate_to_' . $function_version ) ) {
$this->{'migrate_to_' . $function_version}();
} else {
$message = sprintf( /* translators: %1$s - WP Mail SMTP, %2$s - error message. */
esc_html__( 'There was an error while upgrading the database. Please contact %1$s support with this information: %2$s.', 'wp-mail-smtp' ),
'<strong>WP Mail SMTP</strong>',
'<code>migration from v' . self::get_cur_version() . ' to v' . self::VERSION . ' failed. Plugin version: v' . WPMS_PLUGIN_VER . '</code>'
);
WP::add_admin_notice( $message, WP::ADMIN_NOTICE_ERROR );
}
}
/**
* Update migration version in options table.
*
* @since 2.1.0
*
* @param int $version Migration version.
*/
protected function update_db_ver( $version ) {
if ( empty( $version ) ) {
$version = self::VERSION;
}
// Autoload it, because this value is checked all the time
// and no need to request it separately from all autoloaded options.
update_option( self::OPTION_NAME, $version, true );
}
/**
* Prevent running the same migration twice.
* Run migration only when required.
*
* @since 2.1.0
*
* @param string $version The version of migration to check for potential execution.
*/
protected function maybe_required_older_migrations( $version ) {
if ( version_compare( $this->cur_ver, $version, '<' ) ) {
$this->run( $version );
}
}
/**
* Migration from 0.x to 1.0.0.
* Move separate plugin WP options to one main plugin WP option setting.
*
* @since 2.1.0
*/
private function migrate_to_1() {
if ( $this->is_migrated() ) {
return;
}
$this->old_values = $this->get_old_values();
$this->new_values = $this->get_converted_options();
Options::init()->set( $this->new_values, true );
$this->update_db_ver( 1 );
}
/**
* Migration from 1.x to 2.1.0.
* Create Tasks\Meta table, if it does not exist.
*
* @since 2.1.0
*/
private function migrate_to_2() {
$this->maybe_required_older_migrations( 1 );
$meta = new Meta();
// Create the table if it doesn't exist.
if ( $meta && ! $meta->table_exists() ) {
$meta->create_table();
}
$this->update_db_ver( 2 );
}
/**
* Whether we already migrated or not.
*
* @since 1.0.0
*
* @return bool
*/
protected function is_migrated() {
$is_migrated = false;
$new_values = get_option( Options::META_KEY, array() );
if ( ! empty( $new_values ) ) {
$is_migrated = true;
}
return $is_migrated;
}
/**
* Get all old values from DB.
*
* @since 1.0.0
*
* @return array
*/
protected function get_old_values() {
$old_values = array();
foreach ( $this->old_keys as $old_key ) {
$value = get_option( $old_key, '' );
if ( ! empty( $value ) ) {
$old_values[ $old_key ] = $value;
}
}
return $old_values;
}
/**
* Convert old values from key=>value to a multidimensional array of data.
*
* @since 1.0.0
*/
protected function get_converted_options() {
$converted = array();
foreach ( $this->old_keys as $old_key ) {
$old_value = isset( $this->old_values[ $old_key ] ) ? $this->old_values[ $old_key ] : '';
switch ( $old_key ) {
case 'pepipost_user':
case 'pepipost_pass':
case 'pepipost_port':
case 'pepipost_ssl':
// Do not migrate pepipost options if it's not activated at the moment.
if ( isset( $this->old_values['mailer'] ) && $this->old_values['mailer'] === 'pepipost' ) {
$shortcut = explode( '_', $old_key );
if ( $old_key === 'pepipost_ssl' ) {
$converted[ $shortcut[0] ]['encryption'] = $old_value;
} else {
$converted[ $shortcut[0] ][ $shortcut[1] ] = $old_value;
}
}
break;
case 'smtp_host':
case 'smtp_port':
case 'smtp_ssl':
case 'smtp_auth':
case 'smtp_user':
case 'smtp_pass':
$shortcut = explode( '_', $old_key );
if ( $old_key === 'smtp_ssl' ) {
$converted[ $shortcut[0] ]['encryption'] = $old_value;
} elseif ( $old_key === 'smtp_auth' ) {
$converted[ $shortcut[0] ][ $shortcut[1] ] = ( $old_value === 'true' ? 'yes' : 'no' );
} else {
$converted[ $shortcut[0] ][ $shortcut[1] ] = $old_value;
}
break;
case 'mail_from':
$converted['mail']['from_email'] = $old_value;
break;
case 'mail_from_name':
$converted['mail']['from_name'] = $old_value;
break;
case 'mail_set_return_path':
$converted['mail']['return_path'] = ( $old_value === 'true' );
break;
case 'mailer':
$converted['mail']['mailer'] = $old_value;
break;
case 'wp_mail_smtp_am_notifications_hidden':
$converted['general']['am_notifications_hidden'] = ( isset( $old_value ) && $old_value === 'true' );
break;
}
}
$converted = $this->get_converted_constants_options( $converted );
return $converted;
}
/**
* Some users use constants in wp-config.php to define values.
* We need to prioritize them and reapply data to options.
* Use only those that are actually defined.
*
* @since 1.0.0
*
* @param array $converted
*
* @return array
*/
protected function get_converted_constants_options( $converted ) {
// Are we configured via constants?
if ( ! defined( 'WPMS_ON' ) || ! WPMS_ON ) {
return $converted;
}
/*
* Mail settings.
*/
if ( defined( 'WPMS_MAIL_FROM' ) ) {
$converted['mail']['from_email'] = WPMS_MAIL_FROM;
}
if ( defined( 'WPMS_MAIL_FROM_NAME' ) ) {
$converted['mail']['from_name'] = WPMS_MAIL_FROM_NAME;
}
if ( defined( 'WPMS_MAILER' ) ) {
$converted['mail']['mailer'] = WPMS_MAILER;
}
if ( defined( 'WPMS_SET_RETURN_PATH' ) ) {
$converted['mail']['return_path'] = WPMS_SET_RETURN_PATH;
}
/*
* SMTP settings.
*/
if ( defined( 'WPMS_SMTP_HOST' ) ) {
$converted['smtp']['host'] = WPMS_SMTP_HOST;
}
if ( defined( 'WPMS_SMTP_PORT' ) ) {
$converted['smtp']['port'] = WPMS_SMTP_PORT;
}
if ( defined( 'WPMS_SSL' ) ) {
$converted['smtp']['ssl'] = WPMS_SSL;
}
if ( defined( 'WPMS_SMTP_AUTH' ) ) {
$converted['smtp']['auth'] = WPMS_SMTP_AUTH;
}
if ( defined( 'WPMS_SMTP_USER' ) ) {
$converted['smtp']['user'] = WPMS_SMTP_USER;
}
if ( defined( 'WPMS_SMTP_PASS' ) ) {
$converted['smtp']['pass'] = WPMS_SMTP_PASS;
}
return $converted;
}
/**
* Delete all old values that are stored separately each.
*
* @since 1.0.0
*/
protected function clean_deprecated_data() {
foreach ( $this->old_keys as $old_key ) {
delete_option( $old_key );
}
}
}

View File

@ -19,21 +19,22 @@ class Options {
* @since 1.4.0 Added Mailgun:region.
* @since 1.5.0 Added Outlook/AmazonSES.
* @since 1.8.0 Added Pepipost API.
* @since 2.0.0 Added SMTP.com API.
*
* @since
*
* @var array Map of all the default options of the plugin.
*/
private static $map = array(
'mail' => array(
private static $map = [
'mail' => [
'from_name',
'from_email',
'mailer',
'return_path',
'from_name_force',
'from_email_force',
),
'smtp' => array(
],
'smtp' => [
'host',
'port',
'encryption',
@ -41,62 +42,64 @@ class Options {
'auth',
'user',
'pass',
),
'gmail' => array(
],
'gmail' => [
'client_id',
'client_secret',
),
'outlook' => array(
],
'outlook' => [
'client_id',
'client_secret',
),
'amazonses' => array(
],
'amazonses' => [
'client_id',
'client_secret',
'region',
'emails_pending',
),
'mailgun' => array(
],
'mailgun' => [
'api_key',
'domain',
'region',
),
'sendgrid' => array(
],
'sendgrid' => [
'api_key',
),
'smtpcom' => array(
],
'smtpcom' => [
'api_key',
'channel',
),
'sendinblue' => array(
],
'sendinblue' => [
'api_key',
),
'pepipostapi' => array(
],
'pepipostapi' => [
'api_key',
),
'pepipost' => array(
],
'pepipost' => [
'host',
'port',
'encryption',
'auth',
'user',
'pass',
),
'license' => array(
],
'license' => [
'key',
),
);
],
];
/**
* That's where plugin options are saved in wp_options table.
*
* @var string
* @since 1.0.0
*/
const META_KEY = 'wp_mail_smtp';
/**
* All the plugin options.
*
* @since 1.0.0
*
* @var array
*/
private $_options = array();
@ -141,6 +144,7 @@ class Options {
* Default options that are saved on plugin activation.
*
* @since 1.3.0
* @since 2.1.0 Set the Force from email to "on" by default.
*
* @return array
*/
@ -152,7 +156,7 @@ class Options {
'from_name' => get_bloginfo( 'name' ),
'mailer' => 'mail',
'return_path' => false,
'from_email_force' => false,
'from_email_force' => true,
'from_name_force' => false,
),
'smtp' => array(
@ -784,7 +788,7 @@ class Options {
* @since 1.5.0 Added Outlook/AmazonSES, Email Log. Stop saving const values into DB.
*
* @param array $options Plugin options to save.
* @param bool $once Whether to update existing options or to add these options only once.
* @param bool $once Whether to update existing options or to add these options only once.
*/
public function set( $options, $once = false ) {
/*

View File

@ -9,6 +9,18 @@ namespace WPMailSMTP;
*/
class Processor {
/**
* This attribute will hold the "original" WP from email address passed to the wp_mail_from filter,
* that is not equal to the default email address.
*
* It should hold an email address set via the wp_mail_from filter, before we might overwrite it.
*
* @since 2.1.0
*
* @var string
*/
protected $wp_mail_from;
/**
* Processor constructor.
*
@ -81,6 +93,11 @@ class Processor {
$phpmailer->SMTPAutoTLS = false;
}
// Check if original WP from email can be set as the reply_to attribute.
if ( $this->allow_setting_original_from_email_to_reply_to( $phpmailer->getReplyToAddresses(), $mailer ) ) {
$phpmailer->addReplyTo( $this->wp_mail_from );
}
// If we're sending via SMTP, set the host.
if ( 'smtp' === $mailer ) {
// Set the other options.
@ -104,12 +121,62 @@ class Processor {
$phpmailer->Password = $options->get( $mailer, 'pass' );
}
// Maybe set default reply-to header.
$this->set_default_reply_to( $phpmailer );
// You can add your own options here.
// See the phpmailer documentation for more info: https://github.com/PHPMailer/PHPMailer/tree/5.2-stable.
/** @noinspection PhpUnusedLocalVariableInspection It's passed by reference. */
$phpmailer = apply_filters( 'wp_mail_smtp_custom_options', $phpmailer );
}
/**
* Check if it's allowed to set the original WP from email to the reply_to field.
*
* @since 2.1.0
*
* @param array $reply_to Array of currently set reply to emails.
* @param string $mailer The slug of current mailer.
*
* @return bool
*/
protected function allow_setting_original_from_email_to_reply_to( $reply_to, $mailer ) {
$options = new Options();
$forced = $options->get( 'mail', 'from_email_force' );
$from_email = $options->get( 'mail', 'from_email' );
if ( ! empty( $reply_to ) ) {
return false;
}
if ( in_array( $mailer, array( 'gmail', 'outlook' ), true ) ) {
$forced = true;
switch ( $mailer ) {
case 'gmail':
$sender = wp_mail_smtp()->get_providers()->get_auth( 'gmail' )->get_user_info();
break;
case 'outlook':
$sender = $options->get( 'outlook', 'user_details' );
break;
}
$from_email = ! empty( $sender['email'] ) ? $sender['email'] : '';
}
if (
empty( $this->wp_mail_from ) ||
$from_email === $this->wp_mail_from ||
! $forced
) {
return false;
}
return true;
}
/**
* This method will be called every time 'smtp' and 'mail' mailers will be used to send emails.
*
@ -157,6 +224,11 @@ class Processor {
$from_email = $options->get( 'mail', 'from_email' );
$def_email = $this->get_default_email();
// Save the "original" set WP email from address for later use.
if ( $wp_email !== $def_email ) {
$this->wp_mail_from = $wp_email;
}
// Return FROM EMAIL if forced in settings.
if ( $forced & ! empty( $from_email ) ) {
return $from_email;
@ -250,4 +322,34 @@ class Processor {
return $phpmailer;
}
/**
* Set the default reply_to header, if:
* - no other reply_to headers are already set and,
* - the default reply_to address filter `wp_mail_smtp_processor_default_reply_to_addresses` is configured.
*
* @since 2.1.1
*
* @param \PHPMailer $phpmailer The PHPMailer object.
*/
private function set_default_reply_to( $phpmailer ) {
if ( ! empty( $phpmailer->getReplyToAddresses() ) ) {
return;
}
$default_reply_to_emails = apply_filters( 'wp_mail_smtp_processor_set_default_reply_to', '' );
if ( empty( $default_reply_to_emails ) ) {
return;
}
foreach ( explode( ',', $default_reply_to_emails ) as $email ) {
$email = trim( $email );
if ( filter_var( $email, FILTER_VALIDATE_EMAIL ) ) {
$phpmailer->addReplyTo( $email );
}
}
}
}

View File

@ -92,26 +92,28 @@ class Mailer extends MailerAbstract {
$this->phpmailer->Sender = $gmail_creds['email'];
}
// Get the raw MIME email using MailCatcher data.
// We need here to make base64URL-safe string.
$base64 = str_replace(
array( '+', '/', '=' ),
array( '-', '_', '' ),
base64_encode( $this->phpmailer->getSentMIMEMessage() )
);
$message->setRaw( $base64 );
$service = new \Google_Service_Gmail( $auth->get_client() );
try {
// Prepare a message for sending.
$this->phpmailer->preSend();
// Get the raw MIME email using MailCatcher data.
// We need here to make base64URL-safe string.
$base64 = str_replace(
[ '+', '/', '=' ],
[ '-', '_', '' ],
base64_encode( $this->phpmailer->getSentMIMEMessage() ) //phpcs:ignore
);
$message->setRaw( $base64 );
$service = new \Google_Service_Gmail( $auth->get_client() );
$response = $service->users_messages->send( 'me', $message );
$this->process_response( $response );
} catch ( \Exception $e ) {
Debug::set(
'Mailer: Gmail' . "\r\n" .
$e->getMessage()
$this->process_exception_message( $e->getMessage() )
);
return;
@ -124,7 +126,7 @@ class Mailer extends MailerAbstract {
* @since 1.0.0
* @since 1.5.0 Added action "wp_mail_smtp_providers_gmail_mailer_process_response" with $response.
*
* @param \Google_Service_Gmail_Message $response
* @param \Google_Service_Gmail_Message $response Instance of Gmail response.
*/
protected function process_response( $response ) {
@ -160,7 +162,12 @@ class Mailer extends MailerAbstract {
}
/**
* @inheritdoc
* This method is relevant to SMTP and Pepipost.
* All other custom mailers should override it with own information.
*
* @since 1.2.0
*
* @return string
*/
public function get_debug_info() {
@ -200,7 +207,11 @@ class Mailer extends MailerAbstract {
}
/**
* @inheritdoc
* Whether the mailer has all its settings correctly set up and saved.
*
* @since 1.4.0
*
* @return bool
*/
public function is_mailer_complete() {
@ -219,4 +230,75 @@ class Mailer extends MailerAbstract {
return false;
}
/**
* Process the exception message and append additional explanation to it.
*
* @since 2.1.0
*
* @param mixed $message A string or an object with strings.
*
* @return string
*/
protected function process_exception_message( $message ) {
// Transform the passed message to a string.
if ( ! is_string( $message ) ) {
$message = wp_json_encode( $message );
} else {
$message = wp_strip_all_tags( $message, false );
}
// Define known errors, that we will scan the message with.
$known_errors = array(
array(
'errors' => array(
'invalid_grant',
),
'explanation' => esc_html__( 'Please re-grant Google app permissions!', 'wp-mail-smtp' ) . ' ' . PHP_EOL .
esc_html__( 'Go to WP Mail SMTP plugin settings page. Click the “Remove Connection” button.', 'wp-mail-smtp' ) . ' ' . PHP_EOL .
esc_html__( 'Then click the “Allow plugin to send emails using your Google account” button and re-enable access.', 'wp-mail-smtp' ),
),
);
// Check if we get a match and append the explanation to the original message.
foreach ( $known_errors as $error ) {
foreach ( $error['errors'] as $error_fragment ) {
if ( false !== strpos( $message, $error_fragment ) ) {
return $message . PHP_EOL . $error['explanation'];
}
}
}
// If we get no match we return the original message (as a string).
return $message;
}
/**
* Get the default email addresses for the reply to email parameter.
*
* @deprecated 2.1.1
*
* @since 2.1.0
* @since 2.1.1 Not used anymore.
*
* @return array
*/
public function default_reply_to_addresses() {
_deprecated_function( __CLASS__ . '::' . __METHOD__, '2.1.1 of WP Mail SMTP plugin' );
$gmail_creds = ( new Auth() )->get_user_info();
if ( empty( $gmail_creds['email'] ) ) {
return [];
}
return [
$gmail_creds['email'] => [
$gmail_creds['email'],
'',
],
];
}
}

View File

@ -132,8 +132,8 @@ class Loader {
*
* @since 1.0.0
*
* @param string $provider
* @param MailCatcher $phpmailer
* @param string $provider The provider name.
* @param MailCatcher|\PHPMailer $phpmailer The MailCatcher object.
*
* @return MailerAbstract|null
*/

View File

@ -414,4 +414,54 @@ abstract class MailerAbstract implements MailerInterface {
return implode( '<br>', $smtp_text );
}
/**
* Get the email addresses for the reply to email parameter.
*
* @deprecated 2.1.1
*
* @since 2.1.0
* @since 2.1.1 Not used anymore.
*
* @return array
*/
public function get_reply_to_addresses() {
_deprecated_function( __CLASS__ . '::' . __METHOD__, '2.1.1 of WP Mail SMTP plugin' );
$reply_to = $this->phpmailer->getReplyToAddresses();
// Return the passed reply to addresses, if defined.
if ( ! empty( $reply_to ) ) {
return $reply_to;
}
// Return the default reply to addresses.
return apply_filters(
'wp_mail_smtp_providers_mailer_default_reply_to_addresses',
$this->default_reply_to_addresses()
);
}
/**
* Get the default email addresses for the reply to email parameter.
*
* @deprecated 2.1.1
*
* @since 2.1.0
* @since 2.1.1 Not used anymore.
*
* @return array
*/
public function default_reply_to_addresses() {
_deprecated_function( __CLASS__ . '::' . __METHOD__, '2.1.1 of WP Mail SMTP plugin' );
return [
$this->phpmailer->From => [
$this->phpmailer->From,
$this->phpmailer->FromName,
],
];
}
}

View File

@ -344,20 +344,12 @@ abstract class OptionsAbstract implements OptionsInterface {
id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-pass" spellcheck="false" autocomplete="new-password"
/>
<p class="desc">
<?php esc_html_e( 'The password is stored in plain text. We highly recommend you set up your password in your WordPress configuration file for improved security.', 'wp-mail-smtp' ); ?>
<?php esc_html_e( 'The password will be stored in plain text. For improved security, we highly recommend using your site\'s WordPress configuration file to set your password.', 'wp-mail-smtp' ); ?>
<br>
<?php
printf(
/* translators: %s - wp-config.php. */
esc_html__( 'To do this add the lines below to your %s file:', 'wp-mail-smtp' ),
'<code>wp-config.php</code>'
);
?>
<a href="https://wpmailsmtp.com/docs/how-to-secure-smtp-settings-by-using-constants/" target="_blank" rel="noopener noreferrer">
<strong><?php esc_html_e( 'Learn More', 'wp-mail-smtp' ); ?></strong>
</a>
</p>
<pre>
define( 'WPMS_ON', true );
define( 'WPMS_SMTP_PASS', 'your_password' );
</pre>
<?php endif; ?>
</div>
</div>
@ -440,13 +432,21 @@ abstract class OptionsAbstract implements OptionsInterface {
<blockquote>
<?php
printf(
/* translators: %s - Provider name. */
esc_html__( '%s requires a SSL certificate on a site to work and does not support your current installation. Please contact your host and request a SSL certificate or install a free one, like Let\'s Encrypt.', 'wp-mail-smtp' ),
wp_kses( /* translators: %s - Provider name */
__( '%s requires an SSL certificate, and so is not currently compatible with your site. Please contact your host to request a SSL certificate, or check out <a href="https://www.wpbeginner.com/wp-tutorials/how-to-add-ssl-and-https-in-wordpress/" target="_blank">WPBeginner\'s tutorial on how to set up SSL</a>.', 'wp-mail-smtp' ),
[
'a' => [
'href' => [],
'target' => [],
],
]
),
esc_html( $this->get_title() )
);
?>
<br>
<?php esc_html_e( 'Meanwhile you can switch to some other mailers.', 'wp-mail-smtp' ); ?>
<br>
<?php esc_html_e( 'If you\'d prefer not to set up SSL, or need an SMTP solution in the meantime, please select a different mailer option.', 'wp-mail-smtp' ); ?>
</blockquote>
<?php

View File

@ -38,7 +38,7 @@ class Options extends OptionsAbstract {
$description = sprintf(
wp_kses( /* translators: %s - URL to smtp.com site. */
__( '<strong><a href="%s" target="_blank" rel="noopener noreferrer">SMTP.com</a> is a recommended transactional email service.</strong> With over 22 years of email delivery expertise, SMTP.com has been around for almost as long as email itself. They are known among internet providers as one of the most reliable senders on the internet. Their easy integration process lets you start sending emails in minutes and benefit from years of experience. SMTP.com provides users 10,000 free emails the first 30 days.', 'wp-mail-smtp' ),
__( '<strong><a href="%s" target="_blank" rel="noopener noreferrer">SMTP.com</a> is a recommended transactional email service.</strong> With a 22 years of track record of reliable email delivery, SMTP.com is a premiere solution for WordPress developers and website owners. SMTP.com has been around for almost as long as email itself. Their super simple integration interface makes it easy to get started while a powerful API and robust documentation make it a preferred choice among developers. Start a 30-day free trial with 50,000 emails.', 'wp-mail-smtp' ),
$allowed_kses_html
),
'https://wpmailsmtp.com/go/smtp/'

View File

@ -0,0 +1,527 @@
<?php
namespace WPMailSMTP\Tasks;
/**
* Class Meta helps to manage the tasks meta information
* between Action Scheduler and WP Mail SMTP hooks arguments.
* We can't pass arguments longer than >191 chars in JSON to AS,
* so we need to store them somewhere (and clean from time to time).
*
* @since 2.1.0
*/
class Meta {
/**
* Database table name.
*
* @since 2.1.0
*
* @var string
*/
public $table_name;
/**
* Database version.
*
* @since 2.1.0
*
* @var string
*/
public $version;
/**
* Primary key (unique field) for the database table.
*
* @since 2.1.0
*
* @var string
*/
public $primary_key = 'id';
/**
* Database type identifier.
*
* @since 2.1.0
*
* @var string
*/
public $type = 'tasks_meta';
/**
* Primary class constructor.
*
* @since 2.1.0
*/
public function __construct() {
$this->table_name = self::get_table_name();
}
/**
* Get the DB table name.
*
* @since 2.1.0
*
* @return string
*/
public static function get_table_name() {
global $wpdb;
return $wpdb->prefix . 'wpmailsmtp_tasks_meta';
}
/**
* Get table columns.
*
* @since 2.1.0
*/
public function get_columns() {
return array(
'id' => '%d',
'action' => '%s',
'data' => '%s',
'date' => '%s',
);
}
/**
* Default column values.
*
* @since 2.1.0
*
* @return array
*/
public function get_column_defaults() {
return array(
'action' => '',
'data' => '',
'date' => gmdate( 'Y-m-d H:i:s' ),
);
}
/**
* Retrieve a row from the database based on a given row ID.
*
* @since 2.1.0
*
* @param int $row_id Row ID.
*
* @return null|object
*/
private function get_from_db( $row_id ) {
global $wpdb;
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
return $wpdb->get_row(
$wpdb->prepare(
"SELECT * FROM {$this->table_name} WHERE {$this->primary_key} = %s LIMIT 1;", // phpcs:ignore
$row_id
)
);
}
/**
* Retrieve a row based on column and row ID.
*
* @since 2.1.0
*
* @param string $column Column name.
* @param int|string $row_id Row ID.
*
* @return object|null|bool Database query result, object or null on failure.
*/
public function get_by( $column, $row_id ) {
global $wpdb;
if ( empty( $row_id ) || ! array_key_exists( $column, $this->get_columns() ) ) {
return false;
}
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
return $wpdb->get_row(
$wpdb->prepare(
"SELECT * FROM $this->table_name WHERE $column = '%s' LIMIT 1;", // phpcs:ignore
$row_id
)
);
}
/**
* Retrieve a value based on column name and row ID.
*
* @since 2.1.0
*
* @param string $column Column name.
* @param int|string $row_id Row ID.
*
* @return string|null Database query result (as string), or null on failure.
*/
public function get_column( $column, $row_id ) {
global $wpdb;
if ( empty( $row_id ) || ! array_key_exists( $column, $this->get_columns() ) ) {
return false;
}
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
return $wpdb->get_var(
$wpdb->prepare(
"SELECT $column FROM $this->table_name WHERE $this->primary_key = '%s' LIMIT 1;", // phpcs:ignore
$row_id
)
);
}
/**
* Retrieve one column value based on another given column and matching value.
*
* @since 2.1.0
*
* @param string $column Column name.
* @param string $column_where Column to match against in the WHERE clause.
* @param string $column_value Value to match to the column in the WHERE clause.
*
* @return string|null Database query result (as string), or null on failure.
*/
public function get_column_by( $column, $column_where, $column_value ) {
global $wpdb;
if ( empty( $column ) || empty( $column_where ) || empty( $column_value ) || ! array_key_exists( $column, $this->get_columns() ) ) {
return false;
}
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
return $wpdb->get_var(
$wpdb->prepare(
"SELECT $column FROM $this->table_name WHERE $column_where = %s LIMIT 1;", // phpcs:ignore
$column_value
)
);
}
/**
* Insert a new record into the database.
*
* @since 2.1.0
*
* @param array $data Column data.
* @param string $type Optional. Data type context.
*
* @return int ID for the newly inserted record. 0 otherwise.
*/
private function add_to_db( $data, $type = '' ) {
global $wpdb;
// Set default values.
$data = wp_parse_args( $data, $this->get_column_defaults() );
do_action( 'wp_mail_smtp_pre_insert_' . $type, $data );
// Initialise column format array.
$column_formats = $this->get_columns();
// Force fields to lower case.
$data = array_change_key_case( $data );
// White list columns.
$data = array_intersect_key( $data, $column_formats );
// Reorder $column_formats to match the order of columns given in $data.
$data_keys = array_keys( $data );
$column_formats = array_merge( array_flip( $data_keys ), $column_formats );
$wpdb->insert( $this->table_name, $data, $column_formats );
do_action( 'wp_mail_smtp_post_insert_' . $type, $wpdb->insert_id, $data );
return $wpdb->insert_id;
}
/**
* Update an existing record in the database.
*
* @since 2.1.0
*
* @param int|string $row_id Row ID for the record being updated.
* @param array $data Optional. Array of columns and associated data to update. Default empty array.
* @param string $where Optional. Column to match against in the WHERE clause. If empty, $primary_key
* will be used. Default empty.
* @param string $type Optional. Data type context, e.g. 'affiliate', 'creative', etc. Default empty.
*
* @return bool False if the record could not be updated, true otherwise.
*/
public function update( $row_id, $data = array(), $where = '', $type = '' ) {
global $wpdb;
// Row ID must be a positive integer.
$row_id = absint( $row_id );
if ( empty( $row_id ) ) {
return false;
}
if ( empty( $where ) ) {
$where = $this->primary_key;
}
do_action( 'wp_mail_smtp_pre_update_' . $type, $data );
// Initialise column format array.
$column_formats = $this->get_columns();
// Force fields to lower case.
$data = array_change_key_case( $data );
// White list columns.
$data = array_intersect_key( $data, $column_formats );
// Reorder $column_formats to match the order of columns given in $data.
$data_keys = array_keys( $data );
$column_formats = array_merge( array_flip( $data_keys ), $column_formats );
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
if ( false === $wpdb->update( $this->table_name, $data, array( $where => $row_id ), $column_formats ) ) {
return false;
}
do_action( 'wp_mail_smtp_post_update_' . $type, $data );
return true;
}
/**
* Delete a record from the database.
*
* @since 2.1.0
*
* @param int|string $row_id Row ID.
*
* @return bool False if the record could not be deleted, true otherwise.
*/
public function delete( $row_id = 0 ) {
global $wpdb;
// Row ID must be positive integer.
$row_id = absint( $row_id );
if ( empty( $row_id ) ) {
return false;
}
do_action( 'wp_mail_smtp_pre_delete', $row_id );
do_action( 'wp_mail_smtp_pre_delete_' . $this->type, $row_id );
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
if ( false === $wpdb->query( $wpdb->prepare( "DELETE FROM {$this->table_name} WHERE {$this->primary_key} = %d", $row_id ) ) ) { // phpcs:ignore
return false;
}
do_action( 'wp_mail_smtp_post_delete', $row_id );
do_action( 'wp_mail_smtp_post_delete_' . $this->type, $row_id );
return true;
}
/**
* Delete a record from the database by column.
*
* @since 2.1.0
*
* @param string $column Column name.
* @param int|string $column_value Column value.
*
* @return bool False if the record could not be deleted, true otherwise.
*/
public function delete_by( $column, $column_value ) {
global $wpdb;
if ( empty( $column ) || empty( $column_value ) || ! array_key_exists( $column, $this->get_columns() ) ) {
return false;
}
do_action( 'wp_mail_smtp_pre_delete', $column_value );
do_action( 'wp_mail_smtp_pre_delete_' . $this->type, $column_value );
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
if ( false === $wpdb->query( $wpdb->prepare( "DELETE FROM {$this->table_name} WHERE $column = %s", $column_value ) ) ) { // phpcs:ignore
return false;
}
do_action( 'wp_mail_smtp_post_delete', $column_value );
do_action( 'wp_mail_smtp_post_delete_' . $this->type, $column_value );
return true;
}
/**
* Check if the given table exists.
*
* @since 2.1.0
*
* @param string $table The table name. Defaults to the child class table name.
*
* @return string|null If the table name exists.
*/
public function table_exists( $table = '' ) {
global $wpdb;
if ( ! empty( $table ) ) {
$table = sanitize_text_field( $table );
} else {
$table = $this->table_name;
}
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
return $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) ) === $table;
}
/**
* Create custom entry meta database table.
* Used in migration.
*
* @since 2.1.0
*/
public function create_table() {
global $wpdb;
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
$charset_collate = '';
if ( ! empty( $wpdb->charset ) ) {
$charset_collate .= "DEFAULT CHARACTER SET {$wpdb->charset}";
}
if ( ! empty( $wpdb->collate ) ) {
$charset_collate .= " COLLATE {$wpdb->collate}";
}
$sql = "CREATE TABLE {$this->table_name} (
id bigint(20) NOT NULL AUTO_INCREMENT,
action varchar(255) NOT NULL,
data longtext NOT NULL,
date datetime NOT NULL,
PRIMARY KEY (id)
) {$charset_collate};";
dbDelta( $sql );
}
/**
* Remove queue records for a defined period of time in the past.
* Calling this method will remove queue records that are older than $period seconds.
*
* @since 2.1.0
*
* @param string $action Action that should be cleaned up.
* @param int $interval Number of seconds from now.
*
* @return int Number of removed tasks meta records.
*/
public function clean_by( $action, $interval ) {
global $wpdb;
if ( empty( $action ) || empty( $interval ) ) {
return 0;
}
$table = self::get_table_name();
$action = sanitize_key( $action );
$date = gmdate( 'Y-m-d H:i:s', time() - (int) $interval );
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
return (int) $wpdb->query(
$wpdb->prepare(
"DELETE FROM `$table` WHERE action = %s AND date < %s", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
$action,
$date
)
);
}
/**
* Inserts a new record into the database.
*
* @since 2.1.0
*
* @param array $data Column data.
* @param string $type Optional. Data type context.
*
* @return int ID for the newly inserted record. 0 otherwise.
*/
public function add( $data, $type = '' ) {
if ( empty( $data['action'] ) || ! is_string( $data['action'] ) ) {
return 0;
}
$data['action'] = sanitize_key( $data['action'] );
if ( isset( $data['data'] ) ) {
$string = wp_json_encode( $data['data'] );
if ( $string === false ) {
$string = '';
}
/*
* We are encoding the string representation of all the data
* to make sure that nothing can harm the database.
* This is not an encryption, and we need this data later as is,
* so we are using one of the fastest way to do that.
* This data is removed from DB on a daily basis.
*/
// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
$data['data'] = base64_encode( $string );
}
if ( empty( $type ) ) {
$type = $this->type;
}
return $this->add_to_db( $data, $type );
}
/**
* Retrieve a row from the database based on a given row ID.
*
* @since 2.1.0}
*
* @param int $meta_id Meta ID.
*
* @return null|object
*/
public function get( $meta_id ) {
$meta = $this->get_from_db( $meta_id );
if ( empty( $meta ) || empty( $meta->data ) ) {
return $meta;
}
// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
$decoded = base64_decode( $meta->data );
if ( $decoded === false || ! is_string( $decoded ) ) {
$meta->data = '';
} else {
$meta->data = json_decode( $decoded, true );
}
return $meta;
}
}

View File

@ -0,0 +1,304 @@
<?php
namespace WPMailSMTP\Tasks;
/**
* Class Task.
*
* @since 2.1.0
*/
class Task {
/**
* This task is async (runs asap).
*
* @since 2.1.0
*/
const TYPE_ASYNC = 'async';
/**
* This task is a recurring.
*
* @since 2.1.0
*/
const TYPE_RECURRING = 'scheduled';
/**
* This task is run once.
*
* @since 2.1.0
*/
const TYPE_ONCE = 'once';
/**
* Type of the task.
*
* @since 2.1.0
*
* @var string
*/
private $type;
/**
* Action that will be used as a hook.
*
* @since 2.1.0
*
* @var string
*/
private $action;
/**
* Task meta ID.
*
* @since 2.1.0
*
* @var int
*/
private $meta_id;
/**
* All the params that should be passed to the hook.
*
* @since 2.1.0
*
* @var array
*/
private $params;
/**
* When the first instance of the job will run.
* Used for ONCE ane RECURRING tasks.
*
* @since 2.1.0
*
* @var int
*/
private $timestamp;
/**
* How long to wait between runs.
* Used for RECURRING tasks.
*
* @since 2.1.0
*
* @var int
*/
private $interval;
/**
* Task constructor.
*
* @since 2.1.0
*
* @param string $action Action of the task.
*
* @throws \InvalidArgumentException When action is not a string.
* @throws \UnexpectedValueException When action is empty.
*/
public function __construct( $action ) {
if ( ! is_string( $action ) ) {
throw new \InvalidArgumentException( 'Task action should be a string.' );
}
$this->action = sanitize_key( $action );
if ( empty( $this->action ) ) {
throw new \UnexpectedValueException( 'Task action cannot be empty.' );
}
}
/**
* Define the type of the task as async.
*
* @since 2.1.0
*
* @return Task
*/
public function async() {
$this->type = self::TYPE_ASYNC;
return $this;
}
/**
* Define the type of the task as recurring.
*
* @since 2.1.0
*
* @param int $timestamp When the first instance of the job will run.
* @param int $interval How long to wait between runs.
*
* @return Task
*/
public function recurring( $timestamp, $interval ) {
$this->type = self::TYPE_RECURRING;
$this->timestamp = (int) $timestamp;
$this->interval = (int) $interval;
return $this;
}
/**
* Define the type of the task as one-time.
*
* @since 2.1.0
*
* @param int $timestamp When the first instance of the job will run.
*
* @return Task
*/
public function once( $timestamp ) {
$this->type = self::TYPE_ONCE;
$this->timestamp = (int) $timestamp;
return $this;
}
/**
* Pass any number of params that should be saved to Meta table.
*
* @since 2.1.0
*
* @return Task
*/
public function params() {
$this->params = func_get_args();
return $this;
}
/**
* Register the action.
* Should be the final call in a chain.
*
* @since 2.1.0
*
* @return null|string Action ID.
*/
public function register() {
$action_id = null;
// No processing if ActionScheduler is not usable.
if ( ! wp_mail_smtp()->get_tasks()->is_usable() ) {
return $action_id;
}
// Save data to tasks meta table.
$task_meta = new Meta();
$this->meta_id = $task_meta->add(
[
'action' => $this->action,
'data' => $this->params,
]
);
if ( empty( $this->meta_id ) ) {
return $action_id;
}
switch ( $this->type ) {
case self::TYPE_ASYNC:
$action_id = $this->register_async();
break;
case self::TYPE_RECURRING:
$action_id = $this->register_recurring();
break;
case self::TYPE_ONCE:
$action_id = $this->register_once();
break;
}
return $action_id;
}
/**
* Register the async task.
*
* @since 2.1.0
*
* @return null|string Action ID.
*/
protected function register_async() {
if ( ! function_exists( 'as_enqueue_async_action' ) ) {
return null;
}
return as_enqueue_async_action(
$this->action,
[ 'tasks_meta_id' => $this->meta_id ],
Tasks::GROUP
);
}
/**
* Register the recurring task.
*
* @since 2.1.0
*
* @return null|string Action ID.
*/
protected function register_recurring() {
if ( ! function_exists( 'as_schedule_recurring_action' ) ) {
return null;
}
return as_schedule_recurring_action(
$this->timestamp,
$this->interval,
$this->action,
[ 'tasks_meta_id' => $this->meta_id ],
Tasks::GROUP
);
}
/**
* Register the one-time task.
*
* @since 2.1.0
*
* @return null|string Action ID.
*/
protected function register_once() {
if ( ! function_exists( 'as_schedule_single_action' ) ) {
return null;
}
return as_schedule_single_action(
$this->timestamp,
$this->action,
[ 'tasks_meta_id' => $this->meta_id ],
Tasks::GROUP
);
}
/**
* Cancel all occurrences of this task.
*
* @since 2.1.0
*
* @return null|bool|string Null if no matching action found,
* false if AS library is missing,
* string of the scheduled action ID if a scheduled action was found and unscheduled.
*/
public function cancel() {
// Exit if AS function does not exist.
if ( ! function_exists( 'as_unschedule_all_actions' ) ) {
return false;
}
return as_unschedule_all_actions( $this->action );
}
}

View File

@ -0,0 +1,150 @@
<?php
namespace WPMailSMTP\Tasks;
/**
* Class Tasks manages the tasks queue and provides API to work with it.
*
* @since 2.1.0
*/
class Tasks {
/**
* Group that will be assigned to all actions.
*
* @since 2.1.0
*/
const GROUP = 'wp_mail_smtp';
/**
* Perform certain things on class init.
*
* @since 2.1.0
*/
public function init() {
// Register tasks.
foreach ( $this->get_tasks() as $task ) {
if ( ! is_subclass_of( $task, '\WPMailSMTP\Tasks\Task' ) ) {
continue;
}
$new_task = new $task();
// Run the init method, if a task has one defined.
if ( method_exists( $new_task, 'init' ) ) {
$new_task->init();
}
}
add_action( 'admin_menu', array( $this, 'admin_hide_as_menu' ), PHP_INT_MAX );
}
/**
* Get the list of default scheduled tasks.
* Tasks, that are fired under certain specific circumstances
* (like sending emails) are not listed here.
*
* @since 2.1.0
*
* @return Task[] List of tasks classes.
*/
public function get_tasks() {
return apply_filters( 'wp_mail_smtp_tasks_get_tasks', array() );
}
/**
* Hide Action Scheduler admin area when not in debug mode.
*
* @since 2.1.0
*/
public function admin_hide_as_menu() {
// Filter to redefine that WP Mail SMTP hides Tools > Action Scheduler menu item.
if ( apply_filters( 'wp_mail_smtp_tasks_admin_hide_as_menu', true ) ) {
remove_submenu_page( 'tools.php', 'action-scheduler' );
}
}
/**
* Create a new task.
* Used for "inline" tasks, that require additional information
* from the plugin runtime before they can be scheduled.
*
* Example:
* wp_mail_smtp()->get( 'tasks' )
* ->create( 'i_am_the_dude' )
* ->async()
* ->params( 'The Big Lebowski', 1998 )
* ->register();
*
* This `i_am_the_dude` action will be later processed as:
* add_action( 'i_am_the_dude', 'thats_what_you_call_me' );
*
* @since 2.1.0
*
* @param string $action Action that will be used as a hook.
*
* @return \WPMailSMTP\Tasks\Task
*/
public function create( $action ) {
return new Task( $action );
}
/**
* Cancel all the AS actions for a group.
*
* @since 2.1.0
*
* @param string $group Group to cancel all actions for.
*/
public function cancel_all( $group = '' ) {
if ( empty( $group ) ) {
$group = self::GROUP;
} else {
$group = sanitize_key( $group );
}
if ( class_exists( 'ActionScheduler_DBStore' ) ) {
\ActionScheduler_DBStore::instance()->cancel_actions_by_group( $group );
}
}
/**
* Whether ActionScheduler thinks that it has migrated or not.
*
* @since 2.1.0
*
* @return bool
*/
public function is_usable() {
// No tasks if ActionScheduler wasn't loaded.
if ( ! class_exists( 'ActionScheduler_DataController' ) ) {
return false;
}
return \ActionScheduler_DataController::is_migration_complete();
}
/**
* Whether task has been scheduled and is pending.
*
* @since 2.1.0
*
* @param string $hook Hook to check for.
*
* @return bool
*/
public function is_scheduled( $hook ) {
if ( ! function_exists( 'as_next_scheduled_action' ) ) {
return false;
}
return as_next_scheduled_action( $hook );
}
}

View File

@ -18,24 +18,32 @@ class WP {
*/
protected static $admin_notices = array();
/**
* CSS class for a success notice.
*
* @since 1.0.0
*
* @var string
*/
const ADMIN_NOTICE_SUCCESS = 'notice-success';
/**
* CSS class for an error notice.
*
* @since 1.0.0
*
* @var string
*/
const ADMIN_NOTICE_ERROR = 'notice-error';
/**
* CSS class for an info notice.
*
* @since 1.0.0
*
* @var string
*/
const ADMIN_NOTICE_INFO = 'notice-info';
/**
* CSS class for a warning notice.
*
* @since 1.0.0
*
* @var string
@ -43,7 +51,7 @@ class WP {
const ADMIN_NOTICE_WARNING = 'notice-warning';
/**
* True is WP is processing an AJAX call.
* True if WP is processing an AJAX call.
*
* @since 1.0.0
*
@ -103,7 +111,7 @@ class WP {
<div class="notice wp-mail-smtp-notice <?php echo esc_attr( $notice['class'] ); ?> notice <?php echo esc_attr( $dismissible ); ?>">
<p>
<?php echo $notice['message']; ?>
<?php echo wp_kses_post( $notice['message'] ); ?>
</p>
</div>
@ -160,7 +168,7 @@ class WP {
*
* @since 1.5.0
*
* @param string $string
* @param string $string String we want to test if it's json.
*
* @return bool
*/
@ -178,8 +186,7 @@ class WP {
*/
public static function datetime_format() {
return sprintf(
/* translators: %1$s - date, \a\t - specially escaped "at", %2$s - time. */
return sprintf( /* translators: %1$s - date, \a\t - specially escaped "at", %2$s - time. */
esc_html__( '%1$s \a\t %2$s', 'wp-mail-smtp' ),
get_option( 'date_format' ),
get_option( 'time_format' )
@ -199,14 +206,14 @@ class WP {
}
/**
* Sanitize the value, similar to sanitize_text_field(), but a bit differently.
* Sanitize the value, similar to `sanitize_text_field()`, but a bit differently.
* It preserves `<` and `>` for non-HTML tags.
*
* @since 1.5.0
*
* @param string $value
* @param string $value String we want to sanitize.
*
* @return mixed|string|string[]|null
* @return string
*/
public static function sanitize_value( $value ) {

View File

@ -1,80 +1,99 @@
<?php
/**
* Uninstall all WP Mail SMTP data.
*
* @since 1.3.0
*/
// Exit if accessed directly.
if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
exit;
}
// Load plugin file.
require_once 'wp_mail_smtp.php';
// Confirm user has decided to remove all data, otherwise stop.
$settings = get_option( 'wp_mail_smtp', array() );
if ( empty( $settings['general']['uninstall'] ) ) {
return;
}
/*
* Remove options.
*/
$options = array(
'wp_mail_smtp_initial_version',
'wp_mail_smtp_version',
'wp_mail_smtp_debug',
'wp_mail_smtp',
'_amn_smtp_last_checked',
// Legacy options.
'pepipost_ssl',
'pepipost_port',
'pepipost_pass',
'pepipost_user',
'smtp_pass',
'smtp_user',
'smtp_auth',
'smtp_ssl',
'smtp_port',
'smtp_host',
'mail_set_return_path',
'mailer',
'mail_from_name',
'mail_from',
'wp_mail_smtp_am_notifications_hidden',
);
foreach ( $options as $option ) {
delete_option( $option );
}
/*
* Remove product announcements.
*/
$announcements = get_posts(
array(
'post_type' => array( 'amn_smtp' ),
'post_status' => 'any',
'numberposts' => - 1,
'fields' => 'ids',
)
);
if ( ! empty( $announcements ) ) {
foreach ( $announcements as $announcement ) {
wp_delete_post( $announcement, true );
}
}
/*
* Logs for Pro plugin only.
*/
if ( function_exists( 'wp_mail_smtp' ) && wp_mail_smtp()->is_pro() ) {
// DB version.
delete_option( 'wp_mail_smtp_logs_db_version' );
// DB table.
global $wpdb;
$table = \WPMailSMTP\Pro\Emails\Logs\Logs::get_table_name();
$wpdb->query( "DROP TABLE $table;" ); // phpcs:ignore
}
<?php
/**
* Uninstall all WP Mail SMTP data.
*
* @since 1.3.0
*/
// Exit if accessed directly.
if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
exit;
}
// Load plugin file.
require_once 'wp_mail_smtp.php';
// Confirm user has decided to remove all data, otherwise stop.
$settings = get_option( 'wp_mail_smtp', array() );
if ( empty( $settings['general']['uninstall'] ) ) {
return;
}
/*
* Remove Legacy options.
*/
$options = array(
'_amn_smtp_last_checked',
'pepipost_ssl',
'pepipost_port',
'pepipost_pass',
'pepipost_user',
'smtp_pass',
'smtp_user',
'smtp_auth',
'smtp_ssl',
'smtp_port',
'smtp_host',
'mail_set_return_path',
'mailer',
'mail_from_name',
'mail_from',
);
foreach ( $options as $option ) {
delete_option( $option );
}
global $wpdb;
// Delete plugin settings.
$wpdb->query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE 'wp\_mail\_smtp%'" );
// Delete plugin user meta.
$wpdb->query( "DELETE FROM {$wpdb->usermeta} WHERE meta_key LIKE 'wp\_mail\_smtp\_%'" );
// Remove any transients we've left behind.
$wpdb->query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE '\_transient\_wp\_mail\_smtp\_%'" );
$wpdb->query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE '\_site\_transient\_wp\_mail\_smtp\_%'" );
$wpdb->query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE '\_transient\_timeout\_wp\_mail\_smtp\_%'" );
$wpdb->query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE '\_site\_transient\_timeout\_wp\_mail\_smtp\_%'" );
/*
* Remove product announcements.
*/
$announcements = get_posts(
array(
'post_type' => array( 'amn_smtp' ),
'post_status' => 'any',
'numberposts' => - 1,
'fields' => 'ids',
)
);
if ( ! empty( $announcements ) ) {
foreach ( $announcements as $announcement ) {
wp_delete_post( $announcement, true );
}
}
/*
* Logs for Pro plugin only.
*/
if (
function_exists( 'wp_mail_smtp' ) &&
is_readable( wp_mail_smtp()->plugin_path . '/src/Pro/Pro.php' )
) {
// DB table.
$logs_table = \WPMailSMTP\Pro\Emails\Logs\Logs::get_table_name();
$wpdb->query( "DROP TABLE IF EXISTS $logs_table;" ); // phpcs:ignore WordPress.DB
}
/*
* Drop all Action Scheduler data.
*/
require_once dirname( __FILE__ ) . '/vendor/woocommerce/action-scheduler/action-scheduler.php';
// Unschedule all plugin ActionScheduler actions.
( new \WPMailSMTP\Tasks\Tasks() )->cancel_all();
$meta_table = \WPMailSMTP\Tasks\Meta::get_table_name();
$wpdb->query( "DROP TABLE IF EXISTS $meta_table;" ); // phpcs:ignore WordPress.DB

View File

@ -9,6 +9,9 @@ return array(
'7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php',
'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
'25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php',
'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
'decc78cc4436b1292c6c0d151b19445c' => $vendorDir . '/phpseclib/phpseclib/phpseclib/bootstrap.php',
);

View File

@ -8,6 +8,9 @@ $baseDir = dirname($vendorDir);
return array(
'phpseclib\\' => array($vendorDir . '/phpseclib/phpseclib/phpseclib'),
'WPMailSMTP\\' => array($baseDir . '/src'),
'Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'),
'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
'Symfony\\Polyfill\\Intl\\Idn\\' => array($vendorDir . '/symfony/polyfill-intl-idn'),
'SendinBlue\\Client\\' => array($vendorDir . '/sendinblue/api-v3-sdk/lib'),
'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'),

View File

@ -10,6 +10,9 @@ class ComposerStaticInit72f613a3d0c2cc77892490951b6e5352
'7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php',
'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
'25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php',
'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
'decc78cc4436b1292c6c0d151b19445c' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/bootstrap.php',
);
@ -25,6 +28,9 @@ class ComposerStaticInit72f613a3d0c2cc77892490951b6e5352
),
'S' =>
array (
'Symfony\\Polyfill\\Php72\\' => 23,
'Symfony\\Polyfill\\Mbstring\\' => 26,
'Symfony\\Polyfill\\Intl\\Idn\\' => 26,
'SendinBlue\\Client\\' => 18,
),
'P' =>
@ -63,6 +69,18 @@ class ComposerStaticInit72f613a3d0c2cc77892490951b6e5352
array (
0 => __DIR__ . '/../..' . '/src',
),
'Symfony\\Polyfill\\Php72\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php72',
),
'Symfony\\Polyfill\\Mbstring\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
),
'Symfony\\Polyfill\\Intl\\Idn\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-intl-idn',
),
'SendinBlue\\Client\\' =>
array (
0 => __DIR__ . '/..' . '/sendinblue/api-v3-sdk/lib',

View File

@ -19,8 +19,7 @@
* Service definition for Gmail (v1).
*
* <p>
* The Gmail API lets you view and manage Gmail mailbox data like threads,
* messages, and labels.</p>
* Access Gmail mailboxes including sending user email.</p>
*
* <p>
* For more information about this service, see the API
@ -98,8 +97,8 @@ class Google_Service_Gmail extends Google_Service
{
parent::__construct($client);
$this->rootUrl = $rootUrl ?: 'https://www.googleapis.com/';
$this->servicePath = '';
$this->batchPath = 'batch';
$this->servicePath = 'gmail/v1/users/';
$this->batchPath = 'batch/gmail/v1';
$this->version = 'v1';
$this->serviceName = 'gmail';
@ -110,7 +109,7 @@ class Google_Service_Gmail extends Google_Service
array(
'methods' => array(
'getProfile' => array(
'path' => 'gmail/v1/users/{userId}/profile',
'path' => '{userId}/profile',
'httpMethod' => 'GET',
'parameters' => array(
'userId' => array(
@ -120,7 +119,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'stop' => array(
'path' => 'gmail/v1/users/{userId}/stop',
'path' => '{userId}/stop',
'httpMethod' => 'POST',
'parameters' => array(
'userId' => array(
@ -130,7 +129,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'watch' => array(
'path' => 'gmail/v1/users/{userId}/watch',
'path' => '{userId}/watch',
'httpMethod' => 'POST',
'parameters' => array(
'userId' => array(
@ -150,7 +149,7 @@ class Google_Service_Gmail extends Google_Service
array(
'methods' => array(
'create' => array(
'path' => 'gmail/v1/users/{userId}/drafts',
'path' => '{userId}/drafts',
'httpMethod' => 'POST',
'parameters' => array(
'userId' => array(
@ -160,7 +159,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'delete' => array(
'path' => 'gmail/v1/users/{userId}/drafts/{id}',
'path' => '{userId}/drafts/{id}',
'httpMethod' => 'DELETE',
'parameters' => array(
'userId' => array(
@ -175,7 +174,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'get' => array(
'path' => 'gmail/v1/users/{userId}/drafts/{id}',
'path' => '{userId}/drafts/{id}',
'httpMethod' => 'GET',
'parameters' => array(
'userId' => array(
@ -194,7 +193,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'list' => array(
'path' => 'gmail/v1/users/{userId}/drafts',
'path' => '{userId}/drafts',
'httpMethod' => 'GET',
'parameters' => array(
'userId' => array(
@ -206,6 +205,10 @@ class Google_Service_Gmail extends Google_Service
'location' => 'query',
'type' => 'boolean',
),
'maxResults' => array(
'location' => 'query',
'type' => 'integer',
),
'pageToken' => array(
'location' => 'query',
'type' => 'string',
@ -214,13 +217,9 @@ class Google_Service_Gmail extends Google_Service
'location' => 'query',
'type' => 'string',
),
'maxResults' => array(
'location' => 'query',
'type' => 'integer',
),
),
),'send' => array(
'path' => 'gmail/v1/users/{userId}/drafts/send',
'path' => '{userId}/drafts/send',
'httpMethod' => 'POST',
'parameters' => array(
'userId' => array(
@ -230,7 +229,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'update' => array(
'path' => 'gmail/v1/users/{userId}/drafts/{id}',
'path' => '{userId}/drafts/{id}',
'httpMethod' => 'PUT',
'parameters' => array(
'userId' => array(
@ -255,7 +254,7 @@ class Google_Service_Gmail extends Google_Service
array(
'methods' => array(
'list' => array(
'path' => 'gmail/v1/users/{userId}/history',
'path' => '{userId}/history',
'httpMethod' => 'GET',
'parameters' => array(
'userId' => array(
@ -263,9 +262,10 @@ class Google_Service_Gmail extends Google_Service
'type' => 'string',
'required' => true,
),
'pageToken' => array(
'historyTypes' => array(
'location' => 'query',
'type' => 'string',
'repeated' => true,
),
'labelId' => array(
'location' => 'query',
@ -275,10 +275,9 @@ class Google_Service_Gmail extends Google_Service
'location' => 'query',
'type' => 'integer',
),
'historyTypes' => array(
'pageToken' => array(
'location' => 'query',
'type' => 'string',
'repeated' => true,
),
'startHistoryId' => array(
'location' => 'query',
@ -296,7 +295,7 @@ class Google_Service_Gmail extends Google_Service
array(
'methods' => array(
'create' => array(
'path' => 'gmail/v1/users/{userId}/labels',
'path' => '{userId}/labels',
'httpMethod' => 'POST',
'parameters' => array(
'userId' => array(
@ -306,7 +305,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'delete' => array(
'path' => 'gmail/v1/users/{userId}/labels/{id}',
'path' => '{userId}/labels/{id}',
'httpMethod' => 'DELETE',
'parameters' => array(
'userId' => array(
@ -321,7 +320,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'get' => array(
'path' => 'gmail/v1/users/{userId}/labels/{id}',
'path' => '{userId}/labels/{id}',
'httpMethod' => 'GET',
'parameters' => array(
'userId' => array(
@ -336,7 +335,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'list' => array(
'path' => 'gmail/v1/users/{userId}/labels',
'path' => '{userId}/labels',
'httpMethod' => 'GET',
'parameters' => array(
'userId' => array(
@ -346,7 +345,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'patch' => array(
'path' => 'gmail/v1/users/{userId}/labels/{id}',
'path' => '{userId}/labels/{id}',
'httpMethod' => 'PATCH',
'parameters' => array(
'userId' => array(
@ -361,7 +360,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'update' => array(
'path' => 'gmail/v1/users/{userId}/labels/{id}',
'path' => '{userId}/labels/{id}',
'httpMethod' => 'PUT',
'parameters' => array(
'userId' => array(
@ -386,7 +385,7 @@ class Google_Service_Gmail extends Google_Service
array(
'methods' => array(
'batchDelete' => array(
'path' => 'gmail/v1/users/{userId}/messages/batchDelete',
'path' => '{userId}/messages/batchDelete',
'httpMethod' => 'POST',
'parameters' => array(
'userId' => array(
@ -396,7 +395,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'batchModify' => array(
'path' => 'gmail/v1/users/{userId}/messages/batchModify',
'path' => '{userId}/messages/batchModify',
'httpMethod' => 'POST',
'parameters' => array(
'userId' => array(
@ -406,7 +405,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'delete' => array(
'path' => 'gmail/v1/users/{userId}/messages/{id}',
'path' => '{userId}/messages/{id}',
'httpMethod' => 'DELETE',
'parameters' => array(
'userId' => array(
@ -421,7 +420,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'get' => array(
'path' => 'gmail/v1/users/{userId}/messages/{id}',
'path' => '{userId}/messages/{id}',
'httpMethod' => 'GET',
'parameters' => array(
'userId' => array(
@ -434,18 +433,18 @@ class Google_Service_Gmail extends Google_Service
'type' => 'string',
'required' => true,
),
'format' => array(
'location' => 'query',
'type' => 'string',
),
'metadataHeaders' => array(
'location' => 'query',
'type' => 'string',
'repeated' => true,
),
'format' => array(
'location' => 'query',
'type' => 'string',
),
),
),'import' => array(
'path' => 'gmail/v1/users/{userId}/messages/import',
'path' => '{userId}/messages/import',
'httpMethod' => 'POST',
'parameters' => array(
'userId' => array(
@ -453,7 +452,7 @@ class Google_Service_Gmail extends Google_Service
'type' => 'string',
'required' => true,
),
'processForCalendar' => array(
'deleted' => array(
'location' => 'query',
'type' => 'boolean',
),
@ -465,13 +464,13 @@ class Google_Service_Gmail extends Google_Service
'location' => 'query',
'type' => 'boolean',
),
'deleted' => array(
'processForCalendar' => array(
'location' => 'query',
'type' => 'boolean',
),
),
),'insert' => array(
'path' => 'gmail/v1/users/{userId}/messages',
'path' => '{userId}/messages',
'httpMethod' => 'POST',
'parameters' => array(
'userId' => array(
@ -479,17 +478,17 @@ class Google_Service_Gmail extends Google_Service
'type' => 'string',
'required' => true,
),
'internalDateSource' => array(
'location' => 'query',
'type' => 'string',
),
'deleted' => array(
'location' => 'query',
'type' => 'boolean',
),
'internalDateSource' => array(
'location' => 'query',
'type' => 'string',
),
),
),'list' => array(
'path' => 'gmail/v1/users/{userId}/messages',
'path' => '{userId}/messages',
'httpMethod' => 'GET',
'parameters' => array(
'userId' => array(
@ -501,26 +500,26 @@ class Google_Service_Gmail extends Google_Service
'location' => 'query',
'type' => 'boolean',
),
'pageToken' => array(
'location' => 'query',
'type' => 'string',
),
'labelIds' => array(
'location' => 'query',
'type' => 'string',
'repeated' => true,
),
'q' => array(
'location' => 'query',
'type' => 'string',
),
'maxResults' => array(
'location' => 'query',
'type' => 'integer',
),
'pageToken' => array(
'location' => 'query',
'type' => 'string',
),
'q' => array(
'location' => 'query',
'type' => 'string',
),
),
),'modify' => array(
'path' => 'gmail/v1/users/{userId}/messages/{id}/modify',
'path' => '{userId}/messages/{id}/modify',
'httpMethod' => 'POST',
'parameters' => array(
'userId' => array(
@ -535,7 +534,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'send' => array(
'path' => 'gmail/v1/users/{userId}/messages/send',
'path' => '{userId}/messages/send',
'httpMethod' => 'POST',
'parameters' => array(
'userId' => array(
@ -545,7 +544,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'trash' => array(
'path' => 'gmail/v1/users/{userId}/messages/{id}/trash',
'path' => '{userId}/messages/{id}/trash',
'httpMethod' => 'POST',
'parameters' => array(
'userId' => array(
@ -560,7 +559,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'untrash' => array(
'path' => 'gmail/v1/users/{userId}/messages/{id}/untrash',
'path' => '{userId}/messages/{id}/untrash',
'httpMethod' => 'POST',
'parameters' => array(
'userId' => array(
@ -585,7 +584,7 @@ class Google_Service_Gmail extends Google_Service
array(
'methods' => array(
'get' => array(
'path' => 'gmail/v1/users/{userId}/messages/{messageId}/attachments/{id}',
'path' => '{userId}/messages/{messageId}/attachments/{id}',
'httpMethod' => 'GET',
'parameters' => array(
'userId' => array(
@ -615,7 +614,7 @@ class Google_Service_Gmail extends Google_Service
array(
'methods' => array(
'getAutoForwarding' => array(
'path' => 'gmail/v1/users/{userId}/settings/autoForwarding',
'path' => '{userId}/settings/autoForwarding',
'httpMethod' => 'GET',
'parameters' => array(
'userId' => array(
@ -625,7 +624,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'getImap' => array(
'path' => 'gmail/v1/users/{userId}/settings/imap',
'path' => '{userId}/settings/imap',
'httpMethod' => 'GET',
'parameters' => array(
'userId' => array(
@ -635,7 +634,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'getLanguage' => array(
'path' => 'gmail/v1/users/{userId}/settings/language',
'path' => '{userId}/settings/language',
'httpMethod' => 'GET',
'parameters' => array(
'userId' => array(
@ -645,7 +644,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'getPop' => array(
'path' => 'gmail/v1/users/{userId}/settings/pop',
'path' => '{userId}/settings/pop',
'httpMethod' => 'GET',
'parameters' => array(
'userId' => array(
@ -655,7 +654,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'getVacation' => array(
'path' => 'gmail/v1/users/{userId}/settings/vacation',
'path' => '{userId}/settings/vacation',
'httpMethod' => 'GET',
'parameters' => array(
'userId' => array(
@ -665,7 +664,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'updateAutoForwarding' => array(
'path' => 'gmail/v1/users/{userId}/settings/autoForwarding',
'path' => '{userId}/settings/autoForwarding',
'httpMethod' => 'PUT',
'parameters' => array(
'userId' => array(
@ -675,7 +674,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'updateImap' => array(
'path' => 'gmail/v1/users/{userId}/settings/imap',
'path' => '{userId}/settings/imap',
'httpMethod' => 'PUT',
'parameters' => array(
'userId' => array(
@ -685,7 +684,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'updateLanguage' => array(
'path' => 'gmail/v1/users/{userId}/settings/language',
'path' => '{userId}/settings/language',
'httpMethod' => 'PUT',
'parameters' => array(
'userId' => array(
@ -695,7 +694,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'updatePop' => array(
'path' => 'gmail/v1/users/{userId}/settings/pop',
'path' => '{userId}/settings/pop',
'httpMethod' => 'PUT',
'parameters' => array(
'userId' => array(
@ -705,7 +704,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'updateVacation' => array(
'path' => 'gmail/v1/users/{userId}/settings/vacation',
'path' => '{userId}/settings/vacation',
'httpMethod' => 'PUT',
'parameters' => array(
'userId' => array(
@ -725,7 +724,7 @@ class Google_Service_Gmail extends Google_Service
array(
'methods' => array(
'create' => array(
'path' => 'gmail/v1/users/{userId}/settings/delegates',
'path' => '{userId}/settings/delegates',
'httpMethod' => 'POST',
'parameters' => array(
'userId' => array(
@ -735,7 +734,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'delete' => array(
'path' => 'gmail/v1/users/{userId}/settings/delegates/{delegateEmail}',
'path' => '{userId}/settings/delegates/{delegateEmail}',
'httpMethod' => 'DELETE',
'parameters' => array(
'userId' => array(
@ -750,7 +749,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'get' => array(
'path' => 'gmail/v1/users/{userId}/settings/delegates/{delegateEmail}',
'path' => '{userId}/settings/delegates/{delegateEmail}',
'httpMethod' => 'GET',
'parameters' => array(
'userId' => array(
@ -765,7 +764,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'list' => array(
'path' => 'gmail/v1/users/{userId}/settings/delegates',
'path' => '{userId}/settings/delegates',
'httpMethod' => 'GET',
'parameters' => array(
'userId' => array(
@ -785,7 +784,7 @@ class Google_Service_Gmail extends Google_Service
array(
'methods' => array(
'create' => array(
'path' => 'gmail/v1/users/{userId}/settings/filters',
'path' => '{userId}/settings/filters',
'httpMethod' => 'POST',
'parameters' => array(
'userId' => array(
@ -795,7 +794,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'delete' => array(
'path' => 'gmail/v1/users/{userId}/settings/filters/{id}',
'path' => '{userId}/settings/filters/{id}',
'httpMethod' => 'DELETE',
'parameters' => array(
'userId' => array(
@ -810,7 +809,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'get' => array(
'path' => 'gmail/v1/users/{userId}/settings/filters/{id}',
'path' => '{userId}/settings/filters/{id}',
'httpMethod' => 'GET',
'parameters' => array(
'userId' => array(
@ -825,7 +824,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'list' => array(
'path' => 'gmail/v1/users/{userId}/settings/filters',
'path' => '{userId}/settings/filters',
'httpMethod' => 'GET',
'parameters' => array(
'userId' => array(
@ -845,7 +844,7 @@ class Google_Service_Gmail extends Google_Service
array(
'methods' => array(
'create' => array(
'path' => 'gmail/v1/users/{userId}/settings/forwardingAddresses',
'path' => '{userId}/settings/forwardingAddresses',
'httpMethod' => 'POST',
'parameters' => array(
'userId' => array(
@ -855,7 +854,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'delete' => array(
'path' => 'gmail/v1/users/{userId}/settings/forwardingAddresses/{forwardingEmail}',
'path' => '{userId}/settings/forwardingAddresses/{forwardingEmail}',
'httpMethod' => 'DELETE',
'parameters' => array(
'userId' => array(
@ -870,7 +869,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'get' => array(
'path' => 'gmail/v1/users/{userId}/settings/forwardingAddresses/{forwardingEmail}',
'path' => '{userId}/settings/forwardingAddresses/{forwardingEmail}',
'httpMethod' => 'GET',
'parameters' => array(
'userId' => array(
@ -885,7 +884,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'list' => array(
'path' => 'gmail/v1/users/{userId}/settings/forwardingAddresses',
'path' => '{userId}/settings/forwardingAddresses',
'httpMethod' => 'GET',
'parameters' => array(
'userId' => array(
@ -905,7 +904,7 @@ class Google_Service_Gmail extends Google_Service
array(
'methods' => array(
'create' => array(
'path' => 'gmail/v1/users/{userId}/settings/sendAs',
'path' => '{userId}/settings/sendAs',
'httpMethod' => 'POST',
'parameters' => array(
'userId' => array(
@ -915,7 +914,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'delete' => array(
'path' => 'gmail/v1/users/{userId}/settings/sendAs/{sendAsEmail}',
'path' => '{userId}/settings/sendAs/{sendAsEmail}',
'httpMethod' => 'DELETE',
'parameters' => array(
'userId' => array(
@ -930,7 +929,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'get' => array(
'path' => 'gmail/v1/users/{userId}/settings/sendAs/{sendAsEmail}',
'path' => '{userId}/settings/sendAs/{sendAsEmail}',
'httpMethod' => 'GET',
'parameters' => array(
'userId' => array(
@ -945,7 +944,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'list' => array(
'path' => 'gmail/v1/users/{userId}/settings/sendAs',
'path' => '{userId}/settings/sendAs',
'httpMethod' => 'GET',
'parameters' => array(
'userId' => array(
@ -955,7 +954,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'patch' => array(
'path' => 'gmail/v1/users/{userId}/settings/sendAs/{sendAsEmail}',
'path' => '{userId}/settings/sendAs/{sendAsEmail}',
'httpMethod' => 'PATCH',
'parameters' => array(
'userId' => array(
@ -970,7 +969,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'update' => array(
'path' => 'gmail/v1/users/{userId}/settings/sendAs/{sendAsEmail}',
'path' => '{userId}/settings/sendAs/{sendAsEmail}',
'httpMethod' => 'PUT',
'parameters' => array(
'userId' => array(
@ -985,7 +984,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'verify' => array(
'path' => 'gmail/v1/users/{userId}/settings/sendAs/{sendAsEmail}/verify',
'path' => '{userId}/settings/sendAs/{sendAsEmail}/verify',
'httpMethod' => 'POST',
'parameters' => array(
'userId' => array(
@ -1010,7 +1009,7 @@ class Google_Service_Gmail extends Google_Service
array(
'methods' => array(
'delete' => array(
'path' => 'gmail/v1/users/{userId}/settings/sendAs/{sendAsEmail}/smimeInfo/{id}',
'path' => '{userId}/settings/sendAs/{sendAsEmail}/smimeInfo/{id}',
'httpMethod' => 'DELETE',
'parameters' => array(
'userId' => array(
@ -1030,7 +1029,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'get' => array(
'path' => 'gmail/v1/users/{userId}/settings/sendAs/{sendAsEmail}/smimeInfo/{id}',
'path' => '{userId}/settings/sendAs/{sendAsEmail}/smimeInfo/{id}',
'httpMethod' => 'GET',
'parameters' => array(
'userId' => array(
@ -1050,7 +1049,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'insert' => array(
'path' => 'gmail/v1/users/{userId}/settings/sendAs/{sendAsEmail}/smimeInfo',
'path' => '{userId}/settings/sendAs/{sendAsEmail}/smimeInfo',
'httpMethod' => 'POST',
'parameters' => array(
'userId' => array(
@ -1065,7 +1064,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'list' => array(
'path' => 'gmail/v1/users/{userId}/settings/sendAs/{sendAsEmail}/smimeInfo',
'path' => '{userId}/settings/sendAs/{sendAsEmail}/smimeInfo',
'httpMethod' => 'GET',
'parameters' => array(
'userId' => array(
@ -1080,7 +1079,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'setDefault' => array(
'path' => 'gmail/v1/users/{userId}/settings/sendAs/{sendAsEmail}/smimeInfo/{id}/setDefault',
'path' => '{userId}/settings/sendAs/{sendAsEmail}/smimeInfo/{id}/setDefault',
'httpMethod' => 'POST',
'parameters' => array(
'userId' => array(
@ -1110,7 +1109,7 @@ class Google_Service_Gmail extends Google_Service
array(
'methods' => array(
'delete' => array(
'path' => 'gmail/v1/users/{userId}/threads/{id}',
'path' => '{userId}/threads/{id}',
'httpMethod' => 'DELETE',
'parameters' => array(
'userId' => array(
@ -1125,7 +1124,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'get' => array(
'path' => 'gmail/v1/users/{userId}/threads/{id}',
'path' => '{userId}/threads/{id}',
'httpMethod' => 'GET',
'parameters' => array(
'userId' => array(
@ -1138,18 +1137,18 @@ class Google_Service_Gmail extends Google_Service
'type' => 'string',
'required' => true,
),
'format' => array(
'location' => 'query',
'type' => 'string',
),
'metadataHeaders' => array(
'location' => 'query',
'type' => 'string',
'repeated' => true,
),
'format' => array(
'location' => 'query',
'type' => 'string',
),
),
),'list' => array(
'path' => 'gmail/v1/users/{userId}/threads',
'path' => '{userId}/threads',
'httpMethod' => 'GET',
'parameters' => array(
'userId' => array(
@ -1157,30 +1156,30 @@ class Google_Service_Gmail extends Google_Service
'type' => 'string',
'required' => true,
),
'pageToken' => array(
'includeSpamTrash' => array(
'location' => 'query',
'type' => 'string',
'type' => 'boolean',
),
'labelIds' => array(
'location' => 'query',
'type' => 'string',
'repeated' => true,
),
'q' => array(
'location' => 'query',
'type' => 'string',
),
'maxResults' => array(
'location' => 'query',
'type' => 'integer',
),
'includeSpamTrash' => array(
'pageToken' => array(
'location' => 'query',
'type' => 'boolean',
'type' => 'string',
),
'q' => array(
'location' => 'query',
'type' => 'string',
),
),
),'modify' => array(
'path' => 'gmail/v1/users/{userId}/threads/{id}/modify',
'path' => '{userId}/threads/{id}/modify',
'httpMethod' => 'POST',
'parameters' => array(
'userId' => array(
@ -1195,7 +1194,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'trash' => array(
'path' => 'gmail/v1/users/{userId}/threads/{id}/trash',
'path' => '{userId}/threads/{id}/trash',
'httpMethod' => 'POST',
'parameters' => array(
'userId' => array(
@ -1210,7 +1209,7 @@ class Google_Service_Gmail extends Google_Service
),
),
),'untrash' => array(
'path' => 'gmail/v1/users/{userId}/threads/{id}/untrash',
'path' => '{userId}/threads/{id}/untrash',
'httpMethod' => 'POST',
'parameters' => array(
'userId' => array(

View File

@ -81,12 +81,12 @@ class Google_Service_Gmail_Resource_UsersDrafts extends Google_Service_Resource
*
* @opt_param bool includeSpamTrash Include drafts from SPAM and TRASH in the
* results.
* @opt_param string maxResults Maximum number of drafts to return.
* @opt_param string pageToken Page token to retrieve a specific page of results
* in the list.
* @opt_param string q Only return draft messages matching the specified query.
* Supports the same query format as the Gmail search box. For example,
* "from:someuser@example.com rfc822msgid: is:unread".
* @opt_param string maxResults Maximum number of drafts to return.
* @return Google_Service_Gmail_ListDraftsResponse
*/
public function listUsersDrafts($userId, $optParams = array())

View File

@ -34,11 +34,11 @@ class Google_Service_Gmail_Resource_UsersHistory extends Google_Service_Resource
* used to indicate the authenticated user.
* @param array $optParams Optional parameters.
*
* @opt_param string pageToken Page token to retrieve a specific page of results
* in the list.
* @opt_param string historyTypes History types to be returned by the function
* @opt_param string labelId Only return messages with a label matching the ID.
* @opt_param string maxResults The maximum number of history records to return.
* @opt_param string historyTypes History types to be returned by the function
* @opt_param string pageToken Page token to retrieve a specific page of results
* in the list.
* @opt_param string startHistoryId Required. Returns history records after the
* specified startHistoryId. The supplied startHistoryId should be obtained from
* the historyId of a message, thread, or previous list response. History IDs
@ -46,7 +46,7 @@ class Google_Service_Gmail_Resource_UsersHistory extends Google_Service_Resource
* valid IDs. Supplying an invalid or out of date startHistoryId typically
* returns an HTTP 404 error code. A historyId is typically valid for at least a
* week, but in some rare circumstances may be valid for only a few hours. If
* you receive an HTTP 404 error response, your application should perform a
* you receive an HTTP 404 error response, your application should perform a
* full sync. If you receive no nextPageToken in the response, there are no
* updates to retrieve and you can store the returned historyId for a future
* request.

View File

@ -85,7 +85,8 @@ class Google_Service_Gmail_Resource_UsersLabels extends Google_Service_Resource
return $this->call('list', array($params), "Google_Service_Gmail_ListLabelsResponse");
}
/**
* Patch the specified label. (labels.patch)
* Updates the specified label. This method supports patch semantics.
* (labels.patch)
*
* @param string $userId The user's email address. The special value me can be
* used to indicate the authenticated user.

View File

@ -26,7 +26,7 @@
class Google_Service_Gmail_Resource_UsersMessages extends Google_Service_Resource
{
/**
* Deletes many messages by message ID. Provides no guarantees that messages
* Deletes many messages by message ID. Provides no guarantees that messages
* were not already deleted or even existed at all. (messages.batchDelete)
*
* @param string $userId The user's email address. The special value me can be
@ -56,7 +56,7 @@ class Google_Service_Gmail_Resource_UsersMessages extends Google_Service_Resourc
}
/**
* Immediately and permanently deletes the specified message. This operation
* cannot be undone. Prefer messages.trash instead. (messages.delete)
* cannot be undone. Prefer messages.trash instead. (messages.delete)
*
* @param string $userId The user's email address. The special value me can be
* used to indicate the authenticated user.
@ -77,9 +77,9 @@ class Google_Service_Gmail_Resource_UsersMessages extends Google_Service_Resourc
* @param string $id The ID of the message to retrieve.
* @param array $optParams Optional parameters.
*
* @opt_param string format The format to return the message in.
* @opt_param string metadataHeaders When given and format is METADATA, only
* include headers specified.
* @opt_param string format The format to return the message in.
* @return Google_Service_Gmail_Message
*/
public function get($userId, $id, $optParams = array())
@ -98,15 +98,15 @@ class Google_Service_Gmail_Resource_UsersMessages extends Google_Service_Resourc
* @param Google_Service_Gmail_Message $postBody
* @param array $optParams Optional parameters.
*
* @opt_param bool processForCalendar Process calendar invites in the email and
* add any extracted meetings to the Google Calendar for this user.
* @opt_param bool deleted Mark the email as permanently deleted (not TRASH) and
* only visible in Google Vault to a Vault administrator. Only used for G Suite
* accounts.
* @opt_param string internalDateSource Source for Gmail's internal date of the
* message.
* @opt_param bool neverMarkSpam Ignore the Gmail spam classifier decision and
* never mark this email as SPAM in the mailbox.
* @opt_param bool deleted Mark the email as permanently deleted (not TRASH) and
* only visible in Google Vault to a Vault administrator. Only used for G Suite
* accounts.
* @opt_param bool processForCalendar Process calendar invites in the email and
* add any extracted meetings to the Google Calendar for this user.
* @return Google_Service_Gmail_Message
*/
public function import($userId, Google_Service_Gmail_Message $postBody, $optParams = array())
@ -125,11 +125,11 @@ class Google_Service_Gmail_Resource_UsersMessages extends Google_Service_Resourc
* @param Google_Service_Gmail_Message $postBody
* @param array $optParams Optional parameters.
*
* @opt_param string internalDateSource Source for Gmail's internal date of the
* message.
* @opt_param bool deleted Mark the email as permanently deleted (not TRASH) and
* only visible in Google Vault to a Vault administrator. Only used for G Suite
* accounts.
* @opt_param string internalDateSource Source for Gmail's internal date of the
* message.
* @return Google_Service_Gmail_Message
*/
public function insert($userId, Google_Service_Gmail_Message $postBody, $optParams = array())
@ -147,16 +147,15 @@ class Google_Service_Gmail_Resource_UsersMessages extends Google_Service_Resourc
*
* @opt_param bool includeSpamTrash Include messages from SPAM and TRASH in the
* results.
* @opt_param string pageToken Page token to retrieve a specific page of results
* in the list.
* @opt_param string labelIds Only return messages with labels that match all of
* the specified label IDs.
* @opt_param string maxResults Maximum number of messages to return.
* @opt_param string pageToken Page token to retrieve a specific page of results
* in the list.
* @opt_param string q Only return messages matching the specified query.
* Supports the same query format as the Gmail search box. For example,
* "from:someuser@example.com rfc822msgid:somemsgid@example.com is:unread".
* Parameter cannot be used when accessing the api using the gmail.metadata
* scope.
* @opt_param string maxResults Maximum number of messages to return.
* "from:someuser@example.com rfc822msgid: is:unread". Parameter cannot be used
* when accessing the api using the gmail.metadata scope.
* @return Google_Service_Gmail_ListMessagesResponse
*/
public function listUsersMessages($userId, $optParams = array())

View File

@ -29,7 +29,7 @@ class Google_Service_Gmail_Resource_UsersSettings extends Google_Service_Resourc
* Gets the auto-forwarding setting for the specified account.
* (settings.getAutoForwarding)
*
* @param string $userId User's email address. The special value "me" can be
* @param string $userId User's email address. The special value "me" can be
* used to indicate the authenticated user.
* @param array $optParams Optional parameters.
* @return Google_Service_Gmail_AutoForwarding
@ -43,7 +43,7 @@ class Google_Service_Gmail_Resource_UsersSettings extends Google_Service_Resourc
/**
* Gets IMAP settings. (settings.getImap)
*
* @param string $userId User's email address. The special value "me" can be
* @param string $userId User's email address. The special value "me" can be
* used to indicate the authenticated user.
* @param array $optParams Optional parameters.
* @return Google_Service_Gmail_ImapSettings
@ -57,7 +57,7 @@ class Google_Service_Gmail_Resource_UsersSettings extends Google_Service_Resourc
/**
* Gets language settings. (settings.getLanguage)
*
* @param string $userId User's email address. The special value "me" can be
* @param string $userId User's email address. The special value "me" can be
* used to indicate the authenticated user.
* @param array $optParams Optional parameters.
* @return Google_Service_Gmail_LanguageSettings
@ -71,7 +71,7 @@ class Google_Service_Gmail_Resource_UsersSettings extends Google_Service_Resourc
/**
* Gets POP settings. (settings.getPop)
*
* @param string $userId User's email address. The special value "me" can be
* @param string $userId User's email address. The special value "me" can be
* used to indicate the authenticated user.
* @param array $optParams Optional parameters.
* @return Google_Service_Gmail_PopSettings
@ -85,7 +85,7 @@ class Google_Service_Gmail_Resource_UsersSettings extends Google_Service_Resourc
/**
* Gets vacation responder settings. (settings.getVacation)
*
* @param string $userId User's email address. The special value "me" can be
* @param string $userId User's email address. The special value "me" can be
* used to indicate the authenticated user.
* @param array $optParams Optional parameters.
* @return Google_Service_Gmail_VacationSettings
@ -97,13 +97,13 @@ class Google_Service_Gmail_Resource_UsersSettings extends Google_Service_Resourc
return $this->call('getVacation', array($params), "Google_Service_Gmail_VacationSettings");
}
/**
* Updates the auto-forwarding setting for the specified account. A verified
* Updates the auto-forwarding setting for the specified account. A verified
* forwarding address must be specified when auto-forwarding is enabled.
*
* This method is only available to service account clients that have been
* delegated domain-wide authority. (settings.updateAutoForwarding)
*
* @param string $userId User's email address. The special value "me" can be
* @param string $userId User's email address. The special value "me" can be
* used to indicate the authenticated user.
* @param Google_Service_Gmail_AutoForwarding $postBody
* @param array $optParams Optional parameters.
@ -118,7 +118,7 @@ class Google_Service_Gmail_Resource_UsersSettings extends Google_Service_Resourc
/**
* Updates IMAP settings. (settings.updateImap)
*
* @param string $userId User's email address. The special value "me" can be
* @param string $userId User's email address. The special value "me" can be
* used to indicate the authenticated user.
* @param Google_Service_Gmail_ImapSettings $postBody
* @param array $optParams Optional parameters.
@ -139,7 +139,7 @@ class Google_Service_Gmail_Resource_UsersSettings extends Google_Service_Resourc
* Gmail but have a close variant that is, and so the variant may be chosen and
* saved instead. (settings.updateLanguage)
*
* @param string $userId User's email address. The special value "me" can be
* @param string $userId User's email address. The special value "me" can be
* used to indicate the authenticated user.
* @param Google_Service_Gmail_LanguageSettings $postBody
* @param array $optParams Optional parameters.
@ -154,7 +154,7 @@ class Google_Service_Gmail_Resource_UsersSettings extends Google_Service_Resourc
/**
* Updates POP settings. (settings.updatePop)
*
* @param string $userId User's email address. The special value "me" can be
* @param string $userId User's email address. The special value "me" can be
* used to indicate the authenticated user.
* @param Google_Service_Gmail_PopSettings $postBody
* @param array $optParams Optional parameters.
@ -169,7 +169,7 @@ class Google_Service_Gmail_Resource_UsersSettings extends Google_Service_Resourc
/**
* Updates vacation responder settings. (settings.updateVacation)
*
* @param string $userId User's email address. The special value "me" can be
* @param string $userId User's email address. The special value "me" can be
* used to indicate the authenticated user.
* @param Google_Service_Gmail_VacationSettings $postBody
* @param array $optParams Optional parameters.

View File

@ -27,8 +27,8 @@ class Google_Service_Gmail_Resource_UsersSettingsDelegates extends Google_Servic
{
/**
* Adds a delegate with its verification status set directly to accepted,
* without sending any verification email. The delegate user must be a member
* of the same G Suite organization as the delegator user.
* without sending any verification email. The delegate user must be a member of
* the same G Suite organization as the delegator user.
*
* Gmail imposes limitations on the number of delegates and delegators each user
* in a G Suite organization can have. These limits depend on your organization,
@ -43,7 +43,7 @@ class Google_Service_Gmail_Resource_UsersSettingsDelegates extends Google_Servic
* This method is only available to service account clients that have been
* delegated domain-wide authority. (delegates.create)
*
* @param string $userId User's email address. The special value "me" can be
* @param string $userId User's email address. The special value "me" can be
* used to indicate the authenticated user.
* @param Google_Service_Gmail_Delegate $postBody
* @param array $optParams Optional parameters.
@ -65,7 +65,7 @@ class Google_Service_Gmail_Resource_UsersSettingsDelegates extends Google_Servic
* This method is only available to service account clients that have been
* delegated domain-wide authority. (delegates.delete)
*
* @param string $userId User's email address. The special value "me" can be
* @param string $userId User's email address. The special value "me" can be
* used to indicate the authenticated user.
* @param string $delegateEmail The email address of the user to be removed as a
* delegate.
@ -86,7 +86,7 @@ class Google_Service_Gmail_Resource_UsersSettingsDelegates extends Google_Servic
* This method is only available to service account clients that have been
* delegated domain-wide authority. (delegates.get)
*
* @param string $userId User's email address. The special value "me" can be
* @param string $userId User's email address. The special value "me" can be
* used to indicate the authenticated user.
* @param string $delegateEmail The email address of the user whose delegate
* relationship is to be retrieved.
@ -105,7 +105,7 @@ class Google_Service_Gmail_Resource_UsersSettingsDelegates extends Google_Servic
* This method is only available to service account clients that have been
* delegated domain-wide authority. (delegates.listUsersSettingsDelegates)
*
* @param string $userId User's email address. The special value "me" can be
* @param string $userId User's email address. The special value "me" can be
* used to indicate the authenticated user.
* @param array $optParams Optional parameters.
* @return Google_Service_Gmail_ListDelegatesResponse

View File

@ -26,7 +26,7 @@
class Google_Service_Gmail_Resource_UsersSettingsForwardingAddresses extends Google_Service_Resource
{
/**
* Creates a forwarding address. If ownership verification is required, a
* Creates a forwarding address. If ownership verification is required, a
* message will be sent to the recipient and the resource's verification status
* will be set to pending; otherwise, the resource will be created with
* verification status set to accepted.
@ -34,7 +34,7 @@ class Google_Service_Gmail_Resource_UsersSettingsForwardingAddresses extends Goo
* This method is only available to service account clients that have been
* delegated domain-wide authority. (forwardingAddresses.create)
*
* @param string $userId User's email address. The special value "me" can be
* @param string $userId User's email address. The special value "me" can be
* used to indicate the authenticated user.
* @param Google_Service_Gmail_ForwardingAddress $postBody
* @param array $optParams Optional parameters.
@ -53,7 +53,7 @@ class Google_Service_Gmail_Resource_UsersSettingsForwardingAddresses extends Goo
* This method is only available to service account clients that have been
* delegated domain-wide authority. (forwardingAddresses.delete)
*
* @param string $userId User's email address. The special value "me" can be
* @param string $userId User's email address. The special value "me" can be
* used to indicate the authenticated user.
* @param string $forwardingEmail The forwarding address to be deleted.
* @param array $optParams Optional parameters.
@ -67,7 +67,7 @@ class Google_Service_Gmail_Resource_UsersSettingsForwardingAddresses extends Goo
/**
* Gets the specified forwarding address. (forwardingAddresses.get)
*
* @param string $userId User's email address. The special value "me" can be
* @param string $userId User's email address. The special value "me" can be
* used to indicate the authenticated user.
* @param string $forwardingEmail The forwarding address to be retrieved.
* @param array $optParams Optional parameters.
@ -83,7 +83,7 @@ class Google_Service_Gmail_Resource_UsersSettingsForwardingAddresses extends Goo
* Lists the forwarding addresses for the specified account.
* (forwardingAddresses.listUsersSettingsForwardingAddresses)
*
* @param string $userId User's email address. The special value "me" can be
* @param string $userId User's email address. The special value "me" can be
* used to indicate the authenticated user.
* @param array $optParams Optional parameters.
* @return Google_Service_Gmail_ListForwardingAddressesResponse

View File

@ -26,18 +26,18 @@
class Google_Service_Gmail_Resource_UsersSettingsSendAs extends Google_Service_Resource
{
/**
* Creates a custom "from" send-as alias. If an SMTP MSA is specified, Gmail
* Creates a custom "from" send-as alias. If an SMTP MSA is specified, Gmail
* will attempt to connect to the SMTP service to validate the configuration
* before creating the alias. If ownership verification is required for the
* before creating the alias. If ownership verification is required for the
* alias, a message will be sent to the email address and the resource's
* verification status will be set to pending; otherwise, the resource will be
* created with verification status set to accepted. If a signature is
* provided, Gmail will sanitize the HTML before saving it with the alias.
* created with verification status set to accepted. If a signature is provided,
* Gmail will sanitize the HTML before saving it with the alias.
*
* This method is only available to service account clients that have been
* delegated domain-wide authority. (sendAs.create)
*
* @param string $userId User's email address. The special value "me" can be
* @param string $userId User's email address. The special value "me" can be
* used to indicate the authenticated user.
* @param Google_Service_Gmail_SendAs $postBody
* @param array $optParams Optional parameters.
@ -50,13 +50,13 @@ class Google_Service_Gmail_Resource_UsersSettingsSendAs extends Google_Service_R
return $this->call('create', array($params), "Google_Service_Gmail_SendAs");
}
/**
* Deletes the specified send-as alias. Revokes any verification that may have
* Deletes the specified send-as alias. Revokes any verification that may have
* been required for using it.
*
* This method is only available to service account clients that have been
* delegated domain-wide authority. (sendAs.delete)
*
* @param string $userId User's email address. The special value "me" can be
* @param string $userId User's email address. The special value "me" can be
* used to indicate the authenticated user.
* @param string $sendAsEmail The send-as alias to be deleted.
* @param array $optParams Optional parameters.
@ -68,10 +68,10 @@ class Google_Service_Gmail_Resource_UsersSettingsSendAs extends Google_Service_R
return $this->call('delete', array($params));
}
/**
* Gets the specified send-as alias. Fails with an HTTP 404 error if the
* Gets the specified send-as alias. Fails with an HTTP 404 error if the
* specified address is not a member of the collection. (sendAs.get)
*
* @param string $userId User's email address. The special value "me" can be
* @param string $userId User's email address. The special value "me" can be
* used to indicate the authenticated user.
* @param string $sendAsEmail The send-as alias to be retrieved.
* @param array $optParams Optional parameters.
@ -84,11 +84,11 @@ class Google_Service_Gmail_Resource_UsersSettingsSendAs extends Google_Service_R
return $this->call('get', array($params), "Google_Service_Gmail_SendAs");
}
/**
* Lists the send-as aliases for the specified account. The result includes the
* Lists the send-as aliases for the specified account. The result includes the
* primary send-as address associated with the account as well as any custom
* "from" aliases. (sendAs.listUsersSettingsSendAs)
*
* @param string $userId User's email address. The special value "me" can be
* @param string $userId User's email address. The special value "me" can be
* used to indicate the authenticated user.
* @param array $optParams Optional parameters.
* @return Google_Service_Gmail_ListSendAsResponse
@ -100,9 +100,14 @@ class Google_Service_Gmail_Resource_UsersSettingsSendAs extends Google_Service_R
return $this->call('list', array($params), "Google_Service_Gmail_ListSendAsResponse");
}
/**
* Patch the specified send-as alias. (sendAs.patch)
* Updates a send-as alias. If a signature is provided, Gmail will sanitize the
* HTML before saving it with the alias.
*
* @param string $userId User's email address. The special value "me" can be
* Addresses other than the primary address for the account can only be updated
* by service account clients that have been delegated domain-wide authority.
* This method supports patch semantics. (sendAs.patch)
*
* @param string $userId User's email address. The special value "me" can be
* used to indicate the authenticated user.
* @param string $sendAsEmail The send-as alias to be updated.
* @param Google_Service_Gmail_SendAs $postBody
@ -116,14 +121,14 @@ class Google_Service_Gmail_Resource_UsersSettingsSendAs extends Google_Service_R
return $this->call('patch', array($params), "Google_Service_Gmail_SendAs");
}
/**
* Updates a send-as alias. If a signature is provided, Gmail will sanitize the
* Updates a send-as alias. If a signature is provided, Gmail will sanitize the
* HTML before saving it with the alias.
*
* Addresses other than the primary address for the account can only be updated
* by service account clients that have been delegated domain-wide authority.
* (sendAs.update)
*
* @param string $userId User's email address. The special value "me" can be
* @param string $userId User's email address. The special value "me" can be
* used to indicate the authenticated user.
* @param string $sendAsEmail The send-as alias to be updated.
* @param Google_Service_Gmail_SendAs $postBody
@ -143,7 +148,7 @@ class Google_Service_Gmail_Resource_UsersSettingsSendAs extends Google_Service_R
* This method is only available to service account clients that have been
* delegated domain-wide authority. (sendAs.verify)
*
* @param string $userId User's email address. The special value "me" can be
* @param string $userId User's email address. The special value "me" can be
* used to indicate the authenticated user.
* @param string $sendAsEmail The send-as alias to be verified.
* @param array $optParams Optional parameters.

View File

@ -48,9 +48,9 @@ class Google_Service_Gmail_Resource_UsersThreads extends Google_Service_Resource
* @param string $id The ID of the thread to retrieve.
* @param array $optParams Optional parameters.
*
* @opt_param string format The format to return the messages in.
* @opt_param string metadataHeaders When given and format is METADATA, only
* include headers specified.
* @opt_param string format The format to return the messages in.
* @return Google_Service_Gmail_Thread
*/
public function get($userId, $id, $optParams = array())
@ -66,17 +66,17 @@ class Google_Service_Gmail_Resource_UsersThreads extends Google_Service_Resource
* used to indicate the authenticated user.
* @param array $optParams Optional parameters.
*
* @opt_param string pageToken Page token to retrieve a specific page of results
* in the list.
* @opt_param bool includeSpamTrash Include threads from SPAM and TRASH in the
* results.
* @opt_param string labelIds Only return threads with labels that match all of
* the specified label IDs.
* @opt_param string maxResults Maximum number of threads to return.
* @opt_param string pageToken Page token to retrieve a specific page of results
* in the list.
* @opt_param string q Only return threads matching the specified query.
* Supports the same query format as the Gmail search box. For example,
* "from:someuser@example.com rfc822msgid: is:unread". Parameter cannot be used
* when accessing the api using the gmail.metadata scope.
* @opt_param string maxResults Maximum number of threads to return.
* @opt_param bool includeSpamTrash Include threads from SPAM and TRASH in the
* results.
* @return Google_Service_Gmail_ListThreadsResponse
*/
public function listUsersThreads($userId, $optParams = array())

View File

@ -23,7 +23,7 @@ function oauth2client_php_autoload($className)
}
if (count($classPath) > 3) {
// Maximum class file path depth in this project is 3.
$classPath = array_slice($classPath, 0, 3);
$classPath = array_slice($classPath, 0, 3);
}
$filePath = dirname(__FILE__) . '/src/' . implode('/', $classPath) . '.php';
if (file_exists($filePath)) {

View File

@ -82,22 +82,19 @@ class AccessToken
* accepted. By default, the id token must have been issued to this OAuth2 client.
*
* @param string $token The JSON Web Token to be verified.
* @param array $options [optional] {
* Configuration options.
*
* @type string $audience The indended recipient of the token.
* @type string $issuer The intended issuer of the token.
* @type string $certsLocation The location (remote or local) from which
* @param array $options [optional] Configuration options.
* @param string $options.audience The indended recipient of the token.
* @param string $options.issuer The intended issuer of the token.
* @param string $options.cacheKey The cache key of the cached certs. Defaults to
* the sha1 of $certsLocation if provided, otherwise is set to
* "federated_signon_certs_v3".
* @param string $options.certsLocation The location (remote or local) from which
* to retrieve certificates, if not cached. This value should only be
* provided in limited circumstances in which you are sure of the
* behavior.
* @type string $cacheKey The cache key of the cached certs. Defaults to
* the sha1 of $certsLocation if provided, otherwise is set to
* "federated_signon_certs_v3".
* @type bool $throwException Whether the function should throw an
* @param bool $options.throwException Whether the function should throw an
* exception if the verification fails. This is useful for
* determining the reason verification failed.
* }
* @return array|bool the token payload, if successful, or false if not.
* @throws InvalidArgumentException If certs could not be retrieved from a local file.
* @throws InvalidArgumentException If received certs are in an invalid format.
@ -129,7 +126,8 @@ class AccessToken
$alg = $this->determineAlg($certs);
if (!in_array($alg, ['RS256', 'ES256'])) {
throw new InvalidArgumentException(
'unrecognized "alg" in certs, expected ES256 or RS256');
'unrecognized "alg" in certs, expected ES256 or RS256'
);
}
try {
if ($alg == 'RS256') {
@ -186,13 +184,11 @@ class AccessToken
*
* @param string $token The JSON Web Token to be verified.
* @param array $certs Certificate array according to the JWK spec (see
* https://tools.ietf.org/html/rfc7517).
* https://tools.ietf.org/html/rfc7517).
* @param string|null $audience If set, returns false if the provided
* audience does not match the "aud" claim on
* the JWT.
* audience does not match the "aud" claim on the JWT.
* @param string|null $issuer If set, returns false if the provided
* issuer does not match the "iss" claim on
* the JWT.
* issuer does not match the "iss" claim on the JWT.
* @return array|bool the token payload, if successful, or false if not.
*/
private function verifyEs256($token, array $certs, $audience = null, $issuer = null)
@ -228,13 +224,11 @@ class AccessToken
*
* @param string $token The JSON Web Token to be verified.
* @param array $certs Certificate array according to the JWK spec (see
* https://tools.ietf.org/html/rfc7517).
* https://tools.ietf.org/html/rfc7517).
* @param string|null $audience If set, returns false if the provided
* audience does not match the "aud" claim on
* the JWT.
* audience does not match the "aud" claim on the JWT.
* @param string|null $issuer If set, returns false if the provided
* issuer does not match the "iss" claim on
* the JWT.
* issuer does not match the "iss" claim on the JWT.
* @return array|bool the token payload, if successful, or false if not.
*/
private function verifyRs256($token, array $certs, $audience = null, $issuer = null)
@ -325,6 +319,7 @@ class AccessToken
* are PEM encoded certificates.
*
* @param string $location The location from which to retrieve certs.
* @param string $cacheKey The key under which to cache the retrieved certs.
* @param array $options [optional] Configuration options.
* @return array
* @throws InvalidArgumentException If received certs are in an invalid format.

View File

@ -46,23 +46,25 @@ use Psr\Cache\CacheItemPoolInterface;
*
* This allows it to be used as follows with GuzzleHttp\Client:
*
* use Google\Auth\ApplicationDefaultCredentials;
* use GuzzleHttp\Client;
* use GuzzleHttp\HandlerStack;
* ```
* use Google\Auth\ApplicationDefaultCredentials;
* use GuzzleHttp\Client;
* use GuzzleHttp\HandlerStack;
*
* $middleware = ApplicationDefaultCredentials::getMiddleware(
* 'https://www.googleapis.com/auth/taskqueue'
* );
* $stack = HandlerStack::create();
* $stack->push($middleware);
* $middleware = ApplicationDefaultCredentials::getMiddleware(
* 'https://www.googleapis.com/auth/taskqueue'
* );
* $stack = HandlerStack::create();
* $stack->push($middleware);
*
* $client = new Client([
* 'handler' => $stack,
* 'base_uri' => 'https://www.googleapis.com/taskqueue/v1beta2/projects/',
* 'auth' => 'google_auth' // authorize all requests
* ]);
* $client = new Client([
* 'handler' => $stack,
* 'base_uri' => 'https://www.googleapis.com/taskqueue/v1beta2/projects/',
* 'auth' => 'google_auth' // authorize all requests
* ]);
*
* $res = $client->get('myproject/taskqueues/myqueue');
* $res = $client->get('myproject/taskqueues/myqueue');
* ```
*/
class ApplicationDefaultCredentials
{
@ -74,13 +76,12 @@ class ApplicationDefaultCredentials
* this does not fallback to the compute engine defaults.
*
* @param string|array scope the scope of the access request, expressed
* either as an Array or as a space-delimited String.
* either as an Array or as a space-delimited String.
* @param callable $httpHandler callback which delivers psr7 request
* @param array $cacheConfig configuration for the cache when it's present
* @param CacheItemPoolInterface $cache an implementation of CacheItemPoolInterface
*
* @param CacheItemPoolInterface $cache A cache implementation, may be
* provided if you have one already available for use.
* @return AuthTokenSubscriber
*
* @throws DomainException if no implementation can be obtained.
*/
public static function getSubscriber(
@ -102,13 +103,12 @@ class ApplicationDefaultCredentials
* this does not fallback to the compute engine defaults.
*
* @param string|array scope the scope of the access request, expressed
* either as an Array or as a space-delimited String.
* either as an Array or as a space-delimited String.
* @param callable $httpHandler callback which delivers psr7 request
* @param array $cacheConfig configuration for the cache when it's present
* @param CacheItemPoolInterface $cache
*
* @param CacheItemPoolInterface $cache A cache implementation, may be
* provided if you have one already available for use.
* @return AuthTokenMiddleware
*
* @throws DomainException if no implementation can be obtained.
*/
public static function getMiddleware(
@ -131,20 +131,23 @@ class ApplicationDefaultCredentials
* this does not fallback to the Compute Engine defaults.
*
* @param string|array scope the scope of the access request, expressed
* either as an Array or as a space-delimited String.
* either as an Array or as a space-delimited String.
* @param callable $httpHandler callback which delivers psr7 request
* @param array $cacheConfig configuration for the cache when it's present
* @param CacheItemPoolInterface $cache
* @param CacheItemPoolInterface $cache A cache implementation, may be
* provided if you have one already available for use.
* @param string $quotaProject specifies a project to bill for access
* charges associated with the request.
*
* @return CredentialsLoader
*
* @throws DomainException if no implementation can be obtained.
*/
public static function getCredentials(
$scope = null,
callable $httpHandler = null,
array $cacheConfig = null,
CacheItemPoolInterface $cache = null
CacheItemPoolInterface $cache = null,
$quotaProject = null
) {
$creds = null;
$jsonKey = CredentialsLoader::fromEnv()
@ -160,11 +163,12 @@ class ApplicationDefaultCredentials
}
if (!is_null($jsonKey)) {
$jsonKey['quota_project'] = $quotaProject;
$creds = CredentialsLoader::makeCredentials($scope, $jsonKey);
} elseif (AppIdentityCredentials::onAppEngine() && !GCECredentials::onAppEngineFlexible()) {
$creds = new AppIdentityCredentials($scope);
} elseif (GCECredentials::onGce($httpHandler)) {
$creds = new GCECredentials(null, $scope);
$creds = new GCECredentials(null, $scope, null, $quotaProject);
}
if (is_null($creds)) {
@ -187,10 +191,9 @@ class ApplicationDefaultCredentials
* @param string $targetAudience The audience for the ID token.
* @param callable $httpHandler callback which delivers psr7 request
* @param array $cacheConfig configuration for the cache when it's present
* @param CacheItemPoolInterface $cache
*
* @param CacheItemPoolInterface $cache A cache implementation, may be
* provided if you have one already available for use.
* @return AuthTokenMiddleware
*
* @throws DomainException if no implementation can be obtained.
*/
public static function getIdTokenMiddleware(
@ -198,7 +201,6 @@ class ApplicationDefaultCredentials
callable $httpHandler = null,
array $cacheConfig = null,
CacheItemPoolInterface $cache = null
) {
$creds = self::getIdTokenCredentials($targetAudience, $httpHandler, $cacheConfig, $cache);
@ -213,10 +215,9 @@ class ApplicationDefaultCredentials
* @param string $targetAudience The audience for the ID token.
* @param callable $httpHandler callback which delivers psr7 request
* @param array $cacheConfig configuration for the cache when it's present
* @param CacheItemPoolInterface $cache
*
* @param CacheItemPoolInterface $cache A cache implementation, may be
* provided if you have one already available for use.
* @return CredentialsLoader
*
* @throws DomainException if no implementation can be obtained.
* @throws InvalidArgumentException if JSON "type" key is invalid
*/

View File

@ -62,22 +62,22 @@ class SysVCacheItemPool implements CacheItemPoolInterface
/**
* Create a SystemV shared memory based CacheItemPool.
*
* @param array $options [optional] {
* Configuration options.
*
* @type int $variableKey The variable key for getting the data from
* the shared memory. **Defaults to** 1.
* @type string $proj The project identifier for ftok. This needs to
* be a one character string. **Defaults to** 'A'.
* @type int $memsize The memory size in bytes for shm_attach.
* **Defaults to** 10000.
* @type int $perm The permission for shm_attach. **Defaults to** 0600.
* @param array $options [optional] Configuration options.
* @param int $options.variableKey The variable key for getting the data from
* the shared memory. **Defaults to** 1.
* @param $options.proj string The project identifier for ftok. This needs to
* be a one character string. **Defaults to** 'A'.
* @param $options.memsize int The memory size in bytes for shm_attach.
* **Defaults to** 10000.
* @param $options.perm int The permission for shm_attach. **Defaults to**
* 0600.
*/
public function __construct($options = [])
{
if (! extension_loaded('sysvshm')) {
throw new \RuntimeException(
'sysvshm extension is required to use this ItemPool');
'sysvshm extension is required to use this ItemPool'
);
}
$this->options = $options + [
'variableKey' => self::VAR_KEY,
@ -90,9 +90,6 @@ class SysVCacheItemPool implements CacheItemPoolInterface
$this->sysvKey = ftok(__FILE__, $this->options['proj']);
}
/**
* {@inheritdoc}
*/
public function getItem($key)
{
$this->loadItems();

View File

@ -90,7 +90,7 @@ class AppIdentityCredentials extends CredentialsLoader implements
* SERVER_SOFTWARE environment variable (prod) or the APPENGINE_RUNTIME
* environment variable (dev).
*
* @return true if this an App Engine Instance, false otherwise
* @return bool true if this an App Engine Instance, false otherwise
*/
public static function onAppEngine()
{
@ -115,7 +115,6 @@ class AppIdentityCredentials extends CredentialsLoader implements
* the GuzzleHttp\ClientInterface instance passed in will not be used.
*
* @param callable $httpHandler callback which delivers psr7 request
*
* @return array A set of auth related metadata, containing the following
* keys:
* - access_token (string)

View File

@ -18,6 +18,7 @@
namespace Google\Auth\Credentials;
use Google\Auth\CredentialsLoader;
use Google\Auth\GetQuotaProjectInterface;
use Google\Auth\HttpHandler\HttpClientCache;
use Google\Auth\HttpHandler\HttpHandlerFactory;
use Google\Auth\Iam;
@ -55,9 +56,12 @@ use InvalidArgumentException;
*/
class GCECredentials extends CredentialsLoader implements
SignBlobInterface,
ProjectIdProviderInterface
ProjectIdProviderInterface,
GetQuotaProjectInterface
{
// phpcs:disable
const cacheKey = 'GOOGLE_AUTH_PHP_GCE';
// phpcs:enable
/**
* The metadata IP address on appengine instances.
@ -149,19 +153,27 @@ class GCECredentials extends CredentialsLoader implements
*/
private $targetAudience;
/**
* @var string|null
*/
private $quotaProject;
/**
* @param Iam $iam [optional] An IAM instance.
* @param string|array $scope [optional] the scope of the access request,
* expressed either as an array or as a space-delimited string.
* @param string $targetAudience [optional] The audience for the ID token.
* @param string $quotaProject [optional] Specifies a project to bill for access
* charges associated with the request.
*/
public function __construct(Iam $iam = null, $scope = null, $targetAudience = null)
public function __construct(Iam $iam = null, $scope = null, $targetAudience = null, $quotaProject = null)
{
$this->iam = $iam;
if ($scope && $targetAudience) {
throw new InvalidArgumentException(
'Scope and targetAudience cannot both be supplied');
'Scope and targetAudience cannot both be supplied'
);
}
$tokenUri = self::getTokenUri();
@ -174,7 +186,8 @@ class GCECredentials extends CredentialsLoader implements
$tokenUri = $tokenUri . '?scopes='. $scope;
} elseif ($targetAudience) {
$tokenUri = sprintf('http://%s/computeMetadata/%s?audience=%s',
$tokenUri = sprintf(
'http://%s/computeMetadata/%s?audience=%s',
self::METADATA_IP,
self::ID_TOKEN_URI_PATH,
$targetAudience
@ -183,6 +196,7 @@ class GCECredentials extends CredentialsLoader implements
}
$this->tokenUri = $tokenUri;
$this->quotaProject = $quotaProject;
}
/**
@ -225,7 +239,7 @@ class GCECredentials extends CredentialsLoader implements
* Determines if this an App Engine Flexible instance, by accessing the
* GAE_INSTANCE environment variable.
*
* @return true if this an App Engine Flexible Instance, false otherwise
* @return bool true if this an App Engine Flexible Instance, false otherwise
*/
public static function onAppEngineFlexible()
{
@ -456,4 +470,14 @@ class GCECredentials extends CredentialsLoader implements
return (string) $resp->getBody();
}
/**
* Get the quota project used for this API request
*
* @return string|null
*/
public function getQuotaProject()
{
return $this->quotaProject;
}
}

View File

@ -43,11 +43,13 @@ class IAMCredentials
{
if (!is_string($selector)) {
throw new \InvalidArgumentException(
'selector must be a string');
'selector must be a string'
);
}
if (!is_string($token)) {
throw new \InvalidArgumentException(
'token must be a string');
'token must be a string'
);
}
$this->selector = $selector;

View File

@ -112,18 +112,21 @@ class ServiceAccountCredentials extends CredentialsLoader implements
}
if (!array_key_exists('client_email', $jsonKey)) {
throw new \InvalidArgumentException(
'json key is missing the client_email field');
'json key is missing the client_email field'
);
}
if (!array_key_exists('private_key', $jsonKey)) {
throw new \InvalidArgumentException(
'json key is missing the private_key field');
'json key is missing the private_key field'
);
}
if (array_key_exists('quota_project', $jsonKey)) {
$this->quotaProject = (string) $jsonKey['quota_project'];
}
if ($scope && $targetAudience) {
throw new InvalidArgumentException(
'Scope and targetAudience cannot both be supplied');
'Scope and targetAudience cannot both be supplied'
);
}
$additionalClaims = [];
if ($targetAudience) {
@ -199,7 +202,6 @@ class ServiceAccountCredentials extends CredentialsLoader implements
* @param array $metadata metadata hashmap
* @param string $authUri optional auth uri
* @param callable $httpHandler callback which delivers psr7 request
*
* @return array updated metadata hashmap
*/
public function updateMetadata(

View File

@ -71,11 +71,13 @@ class ServiceAccountJwtAccessCredentials extends CredentialsLoader implements
}
if (!array_key_exists('client_email', $jsonKey)) {
throw new \InvalidArgumentException(
'json key is missing the client_email field');
'json key is missing the client_email field'
);
}
if (!array_key_exists('private_key', $jsonKey)) {
throw new \InvalidArgumentException(
'json key is missing the private_key field');
'json key is missing the private_key field'
);
}
if (array_key_exists('quota_project', $jsonKey)) {
$this->quotaProject = (string) $jsonKey['quota_project'];
@ -98,7 +100,6 @@ class ServiceAccountJwtAccessCredentials extends CredentialsLoader implements
* @param array $metadata metadata hashmap
* @param string $authUri optional auth uri
* @param callable $httpHandler callback which delivers psr7 request
*
* @return array updated metadata hashmap
*/
public function updateMetadata(

View File

@ -74,15 +74,18 @@ class UserRefreshCredentials extends CredentialsLoader implements GetQuotaProjec
}
if (!array_key_exists('client_id', $jsonKey)) {
throw new \InvalidArgumentException(
'json key is missing the client_id field');
'json key is missing the client_id field'
);
}
if (!array_key_exists('client_secret', $jsonKey)) {
throw new \InvalidArgumentException(
'json key is missing the client_secret field');
'json key is missing the client_secret field'
);
}
if (!array_key_exists('refresh_token', $jsonKey)) {
throw new \InvalidArgumentException(
'json key is missing the refresh_token field');
'json key is missing the refresh_token field'
);
}
$this->auth = new OAuth2([
'clientId' => $jsonKey['client_id'],
@ -109,7 +112,8 @@ class UserRefreshCredentials extends CredentialsLoader implements GetQuotaProjec
. 'To disable this warning, set '
. self::SUPPRESS_CLOUD_SDK_CREDS_WARNING_ENV
. ' environment variable to "true".',
E_USER_WARNING);
E_USER_WARNING
);
}
}

View File

@ -61,7 +61,7 @@ abstract class CredentialsLoader implements FetchAuthTokenInterface
* variable GOOGLE_APPLICATION_CREDENTIALS. Return null if
* GOOGLE_APPLICATION_CREDENTIALS is not specified.
*
* @return array JSON key | null
* @return array|null JSON key | null
*/
public static function fromEnv()
{
@ -81,12 +81,13 @@ abstract class CredentialsLoader implements FetchAuthTokenInterface
* Load a JSON key from a well known path.
*
* The well known path is OS dependent:
* - windows: %APPDATA%/gcloud/application_default_credentials.json
* - others: $HOME/.config/gcloud/application_default_credentials.json
*
* If the file does not exists, this returns null.
* * windows: %APPDATA%/gcloud/application_default_credentials.json
* * others: $HOME/.config/gcloud/application_default_credentials.json
*
* @return array JSON key | null
* If the file does not exist, this returns null.
*
* @return array|null JSON key | null
*/
public static function fromWellKnownFile()
{
@ -108,9 +109,8 @@ abstract class CredentialsLoader implements FetchAuthTokenInterface
* Create a new Credentials instance.
*
* @param string|array $scope the scope of the access request, expressed
* either as an Array or as a space-delimited String.
* either as an Array or as a space-delimited String.
* @param array $jsonKey the JSON credentials.
*
* @return ServiceAccountCredentials|UserRefreshCredentials
*/
public static function makeCredentials($scope, array $jsonKey)
@ -134,10 +134,9 @@ abstract class CredentialsLoader implements FetchAuthTokenInterface
* Create an authorized HTTP Client from an instance of FetchAuthTokenInterface.
*
* @param FetchAuthTokenInterface $fetcher is used to fetch the auth token
* @param array $httpClientOptoins (optional) Array of request options to apply.
* @param array $httpClientOptions (optional) Array of request options to apply.
* @param callable $httpHandler (optional) http client to fetch the token.
* @param callable $tokenCallback (optional) function to be called when a new token is fetched.
*
* @return \GuzzleHttp\Client
*/
public static function makeHttpClient(
@ -203,7 +202,6 @@ abstract class CredentialsLoader implements FetchAuthTokenInterface
* @param array $metadata metadata hashmap
* @param string $authUri optional auth uri
* @param callable $httpHandler callback which delivers psr7 request
*
* @return array updated metadata hashmap
*/
public function updateMetadata(

View File

@ -46,6 +46,11 @@ class FetchAuthTokenCache implements
*/
private $cache;
/**
* @param FetchAuthTokenInterface $fetcher A credentials fetcher
* @param array $cacheConfig Configuration for the cache
* @param CacheItemPoolInterface $cache
*/
public function __construct(
FetchAuthTokenInterface $fetcher,
array $cacheConfig = null,
@ -66,9 +71,7 @@ class FetchAuthTokenCache implements
* from the supplied fetcher.
*
* @param callable $httpHandler callback which delivers psr7 request
*
* @return array the response
*
* @throws \Exception
*/
public function fetchAuthToken(callable $httpHandler = null)
@ -125,14 +128,14 @@ class FetchAuthTokenCache implements
* Sign a blob using the fetcher.
*
* @param string $stringToSign The string to sign.
* @param bool $forceOpenssl Require use of OpenSSL for local signing. Does
* @param bool $forceOpenSsl Require use of OpenSSL for local signing. Does
* not apply to signing done using external services. **Defaults to**
* `false`.
* @return string The resulting signature.
* @throws \RuntimeException If the fetcher does not implement
* `Google\Auth\SignBlobInterface`.
*/
public function signBlob($stringToSign, $forceOpenSsl = false)
public function signBlob($stringToSign, $forceOpenSsl = false)
{
if (!$this->fetcher instanceof SignBlobInterface) {
throw new \RuntimeException(

View File

@ -26,7 +26,6 @@ interface FetchAuthTokenInterface
* Fetches the auth tokens based on the current state.
*
* @param callable $httpHandler callback which delivers psr7 request
*
* @return array a hash of auth tokens
*/
public function fetchAuthToken(callable $httpHandler = null);

View File

@ -45,7 +45,6 @@ class Guzzle5HttpHandler
*
* @param RequestInterface $request
* @param array $options
*
* @return ResponseInterface
*/
public function __invoke(RequestInterface $request, array $options = [])
@ -62,7 +61,6 @@ class Guzzle5HttpHandler
*
* @param RequestInterface $request
* @param array $options
*
* @return Promise
*/
public function async(RequestInterface $request, array $options = [])

View File

@ -26,7 +26,6 @@ class Guzzle6HttpHandler
*
* @param RequestInterface $request
* @param array $options
*
* @return ResponseInterface
*/
public function __invoke(RequestInterface $request, array $options = [])
@ -40,7 +39,7 @@ class Guzzle6HttpHandler
* @param RequestInterface $request
* @param array $options
*
* @return \GuzzleHttp\Promise\Promise
* @return \GuzzleHttp\Promise\PromiseInterface
*/
public function async(RequestInterface $request, array $options = [])
{

View File

@ -89,7 +89,6 @@ class AuthTokenMiddleware
* $res = $client->get('myproject/taskqueues/myqueue');
*
* @param callable $handler
*
* @return \Closure
*/
public function __invoke(callable $handler)

View File

@ -76,7 +76,8 @@ class ScopedAccessTokenMiddleware
$this->tokenFunc = $tokenFunc;
if (!(is_string($scopes) || is_array($scopes))) {
throw new \InvalidArgumentException(
'wants scope should be string or array');
'wants scope should be string or array'
);
}
$this->scopes = $scopes;
@ -119,7 +120,6 @@ class ScopedAccessTokenMiddleware
* $res = $client->get('myproject/taskqueues/myqueue');
*
* @param callable $handler
*
* @return \Closure
*/
public function __invoke(callable $handler)

View File

@ -71,7 +71,6 @@ class SimpleMiddleware
* $res = $client->get('drive/v2/rest');
*
* @param callable $handler
*
* @return \Closure
*/
public function __invoke(callable $handler)

View File

@ -120,7 +120,7 @@ class OAuth2 implements FetchAuthTokenInterface
* The scope of the access request, expressed either as an Array or as a
* space-delimited string.
*
* @var string
* @var array
*/
private $scope;
@ -175,6 +175,13 @@ class OAuth2 implements FetchAuthTokenInterface
*/
private $signingKey;
/**
* The signing key id when using assertion profile. Param kid in jwt header
*
* @var string
*/
private $signingKeyId;
/**
* The signing algorithm when using an assertion profile.
*
@ -294,6 +301,9 @@ class OAuth2 implements FetchAuthTokenInterface
* - signingKey
* Signing key when using assertion profile
*
* - signingKeyId
* Signing key id when using assertion profile
*
* - refreshToken
* The refresh token associated with the access token
* to be refreshed.
@ -327,6 +337,7 @@ class OAuth2 implements FetchAuthTokenInterface
'sub' => null,
'audience' => null,
'signingKey' => null,
'signingKeyId' => null,
'signingAlgorithm' => null,
'scope' => null,
'additionalClaims' => [],
@ -345,6 +356,7 @@ class OAuth2 implements FetchAuthTokenInterface
$this->setExpiry($opts['expiry']);
$this->setAudience($opts['audience']);
$this->setSigningKey($opts['signingKey']);
$this->setSigningKeyId($opts['signingKeyId']);
$this->setSigningAlgorithm($opts['signingAlgorithm']);
$this->setScope($opts['scope']);
$this->setExtensionParams($opts['extensionParams']);
@ -359,11 +371,21 @@ class OAuth2 implements FetchAuthTokenInterface
* - if present, but invalid, raises DomainException.
* - otherwise returns the payload in the idtoken as a PHP object.
*
* if $publicKey is null, the key is decoded without being verified.
* The behavior of this method varies depending on the version of
* `firebase/php-jwt` you are using. In versions lower than 3.0.0, if
* `$publicKey` is null, the key is decoded without being verified. In
* newer versions, if a public key is not given, this method will throw an
* `\InvalidArgumentException`.
*
* @param string $publicKey The public key to use to authenticate the token
* @param array $allowed_algs List of supported verification algorithms
*
* @throws \DomainException if the token is missing an audience.
* @throws \DomainException if the audience does not match the one set in
* the OAuth2 class instance.
* @throws \UnexpectedValueException If the token is invalid
* @throws SignatureInvalidException If the signature is invalid.
* @throws BeforeValidException If the token is not yet valid.
* @throws ExpiredException If the token has expired.
* @return null|object
*/
public function verifyIdToken($publicKey = null, $allowed_algs = array())
@ -388,7 +410,6 @@ class OAuth2 implements FetchAuthTokenInterface
* Obtains the encoded jwt from the instance data.
*
* @param array $config array optional configuration parameters
*
* @return string
*/
public function toJwt(array $config = [])
@ -424,8 +445,12 @@ class OAuth2 implements FetchAuthTokenInterface
}
$assertion += $this->getAdditionalClaims();
return $this->jwtEncode($assertion, $this->getSigningKey(),
$this->getSigningAlgorithm());
return $this->jwtEncode(
$assertion,
$this->getSigningKey(),
$this->getSigningAlgorithm(),
$this->getSigningKeyId()
);
}
/**
@ -490,7 +515,6 @@ class OAuth2 implements FetchAuthTokenInterface
* Fetches the auth tokens based on the current state.
*
* @param callable $httpHandler callback which delivers psr7 request
*
* @return array the response
*/
public function fetchAuthToken(callable $httpHandler = null)
@ -515,10 +539,6 @@ class OAuth2 implements FetchAuthTokenInterface
*/
public function getCacheKey()
{
if (is_string($this->scope)) {
return $this->scope;
}
if (is_array($this->scope)) {
return implode(':', $this->scope);
}
@ -531,9 +551,7 @@ class OAuth2 implements FetchAuthTokenInterface
* Parses the fetched tokens.
*
* @param ResponseInterface $resp the response.
*
* @return array the tokens parsed from the response body.
*
* @throws \Exception
*/
public function parseTokenResponse(ResponseInterface $resp)
@ -559,12 +577,14 @@ class OAuth2 implements FetchAuthTokenInterface
/**
* Updates an OAuth 2.0 client.
*
* @example
* client.updateToken([
* Example:
* ```
* $oauth->updateToken([
* 'refresh_token' => 'n4E9O119d',
* 'access_token' => 'FJQbwq9',
* 'expires_in' => 3600
* ])
* ]);
* ```
*
* @param array $config
* The configuration parameters related to the token.
@ -621,16 +641,15 @@ class OAuth2 implements FetchAuthTokenInterface
* Builds the authorization Uri that the user should be redirected to.
*
* @param array $config configuration options that customize the return url
*
* @return UriInterface the authorization Url.
*
* @throws InvalidArgumentException
*/
public function buildFullAuthorizationUri(array $config = [])
{
if (is_null($this->getAuthorizationUri())) {
throw new InvalidArgumentException(
'requires an authorizationUri to have been set');
'requires an authorizationUri to have been set'
);
}
$params = array_merge([
@ -645,14 +664,16 @@ class OAuth2 implements FetchAuthTokenInterface
// Validate the auth_params
if (is_null($params['client_id'])) {
throw new InvalidArgumentException(
'missing the required client identifier');
'missing the required client identifier'
);
}
if (is_null($params['redirect_uri'])) {
throw new InvalidArgumentException('missing the required redirect URI');
}
if (!empty($params['prompt']) && !empty($params['approval_prompt'])) {
throw new InvalidArgumentException(
'prompt and approval_prompt are mutually exclusive');
'prompt and approval_prompt are mutually exclusive'
);
}
// Construct the uri object; return it if it is valid.
@ -665,7 +686,8 @@ class OAuth2 implements FetchAuthTokenInterface
if ($result->getScheme() != 'https') {
throw new InvalidArgumentException(
'Authorization endpoint must be protected by TLS');
'Authorization endpoint must be protected by TLS'
);
}
return $result;
@ -743,7 +765,8 @@ class OAuth2 implements FetchAuthTokenInterface
// @see https://developers.google.com/identity/sign-in/web/server-side-flow
if ('postmessage' !== (string)$uri) {
throw new InvalidArgumentException(
'Redirect URI must be absolute');
'Redirect URI must be absolute'
);
}
}
$this->redirectUri = (string)$uri;
@ -768,7 +791,6 @@ class OAuth2 implements FetchAuthTokenInterface
* a space-delimited String.
*
* @param string|array $scope
*
* @throws InvalidArgumentException
*/
public function setScope($scope)
@ -782,13 +804,15 @@ class OAuth2 implements FetchAuthTokenInterface
$pos = strpos($s, ' ');
if ($pos !== false) {
throw new InvalidArgumentException(
'array scope values should not contain spaces');
'array scope values should not contain spaces'
);
}
}
$this->scope = $scope;
} else {
throw new InvalidArgumentException(
'scopes should be a string or array of strings');
'scopes should be a string or array of strings'
);
}
}
@ -828,7 +852,6 @@ class OAuth2 implements FetchAuthTokenInterface
* Sets the current grant type.
*
* @param $grantType
*
* @throws InvalidArgumentException
*/
public function setGrantType($grantType)
@ -839,7 +862,8 @@ class OAuth2 implements FetchAuthTokenInterface
// validate URI
if (!$this->isAbsoluteUri($grantType)) {
throw new InvalidArgumentException(
'invalid grant type');
'invalid grant type'
);
}
$this->grantType = (string)$grantType;
}
@ -1031,6 +1055,26 @@ class OAuth2 implements FetchAuthTokenInterface
$this->signingKey = $signingKey;
}
/**
* Gets the signing key id when using an assertion profile.
*
* @return string
*/
public function getSigningKeyId()
{
return $this->signingKeyId;
}
/**
* Sets the signing key id when using an assertion profile.
*
* @param string $signingKeyId
*/
public function setSigningKeyId($signingKeyId)
{
$this->signingKeyId = $signingKeyId;
}
/**
* Gets the signing algorithm when using an assertion profile.
*
@ -1287,7 +1331,6 @@ class OAuth2 implements FetchAuthTokenInterface
* @todo handle uri as array
*
* @param string $uri
*
* @return null|UriInterface
*/
private function coerceUri($uri)
@ -1303,7 +1346,6 @@ class OAuth2 implements FetchAuthTokenInterface
* @param string $idToken
* @param string|array|null $publicKey
* @param array $allowedAlgs
*
* @return object
*/
private function jwtDecode($idToken, $publicKey, $allowedAlgs)
@ -1315,14 +1357,18 @@ class OAuth2 implements FetchAuthTokenInterface
return \JWT::decode($idToken, $publicKey, $allowedAlgs);
}
private function jwtEncode($assertion, $signingKey, $signingAlgorithm)
private function jwtEncode($assertion, $signingKey, $signingAlgorithm, $signingKeyId = null)
{
if (class_exists('Firebase\JWT\JWT')) {
return \Firebase\JWT\JWT::encode($assertion, $signingKey,
$signingAlgorithm);
return \Firebase\JWT\JWT::encode(
$assertion,
$signingKey,
$signingAlgorithm,
$signingKeyId
);
}
return \JWT::encode($assertion, $signingKey, $signingAlgorithm);
return \JWT::encode($assertion, $signingKey, $signingAlgorithm, $signingKeyId);
}
/**
@ -1330,7 +1376,6 @@ class OAuth2 implements FetchAuthTokenInterface
* (RFC 3986).
*
* @param string $uri
*
* @return bool
*/
private function isAbsoluteUri($uri)
@ -1342,7 +1387,6 @@ class OAuth2 implements FetchAuthTokenInterface
/**
* @param array $params
*
* @return array
*/
private function addClientCredentials(&$params)

View File

@ -79,21 +79,24 @@ class AuthTokenSubscriber implements SubscriberInterface
/**
* Updates the request with an Authorization header when auth is 'fetched_auth_token'.
*
* use GuzzleHttp\Client;
* use Google\Auth\OAuth2;
* use Google\Auth\Subscriber\AuthTokenSubscriber;
* Example:
* ```
* use GuzzleHttp\Client;
* use Google\Auth\OAuth2;
* use Google\Auth\Subscriber\AuthTokenSubscriber;
*
* $config = [..<oauth config param>.];
* $oauth2 = new OAuth2($config)
* $subscriber = new AuthTokenSubscriber($oauth2);
* $config = [..<oauth config param>.];
* $oauth2 = new OAuth2($config)
* $subscriber = new AuthTokenSubscriber($oauth2);
*
* $client = new Client([
* 'base_url' => 'https://www.googleapis.com/taskqueue/v1beta2/projects/',
* 'defaults' => ['auth' => 'google_auth']
* ]);
* $client->getEmitter()->attach($subscriber);
* $client = new Client([
* 'base_url' => 'https://www.googleapis.com/taskqueue/v1beta2/projects/',
* 'defaults' => ['auth' => 'google_auth']
* ]);
* $client->getEmitter()->attach($subscriber);
*
* $res = $client->get('myproject/taskqueues/myqueue');
* $res = $client->get('myproject/taskqueues/myqueue');
* ```
*
* @param BeforeEvent $event
*/

View File

@ -78,7 +78,8 @@ class ScopedAccessTokenSubscriber implements SubscriberInterface
$this->tokenFunc = $tokenFunc;
if (!(is_string($scopes) || is_array($scopes))) {
throw new \InvalidArgumentException(
'wants scope should be string or array');
'wants scope should be string or array'
);
}
$this->scopes = $scopes;
@ -102,28 +103,30 @@ class ScopedAccessTokenSubscriber implements SubscriberInterface
/**
* Updates the request with an Authorization header when auth is 'scoped'.
*
* E.g this could be used to authenticate using the AppEngine
* AppIdentityService.
* E.g this could be used to authenticate using the AppEngine AppIdentityService.
*
* use google\appengine\api\app_identity\AppIdentityService;
* use Google\Auth\Subscriber\ScopedAccessTokenSubscriber;
* use GuzzleHttp\Client;
* Example:
* ```
* use google\appengine\api\app_identity\AppIdentityService;
* use Google\Auth\Subscriber\ScopedAccessTokenSubscriber;
* use GuzzleHttp\Client;
*
* $scope = 'https://www.googleapis.com/auth/taskqueue'
* $subscriber = new ScopedAccessToken(
* 'AppIdentityService::getAccessToken',
* $scope,
* ['prefix' => 'Google\Auth\ScopedAccessToken::'],
* $cache = new Memcache()
* );
* $scope = 'https://www.googleapis.com/auth/taskqueue'
* $subscriber = new ScopedAccessToken(
* 'AppIdentityService::getAccessToken',
* $scope,
* ['prefix' => 'Google\Auth\ScopedAccessToken::'],
* $cache = new Memcache()
* );
*
* $client = new Client([
* 'base_url' => 'https://www.googleapis.com/taskqueue/v1beta2/projects/',
* 'defaults' => ['auth' => 'scoped']
* ]);
* $client->getEmitter()->attach($subscriber);
* $client = new Client([
* 'base_url' => 'https://www.googleapis.com/taskqueue/v1beta2/projects/',
* 'defaults' => ['auth' => 'scoped']
* ]);
* $client->getEmitter()->attach($subscriber);
*
* $res = $client->get('myproject/taskqueues/myqueue');
* $res = $client->get('myproject/taskqueues/myqueue');
* ```
*
* @param BeforeEvent $event
*/

View File

@ -62,19 +62,22 @@ class SimpleSubscriber implements SubscriberInterface
/**
* Updates the request query with the developer key if auth is set to simple.
*
* use Google\Auth\Subscriber\SimpleSubscriber;
* use GuzzleHttp\Client;
* Example:
* ```
* use Google\Auth\Subscriber\SimpleSubscriber;
* use GuzzleHttp\Client;
*
* $my_key = 'is not the same as yours';
* $subscriber = new SimpleSubscriber(['key' => $my_key]);
* $my_key = 'is not the same as yours';
* $subscriber = new SimpleSubscriber(['key' => $my_key]);
*
* $client = new Client([
* 'base_url' => 'https://www.googleapis.com/discovery/v1/',
* 'defaults' => ['auth' => 'simple']
* ]);
* $client->getEmitter()->attach($subscriber);
* $client = new Client([
* 'base_url' => 'https://www.googleapis.com/discovery/v1/',
* 'defaults' => ['auth' => 'simple']
* ]);
* $client->getEmitter()->attach($subscriber);
*
* $res = $client->get('drive/v2/rest');
* $res = $client->get('drive/v2/rest');
* ```
*
* @param BeforeEvent $event
*/

View File

@ -2,11 +2,12 @@
namespace GuzzleHttp;
use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Promise;
use GuzzleHttp\Psr7;
use Psr\Http\Message\UriInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\UriInterface;
/**
* @method ResponseInterface get(string|UriInterface $uri, array $options = [])
@ -46,9 +47,8 @@ class Client implements ClientInterface
* wire. The function is called with a Psr7\Http\Message\RequestInterface
* and array of transfer options, and must return a
* GuzzleHttp\Promise\PromiseInterface that is fulfilled with a
* Psr7\Http\Message\ResponseInterface on success. "handler" is a
* constructor only option that cannot be overridden in per/request
* options. If no handler is provided, a default handler will be created
* Psr7\Http\Message\ResponseInterface on success.
* If no handler is provided, a default handler will be created
* that enables all of the request options below by attaching all of the
* default middleware to the handler.
* - base_uri: (string|UriInterface) Base URI of the client that is merged
@ -75,6 +75,12 @@ class Client implements ClientInterface
$this->configureDefaults($config);
}
/**
* @param string $method
* @param array $args
*
* @return Promise\PromiseInterface
*/
public function __call($method, $args)
{
if (count($args) < 1) {
@ -89,6 +95,14 @@ class Client implements ClientInterface
: $this->request($method, $uri, $opts);
}
/**
* Asynchronously send an HTTP request.
*
* @param array $options Request options to apply to the given
* request and to the transfer. See \GuzzleHttp\RequestOptions.
*
* @return Promise\PromiseInterface
*/
public function sendAsync(RequestInterface $request, array $options = [])
{
// Merge the base URI into the request URI if needed.
@ -100,12 +114,35 @@ class Client implements ClientInterface
);
}
/**
* Send an HTTP request.
*
* @param array $options Request options to apply to the given
* request and to the transfer. See \GuzzleHttp\RequestOptions.
*
* @return ResponseInterface
* @throws GuzzleException
*/
public function send(RequestInterface $request, array $options = [])
{
$options[RequestOptions::SYNCHRONOUS] = true;
return $this->sendAsync($request, $options)->wait();
}
/**
* Create and send an asynchronous HTTP request.
*
* Use an absolute path to override the base path of the client, or a
* relative path to append to the base path of the client. The URL can
* contain the query string as well. Use an array to provide a URL
* template and additional variables to use in the URL template expansion.
*
* @param string $method HTTP method
* @param string|UriInterface $uri URI object or string.
* @param array $options Request options to apply. See \GuzzleHttp\RequestOptions.
*
* @return Promise\PromiseInterface
*/
public function requestAsync($method, $uri = '', array $options = [])
{
$options = $this->prepareDefaults($options);
@ -125,12 +162,37 @@ class Client implements ClientInterface
return $this->transfer($request, $options);
}
/**
* Create and send an HTTP request.
*
* Use an absolute path to override the base path of the client, or a
* relative path to append to the base path of the client. The URL can
* contain the query string as well.
*
* @param string $method HTTP method.
* @param string|UriInterface $uri URI object or string.
* @param array $options Request options to apply. See \GuzzleHttp\RequestOptions.
*
* @return ResponseInterface
* @throws GuzzleException
*/
public function request($method, $uri = '', array $options = [])
{
$options[RequestOptions::SYNCHRONOUS] = true;
return $this->requestAsync($method, $uri, $options)->wait();
}
/**
* Get a client configuration option.
*
* These options include default request options of the client, a "handler"
* (if utilized by the concrete client), and a "base_uri" if utilized by
* the concrete client.
*
* @param string|null $option The config option to retrieve.
*
* @return mixed
*/
public function getConfig($option = null)
{
return $option === null
@ -138,6 +200,11 @@ class Client implements ClientInterface
: (isset($this->config[$option]) ? $this->config[$option] : null);
}
/**
* @param string|null $uri
*
* @return UriInterface
*/
private function buildUri($uri, array $config)
{
// for BC we accept null which would otherwise fail in uri_for
@ -147,6 +214,11 @@ class Client implements ClientInterface
$uri = Psr7\UriResolver::resolve(Psr7\uri_for($config['base_uri']), $uri);
}
if (isset($config['idn_conversion']) && ($config['idn_conversion'] !== false)) {
$idnOptions = ($config['idn_conversion'] === true) ? IDNA_DEFAULT : $config['idn_conversion'];
$uri = Utils::idnUriConvert($uri, $idnOptions);
}
return $uri->getScheme() === '' && $uri->getHost() !== '' ? $uri->withScheme('http') : $uri;
}
@ -154,6 +226,7 @@ class Client implements ClientInterface
* Configures the default options for a client.
*
* @param array $config
* @return void
*/
private function configureDefaults(array $config)
{
@ -162,7 +235,8 @@ class Client implements ClientInterface
'http_errors' => true,
'decode_content' => true,
'verify' => true,
'cookies' => false
'cookies' => false,
'idn_conversion' => true,
];
// Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set.
@ -170,7 +244,7 @@ class Client implements ClientInterface
// We can only trust the HTTP_PROXY environment variable in a CLI
// process due to the fact that PHP has no reliable mechanism to
// get environment variables that start with "HTTP_".
if (php_sapi_name() == 'cli' && getenv('HTTP_PROXY')) {
if (php_sapi_name() === 'cli' && getenv('HTTP_PROXY')) {
$defaults['proxy']['http'] = getenv('HTTP_PROXY');
}
@ -225,7 +299,7 @@ class Client implements ClientInterface
if (array_key_exists('headers', $options)) {
// Allows default headers to be unset.
if ($options['headers'] === null) {
$defaults['_conditional'] = null;
$defaults['_conditional'] = [];
unset($options['headers']);
} elseif (!is_array($options['headers'])) {
throw new \InvalidArgumentException('headers must be an array');
@ -251,8 +325,7 @@ class Client implements ClientInterface
* The URI of the request is not modified and the request options are used
* as-is without merging in default options.
*
* @param RequestInterface $request
* @param array $options
* @param array $options See \GuzzleHttp\RequestOptions.
*
* @return Promise\PromiseInterface
*/
@ -271,6 +344,7 @@ class Client implements ClientInterface
}
$request = $this->applyOptions($request, $options);
/** @var HandlerStack $handler */
$handler = $options['handler'];
try {
@ -411,6 +485,11 @@ class Client implements ClientInterface
return $request;
}
/**
* Throw Exception with pre-set message.
* @return void
* @throws \InvalidArgumentException Invalid body.
*/
private function invalidBody()
{
throw new \InvalidArgumentException('Passing in the "body" request '

View File

@ -1,8 +1,8 @@
<?php
namespace GuzzleHttp;
use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Promise\PromiseInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\UriInterface;
@ -12,7 +12,10 @@ use Psr\Http\Message\UriInterface;
*/
interface ClientInterface
{
const VERSION = '6.4.1';
/**
* @deprecated Will be removed in Guzzle 7.0.0
*/
const VERSION = '6.5.4';
/**
* Send an HTTP request.

View File

@ -94,8 +94,8 @@ class CookieJar implements CookieJarInterface
*/
public function getCookieByName($name)
{
// don't allow a null name
if ($name === null) {
// don't allow a non string name
if ($name === null || !is_scalar($name)) {
return null;
}
foreach ($this->cookies as $cookie) {
@ -103,6 +103,8 @@ class CookieJar implements CookieJarInterface
return $cookie;
}
}
return null;
}
public function toArray()

View File

@ -58,9 +58,9 @@ interface CookieJarInterface extends \Countable, \IteratorAggregate
* arguments, then the cookie with the specified name, path and domain is
* removed.
*
* @param string $domain Clears cookies matching a domain
* @param string $path Clears cookies matching a domain and path
* @param string $name Clears cookies matching a domain, path, and name
* @param string|null $domain Clears cookies matching a domain
* @param string|null $path Clears cookies matching a domain and path
* @param string|null $name Clears cookies matching a domain, path, and name
*
* @return CookieJarInterface
*/

View File

@ -1,9 +1,9 @@
<?php
namespace GuzzleHttp\Exception;
use GuzzleHttp\Promise\PromiseInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\Promise\PromiseInterface;
use Psr\Http\Message\UriInterface;
/**
@ -14,7 +14,7 @@ class RequestException extends TransferException
/** @var RequestInterface */
private $request;
/** @var ResponseInterface */
/** @var ResponseInterface|null */
private $response;
/** @var array */
@ -124,42 +124,17 @@ class RequestException extends TransferException
*/
public static function getResponseBodySummary(ResponseInterface $response)
{
$body = $response->getBody();
if (!$body->isSeekable() || !$body->isReadable()) {
return null;
}
$size = $body->getSize();
if ($size === 0) {
return null;
}
$summary = $body->read(120);
$body->rewind();
if ($size > 120) {
$summary .= ' (truncated...)';
}
// Matches any printable character, including unicode characters:
// letters, marks, numbers, punctuation, spacing, and separators.
if (preg_match('/[^\pL\pM\pN\pP\pS\pZ\n\r\t]/', $summary)) {
return null;
}
return $summary;
return \GuzzleHttp\Psr7\get_message_body_summary($response);
}
/**
* Obfuscates URI if there is an username and a password present
* Obfuscates URI if there is a username and a password present
*
* @param UriInterface $uri
*
* @return UriInterface
*/
private static function obfuscateUri($uri)
private static function obfuscateUri(UriInterface $uri)
{
$userInfo = $uri->getUserInfo();

View File

@ -1,8 +1,8 @@
<?php
namespace GuzzleHttp\Handler;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Promise\FulfilledPromise;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\LazyOpenStream;
@ -454,11 +454,16 @@ class CurlFactory implements CurlFactoryInterface
}
if (isset($options['ssl_key'])) {
$sslKey = $options['ssl_key'];
if (is_array($sslKey)) {
$conf[CURLOPT_SSLKEYPASSWD] = $sslKey[1];
$sslKey = $sslKey[0];
if (is_array($options['ssl_key'])) {
if (count($options['ssl_key']) === 2) {
list($sslKey, $conf[CURLOPT_SSLKEYPASSWD]) = $options['ssl_key'];
} else {
list($sslKey) = $options['ssl_key'];
}
}
$sslKey = isset($sslKey) ? $sslKey: $options['ssl_key'];
if (!file_exists($sslKey)) {
throw new \InvalidArgumentException(
"SSL private key not found: {$sslKey}"

View File

@ -3,7 +3,7 @@ namespace GuzzleHttp\Handler;
use GuzzleHttp\Promise as P;
use GuzzleHttp\Promise\Promise;
use GuzzleHttp\Psr7;
use GuzzleHttp\Utils;
use Psr\Http\Message\RequestInterface;
/**
@ -23,6 +23,7 @@ class CurlMultiHandler
private $active;
private $handles = [];
private $delays = [];
private $options = [];
/**
* This handler accepts the following options:
@ -30,6 +31,8 @@ class CurlMultiHandler
* - handle_factory: An optional factory used to create curl handles
* - select_timeout: Optional timeout (in seconds) to block before timing
* out while selecting curl handles. Defaults to 1 second.
* - options: An associative array of CURLMOPT_* options and
* corresponding values for curl_multi_setopt()
*
* @param array $options
*/
@ -45,12 +48,23 @@ class CurlMultiHandler
} else {
$this->selectTimeout = 1;
}
$this->options = isset($options['options']) ? $options['options'] : [];
}
public function __get($name)
{
if ($name === '_mh') {
return $this->_mh = curl_multi_init();
$this->_mh = curl_multi_init();
foreach ($this->options as $option => $value) {
// A warning is raised in case of a wrong option.
curl_multi_setopt($this->_mh, $option, $value);
}
// Further calls to _mh will return the value directly, without entering the
// __get() method at all.
return $this->_mh;
}
throw new \BadMethodCallException();
@ -88,7 +102,7 @@ class CurlMultiHandler
{
// Add any delayed handles if needed.
if ($this->delays) {
$currentTime = \GuzzleHttp\_current_time();
$currentTime = Utils::currentTime();
foreach ($this->delays as $id => $delay) {
if ($currentTime >= $delay) {
unset($this->delays[$id]);
@ -140,7 +154,7 @@ class CurlMultiHandler
if (empty($easy->options['delay'])) {
curl_multi_add_handle($this->_mh, $easy->handle);
} else {
$this->delays[$id] = \GuzzleHttp\_current_time() + ($easy->options['delay'] / 1000);
$this->delays[$id] = Utils::currentTime() + ($easy->options['delay'] / 1000);
}
}
@ -192,7 +206,7 @@ class CurlMultiHandler
private function timeToNext()
{
$currentTime = \GuzzleHttp\_current_time();
$currentTime = Utils::currentTime();
$nextTime = PHP_INT_MAX;
foreach ($this->delays as $time) {
if ($time < $nextTime) {

View File

@ -66,7 +66,7 @@ class MockHandler implements \Countable
throw new \OutOfBoundsException('Mock queue is empty');
}
if (isset($options['delay'])) {
if (isset($options['delay']) && is_numeric($options['delay'])) {
usleep($options['delay'] * 1000);
}
@ -175,6 +175,11 @@ class MockHandler implements \Countable
return count($this->queue);
}
public function reset()
{
$this->queue = [];
}
private function invokeStats(
RequestInterface $request,
array $options,

View File

@ -1,12 +1,13 @@
<?php
namespace GuzzleHttp\Handler;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Promise\FulfilledPromise;
use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\Psr7;
use GuzzleHttp\TransferStats;
use GuzzleHttp\Utils;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
@ -33,7 +34,7 @@ class StreamHandler
usleep($options['delay'] * 1000);
}
$startTime = isset($options['on_stats']) ? \GuzzleHttp\_current_time() : null;
$startTime = isset($options['on_stats']) ? Utils::currentTime() : null;
try {
// Does not support the expect header.
@ -82,7 +83,7 @@ class StreamHandler
$stats = new TransferStats(
$request,
$response,
\GuzzleHttp\_current_time() - $startTime,
Utils::currentTime() - $startTime,
$error,
[]
);

View File

@ -1,7 +1,9 @@
<?php
namespace GuzzleHttp;
use GuzzleHttp\Promise\PromiseInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
/**
* Creates a composed Guzzle handler function by stacking middlewares on top of
@ -9,7 +11,7 @@ use Psr\Http\Message\RequestInterface;
*/
class HandlerStack
{
/** @var callable */
/** @var callable|null */
private $handler;
/** @var array */
@ -59,6 +61,8 @@ class HandlerStack
*
* @param RequestInterface $request
* @param array $options
*
* @return ResponseInterface|PromiseInterface
*/
public function __invoke(RequestInterface $request, array $options)
{

View File

@ -168,6 +168,11 @@ class MessageFormatter
);
}
/**
* Get headers from message as string
*
* @return string
*/
private function headers(MessageInterface $message)
{
$result = '';

View File

@ -1,9 +1,10 @@
<?php
namespace GuzzleHttp;
use GuzzleHttp\Promise\EachPromise;
use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\Promise\PromisorInterface;
use Psr\Http\Message\RequestInterface;
use GuzzleHttp\Promise\EachPromise;
/**
* Sends an iterator of requests concurrently using a capped pool size.
@ -69,6 +70,11 @@ class Pool implements PromisorInterface
$this->each = new EachPromise($requests(), $config);
}
/**
* Get promise
*
* @return PromiseInterface
*/
public function promise()
{
return $this->each->promise();
@ -106,6 +112,11 @@ class Pool implements PromisorInterface
return $res;
}
/**
* Execute callback(s)
*
* @return void
*/
private static function cmpCallback(array &$options, $name, array &$results)
{
if (!isset($options[$name])) {

View File

@ -66,6 +66,11 @@ class PrepareBodyMiddleware
return $fn(Psr7\modify_request($request, $modify), $options);
}
/**
* Add expect header
*
* @return void
*/
private function addExpectHeader(
RequestInterface $request,
array $options,

View File

@ -13,7 +13,7 @@ use Psr\Http\Message\UriInterface;
* Request redirect middleware.
*
* Apply this middleware like other middleware using
* {@see GuzzleHttp\Middleware::redirect()}.
* {@see \GuzzleHttp\Middleware::redirect()}.
*/
class RedirectMiddleware
{
@ -76,7 +76,7 @@ class RedirectMiddleware
/**
* @param RequestInterface $request
* @param array $options
* @param ResponseInterface|PromiseInterface $response
* @param ResponseInterface $response
*
* @return ResponseInterface|PromiseInterface
*/
@ -118,6 +118,11 @@ class RedirectMiddleware
return $promise;
}
/**
* Enable tracking on promise.
*
* @return PromiseInterface
*/
private function withTracking(PromiseInterface $promise, $uri, $statusCode)
{
return $promise->then(
@ -135,6 +140,13 @@ class RedirectMiddleware
);
}
/**
* Check for too many redirects
*
* @return void
*
* @throws TooManyRedirectsException Too many redirects.
*/
private function guardMax(RequestInterface $request, array &$options)
{
$current = isset($options['__redirect_count'])
@ -172,13 +184,19 @@ class RedirectMiddleware
// would do.
$statusCode = $response->getStatusCode();
if ($statusCode == 303 ||
($statusCode <= 302 && $request->getBody() && !$options['allow_redirects']['strict'])
($statusCode <= 302 && !$options['allow_redirects']['strict'])
) {
$modify['method'] = 'GET';
$modify['body'] = '';
}
$modify['uri'] = $this->redirectUri($request, $response, $protocols);
$uri = $this->redirectUri($request, $response, $protocols);
if (isset($options['idn_conversion']) && ($options['idn_conversion'] !== false)) {
$idnOptions = ($options['idn_conversion'] === true) ? IDNA_DEFAULT : $options['idn_conversion'];
$uri = Utils::idnUriConvert($uri, $idnOptions);
}
$modify['uri'] = $uri;
Psr7\rewind_body($request);
// Add the Referer header if it is told to do so and only

View File

@ -132,6 +132,14 @@ final class RequestOptions
*/
const HTTP_ERRORS = 'http_errors';
/**
* idn: (bool|int, default=true) A combination of IDNA_* constants for
* idn_to_ascii() PHP's function (see "options" parameter). Set to false to
* disable IDN support completely, or to true to use the default
* configuration (IDNA_DEFAULT constant).
*/
const IDN_CONVERSION = 'idn_conversion';
/**
* json: (mixed) Adds JSON data to a request. The provided value is JSON
* encoded and a Content-Type header of application/json will be added to

View File

@ -47,11 +47,11 @@ class RetryMiddleware
*
* @param int $retries
*
* @return int
* @return int milliseconds.
*/
public static function exponentialDelay($retries)
{
return (int) pow(2, $retries - 1);
return (int) pow(2, $retries - 1) * 1000;
}
/**
@ -74,6 +74,11 @@ class RetryMiddleware
);
}
/**
* Execute fulfilled closure
*
* @return mixed
*/
private function onFulfilled(RequestInterface $req, array $options)
{
return function ($value) use ($req, $options) {
@ -90,6 +95,11 @@ class RetryMiddleware
};
}
/**
* Execute rejected closure
*
* @return callable
*/
private function onRejected(RequestInterface $req, array $options)
{
return function ($reason) use ($req, $options) {
@ -106,6 +116,9 @@ class RetryMiddleware
};
}
/**
* @return self
*/
private function doRetry(RequestInterface $request, array $options, ResponseInterface $response = null)
{
$options['delay'] = call_user_func($this->delay, ++$options['retries'], $response);

View File

@ -18,11 +18,11 @@ final class TransferStats
private $handlerErrorData;
/**
* @param RequestInterface $request Request that was sent.
* @param ResponseInterface $response Response received (if any)
* @param float|null $transferTime Total handler transfer time.
* @param mixed $handlerErrorData Handler error data.
* @param array $handlerStats Handler specific stats.
* @param RequestInterface $request Request that was sent.
* @param ResponseInterface|null $response Response received (if any)
* @param float|null $transferTime Total handler transfer time.
* @param mixed $handlerErrorData Handler error data.
* @param array $handlerStats Handler specific stats.
*/
public function __construct(
RequestInterface $request,
@ -93,7 +93,7 @@ final class TransferStats
/**
* Get the estimated time the request was being transferred by the handler.
*
* @return float Time in seconds.
* @return float|null Time in seconds.
*/
public function getTransferTime()
{

View File

@ -0,0 +1,89 @@
<?php
namespace GuzzleHttp;
use GuzzleHttp\Exception\InvalidArgumentException;
use Psr\Http\Message\UriInterface;
use Symfony\Polyfill\Intl\Idn\Idn;
final class Utils
{
/**
* Wrapper for the hrtime() or microtime() functions
* (depending on the PHP version, one of the two is used)
*
* @return float|mixed UNIX timestamp
*
* @internal
*/
public static function currentTime()
{
return function_exists('hrtime') ? hrtime(true) / 1e9 : microtime(true);
}
/**
* @param int $options
*
* @return UriInterface
* @throws InvalidArgumentException
*
* @internal
*/
public static function idnUriConvert(UriInterface $uri, $options = 0)
{
if ($uri->getHost()) {
$asciiHost = self::idnToAsci($uri->getHost(), $options, $info);
if ($asciiHost === false) {
$errorBitSet = isset($info['errors']) ? $info['errors'] : 0;
$errorConstants = array_filter(array_keys(get_defined_constants()), function ($name) {
return substr($name, 0, 11) === 'IDNA_ERROR_';
});
$errors = [];
foreach ($errorConstants as $errorConstant) {
if ($errorBitSet & constant($errorConstant)) {
$errors[] = $errorConstant;
}
}
$errorMessage = 'IDN conversion failed';
if ($errors) {
$errorMessage .= ' (errors: ' . implode(', ', $errors) . ')';
}
throw new InvalidArgumentException($errorMessage);
} else {
if ($uri->getHost() !== $asciiHost) {
// Replace URI only if the ASCII version is different
$uri = $uri->withHost($asciiHost);
}
}
}
return $uri;
}
/**
* @param string $domain
* @param int $options
* @param array $info
*
* @return string|false
*/
private static function idnToAsci($domain, $options, &$info = [])
{
if (\preg_match('%^[ -~]+$%', $domain) === 1) {
return $domain;
}
if (\extension_loaded('intl') && defined('INTL_IDNA_VARIANT_UTS46')) {
return \idn_to_ascii($domain, $options, INTL_IDNA_VARIANT_UTS46, $info);
}
/*
* The Idn class is marked as @internal. We've locked the version to
* symfony/polyfill-intl-idn to avoid issues in the future.
*/
return Idn::idn_to_ascii($domain, $options, Idn::INTL_IDNA_VARIANT_UTS46, $info);
}
}

View File

@ -56,7 +56,7 @@ function describe_type($input)
/**
* Parses an array of header lines into an associative array of headers.
*
* @param array $lines Header lines array of strings in the following
* @param iterable $lines Header lines array of strings in the following
* format: "Name: Value"
* @return array
*/
@ -97,8 +97,8 @@ function debug_resource($value = null)
*
* The returned handler is not wrapped by any default middlewares.
*
* @throws \RuntimeException if no viable Handler is available.
* @return callable Returns the best handler for the given system.
* @throws \RuntimeException if no viable Handler is available.
*/
function choose_handler()
{
@ -332,15 +332,3 @@ function json_encode($value, $options = 0, $depth = 512)
return $json;
}
/**
* Wrapper for the hrtime() or microtime() functions
* (depending on the PHP version, one of the two is used)
*
* @return float|mixed UNIX timestamp
* @internal
*/
function _current_time()
{
return function_exists('hrtime') ? hrtime(true) / 1e9 : microtime(true);
}

View File

@ -14,7 +14,6 @@ namespace Monolog;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use Monolog\Handler\AbstractHandler;
use Monolog\Registry;
/**
* Monolog error handler

View File

@ -142,8 +142,12 @@ class NormalizerFormatter implements FormatterInterface
$data['faultactor'] = $e->faultactor;
}
if (isset($e->detail) && (is_string($e->detail) || is_object($e->detail) || is_array($e->detail))) {
$data['detail'] = is_string($e->detail) ? $e->detail : reset($e->detail);
if (isset($e->detail)) {
if (is_string($e->detail)) {
$data['detail'] = $e->detail;
} elseif (is_object($e->detail) || is_array($e->detail)) {
$data['detail'] = $this->toJson($e->detail, true);
}
}
}

View File

@ -33,8 +33,8 @@ abstract class AbstractHandler implements HandlerInterface, ResettableInterface
protected $processors = array();
/**
* @param int $level The minimum logging level at which this handler will be triggered
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not
* @param int|string $level The minimum logging level at which this handler will be triggered
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not
*/
public function __construct($level = Logger::DEBUG, $bubble = true)
{

View File

@ -12,6 +12,7 @@
namespace Monolog\Handler;
use Monolog\Logger;
use Monolog\Utils;
/**
* Stores logs to files that are rotated every day and a limited number of files are kept.
@ -45,7 +46,7 @@ class RotatingFileHandler extends StreamHandler
*/
public function __construct($filename, $maxFiles = 0, $level = Logger::DEBUG, $bubble = true, $filePermission = null, $useLocking = false)
{
$this->filename = $filename;
$this->filename = Utils::canonicalizePath($filename);
$this->maxFiles = (int) $maxFiles;
$this->nextRotation = new \DateTime('tomorrow');
$this->filenameFormat = '{filename}-{date}';

View File

@ -12,6 +12,7 @@
namespace Monolog\Handler;
use Monolog\Logger;
use Monolog\Utils;
/**
* Stores to any stream resource
@ -45,7 +46,7 @@ class StreamHandler extends AbstractProcessingHandler
if (is_resource($stream)) {
$this->stream = $stream;
} elseif (is_string($stream)) {
$this->url = $stream;
$this->url = Utils::canonicalizePath($stream);
} else {
throw new \InvalidArgumentException('A stream must either be a resource or a string.');
}

View File

@ -52,7 +52,7 @@ class GitProcessor implements ProcessorInterface
}
$branches = `git branch -v --no-abbrev`;
if (preg_match('{^\* (.+?)\s+([a-f0-9]{40})(?:\s|$)}m', $branches, $matches)) {
if ($branches && preg_match('{^\* (.+?)\s+([a-f0-9]{40})(?:\s|$)}m', $branches, $matches)) {
return self::$cache = array(
'branch' => $matches[1],
'commit' => $matches[2],

View File

@ -23,6 +23,36 @@ class Utils
return 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class;
}
/**
* Makes sure if a relative path is passed in it is turned into an absolute path
*
* @param string $streamUrl stream URL or path without protocol
*
* @return string
*/
public static function canonicalizePath($streamUrl)
{
$prefix = '';
if ('file://' === substr($streamUrl, 0, 7)) {
$streamUrl = substr($streamUrl, 7);
$prefix = 'file://';
}
// other type of stream, not supported
if (false !== strpos($streamUrl, '://')) {
return $streamUrl;
}
// already absolute
if (substr($streamUrl, 0, 1) === '/' || substr($streamUrl, 1, 1) === ':' || substr($streamUrl, 0, 2) === '\\\\') {
return $prefix.$streamUrl;
}
$streamUrl = getcwd() . '/' . $streamUrl;
return $prefix.$streamUrl;
}
/**
* Return the JSON representation of a value
*

View File

@ -0,0 +1,287 @@
<?php
/*
* Copyright (c) 2014 TrueServer B.V.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* Originally forked from
* https://github.com/true/php-punycode/blob/v2.1.1/src/Punycode.php
*/
namespace Symfony\Polyfill\Intl\Idn;
/**
* Partial intl implementation in pure PHP.
*
* Implemented:
* - idn_to_ascii - Convert domain name to IDNA ASCII form
* - idn_to_utf8 - Convert domain name from IDNA ASCII to Unicode
*
* @author Renan Gonçalves <renan.saddam@gmail.com>
* @author Sebastian Kroczek <sk@xbug.de>
* @author Dmitry Lukashin <dmitry@lukashin.ru>
* @author Laurent Bassin <laurent@bassin.info>
*
* @internal
*/
final class Idn
{
const INTL_IDNA_VARIANT_2003 = 0;
const INTL_IDNA_VARIANT_UTS46 = 1;
private static $encodeTable = array(
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
);
private static $decodeTable = array(
'a' => 0, 'b' => 1, 'c' => 2, 'd' => 3, 'e' => 4, 'f' => 5,
'g' => 6, 'h' => 7, 'i' => 8, 'j' => 9, 'k' => 10, 'l' => 11,
'm' => 12, 'n' => 13, 'o' => 14, 'p' => 15, 'q' => 16, 'r' => 17,
's' => 18, 't' => 19, 'u' => 20, 'v' => 21, 'w' => 22, 'x' => 23,
'y' => 24, 'z' => 25, '0' => 26, '1' => 27, '2' => 28, '3' => 29,
'4' => 30, '5' => 31, '6' => 32, '7' => 33, '8' => 34, '9' => 35,
);
public static function idn_to_ascii($domain, $options, $variant, &$idna_info = array())
{
if (\PHP_VERSION_ID >= 70200 && self::INTL_IDNA_VARIANT_2003 === $variant) {
@trigger_error('idn_to_ascii(): INTL_IDNA_VARIANT_2003 is deprecated', E_USER_DEPRECATED);
}
if (self::INTL_IDNA_VARIANT_UTS46 === $variant) {
$domain = mb_strtolower($domain, 'utf-8');
}
$parts = explode('.', $domain);
foreach ($parts as $i => &$part) {
if ('' === $part && \count($parts) > 1 + $i) {
return false;
}
if (false === $part = self::encodePart($part)) {
return false;
}
}
$output = implode('.', $parts);
$idna_info = array(
'result' => \strlen($output) > 255 ? false : $output,
'isTransitionalDifferent' => false,
'errors' => 0,
);
return $idna_info['result'];
}
public static function idn_to_utf8($domain, $options, $variant, &$idna_info = array())
{
if (\PHP_VERSION_ID >= 70200 && self::INTL_IDNA_VARIANT_2003 === $variant) {
@trigger_error('idn_to_utf8(): INTL_IDNA_VARIANT_2003 is deprecated', E_USER_DEPRECATED);
}
$parts = explode('.', $domain);
foreach ($parts as &$part) {
$length = \strlen($part);
if ($length < 1 || 63 < $length) {
continue;
}
if (0 !== strpos($part, 'xn--')) {
continue;
}
$part = substr($part, 4);
$part = self::decodePart($part);
}
$output = implode('.', $parts);
$idna_info = array(
'result' => \strlen($output) > 255 ? false : $output,
'isTransitionalDifferent' => false,
'errors' => 0,
);
return $idna_info['result'];
}
private static function encodePart($input)
{
if (\substr($input, 0, 1) === '-' || \substr($input, -1) === '-') {
return false;
}
$codePoints = self::listCodePoints($input);
$n = 128;
$bias = 72;
$delta = 0;
$h = $b = \count($codePoints['basic']);
$output = '';
foreach ($codePoints['basic'] as $code) {
$output .= mb_chr($code, 'utf-8');
}
if ($input === $output) {
return $output;
}
if ($b > 0) {
$output .= '-';
}
$codePoints['nonBasic'] = array_unique($codePoints['nonBasic']);
sort($codePoints['nonBasic']);
$i = 0;
$length = mb_strlen($input, 'utf-8');
while ($h < $length) {
$m = $codePoints['nonBasic'][$i++];
$delta += ($m - $n) * ($h + 1);
$n = $m;
foreach ($codePoints['all'] as $c) {
if ($c < $n || $c < 128) {
++$delta;
}
if ($c === $n) {
$q = $delta;
for ($k = 36;; $k += 36) {
$t = self::calculateThreshold($k, $bias);
if ($q < $t) {
break;
}
$code = $t + (($q - $t) % (36 - $t));
$output .= self::$encodeTable[$code];
$q = ($q - $t) / (36 - $t);
}
$output .= self::$encodeTable[$q];
$bias = self::adapt($delta, $h + 1, ($h === $b));
$delta = 0;
++$h;
}
}
++$delta;
++$n;
}
$output = 'xn--'.$output;
return \strlen($output) < 1 || 63 < \strlen($output) ? false : strtolower($output);
}
private static function listCodePoints($input)
{
$codePoints = array(
'all' => array(),
'basic' => array(),
'nonBasic' => array(),
);
$length = mb_strlen($input, 'utf-8');
for ($i = 0; $i < $length; ++$i) {
$char = mb_substr($input, $i, 1, 'utf-8');
$code = mb_ord($char, 'utf-8');
if ($code < 128) {
$codePoints['all'][] = $codePoints['basic'][] = $code;
} else {
$codePoints['all'][] = $codePoints['nonBasic'][] = $code;
}
}
return $codePoints;
}
private static function calculateThreshold($k, $bias)
{
if ($k <= $bias + 1) {
return 1;
}
if ($k >= $bias + 26) {
return 26;
}
return $k - $bias;
}
private static function adapt($delta, $numPoints, $firstTime)
{
$delta = (int) ($firstTime ? $delta / 700 : $delta / 2);
$delta += (int) ($delta / $numPoints);
$k = 0;
while ($delta > 35 * 13) {
$delta = (int) ($delta / 35);
$k = $k + 36;
}
return $k + (int) (36 * $delta / ($delta + 38));
}
private static function decodePart($input)
{
$n = 128;
$i = 0;
$bias = 72;
$output = '';
$pos = strrpos($input, '-');
if (false !== $pos) {
$output = substr($input, 0, $pos++);
} else {
$pos = 0;
}
$outputLength = \strlen($output);
$inputLength = \strlen($input);
while ($pos < $inputLength) {
$oldi = $i;
$w = 1;
for ($k = 36;; $k += 36) {
$digit = self::$decodeTable[$input[$pos++]];
$i += $digit * $w;
$t = self::calculateThreshold($k, $bias);
if ($digit < $t) {
break;
}
$w *= 36 - $t;
}
$bias = self::adapt($i - $oldi, ++$outputLength, 0 === $oldi);
$n = $n + (int) ($i / $outputLength);
$i = $i % $outputLength;
$output = mb_substr($output, 0, $i, 'utf-8').mb_chr($n, 'utf-8').mb_substr($output, $i, $outputLength - 1, 'utf-8');
++$i;
}
return $output;
}
}

View File

@ -0,0 +1,19 @@
Copyright (c) 2018-2019 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -0,0 +1,141 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Symfony\Polyfill\Intl\Idn as p;
if (extension_loaded('intl')) {
return;
}
if (!defined('U_IDNA_PROHIBITED_ERROR')) {
define('U_IDNA_PROHIBITED_ERROR', 66560);
}
if (!defined('U_IDNA_ERROR_START')) {
define('U_IDNA_ERROR_START', 66560);
}
if (!defined('U_IDNA_UNASSIGNED_ERROR')) {
define('U_IDNA_UNASSIGNED_ERROR', 66561);
}
if (!defined('U_IDNA_CHECK_BIDI_ERROR')) {
define('U_IDNA_CHECK_BIDI_ERROR', 66562);
}
if (!defined('U_IDNA_STD3_ASCII_RULES_ERROR')) {
define('U_IDNA_STD3_ASCII_RULES_ERROR', 66563);
}
if (!defined('U_IDNA_ACE_PREFIX_ERROR')) {
define('U_IDNA_ACE_PREFIX_ERROR', 66564);
}
if (!defined('U_IDNA_VERIFICATION_ERROR')) {
define('U_IDNA_VERIFICATION_ERROR', 66565);
}
if (!defined('U_IDNA_LABEL_TOO_LONG_ERROR')) {
define('U_IDNA_LABEL_TOO_LONG_ERROR', 66566);
}
if (!defined('U_IDNA_ZERO_LENGTH_LABEL_ERROR')) {
define('U_IDNA_ZERO_LENGTH_LABEL_ERROR', 66567);
}
if (!defined('U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR')) {
define('U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR', 66568);
}
if (!defined('U_IDNA_ERROR_LIMIT')) {
define('U_IDNA_ERROR_LIMIT', 66569);
}
if (!defined('U_STRINGPREP_PROHIBITED_ERROR')) {
define('U_STRINGPREP_PROHIBITED_ERROR', 66560);
}
if (!defined('U_STRINGPREP_UNASSIGNED_ERROR')) {
define('U_STRINGPREP_UNASSIGNED_ERROR', 66561);
}
if (!defined('U_STRINGPREP_CHECK_BIDI_ERROR')) {
define('U_STRINGPREP_CHECK_BIDI_ERROR', 66562);
}
if (!defined('IDNA_DEFAULT')) {
define('IDNA_DEFAULT', 0);
}
if (!defined('IDNA_ALLOW_UNASSIGNED')) {
define('IDNA_ALLOW_UNASSIGNED', 1);
}
if (!defined('IDNA_USE_STD3_RULES')) {
define('IDNA_USE_STD3_RULES', 2);
}
if (!defined('IDNA_CHECK_BIDI')) {
define('IDNA_CHECK_BIDI', 4);
}
if (!defined('IDNA_CHECK_CONTEXTJ')) {
define('IDNA_CHECK_CONTEXTJ', 8);
}
if (!defined('IDNA_NONTRANSITIONAL_TO_ASCII')) {
define('IDNA_NONTRANSITIONAL_TO_ASCII', 16);
}
if (!defined('IDNA_NONTRANSITIONAL_TO_UNICODE')) {
define('IDNA_NONTRANSITIONAL_TO_UNICODE', 32);
}
if (!defined('INTL_IDNA_VARIANT_2003')) {
define('INTL_IDNA_VARIANT_2003', 0);
}
if (!defined('INTL_IDNA_VARIANT_UTS46')) {
define('INTL_IDNA_VARIANT_UTS46', 1);
}
if (!defined('IDNA_ERROR_EMPTY_LABEL')) {
define('IDNA_ERROR_EMPTY_LABEL', 1);
}
if (!defined('IDNA_ERROR_LABEL_TOO_LONG')) {
define('IDNA_ERROR_LABEL_TOO_LONG', 2);
}
if (!defined('IDNA_ERROR_DOMAIN_NAME_TOO_LONG')) {
define('IDNA_ERROR_DOMAIN_NAME_TOO_LONG', 4);
}
if (!defined('IDNA_ERROR_LEADING_HYPHEN')) {
define('IDNA_ERROR_LEADING_HYPHEN', 8);
}
if (!defined('IDNA_ERROR_TRAILING_HYPHEN')) {
define('IDNA_ERROR_TRAILING_HYPHEN', 16);
}
if (!defined('IDNA_ERROR_HYPHEN_3_4')) {
define('IDNA_ERROR_HYPHEN_3_4', 32);
}
if (!defined('IDNA_ERROR_LEADING_COMBINING_MARK')) {
define('IDNA_ERROR_LEADING_COMBINING_MARK', 64);
}
if (!defined('IDNA_ERROR_DISALLOWED')) {
define('IDNA_ERROR_DISALLOWED', 128);
}
if (!defined('IDNA_ERROR_PUNYCODE')) {
define('IDNA_ERROR_PUNYCODE', 256);
}
if (!defined('IDNA_ERROR_LABEL_HAS_DOT')) {
define('IDNA_ERROR_LABEL_HAS_DOT', 512);
}
if (!defined('IDNA_ERROR_INVALID_ACE_LABEL')) {
define('IDNA_ERROR_INVALID_ACE_LABEL', 1024);
}
if (!defined('IDNA_ERROR_BIDI')) {
define('IDNA_ERROR_BIDI', 2048);
}
if (!defined('IDNA_ERROR_CONTEXTJ')) {
define('IDNA_ERROR_CONTEXTJ', 4096);
}
if (PHP_VERSION_ID < 70400) {
if (!function_exists('idn_to_ascii')) {
function idn_to_ascii($domain, $options = IDNA_DEFAULT, $variant = INTL_IDNA_VARIANT_2003, &$idna_info = array()) { return p\Idn::idn_to_ascii($domain, $options, $variant, $idna_info); }
}
if (!function_exists('idn_to_utf8')) {
function idn_to_utf8($domain, $options = IDNA_DEFAULT, $variant = INTL_IDNA_VARIANT_2003, &$idna_info = array()) { return p\Idn::idn_to_utf8($domain, $options, $variant, $idna_info); }
}
} else {
if (!function_exists('idn_to_ascii')) {
function idn_to_ascii($domain, $options = IDNA_DEFAULT, $variant = INTL_IDNA_VARIANT_UTS46, &$idna_info = array()) { return p\Idn::idn_to_ascii($domain, $options, $variant, $idna_info); }
}
if (!function_exists('idn_to_utf8')) {
function idn_to_utf8($domain, $options = IDNA_DEFAULT, $variant = INTL_IDNA_VARIANT_UTS46, &$idna_info = array()) { return p\Idn::idn_to_utf8($domain, $options, $variant, $idna_info); }
}
}

Some files were not shown because too many files have changed in this diff Show More