├── .coveralls.yml ├── .gitignore ├── .scrutinizer.yml ├── .travis.yml ├── LICENSE ├── README.md ├── README_CN.md ├── composer.json ├── docs └── .gitignore ├── examples ├── .gitignore ├── access.php ├── config.php ├── css │ ├── main.css │ └── normalize.css ├── index.php ├── request.php └── service.php ├── makefile ├── phpdoc.xml ├── phpunit.xml.dist ├── src └── EvaOAuth │ ├── AdapterTrait.php │ ├── AuthorizedHttpClient.php │ ├── Events │ ├── BeforeAuthorize.php │ ├── BeforeGetAccessToken.php │ ├── BeforeGetRequestToken.php │ ├── EventsManager.php │ ├── Formatter.php │ └── LogSubscriber.php │ ├── Exception │ ├── BadMethodCallException.php │ ├── ExceptionInterface.php │ ├── InvalidArgumentException.php │ ├── RequestException.php │ └── VerifyException.php │ ├── HttpClient.php │ ├── OAuth1 │ ├── Consumer.php │ ├── Providers │ │ ├── AbstractProvider.php │ │ ├── Flickr.php │ │ └── Twitter.php │ ├── ServiceProviderInterface.php │ ├── Signature │ │ ├── Hmac.php │ │ ├── PlainText.php │ │ └── SignatureInterface.php │ └── Token │ │ ├── AccessToken.php │ │ ├── AccessTokenInterface.php │ │ ├── RequestToken.php │ │ └── RequestTokenInterface.php │ ├── OAuth2 │ ├── AuthorizationServerInterface.php │ ├── Client.php │ ├── GrantStrategy │ │ ├── AuthorizationCode.php │ │ └── GrantStrategyInterface.php │ ├── Providers │ │ ├── AbstractProvider.php │ │ ├── Douban.php │ │ ├── Facebook.php │ │ ├── Hundsun.php │ │ ├── Tencent.php │ │ └── Weibo.php │ ├── ResourceServerInterface.php │ └── Token │ │ ├── AccessToken.php │ │ └── AccessTokenInterface.php │ ├── Service.php │ ├── Token │ ├── AccessTokenInterface.php │ └── TokenTrait.php │ ├── User │ ├── StandardUser.php │ ├── UserInterface.php │ └── UserProviderInterface.php │ └── Utils │ ├── ResponseParser.php │ └── Text.php ├── tests ├── Bootstrap.php ├── EvaOAuthTest │ ├── AuthorizedHttpClientTest.php │ ├── Events │ │ ├── FormatterTest.php │ │ └── LogSubscriberTest.php │ ├── OAuth1 │ │ ├── ConsumerTest.php │ │ ├── Signature │ │ │ ├── HmacTest.php │ │ │ └── PlainTextTest.php │ │ └── Token │ │ │ ├── AccessTokenTest.php │ │ │ └── RequestTokenTest.php │ ├── OAuth2 │ │ ├── ClientTest.php │ │ ├── GrantStrategy │ │ │ └── AuthorizationCodeTest.php │ │ └── Token │ │ │ └── AccessTokenTest.php │ ├── ServiceTest.php │ ├── User │ │ └── UserTest.php │ └── Utils │ │ ├── ResponseParserTest.php │ │ └── TextTest.php └── report │ └── .gitignore └── tmp └── .gitignore /.coveralls.yml: -------------------------------------------------------------------------------- 1 | src_dir: . 2 | coverage_clover: ./tmp/clover.xml 3 | json_path: ./tmp/coveralls.json 4 | exclude_no_stmt: true 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | composer.lock 2 | vendor/* 3 | config.local.php 4 | config/access_token* 5 | tests/report/* 6 | .idea 7 | -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | checks: 2 | php: true 3 | 4 | filter: 5 | excluded_paths: 6 | - tests/* 7 | - examples/* 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.4 5 | - 5.5 6 | - 5.6 7 | - 7.0 8 | 9 | matrix: 10 | fast_finish: true 11 | allow_failures: 12 | - php: 7.0 13 | 14 | before_script: 15 | - composer self-update 16 | - composer install --dev --prefer-source 17 | 18 | script: 19 | phpunit -v 20 | 21 | after_script: 22 | - ./vendor/bin/coveralls -v 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, AlloVince 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, this 11 | list of conditions and the following disclaimer in the documentation and/or 12 | other materials provided with the distribution. 13 | 14 | * Neither the name of the {organization} nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 22 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 25 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | EvaOAuth 2 | ========= 3 | 4 | [![Latest Stable Version](https://poser.pugx.org/evaengine/eva-oauth/v/stable.svg)](https://packagist.org/packages/evaengine/eva-oauth) 5 | [![License](https://poser.pugx.org/evaengine/eva-oauth/license.svg)](https://packagist.org/packages/evaengine/eva-oauth) 6 | [![Build Status](https://travis-ci.org/AlloVince/EvaOAuth.svg?branch=feature%2Frefactoring)](https://travis-ci.org/AlloVince/EvaOAuth) 7 | [![Coverage Status](https://coveralls.io/repos/AlloVince/EvaOAuth/badge.svg?branch=master)](https://coveralls.io/r/AlloVince/EvaOAuth?branch=master) 8 | [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/AlloVince/EvaOAuth/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/AlloVince/EvaOAuth/?branch=master) 9 | 10 | EvaOAuth provides a standard interface for OAuth1.0 / OAuth2.0 client authorization, it is easy to integrate with any PHP project by very few lines code. 11 | 12 | [中文文档](http://avnpc.com/pages/evaoauth) 13 | 14 | ## Features 15 | 16 | - **Standard interface**, same code for both OAuth1.0 and OAuth2.0 different workflow, receiving token and user info as same format either. 17 | - **Fully tested** 18 | - **Easy to debug**, enable debug mode will record every request and response, help you find out problems quickly. 19 | - **Out-of-the-box**, already supported most popular websites including Facebook. Twitter, etc. 20 | - **Scalable**, integrate a new oauth website just need 3 lines code. 21 | 22 | ## Quick Start 23 | 24 | EvaOAuth can be found on [Packagist](https://packagist.org/packages/evaengine/eva-oauth). The recommended way to install this is through composer. 25 | 26 | Edit your composer.json and add: 27 | 28 | ``` json 29 | { 30 | "require": { 31 | "evaengine/eva-oauth": "~1.0" 32 | } 33 | } 34 | ``` 35 | 36 | And install dependencies: 37 | 38 | ``` shell 39 | curl -sS https://getcomposer.org/installer | php 40 | php composer.phar install 41 | ``` 42 | 43 | Let's start a example of Facebook Login, if you have already have a Facebook developer account and created an app, prepare a request.php as below: 44 | 45 | ``` php 46 | $service = new Eva\EvaOAuth\Service('Facebook', [ 47 | 'key' => 'You Facebook App ID', 48 | 'secret' => 'You Facebook App Secret', 49 | 'callback' => 'http://localhost/EvaOAuth/example/access.php' 50 | ]); 51 | $service->requestAuthorize(); 52 | ``` 53 | 54 | Run request.php in browser, will be redirected to Facebook authorization page. After user confirm authorization, prepare the access.php for callback: 55 | 56 | ``` php 57 | $token = $service->getAccessToken(); 58 | ``` 59 | 60 | Once access token received, we could use access token to visit any protected resources. 61 | 62 | ``` php 63 | $httpClient = new Eva\EvaOAuth\AuthorizedHttpClient($token); 64 | $response = $httpClient->get('https://graph.facebook.com/me'); 65 | ``` 66 | 67 | That's it, more usages please check [examples](https://github.com/AlloVince/EvaOAuth/tree/master/examples) and [wiki](https://github.com/AlloVince/EvaOAuth/wiki). 68 | 69 | ## Providers 70 | 71 | EvaOAuth supports most popular OAuth services as below: 72 | 73 | - OAuth2.0 74 | - Douban 75 | - Facebook 76 | - Tencent 77 | - Weibo 78 | - OAuth1.0 79 | - Twitter 80 | 81 | Creating a custom provider require only few lines code, for OAuth2 sites: 82 | 83 | 84 | ``` php 85 | namespace YourNamespace; 86 | 87 | class Foursquare extends \Eva\EvaOAuth\OAuth2\Providers\AbstractProvider 88 | { 89 | protected $authorizeUrl = 'https://foursquare.com/oauth2/authorize'; 90 | protected $accessTokenUrl = 'https://foursquare.com/oauth2/access_token'; 91 | } 92 | ``` 93 | 94 | Then register to service and create instance: 95 | 96 | ``` php 97 | use Eva\EvaOAuth\Service; 98 | Service::registerProvider('foursquare', 'YourNamespace\Foursquare'); 99 | $service = new Service('foursquare', [ 100 | 'key' => 'Foursquare App ID', 101 | 'secret' => 'Foursquare App Secret', 102 | 'callback' => 'http://somecallback/' 103 | ]); 104 | ``` 105 | 106 | ## Storage 107 | 108 | In OAuth1.0 workflow, we need to store request token somewhere, and use request token exchange for access token. 109 | 110 | EvaOAuth use [Doctrine\Cache](https://github.com/doctrine/cache) as storage layer. If no configuration, default storage layer use file system to save data, default path is EvaOAuth/tmp. 111 | 112 | Feel free to change file storage path before `Service` start: 113 | 114 | ``` php 115 | Service::setStorage(new Doctrine\Common\Cache\FilesystemCache('/tmp')); 116 | ``` 117 | 118 | Or use other storage such as Memcache: 119 | 120 | ``` php 121 | $storage = new \Doctrine\Common\Cache\MemcacheCache(); 122 | $storage->setMemcache(new \Memcache()); 123 | Service::setStorage($storage); 124 | ``` 125 | 126 | ## Events Support 127 | 128 | EvaOAuth defined some events for easier injection which are: 129 | 130 | - BeforeGetRequestToken: Triggered before get request token. 131 | - BeforeAuthorize: Triggered before redirect to authorize page. 132 | - BeforeGetAccessToken: Triggered before get access token. 133 | 134 | For example, if we want to send an additional header before get access token: 135 | 136 | ``` php 137 | $service->getEmitter()->on('beforeGetAccessToken', function(\Eva\EvaOAuth\Events\BeforeGetAccessToken $event) { 138 | $event->getRequest()->addHeader('foo', 'bar'); 139 | }); 140 | ``` 141 | 142 | ## Implementation Specification 143 | 144 | EvaOAuth based on amazing http client library [Guzzle](https://github.com/guzzle/guzzle), use fully OOP to describe OAuth specification. 145 | 146 | Refer wiki for details: 147 | 148 | - [OAuth1.0](https://github.com/AlloVince/EvaOAuth/wiki/OAuth1.0-Specification-Implementation) 149 | - [OAuth2.0](https://github.com/AlloVince/EvaOAuth/wiki/OAuth2.0-Specification-Implementation) 150 | 151 | ## Debug and Logging 152 | 153 | Enable debug mode will log all requests & responses. 154 | 155 | ``` php 156 | $service->debug('/tmp/access.log'); 157 | ``` 158 | 159 | Make sure PHP script have permission to write log path. 160 | 161 | 162 | ## API References 163 | 164 | Run `phpdoc` will generate API references under `docs/`. 165 | 166 | ![](https://avnpc.com/static/images/telegram.png) 167 | 168 | [Join My Telegram Group](https://t.me/joinchat/HKvcQAw2kqASoYfxiSrIbA) 169 | -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 | EvaOAuth 2 | ========= 3 | 4 | [![Latest Stable Version](https://poser.pugx.org/evaengine/eva-oauth/v/stable.svg)](https://packagist.org/packages/evaengine/eva-oauth) 5 | [![License](https://poser.pugx.org/evaengine/eva-oauth/license.svg)](https://packagist.org/packages/evaengine/eva-oauth) 6 | [![Build Status](https://travis-ci.org/AlloVince/EvaOAuth.svg?branch=feature%2Frefactoring)](https://travis-ci.org/AlloVince/EvaOAuth) 7 | [![Coverage Status](https://coveralls.io/repos/AlloVince/EvaOAuth/badge.svg?branch=master)](https://coveralls.io/r/AlloVince/EvaOAuth?branch=master) 8 | [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/AlloVince/EvaOAuth/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/AlloVince/EvaOAuth/?branch=master) 9 | 10 | EvaOAuth 是一个统一接口设计的[PHP OAuth](http://avnpc.com/pages/evaoauth) Client库,兼容OAuth1.0与OAuth2.0规范,可以通过10多行代码集成到任意项目中。 11 | 12 | 项目代码托管在 [https://github.com/AlloVince/EvaOAuth](https://github.com/AlloVince/EvaOAuth) ,欢迎Star及Fork贡献代码。 13 | 14 | ## 为什么选择EvaOAuth 15 | 16 | 经过若干项目考验, EvaOAuth1.0 根据实际需求进行了一次完全重构,主要的一些特性如下: 17 | 18 | - **标准接口**,无论OAuth1.0或OAuth2.0,同一套代码实现不同工作流,并且获取一致的数据格式,包括用户信息和Token。 19 | - **充分测试**,所有关键代码进行单元测试,同时通过CI保证多版本PHP下的可用性。 20 | - **容易调试**,开启Debug模式后,Log中会记录OAuth流程中所有的URL、Request、Response,帮助定位问题。 21 | - **开箱即用**,项目已经内置了主流的OAuth网址支持,如微博、QQ、Twitter、Facebook等。 22 | - **方便扩展**,可以通过最少3行代码集成新的OAuth服务,工作流程提供事件机制。 23 | 24 | ## 快速开始 25 | 26 | EvaOAuth可以通过[Packagist](https://packagist.org/packages/evaengine/eva-oauth)下载,推荐通过Composer安装。 27 | 28 | 编辑composer.json文件为: 29 | 30 | ``` json 31 | { 32 | "require": { 33 | "evaengine/eva-oauth": "~1.0" 34 | } 35 | } 36 | ``` 37 | 38 | 然后通过Composer进行安装。 39 | 40 | ``` shell 41 | curl -sS https://getcomposer.org/installer | php 42 | php composer.phar install 43 | ``` 44 | 45 | 下面通过一个实例演示如何集成豆瓣登录功能。假设已经在[豆瓣开发者](http://developers.douban.com)创建好一个应用。准备一个request.php如下: 46 | 47 | ``` php 48 | require_once './vendor/autoload.php'; //加载Composer自动生成的autoload 49 | $service = new Eva\EvaOAuth\Service('Douban', [ 50 | 'key' => 'You Douban App ID', //对应豆瓣应用的API Key 51 | 'secret' => 'You Douban App Secret', //对应豆瓣应用的Secret 52 | 'callback' => 'http://localhost/EvaOAuth/example/access.php' //回调地址 53 | ]); 54 | $service->requestAuthorize(); 55 | ``` 56 | 57 | 在浏览器中运行request.php,如果参数正确则会被重定向到豆瓣授权页面,登录授权后会再次重定向回我们设置的`callback`。因此再准备好access.php文件: 58 | 59 | ``` php 60 | $token = $service->getAccessToken(); 61 | ``` 62 | 63 | 这样就拿到了豆瓣的Access Token,接下来可以使用Token去访问受保护的资源: 64 | 65 | ``` php 66 | $httpClient = new Eva\EvaOAuth\AuthorizedHttpClient($token); 67 | $response = $httpClient->get('https://api.douban.com/v2/user/~me'); 68 | ``` 69 | 70 | 这样就完成了OAuth的登录功能。更多细节可以参考代码的[示例](https://github.com/AlloVince/EvaOAuth/tree/master/examples)以及[Wiki](https://github.com/AlloVince/EvaOAuth/wiki)页面。 71 | 72 | ## OAuth网站支持 73 | 74 | EvaOAuth将一个OAuth网站称为一个Provider。目前支持的Provider有: 75 | 76 | - OAuth2.0 77 | - 豆瓣(Douban) 78 | - Facebook 79 | - QQ (Tencent) 80 | - 微博 (Weibo) 81 | - OAuth1.0 82 | - Twitter 83 | 84 | 新增一个Provider仅需数行代码,下面演示如何集成Foursquare网站: 85 | 86 | 87 | ``` php 88 | namespace YourNamespace; 89 | 90 | class Foursquare extends \Eva\EvaOAuth\OAuth2\Providers\AbstractProvider 91 | { 92 | protected $authorizeUrl = 'https://foursquare.com/oauth2/authorize'; 93 | protected $accessTokenUrl = 'https://foursquare.com/oauth2/access_token'; 94 | } 95 | ``` 96 | 97 | 然后将Provider注册到EvaOAuth就可以使用了。 98 | 99 | ``` php 100 | use Eva\EvaOAuth\Service; 101 | Service::registerProvider('foursquare', 'YourNamespace\Foursquare'); 102 | $service = new Service('foursquare', [ 103 | 'key' => 'Foursquare App ID', 104 | 'secret' => 'Foursquare App Secret', 105 | 'callback' => 'http://somecallback/' 106 | ]); 107 | ``` 108 | 109 | ## 数据存储 110 | 111 | 在OAuth1.0的流程中,需要将Request Token保存起来,然后在授权成功后使用Request Token换取Access Token。因此需要数据存储功能。 112 | 113 | EvaOAuth的数据存储通过[Doctrine\Cache](https://github.com/doctrine/cache)实现。默认情况下EvaOAuth会将数据保存为本地文件,保存路径为`EvaOAuth/tmp`。 114 | 115 | 可以在EvaOAuth初始化前任意更改存储方式及存储位置,例如将文件保存位置更改为`/tmp`: 116 | 117 | ``` php 118 | Service::setStorage(new Doctrine\Common\Cache\FilesystemCache('/tmp')); 119 | ``` 120 | 121 | 或者使用Memcache保存: 122 | 123 | ``` php 124 | $storage = new \Doctrine\Common\Cache\MemcacheCache(); 125 | $storage->setMemcache(new \Memcache()); 126 | Service::setStorage($storage); 127 | ``` 128 | 129 | ## 事件支持 130 | 131 | EvaOAuth 定义了若干事件方面更容易的注入逻辑 132 | 133 | - `BeforeGetRequestToken`: 获取Request Token前触发。 134 | - `BeforeAuthorize`: 重定向到授权页面前触发。 135 | - `BeforeGetAccessToken`: 获取Access Token前触发。 136 | 137 | 比如我们希望在获取Access Token前向HTTP请求中加一个自定义Header,可以通过以下方式实现: 138 | 139 | ``` php 140 | $service->getEmitter()->on('beforeGetAccessToken', function(\Eva\EvaOAuth\Events\BeforeGetAccessToken $event) { 141 | $event->getRequest()->addHeader('foo', 'bar'); 142 | }); 143 | ``` 144 | 145 | ## 技术实现 146 | 147 | EvaOAuth 基于强大的HTTP客户端库[Guzzle](https://github.com/guzzle/guzzle),并通过OOP方式对OAuth规范进行了完整的描述。 148 | 149 | 为了避免对规范的诠释上出现误差,底层代码优先选择规范描述中的角色与名词,规范间差异则在上层代码中统一。 150 | 151 | 因此如果没有同时支持两套规范的需求,可以直接使用OAuth1.0、OAuth2.0分别对应的工作流。 152 | 153 | 详细用例可以参考Wiki: 154 | 155 | - [OAuth1.0](https://github.com/AlloVince/EvaOAuth/wiki/OAuth1.0-Specification-Implementation) 156 | - [OAuth2.0](https://github.com/AlloVince/EvaOAuth/wiki/OAuth2.0-Specification-Implementation) 157 | 158 | ## Debug与Log 159 | 160 | 开启Debug模式将在Log中记录所有的请求与响应。 161 | 162 | ``` php 163 | $service->debug('/tmp/access.log'); 164 | ``` 165 | 166 | 请确保PHP对log文件有写入权限。 167 | 168 | ## API文档 169 | 170 | 首先通过`pear install phpdoc/phpDocumentor`安装phpDocumentor,然后在项目根目录下运行`phpdoc`,会在`docs/`下生成API文档。 171 | 172 | ## 问题反馈及贡献代码 173 | 174 | 项目代码托管在 [https://github.com/AlloVince/EvaOAuth](https://github.com/AlloVince/EvaOAuth]) ,欢迎Star及Fork贡献代码。 175 | 176 | 有问题欢迎在[EvaOAuth Issue](https://github.com/AlloVince/EvaOAuth/issues)提出。 177 | 178 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "evaengine/eva-oauth", 3 | "description": "EvaOAuth is an abstract interface to setup OAuth client, both support OAuth1.0a / OAuth2.", 4 | "license": "BSD-3-Clause", 5 | "homepage": "http://avnpc.com/", 6 | "authors": [ 7 | { 8 | "name": "AlloVince", 9 | "email": "allo.vince@gmail.com", 10 | "homepage": "http://avnpc.com" 11 | } 12 | ], 13 | "require": { 14 | "php": ">=5.4", 15 | "guzzlehttp/guzzle": "~5.2", 16 | "doctrine/cache": "~1.4", 17 | "monolog/monolog": "~1.13" 18 | }, 19 | "require-dev": { 20 | "mockery/mockery": "dev-master", 21 | "satooshi/php-coveralls": "dev-master" 22 | }, 23 | "autoload": { 24 | "psr-4": { 25 | "Eva\\EvaOAuth\\": "src/EvaOAuth/" 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /examples/.gitignore: -------------------------------------------------------------------------------- 1 | oauth1/* 2 | config.local.php 3 | -------------------------------------------------------------------------------- /examples/access.php: -------------------------------------------------------------------------------- 1 | '; 5 | $token = $service->getAccessToken(); 6 | var_dump($token); 7 | 8 | $httpClient = new \Eva\EvaOAuth\AuthorizedHttpClient($token); 9 | $response = $httpClient->get('https://graph.facebook.com/me'); 10 | echo $response; 11 | -------------------------------------------------------------------------------- /examples/config.php: -------------------------------------------------------------------------------- 1 | [ 5 | 'key' => '', 6 | 'secret' => '', 7 | ], 8 | 'flickr' => [ 9 | 'key' => '', 10 | 'secret' => '', 11 | ], 12 | 'facebook' => [ 13 | 'key' => '', 14 | 'secret' => '', 15 | ], 16 | 'tencent' => [ 17 | 'key' => '', 18 | 'secret' => '', 19 | ], 20 | 'weibo' => [ 21 | 'key' => '', 22 | 'secret' => '', 23 | ], 24 | 'hundsun' => [ 25 | 'key' => '', 26 | 'secret' => '' 27 | ], 28 | 'douban' => [ 29 | 'key' => '', 30 | 'secret' => '' 31 | ] 32 | ]; 33 | -------------------------------------------------------------------------------- /examples/css/main.css: -------------------------------------------------------------------------------- 1 | /*! HTML5 Boilerplate v5.1.0 | MIT License | https://html5boilerplate.com/ */ 2 | 3 | /* 4 | * What follows is the result of much research on cross-browser styling. 5 | * Credit left inline and big thanks to Nicolas Gallagher, Jonathan Neal, 6 | * Kroc Camen, and the H5BP dev community and team. 7 | */ 8 | 9 | /* ========================================================================== 10 | Base styles: opinionated defaults 11 | ========================================================================== */ 12 | 13 | html { 14 | color: #222; 15 | font-size: 1em; 16 | line-height: 1.4; 17 | } 18 | 19 | /* 20 | * Remove text-shadow in selection highlight: 21 | * https://twitter.com/miketaylr/status/12228805301 22 | * 23 | * These selection rule sets have to be separate. 24 | * Customize the background color to match your design. 25 | */ 26 | 27 | ::-moz-selection { 28 | background: #b3d4fc; 29 | text-shadow: none; 30 | } 31 | 32 | ::selection { 33 | background: #b3d4fc; 34 | text-shadow: none; 35 | } 36 | 37 | /* 38 | * A better looking default horizontal rule 39 | */ 40 | 41 | hr { 42 | display: block; 43 | height: 1px; 44 | border: 0; 45 | border-top: 1px solid #ccc; 46 | margin: 1em 0; 47 | padding: 0; 48 | } 49 | 50 | /* 51 | * Remove the gap between audio, canvas, iframes, 52 | * images, videos and the bottom of their containers: 53 | * https://github.com/h5bp/html5-boilerplate/issues/440 54 | */ 55 | 56 | audio, 57 | canvas, 58 | iframe, 59 | img, 60 | svg, 61 | video { 62 | vertical-align: middle; 63 | } 64 | 65 | /* 66 | * Remove default fieldset styles. 67 | */ 68 | 69 | fieldset { 70 | border: 0; 71 | margin: 0; 72 | padding: 0; 73 | } 74 | 75 | /* 76 | * Allow only vertical resizing of textareas. 77 | */ 78 | 79 | textarea { 80 | resize: vertical; 81 | } 82 | 83 | /* ========================================================================== 84 | Browser Upgrade Prompt 85 | ========================================================================== */ 86 | 87 | .browserupgrade { 88 | margin: 0.2em 0; 89 | background: #ccc; 90 | color: #000; 91 | padding: 0.2em 0; 92 | } 93 | 94 | /* ========================================================================== 95 | Author's custom styles 96 | ========================================================================== */ 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | /* ========================================================================== 115 | Helper classes 116 | ========================================================================== */ 117 | 118 | /* 119 | * Hide visually and from screen readers: 120 | */ 121 | 122 | .hidden { 123 | display: none !important; 124 | } 125 | 126 | /* 127 | * Hide only visually, but have it available for screen readers: 128 | * http://snook.ca/archives/html_and_css/hiding-content-for-accessibility 129 | */ 130 | 131 | .visuallyhidden { 132 | border: 0; 133 | clip: rect(0 0 0 0); 134 | height: 1px; 135 | margin: -1px; 136 | overflow: hidden; 137 | padding: 0; 138 | position: absolute; 139 | width: 1px; 140 | } 141 | 142 | /* 143 | * Extends the .visuallyhidden class to allow the element 144 | * to be focusable when navigated to via the keyboard: 145 | * https://www.drupal.org/node/897638 146 | */ 147 | 148 | .visuallyhidden.focusable:active, 149 | .visuallyhidden.focusable:focus { 150 | clip: auto; 151 | height: auto; 152 | margin: 0; 153 | overflow: visible; 154 | position: static; 155 | width: auto; 156 | } 157 | 158 | /* 159 | * Hide visually and from screen readers, but maintain layout 160 | */ 161 | 162 | .invisible { 163 | visibility: hidden; 164 | } 165 | 166 | /* 167 | * Clearfix: contain floats 168 | * 169 | * For modern browsers 170 | * 1. The space content is one way to avoid an Opera bug when the 171 | * `contenteditable` attribute is included anywhere else in the document. 172 | * Otherwise it causes space to appear at the top and bottom of elements 173 | * that receive the `clearfix` class. 174 | * 2. The use of `table` rather than `block` is only necessary if using 175 | * `:before` to contain the top-margins of child elements. 176 | */ 177 | 178 | .clearfix:before, 179 | .clearfix:after { 180 | content: " "; /* 1 */ 181 | display: table; /* 2 */ 182 | } 183 | 184 | .clearfix:after { 185 | clear: both; 186 | } 187 | 188 | /* ========================================================================== 189 | EXAMPLE Media Queries for Responsive Design. 190 | These examples override the primary ('mobile first') styles. 191 | Modify as content requires. 192 | ========================================================================== */ 193 | 194 | @media only screen and (min-width: 35em) { 195 | /* Style adjustments for viewports that meet the condition */ 196 | } 197 | 198 | @media print, 199 | (-webkit-min-device-pixel-ratio: 1.25), 200 | (min-resolution: 1.25dppx), 201 | (min-resolution: 120dpi) { 202 | /* Style adjustments for high resolution devices */ 203 | } 204 | 205 | /* ========================================================================== 206 | Print styles. 207 | Inlined to avoid the additional HTTP request: 208 | http://www.phpied.com/delay-loading-your-print-css/ 209 | ========================================================================== */ 210 | 211 | @media print { 212 | *, 213 | *:before, 214 | *:after { 215 | background: transparent !important; 216 | color: #000 !important; /* Black prints faster: 217 | http://www.sanbeiji.com/archives/953 */ 218 | box-shadow: none !important; 219 | text-shadow: none !important; 220 | } 221 | 222 | a, 223 | a:visited { 224 | text-decoration: underline; 225 | } 226 | 227 | a[href]:after { 228 | content: " (" attr(href) ")"; 229 | } 230 | 231 | abbr[title]:after { 232 | content: " (" attr(title) ")"; 233 | } 234 | 235 | /* 236 | * Don't show links that are fragment identifiers, 237 | * or use the `javascript:` pseudo protocol 238 | */ 239 | 240 | a[href^="#"]:after, 241 | a[href^="javascript:"]:after { 242 | content: ""; 243 | } 244 | 245 | pre, 246 | blockquote { 247 | border: 1px solid #999; 248 | page-break-inside: avoid; 249 | } 250 | 251 | /* 252 | * Printing Tables: 253 | * http://css-discuss.incutio.com/wiki/Printing_Tables 254 | */ 255 | 256 | thead { 257 | display: table-header-group; 258 | } 259 | 260 | tr, 261 | img { 262 | page-break-inside: avoid; 263 | } 264 | 265 | img { 266 | max-width: 100% !important; 267 | } 268 | 269 | p, 270 | h2, 271 | h3 { 272 | orphans: 3; 273 | widows: 3; 274 | } 275 | 276 | h2, 277 | h3 { 278 | page-break-after: avoid; 279 | } 280 | } 281 | -------------------------------------------------------------------------------- /examples/css/normalize.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ 2 | 3 | /** 4 | * 1. Set default font family to sans-serif. 5 | * 2. Prevent iOS and IE text size adjust after device orientation change, 6 | * without disabling user zoom. 7 | */ 8 | 9 | html { 10 | font-family: sans-serif; /* 1 */ 11 | -ms-text-size-adjust: 100%; /* 2 */ 12 | -webkit-text-size-adjust: 100%; /* 2 */ 13 | } 14 | 15 | /** 16 | * Remove default margin. 17 | */ 18 | 19 | body { 20 | margin: 0; 21 | } 22 | 23 | /* HTML5 display definitions 24 | ========================================================================== */ 25 | 26 | /** 27 | * Correct `block` display not defined for any HTML5 element in IE 8/9. 28 | * Correct `block` display not defined for `details` or `summary` in IE 10/11 29 | * and Firefox. 30 | * Correct `block` display not defined for `main` in IE 11. 31 | */ 32 | 33 | article, 34 | aside, 35 | details, 36 | figcaption, 37 | figure, 38 | footer, 39 | header, 40 | hgroup, 41 | main, 42 | menu, 43 | nav, 44 | section, 45 | summary { 46 | display: block; 47 | } 48 | 49 | /** 50 | * 1. Correct `inline-block` display not defined in IE 8/9. 51 | * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. 52 | */ 53 | 54 | audio, 55 | canvas, 56 | progress, 57 | video { 58 | display: inline-block; /* 1 */ 59 | vertical-align: baseline; /* 2 */ 60 | } 61 | 62 | /** 63 | * Prevent modern browsers from displaying `audio` without controls. 64 | * Remove excess height in iOS 5 devices. 65 | */ 66 | 67 | audio:not([controls]) { 68 | display: none; 69 | height: 0; 70 | } 71 | 72 | /** 73 | * Address `[hidden]` styling not present in IE 8/9/10. 74 | * Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22. 75 | */ 76 | 77 | [hidden], 78 | template { 79 | display: none; 80 | } 81 | 82 | /* Links 83 | ========================================================================== */ 84 | 85 | /** 86 | * Remove the gray background color from active links in IE 10. 87 | */ 88 | 89 | a { 90 | background-color: transparent; 91 | } 92 | 93 | /** 94 | * Improve readability of focused elements when they are also in an 95 | * active/hover state. 96 | */ 97 | 98 | a:active, 99 | a:hover { 100 | outline: 0; 101 | } 102 | 103 | /* Text-level semantics 104 | ========================================================================== */ 105 | 106 | /** 107 | * Address styling not present in IE 8/9/10/11, Safari, and Chrome. 108 | */ 109 | 110 | abbr[title] { 111 | border-bottom: 1px dotted; 112 | } 113 | 114 | /** 115 | * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. 116 | */ 117 | 118 | b, 119 | strong { 120 | font-weight: bold; 121 | } 122 | 123 | /** 124 | * Address styling not present in Safari and Chrome. 125 | */ 126 | 127 | dfn { 128 | font-style: italic; 129 | } 130 | 131 | /** 132 | * Address variable `h1` font-size and margin within `section` and `article` 133 | * contexts in Firefox 4+, Safari, and Chrome. 134 | */ 135 | 136 | h1 { 137 | font-size: 2em; 138 | margin: 0.67em 0; 139 | } 140 | 141 | /** 142 | * Address styling not present in IE 8/9. 143 | */ 144 | 145 | mark { 146 | background: #ff0; 147 | color: #000; 148 | } 149 | 150 | /** 151 | * Address inconsistent and variable font size in all browsers. 152 | */ 153 | 154 | small { 155 | font-size: 80%; 156 | } 157 | 158 | /** 159 | * Prevent `sub` and `sup` affecting `line-height` in all browsers. 160 | */ 161 | 162 | sub, 163 | sup { 164 | font-size: 75%; 165 | line-height: 0; 166 | position: relative; 167 | vertical-align: baseline; 168 | } 169 | 170 | sup { 171 | top: -0.5em; 172 | } 173 | 174 | sub { 175 | bottom: -0.25em; 176 | } 177 | 178 | /* Embedded content 179 | ========================================================================== */ 180 | 181 | /** 182 | * Remove border when inside `a` element in IE 8/9/10. 183 | */ 184 | 185 | img { 186 | border: 0; 187 | } 188 | 189 | /** 190 | * Correct overflow not hidden in IE 9/10/11. 191 | */ 192 | 193 | svg:not(:root) { 194 | overflow: hidden; 195 | } 196 | 197 | /* Grouping content 198 | ========================================================================== */ 199 | 200 | /** 201 | * Address margin not present in IE 8/9 and Safari. 202 | */ 203 | 204 | figure { 205 | margin: 1em 40px; 206 | } 207 | 208 | /** 209 | * Address differences between Firefox and other browsers. 210 | */ 211 | 212 | hr { 213 | box-sizing: content-box; 214 | height: 0; 215 | } 216 | 217 | /** 218 | * Contain overflow in all browsers. 219 | */ 220 | 221 | pre { 222 | overflow: auto; 223 | } 224 | 225 | /** 226 | * Address odd `em`-unit font size rendering in all browsers. 227 | */ 228 | 229 | code, 230 | kbd, 231 | pre, 232 | samp { 233 | font-family: monospace, monospace; 234 | font-size: 1em; 235 | } 236 | 237 | /* Forms 238 | ========================================================================== */ 239 | 240 | /** 241 | * Known limitation: by default, Chrome and Safari on OS X allow very limited 242 | * styling of `select`, unless a `border` property is set. 243 | */ 244 | 245 | /** 246 | * 1. Correct color not being inherited. 247 | * Known issue: affects color of disabled elements. 248 | * 2. Correct font properties not being inherited. 249 | * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. 250 | */ 251 | 252 | button, 253 | input, 254 | optgroup, 255 | select, 256 | textarea { 257 | color: inherit; /* 1 */ 258 | font: inherit; /* 2 */ 259 | margin: 0; /* 3 */ 260 | } 261 | 262 | /** 263 | * Address `overflow` set to `hidden` in IE 8/9/10/11. 264 | */ 265 | 266 | button { 267 | overflow: visible; 268 | } 269 | 270 | /** 271 | * Address inconsistent `text-transform` inheritance for `button` and `select`. 272 | * All other form control elements do not inherit `text-transform` values. 273 | * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. 274 | * Correct `select` style inheritance in Firefox. 275 | */ 276 | 277 | button, 278 | select { 279 | text-transform: none; 280 | } 281 | 282 | /** 283 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 284 | * and `video` controls. 285 | * 2. Correct inability to style clickable `input` types in iOS. 286 | * 3. Improve usability and consistency of cursor style between image-type 287 | * `input` and others. 288 | */ 289 | 290 | button, 291 | html input[type="button"], /* 1 */ 292 | input[type="reset"], 293 | input[type="submit"] { 294 | -webkit-appearance: button; /* 2 */ 295 | cursor: pointer; /* 3 */ 296 | } 297 | 298 | /** 299 | * Re-set default cursor for disabled elements. 300 | */ 301 | 302 | button[disabled], 303 | html input[disabled] { 304 | cursor: default; 305 | } 306 | 307 | /** 308 | * Remove inner padding and border in Firefox 4+. 309 | */ 310 | 311 | button::-moz-focus-inner, 312 | input::-moz-focus-inner { 313 | border: 0; 314 | padding: 0; 315 | } 316 | 317 | /** 318 | * Address Firefox 4+ setting `line-height` on `input` using `!important` in 319 | * the UA stylesheet. 320 | */ 321 | 322 | input { 323 | line-height: normal; 324 | } 325 | 326 | /** 327 | * It's recommended that you don't attempt to style these elements. 328 | * Firefox's implementation doesn't respect box-sizing, padding, or width. 329 | * 330 | * 1. Address box sizing set to `content-box` in IE 8/9/10. 331 | * 2. Remove excess padding in IE 8/9/10. 332 | */ 333 | 334 | input[type="checkbox"], 335 | input[type="radio"] { 336 | box-sizing: border-box; /* 1 */ 337 | padding: 0; /* 2 */ 338 | } 339 | 340 | /** 341 | * Fix the cursor style for Chrome's increment/decrement buttons. For certain 342 | * `font-size` values of the `input`, it causes the cursor style of the 343 | * decrement button to change from `default` to `text`. 344 | */ 345 | 346 | input[type="number"]::-webkit-inner-spin-button, 347 | input[type="number"]::-webkit-outer-spin-button { 348 | height: auto; 349 | } 350 | 351 | /** 352 | * 1. Address `appearance` set to `searchfield` in Safari and Chrome. 353 | * 2. Address `box-sizing` set to `border-box` in Safari and Chrome. 354 | */ 355 | 356 | input[type="search"] { 357 | -webkit-appearance: textfield; /* 1 */ 358 | box-sizing: content-box; /* 2 */ 359 | } 360 | 361 | /** 362 | * Remove inner padding and search cancel button in Safari and Chrome on OS X. 363 | * Safari (but not Chrome) clips the cancel button when the search input has 364 | * padding (and `textfield` appearance). 365 | */ 366 | 367 | input[type="search"]::-webkit-search-cancel-button, 368 | input[type="search"]::-webkit-search-decoration { 369 | -webkit-appearance: none; 370 | } 371 | 372 | /** 373 | * Define consistent border, margin, and padding. 374 | */ 375 | 376 | fieldset { 377 | border: 1px solid #c0c0c0; 378 | margin: 0 2px; 379 | padding: 0.35em 0.625em 0.75em; 380 | } 381 | 382 | /** 383 | * 1. Correct `color` not being inherited in IE 8/9/10/11. 384 | * 2. Remove padding so people aren't caught out if they zero out fieldsets. 385 | */ 386 | 387 | legend { 388 | border: 0; /* 1 */ 389 | padding: 0; /* 2 */ 390 | } 391 | 392 | /** 393 | * Remove default vertical scrollbar in IE 8/9/10/11. 394 | */ 395 | 396 | textarea { 397 | overflow: auto; 398 | } 399 | 400 | /** 401 | * Don't inherit the `font-weight` (applied by a rule above). 402 | * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. 403 | */ 404 | 405 | optgroup { 406 | font-weight: bold; 407 | } 408 | 409 | /* Tables 410 | ========================================================================== */ 411 | 412 | /** 413 | * Remove most spacing between table cells. 414 | */ 415 | 416 | table { 417 | border-collapse: collapse; 418 | border-spacing: 0; 419 | } 420 | 421 | td, 422 | th { 423 | padding: 0; 424 | } 425 | -------------------------------------------------------------------------------- /examples/index.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | EvaEngine OAuth Demo 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |

1. Copy config.php to config.local.php

19 |

2. Fill config keys and secrets

20 |

3. Click below links to start OAuth authorize

21 | 22 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /examples/request.php: -------------------------------------------------------------------------------- 1 | '; 5 | $service->requestAuthorize(); 6 | -------------------------------------------------------------------------------- /examples/service.php: -------------------------------------------------------------------------------- 1 | $config[$provider]['key'], 16 | 'secret' => $config[$provider]['secret'], 17 | 'callback' => dirname('http://' . $_SERVER['HTTP_HOST'] . $_SERVER["REQUEST_URI"]) . '/access.php?provider=' . $provider 18 | ]); 19 | 20 | $service->debug(__DIR__ . '/../tmp/access.log'); 21 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | list: 2 | @echo "fix" 3 | @echo "phpcs" 4 | @echo "test" 5 | @echo "test-report" 6 | @echo "health" 7 | 8 | phpcs: 9 | phpcs --standard=PSR2 --extensions=php --ignore=vendor/*,tests/*,cphalcon/* --warning-severity=0 ./lib 10 | 11 | fix: 12 | phpcbf --standard=PSR2 --extensions=php --ignore=vendor/*,tests/*,cphalcon/* --warning-severity=0 ./ 13 | 14 | test-report: 15 | phpunit -v --coverage-html ./tests/report/ --colors 16 | 17 | test: 18 | phpunit -v --colors 19 | 20 | health: 21 | pdepend --overview-pyramid=tests/report/output.svg src/ -------------------------------------------------------------------------------- /phpdoc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | EvaEngine 4 | 5 | tmp 6 | utf-8 7 | 8 | 9 | docs 10 | 11 | 12 | warn 13 | 14 | docs/log/{DATE}.log 15 | docs/log/{DATE}.errors.log 16 | 17 | 18 | 19 |