Commit inicial - WordPress Análisis de Precios Unitarios

- WordPress core y plugins
- Tema Twenty Twenty-Four configurado
- Plugin allow-unfiltered-html.php simplificado
- .gitignore configurado para excluir wp-config.php y uploads

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root
2025-11-03 21:04:30 -06:00
commit a22573bf0b
24068 changed files with 4993111 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
<?php
/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Google\Site_Kit_Dependencies\Google\AccessToken;
use Google\Site_Kit_Dependencies\Google\Auth\HttpHandler\HttpHandlerFactory;
use Google\Site_Kit_Dependencies\Google\Client;
use Google\Site_Kit_Dependencies\GuzzleHttp\ClientInterface;
use Google\Site_Kit_Dependencies\GuzzleHttp\Psr7;
use Google\Site_Kit_Dependencies\GuzzleHttp\Psr7\Request;
/**
* Wrapper around Google Access Tokens which provides convenience functions
*
*/
class Revoke
{
/**
* @var ClientInterface The http client
*/
private $http;
/**
* Instantiates the class, but does not initiate the login flow, leaving it
* to the discretion of the caller.
*/
public function __construct(?\Google\Site_Kit_Dependencies\GuzzleHttp\ClientInterface $http = null)
{
$this->http = $http;
}
/**
* Revoke an OAuth2 access token or refresh token. This method will revoke the current access
* token, if a token isn't provided.
*
* @param string|array $token The token (access token or a refresh token) that should be revoked.
* @return boolean Returns True if the revocation was successful, otherwise False.
*/
public function revokeToken($token)
{
if (\is_array($token)) {
if (isset($token['refresh_token'])) {
$token = $token['refresh_token'];
} else {
$token = $token['access_token'];
}
}
$body = \Google\Site_Kit_Dependencies\GuzzleHttp\Psr7\Utils::streamFor(\http_build_query(['token' => $token]));
$request = new \Google\Site_Kit_Dependencies\GuzzleHttp\Psr7\Request('POST', \Google\Site_Kit_Dependencies\Google\Client::OAUTH2_REVOKE_URI, ['Cache-Control' => 'no-store', 'Content-Type' => 'application/x-www-form-urlencoded'], $body);
$httpHandler = \Google\Site_Kit_Dependencies\Google\Auth\HttpHandler\HttpHandlerFactory::build($this->http);
$response = $httpHandler($request);
return $response->getStatusCode() == 200;
}
}

View File

@@ -0,0 +1,217 @@
<?php
/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Google\Site_Kit_Dependencies\Google\AccessToken;
use DateTime;
use DomainException;
use Exception;
use Google\Site_Kit_Dependencies\ExpiredException;
use Google\Site_Kit_Dependencies\Firebase\JWT\ExpiredException as ExpiredExceptionV3;
use Google\Site_Kit_Dependencies\Firebase\JWT\JWT;
use Google\Site_Kit_Dependencies\Firebase\JWT\Key;
use Google\Site_Kit_Dependencies\Firebase\JWT\SignatureInvalidException;
use Google\Site_Kit_Dependencies\Google\Auth\Cache\MemoryCacheItemPool;
use Google\Site_Kit_Dependencies\Google\Exception as GoogleException;
use Google\Site_Kit_Dependencies\GuzzleHttp\Client;
use Google\Site_Kit_Dependencies\GuzzleHttp\ClientInterface;
use InvalidArgumentException;
use LogicException;
use Google\Site_Kit_Dependencies\phpseclib3\Crypt\AES;
use Google\Site_Kit_Dependencies\phpseclib3\Crypt\PublicKeyLoader;
use Google\Site_Kit_Dependencies\phpseclib3\Math\BigInteger;
use Google\Site_Kit_Dependencies\Psr\Cache\CacheItemPoolInterface;
/**
* Wrapper around Google Access Tokens which provides convenience functions
*
*/
class Verify
{
const FEDERATED_SIGNON_CERT_URL = 'https://www.googleapis.com/oauth2/v3/certs';
const OAUTH2_ISSUER = 'accounts.google.com';
const OAUTH2_ISSUER_HTTPS = 'https://accounts.google.com';
/**
* @var ClientInterface The http client
*/
private $http;
/**
* @var CacheItemPoolInterface cache class
*/
private $cache;
/**
* @var \Firebase\JWT\JWT
*/
public $jwt;
/**
* Instantiates the class, but does not initiate the login flow, leaving it
* to the discretion of the caller.
*/
public function __construct(?\Google\Site_Kit_Dependencies\GuzzleHttp\ClientInterface $http = null, ?\Google\Site_Kit_Dependencies\Psr\Cache\CacheItemPoolInterface $cache = null, $jwt = null)
{
if (null === $http) {
$http = new \Google\Site_Kit_Dependencies\GuzzleHttp\Client();
}
if (null === $cache) {
$cache = new \Google\Site_Kit_Dependencies\Google\Auth\Cache\MemoryCacheItemPool();
}
$this->http = $http;
$this->cache = $cache;
$this->jwt = $jwt ?: $this->getJwtService();
}
/**
* Verifies an id token and returns the authenticated apiLoginTicket.
* Throws an exception if the id token is not valid.
* The audience parameter can be used to control which id tokens are
* accepted. By default, the id token must have been issued to this OAuth2 client.
*
* @param string $idToken the ID token in JWT format
* @param string $audience Optional. The audience to verify against JWt "aud"
* @return array|false the token payload, if successful
*/
public function verifyIdToken($idToken, $audience = null)
{
if (empty($idToken)) {
throw new \LogicException('id_token cannot be null');
}
// set phpseclib constants if applicable
$this->setPhpsecConstants();
// Check signature
$certs = $this->getFederatedSignOnCerts();
foreach ($certs as $cert) {
try {
$args = [$idToken];
$publicKey = $this->getPublicKey($cert);
if (\class_exists(\Google\Site_Kit_Dependencies\Firebase\JWT\Key::class)) {
$args[] = new \Google\Site_Kit_Dependencies\Firebase\JWT\Key($publicKey, 'RS256');
} else {
$args[] = $publicKey;
$args[] = ['RS256'];
}
$payload = \call_user_func_array([$this->jwt, 'decode'], $args);
if (\property_exists($payload, 'aud')) {
if ($audience && $payload->aud != $audience) {
return \false;
}
}
// support HTTP and HTTPS issuers
// @see https://developers.google.com/identity/sign-in/web/backend-auth
$issuers = [self::OAUTH2_ISSUER, self::OAUTH2_ISSUER_HTTPS];
if (!isset($payload->iss) || !\in_array($payload->iss, $issuers)) {
return \false;
}
return (array) $payload;
} catch (\Google\Site_Kit_Dependencies\ExpiredException $e) {
// @phpstan-ignore-line
return \false;
} catch (\Google\Site_Kit_Dependencies\Firebase\JWT\ExpiredException $e) {
return \false;
} catch (\Google\Site_Kit_Dependencies\Firebase\JWT\SignatureInvalidException $e) {
// continue
} catch (\DomainException $e) {
// continue
}
}
return \false;
}
private function getCache()
{
return $this->cache;
}
/**
* Retrieve and cache a certificates file.
*
* @param string $url location
* @throws \Google\Exception
* @return array certificates
*/
private function retrieveCertsFromLocation($url)
{
// If we're retrieving a local file, just grab it.
if (0 !== \strpos($url, 'http')) {
if (!($file = \file_get_contents($url))) {
throw new \Google\Site_Kit_Dependencies\Google\Exception("Failed to retrieve verification certificates: '" . $url . "'.");
}
return \json_decode($file, \true);
}
// @phpstan-ignore-next-line
$response = $this->http->get($url);
if ($response->getStatusCode() == 200) {
return \json_decode((string) $response->getBody(), \true);
}
throw new \Google\Site_Kit_Dependencies\Google\Exception(\sprintf('Failed to retrieve verification certificates: "%s".', $response->getBody()->getContents()), $response->getStatusCode());
}
// Gets federated sign-on certificates to use for verifying identity tokens.
// Returns certs as array structure, where keys are key ids, and values
// are PEM encoded certificates.
private function getFederatedSignOnCerts()
{
$certs = null;
if ($cache = $this->getCache()) {
$cacheItem = $cache->getItem('federated_signon_certs_v3');
$certs = $cacheItem->get();
}
if (!$certs) {
$certs = $this->retrieveCertsFromLocation(self::FEDERATED_SIGNON_CERT_URL);
if ($cache) {
$cacheItem->expiresAt(new \DateTime('+1 hour'));
$cacheItem->set($certs);
$cache->save($cacheItem);
}
}
if (!isset($certs['keys'])) {
throw new \InvalidArgumentException('federated sign-on certs expects "keys" to be set');
}
return $certs['keys'];
}
private function getJwtService()
{
$jwt = new \Google\Site_Kit_Dependencies\Firebase\JWT\JWT();
if ($jwt::$leeway < 1) {
// Ensures JWT leeway is at least 1
// @see https://github.com/google/google-api-php-client/issues/827
$jwt::$leeway = 1;
}
return $jwt;
}
private function getPublicKey($cert)
{
$modulus = new \Google\Site_Kit_Dependencies\phpseclib3\Math\BigInteger($this->jwt->urlsafeB64Decode($cert['n']), 256);
$exponent = new \Google\Site_Kit_Dependencies\phpseclib3\Math\BigInteger($this->jwt->urlsafeB64Decode($cert['e']), 256);
$component = ['n' => $modulus, 'e' => $exponent];
$loader = \Google\Site_Kit_Dependencies\phpseclib3\Crypt\PublicKeyLoader::load($component);
return $loader->toString('PKCS8');
}
/**
* phpseclib calls "phpinfo" by default, which requires special
* whitelisting in the AppEngine VM environment. This function
* sets constants to bypass the need for phpseclib to check phpinfo
*
* @see phpseclib/Math/BigInteger
* @see https://github.com/GoogleCloudPlatform/getting-started-php/issues/85
*/
private function setPhpsecConstants()
{
if (\filter_var(\getenv('GAE_VM'), \FILTER_VALIDATE_BOOLEAN)) {
if (!\defined('Google\\Site_Kit_Dependencies\\MATH_BIGINTEGER_OPENSSL_ENABLED')) {
\define('Google\\Site_Kit_Dependencies\\MATH_BIGINTEGER_OPENSSL_ENABLED', \true);
}
if (!\defined('Google\\Site_Kit_Dependencies\\CRYPT_RSA_MODE')) {
\define('Google\\Site_Kit_Dependencies\\CRYPT_RSA_MODE', \Google\Site_Kit_Dependencies\phpseclib3\Crypt\AES::ENGINE_OPENSSL);
}
}
}
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Google\Site_Kit_Dependencies\Google\AuthHandler;
use Exception;
use Google\Site_Kit_Dependencies\GuzzleHttp\ClientInterface;
class AuthHandlerFactory
{
/**
* Builds out a default http handler for the installed version of guzzle.
*
* @return Guzzle6AuthHandler|Guzzle7AuthHandler
* @throws Exception
*/
public static function build($cache = null, array $cacheConfig = [])
{
$guzzleVersion = null;
if (\defined('\\Google\\Site_Kit_Dependencies\\GuzzleHttp\\ClientInterface::MAJOR_VERSION')) {
$guzzleVersion = \Google\Site_Kit_Dependencies\GuzzleHttp\ClientInterface::MAJOR_VERSION;
} elseif (\defined('\\Google\\Site_Kit_Dependencies\\GuzzleHttp\\ClientInterface::VERSION')) {
$guzzleVersion = (int) \substr(\Google\Site_Kit_Dependencies\GuzzleHttp\ClientInterface::VERSION, 0, 1);
}
switch ($guzzleVersion) {
case 6:
return new \Google\Site_Kit_Dependencies\Google\AuthHandler\Guzzle6AuthHandler($cache, $cacheConfig);
case 7:
return new \Google\Site_Kit_Dependencies\Google\AuthHandler\Guzzle7AuthHandler($cache, $cacheConfig);
default:
throw new \Exception('Version not supported');
}
}
}

View File

@@ -0,0 +1,76 @@
<?php
namespace Google\Site_Kit_Dependencies\Google\AuthHandler;
use Google\Site_Kit_Dependencies\Google\Auth\CredentialsLoader;
use Google\Site_Kit_Dependencies\Google\Auth\FetchAuthTokenCache;
use Google\Site_Kit_Dependencies\Google\Auth\HttpHandler\HttpHandlerFactory;
use Google\Site_Kit_Dependencies\Google\Auth\Middleware\AuthTokenMiddleware;
use Google\Site_Kit_Dependencies\Google\Auth\Middleware\ScopedAccessTokenMiddleware;
use Google\Site_Kit_Dependencies\Google\Auth\Middleware\SimpleMiddleware;
use Google\Site_Kit_Dependencies\GuzzleHttp\Client;
use Google\Site_Kit_Dependencies\GuzzleHttp\ClientInterface;
use Google\Site_Kit_Dependencies\Psr\Cache\CacheItemPoolInterface;
/**
* This supports Guzzle 6
*/
class Guzzle6AuthHandler
{
protected $cache;
protected $cacheConfig;
public function __construct(?\Google\Site_Kit_Dependencies\Psr\Cache\CacheItemPoolInterface $cache = null, array $cacheConfig = [])
{
$this->cache = $cache;
$this->cacheConfig = $cacheConfig;
}
public function attachCredentials(\Google\Site_Kit_Dependencies\GuzzleHttp\ClientInterface $http, \Google\Site_Kit_Dependencies\Google\Auth\CredentialsLoader $credentials, ?callable $tokenCallback = null)
{
// use the provided cache
if ($this->cache) {
$credentials = new \Google\Site_Kit_Dependencies\Google\Auth\FetchAuthTokenCache($credentials, $this->cacheConfig, $this->cache);
}
return $this->attachCredentialsCache($http, $credentials, $tokenCallback);
}
public function attachCredentialsCache(\Google\Site_Kit_Dependencies\GuzzleHttp\ClientInterface $http, \Google\Site_Kit_Dependencies\Google\Auth\FetchAuthTokenCache $credentials, ?callable $tokenCallback = null)
{
// if we end up needing to make an HTTP request to retrieve credentials, we
// can use our existing one, but we need to throw exceptions so the error
// bubbles up.
$authHttp = $this->createAuthHttp($http);
$authHttpHandler = \Google\Site_Kit_Dependencies\Google\Auth\HttpHandler\HttpHandlerFactory::build($authHttp);
$middleware = new \Google\Site_Kit_Dependencies\Google\Auth\Middleware\AuthTokenMiddleware($credentials, $authHttpHandler, $tokenCallback);
$config = $http->getConfig();
$config['handler']->remove('google_auth');
$config['handler']->push($middleware, 'google_auth');
$config['auth'] = 'google_auth';
$http = new \Google\Site_Kit_Dependencies\GuzzleHttp\Client($config);
return $http;
}
public function attachToken(\Google\Site_Kit_Dependencies\GuzzleHttp\ClientInterface $http, array $token, array $scopes)
{
$tokenFunc = function ($scopes) use($token) {
return $token['access_token'];
};
$middleware = new \Google\Site_Kit_Dependencies\Google\Auth\Middleware\ScopedAccessTokenMiddleware($tokenFunc, $scopes, $this->cacheConfig, $this->cache);
$config = $http->getConfig();
$config['handler']->remove('google_auth');
$config['handler']->push($middleware, 'google_auth');
$config['auth'] = 'scoped';
$http = new \Google\Site_Kit_Dependencies\GuzzleHttp\Client($config);
return $http;
}
public function attachKey(\Google\Site_Kit_Dependencies\GuzzleHttp\ClientInterface $http, $key)
{
$middleware = new \Google\Site_Kit_Dependencies\Google\Auth\Middleware\SimpleMiddleware(['key' => $key]);
$config = $http->getConfig();
$config['handler']->remove('google_auth');
$config['handler']->push($middleware, 'google_auth');
$config['auth'] = 'simple';
$http = new \Google\Site_Kit_Dependencies\GuzzleHttp\Client($config);
return $http;
}
private function createAuthHttp(\Google\Site_Kit_Dependencies\GuzzleHttp\ClientInterface $http)
{
return new \Google\Site_Kit_Dependencies\GuzzleHttp\Client(['http_errors' => \true] + $http->getConfig());
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Google\Site_Kit_Dependencies\Google\AuthHandler;
/**
* This supports Guzzle 7
*/
class Guzzle7AuthHandler extends \Google\Site_Kit_Dependencies\Google\AuthHandler\Guzzle6AuthHandler
{
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,104 @@
<?php
namespace Google\Site_Kit_Dependencies\Google;
/**
* Extension to the regular Google\Model that automatically
* exposes the items array for iteration, so you can just
* iterate over the object rather than a reference inside.
*/
class Collection extends \Google\Site_Kit_Dependencies\Google\Model implements \Iterator, \Countable
{
protected $collection_key = 'items';
/** @return void */
#[\ReturnTypeWillChange]
public function rewind()
{
if (isset($this->{$this->collection_key}) && \is_array($this->{$this->collection_key})) {
\reset($this->{$this->collection_key});
}
}
/** @return mixed */
#[\ReturnTypeWillChange]
public function current()
{
$this->coerceType($this->key());
if (\is_array($this->{$this->collection_key})) {
return \current($this->{$this->collection_key});
}
}
/** @return mixed */
#[\ReturnTypeWillChange]
public function key()
{
if (isset($this->{$this->collection_key}) && \is_array($this->{$this->collection_key})) {
return \key($this->{$this->collection_key});
}
}
/** @return mixed */
#[\ReturnTypeWillChange]
public function next()
{
return \next($this->{$this->collection_key});
}
/** @return bool */
#[\ReturnTypeWillChange]
public function valid()
{
$key = $this->key();
return $key !== null && $key !== \false;
}
/** @return int */
#[\ReturnTypeWillChange]
public function count()
{
if (!isset($this->{$this->collection_key})) {
return 0;
}
return \count($this->{$this->collection_key});
}
/** @return bool */
#[\ReturnTypeWillChange]
public function offsetExists($offset)
{
if (!\is_numeric($offset)) {
return parent::offsetExists($offset);
}
return isset($this->{$this->collection_key}[$offset]);
}
/** @return mixed */
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
if (!\is_numeric($offset)) {
return parent::offsetGet($offset);
}
$this->coerceType($offset);
return $this->{$this->collection_key}[$offset];
}
/** @return void */
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
if (!\is_numeric($offset)) {
parent::offsetSet($offset, $value);
}
$this->{$this->collection_key}[$offset] = $value;
}
/** @return void */
#[\ReturnTypeWillChange]
public function offsetUnset($offset)
{
if (!\is_numeric($offset)) {
parent::offsetUnset($offset);
}
unset($this->{$this->collection_key}[$offset]);
}
private function coerceType($offset)
{
$keyType = $this->keyType($this->collection_key);
if ($keyType && !\is_object($this->{$this->collection_key}[$offset])) {
$this->{$this->collection_key}[$offset] = new $keyType($this->{$this->collection_key}[$offset]);
}
}
}

View File

@@ -0,0 +1,23 @@
<?php
/*
* Copyright 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Google\Site_Kit_Dependencies\Google;
use Exception as BaseException;
class Exception extends \Exception
{
}

View File

@@ -0,0 +1,191 @@
<?php
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Google\Site_Kit_Dependencies\Google\Http;
use Google\Site_Kit_Dependencies\Google\Client;
use Google\Site_Kit_Dependencies\Google\Service\Exception as GoogleServiceException;
use Google\Site_Kit_Dependencies\GuzzleHttp\Psr7;
use Google\Site_Kit_Dependencies\GuzzleHttp\Psr7\Request;
use Google\Site_Kit_Dependencies\GuzzleHttp\Psr7\Response;
use Google\Site_Kit_Dependencies\Psr\Http\Message\RequestInterface;
use Google\Site_Kit_Dependencies\Psr\Http\Message\ResponseInterface;
/**
* Class to handle batched requests to the Google API service.
*
* Note that calls to `Google\Http\Batch::execute()` do not clear the queued
* requests. To start a new batch, be sure to create a new instance of this
* class.
*/
class Batch
{
const BATCH_PATH = 'batch';
private static $CONNECTION_ESTABLISHED_HEADERS = ["HTTP/1.0 200 Connection established\r\n\r\n", "HTTP/1.1 200 Connection established\r\n\r\n"];
/** @var string Multipart Boundary. */
private $boundary;
/** @var array service requests to be executed. */
private $requests = [];
/** @var Client */
private $client;
private $rootUrl;
private $batchPath;
public function __construct(\Google\Site_Kit_Dependencies\Google\Client $client, $boundary = \false, $rootUrl = null, $batchPath = null)
{
$this->client = $client;
$this->boundary = $boundary ?: \mt_rand();
$rootUrl = \rtrim($rootUrl ?: $this->client->getConfig('base_path'), '/');
$this->rootUrl = \str_replace('UNIVERSE_DOMAIN', $this->client->getUniverseDomain(), $rootUrl);
$this->batchPath = $batchPath ?: self::BATCH_PATH;
}
public function add(\Google\Site_Kit_Dependencies\Psr\Http\Message\RequestInterface $request, $key = \false)
{
if (\false == $key) {
$key = \mt_rand();
}
$this->requests[$key] = $request;
}
public function execute()
{
$body = '';
$classes = [];
$batchHttpTemplate = <<<EOF
--%s
Content-Type: application/http
Content-Transfer-Encoding: binary
MIME-Version: 1.0
Content-ID: %s
%s
%s%s
EOF;
/** @var RequestInterface $request */
foreach ($this->requests as $key => $request) {
$firstLine = \sprintf('%s %s HTTP/%s', $request->getMethod(), $request->getRequestTarget(), $request->getProtocolVersion());
$content = (string) $request->getBody();
$headers = '';
foreach ($request->getHeaders() as $name => $values) {
$headers .= \sprintf("%s:%s\r\n", $name, \implode(', ', $values));
}
$body .= \sprintf($batchHttpTemplate, $this->boundary, $key, $firstLine, $headers, $content ? "\n" . $content : '');
$classes['response-' . $key] = $request->getHeaderLine('X-Php-Expected-Class');
}
$body .= "--{$this->boundary}--";
$body = \trim($body);
$url = $this->rootUrl . '/' . $this->batchPath;
$headers = ['Content-Type' => \sprintf('multipart/mixed; boundary=%s', $this->boundary), 'Content-Length' => (string) \strlen($body)];
$request = new \Google\Site_Kit_Dependencies\GuzzleHttp\Psr7\Request('POST', $url, $headers, $body);
$response = $this->client->execute($request);
return $this->parseResponse($response, $classes);
}
public function parseResponse(\Google\Site_Kit_Dependencies\Psr\Http\Message\ResponseInterface $response, $classes = [])
{
$contentType = $response->getHeaderLine('content-type');
$contentType = \explode(';', $contentType);
$boundary = \false;
foreach ($contentType as $part) {
$part = \explode('=', $part, 2);
if (isset($part[0]) && 'boundary' == \trim($part[0])) {
$boundary = $part[1];
}
}
$body = (string) $response->getBody();
if (!empty($body)) {
$body = \str_replace("--{$boundary}--", "--{$boundary}", $body);
$parts = \explode("--{$boundary}", $body);
$responses = [];
$requests = \array_values($this->requests);
foreach ($parts as $i => $part) {
$part = \trim($part);
if (!empty($part)) {
list($rawHeaders, $part) = \explode("\r\n\r\n", $part, 2);
$headers = $this->parseRawHeaders($rawHeaders);
$status = \substr($part, 0, \strpos($part, "\n"));
$status = \explode(" ", $status);
$status = $status[1];
list($partHeaders, $partBody) = $this->parseHttpResponse($part, 0);
$response = new \Google\Site_Kit_Dependencies\GuzzleHttp\Psr7\Response((int) $status, $partHeaders, \Google\Site_Kit_Dependencies\GuzzleHttp\Psr7\Utils::streamFor($partBody));
// Need content id.
$key = $headers['content-id'];
try {
$response = \Google\Site_Kit_Dependencies\Google\Http\REST::decodeHttpResponse($response, $requests[$i - 1]);
} catch (\Google\Site_Kit_Dependencies\Google\Service\Exception $e) {
// Store the exception as the response, so successful responses
// can be processed.
$response = $e;
}
$responses[$key] = $response;
}
}
return $responses;
}
return null;
}
private function parseRawHeaders($rawHeaders)
{
$headers = [];
$responseHeaderLines = \explode("\r\n", $rawHeaders);
foreach ($responseHeaderLines as $headerLine) {
if ($headerLine && \strpos($headerLine, ':') !== \false) {
list($header, $value) = \explode(': ', $headerLine, 2);
$header = \strtolower($header);
if (isset($headers[$header])) {
$headers[$header] = \array_merge((array) $headers[$header], (array) $value);
} else {
$headers[$header] = $value;
}
}
}
return $headers;
}
/**
* Used by the IO lib and also the batch processing.
*
* @param string $respData
* @param int $headerSize
* @return array
*/
private function parseHttpResponse($respData, $headerSize)
{
// check proxy header
foreach (self::$CONNECTION_ESTABLISHED_HEADERS as $established_header) {
if (\stripos($respData, $established_header) !== \false) {
// existed, remove it
$respData = \str_ireplace($established_header, '', $respData);
// Subtract the proxy header size unless the cURL bug prior to 7.30.0
// is present which prevented the proxy header size from being taken into
// account.
// @TODO look into this
// if (!$this->needsQuirk()) {
// $headerSize -= strlen($established_header);
// }
break;
}
}
if ($headerSize) {
$responseBody = \substr($respData, $headerSize);
$responseHeaders = \substr($respData, 0, $headerSize);
} else {
$responseSegments = \explode("\r\n\r\n", $respData, 2);
$responseHeaders = $responseSegments[0];
$responseBody = isset($responseSegments[1]) ? $responseSegments[1] : null;
}
$responseHeaders = $this->parseRawHeaders($responseHeaders);
return [$responseHeaders, $responseBody];
}
}

View File

@@ -0,0 +1,273 @@
<?php
/**
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Google\Site_Kit_Dependencies\Google\Http;
use Google\Site_Kit_Dependencies\Google\Client;
use Google\Site_Kit_Dependencies\Google\Exception as GoogleException;
use Google\Site_Kit_Dependencies\GuzzleHttp\Psr7;
use Google\Site_Kit_Dependencies\GuzzleHttp\Psr7\Request;
use Google\Site_Kit_Dependencies\GuzzleHttp\Psr7\Uri;
use Google\Site_Kit_Dependencies\Psr\Http\Message\RequestInterface;
/**
* Manage large file uploads, which may be media but can be any type
* of sizable data.
*/
class MediaFileUpload
{
const UPLOAD_MEDIA_TYPE = 'media';
const UPLOAD_MULTIPART_TYPE = 'multipart';
const UPLOAD_RESUMABLE_TYPE = 'resumable';
/** @var string $mimeType */
private $mimeType;
/** @var string $data */
private $data;
/** @var bool $resumable */
private $resumable;
/** @var int $chunkSize */
private $chunkSize;
/** @var int $size */
private $size;
/** @var string $resumeUri */
private $resumeUri;
/** @var int $progress */
private $progress;
/** @var Client */
private $client;
/** @var RequestInterface */
private $request;
/** @var string */
private $boundary;
// @phpstan-ignore-line
/**
* Result code from last HTTP call
* @var int
*/
private $httpResultCode;
/**
* @param Client $client
* @param RequestInterface $request
* @param string $mimeType
* @param string $data The bytes you want to upload.
* @param bool $resumable
* @param int $chunkSize File will be uploaded in chunks of this many bytes.
* only used if resumable=True
*/
public function __construct(\Google\Site_Kit_Dependencies\Google\Client $client, \Google\Site_Kit_Dependencies\Psr\Http\Message\RequestInterface $request, $mimeType, $data, $resumable = \false, $chunkSize = 0)
{
$this->client = $client;
$this->request = $request;
$this->mimeType = $mimeType;
$this->data = $data;
$this->resumable = $resumable;
$this->chunkSize = $chunkSize;
$this->progress = 0;
$this->process();
}
/**
* Set the size of the file that is being uploaded.
* @param int $size - int file size in bytes
*/
public function setFileSize($size)
{
$this->size = $size;
}
/**
* Return the progress on the upload
* @return int progress in bytes uploaded.
*/
public function getProgress()
{
return $this->progress;
}
/**
* Send the next part of the file to upload.
* @param string|bool $chunk Optional. The next set of bytes to send. If false will
* use $data passed at construct time.
*/
public function nextChunk($chunk = \false)
{
$resumeUri = $this->getResumeUri();
if (\false == $chunk) {
$chunk = \substr($this->data, $this->progress, $this->chunkSize);
}
$lastBytePos = $this->progress + \strlen($chunk) - 1;
$headers = ['content-range' => "bytes {$this->progress}-{$lastBytePos}/{$this->size}", 'content-length' => (string) \strlen($chunk), 'expect' => ''];
$request = new \Google\Site_Kit_Dependencies\GuzzleHttp\Psr7\Request('PUT', $resumeUri, $headers, \Google\Site_Kit_Dependencies\GuzzleHttp\Psr7\Utils::streamFor($chunk));
return $this->makePutRequest($request);
}
/**
* Return the HTTP result code from the last call made.
* @return int code
*/
public function getHttpResultCode()
{
return $this->httpResultCode;
}
/**
* Sends a PUT-Request to google drive and parses the response,
* setting the appropiate variables from the response()
*
* @param RequestInterface $request the Request which will be send
*
* @return false|mixed false when the upload is unfinished or the decoded http response
*
*/
private function makePutRequest(\Google\Site_Kit_Dependencies\Psr\Http\Message\RequestInterface $request)
{
$response = $this->client->execute($request);
$this->httpResultCode = $response->getStatusCode();
if (308 == $this->httpResultCode) {
// Track the amount uploaded.
$range = $response->getHeaderLine('range');
if ($range) {
$range_array = \explode('-', $range);
$this->progress = (int) $range_array[1] + 1;
}
// Allow for changing upload URLs.
$location = $response->getHeaderLine('location');
if ($location) {
$this->resumeUri = $location;
}
// No problems, but upload not complete.
return \false;
}
return \Google\Site_Kit_Dependencies\Google\Http\REST::decodeHttpResponse($response, $this->request);
}
/**
* Resume a previously unfinished upload
* @param string $resumeUri the resume-URI of the unfinished, resumable upload.
*/
public function resume($resumeUri)
{
$this->resumeUri = $resumeUri;
$headers = ['content-range' => "bytes */{$this->size}", 'content-length' => '0'];
$httpRequest = new \Google\Site_Kit_Dependencies\GuzzleHttp\Psr7\Request('PUT', $this->resumeUri, $headers);
return $this->makePutRequest($httpRequest);
}
/**
* @return RequestInterface
* @visible for testing
*/
private function process()
{
$this->transformToUploadUrl();
$request = $this->request;
$postBody = '';
$contentType = \false;
$meta = \json_decode((string) $request->getBody(), \true);
$uploadType = $this->getUploadType($meta);
$request = $request->withUri(\Google\Site_Kit_Dependencies\GuzzleHttp\Psr7\Uri::withQueryValue($request->getUri(), 'uploadType', $uploadType));
$mimeType = $this->mimeType ?: $request->getHeaderLine('content-type');
if (self::UPLOAD_RESUMABLE_TYPE == $uploadType) {
$contentType = $mimeType;
$postBody = \is_string($meta) ? $meta : \json_encode($meta);
} elseif (self::UPLOAD_MEDIA_TYPE == $uploadType) {
$contentType = $mimeType;
$postBody = $this->data;
} elseif (self::UPLOAD_MULTIPART_TYPE == $uploadType) {
// This is a multipart/related upload.
$boundary = $this->boundary ?: \mt_rand();
$boundary = \str_replace('"', '', $boundary);
$contentType = 'multipart/related; boundary=' . $boundary;
$related = "--{$boundary}\r\n";
$related .= "Content-Type: application/json; charset=UTF-8\r\n";
$related .= "\r\n" . \json_encode($meta) . "\r\n";
$related .= "--{$boundary}\r\n";
$related .= "Content-Type: {$mimeType}\r\n";
$related .= "Content-Transfer-Encoding: base64\r\n";
$related .= "\r\n" . \base64_encode($this->data) . "\r\n";
$related .= "--{$boundary}--";
$postBody = $related;
}
$request = $request->withBody(\Google\Site_Kit_Dependencies\GuzzleHttp\Psr7\Utils::streamFor($postBody));
if ($contentType) {
$request = $request->withHeader('content-type', $contentType);
}
return $this->request = $request;
}
/**
* Valid upload types:
* - resumable (UPLOAD_RESUMABLE_TYPE)
* - media (UPLOAD_MEDIA_TYPE)
* - multipart (UPLOAD_MULTIPART_TYPE)
* @param string|false $meta
* @return string
* @visible for testing
*/
public function getUploadType($meta)
{
if ($this->resumable) {
return self::UPLOAD_RESUMABLE_TYPE;
}
if (\false == $meta && $this->data) {
return self::UPLOAD_MEDIA_TYPE;
}
return self::UPLOAD_MULTIPART_TYPE;
}
public function getResumeUri()
{
if (null === $this->resumeUri) {
$this->resumeUri = $this->fetchResumeUri();
}
return $this->resumeUri;
}
private function fetchResumeUri()
{
$body = $this->request->getBody();
$headers = ['content-type' => 'application/json; charset=UTF-8', 'content-length' => $body->getSize(), 'x-upload-content-type' => $this->mimeType, 'x-upload-content-length' => $this->size, 'expect' => ''];
foreach ($headers as $key => $value) {
$this->request = $this->request->withHeader($key, $value);
}
$response = $this->client->execute($this->request, \false);
$location = $response->getHeaderLine('location');
$code = $response->getStatusCode();
if (200 == $code && \true == $location) {
return $location;
}
$message = $code;
$body = \json_decode((string) $this->request->getBody(), \true);
if (isset($body['error']['errors'])) {
$message .= ': ';
foreach ($body['error']['errors'] as $error) {
$message .= "{$error['domain']}, {$error['message']};";
}
$message = \rtrim($message, ';');
}
$error = "Failed to start the resumable upload (HTTP {$message})";
$this->client->getLogger()->error($error);
throw new \Google\Site_Kit_Dependencies\Google\Exception($error);
}
private function transformToUploadUrl()
{
$parts = \parse_url((string) $this->request->getUri());
if (!isset($parts['path'])) {
$parts['path'] = '';
}
$parts['path'] = '/upload' . $parts['path'];
$uri = \Google\Site_Kit_Dependencies\GuzzleHttp\Psr7\Uri::fromParts($parts);
$this->request = $this->request->withUri($uri);
}
public function setChunkSize($chunkSize)
{
$this->chunkSize = $chunkSize;
}
public function getRequest()
{
return $this->request;
}
}

View File

@@ -0,0 +1,153 @@
<?php
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Google\Site_Kit_Dependencies\Google\Http;
use Google\Site_Kit_Dependencies\Google\Auth\HttpHandler\HttpHandlerFactory;
use Google\Site_Kit_Dependencies\Google\Service\Exception as GoogleServiceException;
use Google\Site_Kit_Dependencies\Google\Task\Runner;
use Google\Site_Kit_Dependencies\GuzzleHttp\ClientInterface;
use Google\Site_Kit_Dependencies\GuzzleHttp\Exception\RequestException;
use Google\Site_Kit_Dependencies\GuzzleHttp\Psr7\Response;
use Google\Site_Kit_Dependencies\Psr\Http\Message\RequestInterface;
use Google\Site_Kit_Dependencies\Psr\Http\Message\ResponseInterface;
/**
* This class implements the RESTful transport of apiServiceRequest()'s
*/
class REST
{
/**
* Executes a Psr\Http\Message\RequestInterface and (if applicable) automatically retries
* when errors occur.
*
* @template T
* @param ClientInterface $client
* @param RequestInterface $request
* @param class-string<T>|false|null $expectedClass
* @param array $config
* @param array $retryMap
* @return mixed|T|null
* @throws \Google\Service\Exception on server side error (ie: not authenticated,
* invalid or malformed post body, invalid url)
*/
public static function execute(\Google\Site_Kit_Dependencies\GuzzleHttp\ClientInterface $client, \Google\Site_Kit_Dependencies\Psr\Http\Message\RequestInterface $request, $expectedClass = null, $config = [], $retryMap = null)
{
$runner = new \Google\Site_Kit_Dependencies\Google\Task\Runner($config, \sprintf('%s %s', $request->getMethod(), (string) $request->getUri()), [self::class, 'doExecute'], [$client, $request, $expectedClass]);
if (null !== $retryMap) {
$runner->setRetryMap($retryMap);
}
return $runner->run();
}
/**
* Executes a Psr\Http\Message\RequestInterface
*
* @template T
* @param ClientInterface $client
* @param RequestInterface $request
* @param class-string<T>|false|null $expectedClass
* @return mixed|T|null
* @throws \Google\Service\Exception on server side error (ie: not authenticated,
* invalid or malformed post body, invalid url)
*/
public static function doExecute(\Google\Site_Kit_Dependencies\GuzzleHttp\ClientInterface $client, \Google\Site_Kit_Dependencies\Psr\Http\Message\RequestInterface $request, $expectedClass = null)
{
try {
$httpHandler = \Google\Site_Kit_Dependencies\Google\Auth\HttpHandler\HttpHandlerFactory::build($client);
$response = $httpHandler($request);
} catch (\Google\Site_Kit_Dependencies\GuzzleHttp\Exception\RequestException $e) {
// if Guzzle throws an exception, catch it and handle the response
if (!$e->hasResponse()) {
throw $e;
}
$response = $e->getResponse();
// specific checking for Guzzle 5: convert to PSR7 response
if (\interface_exists('Google\\Site_Kit_Dependencies\\GuzzleHttp\\Message\\ResponseInterface') && $response instanceof \Google\Site_Kit_Dependencies\GuzzleHttp\Message\ResponseInterface) {
$response = new \Google\Site_Kit_Dependencies\GuzzleHttp\Psr7\Response($response->getStatusCode(), $response->getHeaders() ?: [], $response->getBody(), $response->getProtocolVersion(), $response->getReasonPhrase());
}
}
return self::decodeHttpResponse($response, $request, $expectedClass);
}
/**
* Decode an HTTP Response.
* @static
*
* @template T
* @param RequestInterface $response The http response to be decoded.
* @param ResponseInterface $response
* @param class-string<T>|false|null $expectedClass
* @return mixed|T|null
* @throws \Google\Service\Exception
*/
public static function decodeHttpResponse(\Google\Site_Kit_Dependencies\Psr\Http\Message\ResponseInterface $response, ?\Google\Site_Kit_Dependencies\Psr\Http\Message\RequestInterface $request = null, $expectedClass = null)
{
$code = $response->getStatusCode();
// retry strategy
if (\intVal($code) >= 400) {
// if we errored out, it should be safe to grab the response body
$body = (string) $response->getBody();
// Check if we received errors, and add those to the Exception for convenience
throw new \Google\Site_Kit_Dependencies\Google\Service\Exception($body, $code, null, self::getResponseErrors($body));
}
// Ensure we only pull the entire body into memory if the request is not
// of media type
$body = self::decodeBody($response, $request);
if ($expectedClass = self::determineExpectedClass($expectedClass, $request)) {
$json = \json_decode($body, \true);
return new $expectedClass($json);
}
return $response;
}
private static function decodeBody(\Google\Site_Kit_Dependencies\Psr\Http\Message\ResponseInterface $response, ?\Google\Site_Kit_Dependencies\Psr\Http\Message\RequestInterface $request = null)
{
if (self::isAltMedia($request)) {
// don't decode the body, it's probably a really long string
return '';
}
return (string) $response->getBody();
}
private static function determineExpectedClass($expectedClass, ?\Google\Site_Kit_Dependencies\Psr\Http\Message\RequestInterface $request = null)
{
// "false" is used to explicitly prevent an expected class from being returned
if (\false === $expectedClass) {
return null;
}
// if we don't have a request, we just use what's passed in
if (null === $request) {
return $expectedClass;
}
// return what we have in the request header if one was not supplied
return $expectedClass ?: $request->getHeaderLine('X-Php-Expected-Class');
}
private static function getResponseErrors($body)
{
$json = \json_decode($body, \true);
if (isset($json['error']['errors'])) {
return $json['error']['errors'];
}
return null;
}
private static function isAltMedia(?\Google\Site_Kit_Dependencies\Psr\Http\Message\RequestInterface $request = null)
{
if ($request && ($qs = $request->getUri()->getQuery())) {
\parse_str($qs, $query);
if (isset($query['alt']) && $query['alt'] == 'media') {
return \true;
}
}
return \false;
}
}

View File

@@ -0,0 +1,301 @@
<?php
/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Google\Site_Kit_Dependencies\Google;
use Google\Site_Kit_Dependencies\Google\Exception as GoogleException;
use ReflectionObject;
use ReflectionProperty;
use stdClass;
/**
* This class defines attributes, valid values, and usage which is generated
* from a given json schema.
* http://tools.ietf.org/html/draft-zyp-json-schema-03#section-5
*
*/
#[\AllowDynamicProperties]
class Model implements \ArrayAccess
{
/**
* If you need to specify a NULL JSON value, use Google\Model::NULL_VALUE
* instead - it will be replaced when converting to JSON with a real null.
*/
const NULL_VALUE = "{}gapi-php-null";
protected $internal_gapi_mappings = [];
protected $modelData = [];
protected $processed = [];
/**
* Polymorphic - accepts a variable number of arguments dependent
* on the type of the model subclass.
*/
public final function __construct()
{
if (\func_num_args() == 1 && \is_array(\func_get_arg(0))) {
// Initialize the model with the array's contents.
$array = \func_get_arg(0);
$this->mapTypes($array);
}
$this->gapiInit();
}
/**
* Getter that handles passthrough access to the data array, and lazy object creation.
* @param string $key Property name.
* @return mixed The value if any, or null.
*/
public function __get($key)
{
$keyType = $this->keyType($key);
$keyDataType = $this->dataType($key);
if ($keyType && !isset($this->processed[$key])) {
if (isset($this->modelData[$key])) {
$val = $this->modelData[$key];
} elseif ($keyDataType == 'array' || $keyDataType == 'map') {
$val = [];
} else {
$val = null;
}
if ($this->isAssociativeArray($val)) {
if ($keyDataType && 'map' == $keyDataType) {
foreach ($val as $arrayKey => $arrayItem) {
$this->modelData[$key][$arrayKey] = new $keyType($arrayItem);
}
} else {
$this->modelData[$key] = new $keyType($val);
}
} elseif (\is_array($val)) {
$arrayObject = [];
foreach ($val as $arrayIndex => $arrayItem) {
$arrayObject[$arrayIndex] = new $keyType($arrayItem);
}
$this->modelData[$key] = $arrayObject;
}
$this->processed[$key] = \true;
}
return isset($this->modelData[$key]) ? $this->modelData[$key] : null;
}
/**
* Initialize this object's properties from an array.
*
* @param array $array Used to seed this object's properties.
* @return void
*/
protected function mapTypes($array)
{
// Hard initialise simple types, lazy load more complex ones.
foreach ($array as $key => $val) {
if ($keyType = $this->keyType($key)) {
$dataType = $this->dataType($key);
if ($dataType == 'array' || $dataType == 'map') {
$this->{$key} = [];
foreach ($val as $itemKey => $itemVal) {
if ($itemVal instanceof $keyType) {
$this->{$key}[$itemKey] = $itemVal;
} else {
$this->{$key}[$itemKey] = new $keyType($itemVal);
}
}
} elseif ($val instanceof $keyType) {
$this->{$key} = $val;
} else {
$this->{$key} = new $keyType($val);
}
unset($array[$key]);
} elseif (\property_exists($this, $key)) {
$this->{$key} = $val;
unset($array[$key]);
} elseif (\property_exists($this, $camelKey = $this->camelCase($key))) {
// This checks if property exists as camelCase, leaving it in array as snake_case
// in case of backwards compatibility issues.
$this->{$camelKey} = $val;
}
}
$this->modelData = $array;
}
/**
* Blank initialiser to be used in subclasses to do post-construction initialisation - this
* avoids the need for subclasses to have to implement the variadics handling in their
* constructors.
*/
protected function gapiInit()
{
return;
}
/**
* Create a simplified object suitable for straightforward
* conversion to JSON. This is relatively expensive
* due to the usage of reflection, but shouldn't be called
* a whole lot, and is the most straightforward way to filter.
*/
public function toSimpleObject()
{
$object = new \stdClass();
// Process all other data.
foreach ($this->modelData as $key => $val) {
$result = $this->getSimpleValue($val);
if ($result !== null) {
$object->{$key} = $this->nullPlaceholderCheck($result);
}
}
// Process all public properties.
$reflect = new \ReflectionObject($this);
$props = $reflect->getProperties(\ReflectionProperty::IS_PUBLIC);
foreach ($props as $member) {
$name = $member->getName();
$result = $this->getSimpleValue($this->{$name});
if ($result !== null) {
$name = $this->getMappedName($name);
$object->{$name} = $this->nullPlaceholderCheck($result);
}
}
return $object;
}
/**
* Handle different types of values, primarily
* other objects and map and array data types.
*/
private function getSimpleValue($value)
{
if ($value instanceof \Google\Site_Kit_Dependencies\Google\Model) {
return $value->toSimpleObject();
} elseif (\is_array($value)) {
$return = [];
foreach ($value as $key => $a_value) {
$a_value = $this->getSimpleValue($a_value);
if ($a_value !== null) {
$key = $this->getMappedName($key);
$return[$key] = $this->nullPlaceholderCheck($a_value);
}
}
return $return;
}
return $value;
}
/**
* Check whether the value is the null placeholder and return true null.
*/
private function nullPlaceholderCheck($value)
{
if ($value === self::NULL_VALUE) {
return null;
}
return $value;
}
/**
* If there is an internal name mapping, use that.
*/
private function getMappedName($key)
{
if (isset($this->internal_gapi_mappings, $this->internal_gapi_mappings[$key])) {
$key = $this->internal_gapi_mappings[$key];
}
return $key;
}
/**
* Returns true only if the array is associative.
* @param array $array
* @return bool True if the array is associative.
*/
protected function isAssociativeArray($array)
{
if (!\is_array($array)) {
return \false;
}
$keys = \array_keys($array);
foreach ($keys as $key) {
if (\is_string($key)) {
return \true;
}
}
return \false;
}
/**
* Verify if $obj is an array.
* @throws \Google\Exception Thrown if $obj isn't an array.
* @param array $obj Items that should be validated.
* @param string $method Method expecting an array as an argument.
*/
public function assertIsArray($obj, $method)
{
if ($obj && !\is_array($obj)) {
throw new \Google\Site_Kit_Dependencies\Google\Exception("Incorrect parameter type passed to {$method}(). Expected an array.");
}
}
/** @return bool */
#[\ReturnTypeWillChange]
public function offsetExists($offset)
{
return isset($this->{$offset}) || isset($this->modelData[$offset]);
}
/** @return mixed */
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
return isset($this->{$offset}) ? $this->{$offset} : $this->__get($offset);
}
/** @return void */
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
if (\property_exists($this, $offset)) {
$this->{$offset} = $value;
} else {
$this->modelData[$offset] = $value;
$this->processed[$offset] = \true;
}
}
/** @return void */
#[\ReturnTypeWillChange]
public function offsetUnset($offset)
{
unset($this->modelData[$offset]);
}
protected function keyType($key)
{
$keyType = $key . "Type";
// ensure keyType is a valid class
if (\property_exists($this, $keyType) && $this->{$keyType} !== null && \class_exists($this->{$keyType})) {
return $this->{$keyType};
}
}
protected function dataType($key)
{
$dataType = $key . "DataType";
if (\property_exists($this, $dataType)) {
return $this->{$dataType};
}
}
public function __isset($key)
{
return isset($this->modelData[$key]);
}
public function __unset($key)
{
unset($this->modelData[$key]);
}
/**
* Convert a string to camelCase
* @param string $value
* @return string
*/
private function camelCase($value)
{
$value = \ucwords(\str_replace(['-', '_'], ' ', $value));
$value = \str_replace(' ', '', $value);
$value[0] = \strtolower($value[0]);
return $value;
}
}

View File

@@ -0,0 +1,67 @@
<?php
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Google\Site_Kit_Dependencies\Google;
use Google\Site_Kit_Dependencies\Google\Http\Batch;
use TypeError;
class Service
{
public $batchPath;
/**
* Only used in getBatch
*/
public $rootUrl;
public $rootUrlTemplate;
public $version;
public $servicePath;
public $serviceName;
public $availableScopes;
public $resource;
private $client;
public function __construct($clientOrConfig = [])
{
if ($clientOrConfig instanceof \Google\Site_Kit_Dependencies\Google\Client) {
$this->client = $clientOrConfig;
} elseif (\is_array($clientOrConfig)) {
$this->client = new \Google\Site_Kit_Dependencies\Google\Client($clientOrConfig ?: []);
} else {
$errorMessage = 'Google\\Site_Kit_Dependencies\\constructor must be array or instance of Google\\Client';
if (\class_exists('TypeError')) {
throw new \TypeError($errorMessage);
}
\trigger_error($errorMessage, \E_USER_ERROR);
}
}
/**
* Return the associated Google\Client class.
* @return \Google\Client
*/
public function getClient()
{
return $this->client;
}
/**
* Create a new HTTP Batch handler for this service
*
* @return Batch
*/
public function createBatch()
{
return new \Google\Site_Kit_Dependencies\Google\Http\Batch($this->client, \false, $this->rootUrlTemplate ?? $this->rootUrl, $this->batchPath);
}
}

View File

@@ -0,0 +1,65 @@
<?php
/*
* Copyright 2014 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Google\Site_Kit_Dependencies\Google\Service;
use Google\Site_Kit_Dependencies\Google\Exception as GoogleException;
class Exception extends \Google\Site_Kit_Dependencies\Google\Exception
{
/**
* Optional list of errors returned in a JSON body of an HTTP error response.
*/
protected $errors = [];
/**
* Override default constructor to add the ability to set $errors and a retry
* map.
*
* @param string $message
* @param int $code
* @param Exception|null $previous
* @param array<array<string,string>>|null $errors List of errors returned in an HTTP
* response or null. Defaults to [].
*/
public function __construct($message, $code = 0, ?\Google\Site_Kit_Dependencies\Google\Service\Exception $previous = null, $errors = [])
{
if (\version_compare(\PHP_VERSION, '5.3.0') >= 0) {
parent::__construct($message, $code, $previous);
} else {
parent::__construct($message, $code);
}
$this->errors = $errors;
}
/**
* An example of the possible errors returned.
*
* [
* {
* "domain": "global",
* "reason": "authError",
* "message": "Invalid Credentials",
* "locationType": "header",
* "location": "Authorization",
* }
* ]
*
* @return array<array<string,string>>|null List of errors returned in an HTTP response or null.
*/
public function getErrors()
{
return $this->errors;
}
}

View File

@@ -0,0 +1,216 @@
<?php
/**
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Google\Site_Kit_Dependencies\Google\Service;
use Google\Site_Kit_Dependencies\Google\Exception as GoogleException;
use Google\Site_Kit_Dependencies\Google\Http\MediaFileUpload;
use Google\Site_Kit_Dependencies\Google\Model;
use Google\Site_Kit_Dependencies\Google\Utils\UriTemplate;
use Google\Site_Kit_Dependencies\GuzzleHttp\Psr7\Request;
/**
* Implements the actual methods/resources of the discovered Google API using magic function
* calling overloading (__call()), which on call will see if the method name (plus.activities.list)
* is available in this service, and if so construct an apiHttpRequest representing it.
*
*/
class Resource
{
// Valid query parameters that work, but don't appear in discovery.
private $stackParameters = ['alt' => ['type' => 'string', 'location' => 'query'], 'fields' => ['type' => 'string', 'location' => 'query'], 'trace' => ['type' => 'string', 'location' => 'query'], 'userIp' => ['type' => 'string', 'location' => 'query'], 'quotaUser' => ['type' => 'string', 'location' => 'query'], 'data' => ['type' => 'string', 'location' => 'body'], 'mimeType' => ['type' => 'string', 'location' => 'header'], 'uploadType' => ['type' => 'string', 'location' => 'query'], 'mediaUpload' => ['type' => 'complex', 'location' => 'query'], 'prettyPrint' => ['type' => 'string', 'location' => 'query']];
/** @var string $rootUrlTemplate */
private $rootUrlTemplate;
/** @var \Google\Client $client */
private $client;
/** @var string $serviceName */
private $serviceName;
/** @var string $servicePath */
private $servicePath;
/** @var string $resourceName */
private $resourceName;
/** @var array $methods */
private $methods;
public function __construct($service, $serviceName, $resourceName, $resource)
{
$this->rootUrlTemplate = $service->rootUrlTemplate ?? $service->rootUrl;
$this->client = $service->getClient();
$this->servicePath = $service->servicePath;
$this->serviceName = $serviceName;
$this->resourceName = $resourceName;
$this->methods = \is_array($resource) && isset($resource['methods']) ? $resource['methods'] : [$resourceName => $resource];
}
/**
* TODO: This function needs simplifying.
*
* @template T
* @param string $name
* @param array $arguments
* @param class-string<T> $expectedClass - optional, the expected class name
* @return mixed|T|ResponseInterface|RequestInterface
* @throws \Google\Exception
*/
public function call($name, $arguments, $expectedClass = null)
{
if (!isset($this->methods[$name])) {
$this->client->getLogger()->error('Service method unknown', ['service' => $this->serviceName, 'resource' => $this->resourceName, 'method' => $name]);
throw new \Google\Site_Kit_Dependencies\Google\Exception("Unknown function: " . "{$this->serviceName}->{$this->resourceName}->{$name}()");
}
$method = $this->methods[$name];
$parameters = $arguments[0];
// postBody is a special case since it's not defined in the discovery
// document as parameter, but we abuse the param entry for storing it.
$postBody = null;
if (isset($parameters['postBody'])) {
if ($parameters['postBody'] instanceof \Google\Site_Kit_Dependencies\Google\Model) {
// In the cases the post body is an existing object, we want
// to use the smart method to create a simple object for
// for JSONification.
$parameters['postBody'] = $parameters['postBody']->toSimpleObject();
} elseif (\is_object($parameters['postBody'])) {
// If the post body is another kind of object, we will try and
// wrangle it into a sensible format.
$parameters['postBody'] = $this->convertToArrayAndStripNulls($parameters['postBody']);
}
$postBody = (array) $parameters['postBody'];
unset($parameters['postBody']);
}
// TODO: optParams here probably should have been
// handled already - this may well be redundant code.
if (isset($parameters['optParams'])) {
$optParams = $parameters['optParams'];
unset($parameters['optParams']);
$parameters = \array_merge($parameters, $optParams);
}
if (!isset($method['parameters'])) {
$method['parameters'] = [];
}
$method['parameters'] = \array_merge($this->stackParameters, $method['parameters']);
foreach ($parameters as $key => $val) {
if ($key != 'postBody' && !isset($method['parameters'][$key])) {
$this->client->getLogger()->error('Service parameter unknown', ['service' => $this->serviceName, 'resource' => $this->resourceName, 'method' => $name, 'parameter' => $key]);
throw new \Google\Site_Kit_Dependencies\Google\Exception("({$name}) unknown parameter: '{$key}'");
}
}
foreach ($method['parameters'] as $paramName => $paramSpec) {
if (isset($paramSpec['required']) && $paramSpec['required'] && !isset($parameters[$paramName])) {
$this->client->getLogger()->error('Service parameter missing', ['service' => $this->serviceName, 'resource' => $this->resourceName, 'method' => $name, 'parameter' => $paramName]);
throw new \Google\Site_Kit_Dependencies\Google\Exception("({$name}) missing required param: '{$paramName}'");
}
if (isset($parameters[$paramName])) {
$value = $parameters[$paramName];
$parameters[$paramName] = $paramSpec;
$parameters[$paramName]['value'] = $value;
unset($parameters[$paramName]['required']);
} else {
// Ensure we don't pass nulls.
unset($parameters[$paramName]);
}
}
$this->client->getLogger()->info('Service Call', ['service' => $this->serviceName, 'resource' => $this->resourceName, 'method' => $name, 'arguments' => $parameters]);
// build the service uri
$url = $this->createRequestUri($method['path'], $parameters);
// NOTE: because we're creating the request by hand,
// and because the service has a rootUrl property
// the "base_uri" of the Http Client is not accounted for
$request = new \Google\Site_Kit_Dependencies\GuzzleHttp\Psr7\Request($method['httpMethod'], $url, $postBody ? ['content-type' => 'application/json'] : [], $postBody ? \json_encode($postBody) : '');
// support uploads
if (isset($parameters['data'])) {
$mimeType = isset($parameters['mimeType']) ? $parameters['mimeType']['value'] : 'application/octet-stream';
$data = $parameters['data']['value'];
$upload = new \Google\Site_Kit_Dependencies\Google\Http\MediaFileUpload($this->client, $request, $mimeType, $data);
// pull down the modified request
$request = $upload->getRequest();
}
// if this is a media type, we will return the raw response
// rather than using an expected class
if (isset($parameters['alt']) && $parameters['alt']['value'] == 'media') {
$expectedClass = null;
}
// if the client is marked for deferring, rather than
// execute the request, return the response
if ($this->client->shouldDefer()) {
// @TODO find a better way to do this
$request = $request->withHeader('X-Php-Expected-Class', $expectedClass);
return $request;
}
return $this->client->execute($request, $expectedClass);
}
protected function convertToArrayAndStripNulls($o)
{
$o = (array) $o;
foreach ($o as $k => $v) {
if ($v === null) {
unset($o[$k]);
} elseif (\is_object($v) || \is_array($v)) {
$o[$k] = $this->convertToArrayAndStripNulls($o[$k]);
}
}
return $o;
}
/**
* Parse/expand request parameters and create a fully qualified
* request uri.
* @static
* @param string $restPath
* @param array $params
* @return string $requestUrl
*/
public function createRequestUri($restPath, $params)
{
// Override the default servicePath address if the $restPath use a /
if ('/' == \substr($restPath, 0, 1)) {
$requestUrl = \substr($restPath, 1);
} else {
$requestUrl = $this->servicePath . $restPath;
}
if ($this->rootUrlTemplate) {
// code for universe domain
$rootUrl = \str_replace('UNIVERSE_DOMAIN', $this->client->getUniverseDomain(), $this->rootUrlTemplate);
// code for leading slash
if ('/' !== \substr($rootUrl, -1) && '/' !== \substr($requestUrl, 0, 1)) {
$requestUrl = '/' . $requestUrl;
}
$requestUrl = $rootUrl . $requestUrl;
}
$uriTemplateVars = [];
$queryVars = [];
foreach ($params as $paramName => $paramSpec) {
if ($paramSpec['type'] == 'boolean') {
$paramSpec['value'] = $paramSpec['value'] ? 'true' : 'false';
}
if ($paramSpec['location'] == 'path') {
$uriTemplateVars[$paramName] = $paramSpec['value'];
} elseif ($paramSpec['location'] == 'query') {
if (\is_array($paramSpec['value'])) {
foreach ($paramSpec['value'] as $value) {
$queryVars[] = $paramName . '=' . \rawurlencode(\rawurldecode($value));
}
} else {
$queryVars[] = $paramName . '=' . \rawurlencode(\rawurldecode($paramSpec['value']));
}
}
}
if (\count($uriTemplateVars)) {
$uriTemplateParser = new \Google\Site_Kit_Dependencies\Google\Utils\UriTemplate();
$requestUrl = $uriTemplateParser->parse($requestUrl, $uriTemplateVars);
}
if (\count($queryVars)) {
$requestUrl .= '?' . \implode('&', $queryVars);
}
return $requestUrl;
}
}

View File

@@ -0,0 +1,77 @@
<?php
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
namespace Google\Site_Kit_Dependencies\Google\Task;
use Google\Site_Kit_Dependencies\Composer\Script\Event;
use InvalidArgumentException;
use Google\Site_Kit_Dependencies\Symfony\Component\Filesystem\Filesystem;
use Google\Site_Kit_Dependencies\Symfony\Component\Finder\Finder;
class Composer
{
/**
* @param Event $event Composer event passed in for any script method
* @param Filesystem $filesystem Optional. Used for testing.
*/
public static function cleanup(\Google\Site_Kit_Dependencies\Composer\Script\Event $event, ?\Google\Site_Kit_Dependencies\Symfony\Component\Filesystem\Filesystem $filesystem = null)
{
$composer = $event->getComposer();
$extra = $composer->getPackage()->getExtra();
$servicesToKeep = isset($extra['google/apiclient-services']) ? $extra['google/apiclient-services'] : [];
if ($servicesToKeep) {
$vendorDir = $composer->getConfig()->get('vendor-dir');
$serviceDir = \sprintf('%s/google/apiclient-services/src/Google/Service', $vendorDir);
if (!\is_dir($serviceDir)) {
// path for google/apiclient-services >= 0.200.0
$serviceDir = \sprintf('%s/google/apiclient-services/src', $vendorDir);
}
self::verifyServicesToKeep($serviceDir, $servicesToKeep);
$finder = self::getServicesToRemove($serviceDir, $servicesToKeep);
$filesystem = $filesystem ?: new \Google\Site_Kit_Dependencies\Symfony\Component\Filesystem\Filesystem();
if (0 !== ($count = \count($finder))) {
$event->getIO()->write(\sprintf('Removing %s google services', $count));
foreach ($finder as $file) {
$realpath = $file->getRealPath();
$filesystem->remove($realpath);
$filesystem->remove($realpath . '.php');
}
}
}
}
/**
* @throws InvalidArgumentException when the service doesn't exist
*/
private static function verifyServicesToKeep($serviceDir, array $servicesToKeep)
{
$finder = (new \Google\Site_Kit_Dependencies\Symfony\Component\Finder\Finder())->directories()->depth('== 0');
foreach ($servicesToKeep as $service) {
if (!\preg_match('/^[a-zA-Z0-9]*$/', $service)) {
throw new \InvalidArgumentException(\sprintf('Invalid Google service name "%s"', $service));
}
try {
$finder->in($serviceDir . '/' . $service);
} catch (\InvalidArgumentException $e) {
throw new \InvalidArgumentException(\sprintf('Google service "%s" does not exist or was removed previously', $service));
}
}
}
private static function getServicesToRemove($serviceDir, array $servicesToKeep)
{
// find all files in the current directory
return (new \Google\Site_Kit_Dependencies\Symfony\Component\Finder\Finder())->directories()->depth('== 0')->in($serviceDir)->exclude($servicesToKeep);
}
}

View File

@@ -0,0 +1,23 @@
<?php
/*
* Copyright 2014 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Google\Site_Kit_Dependencies\Google\Task;
use Google\Site_Kit_Dependencies\Google\Exception as GoogleException;
class Exception extends \Google\Site_Kit_Dependencies\Google\Exception
{
}

View File

@@ -0,0 +1,26 @@
<?php
/*
* Copyright 2014 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Google\Site_Kit_Dependencies\Google\Task;
/**
* Interface for checking how many times a given task can be retried following
* a failure.
*/
interface Retryable
{
}

View File

@@ -0,0 +1,235 @@
<?php
/*
* Copyright 2014 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Google\Site_Kit_Dependencies\Google\Task;
use Google\Site_Kit_Dependencies\Google\Service\Exception as GoogleServiceException;
use Google\Site_Kit_Dependencies\Google\Task\Exception as GoogleTaskException;
/**
* A task runner with exponential backoff support.
*
* @see https://developers.google.com/drive/web/handle-errors#implementing_exponential_backoff
*/
class Runner
{
const TASK_RETRY_NEVER = 0;
const TASK_RETRY_ONCE = 1;
const TASK_RETRY_ALWAYS = -1;
/**
* @var integer $maxDelay The max time (in seconds) to wait before a retry.
*/
private $maxDelay = 60;
/**
* @var integer $delay The previous delay from which the next is calculated.
*/
private $delay = 1;
/**
* @var integer $factor The base number for the exponential back off.
*/
private $factor = 2;
/**
* @var float $jitter A random number between -$jitter and $jitter will be
* added to $factor on each iteration to allow for a better distribution of
* retries.
*/
private $jitter = 0.5;
/**
* @var integer $attempts The number of attempts that have been tried so far.
*/
private $attempts = 0;
/**
* @var integer $maxAttempts The max number of attempts allowed.
*/
private $maxAttempts = 1;
/**
* @var callable $action The task to run and possibly retry.
*/
private $action;
/**
* @var array $arguments The task arguments.
*/
private $arguments;
/**
* @var array $retryMap Map of errors with retry counts.
*/
protected $retryMap = [
'500' => self::TASK_RETRY_ALWAYS,
'503' => self::TASK_RETRY_ALWAYS,
'rateLimitExceeded' => self::TASK_RETRY_ALWAYS,
'userRateLimitExceeded' => self::TASK_RETRY_ALWAYS,
6 => self::TASK_RETRY_ALWAYS,
// CURLE_COULDNT_RESOLVE_HOST
7 => self::TASK_RETRY_ALWAYS,
// CURLE_COULDNT_CONNECT
28 => self::TASK_RETRY_ALWAYS,
// CURLE_OPERATION_TIMEOUTED
35 => self::TASK_RETRY_ALWAYS,
// CURLE_SSL_CONNECT_ERROR
52 => self::TASK_RETRY_ALWAYS,
// CURLE_GOT_NOTHING
'lighthouseError' => self::TASK_RETRY_NEVER,
];
/**
* Creates a new task runner with exponential backoff support.
*
* @param array $config The task runner config
* @param string $name The name of the current task (used for logging)
* @param callable $action The task to run and possibly retry
* @param array $arguments The task arguments
* @throws \Google\Task\Exception when misconfigured
*/
// @phpstan-ignore-next-line
public function __construct($config, $name, $action, array $arguments = [])
{
if (isset($config['initial_delay'])) {
if ($config['initial_delay'] < 0) {
throw new \Google\Site_Kit_Dependencies\Google\Task\Exception('Task configuration `initial_delay` must not be negative.');
}
$this->delay = $config['initial_delay'];
}
if (isset($config['max_delay'])) {
if ($config['max_delay'] <= 0) {
throw new \Google\Site_Kit_Dependencies\Google\Task\Exception('Task configuration `max_delay` must be greater than 0.');
}
$this->maxDelay = $config['max_delay'];
}
if (isset($config['factor'])) {
if ($config['factor'] <= 0) {
throw new \Google\Site_Kit_Dependencies\Google\Task\Exception('Task configuration `factor` must be greater than 0.');
}
$this->factor = $config['factor'];
}
if (isset($config['jitter'])) {
if ($config['jitter'] <= 0) {
throw new \Google\Site_Kit_Dependencies\Google\Task\Exception('Task configuration `jitter` must be greater than 0.');
}
$this->jitter = $config['jitter'];
}
if (isset($config['retries'])) {
if ($config['retries'] < 0) {
throw new \Google\Site_Kit_Dependencies\Google\Task\Exception('Task configuration `retries` must not be negative.');
}
$this->maxAttempts += $config['retries'];
}
if (!\is_callable($action)) {
throw new \Google\Site_Kit_Dependencies\Google\Task\Exception('Task argument `$action` must be a valid callable.');
}
$this->action = $action;
$this->arguments = $arguments;
}
/**
* Checks if a retry can be attempted.
*
* @return boolean
*/
public function canAttempt()
{
return $this->attempts < $this->maxAttempts;
}
/**
* Runs the task and (if applicable) automatically retries when errors occur.
*
* @return mixed
* @throws \Google\Service\Exception on failure when no retries are available.
*/
public function run()
{
while ($this->attempt()) {
try {
return \call_user_func_array($this->action, $this->arguments);
} catch (\Google\Site_Kit_Dependencies\Google\Service\Exception $exception) {
$allowedRetries = $this->allowedRetries($exception->getCode(), $exception->getErrors());
if (!$this->canAttempt() || !$allowedRetries) {
throw $exception;
}
if ($allowedRetries > 0) {
$this->maxAttempts = \min($this->maxAttempts, $this->attempts + $allowedRetries);
}
}
}
}
/**
* Runs a task once, if possible. This is useful for bypassing the `run()`
* loop.
*
* NOTE: If this is not the first attempt, this function will sleep in
* accordance to the backoff configurations before running the task.
*
* @return boolean
*/
public function attempt()
{
if (!$this->canAttempt()) {
return \false;
}
if ($this->attempts > 0) {
$this->backOff();
}
$this->attempts++;
return \true;
}
/**
* Sleeps in accordance to the backoff configurations.
*/
private function backOff()
{
$delay = $this->getDelay();
\usleep((int) ($delay * 1000000));
}
/**
* Gets the delay (in seconds) for the current backoff period.
*
* @return int
*/
private function getDelay()
{
$jitter = $this->getJitter();
$factor = $this->attempts > 1 ? $this->factor + $jitter : 1 + \abs($jitter);
return $this->delay = \min($this->maxDelay, $this->delay * $factor);
}
/**
* Gets the current jitter (random number between -$this->jitter and
* $this->jitter).
*
* @return float
*/
private function getJitter()
{
return $this->jitter * 2 * \mt_rand() / \mt_getrandmax() - $this->jitter;
}
/**
* Gets the number of times the associated task can be retried.
*
* NOTE: -1 is returned if the task can be retried indefinitely
*
* @return integer
*/
public function allowedRetries($code, $errors = [])
{
if (isset($this->retryMap[$code])) {
return $this->retryMap[$code];
}
if (!empty($errors) && isset($errors[0]['reason'], $this->retryMap[$errors[0]['reason']])) {
return $this->retryMap[$errors[0]['reason']];
}
return 0;
}
public function setRetryMap($retryMap)
{
$this->retryMap = $retryMap;
}
}

View File

@@ -0,0 +1,264 @@
<?php
/*
* Copyright 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Google\Site_Kit_Dependencies\Google\Utils;
/**
* Implementation of levels 1-3 of the URI Template spec.
* @see http://tools.ietf.org/html/rfc6570
*/
class UriTemplate
{
const TYPE_MAP = "1";
const TYPE_LIST = "2";
const TYPE_SCALAR = "4";
/**
* @var array $operators
* These are valid at the start of a template block to
* modify the way in which the variables inside are
* processed.
*/
private $operators = ["+" => "reserved", "/" => "segments", "." => "dotprefix", "#" => "fragment", ";" => "semicolon", "?" => "form", "&" => "continuation"];
/**
* @var array<string>
* These are the characters which should not be URL encoded in reserved
* strings.
*/
private $reserved = ["=", ",", "!", "@", "|", ":", "/", "?", "#", "[", "]", '$', "&", "'", "(", ")", "*", "+", ";"];
private $reservedEncoded = ["%3D", "%2C", "%21", "%40", "%7C", "%3A", "%2F", "%3F", "%23", "%5B", "%5D", "%24", "%26", "%27", "%28", "%29", "%2A", "%2B", "%3B"];
public function parse($string, array $parameters)
{
return $this->resolveNextSection($string, $parameters);
}
/**
* This function finds the first matching {...} block and
* executes the replacement. It then calls itself to find
* subsequent blocks, if any.
*/
private function resolveNextSection($string, $parameters)
{
$start = \strpos($string, "{");
if ($start === \false) {
return $string;
}
$end = \strpos($string, "}");
if ($end === \false) {
return $string;
}
$string = $this->replace($string, $start, $end, $parameters);
return $this->resolveNextSection($string, $parameters);
}
private function replace($string, $start, $end, $parameters)
{
// We know a data block will have {} round it, so we can strip that.
$data = \substr($string, $start + 1, $end - $start - 1);
// If the first character is one of the reserved operators, it effects
// the processing of the stream.
if (isset($this->operators[$data[0]])) {
$op = $this->operators[$data[0]];
$data = \substr($data, 1);
$prefix = "";
$prefix_on_missing = \false;
switch ($op) {
case "reserved":
// Reserved means certain characters should not be URL encoded
$data = $this->replaceVars($data, $parameters, ",", null, \true);
break;
case "fragment":
// Comma separated with fragment prefix. Bare values only.
$prefix = "#";
$prefix_on_missing = \true;
$data = $this->replaceVars($data, $parameters, ",", null, \true);
break;
case "segments":
// Slash separated data. Bare values only.
$prefix = "/";
$data = $this->replaceVars($data, $parameters, "/");
break;
case "dotprefix":
// Dot separated data. Bare values only.
$prefix = ".";
$prefix_on_missing = \true;
$data = $this->replaceVars($data, $parameters, ".");
break;
case "semicolon":
// Semicolon prefixed and separated. Uses the key name
$prefix = ";";
$data = $this->replaceVars($data, $parameters, ";", "=", \false, \true, \false);
break;
case "form":
// Standard URL format. Uses the key name
$prefix = "?";
$data = $this->replaceVars($data, $parameters, "&", "=");
break;
case "continuation":
// Standard URL, but with leading ampersand. Uses key name.
$prefix = "&";
$data = $this->replaceVars($data, $parameters, "&", "=");
break;
}
// Add the initial prefix character if data is valid.
if ($data || $data !== \false && $prefix_on_missing) {
$data = $prefix . $data;
}
} else {
// If no operator we replace with the defaults.
$data = $this->replaceVars($data, $parameters);
}
// This is chops out the {...} and replaces with the new section.
return \substr($string, 0, $start) . $data . \substr($string, $end + 1);
}
private function replaceVars($section, $parameters, $sep = ",", $combine = null, $reserved = \false, $tag_empty = \false, $combine_on_empty = \true)
{
if (\strpos($section, ",") === \false) {
// If we only have a single value, we can immediately process.
return $this->combine($section, $parameters, $sep, $combine, $reserved, $tag_empty, $combine_on_empty);
} else {
// If we have multiple values, we need to split and loop over them.
// Each is treated individually, then glued together with the
// separator character.
$vars = \explode(",", $section);
return $this->combineList(
$vars,
$sep,
$parameters,
$combine,
$reserved,
\false,
// Never emit empty strings in multi-param replacements
$combine_on_empty
);
}
}
public function combine($key, $parameters, $sep, $combine, $reserved, $tag_empty, $combine_on_empty)
{
$length = \false;
$explode = \false;
$skip_final_combine = \false;
$value = \false;
// Check for length restriction.
if (\strpos($key, ":") !== \false) {
list($key, $length) = \explode(":", $key);
}
// Check for explode parameter.
if ($key[\strlen($key) - 1] == "*") {
$explode = \true;
$key = \substr($key, 0, -1);
$skip_final_combine = \true;
}
// Define the list separator.
$list_sep = $explode ? $sep : ",";
if (isset($parameters[$key])) {
$data_type = $this->getDataType($parameters[$key]);
switch ($data_type) {
case self::TYPE_SCALAR:
$value = $this->getValue($parameters[$key], $length);
break;
case self::TYPE_LIST:
$values = [];
foreach ($parameters[$key] as $pkey => $pvalue) {
$pvalue = $this->getValue($pvalue, $length);
if ($combine && $explode) {
$values[$pkey] = $key . $combine . $pvalue;
} else {
$values[$pkey] = $pvalue;
}
}
$value = \implode($list_sep, $values);
if ($value == '') {
return '';
}
break;
case self::TYPE_MAP:
$values = [];
foreach ($parameters[$key] as $pkey => $pvalue) {
$pvalue = $this->getValue($pvalue, $length);
if ($explode) {
$pkey = $this->getValue($pkey, $length);
$values[] = $pkey . "=" . $pvalue;
// Explode triggers = combine.
} else {
$values[] = $pkey;
$values[] = $pvalue;
}
}
$value = \implode($list_sep, $values);
if ($value == '') {
return \false;
}
break;
}
} elseif ($tag_empty) {
// If we are just indicating empty values with their key name, return that.
return $key;
} else {
// Otherwise we can skip this variable due to not being defined.
return \false;
}
if ($reserved) {
$value = \str_replace($this->reservedEncoded, $this->reserved, $value);
}
// If we do not need to include the key name, we just return the raw
// value.
if (!$combine || $skip_final_combine) {
return $value;
}
// Else we combine the key name: foo=bar, if value is not the empty string.
return $key . ($value != '' || $combine_on_empty ? $combine . $value : '');
}
/**
* Return the type of a passed in value
*/
private function getDataType($data)
{
if (\is_array($data)) {
\reset($data);
if (\key($data) !== 0) {
return self::TYPE_MAP;
}
return self::TYPE_LIST;
}
return self::TYPE_SCALAR;
}
/**
* Utility function that merges multiple combine calls
* for multi-key templates.
*/
private function combineList($vars, $sep, $parameters, $combine, $reserved, $tag_empty, $combine_on_empty)
{
$ret = [];
foreach ($vars as $var) {
$response = $this->combine($var, $parameters, $sep, $combine, $reserved, $tag_empty, $combine_on_empty);
if ($response === \false) {
continue;
}
$ret[] = $response;
}
return \implode($sep, $ret);
}
/**
* Utility function to encode and trim values
*/
private function getValue($value, $length)
{
if ($length) {
$value = \substr($value, 0, $length);
}
$value = \rawurlencode($value);
return $value;
}
}

View File

@@ -0,0 +1,80 @@
<?php
namespace Google\Site_Kit_Dependencies;
if (\class_exists('Google\\Site_Kit_Dependencies\\Google_Client', \false)) {
// Prevent error with preloading in PHP 7.4
// @see https://github.com/googleapis/google-api-php-client/issues/1976
return;
}
$classMap = ['Google\\Site_Kit_Dependencies\\Google\\Client' => 'Google\Site_Kit_Dependencies\Google_Client', 'Google\\Site_Kit_Dependencies\\Google\\Service' => 'Google\Site_Kit_Dependencies\Google_Service', 'Google\\Site_Kit_Dependencies\\Google\\AccessToken\\Revoke' => 'Google\Site_Kit_Dependencies\Google_AccessToken_Revoke', 'Google\\Site_Kit_Dependencies\\Google\\AccessToken\\Verify' => 'Google\Site_Kit_Dependencies\Google_AccessToken_Verify', 'Google\\Site_Kit_Dependencies\\Google\\Model' => 'Google\Site_Kit_Dependencies\Google_Model', 'Google\\Site_Kit_Dependencies\\Google\\Utils\\UriTemplate' => 'Google\Site_Kit_Dependencies\Google_Utils_UriTemplate', 'Google\\Site_Kit_Dependencies\\Google\\AuthHandler\\Guzzle6AuthHandler' => 'Google\Site_Kit_Dependencies\Google_AuthHandler_Guzzle6AuthHandler', 'Google\\Site_Kit_Dependencies\\Google\\AuthHandler\\Guzzle7AuthHandler' => 'Google\Site_Kit_Dependencies\Google_AuthHandler_Guzzle7AuthHandler', 'Google\\Site_Kit_Dependencies\\Google\\AuthHandler\\AuthHandlerFactory' => 'Google\Site_Kit_Dependencies\Google_AuthHandler_AuthHandlerFactory', 'Google\\Site_Kit_Dependencies\\Google\\Http\\Batch' => 'Google\Site_Kit_Dependencies\Google_Http_Batch', 'Google\\Site_Kit_Dependencies\\Google\\Http\\MediaFileUpload' => 'Google\Site_Kit_Dependencies\Google_Http_MediaFileUpload', 'Google\\Site_Kit_Dependencies\\Google\\Http\\REST' => 'Google\Site_Kit_Dependencies\Google_Http_REST', 'Google\\Site_Kit_Dependencies\\Google\\Task\\Retryable' => 'Google\Site_Kit_Dependencies\Google_Task_Retryable', 'Google\\Site_Kit_Dependencies\\Google\\Task\\Exception' => 'Google\Site_Kit_Dependencies\Google_Task_Exception', 'Google\\Site_Kit_Dependencies\\Google\\Task\\Runner' => 'Google\Site_Kit_Dependencies\Google_Task_Runner', 'Google\\Site_Kit_Dependencies\\Google\\Collection' => 'Google\Site_Kit_Dependencies\Google_Collection', 'Google\\Site_Kit_Dependencies\\Google\\Service\\Exception' => 'Google\Site_Kit_Dependencies\Google_Service_Exception', 'Google\\Site_Kit_Dependencies\\Google\\Service\\Resource' => 'Google\Site_Kit_Dependencies\Google_Service_Resource', 'Google\\Site_Kit_Dependencies\\Google\\Exception' => 'Google\Site_Kit_Dependencies\Google_Exception'];
foreach ($classMap as $class => $alias) {
\class_alias($class, $alias);
}
/**
* This class needs to be defined explicitly as scripts must be recognized by
* the autoloader.
*/
class Google_Task_Composer extends \Google\Site_Kit_Dependencies\Google\Task\Composer
{
}
/** @phpstan-ignore-next-line */
if (\false) {
class Google_AccessToken_Revoke extends \Google\Site_Kit_Dependencies\Google\AccessToken\Revoke
{
}
class Google_AccessToken_Verify extends \Google\Site_Kit_Dependencies\Google\AccessToken\Verify
{
}
class Google_AuthHandler_AuthHandlerFactory extends \Google\Site_Kit_Dependencies\Google\AuthHandler\AuthHandlerFactory
{
}
class Google_AuthHandler_Guzzle6AuthHandler extends \Google\Site_Kit_Dependencies\Google\AuthHandler\Guzzle6AuthHandler
{
}
class Google_AuthHandler_Guzzle7AuthHandler extends \Google\Site_Kit_Dependencies\Google\AuthHandler\Guzzle7AuthHandler
{
}
class Google_Client extends \Google\Site_Kit_Dependencies\Google\Client
{
}
class Google_Collection extends \Google\Site_Kit_Dependencies\Google\Collection
{
}
class Google_Exception extends \Google\Site_Kit_Dependencies\Google\Exception
{
}
class Google_Http_Batch extends \Google\Site_Kit_Dependencies\Google\Http\Batch
{
}
class Google_Http_MediaFileUpload extends \Google\Site_Kit_Dependencies\Google\Http\MediaFileUpload
{
}
class Google_Http_REST extends \Google\Site_Kit_Dependencies\Google\Http\REST
{
}
class Google_Model extends \Google\Site_Kit_Dependencies\Google\Model
{
}
class Google_Service extends \Google\Site_Kit_Dependencies\Google\Service
{
}
class Google_Service_Exception extends \Google\Site_Kit_Dependencies\Google\Service\Exception
{
}
class Google_Service_Resource extends \Google\Site_Kit_Dependencies\Google\Service\Resource
{
}
class Google_Task_Exception extends \Google\Site_Kit_Dependencies\Google\Task\Exception
{
}
interface Google_Task_Retryable extends \Google\Site_Kit_Dependencies\Google\Task\Retryable
{
}
class Google_Task_Runner extends \Google\Site_Kit_Dependencies\Google\Task\Runner
{
}
class Google_Utils_UriTemplate extends \Google\Site_Kit_Dependencies\Google\Utils\UriTemplate
{
}
}