PluginProbe ʕ •ᴥ•ʔ
ShareThis Dashboard for Google Analytics / 3.3.1
ShareThis Dashboard for Google Analytics v3.3.1
3.3.2 trunk 1.0.7 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.1 2.1.2 2.1.3 2.1.4 2.1.5 2.2.5 2.3.5 2.3.6 2.3.7 2.3.8 2.4.0 2.4.1 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 3.0.0 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.2.0 3.2.1 3.2.2 3.2.3 3.2.4 3.3.0 3.3.1
googleanalytics / lib / analytics-admin / vendor / google / apiclient / src / Http / Batch.php
googleanalytics / lib / analytics-admin / vendor / google / apiclient / src / Http Last commit date
Batch.php 3 years ago MediaFileUpload.php 3 years ago REST.php 3 years ago
Batch.php
257 lines
1 <?php
2 /*
3 * Copyright 2012 Google Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 namespace Google\Http;
19
20 use Google\Client;
21 use Google\Service\Exception as GoogleServiceException;
22 use GuzzleHttp\Psr7;
23 use GuzzleHttp\Psr7\Request;
24 use GuzzleHttp\Psr7\Response;
25 use Psr\Http\Message\RequestInterface;
26 use Psr\Http\Message\ResponseInterface;
27
28 /**
29 * Class to handle batched requests to the Google API service.
30 *
31 * Note that calls to `Google\Http\Batch::execute()` do not clear the queued
32 * requests. To start a new batch, be sure to create a new instance of this
33 * class.
34 */
35 class Batch
36 {
37 const BATCH_PATH = 'batch';
38
39 private static $CONNECTION_ESTABLISHED_HEADERS = [
40 "HTTP/1.0 200 Connection established\r\n\r\n",
41 "HTTP/1.1 200 Connection established\r\n\r\n",
42 ];
43
44 /** @var string Multipart Boundary. */
45 private $boundary;
46
47 /** @var array service requests to be executed. */
48 private $requests = [];
49
50 /** @var Client */
51 private $client;
52
53 private $rootUrl;
54
55 private $batchPath;
56
57 public function __construct(
58 Client $client,
59 $boundary = false,
60 $rootUrl = null,
61 $batchPath = null
62 ) {
63 $this->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 = <<<EOF
83 --%s
84 Content-Type: application/http
85 Content-Transfer-Encoding: binary
86 MIME-Version: 1.0
87 Content-ID: %s
88
89 %s
90 %s%s
91
92
93 EOF;
94
95 /** @var RequestInterface $request */
96 foreach ($this->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