├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── config.yml │ └── feature_request.md ├── .gitignore ├── LICENSE ├── README.md ├── composer.json ├── phpunit.xml.dist ├── src ├── Auth.php ├── Client.php ├── HttpService.php └── Models │ └── ClaimsResponse.php └── tests └── HttpServiceTest.php /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Documentation 4 | url: https://xbl.io/getting-started 5 | about: Check the documentation before opening an issue. 6 | 7 | - name: Support 8 | url: https://discord.gg/RbhwRMZsJa 9 | about: We use GitHub issues only to discuss bugs and new features. 10 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | composer.lock 3 | phpunit.xml 4 | .phpunit.result.cache 5 | .idea 6 | .vscode 7 | .DS_Store -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-2023 OpenXBL. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenXBL PHP Wrapper 2 | This PHP package is a lightweight wrapper for OpenXBL. It's the easiest way to use OpenXBL in your PHP application. 3 | 4 | Part of the [XBL.IO](https://xbl.io) feature set. 5 | 6 | ```php 7 | get('account')); 15 | ?> 16 | ``` 17 | 18 | Quickstart 19 | ---------- 20 | 21 | This library is available through [Composer](https://getcomposer.org). 22 | 23 | Use the following command: 24 | 25 | `composer require openxbl/openxbl` 26 | 27 | Alternatively, add the repository in your **composer.json** file. If you don't already have this file create it at the root of your project with this content: 28 | 29 | ```json 30 | { 31 | "name": "Example Application", 32 | "description": "This is an example of OpenXBL", 33 | "require": { 34 | "openxbl/openxbl": "^2" 35 | } 36 | } 37 | ``` 38 | 39 | Making an App Request 40 | ---------- 41 | 42 | ```php 43 | isApp = true; 51 | 52 | print_r($client->get('account')); 53 | ?> 54 | ``` 55 | 56 | Making a Claims Request 57 | ---------- 58 | 59 | ```php 60 | claim('CODE_VALUE'); 68 | ?> 69 | ``` 70 | 71 | Optional Parameters 72 | ---------- 73 | ```php 74 | format = 'json'; 77 | 78 | // Language of response. 79 | $client->language = 'en-US,en'; 80 | ?> 81 | ``` 82 | 83 | Supported APIs 84 | ---------- 85 | This wrapper is built using **OpenXBL /api/v2/** 86 | 87 | Collaborate 88 | ---------- 89 | Visit our [discord channel](https://discord.gg/x6kk8M2) and say hello! 90 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "openxbl/openxbl", 3 | "description": "Wrapper for OpenXBL", 4 | "license": "MIT", 5 | "autoload": { 6 | "psr-4": { 7 | "OpenXBL\\": "src/" 8 | } 9 | }, 10 | "autoload-dev": { 11 | "psr-4": { 12 | "OpenXBL\\Tests\\": "tests/" 13 | } 14 | }, 15 | "require": { 16 | "php": ">=7.4", 17 | "guzzlehttp/guzzle": "^7" 18 | }, 19 | "require-dev": { 20 | "phpunit/phpunit": "^9", 21 | "mockery/mockery": "^1.5" 22 | } 23 | } -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | src 6 | 7 | 8 | 9 | 10 | tests 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/Auth.php: -------------------------------------------------------------------------------- 1 | publicKey = $publicKey; 17 | parent::__construct([ 18 | 'base_uri' => $this->baseUrl, 19 | ]); 20 | } 21 | 22 | /** 23 | * @throws GuzzleException 24 | */ 25 | public function claim(string $code): ClaimsResponse 26 | { 27 | $options = [ 28 | 'headers' => [ 29 | 'Accept' => 'application/json', 30 | ], 31 | 'json' => [ 32 | 'code' => $code, 33 | 'app_key' => $this->publicKey, 34 | ], 35 | ]; 36 | 37 | $request = $this->request('POST', 'claim', $options); 38 | 39 | return new ClaimsResponse((string) $request->getBody()); 40 | } 41 | 42 | public function getLoginUrl(): string 43 | { 44 | return "https://xbl.io/app/auth/{$this->publicKey}"; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Client.php: -------------------------------------------------------------------------------- 1 | buildClient($apiKey); 14 | parent::__construct($client); 15 | } 16 | 17 | private function buildClient(string $apiKey): GuzzleClient 18 | { 19 | return new GuzzleClient([ 20 | 'base_uri' => $this->baseUrl, 21 | 'headers' => [ 22 | 'X-Authorization' => $apiKey, 23 | ], 24 | ]); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/HttpService.php: -------------------------------------------------------------------------------- 1 | client = $client; 34 | } 35 | 36 | /** 37 | * @throws GuzzleException 38 | * @throws InvalidArgumentException 39 | */ 40 | public function __call(string $method, array $arguments): ?string 41 | { 42 | if (!isset($arguments[0])) { 43 | throw new InvalidArgumentException("Endpoint is not set."); 44 | } 45 | 46 | $this->method = $method; 47 | 48 | $this->endpoint = $arguments[0]; 49 | 50 | if(isset($arguments[1])) { 51 | $this->payload = $arguments[1]; 52 | } 53 | 54 | return $this->request(); 55 | } 56 | 57 | /** 58 | * @throws GuzzleException 59 | */ 60 | protected function request(): ?string 61 | { 62 | $options = [ 63 | 'headers' => [ 64 | 'Accept' => ($this->format == 'json') ? 'application/json' : 'application/xml', 65 | 'Accept-Language' => $this->language, 66 | 'X-Contract' => $this->isApp ? 100 : null, 67 | ], 68 | ]; 69 | 70 | if ($this->payload) { 71 | $options['json'] = $this->payload; 72 | } 73 | 74 | $request = $this->client->request($this->method, $this->endpoint, $options); 75 | 76 | return (string) $request->getBody(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/Models/ClaimsResponse.php: -------------------------------------------------------------------------------- 1 | $value) { 16 | if (property_exists(__CLASS__, $key)) { 17 | $this->$key = $value; 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/HttpServiceTest.php: -------------------------------------------------------------------------------- 1 | client = Mockery::mock(ClientInterface::class); 30 | $this->stream = Mockery::mock(StreamInterface::class); 31 | $this->response = Mockery::mock(ResponseInterface::class); 32 | } 33 | 34 | public function testGetRequestSuccess(): void 35 | { 36 | $this->client 37 | ->shouldReceive('request') 38 | ->andReturn($this->response); 39 | 40 | $this->response->shouldReceive('getBody') 41 | ->andReturn($this->stream); 42 | 43 | $this->stream->shouldReceive('getContents') 44 | ->andReturn('success'); 45 | 46 | $result = new HttpService($this->client); 47 | 48 | $this->assertEquals('success', $result->get('account')); 49 | } 50 | 51 | public function testPostRequestSuccess(): void 52 | { 53 | $this->client 54 | ->shouldReceive('request') 55 | ->andReturn($this->response); 56 | 57 | $this->response->shouldReceive('getBody') 58 | ->andReturn($this->stream); 59 | 60 | $this->stream->shouldReceive('getContents') 61 | ->andReturn('success'); 62 | 63 | $result = new HttpService($this->client); 64 | 65 | $this->assertEquals('success', $result->post('generate/gamertag', ['unit' => 'test'])); 66 | } 67 | 68 | public function testMissingEndpoint(): void 69 | { 70 | $this->expectException(InvalidArgumentException::class); 71 | $result = new HttpService($this->client); 72 | $result->get(); 73 | } 74 | 75 | } 76 | --------------------------------------------------------------------------------