menu - it will show our menu. about - it will show the 'about us'. contact- it will show 'contact info'. commands - it will show 'keyword'. how to order - it will show the instruction. location - it will show our address.";
9 | } else if (input == "menu") {
10 | return "Here's our menu:
menu - it will show our menu. about - it will show the 'about us'. contact- it will show 'contact info'. commands - it will show 'keyword'. how to order - it will show the instruction. location - it will show our address."
39 | document.getElementById("botStarterMessage").innerHTML = '
' + firstMessage + '
';
40 |
41 | let time = getTime();
42 |
43 | $("#chat-timestamp").append(time);
44 | document.getElementById("userInput").scrollIntoView(false);
45 | }
46 |
47 | firstBotMessage();
48 |
49 | // Retrieves the response
50 | function getHardResponse(userText) {
51 | let botResponse = getBotResponse(userText);
52 | let botHtml = '
' + botResponse + '
';
53 | $("#chatbox").append(botHtml);
54 |
55 | document.getElementById("chat-bar-bottom").scrollIntoView(true);
56 | }
57 |
58 | //Gets the text text from the input box and processes it
59 | function getResponse() {
60 | let userText = $("#textInput").val().toLowerCase();
61 |
62 | if (userText == "") {
63 | alert('Please enter something!');
64 | return;
65 | }
66 |
67 | let userHtml = '
34 | ";
35 | }
36 | } else {
37 | ?>
38 |
68 |
71 |
72 |
73 |
74 |
75 |
95 |
96 |
--------------------------------------------------------------------------------
/google-client/src/Http/REST.php:
--------------------------------------------------------------------------------
1 | |false|null $expectedClass
42 | * @param array $config
43 | * @param array $retryMap
44 | * @return mixed|T|null
45 | * @throws \Google\Service\Exception on server side error (ie: not authenticated,
46 | * invalid or malformed post body, invalid url)
47 | */
48 | public static function execute(
49 | ClientInterface $client,
50 | RequestInterface $request,
51 | $expectedClass = null,
52 | $config = [],
53 | $retryMap = null
54 | ) {
55 | $runner = new Runner(
56 | $config,
57 | sprintf('%s %s', $request->getMethod(), (string) $request->getUri()),
58 | [get_class(), 'doExecute'],
59 | [$client, $request, $expectedClass]
60 | );
61 |
62 | if (null !== $retryMap) {
63 | $runner->setRetryMap($retryMap);
64 | }
65 |
66 | return $runner->run();
67 | }
68 |
69 | /**
70 | * Executes a Psr\Http\Message\RequestInterface
71 | *
72 | * @template T
73 | * @param ClientInterface $client
74 | * @param RequestInterface $request
75 | * @param class-string|false|null $expectedClass
76 | * @return mixed|T|null
77 | * @throws \Google\Service\Exception on server side error (ie: not authenticated,
78 | * invalid or malformed post body, invalid url)
79 | */
80 | public static function doExecute(ClientInterface $client, RequestInterface $request, $expectedClass = null)
81 | {
82 | try {
83 | $httpHandler = HttpHandlerFactory::build($client);
84 | $response = $httpHandler($request);
85 | } catch (RequestException $e) {
86 | // if Guzzle throws an exception, catch it and handle the response
87 | if (!$e->hasResponse()) {
88 | throw $e;
89 | }
90 |
91 | $response = $e->getResponse();
92 | // specific checking for Guzzle 5: convert to PSR7 response
93 | if (
94 | interface_exists('\GuzzleHttp\Message\ResponseInterface')
95 | && $response instanceof \GuzzleHttp\Message\ResponseInterface
96 | ) {
97 | $response = new Response(
98 | $response->getStatusCode(),
99 | $response->getHeaders() ?: [],
100 | $response->getBody(),
101 | $response->getProtocolVersion(),
102 | $response->getReasonPhrase()
103 | );
104 | }
105 | }
106 |
107 | return self::decodeHttpResponse($response, $request, $expectedClass);
108 | }
109 |
110 | /**
111 | * Decode an HTTP Response.
112 | * @static
113 | *
114 | * @template T
115 | * @param RequestInterface $response The http response to be decoded.
116 | * @param ResponseInterface $response
117 | * @param class-string|false|null $expectedClass
118 | * @return mixed|T|null
119 | * @throws \Google\Service\Exception
120 | */
121 | public static function decodeHttpResponse(
122 | ResponseInterface $response,
123 | RequestInterface $request = null,
124 | $expectedClass = null
125 | ) {
126 | $code = $response->getStatusCode();
127 |
128 | // retry strategy
129 | if (intVal($code) >= 400) {
130 | // if we errored out, it should be safe to grab the response body
131 | $body = (string) $response->getBody();
132 |
133 | // Check if we received errors, and add those to the Exception for convenience
134 | throw new GoogleServiceException($body, $code, null, self::getResponseErrors($body));
135 | }
136 |
137 | // Ensure we only pull the entire body into memory if the request is not
138 | // of media type
139 | $body = self::decodeBody($response, $request);
140 |
141 | if ($expectedClass = self::determineExpectedClass($expectedClass, $request)) {
142 | $json = json_decode($body, true);
143 |
144 | return new $expectedClass($json);
145 | }
146 |
147 | return $response;
148 | }
149 |
150 | private static function decodeBody(ResponseInterface $response, RequestInterface $request = null)
151 | {
152 | if (self::isAltMedia($request)) {
153 | // don't decode the body, it's probably a really long string
154 | return '';
155 | }
156 |
157 | return (string) $response->getBody();
158 | }
159 |
160 | private static function determineExpectedClass($expectedClass, RequestInterface $request = null)
161 | {
162 | // "false" is used to explicitly prevent an expected class from being returned
163 | if (false === $expectedClass) {
164 | return null;
165 | }
166 |
167 | // if we don't have a request, we just use what's passed in
168 | if (null === $request) {
169 | return $expectedClass;
170 | }
171 |
172 | // return what we have in the request header if one was not supplied
173 | return $expectedClass ?: $request->getHeaderLine('X-Php-Expected-Class');
174 | }
175 |
176 | private static function getResponseErrors($body)
177 | {
178 | $json = json_decode($body, true);
179 |
180 | if (isset($json['error']['errors'])) {
181 | return $json['error']['errors'];
182 | }
183 |
184 | return null;
185 | }
186 |
187 | private static function isAltMedia(RequestInterface $request = null)
188 | {
189 | if ($request && $qs = $request->getUri()->getQuery()) {
190 | parse_str($qs, $query);
191 | if (isset($query['alt']) && $query['alt'] == 'media') {
192 | return true;
193 | }
194 | }
195 |
196 | return false;
197 | }
198 | }
199 |
--------------------------------------------------------------------------------
/DATABASE/google-api-php-client-main/src/Http/REST.php:
--------------------------------------------------------------------------------
1 | |false|null $expectedClass
42 | * @param array $config
43 | * @param array $retryMap
44 | * @return mixed|T|null
45 | * @throws \Google\Service\Exception on server side error (ie: not authenticated,
46 | * invalid or malformed post body, invalid url)
47 | */
48 | public static function execute(
49 | ClientInterface $client,
50 | RequestInterface $request,
51 | $expectedClass = null,
52 | $config = [],
53 | $retryMap = null
54 | ) {
55 | $runner = new Runner(
56 | $config,
57 | sprintf('%s %s', $request->getMethod(), (string) $request->getUri()),
58 | [get_class(), 'doExecute'],
59 | [$client, $request, $expectedClass]
60 | );
61 |
62 | if (null !== $retryMap) {
63 | $runner->setRetryMap($retryMap);
64 | }
65 |
66 | return $runner->run();
67 | }
68 |
69 | /**
70 | * Executes a Psr\Http\Message\RequestInterface
71 | *
72 | * @template T
73 | * @param ClientInterface $client
74 | * @param RequestInterface $request
75 | * @param class-string|false|null $expectedClass
76 | * @return mixed|T|null
77 | * @throws \Google\Service\Exception on server side error (ie: not authenticated,
78 | * invalid or malformed post body, invalid url)
79 | */
80 | public static function doExecute(ClientInterface $client, RequestInterface $request, $expectedClass = null)
81 | {
82 | try {
83 | $httpHandler = HttpHandlerFactory::build($client);
84 | $response = $httpHandler($request);
85 | } catch (RequestException $e) {
86 | // if Guzzle throws an exception, catch it and handle the response
87 | if (!$e->hasResponse()) {
88 | throw $e;
89 | }
90 |
91 | $response = $e->getResponse();
92 | // specific checking for Guzzle 5: convert to PSR7 response
93 | if (
94 | interface_exists('\GuzzleHttp\Message\ResponseInterface')
95 | && $response instanceof \GuzzleHttp\Message\ResponseInterface
96 | ) {
97 | $response = new Response(
98 | $response->getStatusCode(),
99 | $response->getHeaders() ?: [],
100 | $response->getBody(),
101 | $response->getProtocolVersion(),
102 | $response->getReasonPhrase()
103 | );
104 | }
105 | }
106 |
107 | return self::decodeHttpResponse($response, $request, $expectedClass);
108 | }
109 |
110 | /**
111 | * Decode an HTTP Response.
112 | * @static
113 | *
114 | * @template T
115 | * @param RequestInterface $response The http response to be decoded.
116 | * @param ResponseInterface $response
117 | * @param class-string|false|null $expectedClass
118 | * @return mixed|T|null
119 | * @throws \Google\Service\Exception
120 | */
121 | public static function decodeHttpResponse(
122 | ResponseInterface $response,
123 | RequestInterface $request = null,
124 | $expectedClass = null
125 | ) {
126 | $code = $response->getStatusCode();
127 |
128 | // retry strategy
129 | if (intVal($code) >= 400) {
130 | // if we errored out, it should be safe to grab the response body
131 | $body = (string) $response->getBody();
132 |
133 | // Check if we received errors, and add those to the Exception for convenience
134 | throw new GoogleServiceException($body, $code, null, self::getResponseErrors($body));
135 | }
136 |
137 | // Ensure we only pull the entire body into memory if the request is not
138 | // of media type
139 | $body = self::decodeBody($response, $request);
140 |
141 | if ($expectedClass = self::determineExpectedClass($expectedClass, $request)) {
142 | $json = json_decode($body, true);
143 |
144 | return new $expectedClass($json);
145 | }
146 |
147 | return $response;
148 | }
149 |
150 | private static function decodeBody(ResponseInterface $response, RequestInterface $request = null)
151 | {
152 | if (self::isAltMedia($request)) {
153 | // don't decode the body, it's probably a really long string
154 | return '';
155 | }
156 |
157 | return (string) $response->getBody();
158 | }
159 |
160 | private static function determineExpectedClass($expectedClass, RequestInterface $request = null)
161 | {
162 | // "false" is used to explicitly prevent an expected class from being returned
163 | if (false === $expectedClass) {
164 | return null;
165 | }
166 |
167 | // if we don't have a request, we just use what's passed in
168 | if (null === $request) {
169 | return $expectedClass;
170 | }
171 |
172 | // return what we have in the request header if one was not supplied
173 | return $expectedClass ?: $request->getHeaderLine('X-Php-Expected-Class');
174 | }
175 |
176 | private static function getResponseErrors($body)
177 | {
178 | $json = json_decode($body, true);
179 |
180 | if (isset($json['error']['errors'])) {
181 | return $json['error']['errors'];
182 | }
183 |
184 | return null;
185 | }
186 |
187 | private static function isAltMedia(RequestInterface $request = null)
188 | {
189 | if ($request && $qs = $request->getUri()->getQuery()) {
190 | parse_str($qs, $query);
191 | if (isset($query['alt']) && $query['alt'] == 'media') {
192 | return true;
193 | }
194 | }
195 |
196 | return false;
197 | }
198 | }
199 |
--------------------------------------------------------------------------------
/assets/js/script.js:
--------------------------------------------------------------------------------
1 | // Show Navbar when small screen || Close Cart Items & Search Textbox
2 | let navbar = document.querySelector('.navbar');
3 |
4 | document.querySelector('#menu-btn').onclick = () => {
5 | navbar.classList.toggle('active');
6 | cartItem.classList.remove('active');
7 | searchForm.classList.remove('active');
8 | }
9 |
10 | // Show Cart Items || Close Navbar & Search Textbox
11 | let cartItem = document.querySelector('.cart');
12 |
13 | document.querySelector('#cart-btn').onclick = () => {
14 | cartItem.classList.toggle('active');
15 | navbar.classList.remove('active');
16 | searchForm.classList.remove('active');
17 | }
18 |
19 | // Show Search Textbox || Close Navbar & Cart Items
20 | let searchForm = document.querySelector('.search-form');
21 |
22 | document.querySelector('#search-btn').onclick = () => {
23 | searchForm.classList.toggle('active');
24 | navbar.classList.remove('active');
25 | cartItem.classList.remove('active');
26 | }
27 |
28 | // Remove Active Icons on Scroll and Close it
29 | window.onscroll = () => {
30 | navbar.classList.remove('active');
31 | cartItem.classList.remove('active');
32 | searchForm.classList.remove('active');
33 | }
34 |
35 | // Script for making icon as button
36 | document.getElementById('paper-plane-icon').addEventListener('click', function() {
37 | // Add your desired action here, e.g. submit form, trigger AJAX request, etc.
38 | alert('Paper airplane clicked!');
39 | });
40 |
41 |
42 | //Cart Working JS
43 | if (document.readyState == 'loading') {
44 | document.addEventListener("DOMContentLoaded", ready);
45 | } else {
46 | ready();
47 | }
48 |
49 | // FUNCTIONS FOR CART
50 | function ready() {
51 | //Remove Items from Cart
52 | var removeCartButtons = document.getElementsByClassName('cart-remove');
53 | console.log(removeCartButtons);
54 | for (var i = 0; i < removeCartButtons.length; i++){
55 | var button = removeCartButtons[i];
56 | button.addEventListener('click', removeCartItem);
57 | }
58 |
59 | // When quantity changes
60 | var quantityInputs = document.getElementsByClassName("cart-quantity");
61 | for (var i = 0; i < quantityInputs.length; i++){
62 | var input = quantityInputs[i];
63 | input.addEventListener("change", quantityChanged);
64 | }
65 |
66 | // Add to Cart
67 | var addCart = document.getElementsByClassName('add-cart');
68 | for (var i = 0; i < addCart.length; i++){
69 | var button = addCart[i];
70 | button.addEventListener("click", addCartClicked);
71 | }
72 |
73 | // Buy Button Works
74 | document.getElementsByClassName("btn-buy")[0].addEventListener("click", buyButtonClicked);
75 | }
76 |
77 | // Function for "Buy Button Works"
78 | function buyButtonClicked() {
79 | alert('Your order is placed! Thank you for buying and enjoy your coffee!');
80 | var cartContent = document.getElementsByClassName("cart-content")[0];
81 | var cartBoxes = cartContent.getElementsByClassName("cart-box");
82 | var orderDetails = [];
83 |
84 | // Generate invoice number
85 | var invoiceNumber = generateInvoiceNumber();
86 |
87 | // Loop through all cart boxes to get details
88 | for (var i = 0; i < cartBoxes.length; i++) {
89 | var cartBox = cartBoxes[i];
90 | var title = cartBox.getElementsByClassName("cart-product-title")[0].innerText;
91 | var price = cartBox.getElementsByClassName("cart-price")[0].innerText;
92 | var quantity = cartBox.getElementsByClassName("cart-quantity")[0].value;
93 | var priceValue = parseFloat(price.replace('₱', '').replace(',', ''));
94 | var subtotalAmount = priceValue * quantity;
95 | orderDetails.push({ title: title, price: priceValue, quantity: quantity, subtotal_amount: subtotalAmount, invoice_number: invoiceNumber });
96 | }
97 |
98 | //Send data to server using AJAX
99 | var xhr = new XMLHttpRequest();
100 | xhr.open("POST", "add_to_database.php", true);
101 | xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
102 | xhr.onreadystatechange = function() {
103 | if (xhr.readyState === 4 && xhr.status === 200) {
104 | console.log(xhr.responseText);
105 | }
106 | };
107 | xhr.send(JSON.stringify(orderDetails));
108 | cartItem.classList.remove('active');
109 |
110 | // Clear cart after sending data to server
111 | while (cartContent.hasChildNodes()) {
112 | cartContent.removeChild(cartContent.firstChild);
113 | }
114 | updateTotal();
115 | }
116 |
117 | // Function to generate invoice number
118 | function generateInvoiceNumber() {
119 | // Implement your logic to generate an invoice number here
120 | return "INV-" + Math.floor(Math.random() * 1000000);
121 | }
122 |
123 | // Function for "Remove Items from Cart"
124 | function removeCartItem(event) {
125 | var buttonClicked = event.target;
126 | buttonClicked.parentElement.remove();
127 | updateTotal();
128 | }
129 |
130 | // Function for "When quantity changes"
131 | function quantityChanged(event) {
132 | var input = event.target;
133 | if (isNaN(input.value) || input.value <= 0) {
134 | input.value = 1;
135 | }
136 | updateTotal();
137 | }
138 |
139 | //Add to Cart
140 | function addCartClicked(event) {
141 | var button = event.target;
142 | var shopProducts = button.parentElement;
143 | var title = shopProducts.getElementsByClassName("product-title")[0].innerText;
144 | var price = shopProducts.getElementsByClassName("price")[0].innerText;
145 | var productImg = shopProducts.getElementsByClassName("product-img")[0].src;
146 | addProductToCart(title, price, productImg);
147 | updateTotal();
148 | }
149 |
150 | function addProductToCart(title, price, productImg) {
151 | var cartShopBox = document.createElement("div");
152 | cartShopBox.classList.add("cart-box");
153 | var cartItems = document.getElementsByClassName("cart-content")[0];
154 | var cartItemsNames = cartItems.getElementsByClassName("cart-product-title");
155 | for (var i = 0; i < cartItemsNames.length; i++) {
156 | if (cartItemsNames[i].innerText == title) {
157 | alert("You have already added this item to cart!")
158 | return;
159 | }
160 | }
161 | var cartBoxContent = `
162 |
163 |
164 |
${title}
165 |
${price}
166 |
167 |
168 |
169 | `;
170 | cartShopBox.innerHTML = cartBoxContent;
171 | cartItems.append(cartShopBox);
172 | cartShopBox
173 | .getElementsByClassName("cart-remove")[0]
174 | .addEventListener('click', removeCartItem);
175 | cartShopBox
176 | .getElementsByClassName("cart-quantity")[0]
177 | .addEventListener('change', quantityChanged);
178 |
179 | }
180 |
181 | // Update Total
182 | function updateTotal() {
183 | var cartContent = document.getElementsByClassName("cart-content")[0];
184 | var cartBoxes = cartContent.getElementsByClassName("cart-box");
185 | var total = 0;
186 | for (var i = 0; i < cartBoxes.length; i++) {
187 | var cartBox = cartBoxes[i];
188 | var priceElement = cartBox.getElementsByClassName("cart-price")[0];
189 | var quantityElement = cartBox.getElementsByClassName("cart-quantity")[0];
190 | var price = parseFloat(priceElement.innerText.replace("₱", ""));
191 | var quantity = quantityElement.value;
192 | total = total + (price * quantity);
193 | }
194 | total = Math.round(total * 100) / 100;
195 |
196 | document.getElementsByClassName("total-price")[0].innerText = "₱" + total;
197 | }
--------------------------------------------------------------------------------
/google-client/src/Http/Batch.php:
--------------------------------------------------------------------------------
1 | client = $client;
64 | $this->boundary = $boundary ?: mt_rand();
65 | $this->rootUrl = rtrim($rootUrl ?: $this->client->getConfig('base_path'), '/');
66 | $this->batchPath = $batchPath ?: self::BATCH_PATH;
67 | }
68 |
69 | public function add(RequestInterface $request, $key = false)
70 | {
71 | if (false == $key) {
72 | $key = mt_rand();
73 | }
74 |
75 | $this->requests[$key] = $request;
76 | }
77 |
78 | public function execute()
79 | {
80 | $body = '';
81 | $classes = [];
82 | $batchHttpTemplate = <<requests as $key => $request) {
97 | $firstLine = sprintf(
98 | '%s %s HTTP/%s',
99 | $request->getMethod(),
100 | $request->getRequestTarget(),
101 | $request->getProtocolVersion()
102 | );
103 |
104 | $content = (string) $request->getBody();
105 |
106 | $headers = '';
107 | foreach ($request->getHeaders() as $name => $values) {
108 | $headers .= sprintf("%s:%s\r\n", $name, implode(', ', $values));
109 | }
110 |
111 | $body .= sprintf(
112 | $batchHttpTemplate,
113 | $this->boundary,
114 | $key,
115 | $firstLine,
116 | $headers,
117 | $content ? "\n" . $content : ''
118 | );
119 |
120 | $classes['response-' . $key] = $request->getHeaderLine('X-Php-Expected-Class');
121 | }
122 |
123 | $body .= "--{$this->boundary}--";
124 | $body = trim($body);
125 | $url = $this->rootUrl . '/' . $this->batchPath;
126 | $headers = [
127 | 'Content-Type' => sprintf('multipart/mixed; boundary=%s', $this->boundary),
128 | 'Content-Length' => (string) strlen($body),
129 | ];
130 |
131 | $request = new Request(
132 | 'POST',
133 | $url,
134 | $headers,
135 | $body
136 | );
137 |
138 | $response = $this->client->execute($request);
139 |
140 | return $this->parseResponse($response, $classes);
141 | }
142 |
143 | public function parseResponse(ResponseInterface $response, $classes = [])
144 | {
145 | $contentType = $response->getHeaderLine('content-type');
146 | $contentType = explode(';', $contentType);
147 | $boundary = false;
148 | foreach ($contentType as $part) {
149 | $part = explode('=', $part, 2);
150 | if (isset($part[0]) && 'boundary' == trim($part[0])) {
151 | $boundary = $part[1];
152 | }
153 | }
154 |
155 | $body = (string) $response->getBody();
156 | if (!empty($body)) {
157 | $body = str_replace("--$boundary--", "--$boundary", $body);
158 | $parts = explode("--$boundary", $body);
159 | $responses = [];
160 | $requests = array_values($this->requests);
161 |
162 | foreach ($parts as $i => $part) {
163 | $part = trim($part);
164 | if (!empty($part)) {
165 | list($rawHeaders, $part) = explode("\r\n\r\n", $part, 2);
166 | $headers = $this->parseRawHeaders($rawHeaders);
167 |
168 | $status = substr($part, 0, strpos($part, "\n"));
169 | $status = explode(" ", $status);
170 | $status = $status[1];
171 |
172 | list($partHeaders, $partBody) = $this->parseHttpResponse($part, 0);
173 | $response = new Response(
174 | (int) $status,
175 | $partHeaders,
176 | Psr7\Utils::streamFor($partBody)
177 | );
178 |
179 | // Need content id.
180 | $key = $headers['content-id'];
181 |
182 | try {
183 | $response = REST::decodeHttpResponse($response, $requests[$i-1]);
184 | } catch (GoogleServiceException $e) {
185 | // Store the exception as the response, so successful responses
186 | // can be processed.
187 | $response = $e;
188 | }
189 |
190 | $responses[$key] = $response;
191 | }
192 | }
193 |
194 | return $responses;
195 | }
196 |
197 | return null;
198 | }
199 |
200 | private function parseRawHeaders($rawHeaders)
201 | {
202 | $headers = [];
203 | $responseHeaderLines = explode("\r\n", $rawHeaders);
204 | foreach ($responseHeaderLines as $headerLine) {
205 | if ($headerLine && strpos($headerLine, ':') !== false) {
206 | list($header, $value) = explode(': ', $headerLine, 2);
207 | $header = strtolower($header);
208 | if (isset($headers[$header])) {
209 | $headers[$header] = array_merge((array)$headers[$header], (array)$value);
210 | } else {
211 | $headers[$header] = $value;
212 | }
213 | }
214 | }
215 | return $headers;
216 | }
217 |
218 | /**
219 | * Used by the IO lib and also the batch processing.
220 | *
221 | * @param string $respData
222 | * @param int $headerSize
223 | * @return array
224 | */
225 | private function parseHttpResponse($respData, $headerSize)
226 | {
227 | // check proxy header
228 | foreach (self::$CONNECTION_ESTABLISHED_HEADERS as $established_header) {
229 | if (stripos($respData, $established_header) !== false) {
230 | // existed, remove it
231 | $respData = str_ireplace($established_header, '', $respData);
232 | // Subtract the proxy header size unless the cURL bug prior to 7.30.0
233 | // is present which prevented the proxy header size from being taken into
234 | // account.
235 | // @TODO look into this
236 | // if (!$this->needsQuirk()) {
237 | // $headerSize -= strlen($established_header);
238 | // }
239 | break;
240 | }
241 | }
242 |
243 | if ($headerSize) {
244 | $responseBody = substr($respData, $headerSize);
245 | $responseHeaders = substr($respData, 0, $headerSize);
246 | } else {
247 | $responseSegments = explode("\r\n\r\n", $respData, 2);
248 | $responseHeaders = $responseSegments[0];
249 | $responseBody = isset($responseSegments[1]) ? $responseSegments[1] : null;
250 | }
251 |
252 | $responseHeaders = $this->parseRawHeaders($responseHeaders);
253 |
254 | return [$responseHeaders, $responseBody];
255 | }
256 | }
257 |
--------------------------------------------------------------------------------
/DATABASE/google-api-php-client-main/src/Http/Batch.php:
--------------------------------------------------------------------------------
1 | client = $client;
64 | $this->boundary = $boundary ?: mt_rand();
65 | $this->rootUrl = rtrim($rootUrl ?: $this->client->getConfig('base_path'), '/');
66 | $this->batchPath = $batchPath ?: self::BATCH_PATH;
67 | }
68 |
69 | public function add(RequestInterface $request, $key = false)
70 | {
71 | if (false == $key) {
72 | $key = mt_rand();
73 | }
74 |
75 | $this->requests[$key] = $request;
76 | }
77 |
78 | public function execute()
79 | {
80 | $body = '';
81 | $classes = [];
82 | $batchHttpTemplate = <<requests as $key => $request) {
97 | $firstLine = sprintf(
98 | '%s %s HTTP/%s',
99 | $request->getMethod(),
100 | $request->getRequestTarget(),
101 | $request->getProtocolVersion()
102 | );
103 |
104 | $content = (string) $request->getBody();
105 |
106 | $headers = '';
107 | foreach ($request->getHeaders() as $name => $values) {
108 | $headers .= sprintf("%s:%s\r\n", $name, implode(', ', $values));
109 | }
110 |
111 | $body .= sprintf(
112 | $batchHttpTemplate,
113 | $this->boundary,
114 | $key,
115 | $firstLine,
116 | $headers,
117 | $content ? "\n" . $content : ''
118 | );
119 |
120 | $classes['response-' . $key] = $request->getHeaderLine('X-Php-Expected-Class');
121 | }
122 |
123 | $body .= "--{$this->boundary}--";
124 | $body = trim($body);
125 | $url = $this->rootUrl . '/' . $this->batchPath;
126 | $headers = [
127 | 'Content-Type' => sprintf('multipart/mixed; boundary=%s', $this->boundary),
128 | 'Content-Length' => (string) strlen($body),
129 | ];
130 |
131 | $request = new Request(
132 | 'POST',
133 | $url,
134 | $headers,
135 | $body
136 | );
137 |
138 | $response = $this->client->execute($request);
139 |
140 | return $this->parseResponse($response, $classes);
141 | }
142 |
143 | public function parseResponse(ResponseInterface $response, $classes = [])
144 | {
145 | $contentType = $response->getHeaderLine('content-type');
146 | $contentType = explode(';', $contentType);
147 | $boundary = false;
148 | foreach ($contentType as $part) {
149 | $part = explode('=', $part, 2);
150 | if (isset($part[0]) && 'boundary' == trim($part[0])) {
151 | $boundary = $part[1];
152 | }
153 | }
154 |
155 | $body = (string) $response->getBody();
156 | if (!empty($body)) {
157 | $body = str_replace("--$boundary--", "--$boundary", $body);
158 | $parts = explode("--$boundary", $body);
159 | $responses = [];
160 | $requests = array_values($this->requests);
161 |
162 | foreach ($parts as $i => $part) {
163 | $part = trim($part);
164 | if (!empty($part)) {
165 | list($rawHeaders, $part) = explode("\r\n\r\n", $part, 2);
166 | $headers = $this->parseRawHeaders($rawHeaders);
167 |
168 | $status = substr($part, 0, strpos($part, "\n"));
169 | $status = explode(" ", $status);
170 | $status = $status[1];
171 |
172 | list($partHeaders, $partBody) = $this->parseHttpResponse($part, 0);
173 | $response = new Response(
174 | (int) $status,
175 | $partHeaders,
176 | Psr7\Utils::streamFor($partBody)
177 | );
178 |
179 | // Need content id.
180 | $key = $headers['content-id'];
181 |
182 | try {
183 | $response = REST::decodeHttpResponse($response, $requests[$i-1]);
184 | } catch (GoogleServiceException $e) {
185 | // Store the exception as the response, so successful responses
186 | // can be processed.
187 | $response = $e;
188 | }
189 |
190 | $responses[$key] = $response;
191 | }
192 | }
193 |
194 | return $responses;
195 | }
196 |
197 | return null;
198 | }
199 |
200 | private function parseRawHeaders($rawHeaders)
201 | {
202 | $headers = [];
203 | $responseHeaderLines = explode("\r\n", $rawHeaders);
204 | foreach ($responseHeaderLines as $headerLine) {
205 | if ($headerLine && strpos($headerLine, ':') !== false) {
206 | list($header, $value) = explode(': ', $headerLine, 2);
207 | $header = strtolower($header);
208 | if (isset($headers[$header])) {
209 | $headers[$header] = array_merge((array)$headers[$header], (array)$value);
210 | } else {
211 | $headers[$header] = $value;
212 | }
213 | }
214 | }
215 | return $headers;
216 | }
217 |
218 | /**
219 | * Used by the IO lib and also the batch processing.
220 | *
221 | * @param string $respData
222 | * @param int $headerSize
223 | * @return array
224 | */
225 | private function parseHttpResponse($respData, $headerSize)
226 | {
227 | // check proxy header
228 | foreach (self::$CONNECTION_ESTABLISHED_HEADERS as $established_header) {
229 | if (stripos($respData, $established_header) !== false) {
230 | // existed, remove it
231 | $respData = str_ireplace($established_header, '', $respData);
232 | // Subtract the proxy header size unless the cURL bug prior to 7.30.0
233 | // is present which prevented the proxy header size from being taken into
234 | // account.
235 | // @TODO look into this
236 | // if (!$this->needsQuirk()) {
237 | // $headerSize -= strlen($established_header);
238 | // }
239 | break;
240 | }
241 | }
242 |
243 | if ($headerSize) {
244 | $responseBody = substr($respData, $headerSize);
245 | $responseHeaders = substr($respData, 0, $headerSize);
246 | } else {
247 | $responseSegments = explode("\r\n\r\n", $respData, 2);
248 | $responseHeaders = $responseSegments[0];
249 | $responseBody = isset($responseSegments[1]) ? $responseSegments[1] : null;
250 | }
251 |
252 | $responseHeaders = $this->parseRawHeaders($responseHeaders);
253 |
254 | return [$responseHeaders, $responseBody];
255 | }
256 | }
257 |
--------------------------------------------------------------------------------
/google-client/src/Task/Runner.php:
--------------------------------------------------------------------------------
1 | self::TASK_RETRY_ALWAYS,
81 | '503' => self::TASK_RETRY_ALWAYS,
82 | 'rateLimitExceeded' => self::TASK_RETRY_ALWAYS,
83 | 'userRateLimitExceeded' => self::TASK_RETRY_ALWAYS,
84 | 6 => self::TASK_RETRY_ALWAYS, // CURLE_COULDNT_RESOLVE_HOST
85 | 7 => self::TASK_RETRY_ALWAYS, // CURLE_COULDNT_CONNECT
86 | 28 => self::TASK_RETRY_ALWAYS, // CURLE_OPERATION_TIMEOUTED
87 | 35 => self::TASK_RETRY_ALWAYS, // CURLE_SSL_CONNECT_ERROR
88 | 52 => self::TASK_RETRY_ALWAYS, // CURLE_GOT_NOTHING
89 | 'lighthouseError' => self::TASK_RETRY_NEVER
90 | ];
91 |
92 | /**
93 | * Creates a new task runner with exponential backoff support.
94 | *
95 | * @param array $config The task runner config
96 | * @param string $name The name of the current task (used for logging)
97 | * @param callable $action The task to run and possibly retry
98 | * @param array $arguments The task arguments
99 | * @throws \Google\Task\Exception when misconfigured
100 | */
101 | // @phpstan-ignore-next-line
102 | public function __construct(
103 | $config,
104 | $name,
105 | $action,
106 | array $arguments = []
107 | ) {
108 | if (isset($config['initial_delay'])) {
109 | if ($config['initial_delay'] < 0) {
110 | throw new GoogleTaskException(
111 | 'Task configuration `initial_delay` must not be negative.'
112 | );
113 | }
114 |
115 | $this->delay = $config['initial_delay'];
116 | }
117 |
118 | if (isset($config['max_delay'])) {
119 | if ($config['max_delay'] <= 0) {
120 | throw new GoogleTaskException(
121 | 'Task configuration `max_delay` must be greater than 0.'
122 | );
123 | }
124 |
125 | $this->maxDelay = $config['max_delay'];
126 | }
127 |
128 | if (isset($config['factor'])) {
129 | if ($config['factor'] <= 0) {
130 | throw new GoogleTaskException(
131 | 'Task configuration `factor` must be greater than 0.'
132 | );
133 | }
134 |
135 | $this->factor = $config['factor'];
136 | }
137 |
138 | if (isset($config['jitter'])) {
139 | if ($config['jitter'] <= 0) {
140 | throw new GoogleTaskException(
141 | 'Task configuration `jitter` must be greater than 0.'
142 | );
143 | }
144 |
145 | $this->jitter = $config['jitter'];
146 | }
147 |
148 | if (isset($config['retries'])) {
149 | if ($config['retries'] < 0) {
150 | throw new GoogleTaskException(
151 | 'Task configuration `retries` must not be negative.'
152 | );
153 | }
154 | $this->maxAttempts += $config['retries'];
155 | }
156 |
157 | if (!is_callable($action)) {
158 | throw new GoogleTaskException(
159 | 'Task argument `$action` must be a valid callable.'
160 | );
161 | }
162 |
163 | $this->action = $action;
164 | $this->arguments = $arguments;
165 | }
166 |
167 | /**
168 | * Checks if a retry can be attempted.
169 | *
170 | * @return boolean
171 | */
172 | public function canAttempt()
173 | {
174 | return $this->attempts < $this->maxAttempts;
175 | }
176 |
177 | /**
178 | * Runs the task and (if applicable) automatically retries when errors occur.
179 | *
180 | * @return mixed
181 | * @throws \Google\Service\Exception on failure when no retries are available.
182 | */
183 | public function run()
184 | {
185 | while ($this->attempt()) {
186 | try {
187 | return call_user_func_array($this->action, $this->arguments);
188 | } catch (GoogleServiceException $exception) {
189 | $allowedRetries = $this->allowedRetries(
190 | $exception->getCode(),
191 | $exception->getErrors()
192 | );
193 |
194 | if (!$this->canAttempt() || !$allowedRetries) {
195 | throw $exception;
196 | }
197 |
198 | if ($allowedRetries > 0) {
199 | $this->maxAttempts = min(
200 | $this->maxAttempts,
201 | $this->attempts + $allowedRetries
202 | );
203 | }
204 | }
205 | }
206 | }
207 |
208 | /**
209 | * Runs a task once, if possible. This is useful for bypassing the `run()`
210 | * loop.
211 | *
212 | * NOTE: If this is not the first attempt, this function will sleep in
213 | * accordance to the backoff configurations before running the task.
214 | *
215 | * @return boolean
216 | */
217 | public function attempt()
218 | {
219 | if (!$this->canAttempt()) {
220 | return false;
221 | }
222 |
223 | if ($this->attempts > 0) {
224 | $this->backOff();
225 | }
226 |
227 | $this->attempts++;
228 |
229 | return true;
230 | }
231 |
232 | /**
233 | * Sleeps in accordance to the backoff configurations.
234 | */
235 | private function backOff()
236 | {
237 | $delay = $this->getDelay();
238 |
239 | usleep((int) ($delay * 1000000));
240 | }
241 |
242 | /**
243 | * Gets the delay (in seconds) for the current backoff period.
244 | *
245 | * @return int
246 | */
247 | private function getDelay()
248 | {
249 | $jitter = $this->getJitter();
250 | $factor = $this->attempts > 1 ? $this->factor + $jitter : 1 + abs($jitter);
251 |
252 | return $this->delay = min($this->maxDelay, $this->delay * $factor);
253 | }
254 |
255 | /**
256 | * Gets the current jitter (random number between -$this->jitter and
257 | * $this->jitter).
258 | *
259 | * @return float
260 | */
261 | private function getJitter()
262 | {
263 | return $this->jitter * 2 * mt_rand() / mt_getrandmax() - $this->jitter;
264 | }
265 |
266 | /**
267 | * Gets the number of times the associated task can be retried.
268 | *
269 | * NOTE: -1 is returned if the task can be retried indefinitely
270 | *
271 | * @return integer
272 | */
273 | public function allowedRetries($code, $errors = [])
274 | {
275 | if (isset($this->retryMap[$code])) {
276 | return $this->retryMap[$code];
277 | }
278 |
279 | if (
280 | !empty($errors) &&
281 | isset($errors[0]['reason'], $this->retryMap[$errors[0]['reason']])
282 | ) {
283 | return $this->retryMap[$errors[0]['reason']];
284 | }
285 |
286 | return 0;
287 | }
288 |
289 | public function setRetryMap($retryMap)
290 | {
291 | $this->retryMap = $retryMap;
292 | }
293 | }
294 |
--------------------------------------------------------------------------------
/DATABASE/google-api-php-client-main/src/Task/Runner.php:
--------------------------------------------------------------------------------
1 | self::TASK_RETRY_ALWAYS,
81 | '503' => self::TASK_RETRY_ALWAYS,
82 | 'rateLimitExceeded' => self::TASK_RETRY_ALWAYS,
83 | 'userRateLimitExceeded' => self::TASK_RETRY_ALWAYS,
84 | 6 => self::TASK_RETRY_ALWAYS, // CURLE_COULDNT_RESOLVE_HOST
85 | 7 => self::TASK_RETRY_ALWAYS, // CURLE_COULDNT_CONNECT
86 | 28 => self::TASK_RETRY_ALWAYS, // CURLE_OPERATION_TIMEOUTED
87 | 35 => self::TASK_RETRY_ALWAYS, // CURLE_SSL_CONNECT_ERROR
88 | 52 => self::TASK_RETRY_ALWAYS, // CURLE_GOT_NOTHING
89 | 'lighthouseError' => self::TASK_RETRY_NEVER
90 | ];
91 |
92 | /**
93 | * Creates a new task runner with exponential backoff support.
94 | *
95 | * @param array $config The task runner config
96 | * @param string $name The name of the current task (used for logging)
97 | * @param callable $action The task to run and possibly retry
98 | * @param array $arguments The task arguments
99 | * @throws \Google\Task\Exception when misconfigured
100 | */
101 | // @phpstan-ignore-next-line
102 | public function __construct(
103 | $config,
104 | $name,
105 | $action,
106 | array $arguments = []
107 | ) {
108 | if (isset($config['initial_delay'])) {
109 | if ($config['initial_delay'] < 0) {
110 | throw new GoogleTaskException(
111 | 'Task configuration `initial_delay` must not be negative.'
112 | );
113 | }
114 |
115 | $this->delay = $config['initial_delay'];
116 | }
117 |
118 | if (isset($config['max_delay'])) {
119 | if ($config['max_delay'] <= 0) {
120 | throw new GoogleTaskException(
121 | 'Task configuration `max_delay` must be greater than 0.'
122 | );
123 | }
124 |
125 | $this->maxDelay = $config['max_delay'];
126 | }
127 |
128 | if (isset($config['factor'])) {
129 | if ($config['factor'] <= 0) {
130 | throw new GoogleTaskException(
131 | 'Task configuration `factor` must be greater than 0.'
132 | );
133 | }
134 |
135 | $this->factor = $config['factor'];
136 | }
137 |
138 | if (isset($config['jitter'])) {
139 | if ($config['jitter'] <= 0) {
140 | throw new GoogleTaskException(
141 | 'Task configuration `jitter` must be greater than 0.'
142 | );
143 | }
144 |
145 | $this->jitter = $config['jitter'];
146 | }
147 |
148 | if (isset($config['retries'])) {
149 | if ($config['retries'] < 0) {
150 | throw new GoogleTaskException(
151 | 'Task configuration `retries` must not be negative.'
152 | );
153 | }
154 | $this->maxAttempts += $config['retries'];
155 | }
156 |
157 | if (!is_callable($action)) {
158 | throw new GoogleTaskException(
159 | 'Task argument `$action` must be a valid callable.'
160 | );
161 | }
162 |
163 | $this->action = $action;
164 | $this->arguments = $arguments;
165 | }
166 |
167 | /**
168 | * Checks if a retry can be attempted.
169 | *
170 | * @return boolean
171 | */
172 | public function canAttempt()
173 | {
174 | return $this->attempts < $this->maxAttempts;
175 | }
176 |
177 | /**
178 | * Runs the task and (if applicable) automatically retries when errors occur.
179 | *
180 | * @return mixed
181 | * @throws \Google\Service\Exception on failure when no retries are available.
182 | */
183 | public function run()
184 | {
185 | while ($this->attempt()) {
186 | try {
187 | return call_user_func_array($this->action, $this->arguments);
188 | } catch (GoogleServiceException $exception) {
189 | $allowedRetries = $this->allowedRetries(
190 | $exception->getCode(),
191 | $exception->getErrors()
192 | );
193 |
194 | if (!$this->canAttempt() || !$allowedRetries) {
195 | throw $exception;
196 | }
197 |
198 | if ($allowedRetries > 0) {
199 | $this->maxAttempts = min(
200 | $this->maxAttempts,
201 | $this->attempts + $allowedRetries
202 | );
203 | }
204 | }
205 | }
206 | }
207 |
208 | /**
209 | * Runs a task once, if possible. This is useful for bypassing the `run()`
210 | * loop.
211 | *
212 | * NOTE: If this is not the first attempt, this function will sleep in
213 | * accordance to the backoff configurations before running the task.
214 | *
215 | * @return boolean
216 | */
217 | public function attempt()
218 | {
219 | if (!$this->canAttempt()) {
220 | return false;
221 | }
222 |
223 | if ($this->attempts > 0) {
224 | $this->backOff();
225 | }
226 |
227 | $this->attempts++;
228 |
229 | return true;
230 | }
231 |
232 | /**
233 | * Sleeps in accordance to the backoff configurations.
234 | */
235 | private function backOff()
236 | {
237 | $delay = $this->getDelay();
238 |
239 | usleep((int) ($delay * 1000000));
240 | }
241 |
242 | /**
243 | * Gets the delay (in seconds) for the current backoff period.
244 | *
245 | * @return int
246 | */
247 | private function getDelay()
248 | {
249 | $jitter = $this->getJitter();
250 | $factor = $this->attempts > 1 ? $this->factor + $jitter : 1 + abs($jitter);
251 |
252 | return $this->delay = min($this->maxDelay, $this->delay * $factor);
253 | }
254 |
255 | /**
256 | * Gets the current jitter (random number between -$this->jitter and
257 | * $this->jitter).
258 | *
259 | * @return float
260 | */
261 | private function getJitter()
262 | {
263 | return $this->jitter * 2 * mt_rand() / mt_getrandmax() - $this->jitter;
264 | }
265 |
266 | /**
267 | * Gets the number of times the associated task can be retried.
268 | *
269 | * NOTE: -1 is returned if the task can be retried indefinitely
270 | *
271 | * @return integer
272 | */
273 | public function allowedRetries($code, $errors = [])
274 | {
275 | if (isset($this->retryMap[$code])) {
276 | return $this->retryMap[$code];
277 | }
278 |
279 | if (
280 | !empty($errors) &&
281 | isset($errors[0]['reason'], $this->retryMap[$errors[0]['reason']])
282 | ) {
283 | return $this->retryMap[$errors[0]['reason']];
284 | }
285 |
286 | return 0;
287 | }
288 |
289 | public function setRetryMap($retryMap)
290 | {
291 | $this->retryMap = $retryMap;
292 | }
293 | }
294 |
--------------------------------------------------------------------------------
/google-client/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
203 |
204 |
--------------------------------------------------------------------------------
/DATABASE/google-api-php-client-main/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
203 |
204 |
--------------------------------------------------------------------------------
/google-client/src/AccessToken/Verify.php:
--------------------------------------------------------------------------------
1 | http = $http;
81 | $this->cache = $cache;
82 | $this->jwt = $jwt ?: $this->getJwtService();
83 | }
84 |
85 | /**
86 | * Verifies an id token and returns the authenticated apiLoginTicket.
87 | * Throws an exception if the id token is not valid.
88 | * The audience parameter can be used to control which id tokens are
89 | * accepted. By default, the id token must have been issued to this OAuth2 client.
90 | *
91 | * @param string $idToken the ID token in JWT format
92 | * @param string $audience Optional. The audience to verify against JWt "aud"
93 | * @return array|false the token payload, if successful
94 | */
95 | public function verifyIdToken($idToken, $audience = null)
96 | {
97 | if (empty($idToken)) {
98 | throw new LogicException('id_token cannot be null');
99 | }
100 |
101 | // set phpseclib constants if applicable
102 | $this->setPhpsecConstants();
103 |
104 | // Check signature
105 | $certs = $this->getFederatedSignOnCerts();
106 | foreach ($certs as $cert) {
107 | try {
108 | $args = [$idToken];
109 | $publicKey = $this->getPublicKey($cert);
110 | if (class_exists(Key::class)) {
111 | $args[] = new Key($publicKey, 'RS256');
112 | } else {
113 | $args[] = $publicKey;
114 | $args[] = ['RS256'];
115 | }
116 | $payload = \call_user_func_array([$this->jwt, 'decode'], $args);
117 |
118 | if (property_exists($payload, 'aud')) {
119 | if ($audience && $payload->aud != $audience) {
120 | return false;
121 | }
122 | }
123 |
124 | // support HTTP and HTTPS issuers
125 | // @see https://developers.google.com/identity/sign-in/web/backend-auth
126 | $issuers = [self::OAUTH2_ISSUER, self::OAUTH2_ISSUER_HTTPS];
127 | if (!isset($payload->iss) || !in_array($payload->iss, $issuers)) {
128 | return false;
129 | }
130 |
131 | return (array) $payload;
132 | } catch (ExpiredException $e) { // @phpstan-ignore-line
133 | return false;
134 | } catch (ExpiredExceptionV3 $e) {
135 | return false;
136 | } catch (SignatureInvalidException $e) {
137 | // continue
138 | } catch (DomainException $e) {
139 | // continue
140 | }
141 | }
142 |
143 | return false;
144 | }
145 |
146 | private function getCache()
147 | {
148 | return $this->cache;
149 | }
150 |
151 | /**
152 | * Retrieve and cache a certificates file.
153 | *
154 | * @param string $url location
155 | * @throws \Google\Exception
156 | * @return array certificates
157 | */
158 | private function retrieveCertsFromLocation($url)
159 | {
160 | // If we're retrieving a local file, just grab it.
161 | if (0 !== strpos($url, 'http')) {
162 | if (!$file = file_get_contents($url)) {
163 | throw new GoogleException(
164 | "Failed to retrieve verification certificates: '" .
165 | $url . "'."
166 | );
167 | }
168 |
169 | return json_decode($file, true);
170 | }
171 |
172 | // @phpstan-ignore-next-line
173 | $response = $this->http->get($url);
174 |
175 | if ($response->getStatusCode() == 200) {
176 | return json_decode((string) $response->getBody(), true);
177 | }
178 | throw new GoogleException(
179 | sprintf(
180 | 'Failed to retrieve verification certificates: "%s".',
181 | $response->getBody()->getContents()
182 | ),
183 | $response->getStatusCode()
184 | );
185 | }
186 |
187 | // Gets federated sign-on certificates to use for verifying identity tokens.
188 | // Returns certs as array structure, where keys are key ids, and values
189 | // are PEM encoded certificates.
190 | private function getFederatedSignOnCerts()
191 | {
192 | $certs = null;
193 | if ($cache = $this->getCache()) {
194 | $cacheItem = $cache->getItem('federated_signon_certs_v3');
195 | $certs = $cacheItem->get();
196 | }
197 |
198 |
199 | if (!$certs) {
200 | $certs = $this->retrieveCertsFromLocation(
201 | self::FEDERATED_SIGNON_CERT_URL
202 | );
203 |
204 | if ($cache) {
205 | $cacheItem->expiresAt(new DateTime('+1 hour'));
206 | $cacheItem->set($certs);
207 | $cache->save($cacheItem);
208 | }
209 | }
210 |
211 | if (!isset($certs['keys'])) {
212 | throw new InvalidArgumentException(
213 | 'federated sign-on certs expects "keys" to be set'
214 | );
215 | }
216 |
217 | return $certs['keys'];
218 | }
219 |
220 | private function getJwtService()
221 | {
222 | $jwtClass = 'JWT';
223 | if (class_exists('\Firebase\JWT\JWT')) {
224 | $jwtClass = 'Firebase\JWT\JWT';
225 | }
226 |
227 | if (property_exists($jwtClass, 'leeway') && $jwtClass::$leeway < 1) {
228 | // Ensures JWT leeway is at least 1
229 | // @see https://github.com/google/google-api-php-client/issues/827
230 | $jwtClass::$leeway = 1;
231 | }
232 |
233 | // @phpstan-ignore-next-line
234 | return new $jwtClass();
235 | }
236 |
237 | private function getPublicKey($cert)
238 | {
239 | $bigIntClass = $this->getBigIntClass();
240 | $modulus = new $bigIntClass($this->jwt->urlsafeB64Decode($cert['n']), 256);
241 | $exponent = new $bigIntClass($this->jwt->urlsafeB64Decode($cert['e']), 256);
242 | $component = ['n' => $modulus, 'e' => $exponent];
243 |
244 | if (class_exists('phpseclib3\Crypt\RSA\PublicKey')) {
245 | /** @var PublicKey $loader */
246 | $loader = PublicKeyLoader::load($component);
247 |
248 | return $loader->toString('PKCS8');
249 | }
250 |
251 | $rsaClass = $this->getRsaClass();
252 | $rsa = new $rsaClass();
253 | $rsa->loadKey($component);
254 |
255 | return $rsa->getPublicKey();
256 | }
257 |
258 | private function getRsaClass()
259 | {
260 | if (class_exists('phpseclib3\Crypt\RSA')) {
261 | return 'phpseclib3\Crypt\RSA';
262 | }
263 |
264 | if (class_exists('phpseclib\Crypt\RSA')) {
265 | return 'phpseclib\Crypt\RSA';
266 | }
267 |
268 | return 'Crypt_RSA';
269 | }
270 |
271 | private function getBigIntClass()
272 | {
273 | if (class_exists('phpseclib3\Math\BigInteger')) {
274 | return 'phpseclib3\Math\BigInteger';
275 | }
276 |
277 | if (class_exists('phpseclib\Math\BigInteger')) {
278 | return 'phpseclib\Math\BigInteger';
279 | }
280 |
281 | return 'Math_BigInteger';
282 | }
283 |
284 | private function getOpenSslConstant()
285 | {
286 | if (class_exists('phpseclib3\Crypt\AES')) {
287 | return 'phpseclib3\Crypt\AES::ENGINE_OPENSSL';
288 | }
289 |
290 | if (class_exists('phpseclib\Crypt\RSA')) {
291 | return 'phpseclib\Crypt\RSA::MODE_OPENSSL';
292 | }
293 |
294 | if (class_exists('Crypt_RSA')) {
295 | return 'CRYPT_RSA_MODE_OPENSSL';
296 | }
297 |
298 | throw new Exception('Cannot find RSA class');
299 | }
300 |
301 | /**
302 | * phpseclib calls "phpinfo" by default, which requires special
303 | * whitelisting in the AppEngine VM environment. This function
304 | * sets constants to bypass the need for phpseclib to check phpinfo
305 | *
306 | * @see phpseclib/Math/BigInteger
307 | * @see https://github.com/GoogleCloudPlatform/getting-started-php/issues/85
308 | */
309 | private function setPhpsecConstants()
310 | {
311 | if (filter_var(getenv('GAE_VM'), FILTER_VALIDATE_BOOLEAN)) {
312 | if (!defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
313 | define('MATH_BIGINTEGER_OPENSSL_ENABLED', true);
314 | }
315 | if (!defined('CRYPT_RSA_MODE')) {
316 | define('CRYPT_RSA_MODE', constant($this->getOpenSslConstant()));
317 | }
318 | }
319 | }
320 | }
321 |
--------------------------------------------------------------------------------
/DATABASE/google-api-php-client-main/src/AccessToken/Verify.php:
--------------------------------------------------------------------------------
1 | http = $http;
81 | $this->cache = $cache;
82 | $this->jwt = $jwt ?: $this->getJwtService();
83 | }
84 |
85 | /**
86 | * Verifies an id token and returns the authenticated apiLoginTicket.
87 | * Throws an exception if the id token is not valid.
88 | * The audience parameter can be used to control which id tokens are
89 | * accepted. By default, the id token must have been issued to this OAuth2 client.
90 | *
91 | * @param string $idToken the ID token in JWT format
92 | * @param string $audience Optional. The audience to verify against JWt "aud"
93 | * @return array|false the token payload, if successful
94 | */
95 | public function verifyIdToken($idToken, $audience = null)
96 | {
97 | if (empty($idToken)) {
98 | throw new LogicException('id_token cannot be null');
99 | }
100 |
101 | // set phpseclib constants if applicable
102 | $this->setPhpsecConstants();
103 |
104 | // Check signature
105 | $certs = $this->getFederatedSignOnCerts();
106 | foreach ($certs as $cert) {
107 | try {
108 | $args = [$idToken];
109 | $publicKey = $this->getPublicKey($cert);
110 | if (class_exists(Key::class)) {
111 | $args[] = new Key($publicKey, 'RS256');
112 | } else {
113 | $args[] = $publicKey;
114 | $args[] = ['RS256'];
115 | }
116 | $payload = \call_user_func_array([$this->jwt, 'decode'], $args);
117 |
118 | if (property_exists($payload, 'aud')) {
119 | if ($audience && $payload->aud != $audience) {
120 | return false;
121 | }
122 | }
123 |
124 | // support HTTP and HTTPS issuers
125 | // @see https://developers.google.com/identity/sign-in/web/backend-auth
126 | $issuers = [self::OAUTH2_ISSUER, self::OAUTH2_ISSUER_HTTPS];
127 | if (!isset($payload->iss) || !in_array($payload->iss, $issuers)) {
128 | return false;
129 | }
130 |
131 | return (array) $payload;
132 | } catch (ExpiredException $e) { // @phpstan-ignore-line
133 | return false;
134 | } catch (ExpiredExceptionV3 $e) {
135 | return false;
136 | } catch (SignatureInvalidException $e) {
137 | // continue
138 | } catch (DomainException $e) {
139 | // continue
140 | }
141 | }
142 |
143 | return false;
144 | }
145 |
146 | private function getCache()
147 | {
148 | return $this->cache;
149 | }
150 |
151 | /**
152 | * Retrieve and cache a certificates file.
153 | *
154 | * @param string $url location
155 | * @throws \Google\Exception
156 | * @return array certificates
157 | */
158 | private function retrieveCertsFromLocation($url)
159 | {
160 | // If we're retrieving a local file, just grab it.
161 | if (0 !== strpos($url, 'http')) {
162 | if (!$file = file_get_contents($url)) {
163 | throw new GoogleException(
164 | "Failed to retrieve verification certificates: '" .
165 | $url . "'."
166 | );
167 | }
168 |
169 | return json_decode($file, true);
170 | }
171 |
172 | // @phpstan-ignore-next-line
173 | $response = $this->http->get($url);
174 |
175 | if ($response->getStatusCode() == 200) {
176 | return json_decode((string) $response->getBody(), true);
177 | }
178 | throw new GoogleException(
179 | sprintf(
180 | 'Failed to retrieve verification certificates: "%s".',
181 | $response->getBody()->getContents()
182 | ),
183 | $response->getStatusCode()
184 | );
185 | }
186 |
187 | // Gets federated sign-on certificates to use for verifying identity tokens.
188 | // Returns certs as array structure, where keys are key ids, and values
189 | // are PEM encoded certificates.
190 | private function getFederatedSignOnCerts()
191 | {
192 | $certs = null;
193 | if ($cache = $this->getCache()) {
194 | $cacheItem = $cache->getItem('federated_signon_certs_v3');
195 | $certs = $cacheItem->get();
196 | }
197 |
198 |
199 | if (!$certs) {
200 | $certs = $this->retrieveCertsFromLocation(
201 | self::FEDERATED_SIGNON_CERT_URL
202 | );
203 |
204 | if ($cache) {
205 | $cacheItem->expiresAt(new DateTime('+1 hour'));
206 | $cacheItem->set($certs);
207 | $cache->save($cacheItem);
208 | }
209 | }
210 |
211 | if (!isset($certs['keys'])) {
212 | throw new InvalidArgumentException(
213 | 'federated sign-on certs expects "keys" to be set'
214 | );
215 | }
216 |
217 | return $certs['keys'];
218 | }
219 |
220 | private function getJwtService()
221 | {
222 | $jwtClass = 'JWT';
223 | if (class_exists('\Firebase\JWT\JWT')) {
224 | $jwtClass = 'Firebase\JWT\JWT';
225 | }
226 |
227 | if (property_exists($jwtClass, 'leeway') && $jwtClass::$leeway < 1) {
228 | // Ensures JWT leeway is at least 1
229 | // @see https://github.com/google/google-api-php-client/issues/827
230 | $jwtClass::$leeway = 1;
231 | }
232 |
233 | // @phpstan-ignore-next-line
234 | return new $jwtClass();
235 | }
236 |
237 | private function getPublicKey($cert)
238 | {
239 | $bigIntClass = $this->getBigIntClass();
240 | $modulus = new $bigIntClass($this->jwt->urlsafeB64Decode($cert['n']), 256);
241 | $exponent = new $bigIntClass($this->jwt->urlsafeB64Decode($cert['e']), 256);
242 | $component = ['n' => $modulus, 'e' => $exponent];
243 |
244 | if (class_exists('phpseclib3\Crypt\RSA\PublicKey')) {
245 | /** @var PublicKey $loader */
246 | $loader = PublicKeyLoader::load($component);
247 |
248 | return $loader->toString('PKCS8');
249 | }
250 |
251 | $rsaClass = $this->getRsaClass();
252 | $rsa = new $rsaClass();
253 | $rsa->loadKey($component);
254 |
255 | return $rsa->getPublicKey();
256 | }
257 |
258 | private function getRsaClass()
259 | {
260 | if (class_exists('phpseclib3\Crypt\RSA')) {
261 | return 'phpseclib3\Crypt\RSA';
262 | }
263 |
264 | if (class_exists('phpseclib\Crypt\RSA')) {
265 | return 'phpseclib\Crypt\RSA';
266 | }
267 |
268 | return 'Crypt_RSA';
269 | }
270 |
271 | private function getBigIntClass()
272 | {
273 | if (class_exists('phpseclib3\Math\BigInteger')) {
274 | return 'phpseclib3\Math\BigInteger';
275 | }
276 |
277 | if (class_exists('phpseclib\Math\BigInteger')) {
278 | return 'phpseclib\Math\BigInteger';
279 | }
280 |
281 | return 'Math_BigInteger';
282 | }
283 |
284 | private function getOpenSslConstant()
285 | {
286 | if (class_exists('phpseclib3\Crypt\AES')) {
287 | return 'phpseclib3\Crypt\AES::ENGINE_OPENSSL';
288 | }
289 |
290 | if (class_exists('phpseclib\Crypt\RSA')) {
291 | return 'phpseclib\Crypt\RSA::MODE_OPENSSL';
292 | }
293 |
294 | if (class_exists('Crypt_RSA')) {
295 | return 'CRYPT_RSA_MODE_OPENSSL';
296 | }
297 |
298 | throw new Exception('Cannot find RSA class');
299 | }
300 |
301 | /**
302 | * phpseclib calls "phpinfo" by default, which requires special
303 | * whitelisting in the AppEngine VM environment. This function
304 | * sets constants to bypass the need for phpseclib to check phpinfo
305 | *
306 | * @see phpseclib/Math/BigInteger
307 | * @see https://github.com/GoogleCloudPlatform/getting-started-php/issues/85
308 | */
309 | private function setPhpsecConstants()
310 | {
311 | if (filter_var(getenv('GAE_VM'), FILTER_VALIDATE_BOOLEAN)) {
312 | if (!defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
313 | define('MATH_BIGINTEGER_OPENSSL_ENABLED', true);
314 | }
315 | if (!defined('CRYPT_RSA_MODE')) {
316 | define('CRYPT_RSA_MODE', constant($this->getOpenSslConstant()));
317 | }
318 | }
319 | }
320 | }
321 |
--------------------------------------------------------------------------------
/google-client/src/Http/MediaFileUpload.php:
--------------------------------------------------------------------------------
1 | client = $client;
91 | $this->request = $request;
92 | $this->mimeType = $mimeType;
93 | $this->data = $data;
94 | $this->resumable = $resumable;
95 | $this->chunkSize = $chunkSize;
96 | $this->progress = 0;
97 |
98 | $this->process();
99 | }
100 |
101 | /**
102 | * Set the size of the file that is being uploaded.
103 | * @param int $size - int file size in bytes
104 | */
105 | public function setFileSize($size)
106 | {
107 | $this->size = $size;
108 | }
109 |
110 | /**
111 | * Return the progress on the upload
112 | * @return int progress in bytes uploaded.
113 | */
114 | public function getProgress()
115 | {
116 | return $this->progress;
117 | }
118 |
119 | /**
120 | * Send the next part of the file to upload.
121 | * @param string|bool $chunk Optional. The next set of bytes to send. If false will
122 | * use $data passed at construct time.
123 | */
124 | public function nextChunk($chunk = false)
125 | {
126 | $resumeUri = $this->getResumeUri();
127 |
128 | if (false == $chunk) {
129 | $chunk = substr($this->data, $this->progress, $this->chunkSize);
130 | }
131 |
132 | $lastBytePos = $this->progress + strlen($chunk) - 1;
133 | $headers = [
134 | 'content-range' => "bytes $this->progress-$lastBytePos/$this->size",
135 | 'content-length' => (string) strlen($chunk),
136 | 'expect' => '',
137 | ];
138 |
139 | $request = new Request(
140 | 'PUT',
141 | $resumeUri,
142 | $headers,
143 | Psr7\Utils::streamFor($chunk)
144 | );
145 |
146 | return $this->makePutRequest($request);
147 | }
148 |
149 | /**
150 | * Return the HTTP result code from the last call made.
151 | * @return int code
152 | */
153 | public function getHttpResultCode()
154 | {
155 | return $this->httpResultCode;
156 | }
157 |
158 | /**
159 | * Sends a PUT-Request to google drive and parses the response,
160 | * setting the appropiate variables from the response()
161 | *
162 | * @param RequestInterface $request the Request which will be send
163 | *
164 | * @return false|mixed false when the upload is unfinished or the decoded http response
165 | *
166 | */
167 | private function makePutRequest(RequestInterface $request)
168 | {
169 | $response = $this->client->execute($request);
170 | $this->httpResultCode = $response->getStatusCode();
171 |
172 | if (308 == $this->httpResultCode) {
173 | // Track the amount uploaded.
174 | $range = $response->getHeaderLine('range');
175 | if ($range) {
176 | $range_array = explode('-', $range);
177 | $this->progress = ((int) $range_array[1]) + 1;
178 | }
179 |
180 | // Allow for changing upload URLs.
181 | $location = $response->getHeaderLine('location');
182 | if ($location) {
183 | $this->resumeUri = $location;
184 | }
185 |
186 | // No problems, but upload not complete.
187 | return false;
188 | }
189 |
190 | return REST::decodeHttpResponse($response, $this->request);
191 | }
192 |
193 | /**
194 | * Resume a previously unfinished upload
195 | * @param string $resumeUri the resume-URI of the unfinished, resumable upload.
196 | */
197 | public function resume($resumeUri)
198 | {
199 | $this->resumeUri = $resumeUri;
200 | $headers = [
201 | 'content-range' => "bytes */$this->size",
202 | 'content-length' => '0',
203 | ];
204 | $httpRequest = new Request(
205 | 'PUT',
206 | $this->resumeUri,
207 | $headers
208 | );
209 | return $this->makePutRequest($httpRequest);
210 | }
211 |
212 | /**
213 | * @return RequestInterface
214 | * @visible for testing
215 | */
216 | private function process()
217 | {
218 | $this->transformToUploadUrl();
219 | $request = $this->request;
220 |
221 | $postBody = '';
222 | $contentType = false;
223 |
224 | $meta = json_decode((string) $request->getBody(), true);
225 |
226 | $uploadType = $this->getUploadType($meta);
227 | $request = $request->withUri(
228 | Uri::withQueryValue($request->getUri(), 'uploadType', $uploadType)
229 | );
230 |
231 | $mimeType = $this->mimeType ?: $request->getHeaderLine('content-type');
232 |
233 | if (self::UPLOAD_RESUMABLE_TYPE == $uploadType) {
234 | $contentType = $mimeType;
235 | $postBody = is_string($meta) ? $meta : json_encode($meta);
236 | } elseif (self::UPLOAD_MEDIA_TYPE == $uploadType) {
237 | $contentType = $mimeType;
238 | $postBody = $this->data;
239 | } elseif (self::UPLOAD_MULTIPART_TYPE == $uploadType) {
240 | // This is a multipart/related upload.
241 | $boundary = $this->boundary ?: mt_rand();
242 | $boundary = str_replace('"', '', $boundary);
243 | $contentType = 'multipart/related; boundary=' . $boundary;
244 | $related = "--$boundary\r\n";
245 | $related .= "Content-Type: application/json; charset=UTF-8\r\n";
246 | $related .= "\r\n" . json_encode($meta) . "\r\n";
247 | $related .= "--$boundary\r\n";
248 | $related .= "Content-Type: $mimeType\r\n";
249 | $related .= "Content-Transfer-Encoding: base64\r\n";
250 | $related .= "\r\n" . base64_encode($this->data) . "\r\n";
251 | $related .= "--$boundary--";
252 | $postBody = $related;
253 | }
254 |
255 | $request = $request->withBody(Psr7\Utils::streamFor($postBody));
256 |
257 | if ($contentType) {
258 | $request = $request->withHeader('content-type', $contentType);
259 | }
260 |
261 | return $this->request = $request;
262 | }
263 |
264 | /**
265 | * Valid upload types:
266 | * - resumable (UPLOAD_RESUMABLE_TYPE)
267 | * - media (UPLOAD_MEDIA_TYPE)
268 | * - multipart (UPLOAD_MULTIPART_TYPE)
269 | * @param string|false $meta
270 | * @return string
271 | * @visible for testing
272 | */
273 | public function getUploadType($meta)
274 | {
275 | if ($this->resumable) {
276 | return self::UPLOAD_RESUMABLE_TYPE;
277 | }
278 |
279 | if (false == $meta && $this->data) {
280 | return self::UPLOAD_MEDIA_TYPE;
281 | }
282 |
283 | return self::UPLOAD_MULTIPART_TYPE;
284 | }
285 |
286 | public function getResumeUri()
287 | {
288 | if (null === $this->resumeUri) {
289 | $this->resumeUri = $this->fetchResumeUri();
290 | }
291 |
292 | return $this->resumeUri;
293 | }
294 |
295 | private function fetchResumeUri()
296 | {
297 | $body = $this->request->getBody();
298 | $headers = [
299 | 'content-type' => 'application/json; charset=UTF-8',
300 | 'content-length' => $body->getSize(),
301 | 'x-upload-content-type' => $this->mimeType,
302 | 'x-upload-content-length' => $this->size,
303 | 'expect' => '',
304 | ];
305 | foreach ($headers as $key => $value) {
306 | $this->request = $this->request->withHeader($key, $value);
307 | }
308 |
309 | $response = $this->client->execute($this->request, false);
310 | $location = $response->getHeaderLine('location');
311 | $code = $response->getStatusCode();
312 |
313 | if (200 == $code && true == $location) {
314 | return $location;
315 | }
316 |
317 | $message = $code;
318 | $body = json_decode((string) $this->request->getBody(), true);
319 | if (isset($body['error']['errors'])) {
320 | $message .= ': ';
321 | foreach ($body['error']['errors'] as $error) {
322 | $message .= "{$error['domain']}, {$error['message']};";
323 | }
324 | $message = rtrim($message, ';');
325 | }
326 |
327 | $error = "Failed to start the resumable upload (HTTP {$message})";
328 | $this->client->getLogger()->error($error);
329 |
330 | throw new GoogleException($error);
331 | }
332 |
333 | private function transformToUploadUrl()
334 | {
335 | $parts = parse_url((string) $this->request->getUri());
336 | if (!isset($parts['path'])) {
337 | $parts['path'] = '';
338 | }
339 | $parts['path'] = '/upload' . $parts['path'];
340 | $uri = Uri::fromParts($parts);
341 | $this->request = $this->request->withUri($uri);
342 | }
343 |
344 | public function setChunkSize($chunkSize)
345 | {
346 | $this->chunkSize = $chunkSize;
347 | }
348 |
349 | public function getRequest()
350 | {
351 | return $this->request;
352 | }
353 | }
354 |
--------------------------------------------------------------------------------