diff --git a/.gitignore b/.gitignore index 8c11bd412..92128bc2d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,6 @@ .DS_Store phpunit.xml -composer.lock vendor examples/testfile-small.txt examples/testfile.txt -tests/.accessToken tests/.apiKey diff --git a/README.md b/README.md index d9797b828..fb30e7ee6 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Build Status](https://travis-ci.org/google/google-api-php-client.svg)](https://travis-ci.org/google/google-api-php-client) +[![Build Status](https://travis-ci.org/google/google-api-php-client.svg)](https://travis-ci.org/google/google-api-php-client.svg?branch=master) # Google APIs Client Library for PHP # @@ -9,10 +9,7 @@ The Google API Client Library enables you to work with Google APIs such as Googl This library is in Beta. We're comfortable enough with the stability and features of the library that we want you to build real production applications on it. We will make an effort to support the public and protected surface of the library and maintain backwards compatibility in the future. While we are still in Beta, we reserve the right to make incompatible changes. If we do remove some functionality (typically because better functionality exists or if the feature proved infeasible), our intention is to deprecate and provide ample time for developers to update their code. ## Requirements ## -* [PHP 5.2.1 or higher](http://www.php.net/) -* [PHP JSON extension](http://php.net/manual/en/book.json.php) - -*Note*: some features (service accounts and id token verification) require PHP 5.3.0 and above due to cryptographic algorithm requirements. +* [PHP 5.4.0 or higher](http://www.php.net/) ## Developer Documentation ## http://developers.google.com/api-client-library/php @@ -22,24 +19,32 @@ http://developers.google.com/api-client-library/php For the latest installation and setup instructions, see [the documentation](https://developers.google.com/api-client-library/php/start/installation). ## Basic Example ## -See the examples/ directory for examples of the key client features. +See the examples/ directory for examples of the key client features. You can +view them in your browser by running the php built-in web server. + +``` +$ cd examples/ +$ php -S localhost:8000 +``` + +And then browsing to the host and port you specified +(in the above example, `http://localhost:8000`). + ```PHP -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'], "
\n"; - } - +// 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'], "
\n"; +} ``` ### Service Specific Examples ### @@ -58,7 +63,7 @@ If there is a specific bug with the library, please file a issue in the Github i We accept contributions via Github Pull Requests, but all contributors need to be covered by the standard Google Contributor License Agreement. You can find links, and more instructions, in the documentation: https://developers.google.com/api-client-library/php/contribute -### I want an example of X! ### +### 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! @@ -68,7 +73,7 @@ When we started working on the 1.0.0 branch we knew there were several fundament ### 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. +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? ### @@ -95,10 +100,10 @@ Run the PHPUnit tests with PHPUnit. You can configure an API key and token in Ba To check for coding style violations, run ``` -vendor/bin/phpcs src --standard=style/ruleset.xml -np +vendor/bin/phpcs src --standard=style/ruleset.xml -np ``` -To automatically fix (fixable) coding style violations, run +To automatically fix (fixable) coding style violations, run ``` vendor/bin/phpcbf src --standard=style/ruleset.xml diff --git a/composer.json b/composer.json index 2975a421d..752e04780 100644 --- a/composer.json +++ b/composer.json @@ -7,16 +7,23 @@ "license": "Apache-2.0", "require": { "php": ">=5.4", - "google/auth": "dev-master", - "monolog/monolog": "^1.17" + "google/auth": "v0.2-alpha", + "monolog/monolog": "^1.17", + "phpseclib/phpseclib": "~2.0", + "guzzlehttp/guzzle": "5.2.*" }, "require-dev": { - "phpunit/phpunit": "3.7.*", - "squizlabs/php_codesniffer": "~2.3" + "phpunit/phpunit": "~4", + "squizlabs/php_codesniffer": "~2.3", + "symfony/dom-crawler": "~2.0", + "symfony/css-selector": "~2.0" }, "autoload": { + "psr-0": { + "Google_": "src/" + }, "classmap": [ - "src/" + "src/Google/Service/" ] }, "extra": { diff --git a/composer.lock b/composer.lock new file mode 100644 index 000000000..db10d558c --- /dev/null +++ b/composer.lock @@ -0,0 +1,1649 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "hash": "6ea1c309fe27e654f278f887bb13198d", + "packages": [ + { + "name": "firebase/php-jwt", + "version": "2.0.0", + "target-dir": "Firebase/PHP-JWT", + "source": { + "type": "git", + "url": "https://github.com/firebase/php-jwt.git", + "reference": "ffcfd888ce1e4f2d70cac2dc9b7301038332fe57" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/firebase/php-jwt/zipball/ffcfd888ce1e4f2d70cac2dc9b7301038332fe57", + "reference": "ffcfd888ce1e4f2d70cac2dc9b7301038332fe57", + "shasum": "" + }, + "require": { + "php": ">=5.2.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "Authentication/", + "Exceptions/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Neuman Vong", + "email": "neuman+pear@twilio.com", + "role": "Developer" + }, + { + "name": "Anant Narayanan", + "email": "anant@php.net", + "role": "Developer" + } + ], + "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", + "homepage": "https://github.com/firebase/php-jwt", + "time": "2015-04-01 18:46:38" + }, + { + "name": "google/auth", + "version": "v0.2-alpha", + "source": { + "type": "git", + "url": "https://github.com/google/google-auth-library-php.git", + "reference": "5dc5bcb37a7f50c7132c1feb5037f6c45b249477" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/google/google-auth-library-php/zipball/5dc5bcb37a7f50c7132c1feb5037f6c45b249477", + "reference": "5dc5bcb37a7f50c7132c1feb5037f6c45b249477", + "shasum": "" + }, + "require": { + "firebase/php-jwt": "2.0.0", + "guzzlehttp/guzzle": "5.2.*", + "php": ">=5.4" + }, + "require-dev": { + "phplint/phplint": "0.0.1", + "phpunit/phpunit": "3.7.*" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ], + "psr-4": { + "Google\\Auth\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Google Auth Library for PHP", + "homepage": "http://github.com/google/google-auth-library-php", + "keywords": [ + "Authentication", + "google", + "oauth2" + ], + "time": "2015-10-09 16:50:15" + }, + { + "name": "guzzlehttp/guzzle", + "version": "5.2.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "475b29ccd411f2fa8a408e64576418728c032cfa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/475b29ccd411f2fa8a408e64576418728c032cfa", + "reference": "475b29ccd411f2fa8a408e64576418728c032cfa", + "shasum": "" + }, + "require": { + "guzzlehttp/ringphp": "~1.0", + "php": ">=5.4.0" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "~4.0", + "psr/log": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "time": "2015-01-28 01:03:29" + }, + { + "name": "guzzlehttp/ringphp", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/RingPHP.git", + "reference": "dbbb91d7f6c191e5e405e900e3102ac7f261bc0b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/RingPHP/zipball/dbbb91d7f6c191e5e405e900e3102ac7f261bc0b", + "reference": "dbbb91d7f6c191e5e405e900e3102ac7f261bc0b", + "shasum": "" + }, + "require": { + "guzzlehttp/streams": "~3.0", + "php": ">=5.4.0", + "react/promise": "~2.0" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "~4.0" + }, + "suggest": { + "ext-curl": "Guzzle will use specific adapters if cURL is present" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Ring\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Provides a simple API and specification that abstracts away the details of HTTP into a single PHP function.", + "time": "2015-05-20 03:37:09" + }, + { + "name": "guzzlehttp/streams", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/streams.git", + "reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/streams/zipball/47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5", + "reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Stream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Provides a simple abstraction over streams of data", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "Guzzle", + "stream" + ], + "time": "2014-10-12 19:18:40" + }, + { + "name": "monolog/monolog", + "version": "1.17.1", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "0524c87587ab85bc4c2d6f5b41253ccb930a5422" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/0524c87587ab85bc4c2d6f5b41253ccb930a5422", + "reference": "0524c87587ab85bc4c2d6f5b41253ccb930a5422", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "~1.0" + }, + "provide": { + "psr/log-implementation": "1.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^2.4.9", + "doctrine/couchdb": "~1.0@dev", + "graylog2/gelf-php": "~1.0", + "php-console/php-console": "^3.1.3", + "phpunit/phpunit": "~4.5", + "phpunit/phpunit-mock-objects": "2.3.0", + "raven/raven": "~0.11", + "ruflin/elastica": ">=0.90 <3.0", + "swiftmailer/swiftmailer": "~5.3", + "videlalvaro/php-amqplib": "~2.4" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-mongo": "Allow sending log messages to a MongoDB server", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "php-console/php-console": "Allow sending log messages to Google Chrome", + "raven/raven": "Allow sending log messages to a Sentry server", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server", + "videlalvaro/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.16.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "http://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "time": "2015-08-31 09:17:37" + }, + { + "name": "phpseclib/phpseclib", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/phpseclib/phpseclib.git", + "reference": "a74aa9efbe61430fcb60157c8e025a48ec8ff604" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/a74aa9efbe61430fcb60157c8e025a48ec8ff604", + "reference": "a74aa9efbe61430fcb60157c8e025a48ec8ff604", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phing/phing": "~2.7", + "phpunit/phpunit": "~4.0", + "sami/sami": "~2.0", + "squizlabs/php_codesniffer": "~2.0" + }, + "suggest": { + "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", + "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", + "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", + "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations.", + "pear-pear/PHP_Compat": "Install PHP_Compat to get phpseclib working on PHP < 5.0.0." + }, + "type": "library", + "autoload": { + "psr-4": { + "phpseclib\\": "phpseclib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "phpseclib/" + ], + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jim Wigginton", + "email": "terrafrost@php.net", + "role": "Lead Developer" + }, + { + "name": "Patrick Monnerat", + "email": "pm@datasphere.ch", + "role": "Developer" + }, + { + "name": "Andreas Fischer", + "email": "bantu@phpbb.com", + "role": "Developer" + }, + { + "name": "Hans-Jürgen Petrich", + "email": "petrich@tronic-media.com", + "role": "Developer" + } + ], + "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.", + "homepage": "http://phpseclib.sourceforge.net", + "keywords": [ + "BigInteger", + "aes", + "asn.1", + "asn1", + "blowfish", + "crypto", + "cryptography", + "encryption", + "rsa", + "security", + "sftp", + "signature", + "signing", + "ssh", + "twofish", + "x.509", + "x509" + ], + "time": "2015-08-04 04:48:03" + }, + { + "name": "psr/log", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-0": { + "Psr\\Log\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2012-12-21 11:40:51" + }, + { + "name": "react/promise", + "version": "v2.2.1", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise.git", + "reference": "3b6fca09c7d56321057fa8867c8dbe1abf648627" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise/zipball/3b6fca09c7d56321057fa8867c8dbe1abf648627", + "reference": "3b6fca09c7d56321057fa8867c8dbe1abf648627", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "React\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com" + } + ], + "description": "A lightweight implementation of CommonJS Promises/A for PHP", + "time": "2015-07-03 13:48:55" + } + ], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "shasum": "" + }, + "require": { + "php": ">=5.3,<8.0-DEV" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2015-06-14 21:17:01" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8", + "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "suggest": { + "dflydev/markdown": "~1.0", + "erusev/parsedown": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "phpDocumentor": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "mike.vanriel@naenius.com" + } + ], + "time": "2015-02-03 12:10:50" + }, + { + "name": "phpspec/prophecy", + "version": "v1.5.0", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "4745ded9307786b730d7a60df5cb5a6c43cf95f7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4745ded9307786b730d7a60df5cb5a6c43cf95f7", + "reference": "4745ded9307786b730d7a60df5cb5a6c43cf95f7", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "phpdocumentor/reflection-docblock": "~2.0", + "sebastian/comparator": "~1.1" + }, + "require-dev": { + "phpspec/phpspec": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "psr-0": { + "Prophecy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2015-08-13 10:07:40" + }, + { + "name": "phpunit/php-code-coverage", + "version": "2.2.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979", + "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-file-iterator": "~1.3", + "phpunit/php-text-template": "~1.2", + "phpunit/php-token-stream": "~1.3", + "sebastian/environment": "^1.3.2", + "sebastian/version": "~1.0" + }, + "require-dev": { + "ext-xdebug": ">=2.1.4", + "phpunit/phpunit": "~4" + }, + "suggest": { + "ext-dom": "*", + "ext-xdebug": ">=2.2.1", + "ext-xmlwriter": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2015-10-06 15:47:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0", + "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2015-06-21 13:08:43" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2015-06-21 13:50:34" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.7", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3e82f4e9fc92665fafd9157568e4dcb01d014e5b", + "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2015-06-21 08:01:12" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.4.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", + "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2015-09-15 10:49:45" + }, + { + "name": "phpunit/phpunit", + "version": "4.8.12", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "00194eb95989190a73198390ceca081ad3441a7f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/00194eb95989190a73198390ceca081ad3441a7f", + "reference": "00194eb95989190a73198390ceca081ad3441a7f", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.3.3", + "phpspec/prophecy": "^1.3.1", + "phpunit/php-code-coverage": "~2.1", + "phpunit/php-file-iterator": "~1.4", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": ">=1.0.6", + "phpunit/phpunit-mock-objects": "~2.3", + "sebastian/comparator": "~1.1", + "sebastian/diff": "~1.2", + "sebastian/environment": "~1.3", + "sebastian/exporter": "~1.2", + "sebastian/global-state": "~1.0", + "sebastian/version": "~1.0", + "symfony/yaml": "~2.1|~3.0" + }, + "suggest": { + "phpunit/php-invoker": "~1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.8.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2015-10-12 03:36:47" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "2.3.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983", + "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": ">=5.3.3", + "phpunit/php-text-template": "~1.2", + "sebastian/exporter": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2015-10-02 06:51:40" + }, + { + "name": "sebastian/comparator", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "937efb279bd37a375bcadf584dec0726f84dbf22" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22", + "reference": "937efb279bd37a375bcadf584dec0726f84dbf22", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/diff": "~1.2", + "sebastian/exporter": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2015-07-26 15:48:44" + }, + { + "name": "sebastian/diff", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "863df9687835c62aa423a22412d26fa2ebde3fd3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/863df9687835c62aa423a22412d26fa2ebde3fd3", + "reference": "863df9687835c62aa423a22412d26fa2ebde3fd3", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "http://www.github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "time": "2015-02-22 15:13:53" + }, + { + "name": "sebastian/environment", + "version": "1.3.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "6324c907ce7a52478eeeaede764f48733ef5ae44" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/6324c907ce7a52478eeeaede764f48733ef5ae44", + "reference": "6324c907ce7a52478eeeaede764f48733ef5ae44", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2015-08-03 06:14:51" + }, + { + "name": "sebastian/exporter", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "7ae5513327cb536431847bcc0c10edba2701064e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/7ae5513327cb536431847bcc0c10edba2701064e", + "reference": "7ae5513327cb536431847bcc0c10edba2701064e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/recursion-context": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2015-06-21 07:55:53" + }, + { + "name": "sebastian/global-state", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2015-10-12 03:26:01" + }, + { + "name": "sebastian/recursion-context", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "994d4a811bafe801fb06dccbee797863ba2792ba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/994d4a811bafe801fb06dccbee797863ba2792ba", + "reference": "994d4a811bafe801fb06dccbee797863ba2792ba", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2015-06-21 08:04:50" + }, + { + "name": "sebastian/version", + "version": "1.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", + "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", + "shasum": "" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2015-06-21 13:59:46" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "2.3.4", + "source": { + "type": "git", + "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", + "reference": "11a2545c44a5915f883e2e5ec12e14ed345e3ab2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/11a2545c44a5915f883e2e5ec12e14ed345e3ab2", + "reference": "11a2545c44a5915f883e2e5ec12e14ed345e3ab2", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.1.2" + }, + "bin": [ + "scripts/phpcs", + "scripts/phpcbf" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "CodeSniffer.php", + "CodeSniffer/CLI.php", + "CodeSniffer/Exception.php", + "CodeSniffer/File.php", + "CodeSniffer/Fixer.php", + "CodeSniffer/Report.php", + "CodeSniffer/Reporting.php", + "CodeSniffer/Sniff.php", + "CodeSniffer/Tokens.php", + "CodeSniffer/Reports/", + "CodeSniffer/Tokenizers/", + "CodeSniffer/DocGenerators/", + "CodeSniffer/Standards/AbstractPatternSniff.php", + "CodeSniffer/Standards/AbstractScopeSniff.php", + "CodeSniffer/Standards/AbstractVariableSniff.php", + "CodeSniffer/Standards/IncorrectPatternException.php", + "CodeSniffer/Standards/Generic/Sniffs/", + "CodeSniffer/Standards/MySource/Sniffs/", + "CodeSniffer/Standards/PEAR/Sniffs/", + "CodeSniffer/Standards/PSR1/Sniffs/", + "CodeSniffer/Standards/PSR2/Sniffs/", + "CodeSniffer/Standards/Squiz/Sniffs/", + "CodeSniffer/Standards/Zend/Sniffs/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "lead" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "http://www.squizlabs.com/php-codesniffer", + "keywords": [ + "phpcs", + "standards" + ], + "time": "2015-09-09 00:18:50" + }, + { + "name": "symfony/css-selector", + "version": "v2.7.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "abe19cc0429a06be0c133056d1f9859854860970" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/abe19cc0429a06be0c133056d1f9859854860970", + "reference": "abe19cc0429a06be0c133056d1f9859854860970", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony CssSelector Component", + "homepage": "https://symfony.com", + "time": "2015-09-22 13:49:29" + }, + { + "name": "symfony/dom-crawler", + "version": "v2.7.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "2e185ca136399f902b948694987e62c80099c052" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/2e185ca136399f902b948694987e62c80099c052", + "reference": "2e185ca136399f902b948694987e62c80099c052", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "symfony/css-selector": "~2.3", + "symfony/phpunit-bridge": "~2.7" + }, + "suggest": { + "symfony/css-selector": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\DomCrawler\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony DomCrawler Component", + "homepage": "https://symfony.com", + "time": "2015-09-20 21:13:58" + }, + { + "name": "symfony/yaml", + "version": "v2.7.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "31cb2ad0155c95b88ee55fe12bc7ff92232c1770" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/31cb2ad0155c95b88ee55fe12bc7ff92232c1770", + "reference": "31cb2ad0155c95b88ee55fe12bc7ff92232c1770", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "https://symfony.com", + "time": "2015-09-14 14:14:09" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": { + "google/auth": 15 + }, + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=5.4" + }, + "platform-dev": [] +} diff --git a/examples/appengineauth.php b/examples/appengineauth.php deleted file mode 100644 index 7b147e9e5..000000000 --- a/examples/appengineauth.php +++ /dev/null @@ -1,46 +0,0 @@ -setApplicationName("Client_Library_Examples"); - -$auth = new Google_Auth_AppIdentity($client); -$token = $auth->authenticateForScope(Google_Service_Storage::DEVSTORAGE_READ_ONLY); -if (!$token) { - die("Could not authenticate to AppIdentity service"); -} -$client->setAuth($auth); - -$service = new Google_Service_Storage($client); -$results = $service->buckets->listBuckets(str_replace("s~", "", $_SERVER['APPLICATION_ID'])); - -echo "

Results Of Call:

"; -echo "
";
-var_dump($results);
-echo "
"; - -echo pageFooter(__FILE__); diff --git a/examples/batch.php b/examples/batch.php index 3c8812f51..5d546562b 100644 --- a/examples/batch.php +++ b/examples/batch.php @@ -14,7 +14,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +include_once __DIR__ . '/../vendor/autoload.php'; include_once "templates/base.php"; + echo pageHeader("Batching Queries"); /************************************************ @@ -22,7 +25,6 @@ books API again as an example, but this time we will batch up two queries into a single call. ************************************************/ -require_once realpath(dirname(__FILE__) . '/../src/Google/autoload.php'); /************************************************ We create the client and set the simple API @@ -32,51 +34,50 @@ ************************************************/ $client = new Google_Client(); $client->setApplicationName("Client_Library_Examples"); -$apiKey = ""; // Change to your API key. -// Warn if the API key isn't changed! -if (strpos($apiKey, "<") !== false) { + +// Warn if the API key isn't set. +if (!$apiKey = getApiKey()) { echo missingApiKeyWarning(); exit; -} else { - $client->setDeveloperKey($apiKey); +} +$client->setDeveloperKey($apiKey); - $service = new Google_Service_Books($client); +$service = new Google_Service_Books($client); - /************************************************ - To actually make the batch call we need to - enable batching on the client - this will apply - globally until we set it to false. This causes - call to the service methods to return the query - rather than immediately executing. - ************************************************/ - $client->setUseBatch(true); +/************************************************ + To actually make the batch call we need to + enable batching on the client - this will apply + globally until we set it to false. This causes + call to the service methods to return the query + rather than immediately executing. + ************************************************/ +$client->setUseBatch(true); - /************************************************ - We then create a batch, and add each query we - want to execute with keys of our choice - these - keys will be reflected in the returned array. - ************************************************/ - $batch = new Google_Http_Batch($client); - $optParams = array('filter' => 'free-ebooks'); - $req1 = $service->volumes->listVolumes('Henry David Thoreau', $optParams); - $batch->add($req1, "thoreau"); - $req2 = $service->volumes->listVolumes('George Bernard Shaw', $optParams); - $batch->add($req2, "shaw"); +/************************************************ + We then create a batch, and add each query we + want to execute with keys of our choice - these + keys will be reflected in the returned array. +************************************************/ +$batch = new Google_Http_Batch($client); +$optParams = array('filter' => 'free-ebooks'); +$req1 = $service->volumes->listVolumes('Henry David Thoreau', $optParams); +$batch->add($req1, "thoreau"); +$req2 = $service->volumes->listVolumes('George Bernard Shaw', $optParams); +$batch->add($req2, "shaw"); - /************************************************ - Executing the batch will send all requests off - at once. - ************************************************/ - $results = $batch->execute(); +/************************************************ + Executing the batch will send all requests off + at once. + ************************************************/ +$results = $batch->execute(); - echo "

Results Of Call 1:

"; - foreach ($results['response-thoreau'] as $item) { - echo $item['volumeInfo']['title'], "
\n"; - } - echo "

Results Of Call 2:

"; - foreach ($results['response-shaw'] as $item) { - echo $item['volumeInfo']['title'], "
\n"; - } +echo "

Results Of Call 1:

"; +foreach ($results['response-thoreau'] as $item) { + echo $item['volumeInfo']['title'], "
\n"; +} +echo "

Results Of Call 2:

"; +foreach ($results['response-shaw'] as $item) { + echo $item['volumeInfo']['title'], "
\n"; } echo pageFooter(__FILE__); diff --git a/examples/idtoken.php b/examples/idtoken.php index 80aefa621..465c64f22 100644 --- a/examples/idtoken.php +++ b/examples/idtoken.php @@ -14,45 +14,57 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +include_once __DIR__ . '/../vendor/autoload.php'; include_once "templates/base.php"; -session_start(); -require_once realpath(dirname(__FILE__) . '/../src/Google/autoload.php'); +echo pageHeader("Retrieving An Id Token"); + +/************************************************* + * Ensure you've downloaded your oauth credentials + ************************************************/ +if (!$oauth_credentials = getOAuthCredentialsFile()) { + echo missingOAuth2CredentialsWarning(); + exit; +} /************************************************ - ATTENTION: Fill in these values! Make sure - the redirect URI is to this page, e.g: - http://localhost:8080/user-example.php + * NOTICE: + * The redirect URI is to the current page, e.g: + * http://localhost:8080/idtoken.php ************************************************/ -$client_id = ''; -$client_secret = ''; -$redirect_uri = ''; +$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']; $client = new Google_Client(); -$client->setClientId($client_id); -$client->setClientSecret($client_secret); +$client->setAuthConfig($oauth_credentials); $client->setRedirectUri($redirect_uri); $client->setScopes('email'); /************************************************ - If we're logging out we just need to clear our - local access token in this case + * If we're logging out we just need to clear our + * local access token in this case ************************************************/ if (isset($_REQUEST['logout'])) { - unset($_SESSION['access_token']); + unset($_SESSION['id_token']); } + /************************************************ - If we have a code back from the OAuth 2.0 flow, - we need to exchange that with the authenticate() - function. We store the resultant access token - bundle in the session, and redirect to ourself. + * If we have a code back from the OAuth 2.0 flow, + * we need to exchange that with the + * Google_Client::fetchAccessTokenWithAuthCode() + * function. We store the resultant access token + * bundle in the session, and redirect to ourself. ************************************************/ if (isset($_GET['code'])) { - $client->authenticate($_GET['code']); - $_SESSION['access_token'] = $client->getAccessToken(); - $redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']; - header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL)); + $token = $client->fetchAccessTokenWithAuthCode($_GET['code']); + $client->setAccessToken($token); + + // store in the session also + $_SESSION['id_token'] = $token; + + // redirect back to the example + header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL)); } /************************************************ @@ -60,11 +72,10 @@ function. We store the resultant access token requests, else we generate an authentication URL. ************************************************/ if ( - isset($_SESSION['access_token']) - && $_SESSION['access_token'] - && false !== strpos($_SESSION['access_token'], 'id_token') + !empty($_SESSION['id_token']) + && isset($_SESSION['id_token']['id_token']) ) { - $client->setAccessToken($_SESSION['access_token']); + $client->setAccessToken($_SESSION['id_token']); } else { $authUrl = $client->createAuthUrl(); } @@ -78,34 +89,21 @@ function. We store the resultant access token and that can be cached. ************************************************/ if ($client->getAccessToken()) { - $_SESSION['access_token'] = $client->getAccessToken(); $token_data = $client->verifyIdToken(); } - -echo pageHeader("User Query - Retrieving An Id Token"); -if (strpos($client_id, "googleusercontent") == false) { - echo missingClientSecretsWarning(); - exit; -} ?> +
+
-Connect Me!"; -} else { - echo "Logout"; -} -?> +
- +
- +

Here is the data from your Id Token:

+
+
- diff --git a/examples/index.php b/examples/index.php index 243c9c02a..e901d4bf2 100644 --- a/examples/index.php +++ b/examples/index.php @@ -1,19 +1,41 @@ - + + + + + +
+  To view this page on a webserver using PHP 5.4 or above run:
+    php -S localhost:8080
+  
+ + + + + + + API Key set! + + + + +
+ You have not entered your API key +
+ API Key: + +
+ This can be found in the Google API Console +
+ + - diff --git a/examples/fileupload.php b/examples/large-file-upload.php similarity index 60% rename from examples/fileupload.php rename to examples/large-file-upload.php index 2247087e9..641308a68 100644 --- a/examples/fileupload.php +++ b/examples/large-file-upload.php @@ -14,50 +14,57 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +include_once __DIR__ . '/../vendor/autoload.php'; include_once "templates/base.php"; -session_start(); -require_once realpath(dirname(__FILE__) . '/../src/Google/autoload.php'); +echo pageHeader("File Upload - Uploading a large file"); -/************************************************ - We'll setup an empty 20MB file to upload. +/************************************************* + * Ensure you've downloaded your oauth credentials ************************************************/ -DEFINE("TESTFILE", 'testfile.txt'); -if (!file_exists(TESTFILE)) { - $fh = fopen(TESTFILE, 'w'); - fseek($fh, 1024*1024*20); - fwrite($fh, "!", 1); - fclose($fh); +if (!$oauth_credentials = getOAuthCredentialsFile()) { + echo missingOAuth2CredentialsWarning(); + exit; } /************************************************ - ATTENTION: Fill in these values! Make sure - the redirect URI is to this page, e.g: - http://localhost:8080/fileupload.php + * The redirect URI is to the current page, e.g: + * http://localhost:8080/large-file-upload.php ************************************************/ -$client_id = ''; -$client_secret = ''; -$redirect_uri = ''; +$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']; $client = new Google_Client(); -$client->setClientId($client_id); -$client->setClientSecret($client_secret); +$client->setAuthConfig($oauth_credentials); $client->setRedirectUri($redirect_uri); $client->addScope("https://www.googleapis.com/auth/drive"); $service = new Google_Service_Drive($client); +// add "?logout" to the URL to remove a token from the session if (isset($_REQUEST['logout'])) { unset($_SESSION['upload_token']); } +/************************************************ + * If we have a code back from the OAuth 2.0 flow, + * we need to exchange that with the + * Google_Client::fetchAccessTokenWithAuthCode() + * function. We store the resultant access token + * bundle in the session, and redirect to ourself. + ************************************************/ if (isset($_GET['code'])) { - $client->authenticate($_GET['code']); - $_SESSION['upload_token'] = $client->getAccessToken(); - $redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']; - header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL)); + $token = $client->fetchAccessTokenWithAuthCode($_GET['code']); + $client->setAccessToken($token); + + // store in the session also + $_SESSION['upload_token'] = $token; + + // redirect back to the example + header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL)); } -if (isset($_SESSION['upload_token']) && $_SESSION['upload_token']) { +// set the access token as part of the client +if (!empty($_SESSION['upload_token'])) { $client->setAccessToken($_SESSION['upload_token']); if ($client->isAccessTokenExpired()) { unset($_SESSION['upload_token']); @@ -67,10 +74,21 @@ } /************************************************ - If we're signed in then lets try to upload our - file. + * If we're signed in then lets try to upload our + * file. ************************************************/ -if ($client->getAccessToken()) { +if ($_SERVER['REQUEST_METHOD'] == 'POST' && $client->getAccessToken()) { + /************************************************ + * We'll setup an empty 20MB file to upload. + ************************************************/ + DEFINE("TESTFILE", 'testfile.txt'); + if (!file_exists(TESTFILE)) { + $fh = fopen(TESTFILE, 'w'); + fseek($fh, 1024*1024*20); + fwrite($fh, "!", 1); + fclose($fh); + } + $file = new Google_Service_Drive_DriveFile(); $file->title = "Big File"; $chunkSizeBytes = 1 * 1024 * 1024; @@ -111,11 +129,7 @@ fclose($handle); } -echo pageHeader("File Upload - Uploading a large file"); -if (strpos($client_id, "googleusercontent") == false) { - echo missingClientSecretsWarning(); - exit; -} + function readVideoChunk ($handle, $chunkSize) { $byteCount = 0; @@ -133,22 +147,22 @@ function readVideoChunk ($handle, $chunkSize) return $giantChunk; } ?> +
+
-Connect Me!"; -} -?> +
- -
- -
+ +
+

Your call was successful! Check your drive for this file:

+

title ?>

+
+ +
+ +
+
- diff --git a/examples/multi-api.php b/examples/multi-api.php index e518b5da7..c6f9193e9 100644 --- a/examples/multi-api.php +++ b/examples/multi-api.php @@ -14,62 +14,75 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +include_once __DIR__ . '/../vendor/autoload.php'; include_once "templates/base.php"; -session_start(); -require_once realpath(dirname(__FILE__) . '/../src/Google/autoload.php'); +echo pageHeader("User Query - Multiple APIs"); -/************************************************ - ATTENTION: Fill in these values! Make sure - the redirect URI is to this page, e.g: - http://localhost:8080/user-example.php + +/************************************************* + * Ensure you've downloaded your oauth credentials ************************************************/ - $client_id = ''; - $client_secret = ''; - $redirect_uri = ''; +if (!$oauth_credentials = getOAuthCredentialsFile()) { + echo missingOAuth2CredentialsWarning(); + exit; +} /************************************************ - Make an API request on behalf of a user. In - this case we need to have a valid OAuth 2.0 - token for the user, so we need to send them - through a login flow. To do this we need some - information from our API console project. + * The redirect URI is to the current page, e.g: + * http://localhost:8080/multi-api.php ************************************************/ +$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']; + $client = new Google_Client(); -$client->setClientId($client_id); -$client->setClientSecret($client_secret); +$client->setAuthConfig($oauth_credentials); $client->setRedirectUri($redirect_uri); $client->addScope("https://www.googleapis.com/auth/drive"); $client->addScope("https://www.googleapis.com/auth/youtube"); -/************************************************ - We are going to create both YouTube and Drive - services, and query both. - ************************************************/ -$yt_service = new Google_Service_YouTube($client); -$dr_service = new Google_Service_Drive($client); +$service = new Google_Service_Drive($client); +// add "?logout" to the URL to remove a token from the session +if (isset($_REQUEST['logout'])) { + unset($_SESSION['multi-api-token']); +} /************************************************ - Boilerplate auth management - see - user-example.php for details. + * If we have a code back from the OAuth 2.0 flow, + * we need to exchange that with the + * Google_Client::fetchAccessTokenWithAuthCode() + * function. We store the resultant access token + * bundle in the session, and redirect to ourself. ************************************************/ -if (isset($_REQUEST['logout'])) { - unset($_SESSION['access_token']); -} if (isset($_GET['code'])) { - $client->authenticate($_GET['code']); - $_SESSION['access_token'] = $client->getAccessToken(); - $redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']; - header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL)); + $token = $client->fetchAccessTokenWithAuthCode($_GET['code']); + $client->setAccessToken($token); + + // store in the session also + $_SESSION['multi-api-token'] = $token; + + // redirect back to the example + header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL)); } -if (isset($_SESSION['access_token']) && $_SESSION['access_token']) { - $client->setAccessToken($_SESSION['access_token']); +// set the access token as part of the client +if (!empty($_SESSION['multi-api-token'])) { + $client->setAccessToken($_SESSION['multi-api-token']); + if ($client->isAccessTokenExpired()) { + unset($_SESSION['multi-api-token']); + } } else { $authUrl = $client->createAuthUrl(); } +/************************************************ + We are going to create both YouTube and Drive + services, and query both. + ************************************************/ +$yt_service = new Google_Service_YouTube($client); +$dr_service = new Google_Service_Drive($client); + /************************************************ If we're signed in, retrieve channels from YouTube and a list of files from Drive. @@ -86,29 +99,24 @@ array("playlistId" => $likePlaylist) ); } - -echo pageHeader("User Query - Multiple APIs"); -if (strpos($client_id, "googleusercontent") == false) { - echo missingClientSecretsWarning(); - exit; -} ?> +
-Connect Me!"; -} else { - echo "

Results Of Drive List:

"; - foreach ($dr_results as $item) { - echo $item->title, "
\n"; - } + + + +

Results Of Drive List:

+ + title ?>
+ - echo "

Results Of YouTube Likes:

"; - foreach ($yt_results as $item) { - echo $item['snippet']['title'], "
\n"; - } -} ?> +

Results Of YouTube Likes:

+ +
+ +
- diff --git a/examples/service-account.php b/examples/service-account.php index 594f822f3..bee5df7b3 100644 --- a/examples/service-account.php +++ b/examples/service-account.php @@ -14,18 +14,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -session_start(); + +include_once __DIR__ . '/../vendor/autoload.php'; include_once "templates/base.php"; +echo pageHeader("Service Account Access"); + /************************************************ Make an API request authenticated with a service account. ************************************************/ -require_once realpath(dirname(__FILE__) . '/../src/Google/autoload.php'); + +$client = new Google_Client(); /************************************************ - ATTENTION: Fill in these values! You can get - them by creating a new Service Account in the + ATTENTION: Fill in these values, or make sure you + have set the GOOGLE_APPLICATION_CREDENTIALS + environment variable. You can get these credentials + by creating a new Service Account in the API console. Be sure to store the key file somewhere you can get to it - though in real operations you'd want to make sure it wasn't @@ -33,36 +39,22 @@ Make sure the Books API is enabled on this account as well, or the call will fail. ************************************************/ -$key_file_location = ''; //.json credentials -echo pageHeader("Service Account Access"); -if (!strlen($key_file_location)) { +if ($credentials_file = checkServiceAccountCredentialsFile()) { + // set the location manually + $client->setAuthConfig($credentials_file); +} elseif (getenv('GOOGLE_APPLICATION_CREDENTIALS')) { + // use the application default credentials + $client->useApplicationDefaultCredentials(); +} else { echo missingServiceAccountDetailsWarning(); exit; } -$client = new Google_Client(); $client->setApplicationName("Client_Library_Examples"); $client->setScopes(['https://www.googleapis.com/auth/books']); $service = new Google_Service_Books($client); -/************************************************ - If we have an access token, we can carry on. - Otherwise, we'll get one with the help of an - assertion credential. In other examples the list - of scopes was managed by the Client, but here - we have to list them manually. We also supply - the service account - ************************************************/ -if (isset($_SESSION['service_token'])) { - $client->setAccessToken($_SESSION['service_token']); -} -$client->setAuthConfigFile($key_file_location); -if ($client->getAuth()->isAccessTokenExpired()) { - $client->getAuth()->refreshTokenWithAssertion(); -} -$_SESSION['service_token'] = $client->getAccessToken(); - /************************************************ We're just going to make the same call as in the simple query as an example. diff --git a/examples/simple-file-upload.php b/examples/simple-file-upload.php new file mode 100644 index 000000000..60fbf3a3d --- /dev/null +++ b/examples/simple-file-upload.php @@ -0,0 +1,135 @@ +setAuthConfig($oauth_credentials); +$client->setRedirectUri($redirect_uri); +$client->addScope("https://www.googleapis.com/auth/drive"); +$service = new Google_Service_Drive($client); + +// add "?logout" to the URL to remove a token from the session +if (isset($_REQUEST['logout'])) { + unset($_SESSION['upload_token']); +} + +/************************************************ + * If we have a code back from the OAuth 2.0 flow, + * we need to exchange that with the + * Google_Client::fetchAccessTokenWithAuthCode() + * function. We store the resultant access token + * bundle in the session, and redirect to ourself. + ************************************************/ +if (isset($_GET['code'])) { + $token = $client->fetchAccessTokenWithAuthCode($_GET['code']); + $client->setAccessToken($token); + + // store in the session also + $_SESSION['upload_token'] = $token; + + // redirect back to the example + header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL)); +} + +// set the access token as part of the client +if (!empty($_SESSION['upload_token'])) { + $client->setAccessToken($_SESSION['upload_token']); + if ($client->isAccessTokenExpired()) { + unset($_SESSION['upload_token']); + } +} else { + $authUrl = $client->createAuthUrl(); +} + +/************************************************ + * If we're signed in then lets try to upload our + * file. For larger files, see fileupload.php. + ************************************************/ +if ($_SERVER['REQUEST_METHOD'] == 'POST' && $client->getAccessToken()) { + // We'll setup an empty 1MB file to upload. + DEFINE("TESTFILE", 'testfile-small.txt'); + if (!file_exists(TESTFILE)) { + $fh = fopen(TESTFILE, 'w'); + fseek($fh, 1024 * 1024); + fwrite($fh, "!", 1); + fclose($fh); + } + + // This is uploading a file directly, with no metadata associated. + $file = new Google_Service_Drive_DriveFile(); + $result = $service->files->insert( + $file, + array( + 'data' => file_get_contents(TESTFILE), + 'mimeType' => 'application/octet-stream', + 'uploadType' => 'media' + ) + ); + + // Now lets try and send the metadata as well using multipart! + $file = new Google_Service_Drive_DriveFile(); + $file->setTitle("Hello World!"); + $result2 = $service->files->insert( + $file, + array( + 'data' => file_get_contents(TESTFILE), + 'mimeType' => 'application/octet-stream', + 'uploadType' => 'multipart' + ) + ); +} +?> + +
+ + + +
+

Your call was successful! Check your drive for the following files:

+ +
+ +
+ +
+ +
+ + diff --git a/examples/simple-query.php b/examples/simple-query.php index c0f1149cf..e02c34cf7 100644 --- a/examples/simple-query.php +++ b/examples/simple-query.php @@ -14,18 +14,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +include_once __DIR__ . '/../vendor/autoload.php'; include_once "templates/base.php"; -echo pageHeader("Simple API Access"); -/************************************************ - Make a simple API request using a key. In this - example we're not making a request as a - specific user, but simply indicating that the - request comes from our application, and hence - should use our quota, which is higher than the - anonymous quota (which is limited per IP). - ************************************************/ -require_once realpath(dirname(__FILE__) . '/../src/Google/autoload.php'); +echo pageHeader("Simple API Access"); /************************************************ We create the client and set the simple API @@ -35,9 +28,9 @@ ************************************************/ $client = new Google_Client(); $client->setApplicationName("Client_Library_Examples"); -$apiKey = ""; // Change this line. -// Warn if the API key isn't changed. -if (strpos($apiKey, "<") !== false) { + +// Warn if the API key isn't set. +if (!$apiKey = getApiKey()) { echo missingApiKeyWarning(); exit; } diff --git a/examples/simplefileupload.php b/examples/simplefileupload.php deleted file mode 100644 index 452599878..000000000 --- a/examples/simplefileupload.php +++ /dev/null @@ -1,123 +0,0 @@ -'; -$client_secret = ''; -$redirect_uri = ''; - -$client = new Google_Client(); -$client->setClientId($client_id); -$client->setClientSecret($client_secret); -$client->setRedirectUri($redirect_uri); -$client->addScope("https://www.googleapis.com/auth/drive"); -$service = new Google_Service_Drive($client); - -if (isset($_REQUEST['logout'])) { - unset($_SESSION['upload_token']); -} - -if (isset($_GET['code'])) { - $client->authenticate($_GET['code']); - $_SESSION['upload_token'] = $client->getAccessToken(); - $redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']; - header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL)); -} - -if (isset($_SESSION['upload_token']) && $_SESSION['upload_token']) { - $client->setAccessToken($_SESSION['upload_token']); - if ($client->isAccessTokenExpired()) { - unset($_SESSION['upload_token']); - } -} else { - $authUrl = $client->createAuthUrl(); -} - -/************************************************ - If we're signed in then lets try to upload our - file. For larger files, see fileupload.php. - ************************************************/ -if ($client->getAccessToken()) { - // This is uploading a file directly, with no metadata associated. - $file = new Google_Service_Drive_DriveFile(); - $result = $service->files->insert( - $file, - array( - 'data' => file_get_contents(TESTFILE), - 'mimeType' => 'application/octet-stream', - 'uploadType' => 'media' - ) - ); - - // Now lets try and send the metadata as well using multipart! - $file = new Google_Service_Drive_DriveFile(); - $file->setTitle("Hello World!"); - $result2 = $service->files->insert( - $file, - array( - 'data' => file_get_contents(TESTFILE), - 'mimeType' => 'application/octet-stream', - 'uploadType' => 'multipart' - ) - ); -} - -echo pageHeader("File Upload - Uploading a small file"); -if (strpos($client_id, "googleusercontent") == false) { - echo missingClientSecretsWarning(); - exit; -} -?> -
-
-Connect Me!"; -} -?> -
- -
-title); - var_dump($result2->title); -} -?> -
-
- - - - " . $title . " - - - \n"; - if ($_SERVER['PHP_SELF'] != "/index.php") { - $ret .= "

Back

"; - } - $ret .= "

" . $title . "

"; + $ret = " + + + " . $title . " + + + \n"; + if ($_SERVER['PHP_SELF'] != "/index.php") { + $ret .= "

Back

"; + } + $ret .= "

" . $title . "

"; + + // Start the session (for storing access tokens and things) + if (!headers_sent()) { + session_start(); } + return $ret; } @@ -28,63 +32,110 @@ function pageHeader($title) function pageFooter($file = null) { $ret = ""; - if (isWebRequest()) { - // Echo the code if in an example. - if ($file) { - $ret .= "

Code:

"; - $ret .= "
";
-      $ret .= htmlspecialchars(file_get_contents($file));
-      $ret .= "
"; - } - $ret .= ""; + if ($file) { + $ret .= "

Code:

"; + $ret .= "
";
+    $ret .= htmlspecialchars(file_get_contents($file));
+    $ret .= "
"; } + $ret .= ""; + return $ret; } function missingApiKeyWarning() { - $ret = ""; - if (isWebRequest()) { - $ret = " -

- Warning: You need to set a Simple API Access key from the - Google API console -

"; - } else { - $ret = "Warning: You need to set a Simple API Access key from the Google API console:"; - $ret .= "\nhttp://developers.google.com/console\n"; - } + $ret = " +

+ Warning: You need to set a Simple API Access key from the + Google API console +

"; + return $ret; } function missingClientSecretsWarning() { - $ret = ""; - if (isWebRequest()) { - $ret = " -

- Warning: You need to set Client ID, Client Secret and Redirect URI from the - Google API console -

"; - } else { - $ret = "Warning: You need to set Client ID, Client Secret and Redirect URI from the"; - $ret .= " Google API console:\nhttp://developers.google.com/console\n"; - } + $ret = " +

+ Warning: You need to set Client ID, Client Secret and Redirect URI from the + Google API console +

"; + return $ret; } function missingServiceAccountDetailsWarning() { - $ret = ""; - if (isWebRequest()) { - $ret = " -

- Warning: You need to set the location of your Service Account JSON Credentials from the - Google API console -

"; - } else { - $ret = "Warning: You need to set the location of Service Account JSON Credentials from the"; - $ret .= " Google API console:\nhttp://developers.google.com/console\n"; - } + $ret = " +

+ Warning: You need download your Service Account Credentials JSON from the + Google API console. +

+

+ Once downloaded, move them into the root directory of this repository and + rename them 'service-account-credentials.json'. +

+

+ In your application, you should set the GOOGLE_APPLICATION_CREDENTIALS environment variable + as the path to this file, but in the context of this example we will do this for you. +

"; + + return $ret; +} + +function missingOAuth2CredentialsWarning() +{ + $ret = " +

+ Warning: You need to set the location of your OAuth2 Client Credentials from the + Google API console. +

+

+ Once downloaded, move them into the root directory of this repository and + rename them 'oauth-credentials.json'. +

"; + return $ret; } + +function checkServiceAccountCredentialsFile() +{ + // service account creds + $application_creds = __DIR__ . '/../../service-account-credentials.json'; + + return file_exists($application_creds) ? $application_creds : false; +} + +function getOAuthCredentialsFile() +{ + // oauth2 creds + $oauth_creds = __DIR__ . '/../../oauth-credentials.json'; + + if (file_exists($oauth_creds)) { + return $oauth_creds; + } + + return false; +} + +function setClientCredentialsFile($apiKey) +{ + $file = __DIR__ . '/../../tests/.apiKey'; + file_put_contents($file, $apiKey); +} + + +function getApiKey() +{ + $file = __DIR__ . '/../../tests/.apiKey'; + if (file_exists($file)) { + return file_get_contents($file); + } +} + +function setApiKey($apiKey) +{ + $file = __DIR__ . '/../../tests/.apiKey'; + file_put_contents($file, $apiKey); +} diff --git a/examples/user-example.php b/examples/url-shortener.php similarity index 60% rename from examples/user-example.php rename to examples/url-shortener.php index df09e456e..17cbd407e 100644 --- a/examples/user-example.php +++ b/examples/url-shortener.php @@ -14,19 +14,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +include_once __DIR__ . '/../vendor/autoload.php'; include_once "templates/base.php"; -session_start(); -require_once realpath(dirname(__FILE__) . '/../src/Google/autoload.php'); +echo pageHeader('User Query - URL Shortener'); -/************************************************ - ATTENTION: Fill in these values! Make sure - the redirect URI is to this page, e.g: - http://localhost:8080/user-example.php +/************************************************* + * Ensure you've downloaded your oauth credentials ************************************************/ - $client_id = ''; - $client_secret = ''; - $redirect_uri = ''; +if (!$oauth_credentials = getOAuthCredentialsFile()) { + echo missingOAuth2CredentialsWarning(); + exit; +} /************************************************ Make an API request on behalf of a user. In @@ -35,39 +35,50 @@ through a login flow. To do this we need some information from our API console project. ************************************************/ +/************************************************ + * NOTICE: + * The redirect URI is to this page, e.g: + * http://localhost:8080/simplefileupload.php + ************************************************/ +$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']; + $client = new Google_Client(); -$client->setClientId($client_id); -$client->setClientSecret($client_secret); +$client->setAuthConfig($oauth_credentials); $client->setRedirectUri($redirect_uri); $client->addScope("https://www.googleapis.com/auth/urlshortener"); /************************************************ - When we create the service here, we pass the - client to it. The client then queries the service - for the required scopes, and uses that when - generating the authentication URL later. + * When we create the service here, we pass the + * client to it. The client then queries the service + * for the required scopes, and uses that when + * generating the authentication URL later. ************************************************/ $service = new Google_Service_Urlshortener($client); /************************************************ - If we're logging out we just need to clear our - local access token in this case + * If we're logging out we just need to clear our + * local access token in this case ************************************************/ if (isset($_REQUEST['logout'])) { unset($_SESSION['access_token']); } /************************************************ - If we have a code back from the OAuth 2.0 flow, - we need to exchange that with the authenticate() - function. We store the resultant access token - bundle in the session, and redirect to ourself. + * If we have a code back from the OAuth 2.0 flow, + * we need to exchange that with the + * Google_Client::fetchAccessTokenWithAuthCode() + * function. We store the resultant access token + * bundle in the session, and redirect to ourself. ************************************************/ if (isset($_GET['code'])) { - $client->authenticate($_GET['code']); - $_SESSION['access_token'] = $client->getAccessToken(); - $redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']; - header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL)); + $token = $client->fetchAccessTokenWithAuthCode($_GET['code']); + $client->setAccessToken($token); + + // store in the session also + $_SESSION['access_token'] = $token; + + // redirect back to the example + header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL)); } /************************************************ @@ -96,37 +107,27 @@ function. We store the resultant access token $short = $service->url->insert($url); $_SESSION['access_token'] = $client->getAccessToken(); } - -echo pageHeader("User Query - URL Shortener"); -if (strpos($client_id, "googleusercontent") == false) { - echo missingClientSecretsWarning(); - exit; -} ?> +
+
-Connect Me!"; -} else { - echo << - - - - Logout -END; -} -?> +
- + +
+ + +
+ Logout + + You created a short link!
+
- +
+ Create another +
- + tests/Google + + tests/examples + diff --git a/src/Google/AccessToken.php b/src/Google/AccessToken.php deleted file mode 100644 index d9889a436..000000000 --- a/src/Google/AccessToken.php +++ /dev/null @@ -1,227 +0,0 @@ -http = $http; - $this->cache = $cache; - $this->setAccessToken($token); - } - - /** - * @param string|array $token - * @throws InvalidArgumentException - */ - public function setAccessToken($token) - { - if (is_string($token)) { - if ($json = json_decode($token, true)) { - $token = $json; - } else { - // assume $token is just the token string - $token = [ - 'access_token' => $token, - ]; - } - } - if ($token == null) { - throw new InvalidArgumentException('invalid json token'); - } - if (!isset($token['access_token'])) { - throw new InvalidArgumentException("Invalid token format"); - } - $this->token = $token; - } - - public function getAccessToken() - { - return $this->token; - } - - /** - * Revoke an OAuth2 access token or refresh token. This method will revoke the current access - * token, if a token isn't provided. - * @throws Google_Auth_Exception - * @param string|null $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() - { - if (!$this->token) { - // Not initialized, no token to actually revoke - return false; - } elseif (array_key_exists('refresh_token', $this->token)) { - $token = $this->token['refresh_token']; - } else { - $token = $this->token['access_token']; - } - - $request = $this->http->createRequest('POST', Google_Client::OAUTH2_REVOKE_URI); - $request->addHeader('Cache-Control', 'no-store'); - $request->addHeader('Content-Type', 'application/x-www-form-urlencoded'); - $request->getBody()->replaceFields(array('token' => $token)); - - $response = $this->http->send($request); - if ($response->getStatusCode() == 200) { - $this->token = null; - - return true; - } - - return false; - } - - /** - * Retrieve and cache a certificates file. - * - * @param $url string location - * @throws Google_Auth_Exception - * @return array certificates - */ - private function retrieveCertsFromLocation($url) - { - // If we're retrieving a local file, just grab it. - if ("http" != substr($url, 0, 4)) { - $file = file_get_contents($url); - if ($file) { - return json_decode($file, true); - } else { - throw new Google_Auth_Exception( - "Failed to retrieve verification certificates: '" . - $url . "'." - ); - } - } - - $response = $this->http->get($url); - - if ($response->getStatusCode() == 200) { - return $response->json(); - } - throw new Google_Auth_Exception( - "Failed to retrieve verification certificates: '" . - $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() - { - $cache = $this->getCache(); - - if (!$certs = $cache->get('federated_signon_certs')) { - $certs = $this->retrieveCertsFromLocation( - self::FEDERATED_SIGNON_CERT_URL - ); - - $cache->set('federated_signon_certs', $certs); - } - - return $certs; - } - - /** - * 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 - * @throws Google_Auth_Exception - */ - public function verifyIdToken($audience = null) - { - if (empty($this->token['id_token'])) { - throw new LogicException('id_token cannot be null'); - } - - // Check signature - $certs = $this->getFederatedSignonCerts(); - foreach ($certs as $keyName => $pem) { - $key = openssl_x509_read($pem); - - try { - $payload = JWT::decode($this->token['id_token'], $key, array('RS256')); - if (is_null($audience) || (property_exists($resp, 'aud') && $resp->aud == $audience)) { - return $payload; - } - openssl_x509_free($key); - } catch (ExpiredException $e) { - return false; - // continue - } catch (DomainException $e) { - // continue - } - } - - return false; - } - - public function getCache() - { - if (!$this->cache) { - $this->cache = $this->createDefaultCache(); - } - - return $this->cache; - } - - protected function createDefaultCache() - { - return new Google_Cache_File(sys_get_temp_dir().'/google-api-php-client'); - } -} \ No newline at end of file diff --git a/src/Google/AccessToken/Revoke.php b/src/Google/AccessToken/Revoke.php new file mode 100644 index 000000000..9ae7e553d --- /dev/null +++ b/src/Google/AccessToken/Revoke.php @@ -0,0 +1,73 @@ +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|null $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(array $token) + { + if (isset($token['refresh_token'])) { + $tokenString = $token['refresh_token']; + } else { + $tokenString = $token['access_token']; + } + + $request = $this->http->createRequest('POST', Google_Client::OAUTH2_REVOKE_URI); + $request->addHeader('Cache-Control', 'no-store'); + $request->addHeader('Content-Type', 'application/x-www-form-urlencoded'); + $request->getBody()->replaceFields(array('token' => $tokenString)); + + $response = $this->http->send($request); + if ($response->getStatusCode() == 200) { + return true; + } + + return false; + } +} diff --git a/src/Google/AccessToken/Verify.php b/src/Google/AccessToken/Verify.php new file mode 100644 index 000000000..669e315c4 --- /dev/null +++ b/src/Google/AccessToken/Verify.php @@ -0,0 +1,178 @@ +http = $http; + $this->cache = $cache; + } + + /** + * 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'); + } + + // Check signature + $certs = $this->getFederatedSignonCerts(); + foreach ($certs as $cert) { + $modulus = new BigInteger(JWT::urlsafeB64Decode($cert['n']), 256); + $exponent = new BigInteger(JWT::urlsafeB64Decode($cert['e']), 256); + + $rsa = new RSA(); + $rsa->loadKey(array('n' => $modulus, 'e' => $exponent)); + + try { + $payload = JWT::decode( + $idToken, + $rsa->getPublicKey(), + array('RS256') + ); + if (property_exists($payload, 'aud')) { + if ($audience && $payload->aud != $audience) { + return false; + } + } + + return $payload; + } catch (ExpiredException $e) { + return false; + } catch (DomainException $e) { + // continue + } + } + + return false; + } + + private function getCache() + { + if (!$this->cache) { + $this->cache = $this->createDefaultCache(); + } + + return $this->cache; + } + + private function createDefaultCache() + { + return new Google_Cache_File( + sys_get_temp_dir().'/google-api-php-client' + ); + } + + /** + * 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 $response->json(); + } + 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() + { + $cache = $this->getCache(); + + if (!$certs = $cache->get('federated_signon_certs_v3', 3600)) { + $certs = $this->retrieveCertsFromLocation( + self::FEDERATED_SIGNON_CERT_URL + ); + + $cache->set('federated_signon_certs_v3', $certs); + } + + if (!isset($certs['keys'])) { + throw new InvalidArgumentException( + 'federated sign-on certs expects "keys" to be set' + ); + } + + return $certs['keys']; + } +} diff --git a/src/Google/Auth/AppIdentity.php b/src/Google/Auth/AppIdentity.php deleted file mode 100644 index f74e60027..000000000 --- a/src/Google/Auth/AppIdentity.php +++ /dev/null @@ -1,115 +0,0 @@ -client = $client; - } - - /** - * Retrieve an access token for the scopes supplied. - */ - public function authenticateForScope($scopes) - { - if ($this->token && $this->tokenScopes == $scopes) { - return $this->token; - } - - $cacheKey = self::CACHE_PREFIX; - if (is_string($scopes)) { - $cacheKey .= $scopes; - } else if (is_array($scopes)) { - $cacheKey .= implode(":", $scopes); - } - - $this->token = $this->client->getCache()->get($cacheKey); - if (!$this->token) { - $this->retrieveToken($scopes, $cacheKey); - } else if ($this->token['expiration_time'] < time()) { - $this->client->getCache()->delete($cacheKey); - $this->retrieveToken($scopes, $cacheKey); - } - - $this->tokenScopes = $scopes; - return $this->token; - } - - /** - * Retrieve a new access token and store it in cache - * @param mixed $scopes - * @param string $cacheKey - */ - private function retrieveToken($scopes, $cacheKey) - { - $this->token = AppIdentityService::getAccessToken($scopes); - if ($this->token) { - $this->client->getCache()->set( - $cacheKey, - $this->token - ); - } - } - - /** - * Perform an authenticated / signed apiHttpRequest. - * This function takes the apiHttpRequest, calls apiAuth->sign on it - * (which can modify the request in what ever way fits the auth mechanism) - * and then sends the request using the http client - * - * @param GuzzleHttp\Message\Request $request - * @return GuzzleHttp\Message\Response The resulting HTTP response - */ - public function authenticatedRequest($request) - { - $request = $this->sign($request); - - return $this->client->getHttpClient()->send($request); - } - - public function sign($request) - { - if (!$this->token) { - // No token, so nothing to do. - return $request; - } - - $this->client->getLogger()->debug('App Identity authentication'); - - // Add the OAuth2 header to the request - $request->setHeader('Authorization', 'Bearer ' . $this->token['access_token']); - - return $request; - } -} diff --git a/src/Google/Auth/Exception.php b/src/Google/Auth/Exception.php deleted file mode 100644 index 59420cedf..000000000 --- a/src/Google/Auth/Exception.php +++ /dev/null @@ -1,20 +0,0 @@ -connection, $key, $data, false); } if ($rc == false) { - $this->log('error', + $this->log( + 'error', 'Memcache cache set failed', array('key' => $key, 'var' => $data) ); diff --git a/src/Google/Client.php b/src/Google/Client.php index 0ea786d80..343242204 100644 --- a/src/Google/Client.php +++ b/src/Google/Client.php @@ -16,17 +16,18 @@ */ use Google\Auth\ApplicationDefaultCredentials; +use Google\Auth\AuthTokenFetcher; use Google\Auth\CacheInterface; use Google\Auth\OAuth2; use Google\Auth\ScopedAccessToken; use Google\Auth\Simple; +use Google\Auth\UserRefreshCredentials; use GuzzleHttp\Client; use GuzzleHttp\ClientInterface; use GuzzleHttp\Collection; -use GuzzleHttp\Post\PostBodyInterface; -use GuzzleHttp\Stream\Stream; use Psr\Log\LoggerInterface; use Monolog\Logger; +use Monolog\Handler\StreamHandler; /** * The Google API Client @@ -39,6 +40,7 @@ class Google_Client const OAUTH2_REVOKE_URI = 'https://accounts.google.com/o/oauth2/revoke'; const OAUTH2_TOKEN_URI = 'https://www.googleapis.com/oauth2/v3/token'; const OAUTH2_AUTH_URL = 'https://accounts.google.com/o/oauth2/auth'; + const API_BASE_PATH = 'https://www.googleapis.com'; /** * @var Google\Auth\OAuth2 $auth @@ -79,23 +81,6 @@ class Google_Client // Scopes requested by the client protected $requestedScopes = []; - public static $retryConfig = [ - // Delays are specified in seconds - 'initial_delay' => 1, - 'max_delay' => 60, - // Base number for exponential backoff - 'factor' => 2, - // A random number between -jitter and jitter will be added to the - // factor on each iteration to allow for better distribution of - // retries. - 'jitter' => .5, - // Maximum number of retries allowed - 'retries' => 0 - ]; - - // Used to track authenticated state, can't discover services after doing authenticate() - private $authenticated = false; - /** * Construct the Google Client. * @@ -103,36 +88,45 @@ class Google_Client */ public function __construct($config = array()) { - $this->config = Collection::fromConfig($config, [ - 'application_name' => '', - - // Don't change these unless you're working against a special development - // or testing environment. - 'base_path' => 'https://www.googleapis.com', - - // https://developers.google.com/console - 'client_id' => '', - 'client_secret' => '', - 'redirect_uri' => null, - 'state' => null, - - // Simple API access key, also from the API console. Ensure you get - // a Server key, and not a Browser key. - 'developer_key' => '', - - // Other OAuth2 parameters. - 'hd' => '', - 'prompt' => '', - 'openid.realm' => '', - 'include_granted_scopes' => null, - 'login_hint' => '', - 'request_visible_actions' => '', - 'access_type' => 'online', - 'approval_prompt' => 'auto', - - // misc configuration - 'enable_gzip_for_uploads' => false, - ]); + $this->config = Collection::fromConfig( + $config, + [ + 'application_name' => '', + + // Don't change these unless you're working against a special development + // or testing environment. + 'base_path' => self::API_BASE_PATH, + + // https://developers.google.com/console + 'client_id' => '', + 'client_secret' => '', + 'redirect_uri' => null, + 'state' => null, + + // Simple API access key, also from the API console. Ensure you get + // a Server key, and not a Browser key. + 'developer_key' => '', + + // For use with Google Cloud Platform + // fetch the ApplicationDefaultCredentials, if applicable + // @see https://developers.google.com/identity/protocols/application-default-credentials + 'use_application_default_credentials' => false, + + // Other OAuth2 parameters. + 'hd' => '', + 'prompt' => '', + 'openid.realm' => '', + 'include_granted_scopes' => null, + 'login_hint' => '', + 'request_visible_actions' => '', + 'access_type' => 'online', + 'approval_prompt' => 'auto', + + // Task Runner retry configuration + // @see Google_Task_Runner + 'retry' => array(), + ] + ); } /** @@ -145,17 +139,28 @@ public function getLibraryVersion() return self::LIBVER; } + /** + * For backwards compatibility + * alias for fetchAccessTokenWithAuthCode + * + * @param $code string code from accounts.google.com + * @return array access token + */ + public function authenticate($code) + { + trigger_error('use Google_Client::fetchAccessTokenWithAuthCode', E_DEPRECATED); + + return $this->fetchAccessTokenWithAuthCode($code); + } + /** * Attempt to exchange a code for an valid authentication token. - * If $crossClient is set to true, the request body will not include - * the request_uri argument * Helper wrapped around the OAuth 2.0 implementation. * * @param $code string code from accounts.google.com - * @param $crossClient boolean, whether this is a cross-client authentication - * @return string token + * @return array access token */ - public function authenticate($code, $crossClient = false) + public function fetchAccessTokenWithAuthCode($code) { if (strlen($code) == 0) { throw new InvalidArgumentException("Invalid code"); @@ -163,10 +168,11 @@ public function authenticate($code, $crossClient = false) $auth = $this->getOAuth2Service(); $auth->setCode($code); - $auth->setRedirectUri($this->getConfig('redirect_uri')); + $auth->setRedirectUri($this->getRedirectUri()); $creds = $auth->fetchAuthToken($this->getHttpClient()); if ($creds && isset($creds['access_token'])) { + $creds['created'] = time(); $this->setAccessToken($creds); } @@ -174,61 +180,86 @@ public function authenticate($code, $crossClient = false) } /** - * Create a URL to obtain user authorization. - * The authorization endpoint allows the user to first - * authenticate, and then grant/deny the access request. - * @param string|array $scope The scope is expressed as an array or list of space-delimited strings. - * @return string + * For backwards compatibility + * alias for fetchAccessTokenWithAssertion + * + * @return array access token */ - public function createAuthUrl($scope = null) + public function refreshTokenWithAssertion() { - if (empty($scope)) { - $scope = $this->prepareScopes(); - } - if (is_array($scope)) { - $scope = implode(' ', $scope); - } + trigger_error('use Google_Client::fetchAccessTokenWithAssertion', E_DEPRECATED); - $params = array_filter([ - 'access_type' => $this->config->get('access_type'), - 'approval_prompt' => $this->config->get('prompt') ? null : $this->config->get('approval_prompt'), - 'hd' => $this->config->get('hosted_domain'), - 'include_granted_scopes' => - $this->config->get('include_granted_scopes') === null - ? null - : var_export($this->config->get('include_granted_scopes'), true), - 'login_hint' => $this->config->get('login_hint'), - 'openid.realm' => $this->config->get('openid.realm'), - 'prompt' => $this->config->get('prompt'), - 'response_type' => 'code', - 'scope' => $scope, - 'state' => $this->config->get('state'), - ]); + return $this->fetchAccessTokenWithAssertion(); + } - // If the list of scopes contains plus.login, add request_visible_actions - // to auth URL. - $rva = $this->config->get('request_visible_actions'); - if (strlen($rva) > 0 && false !== strpos($scope, 'plus.login')) { - $params['request_visible_actions'] = $rva; + /** + * Fetches a fresh access token with a given assertion token. + * @param $assertionCredentials optional. + * @return void + */ + public function fetchAccessTokenWithAssertion() + { + if (is_null($this->config->get('signing_key'))) { + throw new LogicException( + 'config parameter "signing_key" must be set to' + . ' refresh a token with assertion' + ); } + $this->getLogger()->log( + 'info', + 'OAuth2 access token refresh with Signed JWT assertion grants.' + ); + $auth = $this->getOAuth2Service(); + $auth->setGrantType(OAuth2::JWT_URN); + $auth->setAudience(self::OAUTH2_TOKEN_URI); + $auth->setScope($this->getScopes()); - return (string) $auth->buildFullAuthorizationUri($params); + $creds = $auth->fetchAuthToken($this->getHttpClient()); + if ($creds && isset($creds['access_token'])) { + $this->setAccessToken($creds); + } + + return $creds; } /** - * Fetches a fresh OAuth 2.0 access token with the given refresh token. + * For backwards compatibility + * alias for fetchAccessTokenWithRefreshToken + * * @param string $refreshToken + * @return array access token */ public function refreshToken($refreshToken) { + trigger_error('use Google_Client::fetchAccessTokenWithRefreshToken', E_DEPRECATED); + + return $this->fetchAccessTokenWithRefreshToken($refreshToken); + } + + /** + * Fetches a fresh OAuth 2.0 access token with the given refresh token. + * @param string $refreshToken + * @return array access token + */ + public function fetchAccessTokenWithRefreshToken($refreshToken = null) + { + if (is_null($refreshToken)) { + if (!isset($this->token['refresh_token'])) { + throw new LogicException( + 'refresh token must be passed in or set as part of setAccessToken' + ); + } + $refreshToken = $this->token['refresh_token']; + } $this->getLogger()->info('OAuth2 access token refresh'); $auth = $this->getOAuth2Service(); $auth->setRefreshToken($refreshToken); $creds = $auth->fetchAuthToken($this->getHttpClient()); if ($creds && isset($creds['access_token'])) { + $creds['created'] = time(); $this->setAccessToken($creds); } @@ -236,79 +267,138 @@ public function refreshToken($refreshToken) } /** - * Fetches a fresh access token with a given assertion token. - * @param Google_Auth_AssertionCredentials $assertionCredentials optional. - * @return void + * Create a URL to obtain user authorization. + * The authorization endpoint allows the user to first + * authenticate, and then grant/deny the access request. + * @param string|array $scope The scope is expressed as an array or list of space-delimited strings. + * @return string */ - public function refreshTokenWithAssertion() + public function createAuthUrl($scope = null) { - if (is_null($this->config->get('signing_key'))) { - throw new LogicException('config parameter "signing_key" must be set to' - . ' refresh a token with assertion'); + if (empty($scope)) { + $scope = $this->prepareScopes(); + } + if (is_array($scope)) { + $scope = implode(' ', $scope); } - $this->getLogger()->log( - 'info', - 'OAuth2 access token refresh with Signed JWT assertion grants.' + // only accept one of prompt or approval_prompt + $approvalPrompt = $this->config->get('prompt') + ? null + : $this->config->get('approval_prompt'); + + // include_granted_scopes should be string "true", string "false", or null + $includeGrantedScopes = $this->config->get('include_granted_scopes') === null + ? null + : var_export($this->config->get('include_granted_scopes'), true); + + $params = array_filter( + [ + 'access_type' => $this->config->get('access_type'), + 'approval_prompt' => $approvalPrompt, + 'hd' => $this->config->get('hd'), + 'include_granted_scopes' => $includeGrantedScopes, + 'login_hint' => $this->config->get('login_hint'), + 'openid.realm' => $this->config->get('openid.realm'), + 'prompt' => $this->config->get('prompt'), + 'response_type' => 'code', + 'scope' => $scope, + 'state' => $this->config->get('state'), + ] ); - $auth = $this->getOAuth2Service(); - $auth->setGrantType(OAuth2::JWT_URN); - $auth->setAudience(self::OAUTH2_TOKEN_URI); - $auth->setScope($this->getScopes()); - - if ($creds && isset($creds['access_token'])) { - $this->setAccessToken($creds); + // If the list of scopes contains plus.login, add request_visible_actions + // to auth URL. + $rva = $this->config->get('request_visible_actions'); + if (strlen($rva) > 0 && false !== strpos($scope, 'plus.login')) { + $params['request_visible_actions'] = $rva; } - return $creds; + $auth = $this->getOAuth2Service(); + + return (string) $auth->buildFullAuthorizationUri($params); } - public function attachAuthListener(ClientInterface $http) + /** + * Adds auth listeners to the HTTP client based on the credentials + * set in the Google API Client object + * + * @param GuzzleHttp\ClientInterface $http the http client object. + * @return void + */ + public function authorize(ClientInterface $http) { - if ($key = $this->getConfig('developer_key')) { - // if a developer key is set, authorize using that - $simple = new Simple(['key' => $key]); - $http->setDefaultOption('auth', 'simple'); - $http->getEmitter()->attach($simple); - $this->getLogger()->log('info', 'Authenticated with API key'); - } else { + $subscriber = null; + $authIdentifier = null; + if ($this->config->get('use_application_default_credentials')) { $scopes = $this->prepareScopes(); - if ($this->token) { - // if a token has been set manually, authorize using it instead - if ($this->isAccessTokenExpired() && isset($this->token['refresh_token'])) { - // try to get another access token with the refresh token - $this->refreshToken($this->token['refresh_token']); - } - $accessToken = $this->token['access_token']; - $scoped = new ScopedAccessToken( - function($scopes) use ($accessToken) { - return $accessToken; - }, + $subscriber = ApplicationDefaultCredentials::getFetcher( $scopes, - [] - ); - $http->setDefaultOption('auth', 'scoped'); - $http->getEmitter()->attach($scoped); - $this->getLogger()->log('info', 'Authenticated with access token'); - } else { - try { - // try to fetch credentials using ApplicationDefaultCredentials, if applicable - $fetcher = ApplicationDefaultCredentials::getFetcher( + null, + array(), + $this->cache + ); + $authIdentifier = 'google_auth'; + } elseif ($key = $this->config->get('developer_key')) { + // if a developer key is set, authorize using that + $subscriber = new Simple(['key' => $key]); + $authIdentifier = 'simple'; + } elseif ($token = $this->getAccessToken()) { + $scopes = $this->prepareScopes(); + // add refresh subscriber to request a new token + if ($this->isAccessTokenExpired()) { + if (isset($token['refresh_token'])) { + $subscriber = $this->createUserRefreshCredentials( $scopes, - $this->getHttpClient(), - array(), - $this->cache + $token['refresh_token'] ); - $http->setDefaultOption('auth', 'google_auth'); - $http->getEmitter()->attach($fetcher); - $this->getLogger()->log('info', 'Authenticated with Application Default Credentials'); - } catch (DomainException $e) { - // no auth - $this->getLogger()->log('info', $e->getMessage()); + $authIdentifier = 'google_auth'; } + } else { + $subscriber = new ScopedAccessToken( + function ($scopes) use ($token) { + return $token['access_token']; + }, + $scopes, + [] + ); + $authIdentifier = 'scoped'; } } + + if ($subscriber) { + $http->setDefaultOption('auth', $authIdentifier); + $http->getEmitter()->attach($subscriber); + $this->getLogger()->log( + 'info', + sprintf('Added listener for auth type "%s"', $authIdentifier) + ); + } + + return $http; + } + + /** + * Set the configuration to use application default credentials for + * authentication + * + * @see https://developers.google.com/identity/protocols/application-default-credentials + * @param boolean $useAppCreds + */ + public function useApplicationDefaultCredentials($useAppCreds = true) + { + $this->config->set('use_application_default_credentials', $useAppCreds); + } + + /** + * To prevent useApplicationDefaultCredentials from inappropriately being + * called in a conditional + * + * @see https://developers.google.com/identity/protocols/application-default-credentials + */ + public function isUsingApplicationDefaultCredentials() + { + return $this->config->get('use_application_default_credentials'); } /** @@ -318,7 +408,14 @@ function($scopes) use ($accessToken) { public function setAccessToken($token) { if (is_string($token)) { - $token = json_decode($token, true); + if ($json = json_decode($token, true)) { + $token = $json; + } else { + // assume $token is just the token string + $token = array( + 'access_token' => $token, + ); + } } if ($token == null) { throw new InvalidArgumentException('invalid json token'); @@ -348,17 +445,41 @@ public function isAccessTokenExpired() if (isset($this->token['created'])) { $created = $this->token['created']; } elseif (isset($this->token['id_token'])) { - $payload = $this->verifyIdToken(); - $created = $payload ? $payload->iat : 0; + // check the ID token for "iat" + // signature verification is not required here, as we are just + // using this for convenience to save a round trip request + // to the Google API server + $idToken = $this->token['id_token']; + if (substr_count($idToken, '.') == 2) { + $parts = explode('.', $idToken); + $payload = json_decode(base64_decode($parts[1]), true); + if ($payload && isset($payload['iat'])) { + $created = $payload['iat']; + } + } } // If the token is set to expire in the next 30 seconds. $expired = ($created - + ($this->token['expires_in'] - 30)) < time(); + + ($this->token['expires_in'] - 30)) < time(); return $expired; } + public function getAuth() + { + throw new BadMethodCallException( + 'This function no longer exists. See UPGRADING.md for more information' + ); + } + + public function setAuth($auth) + { + throw new BadMethodCallException( + 'This function no longer exists. See UPGRADING.md for more information' + ); + } + /** * Set the OAuth 2.0 Client ID. * @param string $clientId @@ -370,7 +491,7 @@ public function setClientId($clientId) public function getClientId() { - return $this->getConfig('client_id'); + return $this->config->get('client_id'); } /** @@ -401,6 +522,70 @@ public function getRedirectUri() return $this->config->get('redirect_uri'); } + /** + * Set OAuth 2.0 "state" parameter to achieve per-request customization. + * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-3.1.2.2 + * @param string $state + */ + public function setState($state) + { + $this->config->set('state', $state); + } + + /** + * @param string $accessType Possible values for access_type include: + * {@code "offline"} to request offline access from the user. + * {@code "online"} to request online access from the user. + */ + public function setAccessType($accessType) + { + $this->config->set('access_type', $accessType); + } + + /** + * @param string $approvalPrompt Possible values for approval_prompt include: + * {@code "force"} to force the approval UI to appear. (This is the default value) + * {@code "auto"} to request auto-approval when possible. + */ + public function setApprovalPrompt($approvalPrompt) + { + $this->config->set('approval_prompt', $approvalPrompt); + } + + /** + * Set the login hint, email address or sub id. + * @param string $loginHint + */ + public function setLoginHint($loginHint) + { + $this->config->set('login_hint', $loginHint); + } + + /** + * Set the application name, this is included in the User-Agent HTTP header. + * @param string $applicationName + */ + public function setApplicationName($applicationName) + { + $this->config->set('application_name', $applicationName); + } + + /** + * If 'plus.login' is included in the list of requested scopes, you can use + * this method to define types of app activities that your app will write. + * You can find a list of available types here: + * @link https://developers.google.com/+/api/moment-types + * + * @param array $requestVisibleActions Array of app activity types + */ + public function setRequestVisibleActions($requestVisibleActions) + { + if (is_array($requestVisibleActions)) { + $requestVisibleActions = join(" ", $requestVisibleActions); + } + $this->config->set('request_visible_actions', $requestVisibleActions); + } + /** * Set the developer key to use, these are obtained through the API Console. * @see http://code.google.com/apis/console-help/#generatingdevkeys @@ -412,48 +597,91 @@ public function setDeveloperKey($developerKey) } /** - * Set OAuth 2.0 "state" parameter to achieve per-request customization. - * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-3.1.2.2 - * @param string $state + * Set the hd (hosted domain) parameter streamlines the login process for + * Google Apps hosted accounts. By including the domain of the user, you + * restrict sign-in to accounts at that domain. + * @param $hd string - the domain to use. */ - public function setState($state) + public function setHostedDomain($hd) { - $this->config->set('state', $state); + $this->config->set('hd', $hd); + } + /** + * Set the prompt hint. Valid values are none, consent and select_account. + * If no value is specified and the user has not previously authorized + * access, then the user is shown a consent screen. + * @param $prompt string + */ + public function setPrompt($prompt) + { + $this->config->set('prompt', $prompt); + } + /** + * openid.realm is a parameter from the OpenID 2.0 protocol, not from OAuth + * 2.0. It is used in OpenID 2.0 requests to signify the URL-space for which + * an authentication request is valid. + * @param $realm string - the URL-space to use. + */ + public function setOpenidRealm($realm) + { + $this->config->set('openid.realm', $realm); + } + /** + * If this is provided with the value true, and the authorization request is + * granted, the authorization will include any previous authorizations + * granted to this user/application combination for other scopes. + * @param $include boolean - the URL-space to use. + */ + public function setIncludeGrantedScopes($include) + { + $this->config->set('include_granted_scopes', $include); } /** * Revoke an OAuth2 access token or refresh token. This method will revoke the current access * token, if a token isn't provided. - * @throws Google_Auth_Exception + * * @param string|null $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 = null) { - $token = new Google_AccessToken( - $token ?: $this->getAccessToken(), - $this->getHttpClient() + $tokenRevoker = new Google_AccessToken_Revoke( + $this->getHttpClient() ); - return $token->revokeToken(); + return $tokenRevoker->revokeToken($token ?: $this->getAccessToken()); } /** * Verify an id_token. This method will verify the current id_token, if one * isn't provided. - * @throws Google_Auth_Exception - * @param string|null $token The token (id_token) that should be verified. - * @return Returns the token payload as an array if the verification was - * successful. + * + * @throws Google_Exception + * @param string|null $idToken The token (id_token) that should be verified. + * @return array|false Returns the token payload as an array if the verification was + * successful, false otherwise. */ - public function verifyIdToken($token = null) + public function verifyIdToken($idToken = null) { - $token = new Google_AccessToken( - $token ?: $this->getAccessToken(), - $this->getHttpClient() + $tokenVerifier = new Google_AccessToken_Verify( + $this->getHttpClient() ); - return $token->verifyIdToken(); + if (is_null($idToken)) { + $token = $this->getAccessToken(); + if (!isset($token['id_token'])) { + throw new LogicException( + 'id_token must be passed in or set as part of setAccessToken' + ); + } + $idToken = $token['id_token']; + } + + return $tokenVerifier->verifyIdToken( + $idToken, + $this->getClientId() + ); } /** @@ -497,7 +725,6 @@ public function getScopes() } /** - * @throws Google_Auth_Exception * @return array * @visible For Testing */ @@ -521,14 +748,14 @@ public function execute($request, $expectedClass = null) { $request->setHeader( 'User-Agent', - $this->getConfig('application_name') + $this->config->get('application_name') . " " . self::USER_AGENT_SUFFIX . $this->getLibraryVersion() ); $http = $this->getHttpClient(); - $result = Google_Http_REST::execute($http, $request, static::$retryConfig); + $result = Google_Http_REST::execute($http, $request, $this->config['retry']); $expectedClass = $expectedClass ?: $request->getHeader('X-Php-Expected-Class'); if ($expectedClass) { $result = new $expectedClass($result); @@ -570,38 +797,65 @@ public function getConfig($name, $default = null) return $this->config->get($name) ?: $default; } + /** + * Set the auth config from the JSON file in the path + * provided. This should match the file downloaded from + * the "Download JSON" button on in the Google Developer + * Console. + * @param string $file the file location of the client json + */ + public function setAuthConfigFile($file) + { + trigger_error('use Google_Client::setAuthConfig', E_USER_DEPRECATED); + + $this->setAuthConfig($file); + } + /** * Set the auth config from new or deprecated JSON config. * This structure should match the file downloaded from * the "Download JSON" button on in the Google Developer * Console. - * @param string|array|stdClass $json the configuration json + * @param string|array $json the configuration json * @throws Google_Exception */ - public function setAuthConfig($json) + public function setAuthConfig($config) { - if (is_string($json)) { - $data = json_decode($json); - } elseif (is_array($json)) { - $data = (object) $json; - } elseif (!$json instanceof stdClass) { - throw new InvalidArgumentException('invalid auth config type'); + if (is_string($config)) { + if (!file_exists($config)) { + throw new InvalidArgumentException('file does not exist'); + } + + $json = file_get_contents($config); + + if (!$config = json_decode($json, true)) { + throw new LogicException('invalid json for auth config'); + } } - $key = isset($data->installed) ? 'installed' : 'web'; - if (isset($data->$key)) { + $key = isset($config['installed']) ? 'installed' : 'web'; + if (isset($config['type']) && $config['type'] == 'service_account') { + // application default credentials + $this->useApplicationDefaultCredentials(); + + // overwrite APPLICATION_DEFAULT_CREDENTIALS with this config + $tmpFile = tempnam(sys_get_temp_dir(), 'appcreds'); + file_put_contents($tmpFile, json_encode($config)); + putenv('GOOGLE_APPLICATION_CREDENTIALS='.$tmpFile); + + } elseif (isset($config[$key])) { // old-style - $this->setClientId($data->$key->client_id); - $this->setClientSecret($data->$key->client_secret); - if (isset($data->$key->redirect_uris)) { - $this->setRedirectUri($data->$key->redirect_uris[0]); + $this->setClientId($config[$key]['client_id']); + $this->setClientSecret($config[$key]['client_secret']); + if (isset($config[$key]['redirect_uris'])) { + $this->setRedirectUri($config[$key]['redirect_uris'][0]); } } else { // new-style - $this->setClientId($data->client_id); - $this->setClientSecret($data->client_secret); - if (isset($data->redirect_uris)) { - $this->setRedirectUri($data->redirect_uris[0]); + $this->setClientId($config['client_id']); + $this->setClientSecret($config['client_secret']); + if (isset($config['redirect_uris'])) { + $this->setRedirectUri($config['redirect_uris'][0]); } } } @@ -641,18 +895,20 @@ public function getOAuth2Service() /** * create a default google auth object */ - public function createOAuth2Service() + protected function createOAuth2Service() { - $auth = new OAuth2([ - 'clientId' => $this->getClientId(), - 'clientSecret' => $this->getClientSecret(), - 'authorizationUri' => self::OAUTH2_AUTH_URL, - 'tokenCredentialUri' => self::OAUTH2_TOKEN_URI, - 'redirectUri' => $this->getRedirectUri(), - 'issuer' => $this->config->get('client_id'), - 'signingKey' => $this->config->get('signing_key'), - 'signingAlgorithm' => $this->config->get('signing_algorithm'), - ]); + $auth = new OAuth2( + [ + 'clientId' => $this->getClientId(), + 'clientSecret' => $this->getClientSecret(), + 'authorizationUri' => self::OAUTH2_AUTH_URL, + 'tokenCredentialUri' => self::OAUTH2_TOKEN_URI, + 'redirectUri' => $this->getRedirectUri(), + 'issuer' => $this->config->get('client_id'), + 'signingKey' => $this->config->get('signing_key'), + 'signingAlgorithm' => $this->config->get('signing_algorithm'), + ] + ); return $auth; } @@ -714,6 +970,7 @@ public function getLogger() protected function createDefaultLogger() { $logger = new Logger('google-api-php-client'); + $logger->pushHandler(new StreamHandler('php://stderr', Logger::NOTICE)); return $logger; } @@ -743,9 +1000,27 @@ protected function createDefaultHttpClient() { $options = [ 'base_url' => $this->config->get('base_path'), - 'defaults' => ['auth' => 'google_auth'], + 'defaults' => ['exceptions' => false] ]; return new Client($options); } + + private function createUserRefreshCredentials($scope, $refreshToken) + { + $creds = array_filter( + array( + 'client_id' => $this->getClientId(), + 'client_secret' => $this->getClientSecret(), + 'refresh_token' => $refreshToken, + ) + ); + + return new AuthTokenFetcher( + new UserRefreshCredentials($scope, $creds), + [], + $this->getCache(), + clone $this->getHttpClient() + ); + } } diff --git a/src/Google/Http/Batch.php b/src/Google/Http/Batch.php new file mode 100644 index 000000000..54b4ad7e4 --- /dev/null +++ b/src/Google/Http/Batch.php @@ -0,0 +1,229 @@ +client = $client; + $this->boundary = mt_rand(); + } + + public function add(RequestInterface $request, $key = false) + { + if (false == $key) { + $key = mt_rand(); + } + + $this->requests[$key] = $request; + } + + public function execute() + { + $body = ''; + $classes = array(); + + /** @var Google_Http_Request $req */ + foreach ($this->requests as $key => $request) { + $request->addHeaders( + [ + 'Content-Type' => 'application/http', + 'Content-Transfer-Encoding' => 'binary', + 'MIME-Version' => '1.0', + 'Content-ID' => $key, + ] + ); + $body .= "--{$this->boundary}"; + $body .= Request::getHeadersAsString($request) . "\n\n"; + $body .= sprintf( + '%s %s HTTP/%s', + $request->getMethod(), + $request->getResource(), + $request->getProtocolVersion() + ); + $body .= "\n\n"; + + $classes['response-' . $key] = $request->getHeader('X-Php-Expected-Class'); + } + + $body .= "--{$this->boundary}--"; + $body = trim($body); + $url = Google_Client::API_BASE_PATH . '/' . self::BATCH_PATH; + $headers = array( + 'Content-Type' => sprintf('multipart/mixed; boundary=%s', $this->boundary), + 'Content-Length' => strlen($body), + ); + $request = $this->client->getHttpClient()->createRequest( + 'POST', + $url, + [ + 'headers' => $headers, + 'body' => Stream::factory($body), + ] + ); + + $response = $this->client->getHttpClient()->send($request); + + return $this->parseResponse($response, $classes); + } + + public function parseResponse(ResponseInterface $response, $classes = array()) + { + $contentType = $response->getHeader('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(); + + 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, + Stream::factory($partBody) + ); + + // Need content id. + $key = $headers['content-id']; + $class = ''; + if (!empty($this->expected_classes[$key])) { + $class = $this->expected_classes[$key]; + } + + try { + $response = Google_Http_REST::decodeHttpResponse($response); + if (isset($classes[$key])) { + $response = new $classes[$key]($response); + } + } 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); + } +} diff --git a/src/Google/Http/MediaFileUpload.php b/src/Google/Http/MediaFileUpload.php index 20381d6d1..b0d6b9dc4 100644 --- a/src/Google/Http/MediaFileUpload.php +++ b/src/Google/Http/MediaFileUpload.php @@ -59,6 +59,12 @@ class Google_Http_MediaFileUpload /** @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. @@ -130,8 +136,9 @@ private function makePutRequest(Google_Http_Request $httpRequest) } $response = $http->send($request); + $this->httpResultCode = $response->getStatusCode(); - if (308 == $response->getStatusCode()) { + if (308 == $this->httpResultCode) { // Track the amount uploaded. $range = explode('-', $response->getHeader('range')); $this->progress = $range[1] + 1; diff --git a/src/Google/Http/Parallel.php b/src/Google/Http/Pool.php similarity index 98% rename from src/Google/Http/Parallel.php rename to src/Google/Http/Pool.php index a28fdd3c9..f8ef527e6 100644 --- a/src/Google/Http/Parallel.php +++ b/src/Google/Http/Pool.php @@ -23,7 +23,7 @@ /** * Class to handle batched requests to the Google API service. */ -class Google_Http_Parallel +class Google_Http_Pool { /** @var array service requests to be executed. */ private $requests = array(); diff --git a/src/Google/IO/Exception.php b/src/Google/IO/Exception.php deleted file mode 100644 index 3151e6350..000000000 --- a/src/Google/IO/Exception.php +++ /dev/null @@ -1,65 +0,0 @@ -= 0) { - parent::__construct($message, $code, $previous); - } else { - parent::__construct($message, $code); - } - - if (is_array($retryMap)) { - $this->retryMap = $retryMap; - } - } - - /** - * 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() - { - if (isset($this->retryMap[$this->code])) { - return $this->retryMap[$this->code]; - } - - return 0; - } -} diff --git a/src/Google/Model.php b/src/Google/Model.php index df8216a80..7168c945b 100644 --- a/src/Google/Model.php +++ b/src/Google/Model.php @@ -102,7 +102,7 @@ protected function mapTypes($array) property_exists($this, $key)) { $this->$key = $val; unset($array[$key]); - } elseif (property_exists($this, $camelKey = Google_Utils::camelCase($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; @@ -175,7 +175,7 @@ private function getSimpleValue($value) } return $value; } - + /** * Check whether the value is the null placeholder and return true null. */ @@ -292,4 +292,17 @@ 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; + } } diff --git a/src/Google/Service/Resource.php b/src/Google/Service/Resource.php index a719402a5..f1e576375 100644 --- a/src/Google/Service/Resource.php +++ b/src/Google/Service/Resource.php @@ -191,7 +191,13 @@ public function call($name, $arguments, $expected_class = null) ); $http = $this->client->getHttpClient(); - $this->client->attachAuthListener($http); + $this->client->authorize($http); + + // Guzzle 5 cannot locate App Engine certs by default, + // so we tell Guzzle where to look + if ($this->client->isAppEngine()) { + $http->setDefaultOption('verify', '/etc/ca-certificates.crt'); + } $request = $http->createRequest( $method['httpMethod'], @@ -269,7 +275,7 @@ public function createRequestUri($restPath, $params) } if (count($uriTemplateVars)) { - $uriTemplateParser = new Google_Utils_URITemplate(); + $uriTemplateParser = new Google_Utils_UriTemplate(); $requestUrl = $uriTemplateParser->parse($requestUrl, $uriTemplateVars); } diff --git a/src/Google/Task/Runner.php b/src/Google/Task/Runner.php index 67bad1c46..b809ee01d 100644 --- a/src/Google/Task/Runner.php +++ b/src/Google/Task/Runner.php @@ -180,7 +180,10 @@ public function run() try { return call_user_func_array($this->action, $this->arguments); } catch (Google_Service_Exception $exception) { - $allowedRetries = $this->allowedRetries($exception->getCode(), $exception->getErrors()); + $allowedRetries = $this->allowedRetries( + $exception->getCode(), + $exception->getErrors() + ); if (!$this->canAttempt() || !$allowedRetries) { throw $exception; diff --git a/src/Google/Utils.php b/src/Google/Utils.php deleted file mode 100644 index 2803daaa1..000000000 --- a/src/Google/Utils.php +++ /dev/null @@ -1,133 +0,0 @@ -= 0x20) && ($ordinalValue <= 0x7F)): - // characters U-00000000 - U-0000007F (same as ASCII) - $ret ++; - break; - case (($ordinalValue & 0xE0) == 0xC0): - // characters U-00000080 - U-000007FF, mask 110XXXXX - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $ret += 2; - break; - case (($ordinalValue & 0xF0) == 0xE0): - // characters U-00000800 - U-0000FFFF, mask 1110XXXX - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $ret += 3; - break; - case (($ordinalValue & 0xF8) == 0xF0): - // characters U-00010000 - U-001FFFFF, mask 11110XXX - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $ret += 4; - break; - case (($ordinalValue & 0xFC) == 0xF8): - // characters U-00200000 - U-03FFFFFF, mask 111110XX - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $ret += 5; - break; - case (($ordinalValue & 0xFE) == 0xFC): - // characters U-04000000 - U-7FFFFFFF, mask 1111110X - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $ret += 6; - break; - default: - $ret ++; - } - } - return $ret; - } - - /** - * Normalize all keys in an array to lower-case. - * @param array $arr - * @return array Normalized array. - */ - public static function normalize($arr) - { - if (!is_array($arr)) { - return array(); - } - - $normalized = array(); - foreach ($arr as $key => $val) { - $normalized[strtolower($key)] = $val; - } - return $normalized; - } - - /** - * Convert a string to camelCase - * @param string $value - * @return string - */ - public static function camelCase($value) - { - $value = ucwords(str_replace(array('-', '_'), ' ', $value)); - $value = str_replace(' ', '', $value); - $value[0] = strtolower($value[0]); - return $value; - } -} diff --git a/src/Google/Utils/URITemplate.php b/src/Google/Utils/UriTemplate.php similarity index 99% rename from src/Google/Utils/URITemplate.php rename to src/Google/Utils/UriTemplate.php index 0e30f80c4..e59fe9f21 100644 --- a/src/Google/Utils/URITemplate.php +++ b/src/Google/Utils/UriTemplate.php @@ -19,7 +19,7 @@ * Implementation of levels 1-3 of the URI Template spec. * @see http://tools.ietf.org/html/rfc6570 */ -class Google_Utils_URITemplate +class Google_Utils_UriTemplate { const TYPE_MAP = "1"; const TYPE_LIST = "2"; @@ -181,7 +181,7 @@ private function replaceVars( ); } } - + public function combine( $key, $parameters, @@ -200,17 +200,17 @@ public function combine( 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) { @@ -267,11 +267,11 @@ public function combine( 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 */ @@ -286,7 +286,7 @@ private function getDataType($data) } return self::TYPE_SCALAR; } - + /** * Utility function that merges multiple combine calls * for multi-key templates. @@ -318,7 +318,7 @@ private function combineList( } return implode($sep, $ret); } - + /** * Utility function to encode and trim values */ diff --git a/tests/BaseTest.php b/tests/BaseTest.php index daf50e9ae..d5c352140 100644 --- a/tests/BaseTest.php +++ b/tests/BaseTest.php @@ -15,10 +15,11 @@ * limitations under the License. */ +use Symfony\Component\DomCrawler\Crawler; + class BaseTest extends PHPUnit_Framework_TestCase { private $key; - private $token; private $client; private $memcacheHost; private $memcachePort; @@ -53,6 +54,7 @@ private function createClient() ]); $client = new Google_Client(); + $client->setApplicationName('google-api-php-client-tests'); $client->setHttpClient($httpClient); $client->setScopes([ "https://www.googleapis.com/auth/plus.me", @@ -65,9 +67,6 @@ private function createClient() if ($this->key) { $client->setDeveloperKey($this->key); } - if ($this->token) { - $client->setAccessToken($this->token); - } list($clientId, $clientSecret) = $this->getClientIdAndSecret(); $client->setClientId($clientId); $client->setClientSecret($clientSecret); @@ -78,36 +77,31 @@ private function createClient() public function checkToken() { - $cache = $this->getCache(); - $this->token = $cache->get('access_token'); - if (!$this->token) { - if (!$this->tryToGetAnAccessToken()) { + $client = $this->getClient(); + $cache = $client->getCache(); + + if (!$token = $cache->get('access_token')) { + if (!$token = $this->tryToGetAnAccessToken($client)) { return $this->markTestSkipped("Test requires access token"); } + $cache->set('access_token', $token); } - $client = $this->getClient(); - $client->setAccessToken($this->token); + $client->setAccessToken($token); if ($client->isAccessTokenExpired()) { - if (isset($this->token['refresh_token'])) { - $this->token = $client->refreshToken($this->token['refresh_token']); - } + // as long as we have client credentials, even if its expired + // our access token will automatically be refreshed + $this->checkClientCredentials(); } - $cache->set('access_token', $this->token); - return true; } - public function tryToGetAnAccessToken() + public function tryToGetAnAccessToken(Google_Client $client) { - $client = $this->getClient(); - if (!($client->getClientId() && $client->getClientSecret())) { - $this->markTestSkipped("Test requires GCLOUD_CLIENT_ID and GCLOUD_CLIENT_SECRET to be set"); - } + $this->checkClientCredentials(); - $client = $this->getClient(); $client->setRedirectUri("urn:ietf:wg:oauth:2.0:oob"); $client->setConfig('access_type', 'offline'); $authUrl = $client->createAuthUrl(); @@ -117,11 +111,9 @@ public function tryToGetAnAccessToken() `open '$authUrl'`; $authCode = trim(fgets(STDIN)); - if ($accessToken = $client->authenticate($authCode)) { + if ($accessToken = $client->fetchAccessTokenWithAuthCode($authCode)) { if (isset($accessToken['access_token'])) { - $this->token = $accessToken; - - return true; + return $accessToken; } } @@ -136,7 +128,15 @@ private function getClientIdAndSecret() return array($clientId, $clientSecret); } - public function checkServiceAccountToken() + public function checkClientCredentials() + { + list($clientId, $clientSecret) = $this->getClientIdAndSecret(); + if (!($clientId && $clientSecret)) { + $this->markTestSkipped("Test requires GCLOUD_CLIENT_ID and GCLOUD_CLIENT_SECRET to be set"); + } + } + + public function checkServiceAccountCredentials() { if (!$f = getenv('GOOGLE_APPLICATION_CREDENTIALS')) { $skip = "This test requires the GOOGLE_APPLICATION_CREDENTIALS environment variable to be set\n" @@ -169,4 +169,24 @@ public function loadKey() return file_get_contents($f); } } + + protected function loadExample($example) + { + // trick app into thinking we are a web server + $_SERVER['HTTP_USER_AGENT'] = 'google-api-php-client-tests'; + $_SERVER['HTTP_HOST'] = 'localhost'; + $_SERVER['REQUEST_METHOD'] = 'GET'; + + // include the file and return an HTML crawler + $file = __DIR__ . '/../examples/' . $example; + if (is_file($file)) { + ob_start(); + include $file; + $html = ob_get_clean(); + + return new Crawler($html); + } + + return false; + } } diff --git a/tests/Google/AccessToken/RevokeTest.php b/tests/Google/AccessToken/RevokeTest.php new file mode 100644 index 000000000..ee5c45588 --- /dev/null +++ b/tests/Google/AccessToken/RevokeTest.php @@ -0,0 +1,87 @@ +getMock('GuzzleHttp\Post\PostBodyInterface'); + $postBody->expects($this->exactly(2)) + ->method('replaceFields') + ->will($this->returnCallback( + function ($fields) use (&$token) { + $token = isset($fields['token']) ? $fields['token'] : null; + } + )); + $request = $this->getMock('GuzzleHttp\Message\RequestInterface'); + $request->expects($this->exactly(2)) + ->method('getBody') + ->will($this->returnValue($postBody)); + $response = $this->getMock('GuzzleHttp\Message\ResponseInterface'); + $response->expects($this->exactly(2)) + ->method('getStatusCode') + ->will($this->returnValue(200)); + $http = $this->getMock('GuzzleHttp\ClientInterface'); + $http->expects($this->exactly(2)) + ->method('send') + ->will($this->returnValue($response)); + $http->expects($this->exactly(2)) + ->method('createRequest') + ->will($this->returnValue($request)); + + $t = array( + 'access_token' => $accessToken, + 'created' => time(), + 'expires_in' => '3600' + ); + + // Test with access token. + $revoke = new Google_AccessToken_Revoke($http); + $this->assertTrue($revoke->revokeToken($t)); + $this->assertEquals($accessToken, $token); + + // Test with refresh token. + $revoke = new Google_AccessToken_Revoke($http); + $t = array( + 'access_token' => $accessToken, + 'refresh_token' => $refreshToken, + 'created' => time(), + 'expires_in' => '3600' + ); + $this->assertTrue($revoke->revokeToken($t)); + $this->assertEquals($refreshToken, $token); + } + + /** @expectedException PHPUnit_Framework_Error */ + public function testInvalidStringToken() + { + // Test with string token + $revoke = new Google_AccessToken_Revoke(); + $revoke->revokeToken('ACCESS_TOKEN'); + } +} diff --git a/tests/Google/AccessToken/VerifyTest.php b/tests/Google/AccessToken/VerifyTest.php new file mode 100644 index 000000000..cae3fb101 --- /dev/null +++ b/tests/Google/AccessToken/VerifyTest.php @@ -0,0 +1,60 @@ +checkToken(); + + $client = $this->getClient(); + $token = $client->getAccessToken(); + if ($client->isAccessTokenExpired()) { + $token = $client->fetchAccessTokenWithRefreshToken(); + } + $segments = explode('.', $token['id_token']); + $this->assertEquals(3, count($segments)); + // Extract the client ID in this case as it wont be set on the test client. + $data = json_decode(JWT::urlSafeB64Decode($segments[1])); + $verify = new Google_AccessToken_Verify(); + $payload = $verify->verifyIdToken($token['id_token'], $data->aud); + $this->assertTrue(isset($payload->sub)); + $this->assertTrue(strlen($payload->sub) > 0); + + // TODO: Need to be smart about testing/disabling the + // caching for this test to make sense. Not sure how to do that + // at the moment. + $client = $this->getClient(); + $data = json_decode(JWT::urlSafeB64Decode($segments[1])); + $verify = new Google_AccessToken_Verify(); + $payload = $verify->verifyIdToken($token['id_token'], $data->aud); + $this->assertTrue(isset($payload->sub)); + $this->assertTrue(strlen($payload->sub) > 0); + } +} diff --git a/tests/Google/AccessTokenTest.php b/tests/Google/AccessTokenTest.php deleted file mode 100644 index 6c58096a6..000000000 --- a/tests/Google/AccessTokenTest.php +++ /dev/null @@ -1,160 +0,0 @@ -getMock('GuzzleHttp\Post\PostBodyInterface'); - $postBody->expects($this->exactly(3)) - ->method('replaceFields') - ->will($this->returnCallback( - function ($fields) use (&$token) { - $token = isset($fields['token']) ? $fields['token'] : null; - } - )); - $request = $this->getMock('GuzzleHttp\Message\RequestInterface'); - $request->expects($this->exactly(3)) - ->method('getBody') - ->will($this->returnValue($postBody)); - $response = $this->getMock('GuzzleHttp\Message\ResponseInterface'); - $response->expects($this->exactly(3)) - ->method('getStatusCode') - ->will($this->returnValue(200)); - $http = $this->getMock('GuzzleHttp\ClientInterface'); - $http->expects($this->exactly(3)) - ->method('send') - ->will($this->returnValue($response)); - $http->expects($this->exactly(3)) - ->method('createRequest') - ->will($this->returnValue($request)); - - // Test with access token. - $t = new Google_AccessToken( - array( - 'access_token' => $accessToken, - 'created' => time(), - 'expires_in' => '3600' - ), - $http - ); - $this->assertTrue($t->revokeToken()); - $this->assertEquals($accessToken, $token); - - // Test with refresh token. - $t->setAccessToken( - array( - 'access_token' => $accessToken, - 'refresh_token' => $refreshToken, - 'created' => time(), - 'expires_in' => '3600' - ) - ); - $this->assertTrue($t->revokeToken()); - $this->assertEquals($refreshToken, $token); - - // Test with string token - $t->setAccessToken($accessToken2); - $this->assertTrue($t->revokeToken()); - $this->assertEquals($accessToken2, $token); - } - - // /** - // * Most of the logic for ID token validation is in AuthTest - - // * this is just a general check to ensure we verify a valid - // * id token if one exists. - // */ - // public function testValidateIdToken() - // { - // $this->checkToken(); - // $client = $this->getClient(); - // $token = json_decode($client->getAccessToken()); - // $segments = explode(".", $token->id_token); - // $this->assertEquals(3, count($segments)); - // // Extract the client ID in this case as it wont be set on the test client. - // $data = json_decode(JWT::urlSafeB64Decode($segments[1])); - // $oauth = new Google_Auth_OAuth2($client); - // $payload = $oauth->verifyIdToken($token->id_token, $data->aud); - // $this->assertArrayHasKey('sub', $payload); - // $this->assertTrue(strlen($payload['sub']) > 0); - - // // TODO: Need to be smart about testing/disabling the - // // caching for this test to make sense. Not sure how to do that - // // at the moment. - // $client = $this->getClient(); - // $data = json_decode(JWT::urlSafeB64Decode($segments[1])); - // $oauth = new Google_Auth_OAuth2($client); - // $payload = $oauth->verifyIdToken($token->id_token, $data->aud); - // $this->assertArrayHasKey('sub', $payload); - // $this->assertTrue(strlen($payload['sub']) > 0); - // } - - // /** - // * Test for revoking token when none is opened - // */ - // public function testRevokeWhenNoTokenExists() - // { - // $client = new Google_Client(); - // $this->assertFalse($client->revokeToken()); - // } - - // /** - // * Test that the ID token is properly refreshed. - // */ - // public function testRefreshTokenSetsValues() - // { - // $client = new Google_Client(); - // $request = $this->getMock('GuzzleHttp\Message\RequestInterface'); - // $request->expects($this->once()) - // ->method('getBody') - // ->will($this->returnValue($this->getMock('GuzzleHttp\Post\PostBodyInterface'))); - // $response = $this->getMock('GuzzleHttp\Message\ResponseInterface'); - // $response->expects($this->once()) - // ->method('json') - // ->will($this->returnValue(array( - // 'access_token' => 'xyz', - // 'id_token' => 'ID_TOKEN', - // ))); - // $response->expects($this->once()) - // ->method('getBody') - // ->will($this->returnValue($this->getMock('GuzzleHttp\Post\PostBody'))); - // $http = $this->getMock('GuzzleHttp\ClientInterface'); - // $http->expects($this->once()) - // ->method('send') - // ->will($this->returnValue($response)); - // $http->expects($this->once()) - // ->method('createRequest') - // ->will($this->returnValue($request)); - // $client->setHttpClient($http); - // $oauth = new Google_Auth_OAuth2($client); - // $oauth->refreshToken("REFRESH_TOKEN"); - // $token = json_decode($oauth->getAccessToken(), true); - // $this->assertEquals($token['id_token'], "ID_TOKEN"); - // } -} diff --git a/tests/Google/ClientTest.php b/tests/Google/ClientTest.php index 97941b7c6..f38bbdfa8 100644 --- a/tests/Google/ClientTest.php +++ b/tests/Google/ClientTest.php @@ -35,7 +35,7 @@ public function testSignAppKey() $client->setDeveloperKey('devKey'); $http = new Client(); - $client->attachAuthListener($http); + $client->authorize($http); $listeners = $http->getEmitter()->listeners('before'); $this->assertEquals(1, count($listeners)); @@ -54,7 +54,7 @@ public function testSignAccessToken() 'created' => time(), ]); $client->setScopes('test_scope'); - $client->attachAuthListener($http); + $client->authorize($http); $listeners = $http->getEmitter()->listeners('before'); $this->assertEquals(1, count($listeners)); @@ -71,10 +71,10 @@ public function testCreateAuthUrl() $client->setRedirectUri('http://localhost'); $client->setDeveloperKey('devKey'); $client->setState('xyz'); - $client->setConfig('access_type', 'offline'); - $client->setConfig('approval_prompt', 'force'); - $client->setConfig('request_visible_actions', 'http://foo'); - $client->setConfig('login_hint', 'bob@example.org'); + $client->setAccessType('offline'); + $client->setApprovalPrompt('force'); + $client->setRequestVisibleActions('http://foo'); + $client->setLoginHint('bob@example.org'); $authUrl = $client->createAuthUrl("http://googleapis.com/scope/foo"); $expected = "https://accounts.google.com/o/oauth2/auth" @@ -89,11 +89,11 @@ public function testCreateAuthUrl() $this->assertEquals($expected, $authUrl); // Again with a blank login hint (should remove all traces from authUrl) - $client->setConfig('login_hint', ''); - $client->setConfig('hosted_domain', 'example.com'); - $client->setConfig('openid.realm', 'example.com'); - $client->setConfig('prompt', 'select_account'); - $client->setConfig('include_granted_scopes', true); + $client->setLoginHint(''); + $client->setHostedDomain('example.com'); + $client->setOpenIdRealm('example.com'); + $client->setPrompt('select_account'); + $client->setIncludeGrantedScopes(true); $authUrl = $client->createAuthUrl("http://googleapis.com/scope/foo"); $expected = "https://accounts.google.com/o/oauth2/auth" . "?access_type=offline" @@ -175,9 +175,6 @@ public function testPrepareService() $http->expects($this->once()) ->method('createRequest') ->will($this->returnValue($request)); - $http->expects($this->once()) - ->method('getEmitter') - ->will($this->returnValue($this->getMock('GuzzleHttp\Event\EmitterInterface'))); $http->expects($this->once()) ->method('send') ->will($this->returnValue($response)); @@ -192,8 +189,8 @@ public function testSettersGetters() $client->setClientId("client1"); $client->setClientSecret('client1secret'); $client->setState('1'); - $client->setConfig('approval_prompt', 'force'); - $client->setConfig('access_type', 'offline'); + $client->setApprovalPrompt('force'); + $client->setAccessType('offline'); $client->setRedirectUri('localhost'); $client->setConfig('application_name', 'me'); @@ -201,7 +198,7 @@ public function testSettersGetters() try { $client->setAccessToken(null); - $this->fail('Should have thrown an Google_Auth_Exception.'); + $this->fail('Should have thrown an Exception.'); } catch (InvalidArgumentException $e) { $this->assertEquals('invalid json token', $e->getMessage()); } @@ -232,11 +229,11 @@ public function testJsonConfig() '"client_email":"","redirect_uris":["urn:ietf:wg:oauth:2.0:oob","oob"],"client_x509_cert_url"'. ':"","client_id":"123456789.apps.googleusercontent.com","auth_provider_x509_cert_url":'. '"https://www.googleapis.com/oauth2/v1/certs"}}'; - $dObj = json_decode($device); - $client->setAuthConfig($device); - $this->assertEquals($client->getClientId(), $dObj->installed->client_id); - $this->assertEquals($client->getClientSecret(), $dObj->installed->client_secret); - $this->assertEquals($client->getRedirectUri(), $dObj->installed->redirect_uris[0]); + $dObj = json_decode($device, true); + $client->setAuthConfig($dObj); + $this->assertEquals($client->getClientId(), $dObj['installed']['client_id']); + $this->assertEquals($client->getClientSecret(), $dObj['installed']['client_secret']); + $this->assertEquals($client->getRedirectUri(), $dObj['installed']['redirect_uris'][0]); // Web config $client = new Google_Client(); @@ -246,10 +243,10 @@ public function testJsonConfig() '"https://www.googleapis.com/robot/v1/metadata/x509/123456789@developer.gserviceaccount.com"'. ',"client_id":"123456789.apps.googleusercontent.com","auth_provider_x509_cert_url":'. '"https://www.googleapis.com/oauth2/v1/certs"}}'; - $wObj = json_decode($web); - $client->setAuthConfig($web); - $this->assertEquals($client->getClientId(), $wObj->web->client_id); - $this->assertEquals($client->getClientSecret(), $wObj->web->client_secret); + $wObj = json_decode($web, true); + $client->setAuthConfig($wObj); + $this->assertEquals($client->getClientId(), $wObj['web']['client_id']); + $this->assertEquals($client->getClientSecret(), $wObj['web']['client_secret']); $this->assertEquals($client->getRedirectUri(), ''); } @@ -277,7 +274,7 @@ public function testNoAuth() putenv('GOOGLE_APPLICATION_CREDENTIALS='); putenv('HOME='.sys_get_temp_dir()); $http = new Client(); - $client->attachAuthListener($http); + $client->authorize($http); $listeners = $http->getEmitter()->listeners('before'); @@ -285,4 +282,37 @@ public function testNoAuth() putenv("HOME=$HOME"); $this->assertEquals(0, count($listeners)); } + + /** + * Test that the ID token is properly refreshed. + */ + public function testRefreshTokenSetsValues() + { + $request = $this->getMock('GuzzleHttp\Message\RequestInterface'); + $request->expects($this->once()) + ->method('getBody') + ->will($this->returnValue($this->getMock('GuzzleHttp\Post\PostBodyInterface'))); + $response = $this->getMock('GuzzleHttp\Message\ResponseInterface'); + $response->expects($this->once()) + ->method('json') + ->will($this->returnValue(array( + 'access_token' => 'xyz', + 'id_token' => 'ID_TOKEN', + ))); + $response->expects($this->once()) + ->method('getBody') + ->will($this->returnValue($this->getMock('GuzzleHttp\Post\PostBody'))); + $http = $this->getMock('GuzzleHttp\ClientInterface'); + $http->expects($this->once()) + ->method('send') + ->will($this->returnValue($response)); + $http->expects($this->once()) + ->method('createRequest') + ->will($this->returnValue($request)); + $client = $this->getClient(); + $client->setHttpClient($http); + $client->fetchAccessTokenWithRefreshToken("REFRESH_TOKEN"); + $token = $client->getAccessToken(); + $this->assertEquals($token['id_token'], "ID_TOKEN"); + } } diff --git a/tests/Google/Http/BatchTest.php b/tests/Google/Http/BatchTest.php new file mode 100644 index 000000000..69df11365 --- /dev/null +++ b/tests/Google/Http/BatchTest.php @@ -0,0 +1,78 @@ +checkToken(); + + $client = $this->getClient(); + $batch = new Google_Http_Batch($client); + $this->plus = new Google_Service_Plus($client); + + $client->setUseBatch(true); + $batch->add($this->plus->people->get('me'), 'key1'); + $batch->add($this->plus->people->get('me'), 'key2'); + $batch->add($this->plus->people->get('me'), 'key3'); + + $result = $batch->execute(); + $this->assertTrue(isset($result['response-key1'])); + $this->assertTrue(isset($result['response-key2'])); + $this->assertTrue(isset($result['response-key3'])); + } + + public function testBatchRequest() + { + $client = $this->getClient(); + $batch = new Google_Http_Batch($client); + $this->plus = new Google_Service_Plus($client); + + $client->setUseBatch(true); + $batch->add($this->plus->people->get('+LarryPage'), 'key1'); + $batch->add($this->plus->people->get('+LarryPage'), 'key2'); + $batch->add($this->plus->people->get('+LarryPage'), 'key3'); + + $result = $batch->execute(); + $this->assertTrue(isset($result['response-key1'])); + $this->assertTrue(isset($result['response-key2'])); + $this->assertTrue(isset($result['response-key3'])); + } + + public function testInvalidBatchRequest() + { + $client = $this->getClient(); + $batch = new Google_Http_Batch($client); + $this->plus = new Google_Service_Plus($client); + + $client->setUseBatch(true); + $batch->add($this->plus->people->get('123456789987654321'), 'key1'); + $batch->add($this->plus->people->get('+LarryPage'), 'key2'); + + $result = $batch->execute(); + $this->assertTrue(isset($result['response-key2'])); + $this->assertInstanceOf( + 'Google_Service_Exception', + $result['response-key1'] + ); + } +} diff --git a/tests/Google/Http/ParallelTest.php b/tests/Google/Http/PoolTest.php similarity index 69% rename from tests/Google/Http/ParallelTest.php rename to tests/Google/Http/PoolTest.php index a82d0689f..952bad0a7 100644 --- a/tests/Google/Http/ParallelTest.php +++ b/tests/Google/Http/PoolTest.php @@ -18,7 +18,7 @@ * under the License. */ -class Google_Http_ParallelTest extends BaseTest +class Google_Http_PoolTest extends BaseTest { public $parallel; public $plus; @@ -28,11 +28,11 @@ public function setUp() $this->checkToken(); $client = $this->getClient(); $client->setUseBatch(true); - $this->parallel = new Google_Http_Parallel($client); + $this->parallel = new Google_Http_Pool($client); $this->plus = new Google_Service_Plus($client); } - public function testBatchRequestWithAuth() + public function testParallelRequestWithAuth() { $this->parallel->add($this->plus->people->get('me'), 'key1'); $this->parallel->add($this->plus->people->get('me'), 'key2'); @@ -47,22 +47,7 @@ public function testBatchRequestWithAuth() $this->assertInstanceOf('Google_Service_Plus_Person', $result['response-key3']); } - public function testBatchRequest() - { - $this->parallel->add($this->plus->people->get('+LarryPage'), 'key1'); - $this->parallel->add($this->plus->people->get('+LarryPage'), 'key2'); - $this->parallel->add($this->plus->people->get('+LarryPage'), 'key3'); - - $result = $this->parallel->execute(); - $this->assertTrue(isset($result['response-key1'])); - $this->assertTrue(isset($result['response-key2'])); - $this->assertTrue(isset($result['response-key3'])); - $this->assertInstanceOf('Google_Service_Plus_Person', $result['response-key1']); - $this->assertInstanceOf('Google_Service_Plus_Person', $result['response-key2']); - $this->assertInstanceOf('Google_Service_Plus_Person', $result['response-key3']); - } - - public function testInvalidBatchRequest() + public function testInvalidParallelRequest() { $this->parallel->add($this->plus->people->get('123456789987654321'), 'key1'); $this->parallel->add($this->plus->people->get('+LarryPage'), 'key2'); diff --git a/tests/Google/Service/PagespeedonlineTest.php b/tests/Google/Service/PagespeedonlineTest.php index 622600433..e63a8780c 100644 --- a/tests/Google/Service/PagespeedonlineTest.php +++ b/tests/Google/Service/PagespeedonlineTest.php @@ -17,17 +17,11 @@ class Google_Service_PagespeedonlineTest extends BaseTest { - public $service; - public function __construct() - { - parent::__construct(); - $this->service = new Google_Service_Pagespeedonline($this->getClient()); - } - public function testPageSpeed() { $this->checkToken(); - $psapi = $this->service->pagespeedapi; + $service = new Google_Service_Pagespeedonline($this->getClient()); + $psapi = $service->pagespeedapi; $result = $psapi->runpagespeed('http://code.google.com'); $this->assertArrayHasKey('kind', $result); $this->assertArrayHasKey('id', $result); diff --git a/tests/Google/Service/ResourceTest.php b/tests/Google/Service/ResourceTest.php index 0f3fa759c..dec93aee0 100644 --- a/tests/Google/Service/ResourceTest.php +++ b/tests/Google/Service/ResourceTest.php @@ -167,4 +167,31 @@ public function testCreateRequestUri() $value = $resource->createRequestUri('/plus', $params); $this->assertEquals("http://localhost/plus?u=%40me%2F", $value); } + + public function testAppEngineSslCerts() + { + $this->client->expects($this->once()) + ->method("isAppEngine") + ->will($this->returnValue(true)); + $resource = new Google_Service_Resource( + $this->service, + "test", + "testResource", + array("methods" => + array( + "testMethod" => array( + "parameters" => array(), + "path" => "method/path", + "httpMethod" => "POST", + ) + ) + ) + ); + $request = $resource->call("testMethod", array(array())); + $this->assertEquals( + '/etc/ca-certificates.crt', + $this->client->getHttpClient()->getDefaultOption('verify') + ); + } + } diff --git a/tests/Google/ServiceTest.php b/tests/Google/ServiceTest.php index 75801c25c..f119a5c42 100644 --- a/tests/Google/ServiceTest.php +++ b/tests/Google/ServiceTest.php @@ -93,15 +93,4 @@ public function serviceProvider() return $classes; } - - public function testStrLen() - { - $this->assertEquals(0, Google_Utils::getStrLen(null)); - $this->assertEquals(0, Google_Utils::getStrLen(false)); - $this->assertEquals(0, Google_Utils::getStrLen("")); - - $this->assertEquals(1, Google_Utils::getStrLen(" ")); - $this->assertEquals(2, Google_Utils::getStrLen(" 1")); - $this->assertEquals(7, Google_Utils::getStrLen("0a\\n\n\r\n")); - } } diff --git a/tests/Google/Task/RunnerTest.php b/tests/Google/Task/RunnerTest.php index 1dc73c9fd..399e1da92 100644 --- a/tests/Google/Task/RunnerTest.php +++ b/tests/Google/Task/RunnerTest.php @@ -26,16 +26,11 @@ class Google_Task_RunnerTest extends PHPUnit_Framework_TestCase private $mockedCallsCount = 0; private $currentMockedCall = 0; private $mockedCalls = array(); - private $nextRetryMap; - private static $retryConfig; + private $retryMap; + private $retryConfig; protected function setUp() { - // hack to reset static Google_Client::$retryConfig each test - if (!self::$retryConfig) { - self::$retryConfig = Google_Client::$retryConfig; - } - Google_Client::$retryConfig = self::$retryConfig; $this->client = new Google_Client(); } @@ -54,7 +49,7 @@ public function testRestRetryOffByDefault($errorCode, $errorBody = '{}') */ public function testOneRestRetryWithError($errorCode, $errorBody = '{}') { - $this->setTaskConfig(array('retries' => 1)); + $this->setRetryConfig(array('retries' => 1)); $this->setNextResponses(2, $errorCode, $errorBody)->makeRequest(); } @@ -66,7 +61,7 @@ public function testMultipleRestRetriesWithErrors( $errorCode, $errorBody = '{}' ) { - $this->setTaskConfig(array('retries' => 5)); + $this->setRetryConfig(array('retries' => 5)); $this->setNextResponses(6, $errorCode, $errorBody)->makeRequest(); } @@ -75,7 +70,7 @@ public function testMultipleRestRetriesWithErrors( */ public function testOneRestRetryWithSuccess($errorCode, $errorBody = '{}') { - $this->setTaskConfig(array('retries' => 1)); + $this->setRetryConfig(array('retries' => 1)); $result = $this->setNextResponse($errorCode, $errorBody) ->setNextResponse(200, '{"success": true}') ->makeRequest(); @@ -90,7 +85,7 @@ public function testMultipleRestRetriesWithSuccess( $errorCode, $errorBody = '{}' ) { - $this->setTaskConfig(array('retries' => 5)); + $this->setRetryConfig(array('retries' => 5)); $result = $this->setNextResponses(2, $errorCode, $errorBody) ->setNextResponse(200, '{"success": true}') ->makeRequest(); @@ -108,7 +103,7 @@ public function testCustomRestRetryMapReplacesDefaults( ) { $this->setRetryMap(array()); - $this->setTaskConfig(array('retries' => 5)); + $this->setRetryConfig(array('retries' => 5)); $this->setNextResponse($errorCode, $errorBody)->makeRequest(); } @@ -118,7 +113,7 @@ public function testCustomRestRetryMapAddsNewHandlers() array('403' => Google_Task_Runner::TASK_RETRY_ALWAYS) ); - $this->setTaskConfig(array('retries' => 5)); + $this->setRetryConfig(array('retries' => 5)); $result = $this->setNextResponses(2, 403) ->setNextResponse(200, '{"success": true}') ->makeRequest(); @@ -136,7 +131,7 @@ public function testCustomRestRetryMapWithCustomLimits($limit) array('403' => $limit) ); - $this->setTaskConfig(array('retries' => 5)); + $this->setRetryConfig(array('retries' => 5)); $this->setNextResponses($limit + 1, 403)->makeRequest(); } @@ -145,7 +140,7 @@ public function testCustomRestRetryMapWithCustomLimits($limit) */ public function testRestTimeouts($config, $minTime) { - $this->setTaskConfig($config); + $this->setRetryConfig($config); $this->setNextResponses($config['retries'], 500) ->setNextResponse(200, '{"success": true}'); @@ -173,7 +168,7 @@ public function testCurlRetryOffByDefault($errorCode, $errorMessage = '') */ public function testOneCurlRetryWithError($errorCode, $errorMessage = '') { - $this->setTaskConfig(array('retries' => 1)); + $this->setRetryConfig(array('retries' => 1)); $this->setNextResponsesThrow(2, $errorMessage, $errorCode)->makeRequest(); } @@ -186,7 +181,7 @@ public function testMultipleCurlRetriesWithErrors( $errorCode, $errorMessage = '' ) { - $this->setTaskConfig(array('retries' => 5)); + $this->setRetryConfig(array('retries' => 5)); $this->setNextResponsesThrow(6, $errorMessage, $errorCode)->makeRequest(); } @@ -196,7 +191,7 @@ public function testMultipleCurlRetriesWithErrors( */ public function testOneCurlRetryWithSuccess($errorCode, $errorMessage = '') { - $this->setTaskConfig(array('retries' => 1)); + $this->setRetryConfig(array('retries' => 1)); $result = $this->setNextResponseThrows($errorMessage, $errorCode) ->setNextResponse(200, '{"success": true}') ->makeRequest(); @@ -212,7 +207,7 @@ public function testMultipleCurlRetriesWithSuccess( $errorCode, $errorMessage = '' ) { - $this->setTaskConfig(array('retries' => 5)); + $this->setRetryConfig(array('retries' => 5)); $result = $this->setNextResponsesThrow(2, $errorMessage, $errorCode) ->setNextResponse(200, '{"success": true}') ->makeRequest(); @@ -231,7 +226,7 @@ public function testCustomCurlRetryMapReplacesDefaults( ) { $this->setRetryMap(array()); - $this->setTaskConfig(array('retries' => 5)); + $this->setRetryConfig(array('retries' => 5)); $this->setNextResponseThrows($errorMessage, $errorCode)->makeRequest(); } @@ -244,7 +239,7 @@ public function testCustomCurlRetryMapAddsNewHandlers() array(CURLE_COULDNT_RESOLVE_PROXY => Google_Task_Runner::TASK_RETRY_ALWAYS) ); - $this->setTaskConfig(array('retries' => 5)); + $this->setRetryConfig(array('retries' => 5)); $result = $this->setNextResponsesThrow(2, '', CURLE_COULDNT_RESOLVE_PROXY) ->setNextResponse(200, '{"success": true}') ->makeRequest(); @@ -263,7 +258,7 @@ public function testCustomCurlRetryMapWithCustomLimits($limit) array(CURLE_COULDNT_RESOLVE_PROXY => $limit) ); - $this->setTaskConfig(array('retries' => 5)); + $this->setRetryConfig(array('retries' => 5)); $this->setNextResponsesThrow($limit + 1, '', CURLE_COULDNT_RESOLVE_PROXY) ->makeRequest(); } @@ -274,7 +269,7 @@ public function testCustomCurlRetryMapWithCustomLimits($limit) */ public function testCurlTimeouts($config, $minTime) { - $this->setTaskConfig($config); + $this->setRetryConfig($config); $this->setNextResponsesThrow($config['retries'], '', CURLE_GOT_NOTHING) ->setNextResponse(200, '{"success": true}'); @@ -291,10 +286,10 @@ public function testCurlTimeouts($config, $minTime) public function testBadTaskConfig($config, $message) { $this->setExpectedException('Google_Task_Exception', $message); - $this->setTaskConfig($config); + $this->setRetryConfig($config); new Google_Task_Runner( - Google_Client::$retryConfig, + $this->retryConfig, '', array($this, 'testBadTaskConfig') ); @@ -324,7 +319,7 @@ public function testTaskRetryOffByDefault() */ public function testOneTaskRetryWithError() { - $this->setTaskConfig(array('retries' => 1)); + $this->setRetryConfig(array('retries' => 1)); $this->setNextTasksAllowedRetries(2, Google_Task_Runner::TASK_RETRY_ALWAYS) ->runTask(); } @@ -334,14 +329,14 @@ public function testOneTaskRetryWithError() */ public function testMultipleTaskRetriesWithErrors() { - $this->setTaskConfig(array('retries' => 5)); + $this->setRetryConfig(array('retries' => 5)); $this->setNextTasksAllowedRetries(6, Google_Task_Runner::TASK_RETRY_ALWAYS) ->runTask(); } public function testOneTaskRetryWithSuccess() { - $this->setTaskConfig(array('retries' => 1)); + $this->setRetryConfig(array('retries' => 1)); $result = $this->setNextTaskAllowedRetries(Google_Task_Runner::TASK_RETRY_ALWAYS) ->setNextTaskReturnValue('success') ->runTask(); @@ -351,7 +346,7 @@ public function testOneTaskRetryWithSuccess() public function testMultipleTaskRetriesWithSuccess() { - $this->setTaskConfig(array('retries' => 5)); + $this->setRetryConfig(array('retries' => 5)); $result = $this->setNextTasksAllowedRetries(2, Google_Task_Runner::TASK_RETRY_ALWAYS) ->setNextTaskReturnValue('success') ->runTask(); @@ -365,7 +360,7 @@ public function testMultipleTaskRetriesWithSuccess() */ public function testTaskRetryWithCustomLimits($limit) { - $this->setTaskConfig(array('retries' => 5)); + $this->setRetryConfig(array('retries' => 5)); $this->setNextTasksAllowedRetries($limit + 1, $limit) ->runTask(); } @@ -375,7 +370,7 @@ public function testTaskRetryWithCustomLimits($limit) */ public function testTaskTimeouts($config, $minTime) { - $this->setTaskConfig($config); + $this->setRetryConfig($config); $this->setNextTasksAllowedRetries($config['retries'], $config['retries'] + 1) ->setNextTaskReturnValue('success'); @@ -388,12 +383,11 @@ public function testTaskTimeouts($config, $minTime) public function testTaskWithManualRetries() { - $this->setTaskConfig(array('retries' => 2)); + $this->setRetryConfig(array('retries' => 2)); $this->setNextTasksAllowedRetries(2, Google_Task_Runner::TASK_RETRY_ALWAYS); - $config = Google_Client::$retryConfig; $task = new Google_Task_Runner( - $config, + $this->retryConfig, '', array($this, 'runNextTask') ); @@ -523,7 +517,7 @@ public static function assertTaskTimeGreaterThanOrEqual( * * @param array $config The task runner configurations */ - private function setTaskConfig(array $config) + private function setRetryConfig(array $config) { $config += array( 'initial_delay' => .0001, @@ -532,12 +526,12 @@ private function setTaskConfig(array $config) 'jitter' => .5, 'retries' => 1 ); - Google_Client::$retryConfig = $config; + $this->retryConfig = $config; } private function setRetryMap(array $retryMap) { - $this->nextRetryMap = $retryMap; + $this->retryMap = $retryMap; } /** @@ -638,11 +632,7 @@ private function makeRequest() ->method('send') ->will($this->returnCallback(array($this, 'getNextMockedCall'))); - $config = Google_Client::$retryConfig; - - $retryMap = $this->nextRetryMap; - $this->nextRetryMap = null; - return Google_Http_REST::execute($http, $request, $config, $retryMap); + return Google_Http_REST::execute($http, $request, $this->retryConfig, $this->retryMap); } /** @@ -716,19 +706,20 @@ private function setNextTasksAllowedRetries($count, $allowedRetries) */ private function runTask() { - $config = Google_Client::$retryConfig; $task = new Google_Task_Runner( - $config, + $this->retryConfig, '', array($this, 'runNextTask') ); - if (null !== $this->nextRetryMap) { - $task->setRetryMap($this->nextRetryMap); - $this->nextRetryMap = null; + if (null !== $this->retryMap) { + $task->setRetryMap($this->retryMap); } $exception = $this->getMockBuilder('Google_Service_Exception') + // HHVM blows up unless this is set + // @see https://github.com/sebastianbergmann/phpunit-mock-objects/issues/207 + ->setMethods(array('setTraceOptions')) ->disableOriginalConstructor() ->getMock(); $exceptionCount = 0; diff --git a/tests/Google/Utils/URITemplateTest.php b/tests/Google/Utils/UriTemplateTest.php similarity index 96% rename from tests/Google/Utils/URITemplateTest.php rename to tests/Google/Utils/UriTemplateTest.php index 2e5535c25..ba5dc3f3b 100644 --- a/tests/Google/Utils/URITemplateTest.php +++ b/tests/Google/Utils/UriTemplateTest.php @@ -18,14 +18,14 @@ * under the License. */ -class Google_Utils_URITemplateTest extends BaseTest +class Google_Utils_UriTemplateTest extends BaseTest { public function testLevelOne() { $var = "value"; $hello = "Hello World!"; - $urit = new Google_Utils_URITemplate(); + $urit = new Google_Utils_UriTemplate(); $this->assertEquals( "value", $urit->parse("{var}", array("var" => $var)) @@ -42,7 +42,7 @@ public function testLevelTwo() $hello = "Hello World!"; $path = "/foo/bar"; - $urit = new Google_Utils_URITemplate(); + $urit = new Google_Utils_UriTemplate(); $this->assertEquals( "value", $urit->parse("{+var}", array("var" => $var)) @@ -78,7 +78,7 @@ public function testLevelThree() $x = "1024"; $y = "768"; - $urit = new Google_Utils_URITemplate(); + $urit = new Google_Utils_UriTemplate(); $this->assertEquals( "map?1024,768", $urit->parse("map?{x,y}", array("x" => $x, "y" => $y)) @@ -219,7 +219,7 @@ public function testLevelFour() ); - $urit = new Google_Utils_URITemplate(); + $urit = new Google_Utils_UriTemplate(); foreach ($tests as $input => $output) { $this->assertEquals($output, $urit->parse($input, $values), $input . " failed"); @@ -230,7 +230,7 @@ public function testMultipleAnnotations() { $var = "value"; $hello = "Hello World!"; - $urit = new Google_Utils_URITemplate(); + $urit = new Google_Utils_UriTemplate(); $this->assertEquals( "http://www.google.com/Hello%20World!?var=value", $urit->parse( @@ -266,7 +266,7 @@ public function testAgainstStandardTests() { $location = "../../uritemplate-test/*.json"; - $urit = new Google_Utils_URITemplate(); + $urit = new Google_Utils_UriTemplate(); foreach (glob($location) as $file) { $test = json_decode(file_get_contents($file), true); foreach ($test as $title => $testsets) { diff --git a/tests/clearToken.php b/tests/clearToken.php index 1990ec84a..cd6fc5b2d 100644 --- a/tests/clearToken.php +++ b/tests/clearToken.php @@ -5,4 +5,4 @@ print_r($test->getCache()->get('access_token')); $test->getCache()->delete('access_token'); -echo "SUCCESS\n"; \ No newline at end of file +echo "SUCCESS\n"; diff --git a/tests/config/test.ini b/tests/config/test.ini index 61be46410..dbae3d78a 100644 --- a/tests/config/test.ini +++ b/tests/config/test.ini @@ -3,4 +3,4 @@ application_name = My Test application auth_class = Google_Auth_OAuth2 client_id = 12345.apps.googleusercontent.com client_secret = gjfiwnGinpena3 -redirect_uri = http://example.com \ No newline at end of file +redirect_uri = http://example.com diff --git a/tests/examples/batchTest.php b/tests/examples/batchTest.php new file mode 100644 index 000000000..b721ffd8a --- /dev/null +++ b/tests/examples/batchTest.php @@ -0,0 +1,35 @@ +checkKey(); + + $crawler = $this->loadExample('batch.php'); + + $nodes = $crawler->filter('br'); + $this->assertEquals(20, count($nodes)); + $this->assertContains('The Life of Henry David Thoreau', $crawler->text()); + $this->assertContains('George Bernard Shaw His Life and Works', $crawler->text()); + } +} \ No newline at end of file diff --git a/tests/examples/idTokenTest.php b/tests/examples/idTokenTest.php new file mode 100644 index 000000000..ecda53bb6 --- /dev/null +++ b/tests/examples/idTokenTest.php @@ -0,0 +1,32 @@ +loadExample('idtoken.php'); + + $nodes = $crawler->filter('h1'); + $this->assertEquals(1, count($nodes)); + $this->assertEquals('Retrieving An Id Token', $nodes->first()->text()); + } +} \ No newline at end of file diff --git a/tests/examples/indexTest.php b/tests/examples/indexTest.php new file mode 100644 index 000000000..d869f9145 --- /dev/null +++ b/tests/examples/indexTest.php @@ -0,0 +1,32 @@ +loadExample('index.php'); + + $nodes = $crawler->filter('li'); + $this->assertEquals(8, count($nodes)); + $this->assertEquals('A query using simple API access', $nodes->first()->text()); + } +} \ No newline at end of file diff --git a/tests/examples/largeFileUploadTest.php b/tests/examples/largeFileUploadTest.php new file mode 100644 index 000000000..c34861ef4 --- /dev/null +++ b/tests/examples/largeFileUploadTest.php @@ -0,0 +1,32 @@ +loadExample('large-file-upload.php'); + + $nodes = $crawler->filter('h1'); + $this->assertEquals(1, count($nodes)); + $this->assertEquals('File Upload - Uploading a large file', $nodes->first()->text()); + } +} \ No newline at end of file diff --git a/tests/examples/multiApiTest.php b/tests/examples/multiApiTest.php new file mode 100644 index 000000000..47d2b178b --- /dev/null +++ b/tests/examples/multiApiTest.php @@ -0,0 +1,34 @@ +checkKey(); + + $crawler = $this->loadExample('multi-api.php'); + + $nodes = $crawler->filter('h1'); + $this->assertEquals(1, count($nodes)); + $this->assertEquals('User Query - Multiple APIs', $nodes->first()->text()); + } +} \ No newline at end of file diff --git a/tests/examples/serviceAccountTest.php b/tests/examples/serviceAccountTest.php new file mode 100644 index 000000000..3bef7133d --- /dev/null +++ b/tests/examples/serviceAccountTest.php @@ -0,0 +1,34 @@ +checkServiceAccountCredentials(); + + $crawler = $this->loadExample('service-account.php'); + + $nodes = $crawler->filter('br'); + $this->assertEquals(10, count($nodes)); + $this->assertContains('The Life of Henry David Thoreau', $crawler->text()); + } +} \ No newline at end of file diff --git a/tests/examples/simpleFileUploadTest.php b/tests/examples/simpleFileUploadTest.php new file mode 100644 index 000000000..3d055edda --- /dev/null +++ b/tests/examples/simpleFileUploadTest.php @@ -0,0 +1,32 @@ +loadExample('simple-file-upload.php'); + + $nodes = $crawler->filter('h1'); + $this->assertEquals(1, count($nodes)); + $this->assertEquals('File Upload - Uploading a simple file', $nodes->first()->text()); + } +} \ No newline at end of file diff --git a/tests/examples/simpleQueryTest.php b/tests/examples/simpleQueryTest.php new file mode 100644 index 000000000..ad0f3b34e --- /dev/null +++ b/tests/examples/simpleQueryTest.php @@ -0,0 +1,37 @@ +checkKey(); + + $crawler = $this->loadExample('simple-query.php'); + + $nodes = $crawler->filter('br'); + $this->assertEquals(20, count($nodes)); + + $nodes = $crawler->filter('h1'); + $this->assertEquals(1, count($nodes)); + $this->assertEquals('Simple API Access', $nodes->first()->text()); + } +} \ No newline at end of file diff --git a/tests/examples/urlShortenerTest.php b/tests/examples/urlShortenerTest.php new file mode 100644 index 000000000..ea9d60c29 --- /dev/null +++ b/tests/examples/urlShortenerTest.php @@ -0,0 +1,34 @@ +checkKey(); + + $crawler = $this->loadExample('url-shortener.php'); + + $nodes = $crawler->filter('h1'); + $this->assertEquals(1, count($nodes)); + $this->assertEquals('User Query - URL Shortener', $nodes->first()->text()); + } +} \ No newline at end of file