Initial commit
This commit is contained in:
43
vendor/google/apiclient/CODE_OF_CONDUCT.md
vendored
Normal file
43
vendor/google/apiclient/CODE_OF_CONDUCT.md
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
# Contributor Code of Conduct
|
||||
|
||||
As contributors and maintainers of this project,
|
||||
and in the interest of fostering an open and welcoming community,
|
||||
we pledge to respect all people who contribute through reporting issues,
|
||||
posting feature requests, updating documentation,
|
||||
submitting pull requests or patches, and other activities.
|
||||
|
||||
We are committed to making participation in this project
|
||||
a harassment-free experience for everyone,
|
||||
regardless of level of experience, gender, gender identity and expression,
|
||||
sexual orientation, disability, personal appearance,
|
||||
body size, race, ethnicity, age, religion, or nationality.
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery
|
||||
* Personal attacks
|
||||
* Trolling or insulting/derogatory comments
|
||||
* Public or private harassment
|
||||
* Publishing other's private information,
|
||||
such as physical or electronic
|
||||
addresses, without explicit permission
|
||||
* Other unethical or unprofessional conduct.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct.
|
||||
By adopting this Code of Conduct,
|
||||
project maintainers commit themselves to fairly and consistently
|
||||
applying these principles to every aspect of managing this project.
|
||||
Project maintainers who do not follow or enforce the Code of Conduct
|
||||
may be permanently removed from the project team.
|
||||
|
||||
This code of conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community.
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior
|
||||
may be reported by opening an issue
|
||||
or contacting one or more of the project maintainers.
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0,
|
||||
available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/)
|
||||
203
vendor/google/apiclient/LICENSE
vendored
Normal file
203
vendor/google/apiclient/LICENSE
vendored
Normal file
@@ -0,0 +1,203 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
396
vendor/google/apiclient/README.md
vendored
Normal file
396
vendor/google/apiclient/README.md
vendored
Normal file
@@ -0,0 +1,396 @@
|
||||
[](https://travis-ci.org/googleapis/google-api-php-client)
|
||||
|
||||
# Google APIs Client Library for PHP #
|
||||
|
||||
The Google API Client Library enables you to work with Google APIs such as Google+, Drive, or YouTube on your server.
|
||||
|
||||
These client libraries are officially supported by Google. However, the libraries are considered complete and are in maintenance mode. This means that we will address critical bugs and security issues but will not add any new features.
|
||||
|
||||
**NOTE** The actively maintained (v2) version of this client requires PHP 5.4 or above. If you require support for PHP 5.2 or 5.3, use the v1 branch.
|
||||
|
||||
## Google Cloud Platform
|
||||
|
||||
For Google Cloud Platform APIs such as Datastore, Cloud Storage or Pub/Sub, we recommend using [GoogleCloudPlatform/google-cloud-php](https://github.com/googleapis/google-cloud-php) which is under active development.
|
||||
|
||||
## Requirements ##
|
||||
* [PHP 5.4.0 or higher](https://www.php.net/)
|
||||
|
||||
## Developer Documentation ##
|
||||
|
||||
The [docs folder](docs/) provides detailed guides for using this library.
|
||||
|
||||
## Installation ##
|
||||
|
||||
You can use **Composer** or simply **Download the Release**
|
||||
|
||||
### Composer
|
||||
|
||||
The preferred method is via [composer](https://getcomposer.org/). Follow the
|
||||
[installation instructions](https://getcomposer.org/doc/00-intro.md) if you do not already have
|
||||
composer installed.
|
||||
|
||||
Once composer is installed, execute the following command in your project root to install this library:
|
||||
|
||||
```sh
|
||||
composer require google/apiclient:"^2.0"
|
||||
```
|
||||
|
||||
Finally, be sure to include the autoloader:
|
||||
|
||||
```php
|
||||
require_once '/path/to/your-project/vendor/autoload.php';
|
||||
```
|
||||
|
||||
### Download the Release
|
||||
|
||||
If you prefer not to use composer, you can download the package in its entirety. The [Releases](https://github.com/googleapis/google-api-php-client/releases) page lists all stable versions. Download any file
|
||||
with the name `google-api-php-client-[RELEASE_NAME].zip` for a package including this library and its dependencies.
|
||||
|
||||
Uncompress the zip file you download, and include the autoloader in your project:
|
||||
|
||||
```php
|
||||
require_once '/path/to/google-api-php-client/vendor/autoload.php';
|
||||
```
|
||||
|
||||
For additional installation and setup instructions, see [the documentation](docs/).
|
||||
|
||||
## Examples ##
|
||||
See the [`examples/`](examples) directory for examples of the key client features. You can
|
||||
view them in your browser by running the php built-in web server.
|
||||
|
||||
```
|
||||
$ php -S localhost:8000 -t examples/
|
||||
```
|
||||
|
||||
And then browsing to the host and port you specified
|
||||
(in the above example, `http://localhost:8000`).
|
||||
|
||||
### Basic Example ###
|
||||
|
||||
```php
|
||||
// include your composer dependencies
|
||||
require_once 'vendor/autoload.php';
|
||||
|
||||
$client = new Google_Client();
|
||||
$client->setApplicationName("Client_Library_Examples");
|
||||
$client->setDeveloperKey("YOUR_APP_KEY");
|
||||
|
||||
$service = new Google_Service_Books($client);
|
||||
$optParams = array('filter' => 'free-ebooks');
|
||||
$results = $service->volumes->listVolumes('Henry David Thoreau', $optParams);
|
||||
|
||||
foreach ($results as $item) {
|
||||
echo $item['volumeInfo']['title'], "<br /> \n";
|
||||
}
|
||||
```
|
||||
|
||||
### Authentication with OAuth ###
|
||||
|
||||
> An example of this can be seen in [`examples/simple-file-upload.php`](examples/simple-file-upload.php).
|
||||
|
||||
1. Follow the instructions to [Create Web Application Credentials](docs/oauth-web.md#create-authorization-credentials)
|
||||
1. Download the JSON credentials
|
||||
1. Set the path to these credentials using `Google_Client::setAuthConfig`:
|
||||
|
||||
```php
|
||||
$client = new Google_Client();
|
||||
$client->setAuthConfig('/path/to/client_credentials.json');
|
||||
```
|
||||
|
||||
1. Set the scopes required for the API you are going to call
|
||||
|
||||
```php
|
||||
$client->addScope(Google_Service_Drive::DRIVE);
|
||||
```
|
||||
|
||||
1. Set your application's redirect URI
|
||||
|
||||
```php
|
||||
// Your redirect URI can be any registered URI, but in this example
|
||||
// we redirect back to this same page
|
||||
$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
|
||||
$client->setRedirectUri($redirect_uri);
|
||||
```
|
||||
|
||||
1. In the script handling the redirect URI, exchange the authorization code for an access token:
|
||||
|
||||
```php
|
||||
if (isset($_GET['code'])) {
|
||||
$token = $client->fetchAccessTokenWithAuthCode($_GET['code']);
|
||||
}
|
||||
```
|
||||
|
||||
### Authentication with Service Accounts ###
|
||||
|
||||
> An example of this can be seen in [`examples/service-account.php`](examples/service-account.php).
|
||||
|
||||
Some APIs
|
||||
(such as the [YouTube Data API](https://developers.google.com/youtube/v3/)) do
|
||||
not support service accounts. Check with the specific API documentation if API
|
||||
calls return unexpected 401 or 403 errors.
|
||||
|
||||
1. Follow the instructions to [Create a Service Account](docs/oauth-server.md#creating-a-service-account)
|
||||
1. Download the JSON credentials
|
||||
1. Set the path to these credentials using the `GOOGLE_APPLICATION_CREDENTIALS` environment variable:
|
||||
|
||||
```php
|
||||
putenv('GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json');
|
||||
```
|
||||
|
||||
1. Tell the Google client to use your service account credentials to authenticate:
|
||||
|
||||
```php
|
||||
$client = new Google_Client();
|
||||
$client->useApplicationDefaultCredentials();
|
||||
```
|
||||
|
||||
1. Set the scopes required for the API you are going to call
|
||||
|
||||
```php
|
||||
$client->addScope(Google_Service_Drive::DRIVE);
|
||||
```
|
||||
|
||||
1. If you have delegated domain-wide access to the service account and you want to impersonate a user account, specify the email address of the user account using the method setSubject:
|
||||
|
||||
```php
|
||||
$client->setSubject($user_to_impersonate);
|
||||
```
|
||||
|
||||
### Making Requests ###
|
||||
|
||||
The classes used to call the API in [google-api-php-client-services](https://github.com/googleapis/google-api-php-client-services) are autogenerated. They map directly to the JSON requests and responses found in the [APIs Explorer](https://developers.google.com/apis-explorer/#p/).
|
||||
|
||||
A JSON request to the [Datastore API](https://developers.google.com/apis-explorer/#p/datastore/v1beta3/datastore.projects.runQuery) would look like this:
|
||||
|
||||
```json
|
||||
POST https://datastore.googleapis.com/v1beta3/projects/YOUR_PROJECT_ID:runQuery?key=YOUR_API_KEY
|
||||
|
||||
{
|
||||
"query": {
|
||||
"kind": [{
|
||||
"name": "Book"
|
||||
}],
|
||||
"order": [{
|
||||
"property": {
|
||||
"name": "title"
|
||||
},
|
||||
"direction": "descending"
|
||||
}],
|
||||
"limit": 10
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Using this library, the same call would look something like this:
|
||||
|
||||
```php
|
||||
// create the datastore service class
|
||||
$datastore = new Google_Service_Datastore($client);
|
||||
|
||||
// build the query - this maps directly to the JSON
|
||||
$query = new Google_Service_Datastore_Query([
|
||||
'kind' => [
|
||||
[
|
||||
'name' => 'Book',
|
||||
],
|
||||
],
|
||||
'order' => [
|
||||
'property' => [
|
||||
'name' => 'title',
|
||||
],
|
||||
'direction' => 'descending',
|
||||
],
|
||||
'limit' => 10,
|
||||
]);
|
||||
|
||||
// build the request and response
|
||||
$request = new Google_Service_Datastore_RunQueryRequest(['query' => $query]);
|
||||
$response = $datastore->projects->runQuery('YOUR_DATASET_ID', $request);
|
||||
```
|
||||
|
||||
However, as each property of the JSON API has a corresponding generated class, the above code could also be written like this:
|
||||
|
||||
```php
|
||||
// create the datastore service class
|
||||
$datastore = new Google_Service_Datastore($client);
|
||||
|
||||
// build the query
|
||||
$request = new Google_Service_Datastore_RunQueryRequest();
|
||||
$query = new Google_Service_Datastore_Query();
|
||||
// - set the order
|
||||
$order = new Google_Service_Datastore_PropertyOrder();
|
||||
$order->setDirection('descending');
|
||||
$property = new Google_Service_Datastore_PropertyReference();
|
||||
$property->setName('title');
|
||||
$order->setProperty($property);
|
||||
$query->setOrder([$order]);
|
||||
// - set the kinds
|
||||
$kind = new Google_Service_Datastore_KindExpression();
|
||||
$kind->setName('Book');
|
||||
$query->setKinds([$kind]);
|
||||
// - set the limit
|
||||
$query->setLimit(10);
|
||||
|
||||
// add the query to the request and make the request
|
||||
$request->setQuery($query);
|
||||
$response = $datastore->projects->runQuery('YOUR_DATASET_ID', $request);
|
||||
```
|
||||
|
||||
The method used is a matter of preference, but *it will be very difficult to use this library without first understanding the JSON syntax for the API*, so it is recommended to look at the [APIs Explorer](https://developers.google.com/apis-explorer/#p/) before using any of the services here.
|
||||
|
||||
### Making HTTP Requests Directly ###
|
||||
|
||||
If Google Authentication is desired for external applications, or a Google API is not available yet in this library, HTTP requests can be made directly.
|
||||
|
||||
The `authorize` method returns an authorized [Guzzle Client](http://docs.guzzlephp.org/), so any request made using the client will contain the corresponding authorization.
|
||||
|
||||
```php
|
||||
// create the Google client
|
||||
$client = new Google_Client();
|
||||
|
||||
/**
|
||||
* Set your method for authentication. Depending on the API, This could be
|
||||
* directly with an access token, API key, or (recommended) using
|
||||
* Application Default Credentials.
|
||||
*/
|
||||
$client->useApplicationDefaultCredentials();
|
||||
$client->addScope(Google_Service_Plus::PLUS_ME);
|
||||
|
||||
// returns a Guzzle HTTP Client
|
||||
$httpClient = $client->authorize();
|
||||
|
||||
// make an HTTP request
|
||||
$response = $httpClient->get('https://www.googleapis.com/plus/v1/people/me');
|
||||
```
|
||||
|
||||
### Caching ###
|
||||
|
||||
It is recommended to use another caching library to improve performance. This can be done by passing a [PSR-6](https://www.php-fig.org/psr/psr-6/) compatible library to the client:
|
||||
|
||||
```php
|
||||
use League\Flysystem\Adapter\Local;
|
||||
use League\Flysystem\Filesystem;
|
||||
use Cache\Adapter\Filesystem\FilesystemCachePool;
|
||||
|
||||
$filesystemAdapter = new Local(__DIR__.'/');
|
||||
$filesystem = new Filesystem($filesystemAdapter);
|
||||
|
||||
$cache = new FilesystemCachePool($filesystem);
|
||||
$client->setCache($cache);
|
||||
```
|
||||
|
||||
In this example we use [PHP Cache](http://www.php-cache.com/). Add this to your project with composer:
|
||||
|
||||
```
|
||||
composer require cache/filesystem-adapter
|
||||
```
|
||||
|
||||
### Updating Tokens ###
|
||||
|
||||
When using [Refresh Tokens](https://developers.google.com/identity/protocols/OAuth2InstalledApp#offline) or [Service Account Credentials](https://developers.google.com/identity/protocols/OAuth2ServiceAccount#overview), it may be useful to perform some action when a new access token is granted. To do this, pass a callable to the `setTokenCallback` method on the client:
|
||||
|
||||
```php
|
||||
$logger = new Monolog\Logger;
|
||||
$tokenCallback = function ($cacheKey, $accessToken) use ($logger) {
|
||||
$logger->debug(sprintf('new access token received at cache key %s', $cacheKey));
|
||||
};
|
||||
$client->setTokenCallback($tokenCallback);
|
||||
```
|
||||
|
||||
### Debugging Your HTTP Request using Charles ###
|
||||
|
||||
It is often very useful to debug your API calls by viewing the raw HTTP request. This library supports the use of [Charles Web Proxy](https://www.charlesproxy.com/documentation/getting-started/). Download and run Charles, and then capture all HTTP traffic through Charles with the following code:
|
||||
|
||||
```php
|
||||
// FOR DEBUGGING ONLY
|
||||
$httpClient = new GuzzleHttp\Client([
|
||||
'proxy' => 'localhost:8888', // by default, Charles runs on localhost port 8888
|
||||
'verify' => false, // otherwise HTTPS requests will fail.
|
||||
]);
|
||||
|
||||
$client = new Google_Client();
|
||||
$client->setHttpClient($httpClient);
|
||||
```
|
||||
|
||||
Now all calls made by this library will appear in the Charles UI.
|
||||
|
||||
One additional step is required in Charles to view SSL requests. Go to **Charles > Proxy > SSL Proxying Settings** and add the domain you'd like captured. In the case of the Google APIs, this is usually `*.googleapis.com`.
|
||||
|
||||
### Controlling HTTP Client Configuration Directly
|
||||
|
||||
Google API Client uses [Guzzle](http://docs.guzzlephp.org/) as its default HTTP client. That means that you can control your HTTP requests in the same manner you would for any application using Guzzle.
|
||||
|
||||
Let's say, for instance, we wished to apply a referrer to each request.
|
||||
|
||||
```php
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
$httpClient = new Client([
|
||||
'headers' => [
|
||||
'referer' => 'mysite.com'
|
||||
]
|
||||
]);
|
||||
|
||||
$client = new Google_Client();
|
||||
$client->setHttpClient($httpClient);
|
||||
```
|
||||
|
||||
Other Guzzle features such as [Handlers and Middleware](http://docs.guzzlephp.org/en/stable/handlers-and-middleware.html) offer even more control.
|
||||
|
||||
### Service Specific Examples ###
|
||||
|
||||
YouTube: https://github.com/youtube/api-samples/tree/master/php
|
||||
|
||||
## How Do I Contribute? ##
|
||||
|
||||
Please see the [contributing](.github/CONTRIBUTING.md) page for more information. In particular, we love pull requests - but please make sure to sign the contributor license agreement.
|
||||
|
||||
## Frequently Asked Questions ##
|
||||
|
||||
### What do I do if something isn't working? ###
|
||||
|
||||
For support with the library the best place to ask is via the google-api-php-client tag on StackOverflow: https://stackoverflow.com/questions/tagged/google-api-php-client
|
||||
|
||||
If there is a specific bug with the library, please [file a issue](https://github.com/googleapis/google-api-php-client/issues) in the GitHub issues tracker, including an example of the failing code and any specific errors retrieved. Feature requests can also be filed, as long as they are core library requests, and not-API specific: for those, refer to the documentation for the individual APIs for the best place to file requests. Please try to provide a clear statement of the problem that the feature would address.
|
||||
|
||||
### I want an example of X! ###
|
||||
|
||||
If X is a feature of the library, file away! If X is an example of using a specific service, the best place to go is to the teams for those specific APIs - our preference is to link to their examples rather than add them to the library, as they can then pin to specific versions of the library. If you have any examples for other APIs, let us know and we will happily add a link to the README above!
|
||||
|
||||
### Why does Google_..._Service have weird names? ###
|
||||
|
||||
The _Service classes are generally automatically generated from the API discovery documents: https://developers.google.com/discovery/. Sometimes new features are added to APIs with unusual names, which can cause some unexpected or non-standard style naming in the PHP classes.
|
||||
|
||||
### How do I deal with non-JSON response types? ###
|
||||
|
||||
Some services return XML or similar by default, rather than JSON, which is what the library supports. You can request a JSON response by adding an 'alt' argument to optional params that is normally the last argument to a method call:
|
||||
|
||||
```
|
||||
$opt_params = array(
|
||||
'alt' => "json"
|
||||
);
|
||||
```
|
||||
|
||||
### How do I set a field to null? ###
|
||||
|
||||
The library strips out nulls from the objects sent to the Google APIs as its the default value of all of the uninitialized properties. To work around this, set the field you want to null to `Google_Model::NULL_VALUE`. This is a placeholder that will be replaced with a true null when sent over the wire.
|
||||
|
||||
## Code Quality ##
|
||||
|
||||
Run the PHPUnit tests with PHPUnit. You can configure an API key and token in BaseTest.php to run all calls, but this will require some setup on the Google Developer Console.
|
||||
|
||||
phpunit tests/
|
||||
|
||||
### Coding Style
|
||||
|
||||
To check for coding style violations, run
|
||||
|
||||
```
|
||||
vendor/bin/phpcs src --standard=style/ruleset.xml -np
|
||||
```
|
||||
|
||||
To automatically fix (fixable) coding style violations, run
|
||||
|
||||
```
|
||||
vendor/bin/phpcbf src --standard=style/ruleset.xml
|
||||
```
|
||||
43
vendor/google/apiclient/composer.json
vendored
Normal file
43
vendor/google/apiclient/composer.json
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"name": "google/apiclient",
|
||||
"type": "library",
|
||||
"description": "Client library for Google APIs",
|
||||
"keywords": ["google"],
|
||||
"homepage": "http://developers.google.com/api-client-library/php",
|
||||
"license": "Apache-2.0",
|
||||
"require": {
|
||||
"php": ">=5.4",
|
||||
"google/auth": "^1.0",
|
||||
"google/apiclient-services": "~0.13",
|
||||
"firebase/php-jwt": "~2.0||~3.0||~4.0||~5.0",
|
||||
"monolog/monolog": "^1.17",
|
||||
"phpseclib/phpseclib": "~0.3.10||~2.0",
|
||||
"guzzlehttp/guzzle": "~5.3.1||~6.0",
|
||||
"guzzlehttp/psr7": "^1.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.8.36",
|
||||
"squizlabs/php_codesniffer": "~2.3",
|
||||
"symfony/dom-crawler": "~2.1",
|
||||
"symfony/css-selector": "~2.1",
|
||||
"cache/filesystem-adapter": "^0.3.2",
|
||||
"phpcompatibility/php-compatibility": "^9.2",
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^0.5.0"
|
||||
},
|
||||
"suggest": {
|
||||
"cache/filesystem-adapter": "For caching certs and tokens (using Google_Client::setCache)"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Google_": "src/"
|
||||
},
|
||||
"classmap": [
|
||||
"src/Google/Service/"
|
||||
]
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.x-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
15
vendor/google/apiclient/docs/README.md
vendored
Normal file
15
vendor/google/apiclient/docs/README.md
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# Google API Client LIbrary for PHP Docs
|
||||
|
||||
The Google API Client Library for PHP offers simple, flexible access to many Google APIs.
|
||||
|
||||
## Documentation
|
||||
|
||||
- [Getting Started](start.md)
|
||||
- [API Keys](api-keys.md)
|
||||
- [Auth](auth.md)
|
||||
- [Installation](install.md)
|
||||
- [Media](media.md)
|
||||
- [OAuth Server](oauth-server.md)
|
||||
- [OAuth Web](oauth-web.md)
|
||||
- [Pagination](pagination.md)
|
||||
- [Parameters](parameters.md)
|
||||
13
vendor/google/apiclient/docs/api-keys.md
vendored
Normal file
13
vendor/google/apiclient/docs/api-keys.md
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
# API Keys
|
||||
|
||||
When calling APIs that do not access private user data, you can use simple API keys. These keys are used to authenticate your application for accounting purposes. The Google Developers Console documentation also describes [API keys](https://developers.google.com/console/help/using-keys).
|
||||
|
||||
> Note: If you do need to access private user data, you must use OAuth 2.0. See [Using OAuth 2.0 for Web Server Applications](/docs/oauth-web.md) and [Using OAuth 2.0 for Server to Server Applications](/docs/oauth-server.md) for more information.
|
||||
|
||||
## Using API Keys
|
||||
|
||||
To use API keys, call the `setDeveloperKey()` method of the `Google_Client` object before making any API calls. For example:
|
||||
|
||||
```php
|
||||
$client->setDeveloperKey($api_key);
|
||||
```
|
||||
11
vendor/google/apiclient/docs/auth.md
vendored
Normal file
11
vendor/google/apiclient/docs/auth.md
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
# Authorization
|
||||
|
||||
The Google PHP Client Library supports several methods for making authenticated calls to the Google APIs.
|
||||
|
||||
- [API Keys](api-keys.md)
|
||||
- [OAuth 2.0 For Webservers](oauth-web.md)
|
||||
- [OAuth 2.0 Service Accounts](oauth-server.md)
|
||||
|
||||
In addition, it supports a method of identifying users without granting access to make Google API calls.
|
||||
|
||||
- [ID Token Verification](id-token.md)
|
||||
22
vendor/google/apiclient/docs/id-token.md
vendored
Normal file
22
vendor/google/apiclient/docs/id-token.md
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
# ID Token Authentication
|
||||
|
||||
ID tokens allow authenticating a user securely without requiring a network call (in many cases), and without granting the server access to request user information from the Google APIs.
|
||||
|
||||
> For a complete example, see the [idtoken.php](https://github.com/googleapis/google-api-php-client/blob/master/examples/idtoken.php) sample in the examples/ directory of the client library.
|
||||
|
||||
This is accomplished because each ID token is a cryptographically signed, base64 encoded JSON structure. The token payload includes the Google user ID, the client ID of the application the user signed in to, and the issuer (in this case, Google). It also contains a cryptographic signature which can be verified with the public Google certificates to ensure that the token was created by Google. If the user has granted permission to view their email address to the application, the ID token will additionally include their email address.
|
||||
|
||||
The token can be easily and securely verified with the PHP client library
|
||||
|
||||
```php
|
||||
function getUserFromToken($token) {
|
||||
$ticket = $client->verifyIdToken($token);
|
||||
if ($ticket) {
|
||||
$data = $ticket->getAttributes();
|
||||
return $data['payload']['sub']; // user ID
|
||||
}
|
||||
return false
|
||||
}
|
||||
```
|
||||
|
||||
The library will automatically download and cache the certificate required for verification, and refresh it if it has expired.
|
||||
39
vendor/google/apiclient/docs/install.md
vendored
Normal file
39
vendor/google/apiclient/docs/install.md
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
# Installation
|
||||
|
||||
This page contains information about installing the Google APIs Client Library for PHP.
|
||||
|
||||
## Requirements
|
||||
|
||||
* PHP version 5.4 or greater.
|
||||
|
||||
## Obtaining the client library
|
||||
|
||||
There are two options for obtaining the files for the client library.
|
||||
|
||||
### Using Composer
|
||||
|
||||
You can install the library by adding it as a dependency to your composer.json.
|
||||
|
||||
```json
|
||||
"require": {
|
||||
"google/apiclient": "^2.0"
|
||||
}
|
||||
```
|
||||
|
||||
### Downloading from GitHub
|
||||
|
||||
Follow [the instructions in the README](https://github.com/google/google-api-php-client#download-the-release) to download the package locally.
|
||||
|
||||
### What to do with the files
|
||||
|
||||
After obtaining the files, include the autloader. If you used Composer, your require statement will look like this:
|
||||
|
||||
```php
|
||||
require_once '/path/to/your-project/vendor/autoload.php';
|
||||
```
|
||||
|
||||
If you downloaded the package separately, your require statement will look like this:
|
||||
|
||||
```php
|
||||
require_once '/path/to/google-api-php-client/vendor/autoload.php';
|
||||
```
|
||||
75
vendor/google/apiclient/docs/media.md
vendored
Normal file
75
vendor/google/apiclient/docs/media.md
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
# Media Upload
|
||||
|
||||
The PHP client library allows for uploading large files for use with APIs such as Drive or YouTube. There are three different methods available.
|
||||
|
||||
## Simple Upload
|
||||
|
||||
In the simple upload case, the data is passed as the body of the request made to the server. This limits the ability to specify metadata, but is very easy to use.
|
||||
|
||||
```php
|
||||
$file = new Google_Service_Drive_DriveFile();
|
||||
$result = $service->files->insert($file, array(
|
||||
'data' => file_get_contents("path/to/file"),
|
||||
'mimeType' => 'application/octet-stream',
|
||||
'uploadType' => 'media'
|
||||
));
|
||||
```
|
||||
|
||||
## Multipart File Upload
|
||||
|
||||
With multipart file uploads, the uploaded file is sent as one part of a multipart form post. This allows metadata about the file object to be sent as part of the post as well. This is triggered by specifying the _multipart_ uploadType.
|
||||
|
||||
```php
|
||||
$file = new Google_Service_Drive_DriveFile();
|
||||
$file->setTitle("Hello World!");
|
||||
$result = $service->files->insert($file, array(
|
||||
'data' => file_get_contents("path/to/file"),
|
||||
'mimeType' => 'application/octet-stream',
|
||||
'uploadType' => 'multipart'
|
||||
));
|
||||
```
|
||||
|
||||
## Resumable File Upload
|
||||
|
||||
It is also possible to split the upload across multiple requests. This is convenient for larger files, and allows resumption of the upload if there is a problem. Resumable uploads can be sent with separate metadata.
|
||||
|
||||
```php
|
||||
$file = new Google_Service_Drive_DriveFile();
|
||||
$file->title = "Big File";
|
||||
$chunkSizeBytes = 1 * 1024 * 1024;
|
||||
|
||||
// Call the API with the media upload, defer so it doesn't immediately return.
|
||||
$client->setDefer(true);
|
||||
$request = $service->files->insert($file);
|
||||
|
||||
// Create a media file upload to represent our upload process.
|
||||
$media = new Google_Http_MediaFileUpload(
|
||||
$client,
|
||||
$request,
|
||||
'text/plain',
|
||||
null,
|
||||
true,
|
||||
$chunkSizeBytes
|
||||
);
|
||||
$media->setFileSize(filesize("path/to/file"));
|
||||
|
||||
// Upload the various chunks. $status will be false until the process is
|
||||
// complete.
|
||||
$status = false;
|
||||
$handle = fopen("path/to/file", "rb");
|
||||
while (!$status && !feof($handle)) {
|
||||
$chunk = fread($handle, $chunkSizeBytes);
|
||||
$status = $media->nextChunk($chunk);
|
||||
}
|
||||
|
||||
// The final value of $status will be the data from the API for the object
|
||||
// that has been uploaded.
|
||||
$result = false;
|
||||
if($status != false) {
|
||||
$result = $status;
|
||||
}
|
||||
|
||||
fclose($handle);
|
||||
// Reset to the client to execute requests immediately in the future.
|
||||
$client->setDefer(false);
|
||||
```
|
||||
144
vendor/google/apiclient/docs/oauth-server.md
vendored
Normal file
144
vendor/google/apiclient/docs/oauth-server.md
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
# Using OAuth 2.0 for Server to Server Applications
|
||||
|
||||
The Google APIs Client Library for PHP supports using OAuth 2.0 for server-to-server interactions such as those between a web application and a Google service. For this scenario you need a service account, which is an account that belongs to your application instead of to an individual end user. Your application calls Google APIs on behalf of the service account, so users aren't directly involved. This scenario is sometimes called "two-legged OAuth," or "2LO." (The related term "three-legged OAuth" refers to scenarios in which your application calls Google APIs on behalf of end users, and in which user consent is sometimes required.)
|
||||
|
||||
Typically, an application uses a service account when the application uses Google APIs to work with its own data rather than a user's data. For example, an application that uses [Google Cloud Datastore](https://cloud.google.com/datastore/) for data persistence would use a service account to authenticate its calls to the Google Cloud Datastore API.
|
||||
|
||||
If you have a G Suite domain—if you use [G Suite Business](https://gsuite.google.com), for example—an administrator of the G Suite domain can authorize an application to access user data on behalf of users in the G Suite domain. For example, an application that uses the [Google Calendar API](https://developers.google.com/google-apps/calendar/) to add events to the calendars of all users in a G Suite domain would use a service account to access the Google Calendar API on behalf of users. Authorizing a service account to access data on behalf of users in a domain is sometimes referred to as "delegating domain-wide authority" to a service account.
|
||||
|
||||
> **Note:** When you use [G Suite Marketplace](https://www.google.com/enterprise/marketplace/) to install an application for your domain, the required permissions are automatically granted to the application. You do not need to manually authorize the service accounts that the application uses.
|
||||
|
||||
> **Note:** Although you can use service accounts in applications that run from a G Suite domain, service accounts are not members of your G Suite account and aren't subject to domain policies set by G Suite administrators. For example, a policy set in the G Suite admin console to restrict the ability of Apps end users to share documents outside of the domain would not apply to service accounts.
|
||||
|
||||
This document describes how an application can complete the server-to-server OAuth 2.0 flow by using the Google APIs Client Library for PHP.
|
||||
|
||||
## Overview
|
||||
|
||||
To support server-to-server interactions, first create a service account for your project in the Developers Console. If you want to access user data for users in your G Suite domain, then delegate domain-wide access to the service account.
|
||||
|
||||
Then, your application prepares to make authorized API calls by using the service account's credentials to request an access token from the OAuth 2.0 auth server.
|
||||
|
||||
Finally, your application can use the access token to call Google APIs.
|
||||
|
||||
## Creating a service account
|
||||
|
||||
A service account's credentials include a generated email address that is unique, a client ID, and at least one public/private key pair.
|
||||
|
||||
If your application runs on Google App Engine, a service account is set up automatically when you create your project.
|
||||
|
||||
If your application doesn't run on Google App Engine or Google Compute Engine, you must obtain these credentials in the Google Developers Console. To generate service-account credentials, or to view the public credentials that you've already generated, do the following:
|
||||
|
||||
If your application runs on Google App Engine, a service account is set up automatically when you create your project.
|
||||
|
||||
If your application doesn't run on Google App Engine or Google Compute Engine, you must obtain these credentials in the Google Developers Console. To generate service-account credentials, or to view the public credentials that you've already generated, do the following:
|
||||
|
||||
1. Open the [**Service accounts** section](https://console.developers.google.com/permissions/serviceaccounts?project=_) of the Developers Console's **Permissions** page.
|
||||
2. Click **Create service account**.
|
||||
3. In the **Create service account** window, type a name for the service account and select **Furnish a new private key**. If you want to [grant G Suite domain-wide authority](https://developers.google.com/identity/protocols/OAuth2ServiceAccount#delegatingauthority) to the service account, also select **Enable G Suite Domain-wide Delegation**. Then, click **Create**.
|
||||
|
||||
Your new public/private key pair is generated and downloaded to your machine; it serves as the only copy of this key. You are responsible for storing it securely.
|
||||
|
||||
You can return to the [Developers Console](https://console.developers.google.com/) at any time to view the client ID, email address, and public key fingerprints, or to generate additional public/private key pairs. For more details about service account credentials in the Developers Console, see [Service accounts](https://developers.google.com/console/help/service-accounts) in the Developers Console help file.
|
||||
|
||||
Take note of the service account's email address and store the service account's private key file in a location accessible to your application. Your application needs them to make authorized API calls.
|
||||
|
||||
**Note:** You must store and manage private keys securely in both development and production environments. Google does not keep a copy of your private keys, only your public keys.
|
||||
|
||||
### Delegating domain-wide authority to the service account
|
||||
|
||||
If your application runs in a G Suite domain and accesses user data, the service account that you created needs to be granted access to the user data that you want to access.
|
||||
|
||||
The following steps must be performed by an administrator of the G Suite domain:
|
||||
|
||||
1. Go to your G Suite domain’s [Admin console](http://admin.google.com).
|
||||
2. Select **Security** from the list of controls. If you don't see **Security** listed, select **More controls** from the gray bar at the bottom of the page, then select **Security** from the list of controls. If you can't see the controls, make sure you're signed in as an administrator for the domain.
|
||||
3. Select **Advanced settings** from the list of options.
|
||||
4. Select **Manage third party OAuth Client access** in the **Authentication** section.
|
||||
5. In the **Client name** field enter the service account's **Client ID**.
|
||||
6. In the **One or More API Scopes** field enter the list of scopes that your application should be granted access to. For example, if your application needs domain-wide access to the Google Drive API and the Google Calendar API, enter: https://www.googleapis.com/auth/drive, https://www.googleapis.com/auth/calendar.
|
||||
7. Click **Authorize**.
|
||||
|
||||
Your application now has the authority to make API calls as users in your domain (to "impersonate" users). When you prepare to make authorized API calls, you specify the user to impersonate.
|
||||
|
||||
[](#top_of_page)Preparing to make an authorized API call
|
||||
--------------------------------------------------------
|
||||
|
||||
After you have obtained the client email address and private key from the Developers Console, set the path to these credentials in the `GOOGLE_APPLICATION_CREDENTIALS` environment variable ( **Note:** This is not required in the App Engine environment):
|
||||
|
||||
```php
|
||||
putenv('GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json');
|
||||
```
|
||||
|
||||
Call the `useApplicationDefaultCredentials` to use your service account credentials to authenticate:
|
||||
|
||||
```php
|
||||
$client = new Google_Client();
|
||||
$client->useApplicationDefaultCredentials();
|
||||
```
|
||||
|
||||
If you have delegated domain-wide access to the service account and you want to impersonate a user account, specify the email address of the user account using the method `setSubject`:
|
||||
|
||||
```php
|
||||
$client->setSubject($user_to_impersonate);
|
||||
```
|
||||
|
||||
Use the authorized `Google_Client` object to call Google APIs in your application.
|
||||
|
||||
## Calling Google APIs
|
||||
|
||||
Use the authorized `Google_Client` object to call Google APIs by completing the following steps:
|
||||
|
||||
1. Build a service object for the API that you want to call, providing the authorized `Google_Client` object. For example, to call the Cloud SQL Administration API:
|
||||
|
||||
```php
|
||||
$sqladmin = new Google_Service_SQLAdmin($client);
|
||||
```
|
||||
|
||||
2. Make requests to the API service using the [interface provided by the service object](https://github.com/googleapis/google-api-php-client/blob/master/docs/start.md#build-the-service-object). For example, to list the instances of Cloud SQL databases in the examinable-example-123 project:
|
||||
|
||||
```php
|
||||
$response = $sqladmin->instances->listInstances('examinable-example-123')->getItems();
|
||||
```
|
||||
|
||||
## Complete example
|
||||
|
||||
The following example prints a JSON-formatted list of Cloud SQL instances in a project.
|
||||
|
||||
To run this example:
|
||||
|
||||
1. Create a new directory and change to it. For example:
|
||||
|
||||
```sh
|
||||
mkdir ~/php-oauth2-example
|
||||
cd ~/php-oauth2-example
|
||||
```
|
||||
|
||||
2. Install the [Google API Client Library](https://github.com/google/google-api-php-client) for PHP using [Composer](https://getcomposer.org):
|
||||
|
||||
```sh
|
||||
composer require google/apiclient:^2.0
|
||||
```
|
||||
|
||||
3. Create the file sqlinstances.php with the content below.
|
||||
4. Run the example from the command line:
|
||||
|
||||
```
|
||||
php ~/php-oauth2-example/sqlinstances.php
|
||||
```
|
||||
|
||||
### sqlinstances.php
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
require_once __DIR__.'/vendor/autoload.php';
|
||||
|
||||
putenv('GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json');
|
||||
$client = new Google_Client();
|
||||
$client->useApplicationDefaultCredentials();
|
||||
|
||||
$sqladmin = new Google_Service_SQLAdmin($client);
|
||||
$response = $sqladmin->instances
|
||||
->listInstances('examinable-example-123')->getItems();
|
||||
echo json_encode($response) . "\n";
|
||||
```
|
||||
424
vendor/google/apiclient/docs/oauth-web.md
vendored
Normal file
424
vendor/google/apiclient/docs/oauth-web.md
vendored
Normal file
@@ -0,0 +1,424 @@
|
||||
# Using OAuth 2.0 for Web Server Applications
|
||||
|
||||
This document explains how web server applications use the Google API Client Library for PHP to implement OAuth 2.0 authorization to access Google APIs. OAuth 2.0 allows users to share specific data with an application while keeping their usernames, passwords, and other information private. For example, an application can use OAuth 2.0 to obtain permission from users to store files in their Google Drives.
|
||||
|
||||
This OAuth 2.0 flow is specifically for user authorization. It is designed for applications that can store confidential information and maintain state. A properly authorized web server application can access an API while the user interacts with the application or after the user has left the application.
|
||||
|
||||
Web server applications frequently also use [service accounts](oauth-server.md) to authorize API requests, particularly when calling Cloud APIs to access project-based data rather than user-specific data. Web server applications can use service accounts in conjunction with user authorization.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Enable APIs for your project
|
||||
|
||||
Any application that calls Google APIs needs to enable those APIs in the API Console. To enable the appropriate APIs for your project:
|
||||
|
||||
1. Open the [Library](https://console.developers.google.com/apis/library) page in the API Console.
|
||||
2. Select the project associated with your application. Create a project if you do not have one already.
|
||||
3. Use the **Library** page to find each API that your application will use. Click on each API and enable it for your project.
|
||||
|
||||
### Create authorization credentials
|
||||
|
||||
Any application that uses OAuth 2.0 to access Google APIs must have authorization credentials that identify the application to Google's OAuth 2.0 server. The following steps explain how to create credentials for your project. Your applications can then use the credentials to access APIs that you have enabled for that project.
|
||||
|
||||
1. Open the [Credentials page](https://console.developers.google.com/apis/credentials) in the API Console.
|
||||
2. Click **Create credentials > OAuth client ID**.
|
||||
3. Complete the form. Set the application type to `Web application`. Applications that use languages and frameworks like PHP, Java, Python, Ruby, and .NET must specify authorized **redirect URIs**. The redirect URIs are the endpoints to which the OAuth 2.0 server can send responses.
|
||||
|
||||
For testing, you can specify URIs that refer to the local machine, such as `http://localhost:8080`. With that in mind, please note that all of the examples in this document use `http://localhost:8080` as the redirect URI.
|
||||
|
||||
We recommend that you design your app's auth endpoints so that your application does not expose authorization codes to other resources on the page.
|
||||
|
||||
After creating your credentials, download the **client_secret.json** file from the API Console. Securely store the file in a location that only your application can access.
|
||||
|
||||
> **Important:** Do not store the **client_secret.json** file in a publicly-accessible location. In addition, if you share the source code to your application—for example, on GitHub—store the **client_secret.json** file outside of your source tree to avoid inadvertently sharing your client credentials.
|
||||
|
||||
### Identify access scopes
|
||||
|
||||
Scopes enable your application to only request access to the resources that it needs while also enabling users to control the amount of access that they grant to your application. Thus, there may be an inverse relationship between the number of scopes requested and the likelihood of obtaining user consent.
|
||||
|
||||
Before you start implementing OAuth 2.0 authorization, we recommend that you identify the scopes that your app will need permission to access.
|
||||
|
||||
We also recommend that your application request access to authorization scopes via an [incremental authorization](#incremental-authorization) process, in which your application requests access to user data in context. This best practice helps users to more easily understand why your application needs the access it is requesting.
|
||||
|
||||
The [OAuth 2.0 API Scopes](https://developers.google.com/identity/protocols/googlescopes) document contains a full list of scopes that you might use to access Google APIs.
|
||||
|
||||
> If your public application uses scopes that permit access to certain user data, it must pass review. If you see **unverified app** on the screen when testing your application, you must submit a verification request to remove it. Find out more about [unverified apps](https://support.google.com/cloud/answer/7454865) and get answers to [frequently asked questions about app verification](https://support.google.com/cloud/answer/9110914) in the Help Center.
|
||||
|
||||
### Language-specific requirements
|
||||
|
||||
To run any of the code samples in this document, you'll need a Google account, access to the Internet, and a web browser. If you are using one of the API client libraries, also see the language-specific requirements below.
|
||||
|
||||
To run the PHP code samples in this document, you'll need:
|
||||
|
||||
* PHP 5.4 or greater with the command-line interface (CLI) and JSON extension installed.
|
||||
* The [Composer](https://getcomposer.org/) dependency management tool.
|
||||
* The Google APIs Client Library for PHP:
|
||||
```sh
|
||||
php composer.phar require google/apiclient:^2.0
|
||||
```
|
||||
|
||||
## Obtaining OAuth 2.0 access tokens
|
||||
|
||||
The following steps show how your application interacts with Google's OAuth 2.0 server to obtain a user's consent to perform an API request on the user's behalf. Your application must have that consent before it can execute a Google API request that requires user authorization.
|
||||
|
||||
The list below quickly summarizes these steps:
|
||||
|
||||
1. Your application identifies the permissions it needs.
|
||||
2. Your application redirects the user to Google along with the list of requested permissions.
|
||||
3. The user decides whether to grant the permissions to your application.
|
||||
4. Your application finds out what the user decided.
|
||||
5. If the user granted the requested permissions, your application retrieves tokens needed to make API requests on the user's behalf.
|
||||
|
||||
### Step 1: Set authorization parameters
|
||||
|
||||
Your first step is to create the authorization request. That request sets parameters that identify your application and define the permissions that the user will be asked to grant to your application.
|
||||
|
||||
The code snippet below creates a `Google_Client()` object, which defines the parameters in the authorization request.
|
||||
|
||||
That object uses information from your **client_secret.json** file to identify your application. The object also identifies the scopes that your application is requesting permission to access and the URL to your application's auth endpoint, which will handle the response from Google's OAuth 2.0 server. Finally, the code sets the optional access_type and include_granted_scopes parameters.
|
||||
|
||||
For example, this code requests read-only, offline access to a user's Google Drive:
|
||||
|
||||
```php
|
||||
$client = new Google_Client();
|
||||
$client->setAuthConfig('client_secret.json');
|
||||
$client->addScope(Google_Service_Drive::DRIVE_METADATA_READONLY);
|
||||
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php');
|
||||
$client->setAccessType('offline'); // offline access
|
||||
$client->setIncludeGrantedScopes(true); // incremental auth
|
||||
```
|
||||
|
||||
The request specifies the following information:
|
||||
|
||||
#### Parameters
|
||||
|
||||
##### `client_id`
|
||||
|
||||
**Required**. The client ID for your application. You can find this value in the [API Console](https://console.developers.google.com/). In PHP, call the `setAuthConfig` function to load authorization credentials from a **client_secret.json** file.
|
||||
|
||||
```php
|
||||
$client = new Google_Client();
|
||||
$client->setAuthConfig('client_secret.json');
|
||||
```
|
||||
|
||||
##### `redirect_uri`
|
||||
|
||||
**Required**. Determines where the API server redirects the user after the user completes the authorization flow. The value must exactly match one of the authorized redirect URIs for the OAuth 2.0 client, which you configured in the [API Console](https://console.developers.google.com/). If this value doesn't match an authorized URI, you will get a 'redirect_uri_mismatch' error. Note that the `http` or `https` scheme, case, and trailing slash ('`/`') must all match.
|
||||
|
||||
To set this value in PHP, call the `setRedirectUri` function. Note that you must specify a valid redirect URI for your API Console project.
|
||||
|
||||
```php
|
||||
$client->setRedirectUri('http://localhost:8080/oauth2callback.php');
|
||||
```
|
||||
|
||||
##### `scope`
|
||||
|
||||
**Required**. A space-delimited list of scopes that identify the resources that your application could access on the user's behalf. These values inform the consent screen that Google displays to the user.
|
||||
|
||||
Scopes enable your application to only request access to the resources that it needs while also enabling users to control the amount of access that they grant to your application. Thus, there is an inverse relationship between the number of scopes requested and the likelihood of obtaining user consent. To set this value in PHP, call the `addScope` function:
|
||||
|
||||
```php
|
||||
$client->addScope(Google_Service_Drive::DRIVE_METADATA_READONLY);
|
||||
```
|
||||
|
||||
The [OAuth 2.0 API Scopes](https://developers.google.com/identity/protocols/googlescopes) document provides a full list of scopes that you might use to access Google APIs.
|
||||
|
||||
We recommend that your application request access to authorization scopes in context whenever possible. By requesting access to user data in context, via [incremental authorization](#Incremental-authorization), you help users to more easily understand why your application needs the access it is requesting.
|
||||
|
||||
##### `access_type`
|
||||
|
||||
**Recommended**. Indicates whether your application can refresh access tokens when the user is not present at the browser. Valid parameter values are `online`, which is the default value, and `offline`.
|
||||
|
||||
Set the value to `offline` if your application needs to refresh access tokens when the user is not present at the browser. This is the method of refreshing access tokens described later in this document. This value instructs the Google authorization server to return a refresh token _and_ an access token the first time that your application exchanges an authorization code for tokens.
|
||||
|
||||
To set this value in PHP, call the `setAccessType` function:
|
||||
|
||||
```php
|
||||
$client->setAccessType('offline');
|
||||
```
|
||||
|
||||
##### `state`
|
||||
|
||||
**Recommended**. Specifies any string value that your application uses to maintain state between your authorization request and the authorization server's response. The server returns the exact value that you send as a `name=value` pair in the hash (`#`) fragment of the `redirect_uri` after the user consents to or denies your application's access request.
|
||||
|
||||
You can use this parameter for several purposes, such as directing the user to the correct resource in your application, sending nonces, and mitigating cross-site request forgery. Since your `redirect_uri` can be guessed, using a `state` value can increase your assurance that an incoming connection is the result of an authentication request. If you generate a random string or encode the hash of a cookie or another value that captures the client's state, you can validate the response to additionally ensure that the request and response originated in the same browser, providing protection against attacks such as cross-site request forgery. See the [OpenID Connect](https://developers.google.com/identity/protocols/OpenIDConnect#createxsrftoken) documentation for an example of how to create and confirm a `state` token.
|
||||
|
||||
To set this value in PHP, call the `setState` function:
|
||||
|
||||
```php
|
||||
$client->setState($sample_passthrough_value);
|
||||
```
|
||||
|
||||
##### `include_granted_scopes`
|
||||
|
||||
**Optional**. Enables applications to use incremental authorization to request access to additional scopes in context. If you set this parameter's value to `true` and the authorization request is granted, then the new access token will also cover any scopes to which the user previously granted the application access. See the [incremental authorization](#Incremental-authorization) section for examples.
|
||||
|
||||
To set this value in PHP, call the `setIncludeGrantedScopes` function:
|
||||
|
||||
```php
|
||||
$client->setIncludeGrantedScopes(true);
|
||||
```
|
||||
|
||||
##### `login_hint`
|
||||
|
||||
**Optional**. If your application knows which user is trying to authenticate, it can use this parameter to provide a hint to the Google Authentication Server. The server uses the hint to simplify the login flow either by prefilling the email field in the sign-in form or by selecting the appropriate multi-login session.
|
||||
|
||||
Set the parameter value to an email address or `sub` identifier, which is equivalent to the user's Google ID.
|
||||
|
||||
To set this value in PHP, call the `setLoginHint` function:
|
||||
|
||||
```php
|
||||
$client->setLoginHint('timmerman@google.com');
|
||||
```
|
||||
|
||||
##### `prompt`
|
||||
|
||||
**Optional**. A space-delimited, case-sensitive list of prompts to present the user. If you don't specify this parameter, the user will be prompted only the first time your app requests access.
|
||||
|
||||
To set this value in PHP, call the `setApprovalPrompt` function:
|
||||
|
||||
```php
|
||||
$client->setApprovalPrompt('consent');
|
||||
```
|
||||
|
||||
Possible values are:
|
||||
|
||||
`none`
|
||||
|
||||
Do not display any authentication or consent screens. Must not be specified with other values.
|
||||
|
||||
`consent`
|
||||
|
||||
Prompt the user for consent.
|
||||
|
||||
`select_account`
|
||||
|
||||
Prompt the user to select an account.
|
||||
|
||||
### Step 2: Redirect to Google's OAuth 2.0 server
|
||||
|
||||
Redirect the user to Google's OAuth 2.0 server to initiate the authentication and authorization process. Typically, this occurs when your application first needs to access the user's data. In the case of [incremental authorization](#incremental-authorization), this step also occurs when your application first needs to access additional resources that it does not yet have permission to access.
|
||||
|
||||
1. Generate a URL to request access from Google's OAuth 2.0 server:
|
||||
|
||||
```php
|
||||
$auth_url = $client->createAuthUrl();
|
||||
```
|
||||
|
||||
2. Redirect the user to `$auth_url`:
|
||||
|
||||
```php
|
||||
header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
|
||||
```
|
||||
|
||||
Google's OAuth 2.0 server authenticates the user and obtains consent from the user for your application to access the requested scopes. The response is sent back to your application using the redirect URL you specified.
|
||||
|
||||
### Step 3: Google prompts user for consent
|
||||
|
||||
In this step, the user decides whether to grant your application the requested access. At this stage, Google displays a consent window that shows the name of your application and the Google API services that it is requesting permission to access with the user's authorization credentials. The user can then consent or refuse to grant access to your application.
|
||||
|
||||
Your application doesn't need to do anything at this stage as it waits for the response from Google's OAuth 2.0 server indicating whether the access was granted. That response is explained in the following step.
|
||||
|
||||
### Step 4: Handle the OAuth 2.0 server response
|
||||
|
||||
The OAuth 2.0 server responds to your application's access request by using the URL specified in the request.
|
||||
|
||||
If the user approves the access request, then the response contains an authorization code. If the user does not approve the request, the response contains an error message. The authorization code or error message that is returned to the web server appears on the query string, as shown below:
|
||||
|
||||
An error response:
|
||||
|
||||
https://oauth2.example.com/auth?error=access_denied
|
||||
|
||||
An authorization code response:
|
||||
|
||||
https://oauth2.example.com/auth?code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7
|
||||
|
||||
> **Important**: If your response endpoint renders an HTML page, any resources on that page will be able to see the authorization code in the URL. Scripts can read the URL directly, and the URL in the `Referer` HTTP header may be sent to any or all resources on the page.
|
||||
>
|
||||
> Carefully consider whether you want to send authorization credentials to all resources on that page (especially third-party scripts such as social plugins and analytics). To avoid this issue, we recommend that the server first handle the request, then redirect to another URL that doesn't include the response parameters.
|
||||
|
||||
#### Sample OAuth 2.0 server response
|
||||
|
||||
You can test this flow by clicking on the following sample URL, which requests read-only access to view metadata for files in your Google Drive:
|
||||
|
||||
```
|
||||
https://accounts.google.com/o/oauth2/v2/auth?
|
||||
scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.metadata.readonly&
|
||||
access_type=offline&
|
||||
include_granted_scopes=true&
|
||||
state=state_parameter_passthrough_value&
|
||||
redirect_uri=http%3A%2F%2Foauth2.example.com%2Fcallback&
|
||||
response_type=code&
|
||||
client_id=client_id
|
||||
```
|
||||
|
||||
After completing the OAuth 2.0 flow, you should be redirected to `http://localhost/oauth2callback`, which will likely yield a `404 NOT FOUND` error unless your local machine serves a file at that address. The next step provides more detail about the information returned in the URI when the user is redirected back to your application.
|
||||
|
||||
### Step 5: Exchange authorization code for refresh and access tokens
|
||||
|
||||
After the web server receives the authorization code, it can exchange the authorization code for an access token.
|
||||
|
||||
To exchange an authorization code for an access token, use the `authenticate` method:
|
||||
|
||||
```php
|
||||
$client->authenticate($_GET['code']);
|
||||
```
|
||||
|
||||
You can retrieve the access token with the `getAccessToken` method:
|
||||
|
||||
```php
|
||||
$access_token = $client->getAccessToken();
|
||||
```
|
||||
|
||||
[](#top_of_page)Calling Google APIs
|
||||
-----------------------------------
|
||||
|
||||
Use the access token to call Google APIs by completing the following steps:
|
||||
|
||||
1. If you need to apply an access token to a new `Google_Client` object—for example, if you stored the access token in a user session—use the `setAccessToken` method:
|
||||
|
||||
```php
|
||||
$client->setAccessToken($access_token);
|
||||
```
|
||||
|
||||
2. Build a service object for the API that you want to call. You build a a service object by providing an authorized `Google_Client` object to the constructor for the API you want to call. For example, to call the Drive API:
|
||||
|
||||
```php
|
||||
$drive = new Google_Service_Drive($client);
|
||||
```
|
||||
|
||||
3. Make requests to the API service using the [interface provided by the service object](start.md). For example, to list the files in the authenticated user's Google Drive:
|
||||
|
||||
```php
|
||||
$files = $drive->files->listFiles(array())->getItems();
|
||||
```
|
||||
|
||||
[](#top_of_page)Complete example
|
||||
--------------------------------
|
||||
|
||||
The following example prints a JSON-formatted list of files in a user's Google Drive after the user authenticates and gives consent for the application to access the user's Drive files.
|
||||
|
||||
To run this example:
|
||||
|
||||
1. In the API Console, add the URL of the local machine to the list of redirect URLs. For example, add `http://localhost:8080`.
|
||||
2. Create a new directory and change to it. For example:
|
||||
|
||||
```sh
|
||||
mkdir ~/php-oauth2-example
|
||||
cd ~/php-oauth2-example
|
||||
```
|
||||
|
||||
3. Install the [Google API Client Library](https://github.com/google/google-api-php-client) for PHP using [Composer](https://getcomposer.org):
|
||||
|
||||
```sh
|
||||
composer require google/apiclient:^2.0
|
||||
```
|
||||
|
||||
4. Create the files `index.php` and `oauth2callback.php` with the content below.
|
||||
5. Run the example with a web server configured to serve PHP. If you use PHP 5.4 or newer, you can use PHP's built-in test web server:
|
||||
|
||||
```sh
|
||||
php -S localhost:8080 ~/php-oauth2-example
|
||||
```
|
||||
|
||||
#### index.php
|
||||
|
||||
```php
|
||||
<?php
|
||||
require_once __DIR__.'/vendor/autoload.php';
|
||||
|
||||
session_start();
|
||||
|
||||
$client = new Google_Client();
|
||||
$client->setAuthConfig('client_secrets.json');
|
||||
$client->addScope(Google_Service_Drive::DRIVE_METADATA_READONLY);
|
||||
|
||||
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
|
||||
$client->setAccessToken($_SESSION['access_token']);
|
||||
$drive = new Google_Service_Drive($client);
|
||||
$files = $drive->files->listFiles(array())->getItems();
|
||||
echo json_encode($files);
|
||||
} else {
|
||||
$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php';
|
||||
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
|
||||
}
|
||||
```
|
||||
|
||||
#### oauth2callback.php
|
||||
|
||||
```php
|
||||
<?php
|
||||
require_once __DIR__.'/vendor/autoload.php';
|
||||
|
||||
session_start();
|
||||
|
||||
$client = new Google_Client();
|
||||
$client->setAuthConfigFile('client_secrets.json');
|
||||
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php');
|
||||
$client->addScope(Google_Service_Drive::DRIVE_METADATA_READONLY);
|
||||
|
||||
if (! isset($_GET['code'])) {
|
||||
$auth_url = $client->createAuthUrl();
|
||||
header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
|
||||
} else {
|
||||
$client->authenticate($_GET['code']);
|
||||
$_SESSION['access_token'] = $client->getAccessToken();
|
||||
$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/';
|
||||
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
|
||||
}
|
||||
```
|
||||
|
||||
## Incremental authorization
|
||||
|
||||
In the OAuth 2.0 protocol, your app requests authorization to access resources, which are identified by scopes. It is considered a best user-experience practice to request authorization for resources at the time you need them. To enable that practice, Google's authorization server supports incremental authorization. This feature lets you request scopes as they are needed and, if the user grants permission, add those scopes to your existing access token for that user.
|
||||
|
||||
For example, an app that lets people sample music tracks and create mixes might need very few resources at sign-in time, perhaps nothing more than the name of the person signing in. However, saving a completed mix would require access to their Google Drive. Most people would find it natural if they only were asked for access to their Google Drive at the time the app actually needed it.
|
||||
|
||||
In this case, at sign-in time the app might request the `profile` scope to perform basic sign-in, and then later request the `https://www.googleapis.com/auth/drive.file` scope at the time of the first request to save a mix.
|
||||
|
||||
To implement incremental authorization, you complete the normal flow for requesting an access token but make sure that the authorization request includes previously granted scopes. This approach allows your app to avoid having to manage multiple access tokens.
|
||||
|
||||
The following rules apply to an access token obtained from an incremental authorization:
|
||||
|
||||
* The token can be used to access resources corresponding to any of the scopes rolled into the new, combined authorization.
|
||||
* When you use the refresh token for the combined authorization to obtain an access token, the access token represents the combined authorization and can be used for any of its scopes.
|
||||
* The combined authorization includes all scopes that the user granted to the API project even if the grants were requested from different clients. For example, if a user granted access to one scope using an application's desktop client and then granted another scope to the same application via a mobile client, the combined authorization would include both scopes.
|
||||
* If you revoke a token that represents a combined authorization, access to all of that authorization's scopes on behalf of the associated user are revoked simultaneously.
|
||||
|
||||
The example for [setting authorization parameters](#Step-1-Set-authorization-parameters) demonstrates how to ensure authorization requests follow this best practice. The code snippet below also shows the code that you need to add to use incremental authorization.
|
||||
|
||||
```php
|
||||
$client->setIncludeGrantedScopes(true);
|
||||
```
|
||||
|
||||
## Refreshing an access token (offline access)
|
||||
|
||||
Access tokens periodically expire. You can refresh an access token without prompting the user for permission (including when the user is not present) if you requested offline access to the scopes associated with the token.
|
||||
|
||||
If you use a Google API Client Library, the [client object](#Step-1-Set-authorization-parameters) refreshes the access token as needed as long as you configure that object for offline access.
|
||||
|
||||
Requesting offline access is a requirement for any application that needs to access a Google API when the user is not present. For example, an app that performs backup services or executes actions at predetermined times needs to be able to refresh its access token when the user is not present. The default style of access is called `online`.
|
||||
|
||||
Server-side web applications, installed applications, and devices all obtain refresh tokens during the authorization process. Refresh tokens are not typically used in client-side (JavaScript) web applications.
|
||||
|
||||
If your application needs offline access to a Google API, set the API client's access type to `offline`:
|
||||
|
||||
```php
|
||||
$client->setAccessType("offline");
|
||||
```
|
||||
|
||||
After a user grants offline access to the requested scopes, you can continue to use the API client to access Google APIs on the user's behalf when the user is offline. The client object will refresh the access token as needed.
|
||||
|
||||
## Revoking a token
|
||||
|
||||
In some cases a user may wish to revoke access given to an application. A user can revoke access by visiting [Account Settings](https://security.google.com/settings/security/permissions). It is also possible for an application to programmatically revoke the access given to it. Programmatic revocation is important in instances where a user unsubscribes or removes an application. In other words, part of the removal process can include an API request to ensure the permissions granted to the application are removed.
|
||||
|
||||
To programmatically revoke a token, call `revokeToken()`:
|
||||
|
||||
```php
|
||||
$client->revokeToken();
|
||||
```
|
||||
|
||||
**Note:** Following a successful revocation response, it might take some time before the revocation has full effect.
|
||||
|
||||
Except as otherwise noted, the content of this page is licensed under the [Creative Commons Attribution 4.0 License](https://creativecommons.org/licenses/by/4.0/), and code samples are licensed under the [Apache 2.0 License](https://www.apache.org/licenses/LICENSE-2.0). For details, see our [Site Policies](https://developers.google.com/terms/site-policies). Java is a registered trademark of Oracle and/or its affiliates.
|
||||
10
vendor/google/apiclient/docs/pagination.md
vendored
Normal file
10
vendor/google/apiclient/docs/pagination.md
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
# Pagination
|
||||
|
||||
Most list API calls have a maximum limit of results they will return in a single response. To allow retrieving more than this number of results, responses may return a pagination token which can be passed with a request in order to access subsequent pages.
|
||||
|
||||
The token for the page will normally be found on list response objects, normally `nextPageToken`. This can be passed in the optional params.
|
||||
|
||||
```php
|
||||
$token = $results->getNextPageToken();
|
||||
$server->listActivities('me', 'public', array('pageToken' => $token));
|
||||
```
|
||||
14
vendor/google/apiclient/docs/parameters.md
vendored
Normal file
14
vendor/google/apiclient/docs/parameters.md
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
# Standard Parameters
|
||||
|
||||
Many API methods include support for certain optional parameters. In addition to these there are several standard parameters that can be applied to any API call. These are defined in the `Google_Service_Resource` class.
|
||||
|
||||
## Parameters
|
||||
|
||||
- **alt**: Specify an alternative response type, for example csv.
|
||||
- **fields**: A comma separated list of fields that should be included in the response. Nested parameters can be specified with parens, e.g. key,parent(child/subsection).
|
||||
- **userIp**: The IP of the end-user making the request. This is used in per-user request quotas, as defined in the Google Developers Console
|
||||
- **quotaUser**: A user ID for the end user, an alternative to userIp for applying per-user request quotas
|
||||
- **data**: Used as part of [media](media.md)
|
||||
- **mimeType**: Used as part of [media](media.md)
|
||||
- **uploadType**: Used as part of [media](media.md)
|
||||
- **mediaUpload**: Used as part of [media](media.md)
|
||||
91
vendor/google/apiclient/docs/start.md
vendored
Normal file
91
vendor/google/apiclient/docs/start.md
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
# Getting Started
|
||||
|
||||
This document provides all the basic information you need to start using the library. It covers important library concepts, shows examples for various use cases, and gives links to more information.
|
||||
|
||||
## Setup
|
||||
|
||||
There are a few setup steps you need to complete before you can use this library:
|
||||
|
||||
1. If you don't already have a Google account, [sign up](https://www.google.com/accounts).
|
||||
2. If you have never created a Google API project, read the [Managing Projects page](https://developers.google.com/console/help/#managingprojects) and create a project in the [Google Developers Console](https://console.developers.google.com/)
|
||||
3. [Install](install.md) the library.
|
||||
|
||||
## Authentication and authorization
|
||||
|
||||
It is important to understand the basics of how API authentication and authorization are handled. All API calls must use either simple or authorized access (defined below). Many API methods require authorized access, but some can use either. Some API methods that can use either behave differently, depending on whether you use simple or authorized access. See the API's method documentation to determine the appropriate access type.
|
||||
|
||||
### 1. Simple API access (API keys)
|
||||
|
||||
These API calls do not access any private user data. Your application must authenticate itself as an application belonging to your Google Cloud project. This is needed to measure project usage for accounting purposes.
|
||||
|
||||
#### Important concepts
|
||||
|
||||
* **API key**: To authenticate your application, use an [API key](https://cloud.google.com/docs/authentication/api-keys) for your Google Cloud Console project. Every simple access call your application makes must include this key.
|
||||
|
||||
> **Warning**: Keep your API key private. If someone obtains your key, they could use it to consume your quota or incur charges against your Google Cloud project.
|
||||
|
||||
|
||||
### 2. Authorized API access (OAuth 2.0)
|
||||
|
||||
These API calls access private user data. Before you can call them, the user that has access to the private data must grant your application access. Therefore, your application must be authenticated, the user must grant access for your application, and the user must be authenticated in order to grant that access. All of this is accomplished with [OAuth 2.0](https://developers.google.com/identity/protocols/OAuth2) and libraries written for it.
|
||||
|
||||
#### Important concepts
|
||||
|
||||
* **Scope**: Each API defines one or more scopes that declare a set of operations permitted. For example, an API might have read-only and read-write scopes. When your application requests access to user data, the request must include one or more scopes. The user needs to approve the scope of access your application is requesting.
|
||||
* **Refresh and access tokens**: When a user grants your application access, the OAuth 2.0 authorization server provides your application with refresh and access tokens. These tokens are only valid for the scope requested. Your application uses access tokens to authorize API calls. Access tokens expire, but refresh tokens do not. Your application can use a refresh token to acquire a new access token.
|
||||
|
||||
> **Warning**: Keep refresh and access tokens private. If someone obtains your tokens, they could use them to access private user data.
|
||||
|
||||
* **Client ID and client secret**: These strings uniquely identify your application and are used to acquire tokens. They are created for your Google Cloud project on the [API Access pane](https://code.google.com/apis/console#:access) of the Google Cloud. There are three types of client IDs, so be sure to get the correct type for your application:
|
||||
|
||||
* Web application client IDs
|
||||
* Installed application client IDs
|
||||
* [Service Account](https://developers.google.com/identity/protocols/OAuth2ServiceAccount) client IDs
|
||||
|
||||
> **Warning**: Keep your client secret private. If someone obtains your client secret, they could use it to consume your quota, incur charges against your Google Cloud project, and request access to user data.
|
||||
|
||||
|
||||
## Building and calling a service
|
||||
|
||||
This section described how to build an API-specific service object, make calls to the service, and process the response.
|
||||
|
||||
### Build the client object
|
||||
|
||||
The client object is the primary container for classes and configuration in the library.
|
||||
|
||||
```php
|
||||
$client = new Google_Client();
|
||||
$client->setApplicationName("My Application");
|
||||
$client->setDeveloperKey("MY_SIMPLE_API_KEY");
|
||||
```
|
||||
|
||||
### Build the service object
|
||||
|
||||
Services are called through queries to service specific objects. These are created by constructing the service object, and passing an instance of `Google_Client` to it. `Google_Client` contains the IO, authentication and other classes required by the service to function, and the service informs the client which scopes it uses to provide a default when authenticating a user.
|
||||
|
||||
```php
|
||||
$service = new Google_Service_Books($client);
|
||||
```
|
||||
|
||||
### Calling an API
|
||||
|
||||
Each API provides resources and methods, usually in a chain. These can be accessed from the service object in the form `$service->resource->method(args)`. Most method require some arguments, then accept a final parameter of an array containing optional parameters. For example, with the Google Books API, we can make a call to list volumes matching a certain string, and add an optional _filter_ parameter.
|
||||
|
||||
```php
|
||||
$optParams = array('filter' => 'free-ebooks');
|
||||
$results = $service->volumes->listVolumes('Henry David Thoreau', $optParams);
|
||||
```
|
||||
|
||||
### Handling the result
|
||||
|
||||
There are two main types of response - items and collections of items. Each can be accessed either as an object or as an array. Collections implement the `Iterator` interface so can be used in foreach and other constructs.
|
||||
|
||||
```php
|
||||
foreach ($results as $item) {
|
||||
echo $item['volumeInfo']['title'], "<br /> \n";
|
||||
}
|
||||
```
|
||||
|
||||
## Google App Engine support
|
||||
|
||||
This library works well with Google App Engine applications. The Memcache class is automatically used for caching, and the file IO is implemented with the use of the Streams API.
|
||||
164
vendor/google/apiclient/phpcs.xml.dist
vendored
Normal file
164
vendor/google/apiclient/phpcs.xml.dist
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset name="GAPI">
|
||||
<description>The Google API client library coding standard.</description>
|
||||
|
||||
<!-- PHP code MUST use the long <?php ?> tags or the short-echo <?= ?> tags; it MUST NOT use the other tag variations. -->
|
||||
<rule ref="Generic.PHP.DisallowShortOpenTag.EchoFound">
|
||||
<severity>0</severity>
|
||||
</rule>
|
||||
|
||||
<!-- PHP code MUST use only UTF-8 without BOM. -->
|
||||
<rule ref="Generic.Files.ByteOrderMark"/>
|
||||
|
||||
<!-- Check for cross-version support for PHP 5.4 and higher. -->
|
||||
<rule ref="PHPCompatibility">
|
||||
<config name="testVersion" value="5.4-"/>
|
||||
</rule>
|
||||
|
||||
<!-- Check for duplicated class names -->
|
||||
<rule ref="Generic.Classes.DuplicateClassName" />
|
||||
|
||||
<!-- Class constants MUST be declared in all upper case with underscore separators. -->
|
||||
<rule ref="Generic.NamingConventions.UpperCaseConstantName"/>
|
||||
|
||||
<!-- Method names MUST be declared in camelCase(). -->
|
||||
<rule ref="Generic.NamingConventions.CamelCapsFunctionName">
|
||||
<properties>
|
||||
<property name="strict" value="false"/>
|
||||
</properties>
|
||||
<!-- Generated libs have some properties that break this! -->
|
||||
<exclude-pattern>Service/*.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<!-- All PHP files MUST use the Unix LF (linefeed) line ending. -->
|
||||
<rule ref="Generic.Files.LineEndings">
|
||||
<properties>
|
||||
<property name="eolChar" value="\n"/>
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
<!-- All PHP files MUST end with a single blank line. -->
|
||||
<rule ref="PSR2.Files.EndFileNewline" />
|
||||
|
||||
<!-- The closing ?> tag MUST be omitted from files containing only PHP. -->
|
||||
<rule ref="Zend.Files.ClosingTag"/>
|
||||
|
||||
<!-- The soft limit on line length MUST be 100 characters; automated style checkers MUST warn but MUST NOT error at the soft limit. -->
|
||||
<rule ref="Generic.Files.LineLength">
|
||||
<properties>
|
||||
<property name="lineLimit" value="100"/>
|
||||
<property name="absoluteLineLimit" value="120"/>
|
||||
</properties>
|
||||
<!-- Generated libs have some rather long class names that break this! -->
|
||||
<exclude-pattern>Service/*.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<!-- There MUST NOT be trailing whitespace at the end of non-blank lines. -->
|
||||
<rule ref="Squiz.WhiteSpace.SuperfluousWhitespace">
|
||||
<properties>
|
||||
<property name="ignoreBlankLines" value="true"/>
|
||||
</properties>
|
||||
</rule>
|
||||
<rule ref="Squiz.WhiteSpace.SuperfluousWhitespace.StartFile">
|
||||
<severity>0</severity>
|
||||
</rule>
|
||||
<rule ref="Squiz.WhiteSpace.SuperfluousWhitespace.EndFile">
|
||||
<severity>0</severity>
|
||||
</rule>
|
||||
<rule ref="Squiz.WhiteSpace.SuperfluousWhitespace.EmptyLines">
|
||||
<severity>0</severity>
|
||||
</rule>
|
||||
|
||||
<!-- There MUST NOT be more than one statement per line. -->
|
||||
<rule ref="Generic.Formatting.DisallowMultipleStatements"/>
|
||||
|
||||
<!-- Code MUST use an indent of 2 spaces, and MUST NOT use tabs for indenting. -->
|
||||
<rule ref="Generic.WhiteSpace.ScopeIndent">
|
||||
<properties>
|
||||
<property name="indent" value="2" />
|
||||
</properties>
|
||||
</rule>
|
||||
<rule ref="Generic.WhiteSpace.DisallowTabIndent"/>
|
||||
|
||||
<!-- PHP keywords MUST be in lower case. -->
|
||||
<rule ref="Generic.PHP.LowerCaseKeyword"/>
|
||||
|
||||
<!-- The PHP constants true, false, and null MUST be in lower case. -->
|
||||
<rule ref="Generic.PHP.LowerCaseConstant"/>
|
||||
|
||||
<!-- The extends and implements keywords MUST be declared on the same line as the class name.
|
||||
The opening brace for the class go MUST go on its own line; the closing brace for the class MUST go on the next line after the body.
|
||||
Lists of implements MAY be split across multiple lines, where each subsequent line is indented once. When doing so, the first item in the list MUST be on the next line, and there MUST be only one interface per line. -->
|
||||
<rule ref="PSR2.Classes.ClassDeclaration" />
|
||||
|
||||
|
||||
<!-- Visibility MUST be declared on all properties.
|
||||
The var keyword MUST NOT be used to declare a property.
|
||||
There MUST NOT be more than one property declared per statement.
|
||||
Property names SHOULD NOT be prefixed with a single underscore to indicate protected or private visibility. -->
|
||||
<rule ref="PSR2.Classes.PropertyDeclaration" />
|
||||
<rule ref="PSR2.Classes.PropertyDeclaration.Underscore" />
|
||||
|
||||
<!-- Visibility MUST be declared on all methods. -->
|
||||
<rule ref="Squiz.Scope.MethodScope"/>
|
||||
<rule ref="Squiz.WhiteSpace.ScopeKeywordSpacing"/>
|
||||
|
||||
|
||||
<!-- Method names MUST NOT be declared with a space after the method name. The opening brace MUST go on its own line, and the closing brace MUST go on the next line following the body. There MUST NOT be a space after the opening parenthesis, and there MUST NOT be a space before the closing parenthesis. -->
|
||||
<rule ref="Squiz.Functions.FunctionDeclaration"/>
|
||||
<rule ref="Squiz.Functions.LowercaseFunctionKeywords"/>
|
||||
|
||||
<!-- In the argument list, there MUST NOT be a space before each comma, and there MUST be one space after each comma. -->
|
||||
<rule ref="Squiz.Functions.FunctionDeclarationArgumentSpacing">
|
||||
<properties>
|
||||
<property name="equalsSpacing" value="1"/>
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
<!-- Method arguments with default values MUST go at the end of the argument list. -->
|
||||
<rule ref="PEAR.Functions.ValidDefaultValue"/>
|
||||
|
||||
<!-- Argument lists MAY be split across multiple lines, where each subsequent line is indented once. When doing so, the first item in the list MUST be on the next line, and there MUST be only one argument per line. When the argument list is split across multiple lines, the closing parenthesis and opening brace MUST be placed together on their own line with one space between them. -->
|
||||
<rule ref="Squiz.Functions.MultiLineFunctionDeclaration"/>
|
||||
|
||||
<!-- When present, the abstract and final declarations MUST precede the visibility declaration.
|
||||
When present, the static declaration MUST come after the visibility declaration. -->
|
||||
<!-- Method names SHOULD NOT be prefixed with a single underscore to indicate protected or private visibility. -->
|
||||
<rule ref="PSR2.Methods.MethodDeclaration" />
|
||||
|
||||
<!-- When making a method or function call, there MUST NOT be a space between the method or function name and the opening parenthesis, there MUST NOT be a space after the opening parenthesis, and there MUST NOT be a space before the closing parenthesis. In the argument list, there MUST NOT be a space before each comma, and there MUST be one space after each comma.
|
||||
Argument lists MAY be split across multiple lines, where each subsequent line is indented once. When doing so, the first item in the list MUST be on the next line, and there MUST be only one argument per line. -->
|
||||
<rule ref="Generic.Functions.FunctionCallArgumentSpacing"/>
|
||||
<rule ref="PEAR.Functions.FunctionCallSignature">
|
||||
<properties>
|
||||
<property name="allowMultipleArguments" value="false"/>
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
<!-- The general style rules for control structures are as follows:
|
||||
There MUST be one space after the control structure keyword
|
||||
There MUST NOT be a space after the opening parenthesis
|
||||
There MUST NOT be a space before the closing parenthesis
|
||||
There MUST be one space between the closing parenthesis and the opening brace
|
||||
The structure body MUST be indented once
|
||||
The closing brace MUST be on the next line after the body -->
|
||||
<rule ref="Squiz.ControlStructures.ControlSignature">
|
||||
<properties>
|
||||
<property name="ignoreComments" value="true"/>
|
||||
</properties>
|
||||
</rule>
|
||||
<rule ref="Squiz.WhiteSpace.ScopeClosingBrace"/>
|
||||
<rule ref="Squiz.ControlStructures.ForEachLoopDeclaration"/>
|
||||
<rule ref="Squiz.ControlStructures.ForLoopDeclaration"/>
|
||||
<rule ref="Squiz.ControlStructures.LowercaseDeclaration"/>
|
||||
|
||||
<!-- The body of each structure MUST be enclosed by braces. This standardizes how the structures look, and reduces the likelihood of introducing errors as new lines get added to the body. -->
|
||||
<rule ref="Generic.ControlStructures.InlineControlStructure"/>
|
||||
|
||||
<!-- The case statement MUST be indented once from switch, and the break keyword (or other terminating keyword) MUST be indented at the same level as the case body. There MUST be a comment such as // no break when fall-through is intentional in a non-empty case body. -->
|
||||
<rule ref="PSR2.ControlStructures.SwitchDeclaration" >
|
||||
<properties>
|
||||
<property name="indent" value="2" />
|
||||
</properties>
|
||||
</rule>
|
||||
</ruleset>
|
||||
78
vendor/google/apiclient/src/Google/AccessToken/Revoke.php
vendored
Normal file
78
vendor/google/apiclient/src/Google/AccessToken/Revoke.php
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use Google\Auth\HttpHandler\HttpHandlerFactory;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use GuzzleHttp\Psr7;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
|
||||
/**
|
||||
* Wrapper around Google Access Tokens which provides convenience functions
|
||||
*
|
||||
*/
|
||||
class Google_AccessToken_Revoke
|
||||
{
|
||||
/**
|
||||
* @var GuzzleHttp\ClientInterface The http client
|
||||
*/
|
||||
private $http;
|
||||
|
||||
/**
|
||||
* Instantiates the class, but does not initiate the login flow, leaving it
|
||||
* to the discretion of the caller.
|
||||
*/
|
||||
public function __construct(ClientInterface $http = null)
|
||||
{
|
||||
$this->http = $http;
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke an OAuth2 access token or refresh token. This method will revoke the current access
|
||||
* token, if a token isn't provided.
|
||||
*
|
||||
* @param string|array $token The token (access token or a refresh token) that should be revoked.
|
||||
* @return boolean Returns True if the revocation was successful, otherwise False.
|
||||
*/
|
||||
public function revokeToken($token)
|
||||
{
|
||||
if (is_array($token)) {
|
||||
if (isset($token['refresh_token'])) {
|
||||
$token = $token['refresh_token'];
|
||||
} else {
|
||||
$token = $token['access_token'];
|
||||
}
|
||||
}
|
||||
|
||||
$body = Psr7\stream_for(http_build_query(array('token' => $token)));
|
||||
$request = new Request(
|
||||
'POST',
|
||||
Google_Client::OAUTH2_REVOKE_URI,
|
||||
[
|
||||
'Cache-Control' => 'no-store',
|
||||
'Content-Type' => 'application/x-www-form-urlencoded',
|
||||
],
|
||||
$body
|
||||
);
|
||||
|
||||
$httpHandler = HttpHandlerFactory::build($this->http);
|
||||
|
||||
$response = $httpHandler($request);
|
||||
|
||||
return $response->getStatusCode() == 200;
|
||||
}
|
||||
}
|
||||
273
vendor/google/apiclient/src/Google/AccessToken/Verify.php
vendored
Normal file
273
vendor/google/apiclient/src/Google/AccessToken/Verify.php
vendored
Normal file
@@ -0,0 +1,273 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use Firebase\JWT\ExpiredException as ExpiredExceptionV3;
|
||||
use Firebase\JWT\SignatureInvalidException;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Google\Auth\Cache\MemoryCacheItemPool;
|
||||
use Stash\Driver\FileSystem;
|
||||
use Stash\Pool;
|
||||
|
||||
/**
|
||||
* Wrapper around Google Access Tokens which provides convenience functions
|
||||
*
|
||||
*/
|
||||
class Google_AccessToken_Verify
|
||||
{
|
||||
const FEDERATED_SIGNON_CERT_URL = 'https://www.googleapis.com/oauth2/v3/certs';
|
||||
const OAUTH2_ISSUER = 'accounts.google.com';
|
||||
const OAUTH2_ISSUER_HTTPS = 'https://accounts.google.com';
|
||||
|
||||
/**
|
||||
* @var GuzzleHttp\ClientInterface The http client
|
||||
*/
|
||||
private $http;
|
||||
|
||||
/**
|
||||
* @var Psr\Cache\CacheItemPoolInterface cache class
|
||||
*/
|
||||
private $cache;
|
||||
|
||||
/**
|
||||
* Instantiates the class, but does not initiate the login flow, leaving it
|
||||
* to the discretion of the caller.
|
||||
*/
|
||||
public function __construct(
|
||||
ClientInterface $http = null,
|
||||
CacheItemPoolInterface $cache = null,
|
||||
$jwt = null
|
||||
) {
|
||||
if (null === $http) {
|
||||
$http = new Client();
|
||||
}
|
||||
|
||||
if (null === $cache) {
|
||||
$cache = new MemoryCacheItemPool;
|
||||
}
|
||||
|
||||
$this->http = $http;
|
||||
$this->cache = $cache;
|
||||
$this->jwt = $jwt ?: $this->getJwtService();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies an id token and returns the authenticated apiLoginTicket.
|
||||
* Throws an exception if the id token is not valid.
|
||||
* The audience parameter can be used to control which id tokens are
|
||||
* accepted. By default, the id token must have been issued to this OAuth2 client.
|
||||
*
|
||||
* @param $audience
|
||||
* @return array the token payload, if successful
|
||||
*/
|
||||
public function verifyIdToken($idToken, $audience = null)
|
||||
{
|
||||
if (empty($idToken)) {
|
||||
throw new LogicException('id_token cannot be null');
|
||||
}
|
||||
|
||||
// set phpseclib constants if applicable
|
||||
$this->setPhpsecConstants();
|
||||
|
||||
// Check signature
|
||||
$certs = $this->getFederatedSignOnCerts();
|
||||
foreach ($certs as $cert) {
|
||||
$bigIntClass = $this->getBigIntClass();
|
||||
$rsaClass = $this->getRsaClass();
|
||||
$modulus = new $bigIntClass($this->jwt->urlsafeB64Decode($cert['n']), 256);
|
||||
$exponent = new $bigIntClass($this->jwt->urlsafeB64Decode($cert['e']), 256);
|
||||
|
||||
$rsa = new $rsaClass();
|
||||
$rsa->loadKey(array('n' => $modulus, 'e' => $exponent));
|
||||
|
||||
try {
|
||||
$payload = $this->jwt->decode(
|
||||
$idToken,
|
||||
$rsa->getPublicKey(),
|
||||
array('RS256')
|
||||
);
|
||||
|
||||
if (property_exists($payload, 'aud')) {
|
||||
if ($audience && $payload->aud != $audience) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// support HTTP and HTTPS issuers
|
||||
// @see https://developers.google.com/identity/sign-in/web/backend-auth
|
||||
$issuers = array(self::OAUTH2_ISSUER, self::OAUTH2_ISSUER_HTTPS);
|
||||
if (!isset($payload->iss) || !in_array($payload->iss, $issuers)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (array) $payload;
|
||||
} catch (ExpiredException $e) {
|
||||
return false;
|
||||
} catch (ExpiredExceptionV3 $e) {
|
||||
return false;
|
||||
} catch (SignatureInvalidException $e) {
|
||||
// continue
|
||||
} catch (DomainException $e) {
|
||||
// continue
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function getCache()
|
||||
{
|
||||
return $this->cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve and cache a certificates file.
|
||||
*
|
||||
* @param $url string location
|
||||
* @throws Google_Exception
|
||||
* @return array certificates
|
||||
*/
|
||||
private function retrieveCertsFromLocation($url)
|
||||
{
|
||||
// If we're retrieving a local file, just grab it.
|
||||
if (0 !== strpos($url, 'http')) {
|
||||
if (!$file = file_get_contents($url)) {
|
||||
throw new Google_Exception(
|
||||
"Failed to retrieve verification certificates: '" .
|
||||
$url . "'."
|
||||
);
|
||||
}
|
||||
|
||||
return json_decode($file, true);
|
||||
}
|
||||
|
||||
$response = $this->http->get($url);
|
||||
|
||||
if ($response->getStatusCode() == 200) {
|
||||
return json_decode((string) $response->getBody(), true);
|
||||
}
|
||||
throw new Google_Exception(
|
||||
sprintf(
|
||||
'Failed to retrieve verification certificates: "%s".',
|
||||
$response->getBody()->getContents()
|
||||
),
|
||||
$response->getStatusCode()
|
||||
);
|
||||
}
|
||||
|
||||
// Gets federated sign-on certificates to use for verifying identity tokens.
|
||||
// Returns certs as array structure, where keys are key ids, and values
|
||||
// are PEM encoded certificates.
|
||||
private function getFederatedSignOnCerts()
|
||||
{
|
||||
$certs = null;
|
||||
if ($cache = $this->getCache()) {
|
||||
$cacheItem = $cache->getItem('federated_signon_certs_v3');
|
||||
$certs = $cacheItem->get();
|
||||
}
|
||||
|
||||
|
||||
if (!$certs) {
|
||||
$certs = $this->retrieveCertsFromLocation(
|
||||
self::FEDERATED_SIGNON_CERT_URL
|
||||
);
|
||||
|
||||
if ($cache) {
|
||||
$cacheItem->expiresAt(new DateTime('+1 hour'));
|
||||
$cacheItem->set($certs);
|
||||
$cache->save($cacheItem);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($certs['keys'])) {
|
||||
throw new InvalidArgumentException(
|
||||
'federated sign-on certs expects "keys" to be set'
|
||||
);
|
||||
}
|
||||
|
||||
return $certs['keys'];
|
||||
}
|
||||
|
||||
private function getJwtService()
|
||||
{
|
||||
$jwtClass = 'JWT';
|
||||
if (class_exists('\Firebase\JWT\JWT')) {
|
||||
$jwtClass = 'Firebase\JWT\JWT';
|
||||
}
|
||||
|
||||
if (property_exists($jwtClass, 'leeway') && $jwtClass::$leeway < 1) {
|
||||
// Ensures JWT leeway is at least 1
|
||||
// @see https://github.com/google/google-api-php-client/issues/827
|
||||
$jwtClass::$leeway = 1;
|
||||
}
|
||||
|
||||
return new $jwtClass;
|
||||
}
|
||||
|
||||
private function getRsaClass()
|
||||
{
|
||||
if (class_exists('phpseclib\Crypt\RSA')) {
|
||||
return 'phpseclib\Crypt\RSA';
|
||||
}
|
||||
|
||||
return 'Crypt_RSA';
|
||||
}
|
||||
|
||||
private function getBigIntClass()
|
||||
{
|
||||
if (class_exists('phpseclib\Math\BigInteger')) {
|
||||
return 'phpseclib\Math\BigInteger';
|
||||
}
|
||||
|
||||
return 'Math_BigInteger';
|
||||
}
|
||||
|
||||
private function getOpenSslConstant()
|
||||
{
|
||||
if (class_exists('phpseclib\Crypt\RSA')) {
|
||||
return 'phpseclib\Crypt\RSA::MODE_OPENSSL';
|
||||
}
|
||||
|
||||
if (class_exists('Crypt_RSA')) {
|
||||
return 'CRYPT_RSA_MODE_OPENSSL';
|
||||
}
|
||||
|
||||
throw new \Exception('Cannot find RSA class');
|
||||
}
|
||||
|
||||
/**
|
||||
* phpseclib calls "phpinfo" by default, which requires special
|
||||
* whitelisting in the AppEngine VM environment. This function
|
||||
* sets constants to bypass the need for phpseclib to check phpinfo
|
||||
*
|
||||
* @see phpseclib/Math/BigInteger
|
||||
* @see https://github.com/GoogleCloudPlatform/getting-started-php/issues/85
|
||||
*/
|
||||
private function setPhpsecConstants()
|
||||
{
|
||||
if (filter_var(getenv('GAE_VM'), FILTER_VALIDATE_BOOLEAN)) {
|
||||
if (!defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
|
||||
define('MATH_BIGINTEGER_OPENSSL_ENABLED', true);
|
||||
}
|
||||
if (!defined('CRYPT_RSA_MODE')) {
|
||||
define('CRYPT_RSA_MODE', constant($this->getOpenSslConstant()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
42
vendor/google/apiclient/src/Google/AuthHandler/AuthHandlerFactory.php
vendored
Normal file
42
vendor/google/apiclient/src/Google/AuthHandler/AuthHandlerFactory.php
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
|
||||
class Google_AuthHandler_AuthHandlerFactory
|
||||
{
|
||||
/**
|
||||
* Builds out a default http handler for the installed version of guzzle.
|
||||
*
|
||||
* @return Google_AuthHandler_Guzzle5AuthHandler|Google_AuthHandler_Guzzle6AuthHandler
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function build($cache = null, array $cacheConfig = [])
|
||||
{
|
||||
$version = ClientInterface::VERSION;
|
||||
|
||||
switch ($version[0]) {
|
||||
case '5':
|
||||
return new Google_AuthHandler_Guzzle5AuthHandler($cache, $cacheConfig);
|
||||
case '6':
|
||||
return new Google_AuthHandler_Guzzle6AuthHandler($cache, $cacheConfig);
|
||||
default:
|
||||
throw new Exception('Version not supported');
|
||||
}
|
||||
}
|
||||
}
|
||||
99
vendor/google/apiclient/src/Google/AuthHandler/Guzzle5AuthHandler.php
vendored
Normal file
99
vendor/google/apiclient/src/Google/AuthHandler/Guzzle5AuthHandler.php
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
use Google\Auth\CredentialsLoader;
|
||||
use Google\Auth\HttpHandler\HttpHandlerFactory;
|
||||
use Google\Auth\FetchAuthTokenCache;
|
||||
use Google\Auth\Subscriber\AuthTokenSubscriber;
|
||||
use Google\Auth\Subscriber\ScopedAccessTokenSubscriber;
|
||||
use Google\Auth\Subscriber\SimpleSubscriber;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class Google_AuthHandler_Guzzle5AuthHandler
|
||||
{
|
||||
protected $cache;
|
||||
protected $cacheConfig;
|
||||
|
||||
public function __construct(CacheItemPoolInterface $cache = null, array $cacheConfig = [])
|
||||
{
|
||||
$this->cache = $cache;
|
||||
$this->cacheConfig = $cacheConfig;
|
||||
}
|
||||
|
||||
public function attachCredentials(
|
||||
ClientInterface $http,
|
||||
CredentialsLoader $credentials,
|
||||
callable $tokenCallback = null
|
||||
) {
|
||||
// use the provided cache
|
||||
if ($this->cache) {
|
||||
$credentials = new FetchAuthTokenCache(
|
||||
$credentials,
|
||||
$this->cacheConfig,
|
||||
$this->cache
|
||||
);
|
||||
}
|
||||
// if we end up needing to make an HTTP request to retrieve credentials, we
|
||||
// can use our existing one, but we need to throw exceptions so the error
|
||||
// bubbles up.
|
||||
$authHttp = $this->createAuthHttp($http);
|
||||
$authHttpHandler = HttpHandlerFactory::build($authHttp);
|
||||
$subscriber = new AuthTokenSubscriber(
|
||||
$credentials,
|
||||
$authHttpHandler,
|
||||
$tokenCallback
|
||||
);
|
||||
|
||||
$http->setDefaultOption('auth', 'google_auth');
|
||||
$http->getEmitter()->attach($subscriber);
|
||||
|
||||
return $http;
|
||||
}
|
||||
|
||||
public function attachToken(ClientInterface $http, array $token, array $scopes)
|
||||
{
|
||||
$tokenFunc = function ($scopes) use ($token) {
|
||||
return $token['access_token'];
|
||||
};
|
||||
|
||||
$subscriber = new ScopedAccessTokenSubscriber(
|
||||
$tokenFunc,
|
||||
$scopes,
|
||||
$this->cacheConfig,
|
||||
$this->cache
|
||||
);
|
||||
|
||||
$http->setDefaultOption('auth', 'scoped');
|
||||
$http->getEmitter()->attach($subscriber);
|
||||
|
||||
return $http;
|
||||
}
|
||||
|
||||
public function attachKey(ClientInterface $http, $key)
|
||||
{
|
||||
$subscriber = new SimpleSubscriber(['key' => $key]);
|
||||
|
||||
$http->setDefaultOption('auth', 'simple');
|
||||
$http->getEmitter()->attach($subscriber);
|
||||
|
||||
return $http;
|
||||
}
|
||||
|
||||
private function createAuthHttp(ClientInterface $http)
|
||||
{
|
||||
return new Client(
|
||||
[
|
||||
'base_url' => $http->getBaseUrl(),
|
||||
'defaults' => [
|
||||
'exceptions' => true,
|
||||
'verify' => $http->getDefaultOption('verify'),
|
||||
'proxy' => $http->getDefaultOption('proxy'),
|
||||
]
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
106
vendor/google/apiclient/src/Google/AuthHandler/Guzzle6AuthHandler.php
vendored
Normal file
106
vendor/google/apiclient/src/Google/AuthHandler/Guzzle6AuthHandler.php
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
use Google\Auth\CredentialsLoader;
|
||||
use Google\Auth\HttpHandler\HttpHandlerFactory;
|
||||
use Google\Auth\FetchAuthTokenCache;
|
||||
use Google\Auth\Middleware\AuthTokenMiddleware;
|
||||
use Google\Auth\Middleware\ScopedAccessTokenMiddleware;
|
||||
use Google\Auth\Middleware\SimpleMiddleware;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class Google_AuthHandler_Guzzle6AuthHandler
|
||||
{
|
||||
protected $cache;
|
||||
protected $cacheConfig;
|
||||
|
||||
public function __construct(CacheItemPoolInterface $cache = null, array $cacheConfig = [])
|
||||
{
|
||||
$this->cache = $cache;
|
||||
$this->cacheConfig = $cacheConfig;
|
||||
}
|
||||
|
||||
public function attachCredentials(
|
||||
ClientInterface $http,
|
||||
CredentialsLoader $credentials,
|
||||
callable $tokenCallback = null
|
||||
) {
|
||||
// use the provided cache
|
||||
if ($this->cache) {
|
||||
$credentials = new FetchAuthTokenCache(
|
||||
$credentials,
|
||||
$this->cacheConfig,
|
||||
$this->cache
|
||||
);
|
||||
}
|
||||
// if we end up needing to make an HTTP request to retrieve credentials, we
|
||||
// can use our existing one, but we need to throw exceptions so the error
|
||||
// bubbles up.
|
||||
$authHttp = $this->createAuthHttp($http);
|
||||
$authHttpHandler = HttpHandlerFactory::build($authHttp);
|
||||
$middleware = new AuthTokenMiddleware(
|
||||
$credentials,
|
||||
$authHttpHandler,
|
||||
$tokenCallback
|
||||
);
|
||||
|
||||
$config = $http->getConfig();
|
||||
$config['handler']->remove('google_auth');
|
||||
$config['handler']->push($middleware, 'google_auth');
|
||||
$config['auth'] = 'google_auth';
|
||||
$http = new Client($config);
|
||||
|
||||
return $http;
|
||||
}
|
||||
|
||||
public function attachToken(ClientInterface $http, array $token, array $scopes)
|
||||
{
|
||||
$tokenFunc = function ($scopes) use ($token) {
|
||||
return $token['access_token'];
|
||||
};
|
||||
|
||||
$middleware = new ScopedAccessTokenMiddleware(
|
||||
$tokenFunc,
|
||||
$scopes,
|
||||
$this->cacheConfig,
|
||||
$this->cache
|
||||
);
|
||||
|
||||
$config = $http->getConfig();
|
||||
$config['handler']->remove('google_auth');
|
||||
$config['handler']->push($middleware, 'google_auth');
|
||||
$config['auth'] = 'scoped';
|
||||
$http = new Client($config);
|
||||
|
||||
return $http;
|
||||
}
|
||||
|
||||
public function attachKey(ClientInterface $http, $key)
|
||||
{
|
||||
$middleware = new SimpleMiddleware(['key' => $key]);
|
||||
|
||||
$config = $http->getConfig();
|
||||
$config['handler']->remove('google_auth');
|
||||
$config['handler']->push($middleware, 'google_auth');
|
||||
$config['auth'] = 'simple';
|
||||
$http = new Client($config);
|
||||
|
||||
return $http;
|
||||
}
|
||||
|
||||
private function createAuthHttp(ClientInterface $http)
|
||||
{
|
||||
return new Client(
|
||||
[
|
||||
'base_uri' => $http->getConfig('base_uri'),
|
||||
'exceptions' => true,
|
||||
'verify' => $http->getConfig('verify'),
|
||||
'proxy' => $http->getConfig('proxy'),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
1173
vendor/google/apiclient/src/Google/Client.php
vendored
Normal file
1173
vendor/google/apiclient/src/Google/Client.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
100
vendor/google/apiclient/src/Google/Collection.php
vendored
Normal file
100
vendor/google/apiclient/src/Google/Collection.php
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
if (!class_exists('Google_Client')) {
|
||||
require_once __DIR__ . '/autoload.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension to the regular Google_Model that automatically
|
||||
* exposes the items array for iteration, so you can just
|
||||
* iterate over the object rather than a reference inside.
|
||||
*/
|
||||
class Google_Collection extends Google_Model implements Iterator, Countable
|
||||
{
|
||||
protected $collection_key = 'items';
|
||||
|
||||
public function rewind()
|
||||
{
|
||||
if (isset($this->{$this->collection_key})
|
||||
&& is_array($this->{$this->collection_key})) {
|
||||
reset($this->{$this->collection_key});
|
||||
}
|
||||
}
|
||||
|
||||
public function current()
|
||||
{
|
||||
$this->coerceType($this->key());
|
||||
if (is_array($this->{$this->collection_key})) {
|
||||
return current($this->{$this->collection_key});
|
||||
}
|
||||
}
|
||||
|
||||
public function key()
|
||||
{
|
||||
if (isset($this->{$this->collection_key})
|
||||
&& is_array($this->{$this->collection_key})) {
|
||||
return key($this->{$this->collection_key});
|
||||
}
|
||||
}
|
||||
|
||||
public function next()
|
||||
{
|
||||
return next($this->{$this->collection_key});
|
||||
}
|
||||
|
||||
public function valid()
|
||||
{
|
||||
$key = $this->key();
|
||||
return $key !== null && $key !== false;
|
||||
}
|
||||
|
||||
public function count()
|
||||
{
|
||||
if (!isset($this->{$this->collection_key})) {
|
||||
return 0;
|
||||
}
|
||||
return count($this->{$this->collection_key});
|
||||
}
|
||||
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
if (!is_numeric($offset)) {
|
||||
return parent::offsetExists($offset);
|
||||
}
|
||||
return isset($this->{$this->collection_key}[$offset]);
|
||||
}
|
||||
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
if (!is_numeric($offset)) {
|
||||
return parent::offsetGet($offset);
|
||||
}
|
||||
$this->coerceType($offset);
|
||||
return $this->{$this->collection_key}[$offset];
|
||||
}
|
||||
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
if (!is_numeric($offset)) {
|
||||
return parent::offsetSet($offset, $value);
|
||||
}
|
||||
$this->{$this->collection_key}[$offset] = $value;
|
||||
}
|
||||
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
if (!is_numeric($offset)) {
|
||||
return parent::offsetUnset($offset);
|
||||
}
|
||||
unset($this->{$this->collection_key}[$offset]);
|
||||
}
|
||||
|
||||
private function coerceType($offset)
|
||||
{
|
||||
$keyType = $this->keyType($this->collection_key);
|
||||
if ($keyType && !is_object($this->{$this->collection_key}[$offset])) {
|
||||
$this->{$this->collection_key}[$offset] =
|
||||
new $keyType($this->{$this->collection_key}[$offset]);
|
||||
}
|
||||
}
|
||||
}
|
||||
20
vendor/google/apiclient/src/Google/Exception.php
vendored
Normal file
20
vendor/google/apiclient/src/Google/Exception.php
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Google_Exception extends Exception
|
||||
{
|
||||
}
|
||||
253
vendor/google/apiclient/src/Google/Http/Batch.php
vendored
Normal file
253
vendor/google/apiclient/src/Google/Http/Batch.php
vendored
Normal file
@@ -0,0 +1,253 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use GuzzleHttp\Psr7;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* Class to handle batched requests to the Google API service.
|
||||
*
|
||||
* Note that calls to `Google_Http_Batch::execute()` do not clear the queued
|
||||
* requests. To start a new batch, be sure to create a new instance of this
|
||||
* class.
|
||||
*/
|
||||
class Google_Http_Batch
|
||||
{
|
||||
const BATCH_PATH = 'batch';
|
||||
|
||||
private static $CONNECTION_ESTABLISHED_HEADERS = array(
|
||||
"HTTP/1.0 200 Connection established\r\n\r\n",
|
||||
"HTTP/1.1 200 Connection established\r\n\r\n",
|
||||
);
|
||||
|
||||
/** @var string Multipart Boundary. */
|
||||
private $boundary;
|
||||
|
||||
/** @var array service requests to be executed. */
|
||||
private $requests = array();
|
||||
|
||||
/** @var Google_Client */
|
||||
private $client;
|
||||
|
||||
private $rootUrl;
|
||||
|
||||
private $batchPath;
|
||||
|
||||
public function __construct(
|
||||
Google_Client $client,
|
||||
$boundary = false,
|
||||
$rootUrl = null,
|
||||
$batchPath = null
|
||||
) {
|
||||
$this->client = $client;
|
||||
$this->boundary = $boundary ?: mt_rand();
|
||||
$this->rootUrl = rtrim($rootUrl ?: $this->client->getConfig('base_path'), '/');
|
||||
$this->batchPath = $batchPath ?: self::BATCH_PATH;
|
||||
}
|
||||
|
||||
public function add(RequestInterface $request, $key = false)
|
||||
{
|
||||
if (false == $key) {
|
||||
$key = mt_rand();
|
||||
}
|
||||
|
||||
$this->requests[$key] = $request;
|
||||
}
|
||||
|
||||
public function execute()
|
||||
{
|
||||
$body = '';
|
||||
$classes = array();
|
||||
$batchHttpTemplate = <<<EOF
|
||||
--%s
|
||||
Content-Type: application/http
|
||||
Content-Transfer-Encoding: binary
|
||||
MIME-Version: 1.0
|
||||
Content-ID: %s
|
||||
|
||||
%s
|
||||
%s%s
|
||||
|
||||
|
||||
EOF;
|
||||
|
||||
/** @var Google_Http_Request $req */
|
||||
foreach ($this->requests as $key => $request) {
|
||||
$firstLine = sprintf(
|
||||
'%s %s HTTP/%s',
|
||||
$request->getMethod(),
|
||||
$request->getRequestTarget(),
|
||||
$request->getProtocolVersion()
|
||||
);
|
||||
|
||||
$content = (string) $request->getBody();
|
||||
|
||||
$headers = '';
|
||||
foreach ($request->getHeaders() as $name => $values) {
|
||||
$headers .= sprintf("%s:%s\r\n", $name, implode(', ', $values));
|
||||
}
|
||||
|
||||
$body .= sprintf(
|
||||
$batchHttpTemplate,
|
||||
$this->boundary,
|
||||
$key,
|
||||
$firstLine,
|
||||
$headers,
|
||||
$content ? "\n".$content : ''
|
||||
);
|
||||
|
||||
$classes['response-' . $key] = $request->getHeaderLine('X-Php-Expected-Class');
|
||||
}
|
||||
|
||||
$body .= "--{$this->boundary}--";
|
||||
$body = trim($body);
|
||||
$url = $this->rootUrl . '/' . $this->batchPath;
|
||||
$headers = array(
|
||||
'Content-Type' => sprintf('multipart/mixed; boundary=%s', $this->boundary),
|
||||
'Content-Length' => strlen($body),
|
||||
);
|
||||
|
||||
$request = new Request(
|
||||
'POST',
|
||||
$url,
|
||||
$headers,
|
||||
$body
|
||||
);
|
||||
|
||||
$response = $this->client->execute($request);
|
||||
|
||||
return $this->parseResponse($response, $classes);
|
||||
}
|
||||
|
||||
public function parseResponse(ResponseInterface $response, $classes = array())
|
||||
{
|
||||
$contentType = $response->getHeaderLine('content-type');
|
||||
$contentType = explode(';', $contentType);
|
||||
$boundary = false;
|
||||
foreach ($contentType as $part) {
|
||||
$part = explode('=', $part, 2);
|
||||
if (isset($part[0]) && 'boundary' == trim($part[0])) {
|
||||
$boundary = $part[1];
|
||||
}
|
||||
}
|
||||
|
||||
$body = (string) $response->getBody();
|
||||
if (!empty($body)) {
|
||||
$body = str_replace("--$boundary--", "--$boundary", $body);
|
||||
$parts = explode("--$boundary", $body);
|
||||
$responses = array();
|
||||
$requests = array_values($this->requests);
|
||||
|
||||
foreach ($parts as $i => $part) {
|
||||
$part = trim($part);
|
||||
if (!empty($part)) {
|
||||
list($rawHeaders, $part) = explode("\r\n\r\n", $part, 2);
|
||||
$headers = $this->parseRawHeaders($rawHeaders);
|
||||
|
||||
$status = substr($part, 0, strpos($part, "\n"));
|
||||
$status = explode(" ", $status);
|
||||
$status = $status[1];
|
||||
|
||||
list($partHeaders, $partBody) = $this->parseHttpResponse($part, false);
|
||||
$response = new Response(
|
||||
$status,
|
||||
$partHeaders,
|
||||
Psr7\stream_for($partBody)
|
||||
);
|
||||
|
||||
// Need content id.
|
||||
$key = $headers['content-id'];
|
||||
|
||||
try {
|
||||
$response = Google_Http_REST::decodeHttpResponse($response, $requests[$i-1]);
|
||||
} catch (Google_Service_Exception $e) {
|
||||
// Store the exception as the response, so successful responses
|
||||
// can be processed.
|
||||
$response = $e;
|
||||
}
|
||||
|
||||
$responses[$key] = $response;
|
||||
}
|
||||
}
|
||||
|
||||
return $responses;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function parseRawHeaders($rawHeaders)
|
||||
{
|
||||
$headers = array();
|
||||
$responseHeaderLines = explode("\r\n", $rawHeaders);
|
||||
foreach ($responseHeaderLines as $headerLine) {
|
||||
if ($headerLine && strpos($headerLine, ':') !== false) {
|
||||
list($header, $value) = explode(': ', $headerLine, 2);
|
||||
$header = strtolower($header);
|
||||
if (isset($headers[$header])) {
|
||||
$headers[$header] .= "\n" . $value;
|
||||
} else {
|
||||
$headers[$header] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by the IO lib and also the batch processing.
|
||||
*
|
||||
* @param $respData
|
||||
* @param $headerSize
|
||||
* @return array
|
||||
*/
|
||||
private function parseHttpResponse($respData, $headerSize)
|
||||
{
|
||||
// check proxy header
|
||||
foreach (self::$CONNECTION_ESTABLISHED_HEADERS as $established_header) {
|
||||
if (stripos($respData, $established_header) !== false) {
|
||||
// existed, remove it
|
||||
$respData = str_ireplace($established_header, '', $respData);
|
||||
// Subtract the proxy header size unless the cURL bug prior to 7.30.0
|
||||
// is present which prevented the proxy header size from being taken into
|
||||
// account.
|
||||
// @TODO look into this
|
||||
// if (!$this->needsQuirk()) {
|
||||
// $headerSize -= strlen($established_header);
|
||||
// }
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($headerSize) {
|
||||
$responseBody = substr($respData, $headerSize);
|
||||
$responseHeaders = substr($respData, 0, $headerSize);
|
||||
} else {
|
||||
$responseSegments = explode("\r\n\r\n", $respData, 2);
|
||||
$responseHeaders = $responseSegments[0];
|
||||
$responseBody = isset($responseSegments[1]) ? $responseSegments[1] :
|
||||
null;
|
||||
}
|
||||
|
||||
$responseHeaders = $this->parseRawHeaders($responseHeaders);
|
||||
|
||||
return array($responseHeaders, $responseBody);
|
||||
}
|
||||
}
|
||||
351
vendor/google/apiclient/src/Google/Http/MediaFileUpload.php
vendored
Normal file
351
vendor/google/apiclient/src/Google/Http/MediaFileUpload.php
vendored
Normal file
@@ -0,0 +1,351 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use GuzzleHttp\Psr7;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use GuzzleHttp\Psr7\Uri;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
/**
|
||||
* Manage large file uploads, which may be media but can be any type
|
||||
* of sizable data.
|
||||
*/
|
||||
class Google_Http_MediaFileUpload
|
||||
{
|
||||
const UPLOAD_MEDIA_TYPE = 'media';
|
||||
const UPLOAD_MULTIPART_TYPE = 'multipart';
|
||||
const UPLOAD_RESUMABLE_TYPE = 'resumable';
|
||||
|
||||
/** @var string $mimeType */
|
||||
private $mimeType;
|
||||
|
||||
/** @var string $data */
|
||||
private $data;
|
||||
|
||||
/** @var bool $resumable */
|
||||
private $resumable;
|
||||
|
||||
/** @var int $chunkSize */
|
||||
private $chunkSize;
|
||||
|
||||
/** @var int $size */
|
||||
private $size;
|
||||
|
||||
/** @var string $resumeUri */
|
||||
private $resumeUri;
|
||||
|
||||
/** @var int $progress */
|
||||
private $progress;
|
||||
|
||||
/** @var Google_Client */
|
||||
private $client;
|
||||
|
||||
/** @var Psr\Http\Message\RequestInterface */
|
||||
private $request;
|
||||
|
||||
/** @var string */
|
||||
private $boundary;
|
||||
|
||||
/**
|
||||
* Result code from last HTTP call
|
||||
* @var int
|
||||
*/
|
||||
private $httpResultCode;
|
||||
|
||||
/**
|
||||
* @param $mimeType string
|
||||
* @param $data string The bytes you want to upload.
|
||||
* @param $resumable bool
|
||||
* @param bool $chunkSize File will be uploaded in chunks of this many bytes.
|
||||
* only used if resumable=True
|
||||
*/
|
||||
public function __construct(
|
||||
Google_Client $client,
|
||||
RequestInterface $request,
|
||||
$mimeType,
|
||||
$data,
|
||||
$resumable = false,
|
||||
$chunkSize = false
|
||||
) {
|
||||
$this->client = $client;
|
||||
$this->request = $request;
|
||||
$this->mimeType = $mimeType;
|
||||
$this->data = $data;
|
||||
$this->resumable = $resumable;
|
||||
$this->chunkSize = $chunkSize;
|
||||
$this->progress = 0;
|
||||
|
||||
$this->process();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the size of the file that is being uploaded.
|
||||
* @param $size - int file size in bytes
|
||||
*/
|
||||
public function setFileSize($size)
|
||||
{
|
||||
$this->size = $size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the progress on the upload
|
||||
* @return int progress in bytes uploaded.
|
||||
*/
|
||||
public function getProgress()
|
||||
{
|
||||
return $this->progress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the next part of the file to upload.
|
||||
* @param [$chunk] the next set of bytes to send. If false will used $data passed
|
||||
* at construct time.
|
||||
*/
|
||||
public function nextChunk($chunk = false)
|
||||
{
|
||||
$resumeUri = $this->getResumeUri();
|
||||
|
||||
if (false == $chunk) {
|
||||
$chunk = substr($this->data, $this->progress, $this->chunkSize);
|
||||
}
|
||||
|
||||
$lastBytePos = $this->progress + strlen($chunk) - 1;
|
||||
$headers = array(
|
||||
'content-range' => "bytes $this->progress-$lastBytePos/$this->size",
|
||||
'content-length' => strlen($chunk),
|
||||
'expect' => '',
|
||||
);
|
||||
|
||||
$request = new Request(
|
||||
'PUT',
|
||||
$resumeUri,
|
||||
$headers,
|
||||
Psr7\stream_for($chunk)
|
||||
);
|
||||
|
||||
return $this->makePutRequest($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the HTTP result code from the last call made.
|
||||
* @return int code
|
||||
*/
|
||||
public function getHttpResultCode()
|
||||
{
|
||||
return $this->httpResultCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a PUT-Request to google drive and parses the response,
|
||||
* setting the appropiate variables from the response()
|
||||
*
|
||||
* @param Google_Http_Request $httpRequest the Reuqest which will be send
|
||||
*
|
||||
* @return false|mixed false when the upload is unfinished or the decoded http response
|
||||
*
|
||||
*/
|
||||
private function makePutRequest(RequestInterface $request)
|
||||
{
|
||||
$response = $this->client->execute($request);
|
||||
$this->httpResultCode = $response->getStatusCode();
|
||||
|
||||
if (308 == $this->httpResultCode) {
|
||||
// Track the amount uploaded.
|
||||
$range = $response->getHeaderLine('range');
|
||||
if ($range) {
|
||||
$range_array = explode('-', $range);
|
||||
$this->progress = $range_array[1] + 1;
|
||||
}
|
||||
|
||||
// Allow for changing upload URLs.
|
||||
$location = $response->getHeaderLine('location');
|
||||
if ($location) {
|
||||
$this->resumeUri = $location;
|
||||
}
|
||||
|
||||
// No problems, but upload not complete.
|
||||
return false;
|
||||
}
|
||||
|
||||
return Google_Http_REST::decodeHttpResponse($response, $this->request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume a previously unfinished upload
|
||||
* @param $resumeUri the resume-URI of the unfinished, resumable upload.
|
||||
*/
|
||||
public function resume($resumeUri)
|
||||
{
|
||||
$this->resumeUri = $resumeUri;
|
||||
$headers = array(
|
||||
'content-range' => "bytes */$this->size",
|
||||
'content-length' => 0,
|
||||
);
|
||||
$httpRequest = new Request(
|
||||
'PUT',
|
||||
$this->resumeUri,
|
||||
$headers
|
||||
);
|
||||
|
||||
return $this->makePutRequest($httpRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Psr\Http\Message\RequestInterface $request
|
||||
* @visible for testing
|
||||
*/
|
||||
private function process()
|
||||
{
|
||||
$this->transformToUploadUrl();
|
||||
$request = $this->request;
|
||||
|
||||
$postBody = '';
|
||||
$contentType = false;
|
||||
|
||||
$meta = (string) $request->getBody();
|
||||
$meta = is_string($meta) ? json_decode($meta, true) : $meta;
|
||||
|
||||
$uploadType = $this->getUploadType($meta);
|
||||
$request = $request->withUri(
|
||||
Uri::withQueryValue($request->getUri(), 'uploadType', $uploadType)
|
||||
);
|
||||
|
||||
$mimeType = $this->mimeType ?: $request->getHeaderLine('content-type');
|
||||
|
||||
if (self::UPLOAD_RESUMABLE_TYPE == $uploadType) {
|
||||
$contentType = $mimeType;
|
||||
$postBody = is_string($meta) ? $meta : json_encode($meta);
|
||||
} else if (self::UPLOAD_MEDIA_TYPE == $uploadType) {
|
||||
$contentType = $mimeType;
|
||||
$postBody = $this->data;
|
||||
} else if (self::UPLOAD_MULTIPART_TYPE == $uploadType) {
|
||||
// This is a multipart/related upload.
|
||||
$boundary = $this->boundary ?: mt_rand();
|
||||
$boundary = str_replace('"', '', $boundary);
|
||||
$contentType = 'multipart/related; boundary=' . $boundary;
|
||||
$related = "--$boundary\r\n";
|
||||
$related .= "Content-Type: application/json; charset=UTF-8\r\n";
|
||||
$related .= "\r\n" . json_encode($meta) . "\r\n";
|
||||
$related .= "--$boundary\r\n";
|
||||
$related .= "Content-Type: $mimeType\r\n";
|
||||
$related .= "Content-Transfer-Encoding: base64\r\n";
|
||||
$related .= "\r\n" . base64_encode($this->data) . "\r\n";
|
||||
$related .= "--$boundary--";
|
||||
$postBody = $related;
|
||||
}
|
||||
|
||||
$request = $request->withBody(Psr7\stream_for($postBody));
|
||||
|
||||
if (isset($contentType) && $contentType) {
|
||||
$request = $request->withHeader('content-type', $contentType);
|
||||
}
|
||||
|
||||
return $this->request = $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Valid upload types:
|
||||
* - resumable (UPLOAD_RESUMABLE_TYPE)
|
||||
* - media (UPLOAD_MEDIA_TYPE)
|
||||
* - multipart (UPLOAD_MULTIPART_TYPE)
|
||||
* @param $meta
|
||||
* @return string
|
||||
* @visible for testing
|
||||
*/
|
||||
public function getUploadType($meta)
|
||||
{
|
||||
if ($this->resumable) {
|
||||
return self::UPLOAD_RESUMABLE_TYPE;
|
||||
}
|
||||
|
||||
if (false == $meta && $this->data) {
|
||||
return self::UPLOAD_MEDIA_TYPE;
|
||||
}
|
||||
|
||||
return self::UPLOAD_MULTIPART_TYPE;
|
||||
}
|
||||
|
||||
public function getResumeUri()
|
||||
{
|
||||
if (null === $this->resumeUri) {
|
||||
$this->resumeUri = $this->fetchResumeUri();
|
||||
}
|
||||
|
||||
return $this->resumeUri;
|
||||
}
|
||||
|
||||
private function fetchResumeUri()
|
||||
{
|
||||
$body = $this->request->getBody();
|
||||
if ($body) {
|
||||
$headers = array(
|
||||
'content-type' => 'application/json; charset=UTF-8',
|
||||
'content-length' => $body->getSize(),
|
||||
'x-upload-content-type' => $this->mimeType,
|
||||
'x-upload-content-length' => $this->size,
|
||||
'expect' => '',
|
||||
);
|
||||
foreach ($headers as $key => $value) {
|
||||
$this->request = $this->request->withHeader($key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
$response = $this->client->execute($this->request, false);
|
||||
$location = $response->getHeaderLine('location');
|
||||
$code = $response->getStatusCode();
|
||||
|
||||
if (200 == $code && true == $location) {
|
||||
return $location;
|
||||
}
|
||||
|
||||
$message = $code;
|
||||
$body = json_decode((string) $this->request->getBody(), true);
|
||||
if (isset($body['error']['errors'])) {
|
||||
$message .= ': ';
|
||||
foreach ($body['error']['errors'] as $error) {
|
||||
$message .= "{$error['domain']}, {$error['message']};";
|
||||
}
|
||||
$message = rtrim($message, ';');
|
||||
}
|
||||
|
||||
$error = "Failed to start the resumable upload (HTTP {$message})";
|
||||
$this->client->getLogger()->error($error);
|
||||
|
||||
throw new Google_Exception($error);
|
||||
}
|
||||
|
||||
private function transformToUploadUrl()
|
||||
{
|
||||
$parts = parse_url((string) $this->request->getUri());
|
||||
if (!isset($parts['path'])) {
|
||||
$parts['path'] = '';
|
||||
}
|
||||
$parts['path'] = '/upload' . $parts['path'];
|
||||
$uri = Uri::fromParts($parts);
|
||||
$this->request = $this->request->withUri($uri);
|
||||
}
|
||||
|
||||
public function setChunkSize($chunkSize)
|
||||
{
|
||||
$this->chunkSize = $chunkSize;
|
||||
}
|
||||
|
||||
public function getRequest()
|
||||
{
|
||||
return $this->request;
|
||||
}
|
||||
}
|
||||
182
vendor/google/apiclient/src/Google/Http/REST.php
vendored
Normal file
182
vendor/google/apiclient/src/Google/Http/REST.php
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use Google\Auth\HttpHandler\HttpHandlerFactory;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* This class implements the RESTful transport of apiServiceRequest()'s
|
||||
*/
|
||||
class Google_Http_REST
|
||||
{
|
||||
/**
|
||||
* Executes a Psr\Http\Message\RequestInterface and (if applicable) automatically retries
|
||||
* when errors occur.
|
||||
*
|
||||
* @param Google_Client $client
|
||||
* @param Psr\Http\Message\RequestInterface $req
|
||||
* @return array decoded result
|
||||
* @throws Google_Service_Exception on server side error (ie: not authenticated,
|
||||
* invalid or malformed post body, invalid url)
|
||||
*/
|
||||
public static function execute(
|
||||
ClientInterface $client,
|
||||
RequestInterface $request,
|
||||
$expectedClass = null,
|
||||
$config = array(),
|
||||
$retryMap = null
|
||||
) {
|
||||
$runner = new Google_Task_Runner(
|
||||
$config,
|
||||
sprintf('%s %s', $request->getMethod(), (string) $request->getUri()),
|
||||
array(get_class(), 'doExecute'),
|
||||
array($client, $request, $expectedClass)
|
||||
);
|
||||
|
||||
if (null !== $retryMap) {
|
||||
$runner->setRetryMap($retryMap);
|
||||
}
|
||||
|
||||
return $runner->run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a Psr\Http\Message\RequestInterface
|
||||
*
|
||||
* @param Google_Client $client
|
||||
* @param Psr\Http\Message\RequestInterface $request
|
||||
* @return array decoded result
|
||||
* @throws Google_Service_Exception on server side error (ie: not authenticated,
|
||||
* invalid or malformed post body, invalid url)
|
||||
*/
|
||||
public static function doExecute(ClientInterface $client, RequestInterface $request, $expectedClass = null)
|
||||
{
|
||||
try {
|
||||
$httpHandler = HttpHandlerFactory::build($client);
|
||||
$response = $httpHandler($request);
|
||||
} catch (RequestException $e) {
|
||||
// if Guzzle throws an exception, catch it and handle the response
|
||||
if (!$e->hasResponse()) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$response = $e->getResponse();
|
||||
// specific checking for Guzzle 5: convert to PSR7 response
|
||||
if ($response instanceof \GuzzleHttp\Message\ResponseInterface) {
|
||||
$response = new Response(
|
||||
$response->getStatusCode(),
|
||||
$response->getHeaders() ?: [],
|
||||
$response->getBody(),
|
||||
$response->getProtocolVersion(),
|
||||
$response->getReasonPhrase()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return self::decodeHttpResponse($response, $request, $expectedClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode an HTTP Response.
|
||||
* @static
|
||||
* @throws Google_Service_Exception
|
||||
* @param Psr\Http\Message\RequestInterface $response The http response to be decoded.
|
||||
* @param Psr\Http\Message\ResponseInterface $response
|
||||
* @return mixed|null
|
||||
*/
|
||||
public static function decodeHttpResponse(
|
||||
ResponseInterface $response,
|
||||
RequestInterface $request = null,
|
||||
$expectedClass = null
|
||||
) {
|
||||
$code = $response->getStatusCode();
|
||||
|
||||
// retry strategy
|
||||
if (intVal($code) >= 400) {
|
||||
// if we errored out, it should be safe to grab the response body
|
||||
$body = (string) $response->getBody();
|
||||
|
||||
// Check if we received errors, and add those to the Exception for convenience
|
||||
throw new Google_Service_Exception($body, $code, null, self::getResponseErrors($body));
|
||||
}
|
||||
|
||||
// Ensure we only pull the entire body into memory if the request is not
|
||||
// of media type
|
||||
$body = self::decodeBody($response, $request);
|
||||
|
||||
if ($expectedClass = self::determineExpectedClass($expectedClass, $request)) {
|
||||
$json = json_decode($body, true);
|
||||
|
||||
return new $expectedClass($json);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
private static function decodeBody(ResponseInterface $response, RequestInterface $request = null)
|
||||
{
|
||||
if (self::isAltMedia($request)) {
|
||||
// don't decode the body, it's probably a really long string
|
||||
return '';
|
||||
}
|
||||
|
||||
return (string) $response->getBody();
|
||||
}
|
||||
|
||||
private static function determineExpectedClass($expectedClass, RequestInterface $request = null)
|
||||
{
|
||||
// "false" is used to explicitly prevent an expected class from being returned
|
||||
if (false === $expectedClass) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// if we don't have a request, we just use what's passed in
|
||||
if (null === $request) {
|
||||
return $expectedClass;
|
||||
}
|
||||
|
||||
// return what we have in the request header if one was not supplied
|
||||
return $expectedClass ?: $request->getHeaderLine('X-Php-Expected-Class');
|
||||
}
|
||||
|
||||
private static function getResponseErrors($body)
|
||||
{
|
||||
$json = json_decode($body, true);
|
||||
|
||||
if (isset($json['error']['errors'])) {
|
||||
return $json['error']['errors'];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static function isAltMedia(RequestInterface $request = null)
|
||||
{
|
||||
if ($request && $qs = $request->getUri()->getQuery()) {
|
||||
parse_str($qs, $query);
|
||||
if (isset($query['alt']) && $query['alt'] == 'media') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
317
vendor/google/apiclient/src/Google/Model.php
vendored
Normal file
317
vendor/google/apiclient/src/Google/Model.php
vendored
Normal file
@@ -0,0 +1,317 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class defines attributes, valid values, and usage which is generated
|
||||
* from a given json schema.
|
||||
* http://tools.ietf.org/html/draft-zyp-json-schema-03#section-5
|
||||
*
|
||||
*/
|
||||
class Google_Model implements ArrayAccess
|
||||
{
|
||||
/**
|
||||
* If you need to specify a NULL JSON value, use Google_Model::NULL_VALUE
|
||||
* instead - it will be replaced when converting to JSON with a real null.
|
||||
*/
|
||||
const NULL_VALUE = "{}gapi-php-null";
|
||||
protected $internal_gapi_mappings = array();
|
||||
protected $modelData = array();
|
||||
protected $processed = array();
|
||||
|
||||
/**
|
||||
* Polymorphic - accepts a variable number of arguments dependent
|
||||
* on the type of the model subclass.
|
||||
*/
|
||||
final public function __construct()
|
||||
{
|
||||
if (func_num_args() == 1 && is_array(func_get_arg(0))) {
|
||||
// Initialize the model with the array's contents.
|
||||
$array = func_get_arg(0);
|
||||
$this->mapTypes($array);
|
||||
}
|
||||
$this->gapiInit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter that handles passthrough access to the data array, and lazy object creation.
|
||||
* @param string $key Property name.
|
||||
* @return mixed The value if any, or null.
|
||||
*/
|
||||
public function __get($key)
|
||||
{
|
||||
$keyType = $this->keyType($key);
|
||||
$keyDataType = $this->dataType($key);
|
||||
if ($keyType && !isset($this->processed[$key])) {
|
||||
if (isset($this->modelData[$key])) {
|
||||
$val = $this->modelData[$key];
|
||||
} elseif ($keyDataType == 'array' || $keyDataType == 'map') {
|
||||
$val = array();
|
||||
} else {
|
||||
$val = null;
|
||||
}
|
||||
|
||||
if ($this->isAssociativeArray($val)) {
|
||||
if ($keyDataType && 'map' == $keyDataType) {
|
||||
foreach ($val as $arrayKey => $arrayItem) {
|
||||
$this->modelData[$key][$arrayKey] =
|
||||
new $keyType($arrayItem);
|
||||
}
|
||||
} else {
|
||||
$this->modelData[$key] = new $keyType($val);
|
||||
}
|
||||
} else if (is_array($val)) {
|
||||
$arrayObject = array();
|
||||
foreach ($val as $arrayIndex => $arrayItem) {
|
||||
$arrayObject[$arrayIndex] = new $keyType($arrayItem);
|
||||
}
|
||||
$this->modelData[$key] = $arrayObject;
|
||||
}
|
||||
$this->processed[$key] = true;
|
||||
}
|
||||
|
||||
return isset($this->modelData[$key]) ? $this->modelData[$key] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this object's properties from an array.
|
||||
*
|
||||
* @param array $array Used to seed this object's properties.
|
||||
* @return void
|
||||
*/
|
||||
protected function mapTypes($array)
|
||||
{
|
||||
// Hard initialise simple types, lazy load more complex ones.
|
||||
foreach ($array as $key => $val) {
|
||||
if ($keyType = $this->keyType($key)) {
|
||||
$dataType = $this->dataType($key);
|
||||
if ($dataType == 'array' || $dataType == 'map') {
|
||||
$this->$key = array();
|
||||
foreach ($val as $itemKey => $itemVal) {
|
||||
if ($itemVal instanceof $keyType) {
|
||||
$this->{$key}[$itemKey] = $itemVal;
|
||||
} else {
|
||||
$this->{$key}[$itemKey] = new $keyType($itemVal);
|
||||
}
|
||||
}
|
||||
} elseif ($val instanceof $keyType) {
|
||||
$this->$key = $val;
|
||||
} else {
|
||||
$this->$key = new $keyType($val);
|
||||
}
|
||||
unset($array[$key]);
|
||||
} elseif (property_exists($this, $key)) {
|
||||
$this->$key = $val;
|
||||
unset($array[$key]);
|
||||
} elseif (property_exists($this, $camelKey = $this->camelCase($key))) {
|
||||
// This checks if property exists as camelCase, leaving it in array as snake_case
|
||||
// in case of backwards compatibility issues.
|
||||
$this->$camelKey = $val;
|
||||
}
|
||||
}
|
||||
$this->modelData = $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Blank initialiser to be used in subclasses to do post-construction initialisation - this
|
||||
* avoids the need for subclasses to have to implement the variadics handling in their
|
||||
* constructors.
|
||||
*/
|
||||
protected function gapiInit()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a simplified object suitable for straightforward
|
||||
* conversion to JSON. This is relatively expensive
|
||||
* due to the usage of reflection, but shouldn't be called
|
||||
* a whole lot, and is the most straightforward way to filter.
|
||||
*/
|
||||
public function toSimpleObject()
|
||||
{
|
||||
$object = new stdClass();
|
||||
|
||||
// Process all other data.
|
||||
foreach ($this->modelData as $key => $val) {
|
||||
$result = $this->getSimpleValue($val);
|
||||
if ($result !== null) {
|
||||
$object->$key = $this->nullPlaceholderCheck($result);
|
||||
}
|
||||
}
|
||||
|
||||
// Process all public properties.
|
||||
$reflect = new ReflectionObject($this);
|
||||
$props = $reflect->getProperties(ReflectionProperty::IS_PUBLIC);
|
||||
foreach ($props as $member) {
|
||||
$name = $member->getName();
|
||||
$result = $this->getSimpleValue($this->$name);
|
||||
if ($result !== null) {
|
||||
$name = $this->getMappedName($name);
|
||||
$object->$name = $this->nullPlaceholderCheck($result);
|
||||
}
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle different types of values, primarily
|
||||
* other objects and map and array data types.
|
||||
*/
|
||||
private function getSimpleValue($value)
|
||||
{
|
||||
if ($value instanceof Google_Model) {
|
||||
return $value->toSimpleObject();
|
||||
} else if (is_array($value)) {
|
||||
$return = array();
|
||||
foreach ($value as $key => $a_value) {
|
||||
$a_value = $this->getSimpleValue($a_value);
|
||||
if ($a_value !== null) {
|
||||
$key = $this->getMappedName($key);
|
||||
$return[$key] = $this->nullPlaceholderCheck($a_value);
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the value is the null placeholder and return true null.
|
||||
*/
|
||||
private function nullPlaceholderCheck($value)
|
||||
{
|
||||
if ($value === self::NULL_VALUE) {
|
||||
return null;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* If there is an internal name mapping, use that.
|
||||
*/
|
||||
private function getMappedName($key)
|
||||
{
|
||||
if (isset($this->internal_gapi_mappings, $this->internal_gapi_mappings[$key])) {
|
||||
$key = $this->internal_gapi_mappings[$key];
|
||||
}
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true only if the array is associative.
|
||||
* @param array $array
|
||||
* @return bool True if the array is associative.
|
||||
*/
|
||||
protected function isAssociativeArray($array)
|
||||
{
|
||||
if (!is_array($array)) {
|
||||
return false;
|
||||
}
|
||||
$keys = array_keys($array);
|
||||
foreach ($keys as $key) {
|
||||
if (is_string($key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify if $obj is an array.
|
||||
* @throws Google_Exception Thrown if $obj isn't an array.
|
||||
* @param array $obj Items that should be validated.
|
||||
* @param string $method Method expecting an array as an argument.
|
||||
*/
|
||||
public function assertIsArray($obj, $method)
|
||||
{
|
||||
if ($obj && !is_array($obj)) {
|
||||
throw new Google_Exception(
|
||||
"Incorrect parameter type passed to $method(). Expected an array."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return isset($this->$offset) || isset($this->modelData[$offset]);
|
||||
}
|
||||
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return isset($this->$offset) ?
|
||||
$this->$offset :
|
||||
$this->__get($offset);
|
||||
}
|
||||
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
if (property_exists($this, $offset)) {
|
||||
$this->$offset = $value;
|
||||
} else {
|
||||
$this->modelData[$offset] = $value;
|
||||
$this->processed[$offset] = true;
|
||||
}
|
||||
}
|
||||
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
unset($this->modelData[$offset]);
|
||||
}
|
||||
|
||||
protected function keyType($key)
|
||||
{
|
||||
$keyType = $key . "Type";
|
||||
|
||||
// ensure keyType is a valid class
|
||||
if (property_exists($this, $keyType) && class_exists($this->$keyType)) {
|
||||
return $this->$keyType;
|
||||
}
|
||||
}
|
||||
|
||||
protected function dataType($key)
|
||||
{
|
||||
$dataType = $key . "DataType";
|
||||
|
||||
if (property_exists($this, $dataType)) {
|
||||
return $this->$dataType;
|
||||
}
|
||||
}
|
||||
|
||||
public function __isset($key)
|
||||
{
|
||||
return isset($this->modelData[$key]);
|
||||
}
|
||||
|
||||
public function __unset($key)
|
||||
{
|
||||
unset($this->modelData[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a string to camelCase
|
||||
* @param string $value
|
||||
* @return string
|
||||
*/
|
||||
private function camelCase($value)
|
||||
{
|
||||
$value = ucwords(str_replace(array('-', '_'), ' ', $value));
|
||||
$value = str_replace(' ', '', $value);
|
||||
$value[0] = strtolower($value[0]);
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
56
vendor/google/apiclient/src/Google/Service.php
vendored
Normal file
56
vendor/google/apiclient/src/Google/Service.php
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Google_Service
|
||||
{
|
||||
public $batchPath;
|
||||
public $rootUrl;
|
||||
public $version;
|
||||
public $servicePath;
|
||||
public $availableScopes;
|
||||
public $resource;
|
||||
private $client;
|
||||
|
||||
public function __construct(Google_Client $client)
|
||||
{
|
||||
$this->client = $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the associated Google_Client class.
|
||||
* @return Google_Client
|
||||
*/
|
||||
public function getClient()
|
||||
{
|
||||
return $this->client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new HTTP Batch handler for this service
|
||||
*
|
||||
* @return Google_Http_Batch
|
||||
*/
|
||||
public function createBatch()
|
||||
{
|
||||
return new Google_Http_Batch(
|
||||
$this->client,
|
||||
false,
|
||||
$this->rootUrl,
|
||||
$this->batchPath
|
||||
);
|
||||
}
|
||||
}
|
||||
68
vendor/google/apiclient/src/Google/Service/Exception.php
vendored
Normal file
68
vendor/google/apiclient/src/Google/Service/Exception.php
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2014 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Google_Service_Exception extends Google_Exception
|
||||
{
|
||||
/**
|
||||
* Optional list of errors returned in a JSON body of an HTTP error response.
|
||||
*/
|
||||
protected $errors = array();
|
||||
|
||||
/**
|
||||
* Override default constructor to add the ability to set $errors and a retry
|
||||
* map.
|
||||
*
|
||||
* @param string $message
|
||||
* @param int $code
|
||||
* @param Exception|null $previous
|
||||
* @param [{string, string}] errors List of errors returned in an HTTP
|
||||
* response. Defaults to [].
|
||||
* @param array|null $retryMap Map of errors with retry counts.
|
||||
*/
|
||||
public function __construct(
|
||||
$message,
|
||||
$code = 0,
|
||||
Exception $previous = null,
|
||||
$errors = array()
|
||||
) {
|
||||
if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
|
||||
parent::__construct($message, $code, $previous);
|
||||
} else {
|
||||
parent::__construct($message, $code);
|
||||
}
|
||||
|
||||
$this->errors = $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* An example of the possible errors returned.
|
||||
*
|
||||
* {
|
||||
* "domain": "global",
|
||||
* "reason": "authError",
|
||||
* "message": "Invalid Credentials",
|
||||
* "locationType": "header",
|
||||
* "location": "Authorization",
|
||||
* }
|
||||
*
|
||||
* @return [{string, string}] List of errors return in an HTTP response or [].
|
||||
*/
|
||||
public function getErrors()
|
||||
{
|
||||
return $this->errors;
|
||||
}
|
||||
}
|
||||
5
vendor/google/apiclient/src/Google/Service/README.md
vendored
Normal file
5
vendor/google/apiclient/src/Google/Service/README.md
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# Google API Client Services
|
||||
|
||||
Google API Client Service classes have been moved to the
|
||||
[google-api-php-client-services](https://github.com/google/google-api-php-client-services)
|
||||
repository.
|
||||
302
vendor/google/apiclient/src/Google/Service/Resource.php
vendored
Normal file
302
vendor/google/apiclient/src/Google/Service/Resource.php
vendored
Normal file
@@ -0,0 +1,302 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
|
||||
/**
|
||||
* Implements the actual methods/resources of the discovered Google API using magic function
|
||||
* calling overloading (__call()), which on call will see if the method name (plus.activities.list)
|
||||
* is available in this service, and if so construct an apiHttpRequest representing it.
|
||||
*
|
||||
*/
|
||||
class Google_Service_Resource
|
||||
{
|
||||
// Valid query parameters that work, but don't appear in discovery.
|
||||
private $stackParameters = array(
|
||||
'alt' => array('type' => 'string', 'location' => 'query'),
|
||||
'fields' => array('type' => 'string', 'location' => 'query'),
|
||||
'trace' => array('type' => 'string', 'location' => 'query'),
|
||||
'userIp' => array('type' => 'string', 'location' => 'query'),
|
||||
'quotaUser' => array('type' => 'string', 'location' => 'query'),
|
||||
'data' => array('type' => 'string', 'location' => 'body'),
|
||||
'mimeType' => array('type' => 'string', 'location' => 'header'),
|
||||
'uploadType' => array('type' => 'string', 'location' => 'query'),
|
||||
'mediaUpload' => array('type' => 'complex', 'location' => 'query'),
|
||||
'prettyPrint' => array('type' => 'string', 'location' => 'query'),
|
||||
);
|
||||
|
||||
/** @var string $rootUrl */
|
||||
private $rootUrl;
|
||||
|
||||
/** @var Google_Client $client */
|
||||
private $client;
|
||||
|
||||
/** @var string $serviceName */
|
||||
private $serviceName;
|
||||
|
||||
/** @var string $servicePath */
|
||||
private $servicePath;
|
||||
|
||||
/** @var string $resourceName */
|
||||
private $resourceName;
|
||||
|
||||
/** @var array $methods */
|
||||
private $methods;
|
||||
|
||||
public function __construct($service, $serviceName, $resourceName, $resource)
|
||||
{
|
||||
$this->rootUrl = $service->rootUrl;
|
||||
$this->client = $service->getClient();
|
||||
$this->servicePath = $service->servicePath;
|
||||
$this->serviceName = $serviceName;
|
||||
$this->resourceName = $resourceName;
|
||||
$this->methods = is_array($resource) && isset($resource['methods']) ?
|
||||
$resource['methods'] :
|
||||
array($resourceName => $resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: This function needs simplifying.
|
||||
* @param $name
|
||||
* @param $arguments
|
||||
* @param $expectedClass - optional, the expected class name
|
||||
* @return Google_Http_Request|expectedClass
|
||||
* @throws Google_Exception
|
||||
*/
|
||||
public function call($name, $arguments, $expectedClass = null)
|
||||
{
|
||||
if (! isset($this->methods[$name])) {
|
||||
$this->client->getLogger()->error(
|
||||
'Service method unknown',
|
||||
array(
|
||||
'service' => $this->serviceName,
|
||||
'resource' => $this->resourceName,
|
||||
'method' => $name
|
||||
)
|
||||
);
|
||||
|
||||
throw new Google_Exception(
|
||||
"Unknown function: " .
|
||||
"{$this->serviceName}->{$this->resourceName}->{$name}()"
|
||||
);
|
||||
}
|
||||
$method = $this->methods[$name];
|
||||
$parameters = $arguments[0];
|
||||
|
||||
// postBody is a special case since it's not defined in the discovery
|
||||
// document as parameter, but we abuse the param entry for storing it.
|
||||
$postBody = null;
|
||||
if (isset($parameters['postBody'])) {
|
||||
if ($parameters['postBody'] instanceof Google_Model) {
|
||||
// In the cases the post body is an existing object, we want
|
||||
// to use the smart method to create a simple object for
|
||||
// for JSONification.
|
||||
$parameters['postBody'] = $parameters['postBody']->toSimpleObject();
|
||||
} else if (is_object($parameters['postBody'])) {
|
||||
// If the post body is another kind of object, we will try and
|
||||
// wrangle it into a sensible format.
|
||||
$parameters['postBody'] =
|
||||
$this->convertToArrayAndStripNulls($parameters['postBody']);
|
||||
}
|
||||
$postBody = (array) $parameters['postBody'];
|
||||
unset($parameters['postBody']);
|
||||
}
|
||||
|
||||
// TODO: optParams here probably should have been
|
||||
// handled already - this may well be redundant code.
|
||||
if (isset($parameters['optParams'])) {
|
||||
$optParams = $parameters['optParams'];
|
||||
unset($parameters['optParams']);
|
||||
$parameters = array_merge($parameters, $optParams);
|
||||
}
|
||||
|
||||
if (!isset($method['parameters'])) {
|
||||
$method['parameters'] = array();
|
||||
}
|
||||
|
||||
$method['parameters'] = array_merge(
|
||||
$this->stackParameters,
|
||||
$method['parameters']
|
||||
);
|
||||
|
||||
foreach ($parameters as $key => $val) {
|
||||
if ($key != 'postBody' && ! isset($method['parameters'][$key])) {
|
||||
$this->client->getLogger()->error(
|
||||
'Service parameter unknown',
|
||||
array(
|
||||
'service' => $this->serviceName,
|
||||
'resource' => $this->resourceName,
|
||||
'method' => $name,
|
||||
'parameter' => $key
|
||||
)
|
||||
);
|
||||
throw new Google_Exception("($name) unknown parameter: '$key'");
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($method['parameters'] as $paramName => $paramSpec) {
|
||||
if (isset($paramSpec['required']) &&
|
||||
$paramSpec['required'] &&
|
||||
! isset($parameters[$paramName])
|
||||
) {
|
||||
$this->client->getLogger()->error(
|
||||
'Service parameter missing',
|
||||
array(
|
||||
'service' => $this->serviceName,
|
||||
'resource' => $this->resourceName,
|
||||
'method' => $name,
|
||||
'parameter' => $paramName
|
||||
)
|
||||
);
|
||||
throw new Google_Exception("($name) missing required param: '$paramName'");
|
||||
}
|
||||
if (isset($parameters[$paramName])) {
|
||||
$value = $parameters[$paramName];
|
||||
$parameters[$paramName] = $paramSpec;
|
||||
$parameters[$paramName]['value'] = $value;
|
||||
unset($parameters[$paramName]['required']);
|
||||
} else {
|
||||
// Ensure we don't pass nulls.
|
||||
unset($parameters[$paramName]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->client->getLogger()->info(
|
||||
'Service Call',
|
||||
array(
|
||||
'service' => $this->serviceName,
|
||||
'resource' => $this->resourceName,
|
||||
'method' => $name,
|
||||
'arguments' => $parameters,
|
||||
)
|
||||
);
|
||||
|
||||
// build the service uri
|
||||
$url = $this->createRequestUri(
|
||||
$method['path'],
|
||||
$parameters
|
||||
);
|
||||
|
||||
// NOTE: because we're creating the request by hand,
|
||||
// and because the service has a rootUrl property
|
||||
// the "base_uri" of the Http Client is not accounted for
|
||||
$request = new Request(
|
||||
$method['httpMethod'],
|
||||
$url,
|
||||
['content-type' => 'application/json'],
|
||||
$postBody ? json_encode($postBody) : ''
|
||||
);
|
||||
|
||||
// support uploads
|
||||
if (isset($parameters['data'])) {
|
||||
$mimeType = isset($parameters['mimeType'])
|
||||
? $parameters['mimeType']['value']
|
||||
: 'application/octet-stream';
|
||||
$data = $parameters['data']['value'];
|
||||
$upload = new Google_Http_MediaFileUpload($this->client, $request, $mimeType, $data);
|
||||
|
||||
// pull down the modified request
|
||||
$request = $upload->getRequest();
|
||||
}
|
||||
|
||||
// if this is a media type, we will return the raw response
|
||||
// rather than using an expected class
|
||||
if (isset($parameters['alt']) && $parameters['alt']['value'] == 'media') {
|
||||
$expectedClass = null;
|
||||
}
|
||||
|
||||
// if the client is marked for deferring, rather than
|
||||
// execute the request, return the response
|
||||
if ($this->client->shouldDefer()) {
|
||||
// @TODO find a better way to do this
|
||||
$request = $request
|
||||
->withHeader('X-Php-Expected-Class', $expectedClass);
|
||||
|
||||
return $request;
|
||||
}
|
||||
|
||||
return $this->client->execute($request, $expectedClass);
|
||||
}
|
||||
|
||||
protected function convertToArrayAndStripNulls($o)
|
||||
{
|
||||
$o = (array) $o;
|
||||
foreach ($o as $k => $v) {
|
||||
if ($v === null) {
|
||||
unset($o[$k]);
|
||||
} elseif (is_object($v) || is_array($v)) {
|
||||
$o[$k] = $this->convertToArrayAndStripNulls($o[$k]);
|
||||
}
|
||||
}
|
||||
return $o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse/expand request parameters and create a fully qualified
|
||||
* request uri.
|
||||
* @static
|
||||
* @param string $restPath
|
||||
* @param array $params
|
||||
* @return string $requestUrl
|
||||
*/
|
||||
public function createRequestUri($restPath, $params)
|
||||
{
|
||||
// Override the default servicePath address if the $restPath use a /
|
||||
if ('/' == substr($restPath, 0, 1)) {
|
||||
$requestUrl = substr($restPath, 1);
|
||||
} else {
|
||||
$requestUrl = $this->servicePath . $restPath;
|
||||
}
|
||||
|
||||
// code for leading slash
|
||||
if ($this->rootUrl) {
|
||||
if ('/' !== substr($this->rootUrl, -1) && '/' !== substr($requestUrl, 0, 1)) {
|
||||
$requestUrl = '/' . $requestUrl;
|
||||
}
|
||||
$requestUrl = $this->rootUrl . $requestUrl;
|
||||
}
|
||||
$uriTemplateVars = array();
|
||||
$queryVars = array();
|
||||
foreach ($params as $paramName => $paramSpec) {
|
||||
if ($paramSpec['type'] == 'boolean') {
|
||||
$paramSpec['value'] = $paramSpec['value'] ? 'true' : 'false';
|
||||
}
|
||||
if ($paramSpec['location'] == 'path') {
|
||||
$uriTemplateVars[$paramName] = $paramSpec['value'];
|
||||
} else if ($paramSpec['location'] == 'query') {
|
||||
if (is_array($paramSpec['value'])) {
|
||||
foreach ($paramSpec['value'] as $value) {
|
||||
$queryVars[] = $paramName . '=' . rawurlencode(rawurldecode($value));
|
||||
}
|
||||
} else {
|
||||
$queryVars[] = $paramName . '=' . rawurlencode(rawurldecode($paramSpec['value']));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count($uriTemplateVars)) {
|
||||
$uriTemplateParser = new Google_Utils_UriTemplate();
|
||||
$requestUrl = $uriTemplateParser->parse($requestUrl, $uriTemplateVars);
|
||||
}
|
||||
|
||||
if (count($queryVars)) {
|
||||
$requestUrl .= '?' . implode('&', $queryVars);
|
||||
}
|
||||
|
||||
return $requestUrl;
|
||||
}
|
||||
}
|
||||
20
vendor/google/apiclient/src/Google/Task/Exception.php
vendored
Normal file
20
vendor/google/apiclient/src/Google/Task/Exception.php
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2014 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Google_Task_Exception extends Google_Exception
|
||||
{
|
||||
}
|
||||
24
vendor/google/apiclient/src/Google/Task/Retryable.php
vendored
Normal file
24
vendor/google/apiclient/src/Google/Task/Retryable.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2014 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Interface for checking how many times a given task can be retried following
|
||||
* a failure.
|
||||
*/
|
||||
interface Google_Task_Retryable
|
||||
{
|
||||
}
|
||||
281
vendor/google/apiclient/src/Google/Task/Runner.php
vendored
Normal file
281
vendor/google/apiclient/src/Google/Task/Runner.php
vendored
Normal file
@@ -0,0 +1,281 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2014 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A task runner with exponential backoff support.
|
||||
*
|
||||
* @see https://developers.google.com/drive/web/handle-errors#implementing_exponential_backoff
|
||||
*/
|
||||
class Google_Task_Runner
|
||||
{
|
||||
const TASK_RETRY_NEVER = 0;
|
||||
const TASK_RETRY_ONCE = 1;
|
||||
const TASK_RETRY_ALWAYS = -1;
|
||||
|
||||
/**
|
||||
* @var integer $maxDelay The max time (in seconds) to wait before a retry.
|
||||
*/
|
||||
private $maxDelay = 60;
|
||||
/**
|
||||
* @var integer $delay The previous delay from which the next is calculated.
|
||||
*/
|
||||
private $delay = 1;
|
||||
|
||||
/**
|
||||
* @var integer $factor The base number for the exponential back off.
|
||||
*/
|
||||
private $factor = 2;
|
||||
/**
|
||||
* @var float $jitter A random number between -$jitter and $jitter will be
|
||||
* added to $factor on each iteration to allow for a better distribution of
|
||||
* retries.
|
||||
*/
|
||||
private $jitter = 0.5;
|
||||
|
||||
/**
|
||||
* @var integer $attempts The number of attempts that have been tried so far.
|
||||
*/
|
||||
private $attempts = 0;
|
||||
/**
|
||||
* @var integer $maxAttempts The max number of attempts allowed.
|
||||
*/
|
||||
private $maxAttempts = 1;
|
||||
|
||||
/**
|
||||
* @var callable $action The task to run and possibly retry.
|
||||
*/
|
||||
private $action;
|
||||
/**
|
||||
* @var array $arguments The task arguments.
|
||||
*/
|
||||
private $arguments;
|
||||
|
||||
/**
|
||||
* @var array $retryMap Map of errors with retry counts.
|
||||
*/
|
||||
protected $retryMap = [
|
||||
'500' => self::TASK_RETRY_ALWAYS,
|
||||
'503' => self::TASK_RETRY_ALWAYS,
|
||||
'rateLimitExceeded' => self::TASK_RETRY_ALWAYS,
|
||||
'userRateLimitExceeded' => self::TASK_RETRY_ALWAYS,
|
||||
6 => self::TASK_RETRY_ALWAYS, // CURLE_COULDNT_RESOLVE_HOST
|
||||
7 => self::TASK_RETRY_ALWAYS, // CURLE_COULDNT_CONNECT
|
||||
28 => self::TASK_RETRY_ALWAYS, // CURLE_OPERATION_TIMEOUTED
|
||||
35 => self::TASK_RETRY_ALWAYS, // CURLE_SSL_CONNECT_ERROR
|
||||
52 => self::TASK_RETRY_ALWAYS // CURLE_GOT_NOTHING
|
||||
];
|
||||
|
||||
/**
|
||||
* Creates a new task runner with exponential backoff support.
|
||||
*
|
||||
* @param array $config The task runner config
|
||||
* @param string $name The name of the current task (used for logging)
|
||||
* @param callable $action The task to run and possibly retry
|
||||
* @param array $arguments The task arguments
|
||||
* @throws Google_Task_Exception when misconfigured
|
||||
*/
|
||||
public function __construct(
|
||||
$config,
|
||||
$name,
|
||||
$action,
|
||||
array $arguments = array()
|
||||
) {
|
||||
if (isset($config['initial_delay'])) {
|
||||
if ($config['initial_delay'] < 0) {
|
||||
throw new Google_Task_Exception(
|
||||
'Task configuration `initial_delay` must not be negative.'
|
||||
);
|
||||
}
|
||||
|
||||
$this->delay = $config['initial_delay'];
|
||||
}
|
||||
|
||||
if (isset($config['max_delay'])) {
|
||||
if ($config['max_delay'] <= 0) {
|
||||
throw new Google_Task_Exception(
|
||||
'Task configuration `max_delay` must be greater than 0.'
|
||||
);
|
||||
}
|
||||
|
||||
$this->maxDelay = $config['max_delay'];
|
||||
}
|
||||
|
||||
if (isset($config['factor'])) {
|
||||
if ($config['factor'] <= 0) {
|
||||
throw new Google_Task_Exception(
|
||||
'Task configuration `factor` must be greater than 0.'
|
||||
);
|
||||
}
|
||||
|
||||
$this->factor = $config['factor'];
|
||||
}
|
||||
|
||||
if (isset($config['jitter'])) {
|
||||
if ($config['jitter'] <= 0) {
|
||||
throw new Google_Task_Exception(
|
||||
'Task configuration `jitter` must be greater than 0.'
|
||||
);
|
||||
}
|
||||
|
||||
$this->jitter = $config['jitter'];
|
||||
}
|
||||
|
||||
if (isset($config['retries'])) {
|
||||
if ($config['retries'] < 0) {
|
||||
throw new Google_Task_Exception(
|
||||
'Task configuration `retries` must not be negative.'
|
||||
);
|
||||
}
|
||||
$this->maxAttempts += $config['retries'];
|
||||
}
|
||||
|
||||
if (!is_callable($action)) {
|
||||
throw new Google_Task_Exception(
|
||||
'Task argument `$action` must be a valid callable.'
|
||||
);
|
||||
}
|
||||
|
||||
$this->action = $action;
|
||||
$this->arguments = $arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a retry can be attempted.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function canAttempt()
|
||||
{
|
||||
return $this->attempts < $this->maxAttempts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the task and (if applicable) automatically retries when errors occur.
|
||||
*
|
||||
* @return mixed
|
||||
* @throws Google_Task_Retryable on failure when no retries are available.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
while ($this->attempt()) {
|
||||
try {
|
||||
return call_user_func_array($this->action, $this->arguments);
|
||||
} catch (Google_Service_Exception $exception) {
|
||||
$allowedRetries = $this->allowedRetries(
|
||||
$exception->getCode(),
|
||||
$exception->getErrors()
|
||||
);
|
||||
|
||||
if (!$this->canAttempt() || !$allowedRetries) {
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
if ($allowedRetries > 0) {
|
||||
$this->maxAttempts = min(
|
||||
$this->maxAttempts,
|
||||
$this->attempts + $allowedRetries
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a task once, if possible. This is useful for bypassing the `run()`
|
||||
* loop.
|
||||
*
|
||||
* NOTE: If this is not the first attempt, this function will sleep in
|
||||
* accordance to the backoff configurations before running the task.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function attempt()
|
||||
{
|
||||
if (!$this->canAttempt()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->attempts > 0) {
|
||||
$this->backOff();
|
||||
}
|
||||
|
||||
$this->attempts++;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sleeps in accordance to the backoff configurations.
|
||||
*/
|
||||
private function backOff()
|
||||
{
|
||||
$delay = $this->getDelay();
|
||||
|
||||
usleep($delay * 1000000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the delay (in seconds) for the current backoff period.
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
private function getDelay()
|
||||
{
|
||||
$jitter = $this->getJitter();
|
||||
$factor = $this->attempts > 1 ? $this->factor + $jitter : 1 + abs($jitter);
|
||||
|
||||
return $this->delay = min($this->maxDelay, $this->delay * $factor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current jitter (random number between -$this->jitter and
|
||||
* $this->jitter).
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
private function getJitter()
|
||||
{
|
||||
return $this->jitter * 2 * mt_rand() / mt_getrandmax() - $this->jitter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of times the associated task can be retried.
|
||||
*
|
||||
* NOTE: -1 is returned if the task can be retried indefinitely
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function allowedRetries($code, $errors = array())
|
||||
{
|
||||
if (isset($this->retryMap[$code])) {
|
||||
return $this->retryMap[$code];
|
||||
}
|
||||
|
||||
if (
|
||||
!empty($errors) &&
|
||||
isset($errors[0]['reason'], $this->retryMap[$errors[0]['reason']])
|
||||
) {
|
||||
return $this->retryMap[$errors[0]['reason']];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function setRetryMap($retryMap)
|
||||
{
|
||||
$this->retryMap = $retryMap;
|
||||
}
|
||||
}
|
||||
333
vendor/google/apiclient/src/Google/Utils/UriTemplate.php
vendored
Normal file
333
vendor/google/apiclient/src/Google/Utils/UriTemplate.php
vendored
Normal file
@@ -0,0 +1,333 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implementation of levels 1-3 of the URI Template spec.
|
||||
* @see http://tools.ietf.org/html/rfc6570
|
||||
*/
|
||||
class Google_Utils_UriTemplate
|
||||
{
|
||||
const TYPE_MAP = "1";
|
||||
const TYPE_LIST = "2";
|
||||
const TYPE_SCALAR = "4";
|
||||
|
||||
/**
|
||||
* @var $operators array
|
||||
* These are valid at the start of a template block to
|
||||
* modify the way in which the variables inside are
|
||||
* processed.
|
||||
*/
|
||||
private $operators = array(
|
||||
"+" => "reserved",
|
||||
"/" => "segments",
|
||||
"." => "dotprefix",
|
||||
"#" => "fragment",
|
||||
";" => "semicolon",
|
||||
"?" => "form",
|
||||
"&" => "continuation"
|
||||
);
|
||||
|
||||
/**
|
||||
* @var reserved array
|
||||
* These are the characters which should not be URL encoded in reserved
|
||||
* strings.
|
||||
*/
|
||||
private $reserved = array(
|
||||
"=", ",", "!", "@", "|", ":", "/", "?", "#",
|
||||
"[", "]",'$', "&", "'", "(", ")", "*", "+", ";"
|
||||
);
|
||||
private $reservedEncoded = array(
|
||||
"%3D", "%2C", "%21", "%40", "%7C", "%3A", "%2F", "%3F",
|
||||
"%23", "%5B", "%5D", "%24", "%26", "%27", "%28", "%29",
|
||||
"%2A", "%2B", "%3B"
|
||||
);
|
||||
|
||||
public function parse($string, array $parameters)
|
||||
{
|
||||
return $this->resolveNextSection($string, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function finds the first matching {...} block and
|
||||
* executes the replacement. It then calls itself to find
|
||||
* subsequent blocks, if any.
|
||||
*/
|
||||
private function resolveNextSection($string, $parameters)
|
||||
{
|
||||
$start = strpos($string, "{");
|
||||
if ($start === false) {
|
||||
return $string;
|
||||
}
|
||||
$end = strpos($string, "}");
|
||||
if ($end === false) {
|
||||
return $string;
|
||||
}
|
||||
$string = $this->replace($string, $start, $end, $parameters);
|
||||
return $this->resolveNextSection($string, $parameters);
|
||||
}
|
||||
|
||||
private function replace($string, $start, $end, $parameters)
|
||||
{
|
||||
// We know a data block will have {} round it, so we can strip that.
|
||||
$data = substr($string, $start + 1, $end - $start - 1);
|
||||
|
||||
// If the first character is one of the reserved operators, it effects
|
||||
// the processing of the stream.
|
||||
if (isset($this->operators[$data[0]])) {
|
||||
$op = $this->operators[$data[0]];
|
||||
$data = substr($data, 1);
|
||||
$prefix = "";
|
||||
$prefix_on_missing = false;
|
||||
|
||||
switch ($op) {
|
||||
case "reserved":
|
||||
// Reserved means certain characters should not be URL encoded
|
||||
$data = $this->replaceVars($data, $parameters, ",", null, true);
|
||||
break;
|
||||
case "fragment":
|
||||
// Comma separated with fragment prefix. Bare values only.
|
||||
$prefix = "#";
|
||||
$prefix_on_missing = true;
|
||||
$data = $this->replaceVars($data, $parameters, ",", null, true);
|
||||
break;
|
||||
case "segments":
|
||||
// Slash separated data. Bare values only.
|
||||
$prefix = "/";
|
||||
$data =$this->replaceVars($data, $parameters, "/");
|
||||
break;
|
||||
case "dotprefix":
|
||||
// Dot separated data. Bare values only.
|
||||
$prefix = ".";
|
||||
$prefix_on_missing = true;
|
||||
$data = $this->replaceVars($data, $parameters, ".");
|
||||
break;
|
||||
case "semicolon":
|
||||
// Semicolon prefixed and separated. Uses the key name
|
||||
$prefix = ";";
|
||||
$data = $this->replaceVars($data, $parameters, ";", "=", false, true, false);
|
||||
break;
|
||||
case "form":
|
||||
// Standard URL format. Uses the key name
|
||||
$prefix = "?";
|
||||
$data = $this->replaceVars($data, $parameters, "&", "=");
|
||||
break;
|
||||
case "continuation":
|
||||
// Standard URL, but with leading ampersand. Uses key name.
|
||||
$prefix = "&";
|
||||
$data = $this->replaceVars($data, $parameters, "&", "=");
|
||||
break;
|
||||
}
|
||||
|
||||
// Add the initial prefix character if data is valid.
|
||||
if ($data || ($data !== false && $prefix_on_missing)) {
|
||||
$data = $prefix . $data;
|
||||
}
|
||||
|
||||
} else {
|
||||
// If no operator we replace with the defaults.
|
||||
$data = $this->replaceVars($data, $parameters);
|
||||
}
|
||||
// This is chops out the {...} and replaces with the new section.
|
||||
return substr($string, 0, $start) . $data . substr($string, $end + 1);
|
||||
}
|
||||
|
||||
private function replaceVars(
|
||||
$section,
|
||||
$parameters,
|
||||
$sep = ",",
|
||||
$combine = null,
|
||||
$reserved = false,
|
||||
$tag_empty = false,
|
||||
$combine_on_empty = true
|
||||
) {
|
||||
if (strpos($section, ",") === false) {
|
||||
// If we only have a single value, we can immediately process.
|
||||
return $this->combine(
|
||||
$section,
|
||||
$parameters,
|
||||
$sep,
|
||||
$combine,
|
||||
$reserved,
|
||||
$tag_empty,
|
||||
$combine_on_empty
|
||||
);
|
||||
} else {
|
||||
// If we have multiple values, we need to split and loop over them.
|
||||
// Each is treated individually, then glued together with the
|
||||
// separator character.
|
||||
$vars = explode(",", $section);
|
||||
return $this->combineList(
|
||||
$vars,
|
||||
$sep,
|
||||
$parameters,
|
||||
$combine,
|
||||
$reserved,
|
||||
false, // Never emit empty strings in multi-param replacements
|
||||
$combine_on_empty
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function combine(
|
||||
$key,
|
||||
$parameters,
|
||||
$sep,
|
||||
$combine,
|
||||
$reserved,
|
||||
$tag_empty,
|
||||
$combine_on_empty
|
||||
) {
|
||||
$length = false;
|
||||
$explode = false;
|
||||
$skip_final_combine = false;
|
||||
$value = false;
|
||||
|
||||
// Check for length restriction.
|
||||
if (strpos($key, ":") !== false) {
|
||||
list($key, $length) = explode(":", $key);
|
||||
}
|
||||
|
||||
// Check for explode parameter.
|
||||
if ($key[strlen($key) - 1] == "*") {
|
||||
$explode = true;
|
||||
$key = substr($key, 0, -1);
|
||||
$skip_final_combine = true;
|
||||
}
|
||||
|
||||
// Define the list separator.
|
||||
$list_sep = $explode ? $sep : ",";
|
||||
|
||||
if (isset($parameters[$key])) {
|
||||
$data_type = $this->getDataType($parameters[$key]);
|
||||
switch ($data_type) {
|
||||
case self::TYPE_SCALAR:
|
||||
$value = $this->getValue($parameters[$key], $length);
|
||||
break;
|
||||
case self::TYPE_LIST:
|
||||
$values = array();
|
||||
foreach ($parameters[$key] as $pkey => $pvalue) {
|
||||
$pvalue = $this->getValue($pvalue, $length);
|
||||
if ($combine && $explode) {
|
||||
$values[$pkey] = $key . $combine . $pvalue;
|
||||
} else {
|
||||
$values[$pkey] = $pvalue;
|
||||
}
|
||||
}
|
||||
$value = implode($list_sep, $values);
|
||||
if ($value == '') {
|
||||
return '';
|
||||
}
|
||||
break;
|
||||
case self::TYPE_MAP:
|
||||
$values = array();
|
||||
foreach ($parameters[$key] as $pkey => $pvalue) {
|
||||
$pvalue = $this->getValue($pvalue, $length);
|
||||
if ($explode) {
|
||||
$pkey = $this->getValue($pkey, $length);
|
||||
$values[] = $pkey . "=" . $pvalue; // Explode triggers = combine.
|
||||
} else {
|
||||
$values[] = $pkey;
|
||||
$values[] = $pvalue;
|
||||
}
|
||||
}
|
||||
$value = implode($list_sep, $values);
|
||||
if ($value == '') {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if ($tag_empty) {
|
||||
// If we are just indicating empty values with their key name, return that.
|
||||
return $key;
|
||||
} else {
|
||||
// Otherwise we can skip this variable due to not being defined.
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($reserved) {
|
||||
$value = str_replace($this->reservedEncoded, $this->reserved, $value);
|
||||
}
|
||||
|
||||
// If we do not need to include the key name, we just return the raw
|
||||
// value.
|
||||
if (!$combine || $skip_final_combine) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// Else we combine the key name: foo=bar, if value is not the empty string.
|
||||
return $key . ($value != '' || $combine_on_empty ? $combine . $value : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of a passed in value
|
||||
*/
|
||||
private function getDataType($data)
|
||||
{
|
||||
if (is_array($data)) {
|
||||
reset($data);
|
||||
if (key($data) !== 0) {
|
||||
return self::TYPE_MAP;
|
||||
}
|
||||
return self::TYPE_LIST;
|
||||
}
|
||||
return self::TYPE_SCALAR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function that merges multiple combine calls
|
||||
* for multi-key templates.
|
||||
*/
|
||||
private function combineList(
|
||||
$vars,
|
||||
$sep,
|
||||
$parameters,
|
||||
$combine,
|
||||
$reserved,
|
||||
$tag_empty,
|
||||
$combine_on_empty
|
||||
) {
|
||||
$ret = array();
|
||||
foreach ($vars as $var) {
|
||||
$response = $this->combine(
|
||||
$var,
|
||||
$parameters,
|
||||
$sep,
|
||||
$combine,
|
||||
$reserved,
|
||||
$tag_empty,
|
||||
$combine_on_empty
|
||||
);
|
||||
if ($response === false) {
|
||||
continue;
|
||||
}
|
||||
$ret[] = $response;
|
||||
}
|
||||
return implode($sep, $ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function to encode and trim values
|
||||
*/
|
||||
private function getValue($value, $length)
|
||||
{
|
||||
if ($length) {
|
||||
$value = substr($value, 0, $length);
|
||||
}
|
||||
$value = rawurlencode($value);
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
21
vendor/google/apiclient/src/Google/autoload.php
vendored
Normal file
21
vendor/google/apiclient/src/Google/autoload.php
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* THIS FILE IS FOR BACKWARDS COMPATIBLITY ONLY
|
||||
*
|
||||
* If you were not already including this file in your project, please ignore it
|
||||
*/
|
||||
|
||||
$file = __DIR__ . '/../../vendor/autoload.php';
|
||||
|
||||
if (!file_exists($file)) {
|
||||
$exception = 'This library must be installed via composer or by downloading the full package.';
|
||||
$exception .= ' See the instructions at https://github.com/google/google-api-php-client#installation.';
|
||||
throw new Exception($exception);
|
||||
}
|
||||
|
||||
$error = 'google-api-php-client\'s autoloader was moved to vendor/autoload.php in 2.0.0. This ';
|
||||
$error .= 'redirect will be removed in 2.1. Please adjust your code to use the new location.';
|
||||
trigger_error($error, E_USER_DEPRECATED);
|
||||
|
||||
require_once $file;
|
||||
Reference in New Issue
Block a user