updated plugin WP Mail SMTP
version 2.1.1
This commit is contained in:
@ -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',
|
||||
);
|
||||
|
@ -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'),
|
||||
|
@ -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',
|
||||
|
@ -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(
|
||||
|
@ -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())
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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())
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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())
|
||||
|
@ -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)) {
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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(
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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(
|
||||
|
@ -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);
|
||||
|
@ -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 = [])
|
||||
|
@ -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 = [])
|
||||
{
|
||||
|
@ -89,7 +89,6 @@ class AuthTokenMiddleware
|
||||
* $res = $client->get('myproject/taskqueues/myqueue');
|
||||
*
|
||||
* @param callable $handler
|
||||
*
|
||||
* @return \Closure
|
||||
*/
|
||||
public function __invoke(callable $handler)
|
||||
|
@ -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)
|
||||
|
@ -71,7 +71,6 @@ class SimpleMiddleware
|
||||
* $res = $client->get('drive/v2/rest');
|
||||
*
|
||||
* @param callable $handler
|
||||
*
|
||||
* @return \Closure
|
||||
*/
|
||||
public function __invoke(callable $handler)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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 '
|
||||
|
@ -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.
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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}"
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
[]
|
||||
);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -168,6 +168,11 @@ class MessageFormatter
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get headers from message as string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function headers(MessageInterface $message)
|
||||
{
|
||||
$result = '';
|
||||
|
@ -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])) {
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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()
|
||||
{
|
||||
|
89
wp-content/plugins/wp-mail-smtp/vendor/guzzlehttp/guzzle/src/Utils.php
vendored
Normal file
89
wp-content/plugins/wp-mail-smtp/vendor/guzzlehttp/guzzle/src/Utils.php
vendored
Normal 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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -14,7 +14,6 @@ namespace Monolog;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\LogLevel;
|
||||
use Monolog\Handler\AbstractHandler;
|
||||
use Monolog\Registry;
|
||||
|
||||
/**
|
||||
* Monolog error handler
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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}';
|
||||
|
@ -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.');
|
||||
}
|
||||
|
@ -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],
|
||||
|
@ -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
|
||||
*
|
||||
|
287
wp-content/plugins/wp-mail-smtp/vendor/symfony/polyfill-intl-idn/Idn.php
vendored
Normal file
287
wp-content/plugins/wp-mail-smtp/vendor/symfony/polyfill-intl-idn/Idn.php
vendored
Normal 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;
|
||||
}
|
||||
}
|
19
wp-content/plugins/wp-mail-smtp/vendor/symfony/polyfill-intl-idn/LICENSE
vendored
Normal file
19
wp-content/plugins/wp-mail-smtp/vendor/symfony/polyfill-intl-idn/LICENSE
vendored
Normal 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.
|
141
wp-content/plugins/wp-mail-smtp/vendor/symfony/polyfill-intl-idn/bootstrap.php
vendored
Normal file
141
wp-content/plugins/wp-mail-smtp/vendor/symfony/polyfill-intl-idn/bootstrap.php
vendored
Normal 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); }
|
||||
}
|
||||
}
|
19
wp-content/plugins/wp-mail-smtp/vendor/symfony/polyfill-mbstring/LICENSE
vendored
Normal file
19
wp-content/plugins/wp-mail-smtp/vendor/symfony/polyfill-mbstring/LICENSE
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (c) 2015-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.
|
847
wp-content/plugins/wp-mail-smtp/vendor/symfony/polyfill-mbstring/Mbstring.php
vendored
Normal file
847
wp-content/plugins/wp-mail-smtp/vendor/symfony/polyfill-mbstring/Mbstring.php
vendored
Normal file
@ -0,0 +1,847 @@
|
||||
<?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.
|
||||
*/
|
||||
|
||||
namespace Symfony\Polyfill\Mbstring;
|
||||
|
||||
/**
|
||||
* Partial mbstring implementation in PHP, iconv based, UTF-8 centric.
|
||||
*
|
||||
* Implemented:
|
||||
* - mb_chr - Returns a specific character from its Unicode code point
|
||||
* - mb_convert_encoding - Convert character encoding
|
||||
* - mb_convert_variables - Convert character code in variable(s)
|
||||
* - mb_decode_mimeheader - Decode string in MIME header field
|
||||
* - mb_encode_mimeheader - Encode string for MIME header XXX NATIVE IMPLEMENTATION IS REALLY BUGGED
|
||||
* - mb_decode_numericentity - Decode HTML numeric string reference to character
|
||||
* - mb_encode_numericentity - Encode character to HTML numeric string reference
|
||||
* - mb_convert_case - Perform case folding on a string
|
||||
* - mb_detect_encoding - Detect character encoding
|
||||
* - mb_get_info - Get internal settings of mbstring
|
||||
* - mb_http_input - Detect HTTP input character encoding
|
||||
* - mb_http_output - Set/Get HTTP output character encoding
|
||||
* - mb_internal_encoding - Set/Get internal character encoding
|
||||
* - mb_list_encodings - Returns an array of all supported encodings
|
||||
* - mb_ord - Returns the Unicode code point of a character
|
||||
* - mb_output_handler - Callback function converts character encoding in output buffer
|
||||
* - mb_scrub - Replaces ill-formed byte sequences with substitute characters
|
||||
* - mb_strlen - Get string length
|
||||
* - mb_strpos - Find position of first occurrence of string in a string
|
||||
* - mb_strrpos - Find position of last occurrence of a string in a string
|
||||
* - mb_str_split - Convert a string to an array
|
||||
* - mb_strtolower - Make a string lowercase
|
||||
* - mb_strtoupper - Make a string uppercase
|
||||
* - mb_substitute_character - Set/Get substitution character
|
||||
* - mb_substr - Get part of string
|
||||
* - mb_stripos - Finds position of first occurrence of a string within another, case insensitive
|
||||
* - mb_stristr - Finds first occurrence of a string within another, case insensitive
|
||||
* - mb_strrchr - Finds the last occurrence of a character in a string within another
|
||||
* - mb_strrichr - Finds the last occurrence of a character in a string within another, case insensitive
|
||||
* - mb_strripos - Finds position of last occurrence of a string within another, case insensitive
|
||||
* - mb_strstr - Finds first occurrence of a string within another
|
||||
* - mb_strwidth - Return width of string
|
||||
* - mb_substr_count - Count the number of substring occurrences
|
||||
*
|
||||
* Not implemented:
|
||||
* - mb_convert_kana - Convert "kana" one from another ("zen-kaku", "han-kaku" and more)
|
||||
* - mb_ereg_* - Regular expression with multibyte support
|
||||
* - mb_parse_str - Parse GET/POST/COOKIE data and set global variable
|
||||
* - mb_preferred_mime_name - Get MIME charset string
|
||||
* - mb_regex_encoding - Returns current encoding for multibyte regex as string
|
||||
* - mb_regex_set_options - Set/Get the default options for mbregex functions
|
||||
* - mb_send_mail - Send encoded mail
|
||||
* - mb_split - Split multibyte string using regular expression
|
||||
* - mb_strcut - Get part of string
|
||||
* - mb_strimwidth - Get truncated string with specified width
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class Mbstring
|
||||
{
|
||||
const MB_CASE_FOLD = PHP_INT_MAX;
|
||||
|
||||
private static $encodingList = array('ASCII', 'UTF-8');
|
||||
private static $language = 'neutral';
|
||||
private static $internalEncoding = 'UTF-8';
|
||||
private static $caseFold = array(
|
||||
array('µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"),
|
||||
array('μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'),
|
||||
);
|
||||
|
||||
public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null)
|
||||
{
|
||||
if (\is_array($fromEncoding) || false !== strpos($fromEncoding, ',')) {
|
||||
$fromEncoding = self::mb_detect_encoding($s, $fromEncoding);
|
||||
} else {
|
||||
$fromEncoding = self::getEncoding($fromEncoding);
|
||||
}
|
||||
|
||||
$toEncoding = self::getEncoding($toEncoding);
|
||||
|
||||
if ('BASE64' === $fromEncoding) {
|
||||
$s = base64_decode($s);
|
||||
$fromEncoding = $toEncoding;
|
||||
}
|
||||
|
||||
if ('BASE64' === $toEncoding) {
|
||||
return base64_encode($s);
|
||||
}
|
||||
|
||||
if ('HTML-ENTITIES' === $toEncoding || 'HTML' === $toEncoding) {
|
||||
if ('HTML-ENTITIES' === $fromEncoding || 'HTML' === $fromEncoding) {
|
||||
$fromEncoding = 'Windows-1252';
|
||||
}
|
||||
if ('UTF-8' !== $fromEncoding) {
|
||||
$s = iconv($fromEncoding, 'UTF-8//IGNORE', $s);
|
||||
}
|
||||
|
||||
return preg_replace_callback('/[\x80-\xFF]+/', array(__CLASS__, 'html_encoding_callback'), $s);
|
||||
}
|
||||
|
||||
if ('HTML-ENTITIES' === $fromEncoding) {
|
||||
$s = html_entity_decode($s, ENT_COMPAT, 'UTF-8');
|
||||
$fromEncoding = 'UTF-8';
|
||||
}
|
||||
|
||||
return iconv($fromEncoding, $toEncoding.'//IGNORE', $s);
|
||||
}
|
||||
|
||||
public static function mb_convert_variables($toEncoding, $fromEncoding, &$a = null, &$b = null, &$c = null, &$d = null, &$e = null, &$f = null)
|
||||
{
|
||||
$vars = array(&$a, &$b, &$c, &$d, &$e, &$f);
|
||||
|
||||
$ok = true;
|
||||
array_walk_recursive($vars, function (&$v) use (&$ok, $toEncoding, $fromEncoding) {
|
||||
if (false === $v = Mbstring::mb_convert_encoding($v, $toEncoding, $fromEncoding)) {
|
||||
$ok = false;
|
||||
}
|
||||
});
|
||||
|
||||
return $ok ? $fromEncoding : false;
|
||||
}
|
||||
|
||||
public static function mb_decode_mimeheader($s)
|
||||
{
|
||||
return iconv_mime_decode($s, 2, self::$internalEncoding);
|
||||
}
|
||||
|
||||
public static function mb_encode_mimeheader($s, $charset = null, $transferEncoding = null, $linefeed = null, $indent = null)
|
||||
{
|
||||
trigger_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', E_USER_WARNING);
|
||||
}
|
||||
|
||||
public static function mb_decode_numericentity($s, $convmap, $encoding = null)
|
||||
{
|
||||
if (null !== $s && !\is_scalar($s) && !(\is_object($s) && \method_exists($s, '__toString'))) {
|
||||
trigger_error('mb_decode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', E_USER_WARNING);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!\is_array($convmap) || !$convmap) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (null !== $encoding && !\is_scalar($encoding)) {
|
||||
trigger_error('mb_decode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', E_USER_WARNING);
|
||||
|
||||
return ''; // Instead of null (cf. mb_encode_numericentity).
|
||||
}
|
||||
|
||||
$s = (string) $s;
|
||||
if ('' === $s) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$encoding = self::getEncoding($encoding);
|
||||
|
||||
if ('UTF-8' === $encoding) {
|
||||
$encoding = null;
|
||||
if (!preg_match('//u', $s)) {
|
||||
$s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
|
||||
}
|
||||
} else {
|
||||
$s = iconv($encoding, 'UTF-8//IGNORE', $s);
|
||||
}
|
||||
|
||||
$cnt = floor(\count($convmap) / 4) * 4;
|
||||
|
||||
for ($i = 0; $i < $cnt; $i += 4) {
|
||||
// collector_decode_htmlnumericentity ignores $convmap[$i + 3]
|
||||
$convmap[$i] += $convmap[$i + 2];
|
||||
$convmap[$i + 1] += $convmap[$i + 2];
|
||||
}
|
||||
|
||||
$s = preg_replace_callback('/&#(?:0*([0-9]+)|x0*([0-9a-fA-F]+))(?!&);?/', function (array $m) use ($cnt, $convmap) {
|
||||
$c = isset($m[2]) ? (int) hexdec($m[2]) : $m[1];
|
||||
for ($i = 0; $i < $cnt; $i += 4) {
|
||||
if ($c >= $convmap[$i] && $c <= $convmap[$i + 1]) {
|
||||
return Mbstring::mb_chr($c - $convmap[$i + 2]);
|
||||
}
|
||||
}
|
||||
|
||||
return $m[0];
|
||||
}, $s);
|
||||
|
||||
if (null === $encoding) {
|
||||
return $s;
|
||||
}
|
||||
|
||||
return iconv('UTF-8', $encoding.'//IGNORE', $s);
|
||||
}
|
||||
|
||||
public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = false)
|
||||
{
|
||||
if (null !== $s && !\is_scalar($s) && !(\is_object($s) && \method_exists($s, '__toString'))) {
|
||||
trigger_error('mb_encode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', E_USER_WARNING);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!\is_array($convmap) || !$convmap) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (null !== $encoding && !\is_scalar($encoding)) {
|
||||
trigger_error('mb_encode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', E_USER_WARNING);
|
||||
|
||||
return null; // Instead of '' (cf. mb_decode_numericentity).
|
||||
}
|
||||
|
||||
if (null !== $is_hex && !\is_scalar($is_hex)) {
|
||||
trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, '.\gettype($s).' given', E_USER_WARNING);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$s = (string) $s;
|
||||
if ('' === $s) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$encoding = self::getEncoding($encoding);
|
||||
|
||||
if ('UTF-8' === $encoding) {
|
||||
$encoding = null;
|
||||
if (!preg_match('//u', $s)) {
|
||||
$s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
|
||||
}
|
||||
} else {
|
||||
$s = iconv($encoding, 'UTF-8//IGNORE', $s);
|
||||
}
|
||||
|
||||
static $ulenMask = array("\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4);
|
||||
|
||||
$cnt = floor(\count($convmap) / 4) * 4;
|
||||
$i = 0;
|
||||
$len = \strlen($s);
|
||||
$result = '';
|
||||
|
||||
while ($i < $len) {
|
||||
$ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
|
||||
$uchr = substr($s, $i, $ulen);
|
||||
$i += $ulen;
|
||||
$c = self::mb_ord($uchr);
|
||||
|
||||
for ($j = 0; $j < $cnt; $j += 4) {
|
||||
if ($c >= $convmap[$j] && $c <= $convmap[$j + 1]) {
|
||||
$cOffset = ($c + $convmap[$j + 2]) & $convmap[$j + 3];
|
||||
$result .= $is_hex ? sprintf('&#x%X;', $cOffset) : '&#'.$cOffset.';';
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
$result .= $uchr;
|
||||
}
|
||||
|
||||
if (null === $encoding) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return iconv('UTF-8', $encoding.'//IGNORE', $result);
|
||||
}
|
||||
|
||||
public static function mb_convert_case($s, $mode, $encoding = null)
|
||||
{
|
||||
$s = (string) $s;
|
||||
if ('' === $s) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$encoding = self::getEncoding($encoding);
|
||||
|
||||
if ('UTF-8' === $encoding) {
|
||||
$encoding = null;
|
||||
if (!preg_match('//u', $s)) {
|
||||
$s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
|
||||
}
|
||||
} else {
|
||||
$s = iconv($encoding, 'UTF-8//IGNORE', $s);
|
||||
}
|
||||
|
||||
if (MB_CASE_TITLE == $mode) {
|
||||
static $titleRegexp = null;
|
||||
if (null === $titleRegexp) {
|
||||
$titleRegexp = self::getData('titleCaseRegexp');
|
||||
}
|
||||
$s = preg_replace_callback($titleRegexp, array(__CLASS__, 'title_case'), $s);
|
||||
} else {
|
||||
if (MB_CASE_UPPER == $mode) {
|
||||
static $upper = null;
|
||||
if (null === $upper) {
|
||||
$upper = self::getData('upperCase');
|
||||
}
|
||||
$map = $upper;
|
||||
} else {
|
||||
if (self::MB_CASE_FOLD === $mode) {
|
||||
$s = str_replace(self::$caseFold[0], self::$caseFold[1], $s);
|
||||
}
|
||||
|
||||
static $lower = null;
|
||||
if (null === $lower) {
|
||||
$lower = self::getData('lowerCase');
|
||||
}
|
||||
$map = $lower;
|
||||
}
|
||||
|
||||
static $ulenMask = array("\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4);
|
||||
|
||||
$i = 0;
|
||||
$len = \strlen($s);
|
||||
|
||||
while ($i < $len) {
|
||||
$ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
|
||||
$uchr = substr($s, $i, $ulen);
|
||||
$i += $ulen;
|
||||
|
||||
if (isset($map[$uchr])) {
|
||||
$uchr = $map[$uchr];
|
||||
$nlen = \strlen($uchr);
|
||||
|
||||
if ($nlen == $ulen) {
|
||||
$nlen = $i;
|
||||
do {
|
||||
$s[--$nlen] = $uchr[--$ulen];
|
||||
} while ($ulen);
|
||||
} else {
|
||||
$s = substr_replace($s, $uchr, $i - $ulen, $ulen);
|
||||
$len += $nlen - $ulen;
|
||||
$i += $nlen - $ulen;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (null === $encoding) {
|
||||
return $s;
|
||||
}
|
||||
|
||||
return iconv('UTF-8', $encoding.'//IGNORE', $s);
|
||||
}
|
||||
|
||||
public static function mb_internal_encoding($encoding = null)
|
||||
{
|
||||
if (null === $encoding) {
|
||||
return self::$internalEncoding;
|
||||
}
|
||||
|
||||
$encoding = self::getEncoding($encoding);
|
||||
|
||||
if ('UTF-8' === $encoding || false !== @iconv($encoding, $encoding, ' ')) {
|
||||
self::$internalEncoding = $encoding;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function mb_language($lang = null)
|
||||
{
|
||||
if (null === $lang) {
|
||||
return self::$language;
|
||||
}
|
||||
|
||||
switch ($lang = strtolower($lang)) {
|
||||
case 'uni':
|
||||
case 'neutral':
|
||||
self::$language = $lang;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function mb_list_encodings()
|
||||
{
|
||||
return array('UTF-8');
|
||||
}
|
||||
|
||||
public static function mb_encoding_aliases($encoding)
|
||||
{
|
||||
switch (strtoupper($encoding)) {
|
||||
case 'UTF8':
|
||||
case 'UTF-8':
|
||||
return array('utf8');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function mb_check_encoding($var = null, $encoding = null)
|
||||
{
|
||||
if (null === $encoding) {
|
||||
if (null === $var) {
|
||||
return false;
|
||||
}
|
||||
$encoding = self::$internalEncoding;
|
||||
}
|
||||
|
||||
return self::mb_detect_encoding($var, array($encoding)) || false !== @iconv($encoding, $encoding, $var);
|
||||
}
|
||||
|
||||
public static function mb_detect_encoding($str, $encodingList = null, $strict = false)
|
||||
{
|
||||
if (null === $encodingList) {
|
||||
$encodingList = self::$encodingList;
|
||||
} else {
|
||||
if (!\is_array($encodingList)) {
|
||||
$encodingList = array_map('trim', explode(',', $encodingList));
|
||||
}
|
||||
$encodingList = array_map('strtoupper', $encodingList);
|
||||
}
|
||||
|
||||
foreach ($encodingList as $enc) {
|
||||
switch ($enc) {
|
||||
case 'ASCII':
|
||||
if (!preg_match('/[\x80-\xFF]/', $str)) {
|
||||
return $enc;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'UTF8':
|
||||
case 'UTF-8':
|
||||
if (preg_match('//u', $str)) {
|
||||
return 'UTF-8';
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (0 === strncmp($enc, 'ISO-8859-', 9)) {
|
||||
return $enc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function mb_detect_order($encodingList = null)
|
||||
{
|
||||
if (null === $encodingList) {
|
||||
return self::$encodingList;
|
||||
}
|
||||
|
||||
if (!\is_array($encodingList)) {
|
||||
$encodingList = array_map('trim', explode(',', $encodingList));
|
||||
}
|
||||
$encodingList = array_map('strtoupper', $encodingList);
|
||||
|
||||
foreach ($encodingList as $enc) {
|
||||
switch ($enc) {
|
||||
default:
|
||||
if (strncmp($enc, 'ISO-8859-', 9)) {
|
||||
return false;
|
||||
}
|
||||
// no break
|
||||
case 'ASCII':
|
||||
case 'UTF8':
|
||||
case 'UTF-8':
|
||||
}
|
||||
}
|
||||
|
||||
self::$encodingList = $encodingList;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function mb_strlen($s, $encoding = null)
|
||||
{
|
||||
$encoding = self::getEncoding($encoding);
|
||||
if ('CP850' === $encoding || 'ASCII' === $encoding) {
|
||||
return \strlen($s);
|
||||
}
|
||||
|
||||
return @iconv_strlen($s, $encoding);
|
||||
}
|
||||
|
||||
public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null)
|
||||
{
|
||||
$encoding = self::getEncoding($encoding);
|
||||
if ('CP850' === $encoding || 'ASCII' === $encoding) {
|
||||
return strpos($haystack, $needle, $offset);
|
||||
}
|
||||
|
||||
$needle = (string) $needle;
|
||||
if ('' === $needle) {
|
||||
trigger_error(__METHOD__.': Empty delimiter', E_USER_WARNING);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return iconv_strpos($haystack, $needle, $offset, $encoding);
|
||||
}
|
||||
|
||||
public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null)
|
||||
{
|
||||
$encoding = self::getEncoding($encoding);
|
||||
if ('CP850' === $encoding || 'ASCII' === $encoding) {
|
||||
return strrpos($haystack, $needle, $offset);
|
||||
}
|
||||
|
||||
if ($offset != (int) $offset) {
|
||||
$offset = 0;
|
||||
} elseif ($offset = (int) $offset) {
|
||||
if ($offset < 0) {
|
||||
if (0 > $offset += self::mb_strlen($needle)) {
|
||||
$haystack = self::mb_substr($haystack, 0, $offset, $encoding);
|
||||
}
|
||||
$offset = 0;
|
||||
} else {
|
||||
$haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding);
|
||||
}
|
||||
}
|
||||
|
||||
$pos = iconv_strrpos($haystack, $needle, $encoding);
|
||||
|
||||
return false !== $pos ? $offset + $pos : false;
|
||||
}
|
||||
|
||||
public static function mb_str_split($string, $split_length = 1, $encoding = null)
|
||||
{
|
||||
if (null !== $string && !\is_scalar($string) && !(\is_object($string) && \method_exists($string, '__toString'))) {
|
||||
trigger_error('mb_str_split() expects parameter 1 to be string, '.\gettype($string).' given', E_USER_WARNING);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (1 > $split_length = (int) $split_length) {
|
||||
trigger_error('The length of each segment must be greater than zero', E_USER_WARNING);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (null === $encoding) {
|
||||
$encoding = mb_internal_encoding();
|
||||
}
|
||||
|
||||
if ('UTF-8' === $encoding = self::getEncoding($encoding)) {
|
||||
$rx = '/(';
|
||||
while (65535 < $split_length) {
|
||||
$rx .= '.{65535}';
|
||||
$split_length -= 65535;
|
||||
}
|
||||
$rx .= '.{'.$split_length.'})/us';
|
||||
|
||||
return preg_split($rx, $string, null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
|
||||
}
|
||||
|
||||
$result = array();
|
||||
$length = mb_strlen($string, $encoding);
|
||||
|
||||
for ($i = 0; $i < $length; $i += $split_length) {
|
||||
$result[] = mb_substr($string, $i, $split_length, $encoding);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function mb_strtolower($s, $encoding = null)
|
||||
{
|
||||
return self::mb_convert_case($s, MB_CASE_LOWER, $encoding);
|
||||
}
|
||||
|
||||
public static function mb_strtoupper($s, $encoding = null)
|
||||
{
|
||||
return self::mb_convert_case($s, MB_CASE_UPPER, $encoding);
|
||||
}
|
||||
|
||||
public static function mb_substitute_character($c = null)
|
||||
{
|
||||
if (0 === strcasecmp($c, 'none')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return null !== $c ? false : 'none';
|
||||
}
|
||||
|
||||
public static function mb_substr($s, $start, $length = null, $encoding = null)
|
||||
{
|
||||
$encoding = self::getEncoding($encoding);
|
||||
if ('CP850' === $encoding || 'ASCII' === $encoding) {
|
||||
return (string) substr($s, $start, null === $length ? 2147483647 : $length);
|
||||
}
|
||||
|
||||
if ($start < 0) {
|
||||
$start = iconv_strlen($s, $encoding) + $start;
|
||||
if ($start < 0) {
|
||||
$start = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (null === $length) {
|
||||
$length = 2147483647;
|
||||
} elseif ($length < 0) {
|
||||
$length = iconv_strlen($s, $encoding) + $length - $start;
|
||||
if ($length < 0) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
return (string) iconv_substr($s, $start, $length, $encoding);
|
||||
}
|
||||
|
||||
public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null)
|
||||
{
|
||||
$haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding);
|
||||
$needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding);
|
||||
|
||||
return self::mb_strpos($haystack, $needle, $offset, $encoding);
|
||||
}
|
||||
|
||||
public static function mb_stristr($haystack, $needle, $part = false, $encoding = null)
|
||||
{
|
||||
$pos = self::mb_stripos($haystack, $needle, 0, $encoding);
|
||||
|
||||
return self::getSubpart($pos, $part, $haystack, $encoding);
|
||||
}
|
||||
|
||||
public static function mb_strrchr($haystack, $needle, $part = false, $encoding = null)
|
||||
{
|
||||
$encoding = self::getEncoding($encoding);
|
||||
if ('CP850' === $encoding || 'ASCII' === $encoding) {
|
||||
return strrchr($haystack, $needle, $part);
|
||||
}
|
||||
$needle = self::mb_substr($needle, 0, 1, $encoding);
|
||||
$pos = iconv_strrpos($haystack, $needle, $encoding);
|
||||
|
||||
return self::getSubpart($pos, $part, $haystack, $encoding);
|
||||
}
|
||||
|
||||
public static function mb_strrichr($haystack, $needle, $part = false, $encoding = null)
|
||||
{
|
||||
$needle = self::mb_substr($needle, 0, 1, $encoding);
|
||||
$pos = self::mb_strripos($haystack, $needle, $encoding);
|
||||
|
||||
return self::getSubpart($pos, $part, $haystack, $encoding);
|
||||
}
|
||||
|
||||
public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null)
|
||||
{
|
||||
$haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding);
|
||||
$needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding);
|
||||
|
||||
return self::mb_strrpos($haystack, $needle, $offset, $encoding);
|
||||
}
|
||||
|
||||
public static function mb_strstr($haystack, $needle, $part = false, $encoding = null)
|
||||
{
|
||||
$pos = strpos($haystack, $needle);
|
||||
if (false === $pos) {
|
||||
return false;
|
||||
}
|
||||
if ($part) {
|
||||
return substr($haystack, 0, $pos);
|
||||
}
|
||||
|
||||
return substr($haystack, $pos);
|
||||
}
|
||||
|
||||
public static function mb_get_info($type = 'all')
|
||||
{
|
||||
$info = array(
|
||||
'internal_encoding' => self::$internalEncoding,
|
||||
'http_output' => 'pass',
|
||||
'http_output_conv_mimetypes' => '^(text/|application/xhtml\+xml)',
|
||||
'func_overload' => 0,
|
||||
'func_overload_list' => 'no overload',
|
||||
'mail_charset' => 'UTF-8',
|
||||
'mail_header_encoding' => 'BASE64',
|
||||
'mail_body_encoding' => 'BASE64',
|
||||
'illegal_chars' => 0,
|
||||
'encoding_translation' => 'Off',
|
||||
'language' => self::$language,
|
||||
'detect_order' => self::$encodingList,
|
||||
'substitute_character' => 'none',
|
||||
'strict_detection' => 'Off',
|
||||
);
|
||||
|
||||
if ('all' === $type) {
|
||||
return $info;
|
||||
}
|
||||
if (isset($info[$type])) {
|
||||
return $info[$type];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function mb_http_input($type = '')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function mb_http_output($encoding = null)
|
||||
{
|
||||
return null !== $encoding ? 'pass' === $encoding : 'pass';
|
||||
}
|
||||
|
||||
public static function mb_strwidth($s, $encoding = null)
|
||||
{
|
||||
$encoding = self::getEncoding($encoding);
|
||||
|
||||
if ('UTF-8' !== $encoding) {
|
||||
$s = iconv($encoding, 'UTF-8//IGNORE', $s);
|
||||
}
|
||||
|
||||
$s = preg_replace('/[\x{1100}-\x{115F}\x{2329}\x{232A}\x{2E80}-\x{303E}\x{3040}-\x{A4CF}\x{AC00}-\x{D7A3}\x{F900}-\x{FAFF}\x{FE10}-\x{FE19}\x{FE30}-\x{FE6F}\x{FF00}-\x{FF60}\x{FFE0}-\x{FFE6}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}]/u', '', $s, -1, $wide);
|
||||
|
||||
return ($wide << 1) + iconv_strlen($s, 'UTF-8');
|
||||
}
|
||||
|
||||
public static function mb_substr_count($haystack, $needle, $encoding = null)
|
||||
{
|
||||
return substr_count($haystack, $needle);
|
||||
}
|
||||
|
||||
public static function mb_output_handler($contents, $status)
|
||||
{
|
||||
return $contents;
|
||||
}
|
||||
|
||||
public static function mb_chr($code, $encoding = null)
|
||||
{
|
||||
if (0x80 > $code %= 0x200000) {
|
||||
$s = \chr($code);
|
||||
} elseif (0x800 > $code) {
|
||||
$s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F);
|
||||
} elseif (0x10000 > $code) {
|
||||
$s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
|
||||
} else {
|
||||
$s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
|
||||
}
|
||||
|
||||
if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
|
||||
$s = mb_convert_encoding($s, $encoding, 'UTF-8');
|
||||
}
|
||||
|
||||
return $s;
|
||||
}
|
||||
|
||||
public static function mb_ord($s, $encoding = null)
|
||||
{
|
||||
if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
|
||||
$s = mb_convert_encoding($s, 'UTF-8', $encoding);
|
||||
}
|
||||
|
||||
if (1 === \strlen($s)) {
|
||||
return \ord($s);
|
||||
}
|
||||
|
||||
$code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0;
|
||||
if (0xF0 <= $code) {
|
||||
return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80;
|
||||
}
|
||||
if (0xE0 <= $code) {
|
||||
return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80;
|
||||
}
|
||||
if (0xC0 <= $code) {
|
||||
return (($code - 0xC0) << 6) + $s[2] - 0x80;
|
||||
}
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
private static function getSubpart($pos, $part, $haystack, $encoding)
|
||||
{
|
||||
if (false === $pos) {
|
||||
return false;
|
||||
}
|
||||
if ($part) {
|
||||
return self::mb_substr($haystack, 0, $pos, $encoding);
|
||||
}
|
||||
|
||||
return self::mb_substr($haystack, $pos, null, $encoding);
|
||||
}
|
||||
|
||||
private static function html_encoding_callback(array $m)
|
||||
{
|
||||
$i = 1;
|
||||
$entities = '';
|
||||
$m = unpack('C*', htmlentities($m[0], ENT_COMPAT, 'UTF-8'));
|
||||
|
||||
while (isset($m[$i])) {
|
||||
if (0x80 > $m[$i]) {
|
||||
$entities .= \chr($m[$i++]);
|
||||
continue;
|
||||
}
|
||||
if (0xF0 <= $m[$i]) {
|
||||
$c = (($m[$i++] - 0xF0) << 18) + (($m[$i++] - 0x80) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
|
||||
} elseif (0xE0 <= $m[$i]) {
|
||||
$c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
|
||||
} else {
|
||||
$c = (($m[$i++] - 0xC0) << 6) + $m[$i++] - 0x80;
|
||||
}
|
||||
|
||||
$entities .= '&#'.$c.';';
|
||||
}
|
||||
|
||||
return $entities;
|
||||
}
|
||||
|
||||
private static function title_case(array $s)
|
||||
{
|
||||
return self::mb_convert_case($s[1], MB_CASE_UPPER, 'UTF-8').self::mb_convert_case($s[2], MB_CASE_LOWER, 'UTF-8');
|
||||
}
|
||||
|
||||
private static function getData($file)
|
||||
{
|
||||
if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) {
|
||||
return require $file;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static function getEncoding($encoding)
|
||||
{
|
||||
if (null === $encoding) {
|
||||
return self::$internalEncoding;
|
||||
}
|
||||
|
||||
if ('UTF-8' === $encoding) {
|
||||
return 'UTF-8';
|
||||
}
|
||||
|
||||
$encoding = strtoupper($encoding);
|
||||
|
||||
if ('8BIT' === $encoding || 'BINARY' === $encoding) {
|
||||
return 'CP850';
|
||||
}
|
||||
|
||||
if ('UTF8' === $encoding) {
|
||||
return 'UTF-8';
|
||||
}
|
||||
|
||||
return $encoding;
|
||||
}
|
||||
}
|
1096
wp-content/plugins/wp-mail-smtp/vendor/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php
vendored
Normal file
1096
wp-content/plugins/wp-mail-smtp/vendor/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
1104
wp-content/plugins/wp-mail-smtp/vendor/symfony/polyfill-mbstring/Resources/unidata/upperCase.php
vendored
Normal file
1104
wp-content/plugins/wp-mail-smtp/vendor/symfony/polyfill-mbstring/Resources/unidata/upperCase.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
141
wp-content/plugins/wp-mail-smtp/vendor/symfony/polyfill-mbstring/bootstrap.php
vendored
Normal file
141
wp-content/plugins/wp-mail-smtp/vendor/symfony/polyfill-mbstring/bootstrap.php
vendored
Normal 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\Mbstring as p;
|
||||
|
||||
if (!function_exists('mb_convert_encoding')) {
|
||||
function mb_convert_encoding($s, $to, $from = null) { return p\Mbstring::mb_convert_encoding($s, $to, $from); }
|
||||
}
|
||||
if (!function_exists('mb_decode_mimeheader')) {
|
||||
function mb_decode_mimeheader($s) { return p\Mbstring::mb_decode_mimeheader($s); }
|
||||
}
|
||||
if (!function_exists('mb_encode_mimeheader')) {
|
||||
function mb_encode_mimeheader($s, $charset = null, $transferEnc = null, $lf = null, $indent = null) { return p\Mbstring::mb_encode_mimeheader($s, $charset, $transferEnc, $lf, $indent); }
|
||||
}
|
||||
if (!function_exists('mb_decode_numericentity')) {
|
||||
function mb_decode_numericentity($s, $convmap, $enc = null) { return p\Mbstring::mb_decode_numericentity($s, $convmap, $enc); }
|
||||
}
|
||||
if (!function_exists('mb_encode_numericentity')) {
|
||||
function mb_encode_numericentity($s, $convmap, $enc = null, $is_hex = false) { return p\Mbstring::mb_encode_numericentity($s, $convmap, $enc, $is_hex); }
|
||||
}
|
||||
if (!function_exists('mb_convert_case')) {
|
||||
function mb_convert_case($s, $mode, $enc = null) { return p\Mbstring::mb_convert_case($s, $mode, $enc); }
|
||||
}
|
||||
if (!function_exists('mb_internal_encoding')) {
|
||||
function mb_internal_encoding($enc = null) { return p\Mbstring::mb_internal_encoding($enc); }
|
||||
}
|
||||
if (!function_exists('mb_language')) {
|
||||
function mb_language($lang = null) { return p\Mbstring::mb_language($lang); }
|
||||
}
|
||||
if (!function_exists('mb_list_encodings')) {
|
||||
function mb_list_encodings() { return p\Mbstring::mb_list_encodings(); }
|
||||
}
|
||||
if (!function_exists('mb_encoding_aliases')) {
|
||||
function mb_encoding_aliases($encoding) { return p\Mbstring::mb_encoding_aliases($encoding); }
|
||||
}
|
||||
if (!function_exists('mb_check_encoding')) {
|
||||
function mb_check_encoding($var = null, $encoding = null) { return p\Mbstring::mb_check_encoding($var, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_detect_encoding')) {
|
||||
function mb_detect_encoding($str, $encodingList = null, $strict = false) { return p\Mbstring::mb_detect_encoding($str, $encodingList, $strict); }
|
||||
}
|
||||
if (!function_exists('mb_detect_order')) {
|
||||
function mb_detect_order($encodingList = null) { return p\Mbstring::mb_detect_order($encodingList); }
|
||||
}
|
||||
if (!function_exists('mb_parse_str')) {
|
||||
function mb_parse_str($s, &$result = array()) { parse_str($s, $result); }
|
||||
}
|
||||
if (!function_exists('mb_strlen')) {
|
||||
function mb_strlen($s, $enc = null) { return p\Mbstring::mb_strlen($s, $enc); }
|
||||
}
|
||||
if (!function_exists('mb_strpos')) {
|
||||
function mb_strpos($s, $needle, $offset = 0, $enc = null) { return p\Mbstring::mb_strpos($s, $needle, $offset, $enc); }
|
||||
}
|
||||
if (!function_exists('mb_strtolower')) {
|
||||
function mb_strtolower($s, $enc = null) { return p\Mbstring::mb_strtolower($s, $enc); }
|
||||
}
|
||||
if (!function_exists('mb_strtoupper')) {
|
||||
function mb_strtoupper($s, $enc = null) { return p\Mbstring::mb_strtoupper($s, $enc); }
|
||||
}
|
||||
if (!function_exists('mb_substitute_character')) {
|
||||
function mb_substitute_character($char = null) { return p\Mbstring::mb_substitute_character($char); }
|
||||
}
|
||||
if (!function_exists('mb_substr')) {
|
||||
function mb_substr($s, $start, $length = 2147483647, $enc = null) { return p\Mbstring::mb_substr($s, $start, $length, $enc); }
|
||||
}
|
||||
if (!function_exists('mb_stripos')) {
|
||||
function mb_stripos($s, $needle, $offset = 0, $enc = null) { return p\Mbstring::mb_stripos($s, $needle, $offset, $enc); }
|
||||
}
|
||||
if (!function_exists('mb_stristr')) {
|
||||
function mb_stristr($s, $needle, $part = false, $enc = null) { return p\Mbstring::mb_stristr($s, $needle, $part, $enc); }
|
||||
}
|
||||
if (!function_exists('mb_strrchr')) {
|
||||
function mb_strrchr($s, $needle, $part = false, $enc = null) { return p\Mbstring::mb_strrchr($s, $needle, $part, $enc); }
|
||||
}
|
||||
if (!function_exists('mb_strrichr')) {
|
||||
function mb_strrichr($s, $needle, $part = false, $enc = null) { return p\Mbstring::mb_strrichr($s, $needle, $part, $enc); }
|
||||
}
|
||||
if (!function_exists('mb_strripos')) {
|
||||
function mb_strripos($s, $needle, $offset = 0, $enc = null) { return p\Mbstring::mb_strripos($s, $needle, $offset, $enc); }
|
||||
}
|
||||
if (!function_exists('mb_strrpos')) {
|
||||
function mb_strrpos($s, $needle, $offset = 0, $enc = null) { return p\Mbstring::mb_strrpos($s, $needle, $offset, $enc); }
|
||||
}
|
||||
if (!function_exists('mb_strstr')) {
|
||||
function mb_strstr($s, $needle, $part = false, $enc = null) { return p\Mbstring::mb_strstr($s, $needle, $part, $enc); }
|
||||
}
|
||||
if (!function_exists('mb_get_info')) {
|
||||
function mb_get_info($type = 'all') { return p\Mbstring::mb_get_info($type); }
|
||||
}
|
||||
if (!function_exists('mb_http_output')) {
|
||||
function mb_http_output($enc = null) { return p\Mbstring::mb_http_output($enc); }
|
||||
}
|
||||
if (!function_exists('mb_strwidth')) {
|
||||
function mb_strwidth($s, $enc = null) { return p\Mbstring::mb_strwidth($s, $enc); }
|
||||
}
|
||||
if (!function_exists('mb_substr_count')) {
|
||||
function mb_substr_count($haystack, $needle, $enc = null) { return p\Mbstring::mb_substr_count($haystack, $needle, $enc); }
|
||||
}
|
||||
if (!function_exists('mb_output_handler')) {
|
||||
function mb_output_handler($contents, $status) { return p\Mbstring::mb_output_handler($contents, $status); }
|
||||
}
|
||||
if (!function_exists('mb_http_input')) {
|
||||
function mb_http_input($type = '') { return p\Mbstring::mb_http_input($type); }
|
||||
}
|
||||
if (!function_exists('mb_convert_variables')) {
|
||||
function mb_convert_variables($toEncoding, $fromEncoding, &$a = null, &$b = null, &$c = null, &$d = null, &$e = null, &$f = null) { return p\Mbstring::mb_convert_variables($toEncoding, $fromEncoding, $a, $b, $c, $d, $e, $f); }
|
||||
}
|
||||
if (!function_exists('mb_ord')) {
|
||||
function mb_ord($s, $enc = null) { return p\Mbstring::mb_ord($s, $enc); }
|
||||
}
|
||||
if (!function_exists('mb_chr')) {
|
||||
function mb_chr($code, $enc = null) { return p\Mbstring::mb_chr($code, $enc); }
|
||||
}
|
||||
if (!function_exists('mb_scrub')) {
|
||||
function mb_scrub($s, $enc = null) { $enc = null === $enc ? mb_internal_encoding() : $enc; return mb_convert_encoding($s, $enc, $enc); }
|
||||
}
|
||||
if (!function_exists('mb_str_split')) {
|
||||
function mb_str_split($string, $split_length = 1, $encoding = null) { return p\Mbstring::mb_str_split($string, $split_length, $encoding); }
|
||||
}
|
||||
|
||||
if (extension_loaded('mbstring')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!defined('MB_CASE_UPPER')) {
|
||||
define('MB_CASE_UPPER', 0);
|
||||
}
|
||||
if (!defined('MB_CASE_LOWER')) {
|
||||
define('MB_CASE_LOWER', 1);
|
||||
}
|
||||
if (!defined('MB_CASE_TITLE')) {
|
||||
define('MB_CASE_TITLE', 2);
|
||||
}
|
19
wp-content/plugins/wp-mail-smtp/vendor/symfony/polyfill-php72/LICENSE
vendored
Normal file
19
wp-content/plugins/wp-mail-smtp/vendor/symfony/polyfill-php72/LICENSE
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (c) 2015-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.
|
217
wp-content/plugins/wp-mail-smtp/vendor/symfony/polyfill-php72/Php72.php
vendored
Normal file
217
wp-content/plugins/wp-mail-smtp/vendor/symfony/polyfill-php72/Php72.php
vendored
Normal file
@ -0,0 +1,217 @@
|
||||
<?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.
|
||||
*/
|
||||
|
||||
namespace Symfony\Polyfill\Php72;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
* @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class Php72
|
||||
{
|
||||
private static $hashMask;
|
||||
|
||||
public static function utf8_encode($s)
|
||||
{
|
||||
$s .= $s;
|
||||
$len = \strlen($s);
|
||||
|
||||
for ($i = $len >> 1, $j = 0; $i < $len; ++$i, ++$j) {
|
||||
switch (true) {
|
||||
case $s[$i] < "\x80": $s[$j] = $s[$i]; break;
|
||||
case $s[$i] < "\xC0": $s[$j] = "\xC2"; $s[++$j] = $s[$i]; break;
|
||||
default: $s[$j] = "\xC3"; $s[++$j] = \chr(\ord($s[$i]) - 64); break;
|
||||
}
|
||||
}
|
||||
|
||||
return substr($s, 0, $j);
|
||||
}
|
||||
|
||||
public static function utf8_decode($s)
|
||||
{
|
||||
$s = (string) $s;
|
||||
$len = \strlen($s);
|
||||
|
||||
for ($i = 0, $j = 0; $i < $len; ++$i, ++$j) {
|
||||
switch ($s[$i] & "\xF0") {
|
||||
case "\xC0":
|
||||
case "\xD0":
|
||||
$c = (\ord($s[$i] & "\x1F") << 6) | \ord($s[++$i] & "\x3F");
|
||||
$s[$j] = $c < 256 ? \chr($c) : '?';
|
||||
break;
|
||||
|
||||
case "\xF0":
|
||||
++$i;
|
||||
// no break
|
||||
|
||||
case "\xE0":
|
||||
$s[$j] = '?';
|
||||
$i += 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
$s[$j] = $s[$i];
|
||||
}
|
||||
}
|
||||
|
||||
return substr($s, 0, $j);
|
||||
}
|
||||
|
||||
public static function php_os_family()
|
||||
{
|
||||
if ('\\' === \DIRECTORY_SEPARATOR) {
|
||||
return 'Windows';
|
||||
}
|
||||
|
||||
$map = array(
|
||||
'Darwin' => 'Darwin',
|
||||
'DragonFly' => 'BSD',
|
||||
'FreeBSD' => 'BSD',
|
||||
'NetBSD' => 'BSD',
|
||||
'OpenBSD' => 'BSD',
|
||||
'Linux' => 'Linux',
|
||||
'SunOS' => 'Solaris',
|
||||
);
|
||||
|
||||
return isset($map[PHP_OS]) ? $map[PHP_OS] : 'Unknown';
|
||||
}
|
||||
|
||||
public static function spl_object_id($object)
|
||||
{
|
||||
if (null === self::$hashMask) {
|
||||
self::initHashMask();
|
||||
}
|
||||
if (null === $hash = spl_object_hash($object)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// On 32-bit systems, PHP_INT_SIZE is 4,
|
||||
return self::$hashMask ^ hexdec(substr($hash, 16 - (\PHP_INT_SIZE * 2 - 1), (\PHP_INT_SIZE * 2 - 1)));
|
||||
}
|
||||
|
||||
public static function sapi_windows_vt100_support($stream, $enable = null)
|
||||
{
|
||||
if (!\is_resource($stream)) {
|
||||
trigger_error('sapi_windows_vt100_support() expects parameter 1 to be resource, '.\gettype($stream).' given', E_USER_WARNING);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$meta = stream_get_meta_data($stream);
|
||||
|
||||
if ('STDIO' !== $meta['stream_type']) {
|
||||
trigger_error('sapi_windows_vt100_support() was not able to analyze the specified stream', E_USER_WARNING);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// We cannot actually disable vt100 support if it is set
|
||||
if (false === $enable || !self::stream_isatty($stream)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The native function does not apply to stdin
|
||||
$meta = array_map('strtolower', $meta);
|
||||
$stdin = 'php://stdin' === $meta['uri'] || 'php://fd/0' === $meta['uri'];
|
||||
|
||||
return !$stdin
|
||||
&& (false !== getenv('ANSICON')
|
||||
|| 'ON' === getenv('ConEmuANSI')
|
||||
|| 'xterm' === getenv('TERM')
|
||||
|| 'Hyper' === getenv('TERM_PROGRAM'));
|
||||
}
|
||||
|
||||
public static function stream_isatty($stream)
|
||||
{
|
||||
if (!\is_resource($stream)) {
|
||||
trigger_error('stream_isatty() expects parameter 1 to be resource, '.\gettype($stream).' given', E_USER_WARNING);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ('\\' === \DIRECTORY_SEPARATOR) {
|
||||
$stat = @fstat($stream);
|
||||
// Check if formatted mode is S_IFCHR
|
||||
return $stat ? 0020000 === ($stat['mode'] & 0170000) : false;
|
||||
}
|
||||
|
||||
return \function_exists('posix_isatty') && @posix_isatty($stream);
|
||||
}
|
||||
|
||||
private static function initHashMask()
|
||||
{
|
||||
$obj = (object) array();
|
||||
self::$hashMask = -1;
|
||||
|
||||
// check if we are nested in an output buffering handler to prevent a fatal error with ob_start() below
|
||||
$obFuncs = array('ob_clean', 'ob_end_clean', 'ob_flush', 'ob_end_flush', 'ob_get_contents', 'ob_get_flush');
|
||||
foreach (debug_backtrace(\PHP_VERSION_ID >= 50400 ? DEBUG_BACKTRACE_IGNORE_ARGS : false) as $frame) {
|
||||
if (isset($frame['function'][0]) && !isset($frame['class']) && 'o' === $frame['function'][0] && \in_array($frame['function'], $obFuncs)) {
|
||||
$frame['line'] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!empty($frame['line'])) {
|
||||
ob_start();
|
||||
debug_zval_dump($obj);
|
||||
self::$hashMask = (int) substr(ob_get_clean(), 17);
|
||||
}
|
||||
|
||||
self::$hashMask ^= hexdec(substr(spl_object_hash($obj), 16 - (\PHP_INT_SIZE * 2 - 1), (\PHP_INT_SIZE * 2 - 1)));
|
||||
}
|
||||
|
||||
public static function mb_chr($code, $encoding = null)
|
||||
{
|
||||
if (0x80 > $code %= 0x200000) {
|
||||
$s = \chr($code);
|
||||
} elseif (0x800 > $code) {
|
||||
$s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F);
|
||||
} elseif (0x10000 > $code) {
|
||||
$s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
|
||||
} else {
|
||||
$s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
|
||||
}
|
||||
|
||||
if ('UTF-8' !== $encoding) {
|
||||
$s = mb_convert_encoding($s, $encoding, 'UTF-8');
|
||||
}
|
||||
|
||||
return $s;
|
||||
}
|
||||
|
||||
public static function mb_ord($s, $encoding = null)
|
||||
{
|
||||
if (null == $encoding) {
|
||||
$s = mb_convert_encoding($s, 'UTF-8');
|
||||
} elseif ('UTF-8' !== $encoding) {
|
||||
$s = mb_convert_encoding($s, 'UTF-8', $encoding);
|
||||
}
|
||||
|
||||
if (1 === \strlen($s)) {
|
||||
return \ord($s);
|
||||
}
|
||||
|
||||
$code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0;
|
||||
if (0xF0 <= $code) {
|
||||
return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80;
|
||||
}
|
||||
if (0xE0 <= $code) {
|
||||
return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80;
|
||||
}
|
||||
if (0xC0 <= $code) {
|
||||
return (($code - 0xC0) << 6) + $s[2] - 0x80;
|
||||
}
|
||||
|
||||
return $code;
|
||||
}
|
||||
}
|
57
wp-content/plugins/wp-mail-smtp/vendor/symfony/polyfill-php72/bootstrap.php
vendored
Normal file
57
wp-content/plugins/wp-mail-smtp/vendor/symfony/polyfill-php72/bootstrap.php
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
<?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\Php72 as p;
|
||||
|
||||
if (PHP_VERSION_ID >= 70200) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!defined('PHP_FLOAT_DIG')) {
|
||||
define('PHP_FLOAT_DIG', 15);
|
||||
}
|
||||
if (!defined('PHP_FLOAT_EPSILON')) {
|
||||
define('PHP_FLOAT_EPSILON', 2.2204460492503E-16);
|
||||
}
|
||||
if (!defined('PHP_FLOAT_MIN')) {
|
||||
define('PHP_FLOAT_MIN', 2.2250738585072E-308);
|
||||
}
|
||||
if (!defined('PHP_FLOAT_MAX')) {
|
||||
define('PHP_FLOAT_MAX', 1.7976931348623157E+308);
|
||||
}
|
||||
if (!defined('PHP_OS_FAMILY')) {
|
||||
define('PHP_OS_FAMILY', p\Php72::php_os_family());
|
||||
}
|
||||
|
||||
if ('\\' === DIRECTORY_SEPARATOR && !function_exists('sapi_windows_vt100_support')) {
|
||||
function sapi_windows_vt100_support($stream, $enable = null) { return p\Php72::sapi_windows_vt100_support($stream, $enable); }
|
||||
}
|
||||
if (!function_exists('stream_isatty')) {
|
||||
function stream_isatty($stream) { return p\Php72::stream_isatty($stream); }
|
||||
}
|
||||
if (!function_exists('utf8_encode')) {
|
||||
function utf8_encode($s) { return p\Php72::utf8_encode($s); }
|
||||
}
|
||||
if (!function_exists('utf8_decode')) {
|
||||
function utf8_decode($s) { return p\Php72::utf8_decode($s); }
|
||||
}
|
||||
if (!function_exists('spl_object_id')) {
|
||||
function spl_object_id($s) { return p\Php72::spl_object_id($s); }
|
||||
}
|
||||
if (!function_exists('mb_ord')) {
|
||||
function mb_ord($s, $enc = null) { return p\Php72::mb_ord($s, $enc); }
|
||||
}
|
||||
if (!function_exists('mb_chr')) {
|
||||
function mb_chr($code, $enc = null) { return p\Php72::mb_chr($code, $enc); }
|
||||
}
|
||||
if (!function_exists('mb_scrub')) {
|
||||
function mb_scrub($s, $enc = null) { $enc = null === $enc ? mb_internal_encoding() : $enc; return mb_convert_encoding($s, $enc, $enc); }
|
||||
}
|
53
wp-content/plugins/wp-mail-smtp/vendor/woocommerce/action-scheduler/action-scheduler.php
vendored
Normal file
53
wp-content/plugins/wp-mail-smtp/vendor/woocommerce/action-scheduler/action-scheduler.php
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
/*
|
||||
* Plugin Name: Action Scheduler
|
||||
* Plugin URI: https://actionscheduler.org
|
||||
* Description: A robust scheduling library for use in WordPress plugins.
|
||||
* Author: Automattic
|
||||
* Author URI: https://automattic.com/
|
||||
* Version: 3.1.6
|
||||
* License: GPLv3
|
||||
*
|
||||
* Copyright 2019 Automattic, Inc. (https://automattic.com/contact/)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
if ( ! function_exists( 'action_scheduler_register_3_dot_1_dot_6' ) ) {
|
||||
|
||||
if ( ! class_exists( 'ActionScheduler_Versions' ) ) {
|
||||
require_once( 'classes/ActionScheduler_Versions.php' );
|
||||
add_action( 'plugins_loaded', array( 'ActionScheduler_Versions', 'initialize_latest_version' ), 1, 0 );
|
||||
}
|
||||
|
||||
add_action( 'plugins_loaded', 'action_scheduler_register_3_dot_1_dot_6', 0, 0 );
|
||||
|
||||
function action_scheduler_register_3_dot_1_dot_6() {
|
||||
$versions = ActionScheduler_Versions::instance();
|
||||
$versions->register( '3.1.6', 'action_scheduler_initialize_3_dot_1_dot_6' );
|
||||
}
|
||||
|
||||
function action_scheduler_initialize_3_dot_1_dot_6() {
|
||||
require_once( 'classes/abstracts/ActionScheduler.php' );
|
||||
ActionScheduler::init( __FILE__ );
|
||||
}
|
||||
|
||||
// Support usage in themes - load this version if no plugin has loaded a version yet.
|
||||
if ( did_action( 'plugins_loaded' ) && ! class_exists( 'ActionScheduler' ) ) {
|
||||
action_scheduler_initialize_3_dot_1_dot_6();
|
||||
do_action( 'action_scheduler_pre_theme_init' );
|
||||
ActionScheduler_Versions::initialize_latest_version();
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class ActionScheduler_ActionClaim
|
||||
*/
|
||||
class ActionScheduler_ActionClaim {
|
||||
private $id = '';
|
||||
private $action_ids = array();
|
||||
|
||||
public function __construct( $id, array $action_ids ) {
|
||||
$this->id = $id;
|
||||
$this->action_ids = $action_ids;
|
||||
}
|
||||
|
||||
public function get_id() {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function get_actions() {
|
||||
return $this->action_ids;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,179 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class ActionScheduler_ActionFactory
|
||||
*/
|
||||
class ActionScheduler_ActionFactory {
|
||||
|
||||
/**
|
||||
* @param string $status The action's status in the data store
|
||||
* @param string $hook The hook to trigger when this action runs
|
||||
* @param array $args Args to pass to callbacks when the hook is triggered
|
||||
* @param ActionScheduler_Schedule $schedule The action's schedule
|
||||
* @param string $group A group to put the action in
|
||||
*
|
||||
* @return ActionScheduler_Action An instance of the stored action
|
||||
*/
|
||||
public function get_stored_action( $status, $hook, array $args = array(), ActionScheduler_Schedule $schedule = null, $group = '' ) {
|
||||
|
||||
switch ( $status ) {
|
||||
case ActionScheduler_Store::STATUS_PENDING :
|
||||
$action_class = 'ActionScheduler_Action';
|
||||
break;
|
||||
case ActionScheduler_Store::STATUS_CANCELED :
|
||||
$action_class = 'ActionScheduler_CanceledAction';
|
||||
if ( ! is_null( $schedule ) && ! is_a( $schedule, 'ActionScheduler_CanceledSchedule' ) && ! is_a( $schedule, 'ActionScheduler_NullSchedule' ) ) {
|
||||
$schedule = new ActionScheduler_CanceledSchedule( $schedule->get_date() );
|
||||
}
|
||||
break;
|
||||
default :
|
||||
$action_class = 'ActionScheduler_FinishedAction';
|
||||
break;
|
||||
}
|
||||
|
||||
$action_class = apply_filters( 'action_scheduler_stored_action_class', $action_class, $status, $hook, $args, $schedule, $group );
|
||||
|
||||
$action = new $action_class( $hook, $args, $schedule, $group );
|
||||
|
||||
/**
|
||||
* Allow 3rd party code to change the instantiated action for a given hook, args, schedule and group.
|
||||
*
|
||||
* @param ActionScheduler_Action $action The instantiated action.
|
||||
* @param string $hook The instantiated action's hook.
|
||||
* @param array $args The instantiated action's args.
|
||||
* @param ActionScheduler_Schedule $schedule The instantiated action's schedule.
|
||||
* @param string $group The instantiated action's group.
|
||||
*/
|
||||
return apply_filters( 'action_scheduler_stored_action_instance', $action, $hook, $args, $schedule, $group );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue an action to run one time, as soon as possible (rather a specific scheduled time).
|
||||
*
|
||||
* This method creates a new action with the NULLSchedule. This schedule maps to a MySQL datetime string of
|
||||
* 0000-00-00 00:00:00. This is done to create a psuedo "async action" type that is fully backward compatible.
|
||||
* Existing queries to claim actions claim by date, meaning actions scheduled for 0000-00-00 00:00:00 will
|
||||
* always be claimed prior to actions scheduled for a specific date. This makes sure that any async action is
|
||||
* given priority in queue processing. This has the added advantage of making sure async actions can be
|
||||
* claimed by both the existing WP Cron and WP CLI runners, as well as a new async request runner.
|
||||
*
|
||||
* @param string $hook The hook to trigger when this action runs
|
||||
* @param array $args Args to pass when the hook is triggered
|
||||
* @param string $group A group to put the action in
|
||||
*
|
||||
* @return int The ID of the stored action
|
||||
*/
|
||||
public function async( $hook, $args = array(), $group = '' ) {
|
||||
$schedule = new ActionScheduler_NullSchedule();
|
||||
$action = new ActionScheduler_Action( $hook, $args, $schedule, $group );
|
||||
return $this->store( $action );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $hook The hook to trigger when this action runs
|
||||
* @param array $args Args to pass when the hook is triggered
|
||||
* @param int $when Unix timestamp when the action will run
|
||||
* @param string $group A group to put the action in
|
||||
*
|
||||
* @return int The ID of the stored action
|
||||
*/
|
||||
public function single( $hook, $args = array(), $when = null, $group = '' ) {
|
||||
$date = as_get_datetime_object( $when );
|
||||
$schedule = new ActionScheduler_SimpleSchedule( $date );
|
||||
$action = new ActionScheduler_Action( $hook, $args, $schedule, $group );
|
||||
return $this->store( $action );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the first instance of an action recurring on a given interval.
|
||||
*
|
||||
* @param string $hook The hook to trigger when this action runs
|
||||
* @param array $args Args to pass when the hook is triggered
|
||||
* @param int $first Unix timestamp for the first run
|
||||
* @param int $interval Seconds between runs
|
||||
* @param string $group A group to put the action in
|
||||
*
|
||||
* @return int The ID of the stored action
|
||||
*/
|
||||
public function recurring( $hook, $args = array(), $first = null, $interval = null, $group = '' ) {
|
||||
if ( empty($interval) ) {
|
||||
return $this->single( $hook, $args, $first, $group );
|
||||
}
|
||||
$date = as_get_datetime_object( $first );
|
||||
$schedule = new ActionScheduler_IntervalSchedule( $date, $interval );
|
||||
$action = new ActionScheduler_Action( $hook, $args, $schedule, $group );
|
||||
return $this->store( $action );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the first instance of an action recurring on a Cron schedule.
|
||||
*
|
||||
* @param string $hook The hook to trigger when this action runs
|
||||
* @param array $args Args to pass when the hook is triggered
|
||||
* @param int $base_timestamp The first instance of the action will be scheduled
|
||||
* to run at a time calculated after this timestamp matching the cron
|
||||
* expression. This can be used to delay the first instance of the action.
|
||||
* @param int $schedule A cron definition string
|
||||
* @param string $group A group to put the action in
|
||||
*
|
||||
* @return int The ID of the stored action
|
||||
*/
|
||||
public function cron( $hook, $args = array(), $base_timestamp = null, $schedule = null, $group = '' ) {
|
||||
if ( empty($schedule) ) {
|
||||
return $this->single( $hook, $args, $base_timestamp, $group );
|
||||
}
|
||||
$date = as_get_datetime_object( $base_timestamp );
|
||||
$cron = CronExpression::factory( $schedule );
|
||||
$schedule = new ActionScheduler_CronSchedule( $date, $cron );
|
||||
$action = new ActionScheduler_Action( $hook, $args, $schedule, $group );
|
||||
return $this->store( $action );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a successive instance of a recurring or cron action.
|
||||
*
|
||||
* Importantly, the action will be rescheduled to run based on the current date/time.
|
||||
* That means when the action is scheduled to run in the past, the next scheduled date
|
||||
* will be pushed forward. For example, if a recurring action set to run every hour
|
||||
* was scheduled to run 5 seconds ago, it will be next scheduled for 1 hour in the
|
||||
* future, which is 1 hour and 5 seconds from when it was last scheduled to run.
|
||||
*
|
||||
* Alternatively, if the action is scheduled to run in the future, and is run early,
|
||||
* likely via manual intervention, then its schedule will change based on the time now.
|
||||
* For example, if a recurring action set to run every day, and is run 12 hours early,
|
||||
* it will run again in 24 hours, not 36 hours.
|
||||
*
|
||||
* This slippage is less of an issue with Cron actions, as the specific run time can
|
||||
* be set for them to run, e.g. 1am each day. In those cases, and entire period would
|
||||
* need to be missed before there was any change is scheduled, e.g. in the case of an
|
||||
* action scheduled for 1am each day, the action would need to run an entire day late.
|
||||
*
|
||||
* @param ActionScheduler_Action $action The existing action.
|
||||
*
|
||||
* @return string The ID of the stored action
|
||||
* @throws InvalidArgumentException If $action is not a recurring action.
|
||||
*/
|
||||
public function repeat( $action ) {
|
||||
$schedule = $action->get_schedule();
|
||||
$next = $schedule->get_next( as_get_datetime_object() );
|
||||
|
||||
if ( is_null( $next ) || ! $schedule->is_recurring() ) {
|
||||
throw new InvalidArgumentException( __( 'Invalid action - must be a recurring action.', 'action-scheduler' ) );
|
||||
}
|
||||
|
||||
$schedule_class = get_class( $schedule );
|
||||
$new_schedule = new $schedule( $next, $schedule->get_recurrence(), $schedule->get_first_date() );
|
||||
$new_action = new ActionScheduler_Action( $action->get_hook(), $action->get_args(), $new_schedule, $action->get_group() );
|
||||
return $this->store( $new_action );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ActionScheduler_Action $action
|
||||
*
|
||||
* @return int The ID of the stored action
|
||||
*/
|
||||
protected function store( ActionScheduler_Action $action ) {
|
||||
$store = ActionScheduler_Store::instance();
|
||||
return $store->save_action( $action );
|
||||
}
|
||||
}
|
@ -0,0 +1,154 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class ActionScheduler_AdminView
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class ActionScheduler_AdminView extends ActionScheduler_AdminView_Deprecated {
|
||||
|
||||
private static $admin_view = NULL;
|
||||
|
||||
private static $screen_id = 'tools_page_action-scheduler';
|
||||
|
||||
/** @var ActionScheduler_ListTable */
|
||||
protected $list_table;
|
||||
|
||||
/**
|
||||
* @return ActionScheduler_AdminView
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public static function instance() {
|
||||
|
||||
if ( empty( self::$admin_view ) ) {
|
||||
$class = apply_filters('action_scheduler_admin_view_class', 'ActionScheduler_AdminView');
|
||||
self::$admin_view = new $class();
|
||||
}
|
||||
|
||||
return self::$admin_view;
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function init() {
|
||||
if ( is_admin() && ( ! defined( 'DOING_AJAX' ) || false == DOING_AJAX ) ) {
|
||||
|
||||
if ( class_exists( 'WooCommerce' ) ) {
|
||||
add_action( 'woocommerce_admin_status_content_action-scheduler', array( $this, 'render_admin_ui' ) );
|
||||
add_action( 'woocommerce_system_status_report', array( $this, 'system_status_report' ) );
|
||||
add_filter( 'woocommerce_admin_status_tabs', array( $this, 'register_system_status_tab' ) );
|
||||
}
|
||||
|
||||
add_action( 'admin_menu', array( $this, 'register_menu' ) );
|
||||
|
||||
add_action( 'current_screen', array( $this, 'add_help_tabs' ) );
|
||||
}
|
||||
}
|
||||
|
||||
public function system_status_report() {
|
||||
$table = new ActionScheduler_wcSystemStatus( ActionScheduler::store() );
|
||||
$table->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers action-scheduler into WooCommerce > System status.
|
||||
*
|
||||
* @param array $tabs An associative array of tab key => label.
|
||||
* @return array $tabs An associative array of tab key => label, including Action Scheduler's tabs
|
||||
*/
|
||||
public function register_system_status_tab( array $tabs ) {
|
||||
$tabs['action-scheduler'] = __( 'Scheduled Actions', 'action-scheduler' );
|
||||
|
||||
return $tabs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include Action Scheduler's administration under the Tools menu.
|
||||
*
|
||||
* A menu under the Tools menu is important for backward compatibility (as that's
|
||||
* where it started), and also provides more convenient access than the WooCommerce
|
||||
* System Status page, and for sites where WooCommerce isn't active.
|
||||
*/
|
||||
public function register_menu() {
|
||||
$hook_suffix = add_submenu_page(
|
||||
'tools.php',
|
||||
__( 'Scheduled Actions', 'action-scheduler' ),
|
||||
__( 'Scheduled Actions', 'action-scheduler' ),
|
||||
'manage_options',
|
||||
'action-scheduler',
|
||||
array( $this, 'render_admin_ui' )
|
||||
);
|
||||
add_action( 'load-' . $hook_suffix , array( $this, 'process_admin_ui' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers processing of any pending actions.
|
||||
*/
|
||||
public function process_admin_ui() {
|
||||
$this->get_list_table();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the Admin UI
|
||||
*/
|
||||
public function render_admin_ui() {
|
||||
$table = $this->get_list_table();
|
||||
$table->display_page();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the admin UI object and process any requested actions.
|
||||
*
|
||||
* @return ActionScheduler_ListTable
|
||||
*/
|
||||
protected function get_list_table() {
|
||||
if ( null === $this->list_table ) {
|
||||
$this->list_table = new ActionScheduler_ListTable( ActionScheduler::store(), ActionScheduler::logger(), ActionScheduler::runner() );
|
||||
$this->list_table->process_actions();
|
||||
}
|
||||
|
||||
return $this->list_table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide more information about the screen and its data in the help tab.
|
||||
*/
|
||||
public function add_help_tabs() {
|
||||
$screen = get_current_screen();
|
||||
|
||||
if ( ! $screen || self::$screen_id != $screen->id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$as_version = ActionScheduler_Versions::instance()->latest_version();
|
||||
$screen->add_help_tab(
|
||||
array(
|
||||
'id' => 'action_scheduler_about',
|
||||
'title' => __( 'About', 'action-scheduler' ),
|
||||
'content' =>
|
||||
'<h2>' . sprintf( __( 'About Action Scheduler %s', 'action-scheduler' ), $as_version ) . '</h2>' .
|
||||
'<p>' .
|
||||
__( 'Action Scheduler is a scalable, traceable job queue for background processing large sets of actions. Action Scheduler works by triggering an action hook to run at some time in the future. Scheduled actions can also be scheduled to run on a recurring schedule.', 'action-scheduler' ) .
|
||||
'</p>',
|
||||
)
|
||||
);
|
||||
|
||||
$screen->add_help_tab(
|
||||
array(
|
||||
'id' => 'action_scheduler_columns',
|
||||
'title' => __( 'Columns', 'action-scheduler' ),
|
||||
'content' =>
|
||||
'<h2>' . __( 'Scheduled Action Columns', 'action-scheduler' ) . '</h2>' .
|
||||
'<ul>' .
|
||||
sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Hook', 'action-scheduler' ), __( 'Name of the action hook that will be triggered.', 'action-scheduler' ) ) .
|
||||
sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Status', 'action-scheduler' ), __( 'Action statuses are Pending, Complete, Canceled, Failed', 'action-scheduler' ) ) .
|
||||
sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Arguments', 'action-scheduler' ), __( 'Optional data array passed to the action hook.', 'action-scheduler' ) ) .
|
||||
sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Group', 'action-scheduler' ), __( 'Optional action group.', 'action-scheduler' ) ) .
|
||||
sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Recurrence', 'action-scheduler' ), __( 'The action\'s schedule frequency.', 'action-scheduler' ) ) .
|
||||
sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Scheduled', 'action-scheduler' ), __( 'The date/time the action is/was scheduled to run.', 'action-scheduler' ) ) .
|
||||
sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Log', 'action-scheduler' ), __( 'Activity log for the action.', 'action-scheduler' ) ) .
|
||||
'</ul>',
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
<?php
|
||||
/**
|
||||
* ActionScheduler_AsyncRequest_QueueRunner
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* ActionScheduler_AsyncRequest_QueueRunner class.
|
||||
*/
|
||||
class ActionScheduler_AsyncRequest_QueueRunner extends WP_Async_Request {
|
||||
|
||||
/**
|
||||
* Data store for querying actions
|
||||
*
|
||||
* @var ActionScheduler_Store
|
||||
* @access protected
|
||||
*/
|
||||
protected $store;
|
||||
|
||||
/**
|
||||
* Prefix for ajax hooks
|
||||
*
|
||||
* @var string
|
||||
* @access protected
|
||||
*/
|
||||
protected $prefix = 'as';
|
||||
|
||||
/**
|
||||
* Action for ajax hooks
|
||||
*
|
||||
* @var string
|
||||
* @access protected
|
||||
*/
|
||||
protected $action = 'async_request_queue_runner';
|
||||
|
||||
/**
|
||||
* Initiate new async request
|
||||
*/
|
||||
public function __construct( ActionScheduler_Store $store ) {
|
||||
parent::__construct();
|
||||
$this->store = $store;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle async requests
|
||||
*
|
||||
* Run a queue, and maybe dispatch another async request to run another queue
|
||||
* if there are still pending actions after completing a queue in this request.
|
||||
*/
|
||||
protected function handle() {
|
||||
do_action( 'action_scheduler_run_queue', 'Async Request' ); // run a queue in the same way as WP Cron, but declare the Async Request context
|
||||
|
||||
$sleep_seconds = $this->get_sleep_seconds();
|
||||
|
||||
if ( $sleep_seconds ) {
|
||||
sleep( $sleep_seconds );
|
||||
}
|
||||
|
||||
$this->maybe_dispatch();
|
||||
}
|
||||
|
||||
/**
|
||||
* If the async request runner is needed and allowed to run, dispatch a request.
|
||||
*/
|
||||
public function maybe_dispatch() {
|
||||
if ( ! $this->allow() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->dispatch();
|
||||
ActionScheduler_QueueRunner::instance()->unhook_dispatch_async_request();
|
||||
}
|
||||
|
||||
/**
|
||||
* Only allow async requests when needed.
|
||||
*
|
||||
* Also allow 3rd party code to disable running actions via async requests.
|
||||
*/
|
||||
protected function allow() {
|
||||
|
||||
if ( ! has_action( 'action_scheduler_run_queue' ) || ActionScheduler::runner()->has_maximum_concurrent_batches() || ! $this->store->has_pending_actions_due() ) {
|
||||
$allow = false;
|
||||
} else {
|
||||
$allow = true;
|
||||
}
|
||||
|
||||
return apply_filters( 'action_scheduler_allow_async_request_runner', $allow );
|
||||
}
|
||||
|
||||
/**
|
||||
* Chaining async requests can crash MySQL. A brief sleep call in PHP prevents that.
|
||||
*/
|
||||
protected function get_sleep_seconds() {
|
||||
return apply_filters( 'action_scheduler_async_request_sleep_seconds', 5, $this );
|
||||
}
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class ActionScheduler_Compatibility
|
||||
*/
|
||||
class ActionScheduler_Compatibility {
|
||||
|
||||
/**
|
||||
* Converts a shorthand byte value to an integer byte value.
|
||||
*
|
||||
* Wrapper for wp_convert_hr_to_bytes(), moved to load.php in WordPress 4.6 from media.php
|
||||
*
|
||||
* @link https://secure.php.net/manual/en/function.ini-get.php
|
||||
* @link https://secure.php.net/manual/en/faq.using.php#faq.using.shorthandbytes
|
||||
*
|
||||
* @param string $value A (PHP ini) byte value, either shorthand or ordinary.
|
||||
* @return int An integer byte value.
|
||||
*/
|
||||
public static function convert_hr_to_bytes( $value ) {
|
||||
if ( function_exists( 'wp_convert_hr_to_bytes' ) ) {
|
||||
return wp_convert_hr_to_bytes( $value );
|
||||
}
|
||||
|
||||
$value = strtolower( trim( $value ) );
|
||||
$bytes = (int) $value;
|
||||
|
||||
if ( false !== strpos( $value, 'g' ) ) {
|
||||
$bytes *= GB_IN_BYTES;
|
||||
} elseif ( false !== strpos( $value, 'm' ) ) {
|
||||
$bytes *= MB_IN_BYTES;
|
||||
} elseif ( false !== strpos( $value, 'k' ) ) {
|
||||
$bytes *= KB_IN_BYTES;
|
||||
}
|
||||
|
||||
// Deal with large (float) values which run into the maximum integer size.
|
||||
return min( $bytes, PHP_INT_MAX );
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to raise the PHP memory limit for memory intensive processes.
|
||||
*
|
||||
* Only allows raising the existing limit and prevents lowering it.
|
||||
*
|
||||
* Wrapper for wp_raise_memory_limit(), added in WordPress v4.6.0
|
||||
*
|
||||
* @return bool|int|string The limit that was set or false on failure.
|
||||
*/
|
||||
public static function raise_memory_limit() {
|
||||
if ( function_exists( 'wp_raise_memory_limit' ) ) {
|
||||
return wp_raise_memory_limit( 'admin' );
|
||||
}
|
||||
|
||||
$current_limit = @ini_get( 'memory_limit' );
|
||||
$current_limit_int = self::convert_hr_to_bytes( $current_limit );
|
||||
|
||||
if ( -1 === $current_limit_int ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$wp_max_limit = WP_MAX_MEMORY_LIMIT;
|
||||
$wp_max_limit_int = self::convert_hr_to_bytes( $wp_max_limit );
|
||||
$filtered_limit = apply_filters( 'admin_memory_limit', $wp_max_limit );
|
||||
$filtered_limit_int = self::convert_hr_to_bytes( $filtered_limit );
|
||||
|
||||
if ( -1 === $filtered_limit_int || ( $filtered_limit_int > $wp_max_limit_int && $filtered_limit_int > $current_limit_int ) ) {
|
||||
if ( false !== @ini_set( 'memory_limit', $filtered_limit ) ) {
|
||||
return $filtered_limit;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} elseif ( -1 === $wp_max_limit_int || $wp_max_limit_int > $current_limit_int ) {
|
||||
if ( false !== @ini_set( 'memory_limit', $wp_max_limit ) ) {
|
||||
return $wp_max_limit;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to raise the PHP timeout for time intensive processes.
|
||||
*
|
||||
* Only allows raising the existing limit and prevents lowering it. Wrapper for wc_set_time_limit(), when available.
|
||||
*
|
||||
* @param int The time limit in seconds.
|
||||
*/
|
||||
public static function raise_time_limit( $limit = 0 ) {
|
||||
if ( $limit < ini_get( 'max_execution_time' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( function_exists( 'wc_set_time_limit' ) ) {
|
||||
wc_set_time_limit( $limit );
|
||||
} elseif ( function_exists( 'set_time_limit' ) && false === strpos( ini_get( 'disable_functions' ), 'set_time_limit' ) && ! ini_get( 'safe_mode' ) ) {
|
||||
@set_time_limit( $limit );
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,187 @@
|
||||
<?php
|
||||
|
||||
use Action_Scheduler\Migration\Controller;
|
||||
|
||||
/**
|
||||
* Class ActionScheduler_DataController
|
||||
*
|
||||
* The main plugin/initialization class for the data stores.
|
||||
*
|
||||
* Responsible for hooking everything up with WordPress.
|
||||
*
|
||||
* @package Action_Scheduler
|
||||
*
|
||||
* @since 3.0.0
|
||||
*/
|
||||
class ActionScheduler_DataController {
|
||||
/** Action data store class name. */
|
||||
const DATASTORE_CLASS = 'ActionScheduler_DBStore';
|
||||
|
||||
/** Logger data store class name. */
|
||||
const LOGGER_CLASS = 'ActionScheduler_DBLogger';
|
||||
|
||||
/** Migration status option name. */
|
||||
const STATUS_FLAG = 'action_scheduler_migration_status';
|
||||
|
||||
/** Migration status option value. */
|
||||
const STATUS_COMPLETE = 'complete';
|
||||
|
||||
/** Migration minimum required PHP version. */
|
||||
const MIN_PHP_VERSION = '5.5';
|
||||
|
||||
/** @var ActionScheduler_DataController */
|
||||
private static $instance;
|
||||
|
||||
/** @var int */
|
||||
private static $sleep_time = 0;
|
||||
|
||||
/** @var int */
|
||||
private static $free_ticks = 50;
|
||||
|
||||
/**
|
||||
* Get a flag indicating whether the migration environment dependencies are met.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function dependencies_met() {
|
||||
$php_support = version_compare( PHP_VERSION, self::MIN_PHP_VERSION, '>=' );
|
||||
return $php_support && apply_filters( 'action_scheduler_migration_dependencies_met', true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a flag indicating whether the migration is complete.
|
||||
*
|
||||
* @return bool Whether the flag has been set marking the migration as complete
|
||||
*/
|
||||
public static function is_migration_complete() {
|
||||
return get_option( self::STATUS_FLAG ) === self::STATUS_COMPLETE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the migration as complete.
|
||||
*/
|
||||
public static function mark_migration_complete() {
|
||||
update_option( self::STATUS_FLAG, self::STATUS_COMPLETE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmark migration when a plugin is de-activated. Will not work in case of silent activation, for example in an update.
|
||||
* We do this to mitigate the bug of lost actions which happens if there was an AS 2.x to AS 3.x migration in the past, but that plugin is now
|
||||
* deactivated and the site was running on AS 2.x again.
|
||||
*/
|
||||
public static function mark_migration_incomplete() {
|
||||
delete_option( self::STATUS_FLAG );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the action store class name.
|
||||
*
|
||||
* @param string $class Classname of the store class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function set_store_class( $class ) {
|
||||
return self::DATASTORE_CLASS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the action logger class name.
|
||||
*
|
||||
* @param string $class Classname of the logger class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function set_logger_class( $class ) {
|
||||
return self::LOGGER_CLASS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the sleep time in seconds.
|
||||
*
|
||||
* @param integer $sleep_time The number of seconds to pause before resuming operation.
|
||||
*/
|
||||
public static function set_sleep_time( $sleep_time ) {
|
||||
self::$sleep_time = (int) $sleep_time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the tick count required for freeing memory.
|
||||
*
|
||||
* @param integer $free_ticks The number of ticks to free memory on.
|
||||
*/
|
||||
public static function set_free_ticks( $free_ticks ) {
|
||||
self::$free_ticks = (int) $free_ticks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free memory if conditions are met.
|
||||
*
|
||||
* @param int $ticks Current tick count.
|
||||
*/
|
||||
public static function maybe_free_memory( $ticks ) {
|
||||
if ( self::$free_ticks && 0 === $ticks % self::$free_ticks ) {
|
||||
self::free_memory();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduce memory footprint by clearing the database query and object caches.
|
||||
*/
|
||||
public static function free_memory() {
|
||||
if ( 0 < self::$sleep_time ) {
|
||||
/* translators: %d: amount of time */
|
||||
\WP_CLI::warning( sprintf( _n( 'Stopped the insanity for %d second', 'Stopped the insanity for %d seconds', self::$sleep_time, 'action-scheduler' ), self::$sleep_time ) );
|
||||
sleep( self::$sleep_time );
|
||||
}
|
||||
|
||||
\WP_CLI::warning( __( 'Attempting to reduce used memory...', 'action-scheduler' ) );
|
||||
|
||||
/**
|
||||
* @var $wpdb \wpdb
|
||||
* @var $wp_object_cache \WP_Object_Cache
|
||||
*/
|
||||
global $wpdb, $wp_object_cache;
|
||||
|
||||
$wpdb->queries = array();
|
||||
|
||||
if ( ! is_a( $wp_object_cache, 'WP_Object_Cache' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$wp_object_cache->group_ops = array();
|
||||
$wp_object_cache->stats = array();
|
||||
$wp_object_cache->memcache_debug = array();
|
||||
$wp_object_cache->cache = array();
|
||||
|
||||
if ( is_callable( array( $wp_object_cache, '__remoteset' ) ) ) {
|
||||
call_user_func( array( $wp_object_cache, '__remoteset' ) ); // important
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to table datastores if migration is complete.
|
||||
* Otherwise, proceed with the migration if the dependencies have been met.
|
||||
*/
|
||||
public static function init() {
|
||||
if ( self::is_migration_complete() ) {
|
||||
add_filter( 'action_scheduler_store_class', array( 'ActionScheduler_DataController', 'set_store_class' ), 100 );
|
||||
add_filter( 'action_scheduler_logger_class', array( 'ActionScheduler_DataController', 'set_logger_class' ), 100 );
|
||||
add_action( 'deactivate_plugin', array( 'ActionScheduler_DataController', 'mark_migration_incomplete' ) );
|
||||
} elseif ( self::dependencies_met() ) {
|
||||
Controller::init();
|
||||
}
|
||||
|
||||
add_action( 'action_scheduler/progress_tick', array( 'ActionScheduler_DataController', 'maybe_free_memory' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Singleton factory.
|
||||
*/
|
||||
public static function instance() {
|
||||
if ( ! isset( self::$instance ) ) {
|
||||
self::$instance = new static();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* ActionScheduler DateTime class.
|
||||
*
|
||||
* This is a custom extension to DateTime that
|
||||
*/
|
||||
class ActionScheduler_DateTime extends DateTime {
|
||||
|
||||
/**
|
||||
* UTC offset.
|
||||
*
|
||||
* Only used when a timezone is not set. When a timezone string is
|
||||
* used, this will be set to 0.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $utcOffset = 0;
|
||||
|
||||
/**
|
||||
* Get the unix timestamp of the current object.
|
||||
*
|
||||
* Missing in PHP 5.2 so just here so it can be supported consistently.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getTimestamp() {
|
||||
return method_exists( 'DateTime', 'getTimestamp' ) ? parent::getTimestamp() : $this->format( 'U' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the UTC offset.
|
||||
*
|
||||
* This represents a fixed offset instead of a timezone setting.
|
||||
*
|
||||
* @param $offset
|
||||
*/
|
||||
public function setUtcOffset( $offset ) {
|
||||
$this->utcOffset = intval( $offset );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the timezone offset.
|
||||
*
|
||||
* @return int
|
||||
* @link http://php.net/manual/en/datetime.getoffset.php
|
||||
*/
|
||||
public function getOffset() {
|
||||
return $this->utcOffset ? $this->utcOffset : parent::getOffset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the TimeZone associated with the DateTime
|
||||
*
|
||||
* @param DateTimeZone $timezone
|
||||
*
|
||||
* @return static
|
||||
* @link http://php.net/manual/en/datetime.settimezone.php
|
||||
*/
|
||||
public function setTimezone( $timezone ) {
|
||||
$this->utcOffset = 0;
|
||||
parent::setTimezone( $timezone );
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timestamp with the WordPress timezone offset added or subtracted.
|
||||
*
|
||||
* @since 3.0.0
|
||||
* @return int
|
||||
*/
|
||||
public function getOffsetTimestamp() {
|
||||
return $this->getTimestamp() + $this->getOffset();
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* ActionScheduler Exception Interface.
|
||||
*
|
||||
* Facilitates catching Exceptions unique to Action Scheduler.
|
||||
*
|
||||
* @package ActionScheduler
|
||||
* @since %VERSION%
|
||||
*/
|
||||
interface ActionScheduler_Exception {}
|
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class ActionScheduler_FatalErrorMonitor
|
||||
*/
|
||||
class ActionScheduler_FatalErrorMonitor {
|
||||
/** @var ActionScheduler_ActionClaim */
|
||||
private $claim = NULL;
|
||||
/** @var ActionScheduler_Store */
|
||||
private $store = NULL;
|
||||
private $action_id = 0;
|
||||
|
||||
public function __construct( ActionScheduler_Store $store ) {
|
||||
$this->store = $store;
|
||||
}
|
||||
|
||||
public function attach( ActionScheduler_ActionClaim $claim ) {
|
||||
$this->claim = $claim;
|
||||
add_action( 'shutdown', array( $this, 'handle_unexpected_shutdown' ) );
|
||||
add_action( 'action_scheduler_before_execute', array( $this, 'track_current_action' ), 0, 1 );
|
||||
add_action( 'action_scheduler_after_execute', array( $this, 'untrack_action' ), 0, 0 );
|
||||
add_action( 'action_scheduler_execution_ignored', array( $this, 'untrack_action' ), 0, 0 );
|
||||
add_action( 'action_scheduler_failed_execution', array( $this, 'untrack_action' ), 0, 0 );
|
||||
}
|
||||
|
||||
public function detach() {
|
||||
$this->claim = NULL;
|
||||
$this->untrack_action();
|
||||
remove_action( 'shutdown', array( $this, 'handle_unexpected_shutdown' ) );
|
||||
remove_action( 'action_scheduler_before_execute', array( $this, 'track_current_action' ), 0 );
|
||||
remove_action( 'action_scheduler_after_execute', array( $this, 'untrack_action' ), 0 );
|
||||
remove_action( 'action_scheduler_execution_ignored', array( $this, 'untrack_action' ), 0 );
|
||||
remove_action( 'action_scheduler_failed_execution', array( $this, 'untrack_action' ), 0 );
|
||||
}
|
||||
|
||||
public function track_current_action( $action_id ) {
|
||||
$this->action_id = $action_id;
|
||||
}
|
||||
|
||||
public function untrack_action() {
|
||||
$this->action_id = 0;
|
||||
}
|
||||
|
||||
public function handle_unexpected_shutdown() {
|
||||
if ( $error = error_get_last() ) {
|
||||
if ( in_array( $error['type'], array( E_ERROR, E_PARSE, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR ) ) ) {
|
||||
if ( !empty($this->action_id) ) {
|
||||
$this->store->mark_failure( $this->action_id );
|
||||
do_action( 'action_scheduler_unexpected_shutdown', $this->action_id, $error );
|
||||
}
|
||||
}
|
||||
$this->store->release_claim( $this->claim );
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* InvalidAction Exception.
|
||||
*
|
||||
* Used for identifying actions that are invalid in some way.
|
||||
*
|
||||
* @package ActionScheduler
|
||||
*/
|
||||
class ActionScheduler_InvalidActionException extends \InvalidArgumentException implements ActionScheduler_Exception {
|
||||
|
||||
/**
|
||||
* Create a new exception when the action's schedule cannot be fetched.
|
||||
*
|
||||
* @param string $action_id The action ID with bad args.
|
||||
* @return static
|
||||
*/
|
||||
public static function from_schedule( $action_id, $schedule ) {
|
||||
$message = sprintf(
|
||||
/* translators: 1: action ID 2: schedule */
|
||||
__( 'Action [%1$s] has an invalid schedule: %2$s', 'action-scheduler' ),
|
||||
$action_id,
|
||||
var_export( $schedule, true )
|
||||
);
|
||||
|
||||
return new static( $message );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new exception when the action's args cannot be decoded to an array.
|
||||
*
|
||||
* @author Jeremy Pry
|
||||
*
|
||||
* @param string $action_id The action ID with bad args.
|
||||
* @return static
|
||||
*/
|
||||
public static function from_decoding_args( $action_id, $args = array() ) {
|
||||
$message = sprintf(
|
||||
/* translators: 1: action ID 2: arguments */
|
||||
__( 'Action [%1$s] has invalid arguments. It cannot be JSON decoded to an array. $args = %2$s', 'action-scheduler' ),
|
||||
$action_id,
|
||||
var_export( $args, true )
|
||||
);
|
||||
|
||||
return new static( $message );
|
||||
}
|
||||
}
|
@ -0,0 +1,612 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Implements the admin view of the actions.
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
|
||||
|
||||
/**
|
||||
* The package name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $package = 'action-scheduler';
|
||||
|
||||
/**
|
||||
* Columns to show (name => label).
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $columns = array();
|
||||
|
||||
/**
|
||||
* Actions (name => label).
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $row_actions = array();
|
||||
|
||||
/**
|
||||
* The active data stores
|
||||
*
|
||||
* @var ActionScheduler_Store
|
||||
*/
|
||||
protected $store;
|
||||
|
||||
/**
|
||||
* A logger to use for getting action logs to display
|
||||
*
|
||||
* @var ActionScheduler_Logger
|
||||
*/
|
||||
protected $logger;
|
||||
|
||||
/**
|
||||
* A ActionScheduler_QueueRunner runner instance (or child class)
|
||||
*
|
||||
* @var ActionScheduler_QueueRunner
|
||||
*/
|
||||
protected $runner;
|
||||
|
||||
/**
|
||||
* Bulk actions. The key of the array is the method name of the implementation:
|
||||
*
|
||||
* bulk_<key>(array $ids, string $sql_in).
|
||||
*
|
||||
* See the comments in the parent class for further details
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $bulk_actions = array();
|
||||
|
||||
/**
|
||||
* Flag variable to render our notifications, if any, once.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected static $did_notification = false;
|
||||
|
||||
/**
|
||||
* Array of seconds for common time periods, like week or month, alongside an internationalised string representation, i.e. "Day" or "Days"
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $time_periods;
|
||||
|
||||
/**
|
||||
* Sets the current data store object into `store->action` and initialises the object.
|
||||
*
|
||||
* @param ActionScheduler_Store $store
|
||||
* @param ActionScheduler_Logger $logger
|
||||
* @param ActionScheduler_QueueRunner $runner
|
||||
*/
|
||||
public function __construct( ActionScheduler_Store $store, ActionScheduler_Logger $logger, ActionScheduler_QueueRunner $runner ) {
|
||||
|
||||
$this->store = $store;
|
||||
$this->logger = $logger;
|
||||
$this->runner = $runner;
|
||||
|
||||
$this->table_header = __( 'Scheduled Actions', 'action-scheduler' );
|
||||
|
||||
$this->bulk_actions = array(
|
||||
'delete' => __( 'Delete', 'action-scheduler' ),
|
||||
);
|
||||
|
||||
$this->columns = array(
|
||||
'hook' => __( 'Hook', 'action-scheduler' ),
|
||||
'status' => __( 'Status', 'action-scheduler' ),
|
||||
'args' => __( 'Arguments', 'action-scheduler' ),
|
||||
'group' => __( 'Group', 'action-scheduler' ),
|
||||
'recurrence' => __( 'Recurrence', 'action-scheduler' ),
|
||||
'schedule' => __( 'Scheduled Date', 'action-scheduler' ),
|
||||
'log_entries' => __( 'Log', 'action-scheduler' ),
|
||||
);
|
||||
|
||||
$this->sort_by = array(
|
||||
'schedule',
|
||||
'hook',
|
||||
'group',
|
||||
);
|
||||
|
||||
$this->search_by = array(
|
||||
'hook',
|
||||
'args',
|
||||
'claim_id',
|
||||
);
|
||||
|
||||
$request_status = $this->get_request_status();
|
||||
|
||||
if ( empty( $request_status ) ) {
|
||||
$this->sort_by[] = 'status';
|
||||
} elseif ( in_array( $request_status, array( 'in-progress', 'failed' ) ) ) {
|
||||
$this->columns += array( 'claim_id' => __( 'Claim ID', 'action-scheduler' ) );
|
||||
$this->sort_by[] = 'claim_id';
|
||||
}
|
||||
|
||||
$this->row_actions = array(
|
||||
'hook' => array(
|
||||
'run' => array(
|
||||
'name' => __( 'Run', 'action-scheduler' ),
|
||||
'desc' => __( 'Process the action now as if it were run as part of a queue', 'action-scheduler' ),
|
||||
),
|
||||
'cancel' => array(
|
||||
'name' => __( 'Cancel', 'action-scheduler' ),
|
||||
'desc' => __( 'Cancel the action now to avoid it being run in future', 'action-scheduler' ),
|
||||
'class' => 'cancel trash',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
self::$time_periods = array(
|
||||
array(
|
||||
'seconds' => YEAR_IN_SECONDS,
|
||||
/* translators: %s: amount of time */
|
||||
'names' => _n_noop( '%s year', '%s years', 'action-scheduler' ),
|
||||
),
|
||||
array(
|
||||
'seconds' => MONTH_IN_SECONDS,
|
||||
/* translators: %s: amount of time */
|
||||
'names' => _n_noop( '%s month', '%s months', 'action-scheduler' ),
|
||||
),
|
||||
array(
|
||||
'seconds' => WEEK_IN_SECONDS,
|
||||
/* translators: %s: amount of time */
|
||||
'names' => _n_noop( '%s week', '%s weeks', 'action-scheduler' ),
|
||||
),
|
||||
array(
|
||||
'seconds' => DAY_IN_SECONDS,
|
||||
/* translators: %s: amount of time */
|
||||
'names' => _n_noop( '%s day', '%s days', 'action-scheduler' ),
|
||||
),
|
||||
array(
|
||||
'seconds' => HOUR_IN_SECONDS,
|
||||
/* translators: %s: amount of time */
|
||||
'names' => _n_noop( '%s hour', '%s hours', 'action-scheduler' ),
|
||||
),
|
||||
array(
|
||||
'seconds' => MINUTE_IN_SECONDS,
|
||||
/* translators: %s: amount of time */
|
||||
'names' => _n_noop( '%s minute', '%s minutes', 'action-scheduler' ),
|
||||
),
|
||||
array(
|
||||
'seconds' => 1,
|
||||
/* translators: %s: amount of time */
|
||||
'names' => _n_noop( '%s second', '%s seconds', 'action-scheduler' ),
|
||||
),
|
||||
);
|
||||
|
||||
parent::__construct( array(
|
||||
'singular' => 'action-scheduler',
|
||||
'plural' => 'action-scheduler',
|
||||
'ajax' => false,
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an interval of seconds into a two part human friendly string.
|
||||
*
|
||||
* The WordPress human_time_diff() function only calculates the time difference to one degree, meaning
|
||||
* even if an action is 1 day and 11 hours away, it will display "1 day". This function goes one step
|
||||
* further to display two degrees of accuracy.
|
||||
*
|
||||
* Inspired by the Crontrol::interval() function by Edward Dale: https://wordpress.org/plugins/wp-crontrol/
|
||||
*
|
||||
* @param int $interval A interval in seconds.
|
||||
* @param int $periods_to_include Depth of time periods to include, e.g. for an interval of 70, and $periods_to_include of 2, both minutes and seconds would be included. With a value of 1, only minutes would be included.
|
||||
* @return string A human friendly string representation of the interval.
|
||||
*/
|
||||
private static function human_interval( $interval, $periods_to_include = 2 ) {
|
||||
|
||||
if ( $interval <= 0 ) {
|
||||
return __( 'Now!', 'action-scheduler' );
|
||||
}
|
||||
|
||||
$output = '';
|
||||
|
||||
for ( $time_period_index = 0, $periods_included = 0, $seconds_remaining = $interval; $time_period_index < count( self::$time_periods ) && $seconds_remaining > 0 && $periods_included < $periods_to_include; $time_period_index++ ) {
|
||||
|
||||
$periods_in_interval = floor( $seconds_remaining / self::$time_periods[ $time_period_index ]['seconds'] );
|
||||
|
||||
if ( $periods_in_interval > 0 ) {
|
||||
if ( ! empty( $output ) ) {
|
||||
$output .= ' ';
|
||||
}
|
||||
$output .= sprintf( _n( self::$time_periods[ $time_period_index ]['names'][0], self::$time_periods[ $time_period_index ]['names'][1], $periods_in_interval, 'action-scheduler' ), $periods_in_interval );
|
||||
$seconds_remaining -= $periods_in_interval * self::$time_periods[ $time_period_index ]['seconds'];
|
||||
$periods_included++;
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the recurrence of an action or 'Non-repeating'. The output is human readable.
|
||||
*
|
||||
* @param ActionScheduler_Action $action
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_recurrence( $action ) {
|
||||
$schedule = $action->get_schedule();
|
||||
if ( $schedule->is_recurring() ) {
|
||||
$recurrence = $schedule->get_recurrence();
|
||||
|
||||
if ( is_numeric( $recurrence ) ) {
|
||||
/* translators: %s: time interval */
|
||||
return sprintf( __( 'Every %s', 'action-scheduler' ), self::human_interval( $recurrence ) );
|
||||
} else {
|
||||
return $recurrence;
|
||||
}
|
||||
}
|
||||
|
||||
return __( 'Non-repeating', 'action-scheduler' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the argument of an action to render it in a human friendly format.
|
||||
*
|
||||
* @param array $row The array representation of the current row of the table
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function column_args( array $row ) {
|
||||
if ( empty( $row['args'] ) ) {
|
||||
return apply_filters( 'action_scheduler_list_table_column_args', '', $row );
|
||||
}
|
||||
|
||||
$row_html = '<ul>';
|
||||
foreach ( $row['args'] as $key => $value ) {
|
||||
$row_html .= sprintf( '<li><code>%s => %s</code></li>', esc_html( var_export( $key, true ) ), esc_html( var_export( $value, true ) ) );
|
||||
}
|
||||
$row_html .= '</ul>';
|
||||
|
||||
return apply_filters( 'action_scheduler_list_table_column_args', $row_html, $row );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the logs entries inline. We do so to avoid loading Javascript and other hacks to show it in a modal.
|
||||
*
|
||||
* @param array $row Action array.
|
||||
* @return string
|
||||
*/
|
||||
public function column_log_entries( array $row ) {
|
||||
|
||||
$log_entries_html = '<ol>';
|
||||
|
||||
$timezone = new DateTimezone( 'UTC' );
|
||||
|
||||
foreach ( $row['log_entries'] as $log_entry ) {
|
||||
$log_entries_html .= $this->get_log_entry_html( $log_entry, $timezone );
|
||||
}
|
||||
|
||||
$log_entries_html .= '</ol>';
|
||||
|
||||
return $log_entries_html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the logs entries inline. We do so to avoid loading Javascript and other hacks to show it in a modal.
|
||||
*
|
||||
* @param ActionScheduler_LogEntry $log_entry
|
||||
* @param DateTimezone $timezone
|
||||
* @return string
|
||||
*/
|
||||
protected function get_log_entry_html( ActionScheduler_LogEntry $log_entry, DateTimezone $timezone ) {
|
||||
$date = $log_entry->get_date();
|
||||
$date->setTimezone( $timezone );
|
||||
return sprintf( '<li><strong>%s</strong><br/>%s</li>', esc_html( $date->format( 'Y-m-d H:i:s O' ) ), esc_html( $log_entry->get_message() ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Only display row actions for pending actions.
|
||||
*
|
||||
* @param array $row Row to render
|
||||
* @param string $column_name Current row
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function maybe_render_actions( $row, $column_name ) {
|
||||
if ( 'pending' === strtolower( $row[ 'status_name' ] ) ) {
|
||||
return parent::maybe_render_actions( $row, $column_name );
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders admin notifications
|
||||
*
|
||||
* Notifications:
|
||||
* 1. When the maximum number of tasks are being executed simultaneously.
|
||||
* 2. Notifications when a task is manually executed.
|
||||
* 3. Tables are missing.
|
||||
*/
|
||||
public function display_admin_notices() {
|
||||
global $wpdb;
|
||||
|
||||
if ( ( is_a( $this->store, 'ActionScheduler_HybridStore' ) || is_a( $this->store, 'ActionScheduler_DBStore' ) ) && apply_filters( 'action_scheduler_enable_recreate_data_store', true ) ) {
|
||||
$table_list = array(
|
||||
'actionscheduler_actions',
|
||||
'actionscheduler_logs',
|
||||
'actionscheduler_groups',
|
||||
'actionscheduler_claims',
|
||||
);
|
||||
|
||||
$found_tables = $wpdb->get_col( "SHOW TABLES LIKE '{$wpdb->prefix}actionscheduler%'" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
foreach ( $table_list as $table_name ) {
|
||||
if ( ! in_array( $wpdb->prefix . $table_name, $found_tables ) ) {
|
||||
$this->admin_notices[] = array(
|
||||
'class' => 'error',
|
||||
'message' => __( 'It appears one or more database tables were missing. Attempting to re-create the missing table(s).' , 'action-scheduler' ),
|
||||
);
|
||||
$this->recreate_tables();
|
||||
parent::display_admin_notices();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $this->runner->has_maximum_concurrent_batches() ) {
|
||||
$claim_count = $this->store->get_claim_count();
|
||||
$this->admin_notices[] = array(
|
||||
'class' => 'updated',
|
||||
'message' => sprintf(
|
||||
/* translators: %s: amount of claims */
|
||||
_n(
|
||||
'Maximum simultaneous queues already in progress (%s queue). No additional queues will begin processing until the current queues are complete.',
|
||||
'Maximum simultaneous queues already in progress (%s queues). No additional queues will begin processing until the current queues are complete.',
|
||||
$claim_count,
|
||||
'action-scheduler'
|
||||
),
|
||||
$claim_count
|
||||
),
|
||||
);
|
||||
} elseif ( $this->store->has_pending_actions_due() ) {
|
||||
|
||||
$async_request_lock_expiration = ActionScheduler::lock()->get_expiration( 'async-request-runner' );
|
||||
|
||||
// No lock set or lock expired
|
||||
if ( false === $async_request_lock_expiration || $async_request_lock_expiration < time() ) {
|
||||
$in_progress_url = add_query_arg( 'status', 'in-progress', remove_query_arg( 'status' ) );
|
||||
/* translators: %s: process URL */
|
||||
$async_request_message = sprintf( __( 'A new queue has begun processing. <a href="%s">View actions in-progress »</a>', 'action-scheduler' ), esc_url( $in_progress_url ) );
|
||||
} else {
|
||||
/* translators: %d: seconds */
|
||||
$async_request_message = sprintf( __( 'The next queue will begin processing in approximately %d seconds.', 'action-scheduler' ), $async_request_lock_expiration - time() );
|
||||
}
|
||||
|
||||
$this->admin_notices[] = array(
|
||||
'class' => 'notice notice-info',
|
||||
'message' => $async_request_message,
|
||||
);
|
||||
}
|
||||
|
||||
$notification = get_transient( 'action_scheduler_admin_notice' );
|
||||
|
||||
if ( is_array( $notification ) ) {
|
||||
delete_transient( 'action_scheduler_admin_notice' );
|
||||
|
||||
$action = $this->store->fetch_action( $notification['action_id'] );
|
||||
$action_hook_html = '<strong><code>' . $action->get_hook() . '</code></strong>';
|
||||
if ( 1 == $notification['success'] ) {
|
||||
$class = 'updated';
|
||||
switch ( $notification['row_action_type'] ) {
|
||||
case 'run' :
|
||||
/* translators: %s: action HTML */
|
||||
$action_message_html = sprintf( __( 'Successfully executed action: %s', 'action-scheduler' ), $action_hook_html );
|
||||
break;
|
||||
case 'cancel' :
|
||||
/* translators: %s: action HTML */
|
||||
$action_message_html = sprintf( __( 'Successfully canceled action: %s', 'action-scheduler' ), $action_hook_html );
|
||||
break;
|
||||
default :
|
||||
/* translators: %s: action HTML */
|
||||
$action_message_html = sprintf( __( 'Successfully processed change for action: %s', 'action-scheduler' ), $action_hook_html );
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
$class = 'error';
|
||||
/* translators: 1: action HTML 2: action ID 3: error message */
|
||||
$action_message_html = sprintf( __( 'Could not process change for action: "%1$s" (ID: %2$d). Error: %3$s', 'action-scheduler' ), $action_hook_html, esc_html( $notification['action_id'] ), esc_html( $notification['error_message'] ) );
|
||||
}
|
||||
|
||||
$action_message_html = apply_filters( 'action_scheduler_admin_notice_html', $action_message_html, $action, $notification );
|
||||
|
||||
$this->admin_notices[] = array(
|
||||
'class' => $class,
|
||||
'message' => $action_message_html,
|
||||
);
|
||||
}
|
||||
|
||||
parent::display_admin_notices();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the scheduled date in a human friendly format.
|
||||
*
|
||||
* @param array $row The array representation of the current row of the table
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function column_schedule( $row ) {
|
||||
return $this->get_schedule_display_string( $row['schedule'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scheduled date in a human friendly format.
|
||||
*
|
||||
* @param ActionScheduler_Schedule $schedule
|
||||
* @return string
|
||||
*/
|
||||
protected function get_schedule_display_string( ActionScheduler_Schedule $schedule ) {
|
||||
|
||||
$schedule_display_string = '';
|
||||
|
||||
if ( ! $schedule->get_date() ) {
|
||||
return '0000-00-00 00:00:00';
|
||||
}
|
||||
|
||||
$next_timestamp = $schedule->get_date()->getTimestamp();
|
||||
|
||||
$schedule_display_string .= $schedule->get_date()->format( 'Y-m-d H:i:s O' );
|
||||
$schedule_display_string .= '<br/>';
|
||||
|
||||
if ( gmdate( 'U' ) > $next_timestamp ) {
|
||||
/* translators: %s: date interval */
|
||||
$schedule_display_string .= sprintf( __( ' (%s ago)', 'action-scheduler' ), self::human_interval( gmdate( 'U' ) - $next_timestamp ) );
|
||||
} else {
|
||||
/* translators: %s: date interval */
|
||||
$schedule_display_string .= sprintf( __( ' (%s)', 'action-scheduler' ), self::human_interval( $next_timestamp - gmdate( 'U' ) ) );
|
||||
}
|
||||
|
||||
return $schedule_display_string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bulk delete
|
||||
*
|
||||
* Deletes actions based on their ID. This is the handler for the bulk delete. It assumes the data
|
||||
* properly validated by the callee and it will delete the actions without any extra validation.
|
||||
*
|
||||
* @param array $ids
|
||||
* @param string $ids_sql Inherited and unused
|
||||
*/
|
||||
protected function bulk_delete( array $ids, $ids_sql ) {
|
||||
foreach ( $ids as $id ) {
|
||||
$this->store->delete_action( $id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the logic behind running an action. ActionScheduler_Abstract_ListTable validates the request and their
|
||||
* parameters are valid.
|
||||
*
|
||||
* @param int $action_id
|
||||
*/
|
||||
protected function row_action_cancel( $action_id ) {
|
||||
$this->process_row_action( $action_id, 'cancel' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the logic behind running an action. ActionScheduler_Abstract_ListTable validates the request and their
|
||||
* parameters are valid.
|
||||
*
|
||||
* @param int $action_id
|
||||
*/
|
||||
protected function row_action_run( $action_id ) {
|
||||
$this->process_row_action( $action_id, 'run' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Force the data store schema updates.
|
||||
*/
|
||||
protected function recreate_tables() {
|
||||
if ( is_a( $this->store, 'ActionScheduler_HybridStore' ) ) {
|
||||
$store = $this->store;
|
||||
} else {
|
||||
$store = new ActionScheduler_HybridStore();
|
||||
}
|
||||
add_action( 'action_scheduler/created_table', array( $store, 'set_autoincrement' ), 10, 2 );
|
||||
|
||||
$store_schema = new ActionScheduler_StoreSchema();
|
||||
$logger_schema = new ActionScheduler_LoggerSchema();
|
||||
$store_schema->register_tables( true );
|
||||
$logger_schema->register_tables( true );
|
||||
|
||||
remove_action( 'action_scheduler/created_table', array( $store, 'set_autoincrement' ), 10 );
|
||||
}
|
||||
/**
|
||||
* Implements the logic behind processing an action once an action link is clicked on the list table.
|
||||
*
|
||||
* @param int $action_id
|
||||
* @param string $row_action_type The type of action to perform on the action.
|
||||
*/
|
||||
protected function process_row_action( $action_id, $row_action_type ) {
|
||||
try {
|
||||
switch ( $row_action_type ) {
|
||||
case 'run' :
|
||||
$this->runner->process_action( $action_id, 'Admin List Table' );
|
||||
break;
|
||||
case 'cancel' :
|
||||
$this->store->cancel_action( $action_id );
|
||||
break;
|
||||
}
|
||||
$success = 1;
|
||||
$error_message = '';
|
||||
} catch ( Exception $e ) {
|
||||
$success = 0;
|
||||
$error_message = $e->getMessage();
|
||||
}
|
||||
|
||||
set_transient( 'action_scheduler_admin_notice', compact( 'action_id', 'success', 'error_message', 'row_action_type' ), 30 );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function prepare_items() {
|
||||
$this->prepare_column_headers();
|
||||
|
||||
$per_page = $this->get_items_per_page( $this->package . '_items_per_page', $this->items_per_page );
|
||||
$query = array(
|
||||
'per_page' => $per_page,
|
||||
'offset' => $this->get_items_offset(),
|
||||
'status' => $this->get_request_status(),
|
||||
'orderby' => $this->get_request_orderby(),
|
||||
'order' => $this->get_request_order(),
|
||||
'search' => $this->get_request_search_query(),
|
||||
);
|
||||
|
||||
$this->items = array();
|
||||
|
||||
$total_items = $this->store->query_actions( $query, 'count' );
|
||||
|
||||
$status_labels = $this->store->get_status_labels();
|
||||
|
||||
foreach ( $this->store->query_actions( $query ) as $action_id ) {
|
||||
try {
|
||||
$action = $this->store->fetch_action( $action_id );
|
||||
} catch ( Exception $e ) {
|
||||
continue;
|
||||
}
|
||||
if ( is_a( $action, 'ActionScheduler_NullAction' ) ) {
|
||||
continue;
|
||||
}
|
||||
$this->items[ $action_id ] = array(
|
||||
'ID' => $action_id,
|
||||
'hook' => $action->get_hook(),
|
||||
'status_name' => $this->store->get_status( $action_id ),
|
||||
'status' => $status_labels[ $this->store->get_status( $action_id ) ],
|
||||
'args' => $action->get_args(),
|
||||
'group' => $action->get_group(),
|
||||
'log_entries' => $this->logger->get_logs( $action_id ),
|
||||
'claim_id' => $this->store->get_claim_id( $action_id ),
|
||||
'recurrence' => $this->get_recurrence( $action ),
|
||||
'schedule' => $action->get_schedule(),
|
||||
);
|
||||
}
|
||||
|
||||
$this->set_pagination_args( array(
|
||||
'total_items' => $total_items,
|
||||
'per_page' => $per_page,
|
||||
'total_pages' => ceil( $total_items / $per_page ),
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the available statuses so the user can click to filter.
|
||||
*/
|
||||
protected function display_filter_by_status() {
|
||||
$this->status_counts = $this->store->action_counts();
|
||||
parent::display_filter_by_status();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text to display in the search box on the list table.
|
||||
*/
|
||||
protected function get_search_box_button_text() {
|
||||
return __( 'Search hook, args and claim ID', 'action-scheduler' );
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class ActionScheduler_LogEntry
|
||||
*/
|
||||
class ActionScheduler_LogEntry {
|
||||
|
||||
/**
|
||||
* @var int $action_id
|
||||
*/
|
||||
protected $action_id = '';
|
||||
|
||||
/**
|
||||
* @var string $message
|
||||
*/
|
||||
protected $message = '';
|
||||
|
||||
/**
|
||||
* @var Datetime $date
|
||||
*/
|
||||
protected $date;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param mixed $action_id Action ID
|
||||
* @param string $message Message
|
||||
* @param Datetime $date Datetime object with the time when this log entry was created. If this parameter is
|
||||
* not provided a new Datetime object (with current time) will be created.
|
||||
*/
|
||||
public function __construct( $action_id, $message, $date = null ) {
|
||||
|
||||
/*
|
||||
* ActionScheduler_wpCommentLogger::get_entry() previously passed a 3rd param of $comment->comment_type
|
||||
* to ActionScheduler_LogEntry::__construct(), goodness knows why, and the Follow-up Emails plugin
|
||||
* hard-codes loading its own version of ActionScheduler_wpCommentLogger with that out-dated method,
|
||||
* goodness knows why, so we need to guard against that here instead of using a DateTime type declaration
|
||||
* for the constructor's 3rd param of $date and causing a fatal error with older versions of FUE.
|
||||
*/
|
||||
if ( null !== $date && ! is_a( $date, 'DateTime' ) ) {
|
||||
_doing_it_wrong( __METHOD__, 'The third parameter must be a valid DateTime instance, or null.', '2.0.0' );
|
||||
$date = null;
|
||||
}
|
||||
|
||||
$this->action_id = $action_id;
|
||||
$this->message = $message;
|
||||
$this->date = $date ? $date : new Datetime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the date when this log entry was created
|
||||
*
|
||||
* @return Datetime
|
||||
*/
|
||||
public function get_date() {
|
||||
return $this->date;
|
||||
}
|
||||
|
||||
public function get_action_id() {
|
||||
return $this->action_id;
|
||||
}
|
||||
|
||||
public function get_message() {
|
||||
return $this->message;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class ActionScheduler_NullLogEntry
|
||||
*/
|
||||
class ActionScheduler_NullLogEntry extends ActionScheduler_LogEntry {
|
||||
public function __construct( $action_id = '', $message = '' ) {
|
||||
// nothing to see here
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Provide a way to set simple transient locks to block behaviour
|
||||
* for up-to a given duration.
|
||||
*
|
||||
* Class ActionScheduler_OptionLock
|
||||
* @since 3.0.0
|
||||
*/
|
||||
class ActionScheduler_OptionLock extends ActionScheduler_Lock {
|
||||
|
||||
/**
|
||||
* Set a lock using options for a given amount of time (60 seconds by default).
|
||||
*
|
||||
* Using an autoloaded option avoids running database queries or other resource intensive tasks
|
||||
* on frequently triggered hooks, like 'init' or 'shutdown'.
|
||||
*
|
||||
* For example, ActionScheduler_QueueRunner->maybe_dispatch_async_request() uses a lock to avoid
|
||||
* calling ActionScheduler_QueueRunner->has_maximum_concurrent_batches() every time the 'shutdown',
|
||||
* hook is triggered, because that method calls ActionScheduler_QueueRunner->store->get_claim_count()
|
||||
* to find the current number of claims in the database.
|
||||
*
|
||||
* @param string $lock_type A string to identify different lock types.
|
||||
* @bool True if lock value has changed, false if not or if set failed.
|
||||
*/
|
||||
public function set( $lock_type ) {
|
||||
return update_option( $this->get_key( $lock_type ), time() + $this->get_duration( $lock_type ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* If a lock is set, return the timestamp it was set to expiry.
|
||||
*
|
||||
* @param string $lock_type A string to identify different lock types.
|
||||
* @return bool|int False if no lock is set, otherwise the timestamp for when the lock is set to expire.
|
||||
*/
|
||||
public function get_expiration( $lock_type ) {
|
||||
return get_option( $this->get_key( $lock_type ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the key to use for storing the lock in the transient
|
||||
*
|
||||
* @param string $lock_type A string to identify different lock types.
|
||||
* @return string
|
||||
*/
|
||||
protected function get_key( $lock_type ) {
|
||||
return sprintf( 'action_scheduler_lock_%s', $lock_type );
|
||||
}
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class ActionScheduler_QueueCleaner
|
||||
*/
|
||||
class ActionScheduler_QueueCleaner {
|
||||
|
||||
/** @var int */
|
||||
protected $batch_size;
|
||||
|
||||
/** @var ActionScheduler_Store */
|
||||
private $store = null;
|
||||
|
||||
/**
|
||||
* 31 days in seconds.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $month_in_seconds = 2678400;
|
||||
|
||||
/**
|
||||
* ActionScheduler_QueueCleaner constructor.
|
||||
*
|
||||
* @param ActionScheduler_Store $store The store instance.
|
||||
* @param int $batch_size The batch size.
|
||||
*/
|
||||
public function __construct( ActionScheduler_Store $store = null, $batch_size = 20 ) {
|
||||
$this->store = $store ? $store : ActionScheduler_Store::instance();
|
||||
$this->batch_size = $batch_size;
|
||||
}
|
||||
|
||||
public function delete_old_actions() {
|
||||
$lifespan = apply_filters( 'action_scheduler_retention_period', $this->month_in_seconds );
|
||||
$cutoff = as_get_datetime_object($lifespan.' seconds ago');
|
||||
|
||||
$statuses_to_purge = array(
|
||||
ActionScheduler_Store::STATUS_COMPLETE,
|
||||
ActionScheduler_Store::STATUS_CANCELED,
|
||||
);
|
||||
|
||||
foreach ( $statuses_to_purge as $status ) {
|
||||
$actions_to_delete = $this->store->query_actions( array(
|
||||
'status' => $status,
|
||||
'modified' => $cutoff,
|
||||
'modified_compare' => '<=',
|
||||
'per_page' => $this->get_batch_size(),
|
||||
) );
|
||||
|
||||
foreach ( $actions_to_delete as $action_id ) {
|
||||
try {
|
||||
$this->store->delete_action( $action_id );
|
||||
} catch ( Exception $e ) {
|
||||
|
||||
/**
|
||||
* Notify 3rd party code of exceptions when deleting a completed action older than the retention period
|
||||
*
|
||||
* This hook provides a way for 3rd party code to log or otherwise handle exceptions relating to their
|
||||
* actions.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @param int $action_id The scheduled actions ID in the data store
|
||||
* @param Exception $e The exception thrown when attempting to delete the action from the data store
|
||||
* @param int $lifespan The retention period, in seconds, for old actions
|
||||
* @param int $count_of_actions_to_delete The number of old actions being deleted in this batch
|
||||
*/
|
||||
do_action( 'action_scheduler_failed_old_action_deletion', $action_id, $e, $lifespan, count( $actions_to_delete ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unclaim pending actions that have not been run within a given time limit.
|
||||
*
|
||||
* When called by ActionScheduler_Abstract_QueueRunner::run_cleanup(), the time limit passed
|
||||
* as a parameter is 10x the time limit used for queue processing.
|
||||
*
|
||||
* @param int $time_limit The number of seconds to allow a queue to run before unclaiming its pending actions. Default 300 (5 minutes).
|
||||
*/
|
||||
public function reset_timeouts( $time_limit = 300 ) {
|
||||
$timeout = apply_filters( 'action_scheduler_timeout_period', $time_limit );
|
||||
if ( $timeout < 0 ) {
|
||||
return;
|
||||
}
|
||||
$cutoff = as_get_datetime_object($timeout.' seconds ago');
|
||||
$actions_to_reset = $this->store->query_actions( array(
|
||||
'status' => ActionScheduler_Store::STATUS_PENDING,
|
||||
'modified' => $cutoff,
|
||||
'modified_compare' => '<=',
|
||||
'claimed' => true,
|
||||
'per_page' => $this->get_batch_size(),
|
||||
) );
|
||||
|
||||
foreach ( $actions_to_reset as $action_id ) {
|
||||
$this->store->unclaim_action( $action_id );
|
||||
do_action( 'action_scheduler_reset_action', $action_id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark actions that have been running for more than a given time limit as failed, based on
|
||||
* the assumption some uncatachable and unloggable fatal error occurred during processing.
|
||||
*
|
||||
* When called by ActionScheduler_Abstract_QueueRunner::run_cleanup(), the time limit passed
|
||||
* as a parameter is 10x the time limit used for queue processing.
|
||||
*
|
||||
* @param int $time_limit The number of seconds to allow an action to run before it is considered to have failed. Default 300 (5 minutes).
|
||||
*/
|
||||
public function mark_failures( $time_limit = 300 ) {
|
||||
$timeout = apply_filters( 'action_scheduler_failure_period', $time_limit );
|
||||
if ( $timeout < 0 ) {
|
||||
return;
|
||||
}
|
||||
$cutoff = as_get_datetime_object($timeout.' seconds ago');
|
||||
$actions_to_reset = $this->store->query_actions( array(
|
||||
'status' => ActionScheduler_Store::STATUS_RUNNING,
|
||||
'modified' => $cutoff,
|
||||
'modified_compare' => '<=',
|
||||
'per_page' => $this->get_batch_size(),
|
||||
) );
|
||||
|
||||
foreach ( $actions_to_reset as $action_id ) {
|
||||
$this->store->mark_failure( $action_id );
|
||||
do_action( 'action_scheduler_failed_action', $action_id, $timeout );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do all of the cleaning actions.
|
||||
*
|
||||
* @param int $time_limit The number of seconds to use as the timeout and failure period. Default 300 (5 minutes).
|
||||
* @author Jeremy Pry
|
||||
*/
|
||||
public function clean( $time_limit = 300 ) {
|
||||
$this->delete_old_actions();
|
||||
$this->reset_timeouts( $time_limit );
|
||||
$this->mark_failures( $time_limit );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the batch size for cleaning the queue.
|
||||
*
|
||||
* @author Jeremy Pry
|
||||
* @return int
|
||||
*/
|
||||
protected function get_batch_size() {
|
||||
/**
|
||||
* Filter the batch size when cleaning the queue.
|
||||
*
|
||||
* @param int $batch_size The number of actions to clean in one batch.
|
||||
*/
|
||||
return absint( apply_filters( 'action_scheduler_cleanup_batch_size', $this->batch_size ) );
|
||||
}
|
||||
}
|
@ -0,0 +1,197 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class ActionScheduler_QueueRunner
|
||||
*/
|
||||
class ActionScheduler_QueueRunner extends ActionScheduler_Abstract_QueueRunner {
|
||||
const WP_CRON_HOOK = 'action_scheduler_run_queue';
|
||||
|
||||
const WP_CRON_SCHEDULE = 'every_minute';
|
||||
|
||||
/** @var ActionScheduler_AsyncRequest_QueueRunner */
|
||||
protected $async_request;
|
||||
|
||||
/** @var ActionScheduler_QueueRunner */
|
||||
private static $runner = null;
|
||||
|
||||
/**
|
||||
* @return ActionScheduler_QueueRunner
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public static function instance() {
|
||||
if ( empty(self::$runner) ) {
|
||||
$class = apply_filters('action_scheduler_queue_runner_class', 'ActionScheduler_QueueRunner');
|
||||
self::$runner = new $class();
|
||||
}
|
||||
return self::$runner;
|
||||
}
|
||||
|
||||
/**
|
||||
* ActionScheduler_QueueRunner constructor.
|
||||
*
|
||||
* @param ActionScheduler_Store $store
|
||||
* @param ActionScheduler_FatalErrorMonitor $monitor
|
||||
* @param ActionScheduler_QueueCleaner $cleaner
|
||||
*/
|
||||
public function __construct( ActionScheduler_Store $store = null, ActionScheduler_FatalErrorMonitor $monitor = null, ActionScheduler_QueueCleaner $cleaner = null, ActionScheduler_AsyncRequest_QueueRunner $async_request = null ) {
|
||||
parent::__construct( $store, $monitor, $cleaner );
|
||||
|
||||
if ( is_null( $async_request ) ) {
|
||||
$async_request = new ActionScheduler_AsyncRequest_QueueRunner( $this->store );
|
||||
}
|
||||
|
||||
$this->async_request = $async_request;
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function init() {
|
||||
|
||||
add_filter( 'cron_schedules', array( self::instance(), 'add_wp_cron_schedule' ) );
|
||||
|
||||
// Check for and remove any WP Cron hook scheduled by Action Scheduler < 3.0.0, which didn't include the $context param
|
||||
$next_timestamp = wp_next_scheduled( self::WP_CRON_HOOK );
|
||||
if ( $next_timestamp ) {
|
||||
wp_unschedule_event( $next_timestamp, self::WP_CRON_HOOK );
|
||||
}
|
||||
|
||||
$cron_context = array( 'WP Cron' );
|
||||
|
||||
if ( ! wp_next_scheduled( self::WP_CRON_HOOK, $cron_context ) ) {
|
||||
$schedule = apply_filters( 'action_scheduler_run_schedule', self::WP_CRON_SCHEDULE );
|
||||
wp_schedule_event( time(), $schedule, self::WP_CRON_HOOK, $cron_context );
|
||||
}
|
||||
|
||||
add_action( self::WP_CRON_HOOK, array( self::instance(), 'run' ) );
|
||||
$this->hook_dispatch_async_request();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook check for dispatching an async request.
|
||||
*/
|
||||
public function hook_dispatch_async_request() {
|
||||
add_action( 'shutdown', array( $this, 'maybe_dispatch_async_request' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Unhook check for dispatching an async request.
|
||||
*/
|
||||
public function unhook_dispatch_async_request() {
|
||||
remove_action( 'shutdown', array( $this, 'maybe_dispatch_async_request' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we should dispatch an async request to process actions.
|
||||
*
|
||||
* This method is attached to 'shutdown', so is called frequently. To avoid slowing down
|
||||
* the site, it mitigates the work performed in each request by:
|
||||
* 1. checking if it's in the admin context and then
|
||||
* 2. haven't run on the 'shutdown' hook within the lock time (60 seconds by default)
|
||||
* 3. haven't exceeded the number of allowed batches.
|
||||
*
|
||||
* The order of these checks is important, because they run from a check on a value:
|
||||
* 1. in memory - is_admin() maps to $GLOBALS or the WP_ADMIN constant
|
||||
* 2. in memory - transients use autoloaded options by default
|
||||
* 3. from a database query - has_maximum_concurrent_batches() run the query
|
||||
* $this->store->get_claim_count() to find the current number of claims in the DB.
|
||||
*
|
||||
* If all of these conditions are met, then we request an async runner check whether it
|
||||
* should dispatch a request to process pending actions.
|
||||
*/
|
||||
public function maybe_dispatch_async_request() {
|
||||
if ( is_admin() && ! ActionScheduler::lock()->is_locked( 'async-request-runner' ) ) {
|
||||
// Only start an async queue at most once every 60 seconds
|
||||
ActionScheduler::lock()->set( 'async-request-runner' );
|
||||
$this->async_request->maybe_dispatch();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process actions in the queue. Attached to self::WP_CRON_HOOK i.e. 'action_scheduler_run_queue'
|
||||
*
|
||||
* The $context param of this method defaults to 'WP Cron', because prior to Action Scheduler 3.0.0
|
||||
* that was the only context in which this method was run, and the self::WP_CRON_HOOK hook had no context
|
||||
* passed along with it. New code calling this method directly, or by triggering the self::WP_CRON_HOOK,
|
||||
* should set a context as the first parameter. For an example of this, refer to the code seen in
|
||||
* @see ActionScheduler_AsyncRequest_QueueRunner::handle()
|
||||
*
|
||||
* @param string $context Optional identifer for the context in which this action is being processed, e.g. 'WP CLI' or 'WP Cron'
|
||||
* Generally, this should be capitalised and not localised as it's a proper noun.
|
||||
* @return int The number of actions processed.
|
||||
*/
|
||||
public function run( $context = 'WP Cron' ) {
|
||||
ActionScheduler_Compatibility::raise_memory_limit();
|
||||
ActionScheduler_Compatibility::raise_time_limit( $this->get_time_limit() );
|
||||
do_action( 'action_scheduler_before_process_queue' );
|
||||
$this->run_cleanup();
|
||||
$processed_actions = 0;
|
||||
if ( false === $this->has_maximum_concurrent_batches() ) {
|
||||
$batch_size = apply_filters( 'action_scheduler_queue_runner_batch_size', 25 );
|
||||
do {
|
||||
$processed_actions_in_batch = $this->do_batch( $batch_size, $context );
|
||||
$processed_actions += $processed_actions_in_batch;
|
||||
} while ( $processed_actions_in_batch > 0 && ! $this->batch_limits_exceeded( $processed_actions ) ); // keep going until we run out of actions, time, or memory
|
||||
}
|
||||
|
||||
do_action( 'action_scheduler_after_process_queue' );
|
||||
return $processed_actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a batch of actions pending in the queue.
|
||||
*
|
||||
* Actions are processed by claiming a set of pending actions then processing each one until either the batch
|
||||
* size is completed, or memory or time limits are reached, defined by @see $this->batch_limits_exceeded().
|
||||
*
|
||||
* @param int $size The maximum number of actions to process in the batch.
|
||||
* @param string $context Optional identifer for the context in which this action is being processed, e.g. 'WP CLI' or 'WP Cron'
|
||||
* Generally, this should be capitalised and not localised as it's a proper noun.
|
||||
* @return int The number of actions processed.
|
||||
*/
|
||||
protected function do_batch( $size = 100, $context = '' ) {
|
||||
$claim = $this->store->stake_claim($size);
|
||||
$this->monitor->attach($claim);
|
||||
$processed_actions = 0;
|
||||
|
||||
foreach ( $claim->get_actions() as $action_id ) {
|
||||
// bail if we lost the claim
|
||||
if ( ! in_array( $action_id, $this->store->find_actions_by_claim_id( $claim->get_id() ) ) ) {
|
||||
break;
|
||||
}
|
||||
$this->process_action( $action_id, $context );
|
||||
$processed_actions++;
|
||||
|
||||
if ( $this->batch_limits_exceeded( $processed_actions ) ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->store->release_claim($claim);
|
||||
$this->monitor->detach();
|
||||
$this->clear_caches();
|
||||
return $processed_actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Running large batches can eat up memory, as WP adds data to its object cache.
|
||||
*
|
||||
* If using a persistent object store, this has the side effect of flushing that
|
||||
* as well, so this is disabled by default. To enable:
|
||||
*
|
||||
* add_filter( 'action_scheduler_queue_runner_flush_cache', '__return_true' );
|
||||
*/
|
||||
protected function clear_caches() {
|
||||
if ( ! wp_using_ext_object_cache() || apply_filters( 'action_scheduler_queue_runner_flush_cache', false ) ) {
|
||||
wp_cache_flush();
|
||||
}
|
||||
}
|
||||
|
||||
public function add_wp_cron_schedule( $schedules ) {
|
||||
$schedules['every_minute'] = array(
|
||||
'interval' => 60, // in seconds
|
||||
'display' => __( 'Every minute', 'action-scheduler' ),
|
||||
);
|
||||
|
||||
return $schedules;
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class ActionScheduler_Versions
|
||||
*/
|
||||
class ActionScheduler_Versions {
|
||||
/**
|
||||
* @var ActionScheduler_Versions
|
||||
*/
|
||||
private static $instance = NULL;
|
||||
|
||||
private $versions = array();
|
||||
|
||||
public function register( $version_string, $initialization_callback ) {
|
||||
if ( isset($this->versions[$version_string]) ) {
|
||||
return FALSE;
|
||||
}
|
||||
$this->versions[$version_string] = $initialization_callback;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
public function get_versions() {
|
||||
return $this->versions;
|
||||
}
|
||||
|
||||
public function latest_version() {
|
||||
$keys = array_keys($this->versions);
|
||||
if ( empty($keys) ) {
|
||||
return false;
|
||||
}
|
||||
uasort( $keys, 'version_compare' );
|
||||
return end($keys);
|
||||
}
|
||||
|
||||
public function latest_version_callback() {
|
||||
$latest = $this->latest_version();
|
||||
if ( empty($latest) || !isset($this->versions[$latest]) ) {
|
||||
return '__return_null';
|
||||
}
|
||||
return $this->versions[$latest];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ActionScheduler_Versions
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public static function instance() {
|
||||
if ( empty(self::$instance) ) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public static function initialize_latest_version() {
|
||||
$self = self::instance();
|
||||
call_user_func($self->latest_version_callback());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class ActionScheduler_WPCommentCleaner
|
||||
*
|
||||
* @since 3.0.0
|
||||
*/
|
||||
class ActionScheduler_WPCommentCleaner {
|
||||
|
||||
/**
|
||||
* Post migration hook used to cleanup the WP comment table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $cleanup_hook = 'action_scheduler/cleanup_wp_comment_logs';
|
||||
|
||||
/**
|
||||
* An instance of the ActionScheduler_wpCommentLogger class to interact with the comments table.
|
||||
*
|
||||
* This instance should only be used as an interface. It should not be initialized.
|
||||
*
|
||||
* @var ActionScheduler_wpCommentLogger
|
||||
*/
|
||||
protected static $wp_comment_logger = null;
|
||||
|
||||
/**
|
||||
* The key used to store the cached value of whether there are logs in the WP comment table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $has_logs_option_key = 'as_has_wp_comment_logs';
|
||||
|
||||
/**
|
||||
* Initialize the class and attach callbacks.
|
||||
*/
|
||||
public static function init() {
|
||||
if ( empty( self::$wp_comment_logger ) ) {
|
||||
self::$wp_comment_logger = new ActionScheduler_wpCommentLogger();
|
||||
}
|
||||
|
||||
add_action( self::$cleanup_hook, array( __CLASS__, 'delete_all_action_comments' ) );
|
||||
|
||||
// While there are orphaned logs left in the comments table, we need to attach the callbacks which filter comment counts.
|
||||
add_action( 'pre_get_comments', array( self::$wp_comment_logger, 'filter_comment_queries' ), 10, 1 );
|
||||
add_action( 'wp_count_comments', array( self::$wp_comment_logger, 'filter_comment_count' ), 20, 2 ); // run after WC_Comments::wp_count_comments() to make sure we exclude order notes and action logs
|
||||
add_action( 'comment_feed_where', array( self::$wp_comment_logger, 'filter_comment_feed' ), 10, 2 );
|
||||
|
||||
// Action Scheduler may be displayed as a Tools screen or WooCommerce > Status administration screen
|
||||
add_action( 'load-tools_page_action-scheduler', array( __CLASS__, 'register_admin_notice' ) );
|
||||
add_action( 'load-woocommerce_page_wc-status', array( __CLASS__, 'register_admin_notice' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if there are log entries in the wp comments table.
|
||||
*
|
||||
* Uses the flag set on migration completion set by @see self::maybe_schedule_cleanup().
|
||||
*
|
||||
* @return boolean Whether there are scheduled action comments in the comments table.
|
||||
*/
|
||||
public static function has_logs() {
|
||||
return 'yes' === get_option( self::$has_logs_option_key );
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules the WP Post comment table cleanup to run in 6 months if it's not already scheduled.
|
||||
* Attached to the migration complete hook 'action_scheduler/migration_complete'.
|
||||
*/
|
||||
public static function maybe_schedule_cleanup() {
|
||||
if ( (bool) get_comments( array( 'type' => ActionScheduler_wpCommentLogger::TYPE, 'number' => 1, 'fields' => 'ids' ) ) ) {
|
||||
update_option( self::$has_logs_option_key, 'yes' );
|
||||
|
||||
if ( ! as_next_scheduled_action( self::$cleanup_hook ) ) {
|
||||
as_schedule_single_action( gmdate( 'U' ) + ( 6 * MONTH_IN_SECONDS ), self::$cleanup_hook );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all action comments from the WP Comments table.
|
||||
*/
|
||||
public static function delete_all_action_comments() {
|
||||
global $wpdb;
|
||||
$wpdb->delete( $wpdb->comments, array( 'comment_type' => ActionScheduler_wpCommentLogger::TYPE, 'comment_agent' => ActionScheduler_wpCommentLogger::AGENT ) );
|
||||
delete_option( self::$has_logs_option_key );
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers admin notices about the orphaned action logs.
|
||||
*/
|
||||
public static function register_admin_notice() {
|
||||
add_action( 'admin_notices', array( __CLASS__, 'print_admin_notice' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints details about the orphaned action logs and includes information on where to learn more.
|
||||
*/
|
||||
public static function print_admin_notice() {
|
||||
$next_cleanup_message = '';
|
||||
$next_scheduled_cleanup_hook = as_next_scheduled_action( self::$cleanup_hook );
|
||||
|
||||
if ( $next_scheduled_cleanup_hook ) {
|
||||
/* translators: %s: date interval */
|
||||
$next_cleanup_message = sprintf( __( 'This data will be deleted in %s.', 'action-scheduler' ), human_time_diff( gmdate( 'U' ), $next_scheduled_cleanup_hook ) );
|
||||
}
|
||||
|
||||
$notice = sprintf(
|
||||
/* translators: 1: next cleanup message 2: github issue URL */
|
||||
__( 'Action Scheduler has migrated data to custom tables; however, orphaned log entries exist in the WordPress Comments table. %1$s <a href="%2$s">Learn more »</a>', 'action-scheduler' ),
|
||||
$next_cleanup_message,
|
||||
'https://github.com/woocommerce/action-scheduler/issues/368'
|
||||
);
|
||||
|
||||
echo '<div class="notice notice-warning"><p>' . wp_kses_post( $notice ) . '</p></div>';
|
||||
}
|
||||
}
|
@ -0,0 +1,152 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class ActionScheduler_wcSystemStatus
|
||||
*/
|
||||
class ActionScheduler_wcSystemStatus {
|
||||
|
||||
/**
|
||||
* The active data stores
|
||||
*
|
||||
* @var ActionScheduler_Store
|
||||
*/
|
||||
protected $store;
|
||||
|
||||
function __construct( $store ) {
|
||||
$this->store = $store;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display action data, including number of actions grouped by status and the oldest & newest action in each status.
|
||||
*
|
||||
* Helpful to identify issues, like a clogged queue.
|
||||
*/
|
||||
public function render() {
|
||||
$action_counts = $this->store->action_counts();
|
||||
$status_labels = $this->store->get_status_labels();
|
||||
$oldest_and_newest = $this->get_oldest_and_newest( array_keys( $status_labels ) );
|
||||
|
||||
$this->get_template( $status_labels, $action_counts, $oldest_and_newest );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get oldest and newest scheduled dates for a given set of statuses.
|
||||
*
|
||||
* @param array $status_keys Set of statuses to find oldest & newest action for.
|
||||
* @return array
|
||||
*/
|
||||
protected function get_oldest_and_newest( $status_keys ) {
|
||||
|
||||
$oldest_and_newest = array();
|
||||
|
||||
foreach ( $status_keys as $status ) {
|
||||
$oldest_and_newest[ $status ] = array(
|
||||
'oldest' => '–',
|
||||
'newest' => '–',
|
||||
);
|
||||
|
||||
if ( 'in-progress' === $status ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$oldest_and_newest[ $status ]['oldest'] = $this->get_action_status_date( $status, 'oldest' );
|
||||
$oldest_and_newest[ $status ]['newest'] = $this->get_action_status_date( $status, 'newest' );
|
||||
}
|
||||
|
||||
return $oldest_and_newest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get oldest or newest scheduled date for a given status.
|
||||
*
|
||||
* @param string $status Action status label/name string.
|
||||
* @param string $date_type Oldest or Newest.
|
||||
* @return DateTime
|
||||
*/
|
||||
protected function get_action_status_date( $status, $date_type = 'oldest' ) {
|
||||
|
||||
$order = 'oldest' === $date_type ? 'ASC' : 'DESC';
|
||||
|
||||
$action = $this->store->query_actions( array(
|
||||
'claimed' => false,
|
||||
'status' => $status,
|
||||
'per_page' => 1,
|
||||
'order' => $order,
|
||||
) );
|
||||
|
||||
if ( ! empty( $action ) ) {
|
||||
$date_object = $this->store->get_date( $action[0] );
|
||||
$action_date = $date_object->format( 'Y-m-d H:i:s O' );
|
||||
} else {
|
||||
$action_date = '–';
|
||||
}
|
||||
|
||||
return $action_date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get oldest or newest scheduled date for a given status.
|
||||
*
|
||||
* @param array $status_labels Set of statuses to find oldest & newest action for.
|
||||
* @param array $action_counts Number of actions grouped by status.
|
||||
* @param array $oldest_and_newest Date of the oldest and newest action with each status.
|
||||
*/
|
||||
protected function get_template( $status_labels, $action_counts, $oldest_and_newest ) {
|
||||
$as_version = ActionScheduler_Versions::instance()->latest_version();
|
||||
?>
|
||||
|
||||
<table class="wc_status_table widefat" cellspacing="0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="5" data-export-label="Action Scheduler"><h2><?php esc_html_e( 'Action Scheduler', 'action-scheduler' ); ?><?php echo wc_help_tip( esc_html__( 'This section shows scheduled action counts.', 'action-scheduler' ) ); ?></h2></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" data-export-label="Version"><?php esc_html_e( 'Version:', 'action-scheduler' ); ?></td>
|
||||
<td colspan="3"><?php echo esc_html( $as_version ); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong><?php esc_html_e( 'Action Status', 'action-scheduler' ); ?></strong></td>
|
||||
<td class="help"> </td>
|
||||
<td><strong><?php esc_html_e( 'Count', 'action-scheduler' ); ?></strong></td>
|
||||
<td><strong><?php esc_html_e( 'Oldest Scheduled Date', 'action-scheduler' ); ?></strong></td>
|
||||
<td><strong><?php esc_html_e( 'Newest Scheduled Date', 'action-scheduler' ); ?></strong></td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
foreach ( $action_counts as $status => $count ) {
|
||||
// WC uses the 3rd column for export, so we need to display more data in that (hidden when viewed as part of the table) and add an empty 2nd column.
|
||||
printf(
|
||||
'<tr><td>%1$s</td><td> </td><td>%2$s<span style="display: none;">, Oldest: %3$s, Newest: %4$s</span></td><td>%3$s</td><td>%4$s</td></tr>',
|
||||
esc_html( $status_labels[ $status ] ),
|
||||
number_format_i18n( $count ),
|
||||
$oldest_and_newest[ $status ]['oldest'],
|
||||
$oldest_and_newest[ $status ]['newest']
|
||||
);
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* is triggered when invoking inaccessible methods in an object context.
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $arguments
|
||||
*
|
||||
* @return mixed
|
||||
* @link https://php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.methods
|
||||
*/
|
||||
public function __call( $name, $arguments ) {
|
||||
switch ( $name ) {
|
||||
case 'print':
|
||||
_deprecated_function( __CLASS__ . '::print()', '2.2.4', __CLASS__ . '::render()' );
|
||||
return call_user_func_array( array( $this, 'render' ), $arguments );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,197 @@
|
||||
<?php
|
||||
|
||||
use Action_Scheduler\WP_CLI\ProgressBar;
|
||||
|
||||
/**
|
||||
* WP CLI Queue runner.
|
||||
*
|
||||
* This class can only be called from within a WP CLI instance.
|
||||
*/
|
||||
class ActionScheduler_WPCLI_QueueRunner extends ActionScheduler_Abstract_QueueRunner {
|
||||
|
||||
/** @var array */
|
||||
protected $actions;
|
||||
|
||||
/** @var ActionScheduler_ActionClaim */
|
||||
protected $claim;
|
||||
|
||||
/** @var \cli\progress\Bar */
|
||||
protected $progress_bar;
|
||||
|
||||
/**
|
||||
* ActionScheduler_WPCLI_QueueRunner constructor.
|
||||
*
|
||||
* @param ActionScheduler_Store $store
|
||||
* @param ActionScheduler_FatalErrorMonitor $monitor
|
||||
* @param ActionScheduler_QueueCleaner $cleaner
|
||||
*
|
||||
* @throws Exception When this is not run within WP CLI
|
||||
*/
|
||||
public function __construct( ActionScheduler_Store $store = null, ActionScheduler_FatalErrorMonitor $monitor = null, ActionScheduler_QueueCleaner $cleaner = null ) {
|
||||
if ( ! ( defined( 'WP_CLI' ) && WP_CLI ) ) {
|
||||
/* translators: %s php class name */
|
||||
throw new Exception( sprintf( __( 'The %s class can only be run within WP CLI.', 'action-scheduler' ), __CLASS__ ) );
|
||||
}
|
||||
|
||||
parent::__construct( $store, $monitor, $cleaner );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the Queue before processing.
|
||||
*
|
||||
* @author Jeremy Pry
|
||||
*
|
||||
* @param int $batch_size The batch size to process.
|
||||
* @param array $hooks The hooks being used to filter the actions claimed in this batch.
|
||||
* @param string $group The group of actions to claim with this batch.
|
||||
* @param bool $force Whether to force running even with too many concurrent processes.
|
||||
*
|
||||
* @return int The number of actions that will be run.
|
||||
* @throws \WP_CLI\ExitException When there are too many concurrent batches.
|
||||
*/
|
||||
public function setup( $batch_size, $hooks = array(), $group = '', $force = false ) {
|
||||
$this->run_cleanup();
|
||||
$this->add_hooks();
|
||||
|
||||
// Check to make sure there aren't too many concurrent processes running.
|
||||
if ( $this->has_maximum_concurrent_batches() ) {
|
||||
if ( $force ) {
|
||||
WP_CLI::warning( __( 'There are too many concurrent batches, but the run is forced to continue.', 'action-scheduler' ) );
|
||||
} else {
|
||||
WP_CLI::error( __( 'There are too many concurrent batches.', 'action-scheduler' ) );
|
||||
}
|
||||
}
|
||||
|
||||
// Stake a claim and store it.
|
||||
$this->claim = $this->store->stake_claim( $batch_size, null, $hooks, $group );
|
||||
$this->monitor->attach( $this->claim );
|
||||
$this->actions = $this->claim->get_actions();
|
||||
|
||||
return count( $this->actions );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add our hooks to the appropriate actions.
|
||||
*
|
||||
* @author Jeremy Pry
|
||||
*/
|
||||
protected function add_hooks() {
|
||||
add_action( 'action_scheduler_before_execute', array( $this, 'before_execute' ) );
|
||||
add_action( 'action_scheduler_after_execute', array( $this, 'after_execute' ), 10, 2 );
|
||||
add_action( 'action_scheduler_failed_execution', array( $this, 'action_failed' ), 10, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the WP CLI progress bar.
|
||||
*
|
||||
* @author Jeremy Pry
|
||||
*/
|
||||
protected function setup_progress_bar() {
|
||||
$count = count( $this->actions );
|
||||
$this->progress_bar = new ProgressBar(
|
||||
/* translators: %d: amount of actions */
|
||||
sprintf( _n( 'Running %d action', 'Running %d actions', $count, 'action-scheduler' ), number_format_i18n( $count ) ),
|
||||
$count
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process actions in the queue.
|
||||
*
|
||||
* @author Jeremy Pry
|
||||
*
|
||||
* @param string $context Optional runner context. Default 'WP CLI'.
|
||||
*
|
||||
* @return int The number of actions processed.
|
||||
*/
|
||||
public function run( $context = 'WP CLI' ) {
|
||||
do_action( 'action_scheduler_before_process_queue' );
|
||||
$this->setup_progress_bar();
|
||||
foreach ( $this->actions as $action_id ) {
|
||||
// Error if we lost the claim.
|
||||
if ( ! in_array( $action_id, $this->store->find_actions_by_claim_id( $this->claim->get_id() ) ) ) {
|
||||
WP_CLI::warning( __( 'The claim has been lost. Aborting current batch.', 'action-scheduler' ) );
|
||||
break;
|
||||
}
|
||||
|
||||
$this->process_action( $action_id, $context );
|
||||
$this->progress_bar->tick();
|
||||
}
|
||||
|
||||
$completed = $this->progress_bar->current();
|
||||
$this->progress_bar->finish();
|
||||
$this->store->release_claim( $this->claim );
|
||||
do_action( 'action_scheduler_after_process_queue' );
|
||||
|
||||
return $completed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle WP CLI message when the action is starting.
|
||||
*
|
||||
* @author Jeremy Pry
|
||||
*
|
||||
* @param $action_id
|
||||
*/
|
||||
public function before_execute( $action_id ) {
|
||||
/* translators: %s refers to the action ID */
|
||||
WP_CLI::log( sprintf( __( 'Started processing action %s', 'action-scheduler' ), $action_id ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle WP CLI message when the action has completed.
|
||||
*
|
||||
* @author Jeremy Pry
|
||||
*
|
||||
* @param int $action_id
|
||||
* @param null|ActionScheduler_Action $action The instance of the action. Default to null for backward compatibility.
|
||||
*/
|
||||
public function after_execute( $action_id, $action = null ) {
|
||||
// backward compatibility
|
||||
if ( null === $action ) {
|
||||
$action = $this->store->fetch_action( $action_id );
|
||||
}
|
||||
/* translators: 1: action ID 2: hook name */
|
||||
WP_CLI::log( sprintf( __( 'Completed processing action %1$s with hook: %2$s', 'action-scheduler' ), $action_id, $action->get_hook() ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle WP CLI message when the action has failed.
|
||||
*
|
||||
* @author Jeremy Pry
|
||||
*
|
||||
* @param int $action_id
|
||||
* @param Exception $exception
|
||||
* @throws \WP_CLI\ExitException With failure message.
|
||||
*/
|
||||
public function action_failed( $action_id, $exception ) {
|
||||
WP_CLI::error(
|
||||
/* translators: 1: action ID 2: exception message */
|
||||
sprintf( __( 'Error processing action %1$s: %2$s', 'action-scheduler' ), $action_id, $exception->getMessage() ),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sleep and help avoid hitting memory limit
|
||||
*
|
||||
* @param int $sleep_time Amount of seconds to sleep
|
||||
* @deprecated 3.0.0
|
||||
*/
|
||||
protected function stop_the_insanity( $sleep_time = 0 ) {
|
||||
_deprecated_function( 'ActionScheduler_WPCLI_QueueRunner::stop_the_insanity', '3.0.0', 'ActionScheduler_DataController::free_memory' );
|
||||
|
||||
ActionScheduler_DataController::free_memory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe trigger the stop_the_insanity() method to free up memory.
|
||||
*/
|
||||
protected function maybe_stop_the_insanity() {
|
||||
// The value returned by progress_bar->current() might be padded. Remove padding, and convert to int.
|
||||
$current_iteration = intval( trim( $this->progress_bar->current() ) );
|
||||
if ( 0 === $current_iteration % 50 ) {
|
||||
$this->stop_the_insanity();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,158 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Commands for Action Scheduler.
|
||||
*/
|
||||
class ActionScheduler_WPCLI_Scheduler_command extends WP_CLI_Command {
|
||||
|
||||
/**
|
||||
* Run the Action Scheduler
|
||||
*
|
||||
* ## OPTIONS
|
||||
*
|
||||
* [--batch-size=<size>]
|
||||
* : The maximum number of actions to run. Defaults to 100.
|
||||
*
|
||||
* [--batches=<size>]
|
||||
* : Limit execution to a number of batches. Defaults to 0, meaning batches will continue being executed until all actions are complete.
|
||||
*
|
||||
* [--cleanup-batch-size=<size>]
|
||||
* : The maximum number of actions to clean up. Defaults to the value of --batch-size.
|
||||
*
|
||||
* [--hooks=<hooks>]
|
||||
* : Only run actions with the specified hook. Omitting this option runs actions with any hook. Define multiple hooks as a comma separated string (without spaces), e.g. `--hooks=hook_one,hook_two,hook_three`
|
||||
*
|
||||
* [--group=<group>]
|
||||
* : Only run actions from the specified group. Omitting this option runs actions from all groups.
|
||||
*
|
||||
* [--free-memory-on=<count>]
|
||||
* : The number of actions to process between freeing memory. 0 disables freeing memory. Default 50.
|
||||
*
|
||||
* [--pause=<seconds>]
|
||||
* : The number of seconds to pause when freeing memory. Default no pause.
|
||||
*
|
||||
* [--force]
|
||||
* : Whether to force execution despite the maximum number of concurrent processes being exceeded.
|
||||
*
|
||||
* @param array $args Positional arguments.
|
||||
* @param array $assoc_args Keyed arguments.
|
||||
* @throws \WP_CLI\ExitException When an error occurs.
|
||||
*
|
||||
* @subcommand run
|
||||
*/
|
||||
public function run( $args, $assoc_args ) {
|
||||
// Handle passed arguments.
|
||||
$batch = absint( \WP_CLI\Utils\get_flag_value( $assoc_args, 'batch-size', 100 ) );
|
||||
$batches = absint( \WP_CLI\Utils\get_flag_value( $assoc_args, 'batches', 0 ) );
|
||||
$clean = absint( \WP_CLI\Utils\get_flag_value( $assoc_args, 'cleanup-batch-size', $batch ) );
|
||||
$hooks = explode( ',', WP_CLI\Utils\get_flag_value( $assoc_args, 'hooks', '' ) );
|
||||
$hooks = array_filter( array_map( 'trim', $hooks ) );
|
||||
$group = \WP_CLI\Utils\get_flag_value( $assoc_args, 'group', '' );
|
||||
$free_on = \WP_CLI\Utils\get_flag_value( $assoc_args, 'free-memory-on', 50 );
|
||||
$sleep = \WP_CLI\Utils\get_flag_value( $assoc_args, 'pause', 0 );
|
||||
$force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force', false );
|
||||
|
||||
ActionScheduler_DataController::set_free_ticks( $free_on );
|
||||
ActionScheduler_DataController::set_sleep_time( $sleep );
|
||||
|
||||
$batches_completed = 0;
|
||||
$actions_completed = 0;
|
||||
$unlimited = $batches === 0;
|
||||
|
||||
try {
|
||||
// Custom queue cleaner instance.
|
||||
$cleaner = new ActionScheduler_QueueCleaner( null, $clean );
|
||||
|
||||
// Get the queue runner instance
|
||||
$runner = new ActionScheduler_WPCLI_QueueRunner( null, null, $cleaner );
|
||||
|
||||
// Determine how many tasks will be run in the first batch.
|
||||
$total = $runner->setup( $batch, $hooks, $group, $force );
|
||||
|
||||
// Run actions for as long as possible.
|
||||
while ( $total > 0 ) {
|
||||
$this->print_total_actions( $total );
|
||||
$actions_completed += $runner->run();
|
||||
$batches_completed++;
|
||||
|
||||
// Maybe set up tasks for the next batch.
|
||||
$total = ( $unlimited || $batches_completed < $batches ) ? $runner->setup( $batch, $hooks, $group, $force ) : 0;
|
||||
}
|
||||
} catch ( Exception $e ) {
|
||||
$this->print_error( $e );
|
||||
}
|
||||
|
||||
$this->print_total_batches( $batches_completed );
|
||||
$this->print_success( $actions_completed );
|
||||
}
|
||||
|
||||
/**
|
||||
* Print WP CLI message about how many actions are about to be processed.
|
||||
*
|
||||
* @author Jeremy Pry
|
||||
*
|
||||
* @param int $total
|
||||
*/
|
||||
protected function print_total_actions( $total ) {
|
||||
WP_CLI::log(
|
||||
sprintf(
|
||||
/* translators: %d refers to how many scheduled taks were found to run */
|
||||
_n( 'Found %d scheduled task', 'Found %d scheduled tasks', $total, 'action-scheduler' ),
|
||||
number_format_i18n( $total )
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print WP CLI message about how many batches of actions were processed.
|
||||
*
|
||||
* @author Jeremy Pry
|
||||
*
|
||||
* @param int $batches_completed
|
||||
*/
|
||||
protected function print_total_batches( $batches_completed ) {
|
||||
WP_CLI::log(
|
||||
sprintf(
|
||||
/* translators: %d refers to the total number of batches executed */
|
||||
_n( '%d batch executed.', '%d batches executed.', $batches_completed, 'action-scheduler' ),
|
||||
number_format_i18n( $batches_completed )
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an exception into a WP CLI error.
|
||||
*
|
||||
* @author Jeremy Pry
|
||||
*
|
||||
* @param Exception $e The error object.
|
||||
*
|
||||
* @throws \WP_CLI\ExitException
|
||||
*/
|
||||
protected function print_error( Exception $e ) {
|
||||
WP_CLI::error(
|
||||
sprintf(
|
||||
/* translators: %s refers to the exception error message */
|
||||
__( 'There was an error running the action scheduler: %s', 'action-scheduler' ),
|
||||
$e->getMessage()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a success message with the number of completed actions.
|
||||
*
|
||||
* @author Jeremy Pry
|
||||
*
|
||||
* @param int $actions_completed
|
||||
*/
|
||||
protected function print_success( $actions_completed ) {
|
||||
WP_CLI::success(
|
||||
sprintf(
|
||||
/* translators: %d refers to the total number of taskes completed */
|
||||
_n( '%d scheduled task completed.', '%d scheduled tasks completed.', $actions_completed, 'action-scheduler' ),
|
||||
number_format_i18n( $actions_completed )
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Action_Scheduler\WP_CLI;
|
||||
|
||||
use Action_Scheduler\Migration\Config;
|
||||
use Action_Scheduler\Migration\Runner;
|
||||
use Action_Scheduler\Migration\Scheduler;
|
||||
use Action_Scheduler\Migration\Controller;
|
||||
use WP_CLI;
|
||||
use WP_CLI_Command;
|
||||
|
||||
/**
|
||||
* Class Migration_Command
|
||||
*
|
||||
* @package Action_Scheduler\WP_CLI
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class Migration_Command extends WP_CLI_Command {
|
||||
|
||||
/** @var int */
|
||||
private $total_processed = 0;
|
||||
|
||||
/**
|
||||
* Register the command with WP-CLI
|
||||
*/
|
||||
public function register() {
|
||||
if ( ! defined( 'WP_CLI' ) || ! WP_CLI ) {
|
||||
return;
|
||||
}
|
||||
|
||||
WP_CLI::add_command( 'action-scheduler migrate', [ $this, 'migrate' ], [
|
||||
'shortdesc' => 'Migrates actions to the DB tables store',
|
||||
'synopsis' => [
|
||||
[
|
||||
'type' => 'assoc',
|
||||
'name' => 'batch-size',
|
||||
'optional' => true,
|
||||
'default' => 100,
|
||||
'description' => 'The number of actions to process in each batch',
|
||||
],
|
||||
[
|
||||
'type' => 'assoc',
|
||||
'name' => 'free-memory-on',
|
||||
'optional' => true,
|
||||
'default' => 50,
|
||||
'description' => 'The number of actions to process between freeing memory. 0 disables freeing memory',
|
||||
],
|
||||
[
|
||||
'type' => 'assoc',
|
||||
'name' => 'pause',
|
||||
'optional' => true,
|
||||
'default' => 0,
|
||||
'description' => 'The number of seconds to pause when freeing memory',
|
||||
],
|
||||
[
|
||||
'type' => 'flag',
|
||||
'name' => 'dry-run',
|
||||
'optional' => true,
|
||||
'description' => 'Reports on the actions that would have been migrated, but does not change any data',
|
||||
],
|
||||
],
|
||||
] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the data migration.
|
||||
*
|
||||
* @param array $positional_args Required for WP CLI. Not used in migration.
|
||||
* @param array $assoc_args Optional arguments.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function migrate( $positional_args, $assoc_args ) {
|
||||
$this->init_logging();
|
||||
|
||||
$config = $this->get_migration_config( $assoc_args );
|
||||
$runner = new Runner( $config );
|
||||
$runner->init_destination();
|
||||
|
||||
$batch_size = isset( $assoc_args[ 'batch-size' ] ) ? (int) $assoc_args[ 'batch-size' ] : 100;
|
||||
$free_on = isset( $assoc_args[ 'free-memory-on' ] ) ? (int) $assoc_args[ 'free-memory-on' ] : 50;
|
||||
$sleep = isset( $assoc_args[ 'pause' ] ) ? (int) $assoc_args[ 'pause' ] : 0;
|
||||
\ActionScheduler_DataController::set_free_ticks( $free_on );
|
||||
\ActionScheduler_DataController::set_sleep_time( $sleep );
|
||||
|
||||
do {
|
||||
$actions_processed = $runner->run( $batch_size );
|
||||
$this->total_processed += $actions_processed;
|
||||
} while ( $actions_processed > 0 );
|
||||
|
||||
if ( ! $config->get_dry_run() ) {
|
||||
// let the scheduler know that there's nothing left to do
|
||||
$scheduler = new Scheduler();
|
||||
$scheduler->mark_complete();
|
||||
}
|
||||
|
||||
WP_CLI::success( sprintf( '%s complete. %d actions processed.', $config->get_dry_run() ? 'Dry run' : 'Migration', $this->total_processed ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the config object used to create the Runner
|
||||
*
|
||||
* @param array $args Optional arguments.
|
||||
*
|
||||
* @return ActionScheduler\Migration\Config
|
||||
*/
|
||||
private function get_migration_config( $args ) {
|
||||
$args = wp_parse_args( $args, [
|
||||
'dry-run' => false,
|
||||
] );
|
||||
|
||||
$config = Controller::instance()->get_migration_config_object();
|
||||
$config->set_dry_run( ! empty( $args[ 'dry-run' ] ) );
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook command line logging into migration actions.
|
||||
*/
|
||||
private function init_logging() {
|
||||
add_action( 'action_scheduler/migrate_action_dry_run', function ( $action_id ) {
|
||||
WP_CLI::debug( sprintf( 'Dry-run: migrated action %d', $action_id ) );
|
||||
}, 10, 1 );
|
||||
add_action( 'action_scheduler/no_action_to_migrate', function ( $action_id ) {
|
||||
WP_CLI::debug( sprintf( 'No action found to migrate for ID %d', $action_id ) );
|
||||
}, 10, 1 );
|
||||
add_action( 'action_scheduler/migrate_action_failed', function ( $action_id ) {
|
||||
WP_CLI::warning( sprintf( 'Failed migrating action with ID %d', $action_id ) );
|
||||
}, 10, 1 );
|
||||
add_action( 'action_scheduler/migrate_action_incomplete', function ( $source_id, $destination_id ) {
|
||||
WP_CLI::warning( sprintf( 'Unable to remove source action with ID %d after migrating to new ID %d', $source_id, $destination_id ) );
|
||||
}, 10, 2 );
|
||||
add_action( 'action_scheduler/migrated_action', function ( $source_id, $destination_id ) {
|
||||
WP_CLI::debug( sprintf( 'Migrated source action with ID %d to new store with ID %d', $source_id, $destination_id ) );
|
||||
}, 10, 2 );
|
||||
add_action( 'action_scheduler/migration_batch_starting', function ( $batch ) {
|
||||
WP_CLI::debug( 'Beginning migration of batch: ' . print_r( $batch, true ) );
|
||||
}, 10, 1 );
|
||||
add_action( 'action_scheduler/migration_batch_complete', function ( $batch ) {
|
||||
WP_CLI::log( sprintf( 'Completed migration of %d actions', count( $batch ) ) );
|
||||
}, 10, 1 );
|
||||
}
|
||||
}
|
119
wp-content/plugins/wp-mail-smtp/vendor/woocommerce/action-scheduler/classes/WP_CLI/ProgressBar.php
vendored
Normal file
119
wp-content/plugins/wp-mail-smtp/vendor/woocommerce/action-scheduler/classes/WP_CLI/ProgressBar.php
vendored
Normal file
@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
namespace Action_Scheduler\WP_CLI;
|
||||
|
||||
/**
|
||||
* WP_CLI progress bar for Action Scheduler.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class ProgressBar
|
||||
*
|
||||
* @package Action_Scheduler\WP_CLI
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class ProgressBar {
|
||||
|
||||
/** @var integer */
|
||||
protected $total_ticks;
|
||||
|
||||
/** @var integer */
|
||||
protected $count;
|
||||
|
||||
/** @var integer */
|
||||
protected $interval;
|
||||
|
||||
/** @var string */
|
||||
protected $message;
|
||||
|
||||
/** @var \cli\progress\Bar */
|
||||
protected $progress_bar;
|
||||
|
||||
/**
|
||||
* ProgressBar constructor.
|
||||
*
|
||||
* @param string $message Text to display before the progress bar.
|
||||
* @param integer $count Total number of ticks to be performed.
|
||||
* @param integer $interval Optional. The interval in milliseconds between updates. Default 100.
|
||||
*
|
||||
* @throws Exception When this is not run within WP CLI
|
||||
*/
|
||||
public function __construct( $message, $count, $interval = 100 ) {
|
||||
if ( ! ( defined( 'WP_CLI' ) && WP_CLI ) ) {
|
||||
/* translators: %s php class name */
|
||||
throw new \Exception( sprintf( __( 'The %s class can only be run within WP CLI.', 'action-scheduler' ), __CLASS__ ) );
|
||||
}
|
||||
|
||||
$this->total_ticks = 0;
|
||||
$this->message = $message;
|
||||
$this->count = $count;
|
||||
$this->interval = $interval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the progress bar ticks.
|
||||
*/
|
||||
public function tick() {
|
||||
if ( null === $this->progress_bar ) {
|
||||
$this->setup_progress_bar();
|
||||
}
|
||||
|
||||
$this->progress_bar->tick();
|
||||
$this->total_ticks++;
|
||||
|
||||
do_action( 'action_scheduler/progress_tick', $this->total_ticks );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the progress bar tick count.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function current() {
|
||||
return $this->progress_bar ? $this->progress_bar->current() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish the current progress bar.
|
||||
*/
|
||||
public function finish() {
|
||||
if ( null !== $this->progress_bar ) {
|
||||
$this->progress_bar->finish();
|
||||
}
|
||||
|
||||
$this->progress_bar = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the message used when creating the progress bar.
|
||||
*
|
||||
* @param string $message The message to be used when the next progress bar is created.
|
||||
*/
|
||||
public function set_message( $message ) {
|
||||
$this->message = $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the count for a new progress bar.
|
||||
*
|
||||
* @param integer $count The total number of ticks expected to complete.
|
||||
*/
|
||||
public function set_count( $count ) {
|
||||
$this->count = $count;
|
||||
$this->finish();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the progress bar.
|
||||
*/
|
||||
protected function setup_progress_bar() {
|
||||
$this->progress_bar = \WP_CLI\Utils\make_progress_bar(
|
||||
$this->message,
|
||||
$this->count,
|
||||
$this->interval
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,304 @@
|
||||
<?php
|
||||
|
||||
use Action_Scheduler\WP_CLI\Migration_Command;
|
||||
use Action_Scheduler\Migration\Controller;
|
||||
|
||||
/**
|
||||
* Class ActionScheduler
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
abstract class ActionScheduler {
|
||||
private static $plugin_file = '';
|
||||
/** @var ActionScheduler_ActionFactory */
|
||||
private static $factory = NULL;
|
||||
/** @var bool */
|
||||
private static $data_store_initialized = false;
|
||||
|
||||
public static function factory() {
|
||||
if ( !isset(self::$factory) ) {
|
||||
self::$factory = new ActionScheduler_ActionFactory();
|
||||
}
|
||||
return self::$factory;
|
||||
}
|
||||
|
||||
public static function store() {
|
||||
return ActionScheduler_Store::instance();
|
||||
}
|
||||
|
||||
public static function lock() {
|
||||
return ActionScheduler_Lock::instance();
|
||||
}
|
||||
|
||||
public static function logger() {
|
||||
return ActionScheduler_Logger::instance();
|
||||
}
|
||||
|
||||
public static function runner() {
|
||||
return ActionScheduler_QueueRunner::instance();
|
||||
}
|
||||
|
||||
public static function admin_view() {
|
||||
return ActionScheduler_AdminView::instance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the absolute system path to the plugin directory, or a file therein
|
||||
* @static
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
public static function plugin_path( $path ) {
|
||||
$base = dirname(self::$plugin_file);
|
||||
if ( $path ) {
|
||||
return trailingslashit($base).$path;
|
||||
} else {
|
||||
return untrailingslashit($base);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the absolute URL to the plugin directory, or a file therein
|
||||
* @static
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
public static function plugin_url( $path ) {
|
||||
return plugins_url($path, self::$plugin_file);
|
||||
}
|
||||
|
||||
public static function autoload( $class ) {
|
||||
$d = DIRECTORY_SEPARATOR;
|
||||
$classes_dir = self::plugin_path( 'classes' . $d );
|
||||
$separator = strrpos( $class, '\\' );
|
||||
if ( false !== $separator ) {
|
||||
if ( 0 !== strpos( $class, 'Action_Scheduler' ) ) {
|
||||
return;
|
||||
}
|
||||
$class = substr( $class, $separator + 1 );
|
||||
}
|
||||
|
||||
if ( 'Deprecated' === substr( $class, -10 ) ) {
|
||||
$dir = self::plugin_path( 'deprecated' . $d );
|
||||
} elseif ( self::is_class_abstract( $class ) ) {
|
||||
$dir = $classes_dir . 'abstracts' . $d;
|
||||
} elseif ( self::is_class_migration( $class ) ) {
|
||||
$dir = $classes_dir . 'migration' . $d;
|
||||
} elseif ( 'Schedule' === substr( $class, -8 ) ) {
|
||||
$dir = $classes_dir . 'schedules' . $d;
|
||||
} elseif ( 'Action' === substr( $class, -6 ) ) {
|
||||
$dir = $classes_dir . 'actions' . $d;
|
||||
} elseif ( 'Schema' === substr( $class, -6 ) ) {
|
||||
$dir = $classes_dir . 'schema' . $d;
|
||||
} elseif ( strpos( $class, 'ActionScheduler' ) === 0 ) {
|
||||
$segments = explode( '_', $class );
|
||||
$type = isset( $segments[ 1 ] ) ? $segments[ 1 ] : '';
|
||||
|
||||
switch ( $type ) {
|
||||
case 'WPCLI':
|
||||
$dir = $classes_dir . 'WP_CLI' . $d;
|
||||
break;
|
||||
case 'DBLogger':
|
||||
case 'DBStore':
|
||||
case 'HybridStore':
|
||||
case 'wpPostStore':
|
||||
case 'wpCommentLogger':
|
||||
$dir = $classes_dir . 'data-stores' . $d;
|
||||
break;
|
||||
default:
|
||||
$dir = $classes_dir;
|
||||
break;
|
||||
}
|
||||
} elseif ( self::is_class_cli( $class ) ) {
|
||||
$dir = $classes_dir . 'WP_CLI' . $d;
|
||||
} elseif ( strpos( $class, 'CronExpression' ) === 0 ) {
|
||||
$dir = self::plugin_path( 'lib' . $d . 'cron-expression' . $d );
|
||||
} elseif ( strpos( $class, 'WP_Async_Request' ) === 0 ) {
|
||||
$dir = self::plugin_path( 'lib' . $d );
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( file_exists( "{$dir}{$class}.php" ) ) {
|
||||
include( "{$dir}{$class}.php" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the plugin
|
||||
*
|
||||
* @static
|
||||
* @param string $plugin_file
|
||||
*/
|
||||
public static function init( $plugin_file ) {
|
||||
self::$plugin_file = $plugin_file;
|
||||
spl_autoload_register( array( __CLASS__, 'autoload' ) );
|
||||
|
||||
/**
|
||||
* Fires in the early stages of Action Scheduler init hook.
|
||||
*/
|
||||
do_action( 'action_scheduler_pre_init' );
|
||||
|
||||
require_once( self::plugin_path( 'functions.php' ) );
|
||||
ActionScheduler_DataController::init();
|
||||
|
||||
$store = self::store();
|
||||
$logger = self::logger();
|
||||
$runner = self::runner();
|
||||
$admin_view = self::admin_view();
|
||||
|
||||
// Ensure initialization on plugin activation.
|
||||
if ( ! did_action( 'init' ) ) {
|
||||
add_action( 'init', array( $admin_view, 'init' ), 0, 0 ); // run before $store::init()
|
||||
add_action( 'init', array( $store, 'init' ), 1, 0 );
|
||||
add_action( 'init', array( $logger, 'init' ), 1, 0 );
|
||||
add_action( 'init', array( $runner, 'init' ), 1, 0 );
|
||||
} else {
|
||||
$admin_view->init();
|
||||
$store->init();
|
||||
$logger->init();
|
||||
$runner->init();
|
||||
}
|
||||
|
||||
if ( apply_filters( 'action_scheduler_load_deprecated_functions', true ) ) {
|
||||
require_once( self::plugin_path( 'deprecated/functions.php' ) );
|
||||
}
|
||||
|
||||
if ( defined( 'WP_CLI' ) && WP_CLI ) {
|
||||
WP_CLI::add_command( 'action-scheduler', 'ActionScheduler_WPCLI_Scheduler_command' );
|
||||
if ( ! ActionScheduler_DataController::is_migration_complete() && Controller::instance()->allow_migration() ) {
|
||||
$command = new Migration_Command();
|
||||
$command->register();
|
||||
}
|
||||
}
|
||||
|
||||
self::$data_store_initialized = true;
|
||||
|
||||
/**
|
||||
* Handle WP comment cleanup after migration.
|
||||
*/
|
||||
if ( is_a( $logger, 'ActionScheduler_DBLogger' ) && ActionScheduler_DataController::is_migration_complete() && ActionScheduler_WPCommentCleaner::has_logs() ) {
|
||||
ActionScheduler_WPCommentCleaner::init();
|
||||
}
|
||||
|
||||
add_action( 'action_scheduler/migration_complete', 'ActionScheduler_WPCommentCleaner::maybe_schedule_cleanup' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the AS data store has been initialized.
|
||||
*
|
||||
* @param string $function_name The name of the function being called. Optional. Default `null`.
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_initialized( $function_name = null ) {
|
||||
if ( ! self::$data_store_initialized && ! empty( $function_name ) ) {
|
||||
$message = sprintf( __( '%s() was called before the Action Scheduler data store was initialized', 'action-scheduler' ), esc_attr( $function_name ) );
|
||||
error_log( $message, E_WARNING );
|
||||
}
|
||||
|
||||
return self::$data_store_initialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the class is one of our abstract classes.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @param string $class The class name.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected static function is_class_abstract( $class ) {
|
||||
static $abstracts = array(
|
||||
'ActionScheduler' => true,
|
||||
'ActionScheduler_Abstract_ListTable' => true,
|
||||
'ActionScheduler_Abstract_QueueRunner' => true,
|
||||
'ActionScheduler_Abstract_Schedule' => true,
|
||||
'ActionScheduler_Abstract_RecurringSchedule' => true,
|
||||
'ActionScheduler_Lock' => true,
|
||||
'ActionScheduler_Logger' => true,
|
||||
'ActionScheduler_Abstract_Schema' => true,
|
||||
'ActionScheduler_Store' => true,
|
||||
'ActionScheduler_TimezoneHelper' => true,
|
||||
);
|
||||
|
||||
return isset( $abstracts[ $class ] ) && $abstracts[ $class ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the class is one of our migration classes.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @param string $class The class name.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected static function is_class_migration( $class ) {
|
||||
static $migration_segments = array(
|
||||
'ActionMigrator' => true,
|
||||
'BatchFetcher' => true,
|
||||
'DBStoreMigrator' => true,
|
||||
'DryRun' => true,
|
||||
'LogMigrator' => true,
|
||||
'Config' => true,
|
||||
'Controller' => true,
|
||||
'Runner' => true,
|
||||
'Scheduler' => true,
|
||||
);
|
||||
|
||||
$segments = explode( '_', $class );
|
||||
$segment = isset( $segments[ 1 ] ) ? $segments[ 1 ] : $class;
|
||||
|
||||
return isset( $migration_segments[ $segment ] ) && $migration_segments[ $segment ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the class is one of our WP CLI classes.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @param string $class The class name.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected static function is_class_cli( $class ) {
|
||||
static $cli_segments = array(
|
||||
'QueueRunner' => true,
|
||||
'Command' => true,
|
||||
'ProgressBar' => true,
|
||||
);
|
||||
|
||||
$segments = explode( '_', $class );
|
||||
$segment = isset( $segments[ 1 ] ) ? $segments[ 1 ] : $class;
|
||||
|
||||
return isset( $cli_segments[ $segment ] ) && $cli_segments[ $segment ];
|
||||
}
|
||||
|
||||
final public function __clone() {
|
||||
trigger_error("Singleton. No cloning allowed!", E_USER_ERROR);
|
||||
}
|
||||
|
||||
final public function __wakeup() {
|
||||
trigger_error("Singleton. No serialization allowed!", E_USER_ERROR);
|
||||
}
|
||||
|
||||
final private function __construct() {}
|
||||
|
||||
/** Deprecated **/
|
||||
|
||||
public static function get_datetime_object( $when = null, $timezone = 'UTC' ) {
|
||||
_deprecated_function( __METHOD__, '2.0', 'wcs_add_months()' );
|
||||
return as_get_datetime_object( $when, $timezone );
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue deprecated warning if an Action Scheduler function is called in the shutdown hook.
|
||||
*
|
||||
* @param string $function_name The name of the function being called.
|
||||
* @deprecated 3.1.6.
|
||||
*/
|
||||
public static function check_shutdown_hook( $function_name ) {
|
||||
_deprecated_function( __FUNCTION__, '3.1.6' );
|
||||
}
|
||||
}
|
@ -0,0 +1,674 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'WP_List_Table' ) ) {
|
||||
require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Action Scheduler Abstract List Table class
|
||||
*
|
||||
* This abstract class enhances WP_List_Table making it ready to use.
|
||||
*
|
||||
* By extending this class we can focus on describing how our table looks like,
|
||||
* which columns needs to be shown, filter, ordered by and more and forget about the details.
|
||||
*
|
||||
* This class supports:
|
||||
* - Bulk actions
|
||||
* - Search
|
||||
* - Sortable columns
|
||||
* - Automatic translations of the columns
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @since 2.0.0
|
||||
*/
|
||||
abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
||||
|
||||
/**
|
||||
* The table name
|
||||
*/
|
||||
protected $table_name;
|
||||
|
||||
/**
|
||||
* Package name, used to get options from WP_List_Table::get_items_per_page.
|
||||
*/
|
||||
protected $package;
|
||||
|
||||
/**
|
||||
* How many items do we render per page?
|
||||
*/
|
||||
protected $items_per_page = 10;
|
||||
|
||||
/**
|
||||
* Enables search in this table listing. If this array
|
||||
* is empty it means the listing is not searchable.
|
||||
*/
|
||||
protected $search_by = array();
|
||||
|
||||
/**
|
||||
* Columns to show in the table listing. It is a key => value pair. The
|
||||
* key must much the table column name and the value is the label, which is
|
||||
* automatically translated.
|
||||
*/
|
||||
protected $columns = array();
|
||||
|
||||
/**
|
||||
* Defines the row-actions. It expects an array where the key
|
||||
* is the column name and the value is an array of actions.
|
||||
*
|
||||
* The array of actions are key => value, where key is the method name
|
||||
* (with the prefix row_action_<key>) and the value is the label
|
||||
* and title.
|
||||
*/
|
||||
protected $row_actions = array();
|
||||
|
||||
/**
|
||||
* The Primary key of our table
|
||||
*/
|
||||
protected $ID = 'ID';
|
||||
|
||||
/**
|
||||
* Enables sorting, it expects an array
|
||||
* of columns (the column names are the values)
|
||||
*/
|
||||
protected $sort_by = array();
|
||||
|
||||
protected $filter_by = array();
|
||||
|
||||
/**
|
||||
* @var array The status name => count combinations for this table's items. Used to display status filters.
|
||||
*/
|
||||
protected $status_counts = array();
|
||||
|
||||
/**
|
||||
* @var array Notices to display when loading the table. Array of arrays of form array( 'class' => {updated|error}, 'message' => 'This is the notice text display.' ).
|
||||
*/
|
||||
protected $admin_notices = array();
|
||||
|
||||
/**
|
||||
* @var string Localised string displayed in the <h1> element above the able.
|
||||
*/
|
||||
protected $table_header;
|
||||
|
||||
/**
|
||||
* Enables bulk actions. It must be an array where the key is the action name
|
||||
* and the value is the label (which is translated automatically). It is important
|
||||
* to notice that it will check that the method exists (`bulk_$name`) and will throw
|
||||
* an exception if it does not exists.
|
||||
*
|
||||
* This class will automatically check if the current request has a bulk action, will do the
|
||||
* validations and afterwards will execute the bulk method, with two arguments. The first argument
|
||||
* is the array with primary keys, the second argument is a string with a list of the primary keys,
|
||||
* escaped and ready to use (with `IN`).
|
||||
*/
|
||||
protected $bulk_actions = array();
|
||||
|
||||
/**
|
||||
* Makes translation easier, it basically just wraps
|
||||
* `_x` with some default (the package name).
|
||||
*
|
||||
* @deprecated 3.0.0
|
||||
*/
|
||||
protected function translate( $text, $context = '' ) {
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads `$this->bulk_actions` and returns an array that WP_List_Table understands. It
|
||||
* also validates that the bulk method handler exists. It throws an exception because
|
||||
* this is a library meant for developers and missing a bulk method is a development-time error.
|
||||
*/
|
||||
protected function get_bulk_actions() {
|
||||
$actions = array();
|
||||
|
||||
foreach ( $this->bulk_actions as $action => $label ) {
|
||||
if ( ! is_callable( array( $this, 'bulk_' . $action ) ) ) {
|
||||
throw new RuntimeException( "The bulk action $action does not have a callback method" );
|
||||
}
|
||||
|
||||
$actions[ $action ] = $label;
|
||||
}
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current request has a bulk action. If that is the case it will validate and will
|
||||
* execute the bulk method handler. Regardless if the action is valid or not it will redirect to
|
||||
* the previous page removing the current arguments that makes this request a bulk action.
|
||||
*/
|
||||
protected function process_bulk_action() {
|
||||
global $wpdb;
|
||||
// Detect when a bulk action is being triggered.
|
||||
$action = $this->current_action();
|
||||
if ( ! $action ) {
|
||||
return;
|
||||
}
|
||||
|
||||
check_admin_referer( 'bulk-' . $this->_args['plural'] );
|
||||
|
||||
$method = 'bulk_' . $action;
|
||||
if ( array_key_exists( $action, $this->bulk_actions ) && is_callable( array( $this, $method ) ) && ! empty( $_GET['ID'] ) && is_array( $_GET['ID'] ) ) {
|
||||
$ids_sql = '(' . implode( ',', array_fill( 0, count( $_GET['ID'] ), '%s' ) ) . ')';
|
||||
$this->$method( $_GET['ID'], $wpdb->prepare( $ids_sql, $_GET['ID'] ) );
|
||||
}
|
||||
|
||||
wp_redirect( remove_query_arg(
|
||||
array( '_wp_http_referer', '_wpnonce', 'ID', 'action', 'action2' ),
|
||||
wp_unslash( $_SERVER['REQUEST_URI'] )
|
||||
) );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default code for deleting entries.
|
||||
* validated already by process_bulk_action()
|
||||
*/
|
||||
protected function bulk_delete( array $ids, $ids_sql ) {
|
||||
$store = ActionScheduler::store();
|
||||
foreach ( $ids as $action_id ) {
|
||||
$store->delete( $action_id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the _column_headers property which is used by WP_Table_List at rendering.
|
||||
* It merges the columns and the sortable columns.
|
||||
*/
|
||||
protected function prepare_column_headers() {
|
||||
$this->_column_headers = array(
|
||||
$this->get_columns(),
|
||||
array(),
|
||||
$this->get_sortable_columns(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads $this->sort_by and returns the columns name in a format that WP_Table_List
|
||||
* expects
|
||||
*/
|
||||
public function get_sortable_columns() {
|
||||
$sort_by = array();
|
||||
foreach ( $this->sort_by as $column ) {
|
||||
$sort_by[ $column ] = array( $column, true );
|
||||
}
|
||||
return $sort_by;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the columns names for rendering. It adds a checkbox for selecting everything
|
||||
* as the first column
|
||||
*/
|
||||
public function get_columns() {
|
||||
$columns = array_merge(
|
||||
array( 'cb' => '<input type="checkbox" />' ),
|
||||
$this->columns
|
||||
);
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get prepared LIMIT clause for items query
|
||||
*
|
||||
* @global wpdb $wpdb
|
||||
*
|
||||
* @return string Prepared LIMIT clause for items query.
|
||||
*/
|
||||
protected function get_items_query_limit() {
|
||||
global $wpdb;
|
||||
|
||||
$per_page = $this->get_items_per_page( $this->package . '_items_per_page', $this->items_per_page );
|
||||
return $wpdb->prepare( 'LIMIT %d', $per_page );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of items to offset/skip for this current view.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function get_items_offset() {
|
||||
$per_page = $this->get_items_per_page( $this->package . '_items_per_page', $this->items_per_page );
|
||||
$current_page = $this->get_pagenum();
|
||||
if ( 1 < $current_page ) {
|
||||
$offset = $per_page * ( $current_page - 1 );
|
||||
} else {
|
||||
$offset = 0;
|
||||
}
|
||||
|
||||
return $offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get prepared OFFSET clause for items query
|
||||
*
|
||||
* @global wpdb $wpdb
|
||||
*
|
||||
* @return string Prepared OFFSET clause for items query.
|
||||
*/
|
||||
protected function get_items_query_offset() {
|
||||
global $wpdb;
|
||||
|
||||
return $wpdb->prepare( 'OFFSET %d', $this->get_items_offset() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the ORDER BY sql statement. It uses `$this->sort_by` to know which
|
||||
* columns are sortable. This requests validates the orderby $_GET parameter is a valid
|
||||
* column and sortable. It will also use order (ASC|DESC) using DESC by default.
|
||||
*/
|
||||
protected function get_items_query_order() {
|
||||
if ( empty( $this->sort_by ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$orderby = esc_sql( $this->get_request_orderby() );
|
||||
$order = esc_sql( $this->get_request_order() );
|
||||
|
||||
return "ORDER BY {$orderby} {$order}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the sortable column specified for this request to order the results by, if any.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_request_orderby() {
|
||||
|
||||
$valid_sortable_columns = array_values( $this->sort_by );
|
||||
|
||||
if ( ! empty( $_GET['orderby'] ) && in_array( $_GET['orderby'], $valid_sortable_columns ) ) {
|
||||
$orderby = sanitize_text_field( $_GET['orderby'] );
|
||||
} else {
|
||||
$orderby = $valid_sortable_columns[0];
|
||||
}
|
||||
|
||||
return $orderby;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the sortable column order specified for this request.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_request_order() {
|
||||
|
||||
if ( ! empty( $_GET['order'] ) && 'desc' === strtolower( $_GET['order'] ) ) {
|
||||
$order = 'DESC';
|
||||
} else {
|
||||
$order = 'ASC';
|
||||
}
|
||||
|
||||
return $order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the status filter for this request, if any.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_request_status() {
|
||||
$status = ( ! empty( $_GET['status'] ) ) ? $_GET['status'] : '';
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the search filter for this request, if any.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_request_search_query() {
|
||||
$search_query = ( ! empty( $_GET['s'] ) ) ? $_GET['s'] : '';
|
||||
return $search_query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process and return the columns name. This is meant for using with SQL, this means it
|
||||
* always includes the primary key.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_table_columns() {
|
||||
$columns = array_keys( $this->columns );
|
||||
if ( ! in_array( $this->ID, $columns ) ) {
|
||||
$columns[] = $this->ID;
|
||||
}
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current request is doing a "full text" search. If that is the case
|
||||
* prepares the SQL to search texts using LIKE.
|
||||
*
|
||||
* If the current request does not have any search or if this list table does not support
|
||||
* that feature it will return an empty string.
|
||||
*
|
||||
* TODO:
|
||||
* - Improve search doing LIKE by word rather than by phrases.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_items_query_search() {
|
||||
global $wpdb;
|
||||
|
||||
if ( empty( $_GET['s'] ) || empty( $this->search_by ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$filter = array();
|
||||
foreach ( $this->search_by as $column ) {
|
||||
$filter[] = $wpdb->prepare('`' . $column . '` like "%%s%"', $wpdb->esc_like( $_GET['s'] ));
|
||||
}
|
||||
return implode( ' OR ', $filter );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the SQL to filter rows by the options defined at `$this->filter_by`. Before trusting
|
||||
* any data sent by the user it validates that it is a valid option.
|
||||
*/
|
||||
protected function get_items_query_filters() {
|
||||
global $wpdb;
|
||||
|
||||
if ( ! $this->filter_by || empty( $_GET['filter_by'] ) || ! is_array( $_GET['filter_by'] ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$filter = array();
|
||||
|
||||
foreach ( $this->filter_by as $column => $options ) {
|
||||
if ( empty( $_GET['filter_by'][ $column ] ) || empty( $options[ $_GET['filter_by'][ $column ] ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$filter[] = $wpdb->prepare( "`$column` = %s", $_GET['filter_by'][ $column ] );
|
||||
}
|
||||
|
||||
return implode( ' AND ', $filter );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the data to feed WP_Table_List.
|
||||
*
|
||||
* This has the core for selecting, sorting and filting data. To keep the code simple
|
||||
* its logic is split among many methods (get_items_query_*).
|
||||
*
|
||||
* Beside populating the items this function will also count all the records that matches
|
||||
* the filtering criteria and will do fill the pagination variables.
|
||||
*/
|
||||
public function prepare_items() {
|
||||
global $wpdb;
|
||||
|
||||
$this->process_bulk_action();
|
||||
|
||||
$this->process_row_actions();
|
||||
|
||||
if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) {
|
||||
// _wp_http_referer is used only on bulk actions, we remove it to keep the $_GET shorter
|
||||
wp_redirect( remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
|
||||
exit;
|
||||
}
|
||||
|
||||
$this->prepare_column_headers();
|
||||
|
||||
$limit = $this->get_items_query_limit();
|
||||
$offset = $this->get_items_query_offset();
|
||||
$order = $this->get_items_query_order();
|
||||
$where = array_filter(array(
|
||||
$this->get_items_query_search(),
|
||||
$this->get_items_query_filters(),
|
||||
));
|
||||
$columns = '`' . implode( '`, `', $this->get_table_columns() ) . '`';
|
||||
|
||||
if ( ! empty( $where ) ) {
|
||||
$where = 'WHERE ('. implode( ') AND (', $where ) . ')';
|
||||
} else {
|
||||
$where = '';
|
||||
}
|
||||
|
||||
$sql = "SELECT $columns FROM {$this->table_name} {$where} {$order} {$limit} {$offset}";
|
||||
|
||||
$this->set_items( $wpdb->get_results( $sql, ARRAY_A ) );
|
||||
|
||||
$query_count = "SELECT COUNT({$this->ID}) FROM {$this->table_name} {$where}";
|
||||
$total_items = $wpdb->get_var( $query_count );
|
||||
$per_page = $this->get_items_per_page( $this->package . '_items_per_page', $this->items_per_page );
|
||||
$this->set_pagination_args( array(
|
||||
'total_items' => $total_items,
|
||||
'per_page' => $per_page,
|
||||
'total_pages' => ceil( $total_items / $per_page ),
|
||||
) );
|
||||
}
|
||||
|
||||
public function extra_tablenav( $which ) {
|
||||
if ( ! $this->filter_by || 'top' !== $which ) {
|
||||
return;
|
||||
}
|
||||
|
||||
echo '<div class="alignleft actions">';
|
||||
|
||||
foreach ( $this->filter_by as $id => $options ) {
|
||||
$default = ! empty( $_GET['filter_by'][ $id ] ) ? $_GET['filter_by'][ $id ] : '';
|
||||
if ( empty( $options[ $default ] ) ) {
|
||||
$default = '';
|
||||
}
|
||||
|
||||
echo '<select name="filter_by[' . esc_attr( $id ) . ']" class="first" id="filter-by-' . esc_attr( $id ) . '">';
|
||||
|
||||
foreach ( $options as $value => $label ) {
|
||||
echo '<option value="' . esc_attr( $value ) . '" ' . esc_html( $value == $default ? 'selected' : '' ) .'>'
|
||||
. esc_html( $label )
|
||||
. '</option>';
|
||||
}
|
||||
|
||||
echo '</select>';
|
||||
}
|
||||
|
||||
submit_button( esc_html__( 'Filter', 'action-scheduler' ), '', 'filter_action', false, array( 'id' => 'post-query-submit' ) );
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the data for displaying. It will attempt to unserialize (There is a chance that some columns
|
||||
* are serialized). This can be override in child classes for futher data transformation.
|
||||
*/
|
||||
protected function set_items( array $items ) {
|
||||
$this->items = array();
|
||||
foreach ( $items as $item ) {
|
||||
$this->items[ $item[ $this->ID ] ] = array_map( 'maybe_unserialize', $item );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the checkbox for each row, this is the first column and it is named ID regardless
|
||||
* of how the primary key is named (to keep the code simpler). The bulk actions will do the proper
|
||||
* name transformation though using `$this->ID`.
|
||||
*/
|
||||
public function column_cb( $row ) {
|
||||
return '<input name="ID[]" type="checkbox" value="' . esc_attr( $row[ $this->ID ] ) .'" />';
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the row-actions.
|
||||
*
|
||||
* This method renders the action menu, it reads the definition from the $row_actions property,
|
||||
* and it checks that the row action method exists before rendering it.
|
||||
*
|
||||
* @param array $row Row to render
|
||||
* @param $column_name Current row
|
||||
* @return
|
||||
*/
|
||||
protected function maybe_render_actions( $row, $column_name ) {
|
||||
if ( empty( $this->row_actions[ $column_name ] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$row_id = $row[ $this->ID ];
|
||||
|
||||
$actions = '<div class="row-actions">';
|
||||
$action_count = 0;
|
||||
foreach ( $this->row_actions[ $column_name ] as $action_key => $action ) {
|
||||
|
||||
$action_count++;
|
||||
|
||||
if ( ! method_exists( $this, 'row_action_' . $action_key ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$action_link = ! empty( $action['link'] ) ? $action['link'] : add_query_arg( array( 'row_action' => $action_key, 'row_id' => $row_id, 'nonce' => wp_create_nonce( $action_key . '::' . $row_id ) ) );
|
||||
$span_class = ! empty( $action['class'] ) ? $action['class'] : $action_key;
|
||||
$separator = ( $action_count < count( $this->row_actions[ $column_name ] ) ) ? ' | ' : '';
|
||||
|
||||
$actions .= sprintf( '<span class="%s">', esc_attr( $span_class ) );
|
||||
$actions .= sprintf( '<a href="%1$s" title="%2$s">%3$s</a>', esc_url( $action_link ), esc_attr( $action['desc'] ), esc_html( $action['name'] ) );
|
||||
$actions .= sprintf( '%s</span>', $separator );
|
||||
}
|
||||
$actions .= '</div>';
|
||||
return $actions;
|
||||
}
|
||||
|
||||
protected function process_row_actions() {
|
||||
$parameters = array( 'row_action', 'row_id', 'nonce' );
|
||||
foreach ( $parameters as $parameter ) {
|
||||
if ( empty( $_REQUEST[ $parameter ] ) ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$method = 'row_action_' . $_REQUEST['row_action'];
|
||||
|
||||
if ( $_REQUEST['nonce'] === wp_create_nonce( $_REQUEST[ 'row_action' ] . '::' . $_REQUEST[ 'row_id' ] ) && method_exists( $this, $method ) ) {
|
||||
$this->$method( $_REQUEST['row_id'] );
|
||||
}
|
||||
|
||||
wp_redirect( remove_query_arg(
|
||||
array( 'row_id', 'row_action', 'nonce' ),
|
||||
wp_unslash( $_SERVER['REQUEST_URI'] )
|
||||
) );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default column formatting, it will escape everythig for security.
|
||||
*/
|
||||
public function column_default( $item, $column_name ) {
|
||||
$column_html = esc_html( $item[ $column_name ] );
|
||||
$column_html .= $this->maybe_render_actions( $item, $column_name );
|
||||
return $column_html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the table heading and search query, if any
|
||||
*/
|
||||
protected function display_header() {
|
||||
echo '<h1 class="wp-heading-inline">' . esc_attr( $this->table_header ) . '</h1>';
|
||||
if ( $this->get_request_search_query() ) {
|
||||
/* translators: %s: search query */
|
||||
echo '<span class="subtitle">' . esc_attr( sprintf( __( 'Search results for "%s"', 'action-scheduler' ), $this->get_request_search_query() ) ) . '</span>';
|
||||
}
|
||||
echo '<hr class="wp-header-end">';
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the table heading and search query, if any
|
||||
*/
|
||||
protected function display_admin_notices() {
|
||||
foreach ( $this->admin_notices as $notice ) {
|
||||
echo '<div id="message" class="' . $notice['class'] . '">';
|
||||
echo ' <p>' . wp_kses_post( $notice['message'] ) . '</p>';
|
||||
echo '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the available statuses so the user can click to filter.
|
||||
*/
|
||||
protected function display_filter_by_status() {
|
||||
|
||||
$status_list_items = array();
|
||||
$request_status = $this->get_request_status();
|
||||
|
||||
// Helper to set 'all' filter when not set on status counts passed in
|
||||
if ( ! isset( $this->status_counts['all'] ) ) {
|
||||
$this->status_counts = array( 'all' => array_sum( $this->status_counts ) ) + $this->status_counts;
|
||||
}
|
||||
|
||||
foreach ( $this->status_counts as $status_name => $count ) {
|
||||
|
||||
if ( 0 === $count ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $status_name === $request_status || ( empty( $request_status ) && 'all' === $status_name ) ) {
|
||||
$status_list_item = '<li class="%1$s"><strong>%3$s</strong> (%4$d)</li>';
|
||||
} else {
|
||||
$status_list_item = '<li class="%1$s"><a href="%2$s">%3$s</a> (%4$d)</li>';
|
||||
}
|
||||
|
||||
$status_filter_url = ( 'all' === $status_name ) ? remove_query_arg( 'status' ) : add_query_arg( 'status', $status_name );
|
||||
$status_filter_url = remove_query_arg( array( 'paged', 's' ), $status_filter_url );
|
||||
$status_list_items[] = sprintf( $status_list_item, esc_attr( $status_name ), esc_url( $status_filter_url ), esc_html( ucfirst( $status_name ) ), absint( $count ) );
|
||||
}
|
||||
|
||||
if ( $status_list_items ) {
|
||||
echo '<ul class="subsubsub">';
|
||||
echo implode( " | \n", $status_list_items );
|
||||
echo '</ul>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the table list, we override the original class to render the table inside a form
|
||||
* and to render any needed HTML (like the search box). By doing so the callee of a function can simple
|
||||
* forget about any extra HTML.
|
||||
*/
|
||||
protected function display_table() {
|
||||
echo '<form id="' . esc_attr( $this->_args['plural'] ) . '-filter" method="get">';
|
||||
foreach ( $_GET as $key => $value ) {
|
||||
if ( '_' === $key[0] || 'paged' === $key ) {
|
||||
continue;
|
||||
}
|
||||
echo '<input type="hidden" name="' . esc_attr( $key ) . '" value="' . esc_attr( $value ) . '" />';
|
||||
}
|
||||
if ( ! empty( $this->search_by ) ) {
|
||||
echo $this->search_box( $this->get_search_box_button_text(), 'plugin' ); // WPCS: XSS OK
|
||||
}
|
||||
parent::display();
|
||||
echo '</form>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Process any pending actions.
|
||||
*/
|
||||
public function process_actions() {
|
||||
$this->process_bulk_action();
|
||||
$this->process_row_actions();
|
||||
|
||||
if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) {
|
||||
// _wp_http_referer is used only on bulk actions, we remove it to keep the $_GET shorter
|
||||
wp_redirect( remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the list table page, including header, notices, status filters and table.
|
||||
*/
|
||||
public function display_page() {
|
||||
$this->prepare_items();
|
||||
|
||||
echo '<div class="wrap">';
|
||||
$this->display_header();
|
||||
$this->display_admin_notices();
|
||||
$this->display_filter_by_status();
|
||||
$this->display_table();
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text to display in the search box on the list table.
|
||||
*/
|
||||
protected function get_search_box_placeholder() {
|
||||
return esc_html__( 'Search', 'action-scheduler' );
|
||||
}
|
||||
}
|
@ -0,0 +1,240 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Abstract class with common Queue Cleaner functionality.
|
||||
*/
|
||||
abstract class ActionScheduler_Abstract_QueueRunner extends ActionScheduler_Abstract_QueueRunner_Deprecated {
|
||||
|
||||
/** @var ActionScheduler_QueueCleaner */
|
||||
protected $cleaner;
|
||||
|
||||
/** @var ActionScheduler_FatalErrorMonitor */
|
||||
protected $monitor;
|
||||
|
||||
/** @var ActionScheduler_Store */
|
||||
protected $store;
|
||||
|
||||
/**
|
||||
* The created time.
|
||||
*
|
||||
* Represents when the queue runner was constructed and used when calculating how long a PHP request has been running.
|
||||
* For this reason it should be as close as possible to the PHP request start time.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $created_time;
|
||||
|
||||
/**
|
||||
* ActionScheduler_Abstract_QueueRunner constructor.
|
||||
*
|
||||
* @param ActionScheduler_Store $store
|
||||
* @param ActionScheduler_FatalErrorMonitor $monitor
|
||||
* @param ActionScheduler_QueueCleaner $cleaner
|
||||
*/
|
||||
public function __construct( ActionScheduler_Store $store = null, ActionScheduler_FatalErrorMonitor $monitor = null, ActionScheduler_QueueCleaner $cleaner = null ) {
|
||||
|
||||
$this->created_time = microtime( true );
|
||||
|
||||
$this->store = $store ? $store : ActionScheduler_Store::instance();
|
||||
$this->monitor = $monitor ? $monitor : new ActionScheduler_FatalErrorMonitor( $this->store );
|
||||
$this->cleaner = $cleaner ? $cleaner : new ActionScheduler_QueueCleaner( $this->store );
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an individual action.
|
||||
*
|
||||
* @param int $action_id The action ID to process.
|
||||
* @param string $context Optional identifer for the context in which this action is being processed, e.g. 'WP CLI' or 'WP Cron'
|
||||
* Generally, this should be capitalised and not localised as it's a proper noun.
|
||||
*/
|
||||
public function process_action( $action_id, $context = '' ) {
|
||||
try {
|
||||
$valid_action = false;
|
||||
do_action( 'action_scheduler_before_execute', $action_id, $context );
|
||||
|
||||
if ( ActionScheduler_Store::STATUS_PENDING !== $this->store->get_status( $action_id ) ) {
|
||||
do_action( 'action_scheduler_execution_ignored', $action_id, $context );
|
||||
return;
|
||||
}
|
||||
|
||||
$valid_action = true;
|
||||
do_action( 'action_scheduler_begin_execute', $action_id, $context );
|
||||
|
||||
$action = $this->store->fetch_action( $action_id );
|
||||
$this->store->log_execution( $action_id );
|
||||
$action->execute();
|
||||
do_action( 'action_scheduler_after_execute', $action_id, $action, $context );
|
||||
$this->store->mark_complete( $action_id );
|
||||
} catch ( Exception $e ) {
|
||||
if ( $valid_action ) {
|
||||
$this->store->mark_failure( $action_id );
|
||||
do_action( 'action_scheduler_failed_execution', $action_id, $e, $context );
|
||||
} else {
|
||||
do_action( 'action_scheduler_failed_validation', $action_id, $e, $context );
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset( $action ) && is_a( $action, 'ActionScheduler_Action' ) && $action->get_schedule()->is_recurring() ) {
|
||||
$this->schedule_next_instance( $action, $action_id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule the next instance of the action if necessary.
|
||||
*
|
||||
* @param ActionScheduler_Action $action
|
||||
* @param int $action_id
|
||||
*/
|
||||
protected function schedule_next_instance( ActionScheduler_Action $action, $action_id ) {
|
||||
try {
|
||||
ActionScheduler::factory()->repeat( $action );
|
||||
} catch ( Exception $e ) {
|
||||
do_action( 'action_scheduler_failed_to_schedule_next_instance', $action_id, $e, $action );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the queue cleaner.
|
||||
*
|
||||
* @author Jeremy Pry
|
||||
*/
|
||||
protected function run_cleanup() {
|
||||
$this->cleaner->clean( 10 * $this->get_time_limit() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of concurrent batches a runner allows.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_allowed_concurrent_batches() {
|
||||
return apply_filters( 'action_scheduler_queue_runner_concurrent_batches', 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the number of allowed concurrent batches is met or exceeded.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_maximum_concurrent_batches() {
|
||||
return $this->store->get_claim_count() >= $this->get_allowed_concurrent_batches();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum number of seconds a batch can run for.
|
||||
*
|
||||
* @return int The number of seconds.
|
||||
*/
|
||||
protected function get_time_limit() {
|
||||
|
||||
$time_limit = 30;
|
||||
|
||||
// Apply deprecated filter from deprecated get_maximum_execution_time() method
|
||||
if ( has_filter( 'action_scheduler_maximum_execution_time' ) ) {
|
||||
_deprecated_function( 'action_scheduler_maximum_execution_time', '2.1.1', 'action_scheduler_queue_runner_time_limit' );
|
||||
$time_limit = apply_filters( 'action_scheduler_maximum_execution_time', $time_limit );
|
||||
}
|
||||
|
||||
return absint( apply_filters( 'action_scheduler_queue_runner_time_limit', $time_limit ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of seconds the process has been running.
|
||||
*
|
||||
* @return int The number of seconds.
|
||||
*/
|
||||
protected function get_execution_time() {
|
||||
$execution_time = microtime( true ) - $this->created_time;
|
||||
|
||||
// Get the CPU time if the hosting environment uses it rather than wall-clock time to calculate a process's execution time.
|
||||
if ( function_exists( 'getrusage' ) && apply_filters( 'action_scheduler_use_cpu_execution_time', defined( 'PANTHEON_ENVIRONMENT' ) ) ) {
|
||||
$resource_usages = getrusage();
|
||||
|
||||
if ( isset( $resource_usages['ru_stime.tv_usec'], $resource_usages['ru_stime.tv_usec'] ) ) {
|
||||
$execution_time = $resource_usages['ru_stime.tv_sec'] + ( $resource_usages['ru_stime.tv_usec'] / 1000000 );
|
||||
}
|
||||
}
|
||||
|
||||
return $execution_time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the host's max execution time is (likely) to be exceeded if processing more actions.
|
||||
*
|
||||
* @param int $processed_actions The number of actions processed so far - used to determine the likelihood of exceeding the time limit if processing another action
|
||||
* @return bool
|
||||
*/
|
||||
protected function time_likely_to_be_exceeded( $processed_actions ) {
|
||||
|
||||
$execution_time = $this->get_execution_time();
|
||||
$max_execution_time = $this->get_time_limit();
|
||||
$time_per_action = $execution_time / $processed_actions;
|
||||
$estimated_time = $execution_time + ( $time_per_action * 3 );
|
||||
$likely_to_be_exceeded = $estimated_time > $max_execution_time;
|
||||
|
||||
return apply_filters( 'action_scheduler_maximum_execution_time_likely_to_be_exceeded', $likely_to_be_exceeded, $this, $processed_actions, $execution_time, $max_execution_time );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get memory limit
|
||||
*
|
||||
* Based on WP_Background_Process::get_memory_limit()
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function get_memory_limit() {
|
||||
if ( function_exists( 'ini_get' ) ) {
|
||||
$memory_limit = ini_get( 'memory_limit' );
|
||||
} else {
|
||||
$memory_limit = '128M'; // Sensible default, and minimum required by WooCommerce
|
||||
}
|
||||
|
||||
if ( ! $memory_limit || -1 === $memory_limit || '-1' === $memory_limit ) {
|
||||
// Unlimited, set to 32GB.
|
||||
$memory_limit = '32G';
|
||||
}
|
||||
|
||||
return ActionScheduler_Compatibility::convert_hr_to_bytes( $memory_limit );
|
||||
}
|
||||
|
||||
/**
|
||||
* Memory exceeded
|
||||
*
|
||||
* Ensures the batch process never exceeds 90% of the maximum WordPress memory.
|
||||
*
|
||||
* Based on WP_Background_Process::memory_exceeded()
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function memory_exceeded() {
|
||||
|
||||
$memory_limit = $this->get_memory_limit() * 0.90;
|
||||
$current_memory = memory_get_usage( true );
|
||||
$memory_exceeded = $current_memory >= $memory_limit;
|
||||
|
||||
return apply_filters( 'action_scheduler_memory_exceeded', $memory_exceeded, $this );
|
||||
}
|
||||
|
||||
/**
|
||||
* See if the batch limits have been exceeded, which is when memory usage is almost at
|
||||
* the maximum limit, or the time to process more actions will exceed the max time limit.
|
||||
*
|
||||
* Based on WC_Background_Process::batch_limits_exceeded()
|
||||
*
|
||||
* @param int $processed_actions The number of actions processed so far - used to determine the likelihood of exceeding the time limit if processing another action
|
||||
* @return bool
|
||||
*/
|
||||
protected function batch_limits_exceeded( $processed_actions ) {
|
||||
return $this->memory_exceeded() || $this->time_likely_to_be_exceeded( $processed_actions );
|
||||
}
|
||||
|
||||
/**
|
||||
* Process actions in the queue.
|
||||
*
|
||||
* @author Jeremy Pry
|
||||
* @param string $context Optional identifer for the context in which this action is being processed, e.g. 'WP CLI' or 'WP Cron'
|
||||
* Generally, this should be capitalised and not localised as it's a proper noun.
|
||||
* @return int The number of actions processed.
|
||||
*/
|
||||
abstract public function run( $context = '' );
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user