├── CODE_OF_CONDUCT.md ├── LICENSE ├── NOTICE ├── README.md ├── composer.json ├── format-check.py └── src └── AWS └── CRT ├── Auth ├── AwsCredentials.php ├── CredentialsProvider.php ├── Signable.php ├── SignatureType.php ├── SignedBodyHeaderType.php ├── Signing.php ├── SigningAlgorithm.php ├── SigningConfigAWS.php ├── SigningResult.php └── StaticCredentialsProvider.php ├── CRT.php ├── HTTP ├── Headers.php ├── Message.php ├── Request.php └── Response.php ├── IO ├── EventLoopGroup.php └── InputStream.php ├── Internal ├── Encoding.php └── Extension.php ├── Log.php ├── NativeResource.php └── Options.php /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AWS Common Runtime PHP bindings 2 | 3 | ## Requirements 4 | 5 | * PHP 5.5+ on UNIX platforms, 7.2+ on Windows 6 | * CMake 3.x 7 | * GCC 4.4+, clang 3.8+ on UNIX, Visual Studio build tools on Windows 8 | * Tests require [Composer](https://getcomposer.org) 9 | 10 | ## Installing with Composer and PECL 11 | 12 | The package has two different package published to [composer](https://packagist.org/packages/aws/aws-crt-php) and [PECL](https://pecl.php.net/package/awscrt). 13 | 14 | On UNIX, you can get the package from package manager or build from source: 15 | 16 | ``` 17 | pecl install awscrt 18 | composer require aws/aws-crt-php 19 | ``` 20 | 21 | On Windows, you need to build from source as instruction written below for the native extension `php_awscrt.dll` . And, follow https://www.php.net/manual/en/install.pecl.windows.php#install.pecl.windows.loading to load extension. After that: 22 | 23 | ``` 24 | composer require aws/aws-crt-php 25 | ``` 26 | 27 | ## Building from Github source 28 | 29 | ```sh 30 | $ git clone --recursive https://github.com/awslabs/aws-crt-php.git 31 | $ cd aws-crt-php 32 | $ phpize 33 | $ ./configure 34 | $ make 35 | $ ./dev-scripts/run_tests.sh 36 | ``` 37 | 38 | ## Building on Windows 39 | 40 | ### Requirements for Windows 41 | 42 | * Ensure you have the [windows PHP SDK](https://github.com/microsoft/php-sdk-binary-tools) (this example assumes installation of the SDK to C:\php-sdk and that you've checked out the PHP source to php-src within the build directory) and it works well on your machine. 43 | 44 | * Ensure you have "Development package (SDK to develop PHP extensions)" and PHP available from your system path. You can download them from https://windows.php.net/download/. You can check if they are available by running `phpize -v` and `php -v` 45 | 46 | ### Instructions 47 | 48 | From Command Prompt (not powershell). The instruction is based on Visual Studio 2019 on 64bit Windows. 49 | 50 | ```bat 51 | > git clone --recursive https://github.com/awslabs/aws-crt-php.git 52 | > git clone https://github.com/microsoft/php-sdk-binary-tools.git C:\php-sdk 53 | > C:\php-sdk\phpsdk-vs16-x64.bat 54 | 55 | C:\php-sdk\ 56 | $ cd 57 | 58 | \ 59 | $ phpize 60 | 61 | # --with-prefix only required when your php runtime in system path is different than the runtime you wish to use. 62 | \ 63 | $ configure --enable-awscrt=shared --with-prefix= 64 | 65 | \ 66 | $ nmake 67 | 68 | \ 69 | $ nmake generate-php-ini 70 | 71 | # check .\php-win.ini, it now has the full path to php_awscrt.dll that you can manually load to your php runtime, or you can run the following command to run tests and load the required native extension for awscrt. 72 | \ 73 | $ .\dev-scripts\run_tests.bat 74 | ``` 75 | 76 | Note: for VS2017, Cmake will default to build for Win32, refer to [here](https://cmake.org/cmake/help/latest/generator/Visual%20Studio%2015%202017.html). If you are building for x64 php, you can set environment variable as follow to let cmake pick x64 compiler. 77 | 78 | ```bat 79 | set CMAKE_GENERATOR=Visual Studio 15 2017 80 | set CMAKE_GENERATOR_PLATFORM=x64 81 | ``` 82 | 83 | ## Debugging 84 | 85 | Using [PHPBrew](https://github.com/phpbrew/phpbrew) to build/manage multiple versions of PHP is helpful. 86 | 87 | Note: You must use a debug build of PHP to debug native extensions. 88 | See the [PHP Internals Book](https://www.phpinternalsbook.com/php7/build_system/building_php.html) for more info 89 | 90 | ```shell 91 | # PHP 8 example 92 | $ phpbrew install --stdout -j 8 8.0 +default -- CFLAGS=-Wno-error --disable-cgi --enable-debug 93 | # PHP 5.5 example 94 | $ phpbrew install --stdout -j 8 5.5 +default -openssl -mbstring -- CFLAGS="-w -Wno-error" --enable-debug --with-zlib=/usr/local/opt/zlib 95 | $ phpbrew switch php-8.0.6 # or whatever version is current, it'll be at the end of the build output 96 | $ phpize 97 | $ ./configure 98 | $ make CMAKE_BUILD_TYPE=Debug 99 | ``` 100 | 101 | Ensure that the php you launch from your debugger is the result of `which php` , not just 102 | the system default php. 103 | 104 | ## Security 105 | 106 | See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information. 107 | 108 | ## Known OpenSSL related issue (Unix only) 109 | 110 | * When your php loads a different version of openssl than your system openssl version, awscrt may fail to load or weirdly crash. You can find the openssl version php linked via: `php -i | grep 'OpenSSL'`, and awscrt linked from the build log, which will be `Found OpenSSL: * (found version *)` 111 | 112 | The easiest workaround to those issue is to build from source and get aws-lc for awscrt to depend on instead. 113 | TO do that, same instructions as [here](#building-from-github-source), but use `USE_OPENSSL=OFF make` instead of `make` 114 | 115 | ## License 116 | 117 | This project is licensed under the Apache-2.0 License. 118 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aws/aws-crt-php", 3 | "homepage": "https://github.com/awslabs/aws-crt-php", 4 | "description": "AWS Common Runtime for PHP", 5 | "keywords": ["aws","amazon","sdk","crt"], 6 | "type": "library", 7 | "authors": [ 8 | { 9 | "name": "AWS SDK Common Runtime Team", 10 | "email": "aws-sdk-common-runtime@amazon.com" 11 | } 12 | ], 13 | "minimum-stability": "alpha", 14 | "require": { 15 | "php": ">=5.5" 16 | }, 17 | "require-dev": { 18 | "phpunit/phpunit":"^4.8.35||^5.6.3||^9.5", 19 | "yoast/phpunit-polyfills": "^1.0" 20 | }, 21 | "autoload": { 22 | "classmap": [ 23 | "src/" 24 | ] 25 | }, 26 | "suggest": { 27 | "ext-awscrt": "Make sure you install awscrt native extension to use any of the functionality." 28 | }, 29 | "scripts": { 30 | "test": "./dev-scripts/run_tests.sh", 31 | "test-extension": "@test", 32 | "test-win": ".\\dev-scripts\\run_tests.bat" 33 | }, 34 | "license": "Apache-2.0" 35 | } 36 | -------------------------------------------------------------------------------- /format-check.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import argparse 3 | import os 4 | from pathlib import Path 5 | import re 6 | from subprocess import list2cmdline, run 7 | from tempfile import NamedTemporaryFile 8 | 9 | CLANG_FORMAT_VERSION = '18.1.6' 10 | 11 | INCLUDE_REGEX = re.compile(r'^ext/.*\.(c|h|inl)$') 12 | EXCLUDE_REGEX = re.compile(r'^$') 13 | 14 | arg_parser = argparse.ArgumentParser(description="Check with clang-format") 15 | arg_parser.add_argument('-i', '--inplace-edit', action='store_true', 16 | help="Edit files inplace") 17 | args = arg_parser.parse_args() 18 | 19 | os.chdir(Path(__file__).parent) 20 | 21 | # create file containing list of all files to format 22 | filepaths_file = NamedTemporaryFile(delete=False) 23 | for dirpath, dirnames, filenames in os.walk('.'): 24 | for filename in filenames: 25 | # our regexes expect filepath to use forward slash 26 | filepath = Path(dirpath, filename).as_posix() 27 | if not INCLUDE_REGEX.match(filepath): 28 | continue 29 | if EXCLUDE_REGEX.match(filepath): 30 | continue 31 | 32 | filepaths_file.write(f"{filepath}\n".encode()) 33 | filepaths_file.close() 34 | 35 | # use pipx to run clang-format from PyPI 36 | # this is a simple way to run the same clang-format version regardless of OS 37 | cmd = ['pipx', 'run', f'clang-format=={CLANG_FORMAT_VERSION}', 38 | f'--files={filepaths_file.name}'] 39 | if args.inplace_edit: 40 | cmd += ['-i'] 41 | else: 42 | cmd += ['--Werror', '--dry-run'] 43 | 44 | print(f"{Path.cwd()}$ {list2cmdline(cmd)}") 45 | if run(cmd).returncode: 46 | exit(1) 47 | -------------------------------------------------------------------------------- /src/AWS/CRT/Auth/AwsCredentials.php: -------------------------------------------------------------------------------- 1 | '', 25 | 'secret_access_key' => '', 26 | 'session_token' => '', 27 | 'expiration_timepoint_seconds' => 0, 28 | ]; 29 | } 30 | 31 | private $access_key_id; 32 | private $secret_access_key; 33 | private $session_token; 34 | private $expiration_timepoint_seconds = 0; 35 | 36 | public function __get($name) { 37 | return $this->$name; 38 | } 39 | 40 | function __construct(array $options = []) { 41 | parent::__construct(); 42 | 43 | $options = new Options($options, self::defaults()); 44 | $this->access_key_id = $options->access_key_id->asString(); 45 | $this->secret_access_key = $options->secret_access_key->asString(); 46 | $this->session_token = $options->session_token ? $options->session_token->asString() : null; 47 | $this->expiration_timepoint_seconds = $options->expiration_timepoint_seconds->asInt(); 48 | 49 | if (strlen($this->access_key_id) == 0) { 50 | throw new \InvalidArgumentException("access_key_id must be provided"); 51 | } 52 | if (strlen($this->secret_access_key) == 0) { 53 | throw new \InvalidArgumentException("secret_access_key must be provided"); 54 | } 55 | 56 | $creds_options = self::$crt->aws_credentials_options_new(); 57 | self::$crt->aws_credentials_options_set_access_key_id($creds_options, $this->access_key_id); 58 | self::$crt->aws_credentials_options_set_secret_access_key($creds_options, $this->secret_access_key); 59 | self::$crt->aws_credentials_options_set_session_token($creds_options, $this->session_token); 60 | self::$crt->aws_credentials_options_set_expiration_timepoint_seconds($creds_options, $this->expiration_timepoint_seconds); 61 | $this->acquire(self::$crt->aws_credentials_new($creds_options)); 62 | self::$crt->aws_credentials_options_release($creds_options); 63 | } 64 | 65 | function __destruct() { 66 | self::$crt->aws_credentials_release($this->release()); 67 | parent::__destruct(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/AWS/CRT/Auth/CredentialsProvider.php: -------------------------------------------------------------------------------- 1 | credentials_provider_release($this->release()); 21 | parent::__destruct(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/AWS/CRT/Auth/Signable.php: -------------------------------------------------------------------------------- 1 | signable_new_from_http_request($http_message->native); 16 | }); 17 | } 18 | 19 | public static function fromChunk($chunk_stream, $previous_signature="") { 20 | if (!($chunk_stream instanceof InputStream)) { 21 | $chunk_stream = new InputStream($chunk_stream); 22 | } 23 | return new Signable(function() use($chunk_stream, $previous_signature) { 24 | return self::$crt->signable_new_from_chunk($chunk_stream->native, $previous_signature); 25 | }); 26 | } 27 | 28 | public static function fromCanonicalRequest($canonical_request) { 29 | return new Signable(function() use($canonical_request) { 30 | return self::$crt->signable_new_from_canonical_request($canonical_request); 31 | }); 32 | } 33 | 34 | protected function __construct($ctor) { 35 | parent::__construct(); 36 | $this->acquire($ctor()); 37 | } 38 | 39 | function __destruct() { 40 | self::$crt->signable_release($this->release()); 41 | parent::__destruct(); 42 | } 43 | } -------------------------------------------------------------------------------- /src/AWS/CRT/Auth/SignatureType.php: -------------------------------------------------------------------------------- 1 | sign_request_aws($signable->native, $signing_config->native, 13 | function($result, $error_code) use ($on_complete) { 14 | $signing_result = SigningResult::fromNative($result); 15 | $on_complete($signing_result, $error_code); 16 | }, null); 17 | } 18 | 19 | static function testVerifySigV4ASigning($signable, $signing_config, $expected_canonical_request, $signature, $ecc_key_pub_x, $ecc_key_pub_y) { 20 | return self::$crt->test_verify_sigv4a_signing($signable, $signing_config, $expected_canonical_request, $signature, $ecc_key_pub_x, $ecc_key_pub_y); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/AWS/CRT/Auth/SigningAlgorithm.php: -------------------------------------------------------------------------------- 1 | SigningAlgorithm::SIGv4, 16 | 'signature_type' => SignatureType::HTTP_REQUEST_HEADERS, 17 | 'credentials_provider' => null, 18 | 'region' => null, 19 | 'service' => null, 20 | 'use_double_uri_encode' => false, 21 | 'should_normalize_uri_path' => false, 22 | 'omit_session_token' => false, 23 | 'signed_body_value' => null, 24 | 'signed_body_header_type' => SignedBodyHeaderType::NONE, 25 | 'expiration_in_seconds' => 0, 26 | 'date' => time(), 27 | 'should_sign_header' => null, 28 | ]; 29 | } 30 | 31 | private $options; 32 | 33 | public function __construct(array $options = []) { 34 | parent::__construct(); 35 | $this->options = $options = new Options($options, self::defaults()); 36 | $sc = $this->acquire(self::$crt->signing_config_aws_new()); 37 | self::$crt->signing_config_aws_set_algorithm($sc, $options->algorithm->asInt()); 38 | self::$crt->signing_config_aws_set_signature_type($sc, $options->signature_type->asInt()); 39 | if ($credentials_provider = $options->credentials_provider->asObject()) { 40 | self::$crt->signing_config_aws_set_credentials_provider( 41 | $sc, 42 | $credentials_provider->native); 43 | } 44 | self::$crt->signing_config_aws_set_region( 45 | $sc, $options->region->asString()); 46 | self::$crt->signing_config_aws_set_service( 47 | $sc, $options->service->asString()); 48 | self::$crt->signing_config_aws_set_use_double_uri_encode( 49 | $sc, $options->use_double_uri_encode->asBool()); 50 | self::$crt->signing_config_aws_set_should_normalize_uri_path( 51 | $sc, $options->should_normalize_uri_path->asBool()); 52 | self::$crt->signing_config_aws_set_omit_session_token( 53 | $sc, $options->omit_session_token->asBool()); 54 | self::$crt->signing_config_aws_set_signed_body_value( 55 | $sc, $options->signed_body_value->asString()); 56 | self::$crt->signing_config_aws_set_signed_body_header_type( 57 | $sc, $options->signed_body_header_type->asInt()); 58 | self::$crt->signing_config_aws_set_expiration_in_seconds( 59 | $sc, $options->expiration_in_seconds->asInt()); 60 | self::$crt->signing_config_aws_set_date($sc, $options->date->asInt()); 61 | if ($should_sign_header = $options->should_sign_header->asCallable()) { 62 | self::$crt->signing_config_aws_set_should_sign_header_fn($sc, $should_sign_header); 63 | } 64 | } 65 | 66 | function __destruct() 67 | { 68 | self::$crt->signing_config_aws_release($this->release()); 69 | parent::__destruct(); 70 | } 71 | 72 | public function __get($name) { 73 | return $this->options->get($name); 74 | } 75 | } -------------------------------------------------------------------------------- /src/AWS/CRT/Auth/SigningResult.php: -------------------------------------------------------------------------------- 1 | acquire($native); 16 | } 17 | 18 | function __destruct() { 19 | // No destruction necessary, SigningResults are transient, just release 20 | $this->release(); 21 | parent::__destruct(); 22 | } 23 | 24 | public static function fromNative($ptr) { 25 | return new SigningResult($ptr); 26 | } 27 | 28 | public function applyToHttpRequest(&$http_request) { 29 | self::$crt->signing_result_apply_to_http_request($this->native, $http_request->native); 30 | // Update http_request from native 31 | $http_request = Request::unmarshall($http_request->toBlob()); 32 | } 33 | } -------------------------------------------------------------------------------- /src/AWS/CRT/Auth/StaticCredentialsProvider.php: -------------------------------------------------------------------------------- 1 | $name; 22 | } 23 | 24 | function __construct(array $options = []) { 25 | parent::__construct(); 26 | $this->credentials = new AwsCredentials($options); 27 | 28 | $provider_options = self::$crt->credentials_provider_static_options_new(); 29 | self::$crt->credentials_provider_static_options_set_access_key_id($provider_options, $this->credentials->access_key_id); 30 | self::$crt->credentials_provider_static_options_set_secret_access_key($provider_options, $this->credentials->secret_access_key); 31 | self::$crt->credentials_provider_static_options_set_session_token($provider_options, $this->credentials->session_token); 32 | $this->acquire(self::$crt->credentials_provider_static_new($provider_options)); 33 | self::$crt->credentials_provider_static_options_release($provider_options); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/AWS/CRT/CRT.php: -------------------------------------------------------------------------------- 1 | aws_crt_last_error(); 64 | } 65 | 66 | /** 67 | * @param integer $error Error code from the CRT, usually delivered via callback or {@see last_error} 68 | * @return string Human-readable description of the provided error code 69 | */ 70 | public static function error_str($error) { 71 | return self::$impl->aws_crt_error_str((int) $error); 72 | } 73 | 74 | /** 75 | * @param integer $error Error code from the CRT, usually delivered via callback or {@see last_error} 76 | * @return string Name/enum identifier for the provided error code 77 | */ 78 | public static function error_name($error) { 79 | return self::$impl->aws_crt_error_name((int) $error); 80 | } 81 | 82 | public static function log_to_stdout() { 83 | return self::$impl->aws_crt_log_to_stdout(); 84 | } 85 | 86 | public static function log_to_stderr() { 87 | return self::$impl->aws_crt_log_to_stderr(); 88 | } 89 | 90 | public static function log_to_file($filename) { 91 | return self::$impl->aws_crt_log_to_file($filename); 92 | } 93 | 94 | public static function log_to_stream($stream) { 95 | return self::$impl->aws_crt_log_to_stream($stream); 96 | } 97 | 98 | public static function log_set_level($level) { 99 | return self::$impl->aws_crt_log_set_level($level); 100 | } 101 | 102 | public static function log_stop() { 103 | return self::$impl->aws_crt_log_stop(); 104 | } 105 | 106 | public static function log_message($level, $message) { 107 | return self::$impl->aws_crt_log_message($level, $message); 108 | } 109 | 110 | /** 111 | * @return object Pointer to native event_loop_group_options 112 | */ 113 | function event_loop_group_options_new() { 114 | return self::$impl->aws_crt_event_loop_group_options_new(); 115 | } 116 | 117 | /** 118 | * @param object $elg_options Pointer to native event_loop_group_options 119 | */ 120 | function event_loop_group_options_release($elg_options) { 121 | self::$impl->aws_crt_event_loop_group_options_release($elg_options); 122 | } 123 | 124 | /** 125 | * @param object $elg_options Pointer to native event_loop_group_options 126 | * @param integer $max_threads Maximum number of threads to allow the event loop group to use, default: 0/1 per CPU core 127 | */ 128 | function event_loop_group_options_set_max_threads($elg_options, $max_threads) { 129 | self::$impl->aws_crt_event_loop_group_options_set_max_threads($elg_options, (int)$max_threads); 130 | } 131 | 132 | /** 133 | * @param object Pointer to event_loop_group_options, {@see event_loop_group_options_new} 134 | * @return object Pointer to the new event loop group 135 | */ 136 | function event_loop_group_new($options) { 137 | return self::$impl->aws_crt_event_loop_group_new($options); 138 | } 139 | 140 | /** 141 | * @param object $elg Pointer to the event loop group to release 142 | */ 143 | function event_loop_group_release($elg) { 144 | self::$impl->aws_crt_event_loop_group_release($elg); 145 | } 146 | 147 | /** 148 | * return object Pointer to native AWS credentials options 149 | */ 150 | function aws_credentials_options_new() { 151 | return self::$impl->aws_crt_credentials_options_new(); 152 | } 153 | 154 | function aws_credentials_options_release($options) { 155 | self::$impl->aws_crt_credentials_options_release($options); 156 | } 157 | 158 | function aws_credentials_options_set_access_key_id($options, $access_key_id) { 159 | self::$impl->aws_crt_credentials_options_set_access_key_id($options, $access_key_id); 160 | } 161 | 162 | function aws_credentials_options_set_secret_access_key($options, $secret_access_key) { 163 | self::$impl->aws_crt_credentials_options_set_secret_access_key($options, $secret_access_key); 164 | } 165 | 166 | function aws_credentials_options_set_session_token($options, $session_token) { 167 | self::$impl->aws_crt_credentials_options_set_session_token($options, $session_token); 168 | } 169 | 170 | function aws_credentials_options_set_expiration_timepoint_seconds($options, $expiration_timepoint_seconds) { 171 | self::$impl->aws_crt_credentials_options_set_expiration_timepoint_seconds($options, $expiration_timepoint_seconds); 172 | } 173 | 174 | function aws_credentials_new($options) { 175 | return self::$impl->aws_crt_credentials_new($options); 176 | } 177 | 178 | function aws_credentials_release($credentials) { 179 | self::$impl->aws_crt_credentials_release($credentials); 180 | } 181 | 182 | function credentials_provider_release($provider) { 183 | self::$impl->aws_crt_credentials_provider_release($provider); 184 | } 185 | 186 | function credentials_provider_static_options_new() { 187 | return self::$impl->aws_crt_credentials_provider_static_options_new(); 188 | } 189 | 190 | function credentials_provider_static_options_release($options) { 191 | self::$impl->aws_crt_credentials_provider_static_options_release($options); 192 | } 193 | 194 | function credentials_provider_static_options_set_access_key_id($options, $access_key_id) { 195 | self::$impl->aws_crt_credentials_provider_static_options_set_access_key_id($options, $access_key_id); 196 | } 197 | 198 | function credentials_provider_static_options_set_secret_access_key($options, $secret_access_key) { 199 | self::$impl->aws_crt_credentials_provider_static_options_set_secret_access_key($options, $secret_access_key); 200 | } 201 | 202 | function credentials_provider_static_options_set_session_token($options, $session_token) { 203 | self::$impl->aws_crt_credentials_provider_static_options_set_session_token($options, $session_token); 204 | } 205 | 206 | function credentials_provider_static_new($options) { 207 | return self::$impl->aws_crt_credentials_provider_static_new($options); 208 | } 209 | 210 | function input_stream_options_new() { 211 | return self::$impl->aws_crt_input_stream_options_new(); 212 | } 213 | 214 | function input_stream_options_release($options) { 215 | self::$impl->aws_crt_input_stream_options_release($options); 216 | } 217 | 218 | function input_stream_options_set_user_data($options, $user_data) { 219 | self::$impl->aws_crt_input_stream_options_set_user_data($options, $user_data); 220 | } 221 | 222 | function input_stream_new($options) { 223 | return self::$impl->aws_crt_input_stream_new($options); 224 | } 225 | 226 | function input_stream_release($stream) { 227 | self::$impl->aws_crt_input_stream_release($stream); 228 | } 229 | 230 | function input_stream_seek($stream, $offset, $basis) { 231 | return self::$impl->aws_crt_input_stream_seek($stream, $offset, $basis); 232 | } 233 | 234 | function input_stream_read($stream, $length) { 235 | return self::$impl->aws_crt_input_stream_read($stream, $length); 236 | } 237 | 238 | function input_stream_eof($stream) { 239 | return self::$impl->aws_crt_input_stream_eof($stream); 240 | } 241 | 242 | function input_stream_get_length($stream) { 243 | return self::$impl->aws_crt_input_stream_get_length($stream); 244 | } 245 | 246 | function http_message_new_from_blob($blob) { 247 | return self::$impl->aws_crt_http_message_new_from_blob($blob); 248 | } 249 | 250 | function http_message_to_blob($message) { 251 | return self::$impl->aws_crt_http_message_to_blob($message); 252 | } 253 | 254 | function http_message_release($message) { 255 | self::$impl->aws_crt_http_message_release($message); 256 | } 257 | 258 | function signing_config_aws_new() { 259 | return self::$impl->aws_crt_signing_config_aws_new(); 260 | } 261 | 262 | function signing_config_aws_release($signing_config) { 263 | return self::$impl->aws_crt_signing_config_aws_release($signing_config); 264 | } 265 | 266 | function signing_config_aws_set_algorithm($signing_config, $algorithm) { 267 | self::$impl->aws_crt_signing_config_aws_set_algorithm($signing_config, (int)$algorithm); 268 | } 269 | 270 | function signing_config_aws_set_signature_type($signing_config, $signature_type) { 271 | self::$impl->aws_crt_signing_config_aws_set_signature_type($signing_config, (int)$signature_type); 272 | } 273 | 274 | function signing_config_aws_set_credentials_provider($signing_config, $credentials_provider) { 275 | self::$impl->aws_crt_signing_config_aws_set_credentials_provider($signing_config, $credentials_provider); 276 | } 277 | 278 | function signing_config_aws_set_region($signing_config, $region) { 279 | self::$impl->aws_crt_signing_config_aws_set_region($signing_config, $region); 280 | } 281 | 282 | function signing_config_aws_set_service($signing_config, $service) { 283 | self::$impl->aws_crt_signing_config_aws_set_service($signing_config, $service); 284 | } 285 | 286 | function signing_config_aws_set_use_double_uri_encode($signing_config, $use_double_uri_encode) { 287 | self::$impl->aws_crt_signing_config_aws_set_use_double_uri_encode($signing_config, $use_double_uri_encode); 288 | } 289 | 290 | function signing_config_aws_set_should_normalize_uri_path($signing_config, $should_normalize_uri_path) { 291 | self::$impl->aws_crt_signing_config_aws_set_should_normalize_uri_path($signing_config, $should_normalize_uri_path); 292 | } 293 | 294 | function signing_config_aws_set_omit_session_token($signing_config, $omit_session_token) { 295 | self::$impl->aws_crt_signing_config_aws_set_omit_session_token($signing_config, $omit_session_token); 296 | } 297 | 298 | function signing_config_aws_set_signed_body_value($signing_config, $signed_body_value) { 299 | self::$impl->aws_crt_signing_config_aws_set_signed_body_value($signing_config, $signed_body_value); 300 | } 301 | 302 | function signing_config_aws_set_signed_body_header_type($signing_config, $signed_body_header_type) { 303 | self::$impl->aws_crt_signing_config_aws_set_signed_body_header_type($signing_config, $signed_body_header_type); 304 | } 305 | 306 | function signing_config_aws_set_expiration_in_seconds($signing_config, $expiration_in_seconds) { 307 | self::$impl->aws_crt_signing_config_aws_set_expiration_in_seconds($signing_config, $expiration_in_seconds); 308 | } 309 | 310 | function signing_config_aws_set_date($signing_config, $timestamp) { 311 | self::$impl->aws_crt_signing_config_aws_set_date($signing_config, $timestamp); 312 | } 313 | 314 | function signing_config_aws_set_should_sign_header_fn($signing_config, $should_sign_header_fn) { 315 | self::$impl->aws_crt_signing_config_aws_set_should_sign_header_fn($signing_config, $should_sign_header_fn); 316 | } 317 | 318 | function signable_new_from_http_request($http_message) { 319 | return self::$impl->aws_crt_signable_new_from_http_request($http_message); 320 | } 321 | 322 | function signable_new_from_chunk($chunk_stream, $previous_signature) { 323 | return self::$impl->aws_crt_signable_new_from_chunk($chunk_stream, $previous_signature); 324 | } 325 | 326 | function signable_new_from_canonical_request($canonical_request) { 327 | return self::$impl->aws_crt_signable_new_from_canonical_request($canonical_request); 328 | } 329 | 330 | function signable_release($signable) { 331 | self::$impl->aws_crt_signable_release($signable); 332 | } 333 | 334 | function signing_result_release($signing_result) { 335 | self::$impl->aws_crt_signing_result_release($signing_result); 336 | } 337 | 338 | function signing_result_apply_to_http_request($signing_result, $http_message) { 339 | return self::$impl->aws_crt_signing_result_apply_to_http_request( 340 | $signing_result, $http_message); 341 | } 342 | 343 | function sign_request_aws($signable, $signing_config, $on_complete, $user_data) { 344 | return self::$impl->aws_crt_sign_request_aws($signable, $signing_config, $on_complete, $user_data); 345 | } 346 | 347 | function test_verify_sigv4a_signing($signable, $signing_config, $expected_canonical_request, $signature, $ecc_key_pub_x, $ecc_key_pub_y) { 348 | return self::$impl->aws_crt_test_verify_sigv4a_signing($signable, $signing_config, $expected_canonical_request, $signature, $ecc_key_pub_x, $ecc_key_pub_y); 349 | } 350 | 351 | public static function crc32($input, $previous = 0) { 352 | return self::$impl->aws_crt_crc32($input, $previous); 353 | } 354 | 355 | public static function crc32c($input, $previous = 0) { 356 | return self::$impl->aws_crt_crc32c($input, $previous); 357 | } 358 | } 359 | -------------------------------------------------------------------------------- /src/AWS/CRT/HTTP/Headers.php: -------------------------------------------------------------------------------- 1 | headers = $headers; 15 | } 16 | 17 | public static function marshall($headers) { 18 | $buf = ""; 19 | foreach ($headers->headers as $header => $value) { 20 | $buf .= Encoding::encodeString($header); 21 | $buf .= Encoding::encodeString($value); 22 | } 23 | return $buf; 24 | } 25 | 26 | public static function unmarshall($buf) { 27 | $strings = Encoding::readStrings($buf); 28 | $headers = []; 29 | for ($idx = 0; $idx < count($strings);) { 30 | $headers[$strings[$idx++]] = $strings[$idx++]; 31 | } 32 | return new Headers($headers); 33 | } 34 | 35 | public function count() { 36 | return count($this->headers); 37 | } 38 | 39 | public function get($header) { 40 | return isset($this->headers[$header]) ? $this->headers[$header] : null; 41 | } 42 | 43 | public function set($header, $value) { 44 | $this->headers[$header] = $value; 45 | } 46 | 47 | public function toArray() { 48 | return $this->headers; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/AWS/CRT/HTTP/Message.php: -------------------------------------------------------------------------------- 1 | method = $method; 20 | $this->path = $path; 21 | $this->query = $query; 22 | $this->headers = new Headers($headers); 23 | $this->acquire(self::$crt->http_message_new_from_blob(self::marshall($this))); 24 | } 25 | 26 | public function __destruct() { 27 | self::$crt->http_message_release($this->release()); 28 | parent::__destruct(); 29 | } 30 | 31 | public function toBlob() { 32 | return self::$crt->http_message_to_blob($this->native); 33 | } 34 | 35 | protected static function marshall($msg) { 36 | $buf = ""; 37 | $buf .= Encoding::encodeString($msg->method); 38 | $buf .= Encoding::encodeString($msg->pathAndQuery()); 39 | $buf .= Headers::marshall($msg->headers); 40 | return $buf; 41 | } 42 | 43 | protected static function _unmarshall($buf, $class=Message::class) { 44 | $method = Encoding::readString($buf); 45 | $path_and_query = Encoding::readString($buf); 46 | $parts = explode("?", $path_and_query, 2); 47 | $path = isset($parts[0]) ? $parts[0] : ""; 48 | $query = isset($parts[1]) ? $parts[1] : ""; 49 | $headers = Headers::unmarshall($buf); 50 | 51 | // Turn query params back into a dictionary 52 | if (strlen($query)) { 53 | $query = rawurldecode($query); 54 | $query = explode("&", $query); 55 | $query = array_reduce($query, function($params, $pair) { 56 | list($param, $value) = explode("=", $pair, 2); 57 | $params[$param] = $value; 58 | return $params; 59 | }, []); 60 | } else { 61 | $query = []; 62 | } 63 | 64 | return new $class($method, $path, $query, $headers->toArray()); 65 | } 66 | 67 | public function pathAndQuery() { 68 | $path = $this->path; 69 | $queries = []; 70 | foreach ($this->query as $param => $value) { 71 | $queries []= urlencode($param) . "=" . urlencode($value); 72 | } 73 | $query = implode("&", $queries); 74 | if (strlen($query)) { 75 | $path = implode("?", [$path, $query]); 76 | } 77 | return $path; 78 | } 79 | 80 | public function method() { 81 | return $this->method; 82 | } 83 | 84 | public function path() { 85 | return $this->path; 86 | } 87 | 88 | public function query() { 89 | return $this->query; 90 | } 91 | 92 | public function headers() { 93 | return $this->headers; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/AWS/CRT/HTTP/Request.php: -------------------------------------------------------------------------------- 1 | body_stream = $body_stream; 19 | } 20 | 21 | public static function marshall($request) { 22 | return parent::marshall($request); 23 | } 24 | 25 | public static function unmarshall($buf) { 26 | return parent::_unmarshall($buf, Request::class); 27 | } 28 | 29 | public function body_stream() { 30 | return $this->body_stream; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/AWS/CRT/HTTP/Response.php: -------------------------------------------------------------------------------- 1 | status_code = $status_code; 14 | } 15 | 16 | public static function marshall($response) { 17 | return parent::marshall($response); 18 | } 19 | 20 | public static function unmarshall($buf) { 21 | return parent::_unmarshall($buf, Response::class); 22 | } 23 | 24 | public function status_code() { 25 | return $this->status_code; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/AWS/CRT/IO/EventLoopGroup.php: -------------------------------------------------------------------------------- 1 | 0, 23 | ]; 24 | } 25 | 26 | function __construct(array $options = []) { 27 | parent::__construct(); 28 | $options = new Options($options, self::defaults()); 29 | $elg_options = self::$crt->event_loop_group_options_new(); 30 | self::$crt->event_loop_group_options_set_max_threads($elg_options, $options->getInt('max_threads')); 31 | $this->acquire(self::$crt->event_loop_group_new($elg_options)); 32 | self::$crt->event_loop_group_options_release($elg_options); 33 | } 34 | 35 | function __destruct() { 36 | self::$crt->event_loop_group_release($this->release()); 37 | parent::__destruct(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/AWS/CRT/IO/InputStream.php: -------------------------------------------------------------------------------- 1 | stream = $stream; 19 | $options = self::$crt->input_stream_options_new(); 20 | // The stream implementation in native just converts the PHP stream into 21 | // a native php_stream* and executes operations entirely in native 22 | self::$crt->input_stream_options_set_user_data($options, $stream); 23 | $this->acquire(self::$crt->input_stream_new($options)); 24 | self::$crt->input_stream_options_release($options); 25 | } 26 | 27 | public function __destruct() { 28 | $this->release(); 29 | parent::__destruct(); 30 | } 31 | 32 | public function eof() { 33 | return self::$crt->input_stream_eof($this->native); 34 | } 35 | 36 | public function length() { 37 | return self::$crt->input_stream_get_length($this->native); 38 | } 39 | 40 | public function read($length = 0) { 41 | if ($length == 0) { 42 | $length = $this->length(); 43 | } 44 | return self::$crt->input_stream_read($this->native, $length); 45 | } 46 | 47 | public function seek($offset, $basis) { 48 | return self::$crt->input_stream_seek($this->native, $offset, $basis); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/AWS/CRT/Internal/Encoding.php: -------------------------------------------------------------------------------- 1 | = self::NONE && $level <= self::TRACE); 41 | CRT::log_set_level($level); 42 | } 43 | 44 | public static function log($level, $message) { 45 | CRT::log_message($level, $message); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/AWS/CRT/NativeResource.php: -------------------------------------------------------------------------------- 1 | native = $handle; 29 | } 30 | 31 | protected function release() { 32 | $native = $this->native; 33 | $this->native = null; 34 | return $native; 35 | } 36 | 37 | function __destruct() { 38 | // Should have been destroyed and released by derived resource 39 | assert($this->native == null); 40 | unset(self::$resources[spl_object_hash($this)]); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/AWS/CRT/Options.php: -------------------------------------------------------------------------------- 1 | value = $value; 12 | } 13 | 14 | public function asObject() { 15 | return $this->value; 16 | } 17 | 18 | public function asMixed() { 19 | return $this->value; 20 | } 21 | 22 | public function asInt() { 23 | return empty($this->value) ? 0 : (int)$this->value; 24 | } 25 | 26 | public function asBool() { 27 | return boolval($this->value); 28 | } 29 | 30 | public function asString() { 31 | return !empty($this->value) ? strval($this->value) : ""; 32 | } 33 | 34 | public function asArray() { 35 | return is_array($this->value) ? $this->value : (!empty($this->value) ? [$this->value] : []); 36 | } 37 | 38 | public function asCallable() { 39 | return is_callable($this->value) ? $this->value : null; 40 | } 41 | } 42 | 43 | final class Options { 44 | private $options; 45 | 46 | public function __construct($opts = [], $defaults = []) { 47 | $this->options = array_replace($defaults, empty($opts) ? [] : $opts); 48 | } 49 | 50 | public function __get($name) { 51 | return $this->get($name); 52 | } 53 | 54 | public function asArray() { 55 | return $this->options; 56 | } 57 | 58 | public function toArray() { 59 | return array_merge_recursive([], $this->options); 60 | } 61 | 62 | public function get($name) { 63 | return new OptionValue($this->options[$name]); 64 | } 65 | 66 | public function getInt($name) { 67 | return $this->get($name)->asInt(); 68 | } 69 | 70 | public function getString($name) { 71 | return $this->get($name)->asString(); 72 | } 73 | 74 | public function getBool($name) { 75 | return $this->get($name)->asBool(); 76 | } 77 | } 78 | --------------------------------------------------------------------------------