Shariff Wrapper - Version 1.9.0

Version Description

Download this release

Release Info

Developer 3UU
Plugin Icon 128x128 Shariff Wrapper
Version 1.9.0
Comparing to
See all releases

Version 1.9.0

Files changed (243) hide show
  1. LICENSE.txt +24 -0
  2. admin.css +15 -0
  3. backend/index.php +63 -0
  4. backend/shariff.json.example +18 -0
  5. backend/src/Backend.php +112 -0
  6. backend/src/Backend/Facebook.php +24 -0
  7. backend/src/Backend/Flattr.php +23 -0
  8. backend/src/Backend/GooglePlus.php +37 -0
  9. backend/src/Backend/LinkedIn.php +23 -0
  10. backend/src/Backend/Pinterest.php +33 -0
  11. backend/src/Backend/Reddit.php +26 -0
  12. backend/src/Backend/Request.php +30 -0
  13. backend/src/Backend/ServiceInterface.php +10 -0
  14. backend/src/Backend/StumbleUpon.php +22 -0
  15. backend/src/Backend/Twitter.php +22 -0
  16. backend/src/Backend/Xing.php +24 -0
  17. backend/vendor/autoload.php +7 -0
  18. backend/vendor/composer/ClassLoader.php +387 -0
  19. backend/vendor/composer/autoload_classmap.php +9 -0
  20. backend/vendor/composer/autoload_files.php +10 -0
  21. backend/vendor/composer/autoload_namespaces.php +15 -0
  22. backend/vendor/composer/autoload_psr4.php +14 -0
  23. backend/vendor/composer/autoload_real.php +55 -0
  24. backend/vendor/composer/installed.json +527 -0
  25. backend/vendor/guzzlehttp/guzzle/.gitignore +11 -0
  26. backend/vendor/guzzlehttp/guzzle/.travis.yml +39 -0
  27. backend/vendor/guzzlehttp/guzzle/CHANGELOG.md +1033 -0
  28. backend/vendor/guzzlehttp/guzzle/LICENSE +19 -0
  29. backend/vendor/guzzlehttp/guzzle/Makefile +50 -0
  30. backend/vendor/guzzlehttp/guzzle/README.md +70 -0
  31. backend/vendor/guzzlehttp/guzzle/UPGRADING.md +1050 -0
  32. backend/vendor/guzzlehttp/guzzle/build/packager.php +21 -0
  33. backend/vendor/guzzlehttp/guzzle/composer.json +39 -0
  34. backend/vendor/guzzlehttp/guzzle/docs/Makefile +153 -0
  35. backend/vendor/guzzlehttp/guzzle/docs/_static/guzzle-icon.png +0 -0
  36. backend/vendor/guzzlehttp/guzzle/docs/_static/logo.png +0 -0
  37. backend/vendor/guzzlehttp/guzzle/docs/_templates/nav_links.html +3 -0
  38. backend/vendor/guzzlehttp/guzzle/docs/clients.rst +1315 -0
  39. backend/vendor/guzzlehttp/guzzle/docs/conf.py +28 -0
  40. backend/vendor/guzzlehttp/guzzle/docs/events.rst +520 -0
  41. backend/vendor/guzzlehttp/guzzle/docs/faq.rst +199 -0
  42. backend/vendor/guzzlehttp/guzzle/docs/handlers.rst +43 -0
  43. backend/vendor/guzzlehttp/guzzle/docs/http-messages.rst +483 -0
  44. backend/vendor/guzzlehttp/guzzle/docs/index.rst +98 -0
  45. backend/vendor/guzzlehttp/guzzle/docs/overview.rst +150 -0
  46. backend/vendor/guzzlehttp/guzzle/docs/quickstart.rst +448 -0
  47. backend/vendor/guzzlehttp/guzzle/docs/requirements.txt +2 -0
  48. backend/vendor/guzzlehttp/guzzle/docs/streams.rst +213 -0
  49. backend/vendor/guzzlehttp/guzzle/docs/testing.rst +232 -0
  50. backend/vendor/guzzlehttp/guzzle/phpunit.xml.dist +17 -0
  51. backend/vendor/guzzlehttp/guzzle/src/BatchResults.php +148 -0
  52. backend/vendor/guzzlehttp/guzzle/src/Client.php +394 -0
  53. backend/vendor/guzzlehttp/guzzle/src/ClientInterface.php +150 -0
  54. backend/vendor/guzzlehttp/guzzle/src/Collection.php +236 -0
  55. backend/vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php +248 -0
  56. backend/vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php +75 -0
  57. backend/vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php +86 -0
  58. backend/vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php +66 -0
  59. backend/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php +373 -0
  60. backend/vendor/guzzlehttp/guzzle/src/Event/AbstractEvent.php +20 -0
  61. backend/vendor/guzzlehttp/guzzle/src/Event/AbstractRequestEvent.php +51 -0
  62. backend/vendor/guzzlehttp/guzzle/src/Event/AbstractRetryableEvent.php +40 -0
  63. backend/vendor/guzzlehttp/guzzle/src/Event/AbstractTransferEvent.php +73 -0
  64. backend/vendor/guzzlehttp/guzzle/src/Event/BeforeEvent.php +26 -0
  65. backend/vendor/guzzlehttp/guzzle/src/Event/CompleteEvent.php +14 -0
  66. backend/vendor/guzzlehttp/guzzle/src/Event/Emitter.php +146 -0
  67. backend/vendor/guzzlehttp/guzzle/src/Event/EmitterInterface.php +96 -0
  68. backend/vendor/guzzlehttp/guzzle/src/Event/EndEvent.php +28 -0
  69. backend/vendor/guzzlehttp/guzzle/src/Event/ErrorEvent.php +27 -0
  70. backend/vendor/guzzlehttp/guzzle/src/Event/EventInterface.php +23 -0
  71. backend/vendor/guzzlehttp/guzzle/src/Event/HasEmitterInterface.php +15 -0
  72. backend/vendor/guzzlehttp/guzzle/src/Event/HasEmitterTrait.php +20 -0
  73. backend/vendor/guzzlehttp/guzzle/src/Event/ListenerAttacherTrait.php +88 -0
  74. backend/vendor/guzzlehttp/guzzle/src/Event/ProgressEvent.php +51 -0
  75. backend/vendor/guzzlehttp/guzzle/src/Event/RequestEvents.php +56 -0
  76. backend/vendor/guzzlehttp/guzzle/src/Event/SubscriberInterface.php +34 -0
  77. backend/vendor/guzzlehttp/guzzle/src/Exception/BadResponseException.php +7 -0
  78. backend/vendor/guzzlehttp/guzzle/src/Exception/ClientException.php +7 -0
  79. backend/vendor/guzzlehttp/guzzle/src/Exception/ConnectException.php +4 -0
  80. backend/vendor/guzzlehttp/guzzle/src/Exception/CouldNotRewindStreamException.php +4 -0
  81. backend/vendor/guzzlehttp/guzzle/src/Exception/ParseException.php +31 -0
  82. backend/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php +121 -0
  83. backend/vendor/guzzlehttp/guzzle/src/Exception/ServerException.php +7 -0
  84. backend/vendor/guzzlehttp/guzzle/src/Exception/StateException.php +4 -0
  85. backend/vendor/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php +4 -0
  86. backend/vendor/guzzlehttp/guzzle/src/Exception/TransferException.php +4 -0
  87. backend/vendor/guzzlehttp/guzzle/src/Exception/XmlParseException.php +34 -0
  88. backend/vendor/guzzlehttp/guzzle/src/HasDataTrait.php +75 -0
  89. backend/vendor/guzzlehttp/guzzle/src/Message/AbstractMessage.php +253 -0
  90. backend/vendor/guzzlehttp/guzzle/src/Message/FutureResponse.php +158 -0
  91. backend/vendor/guzzlehttp/guzzle/src/Message/MessageFactory.php +364 -0
  92. backend/vendor/guzzlehttp/guzzle/src/Message/MessageFactoryInterface.php +71 -0
  93. backend/vendor/guzzlehttp/guzzle/src/Message/MessageInterface.php +136 -0
  94. backend/vendor/guzzlehttp/guzzle/src/Message/MessageParser.php +171 -0
  95. backend/vendor/guzzlehttp/guzzle/src/Message/Request.php +195 -0
  96. backend/vendor/guzzlehttp/guzzle/src/Message/RequestInterface.php +136 -0
  97. backend/vendor/guzzlehttp/guzzle/src/Message/Response.php +208 -0
  98. backend/vendor/guzzlehttp/guzzle/src/Message/ResponseInterface.php +111 -0
  99. backend/vendor/guzzlehttp/guzzle/src/Mimetypes.php +963 -0
  100. backend/vendor/guzzlehttp/guzzle/src/Pool.php +322 -0
  101. backend/vendor/guzzlehttp/guzzle/src/Post/MultipartBody.php +109 -0
  102. backend/vendor/guzzlehttp/guzzle/src/Post/PostBody.php +287 -0
  103. backend/vendor/guzzlehttp/guzzle/src/Post/PostBodyInterface.php +116 -0
  104. backend/vendor/guzzlehttp/guzzle/src/Post/PostFile.php +135 -0
  105. backend/vendor/guzzlehttp/guzzle/src/Post/PostFileInterface.php +41 -0
  106. backend/vendor/guzzlehttp/guzzle/src/Query.php +204 -0
  107. backend/vendor/guzzlehttp/guzzle/src/QueryParser.php +163 -0
  108. backend/vendor/guzzlehttp/guzzle/src/RequestFsm.php +233 -0
  109. backend/vendor/guzzlehttp/guzzle/src/RingBridge.php +170 -0
  110. backend/vendor/guzzlehttp/guzzle/src/Subscriber/Cookie.php +58 -0
  111. backend/vendor/guzzlehttp/guzzle/src/Subscriber/History.php +172 -0
  112. backend/vendor/guzzlehttp/guzzle/src/Subscriber/HttpError.php +36 -0
  113. backend/vendor/guzzlehttp/guzzle/src/Subscriber/Mock.php +132 -0
  114. backend/vendor/guzzlehttp/guzzle/src/Subscriber/Prepare.php +130 -0
  115. backend/vendor/guzzlehttp/guzzle/src/Subscriber/Redirect.php +176 -0
  116. backend/vendor/guzzlehttp/guzzle/src/ToArrayInterface.php +15 -0
  117. backend/vendor/guzzlehttp/guzzle/src/Transaction.php +103 -0
  118. backend/vendor/guzzlehttp/guzzle/src/UriTemplate.php +241 -0
  119. backend/vendor/guzzlehttp/guzzle/src/Url.php +595 -0
  120. backend/vendor/guzzlehttp/guzzle/src/Utils.php +145 -0
  121. backend/vendor/guzzlehttp/ringphp/.gitignore +4 -0
  122. backend/vendor/guzzlehttp/ringphp/.travis.yml +21 -0
  123. backend/vendor/guzzlehttp/ringphp/CHANGELOG.md +34 -0
  124. backend/vendor/guzzlehttp/ringphp/LICENSE +19 -0
  125. backend/vendor/guzzlehttp/ringphp/Makefile +46 -0
  126. backend/vendor/guzzlehttp/ringphp/README.rst +46 -0
  127. backend/vendor/guzzlehttp/ringphp/composer.json +38 -0
  128. backend/vendor/guzzlehttp/ringphp/docs/Makefile +153 -0
  129. backend/vendor/guzzlehttp/ringphp/docs/client_handlers.rst +173 -0
  130. backend/vendor/guzzlehttp/ringphp/docs/client_middleware.rst +165 -0
  131. backend/vendor/guzzlehttp/ringphp/docs/conf.py +23 -0
  132. backend/vendor/guzzlehttp/ringphp/docs/futures.rst +164 -0
  133. backend/vendor/guzzlehttp/ringphp/docs/index.rst +50 -0
  134. backend/vendor/guzzlehttp/ringphp/docs/requirements.txt +1 -0
  135. backend/vendor/guzzlehttp/ringphp/docs/spec.rst +311 -0
  136. backend/vendor/guzzlehttp/ringphp/docs/testing.rst +74 -0
  137. backend/vendor/guzzlehttp/ringphp/phpunit.xml.dist +14 -0
  138. backend/vendor/guzzlehttp/ringphp/src/Client/ClientUtils.php +74 -0
  139. backend/vendor/guzzlehttp/ringphp/src/Client/CurlFactory.php +546 -0
  140. backend/vendor/guzzlehttp/ringphp/src/Client/CurlHandler.php +117 -0
  141. backend/vendor/guzzlehttp/ringphp/src/Client/CurlMultiHandler.php +239 -0
  142. backend/vendor/guzzlehttp/ringphp/src/Client/Middleware.php +58 -0
  143. backend/vendor/guzzlehttp/ringphp/src/Client/MockHandler.php +52 -0
  144. backend/vendor/guzzlehttp/ringphp/src/Client/StreamHandler.php +412 -0
  145. backend/vendor/guzzlehttp/ringphp/src/Core.php +364 -0
  146. backend/vendor/guzzlehttp/ringphp/src/Exception/CancelledException.php +7 -0
  147. backend/vendor/guzzlehttp/ringphp/src/Exception/CancelledFutureAccessException.php +4 -0
  148. backend/vendor/guzzlehttp/ringphp/src/Exception/ConnectException.php +7 -0
  149. backend/vendor/guzzlehttp/ringphp/src/Exception/RingException.php +4 -0
  150. backend/vendor/guzzlehttp/ringphp/src/Future/BaseFutureTrait.php +125 -0
  151. backend/vendor/guzzlehttp/ringphp/src/Future/CompletedFutureArray.php +43 -0
  152. backend/vendor/guzzlehttp/ringphp/src/Future/CompletedFutureValue.php +57 -0
  153. backend/vendor/guzzlehttp/ringphp/src/Future/FutureArray.php +40 -0
  154. backend/vendor/guzzlehttp/ringphp/src/Future/FutureArrayInterface.php +11 -0
  155. backend/vendor/guzzlehttp/ringphp/src/Future/FutureInterface.php +56 -0
  156. backend/vendor/guzzlehttp/ringphp/src/Future/FutureValue.php +12 -0
  157. backend/vendor/guzzlehttp/ringphp/src/Future/MagicFutureTrait.php +32 -0
  158. backend/vendor/guzzlehttp/ringphp/tests/Client/CurlFactoryTest.php +792 -0
  159. backend/vendor/guzzlehttp/ringphp/tests/Client/CurlHandlerTest.php +96 -0
  160. backend/vendor/guzzlehttp/ringphp/tests/Client/CurlMultiHandlerTest.php +165 -0
  161. backend/vendor/guzzlehttp/ringphp/tests/Client/MiddlewareTest.php +65 -0
  162. backend/vendor/guzzlehttp/ringphp/tests/Client/MockHandlerTest.php +86 -0
  163. backend/vendor/guzzlehttp/ringphp/tests/Client/Server.php +183 -0
  164. backend/vendor/guzzlehttp/ringphp/tests/Client/StreamHandlerTest.php +479 -0
  165. backend/vendor/guzzlehttp/ringphp/tests/Client/server.js +230 -0
  166. backend/vendor/guzzlehttp/ringphp/tests/CoreTest.php +336 -0
  167. backend/vendor/guzzlehttp/ringphp/tests/Future/CompletedFutureArrayTest.php +21 -0
  168. backend/vendor/guzzlehttp/ringphp/tests/Future/CompletedFutureValueTest.php +46 -0
  169. backend/vendor/guzzlehttp/ringphp/tests/Future/FutureArrayTest.php +56 -0
  170. backend/vendor/guzzlehttp/ringphp/tests/Future/FutureValueTest.php +109 -0
  171. backend/vendor/guzzlehttp/ringphp/tests/bootstrap.php +11 -0
  172. backend/vendor/guzzlehttp/streams/.gitignore +6 -0
  173. backend/vendor/guzzlehttp/streams/.travis.yml +17 -0
  174. backend/vendor/guzzlehttp/streams/CHANGELOG.rst +94 -0
  175. backend/vendor/guzzlehttp/streams/LICENSE +19 -0
  176. backend/vendor/guzzlehttp/streams/Makefile +19 -0
  177. backend/vendor/guzzlehttp/streams/README.rst +36 -0
  178. backend/vendor/guzzlehttp/streams/composer.json +28 -0
  179. backend/vendor/guzzlehttp/streams/phpunit.xml.dist +17 -0
  180. backend/vendor/guzzlehttp/streams/src/AppendStream.php +220 -0
  181. backend/vendor/guzzlehttp/streams/src/AsyncReadStream.php +207 -0
  182. backend/vendor/guzzlehttp/streams/src/BufferStream.php +138 -0
  183. backend/vendor/guzzlehttp/streams/src/CachingStream.php +122 -0
  184. backend/vendor/guzzlehttp/streams/src/DroppingStream.php +42 -0
  185. backend/vendor/guzzlehttp/streams/src/Exception/CannotAttachException.php +4 -0
  186. backend/vendor/guzzlehttp/streams/src/Exception/SeekException.php +27 -0
  187. backend/vendor/guzzlehttp/streams/src/FnStream.php +147 -0
  188. backend/vendor/guzzlehttp/streams/src/GuzzleStreamWrapper.php +117 -0
  189. backend/vendor/guzzlehttp/streams/src/InflateStream.php +27 -0
  190. backend/vendor/guzzlehttp/streams/src/LazyOpenStream.php +37 -0
  191. backend/vendor/guzzlehttp/streams/src/LimitStream.php +161 -0
  192. backend/vendor/guzzlehttp/streams/src/MetadataStreamInterface.php +11 -0
  193. backend/vendor/guzzlehttp/streams/src/NoSeekStream.php +25 -0
  194. backend/vendor/guzzlehttp/streams/src/NullStream.php +78 -0
  195. backend/vendor/guzzlehttp/streams/src/PumpStream.php +161 -0
  196. backend/vendor/guzzlehttp/streams/src/Stream.php +261 -0
  197. backend/vendor/guzzlehttp/streams/src/StreamDecoratorTrait.php +143 -0
  198. backend/vendor/guzzlehttp/streams/src/StreamInterface.php +159 -0
  199. backend/vendor/guzzlehttp/streams/src/Utils.php +196 -0
  200. backend/vendor/guzzlehttp/streams/tests/AppendStreamTest.php +178 -0
  201. backend/vendor/guzzlehttp/streams/tests/AsyncReadStreamTest.php +186 -0
  202. backend/vendor/guzzlehttp/streams/tests/BufferStreamTest.php +69 -0
  203. backend/vendor/guzzlehttp/streams/tests/CachingStreamTest.php +136 -0
  204. backend/vendor/guzzlehttp/streams/tests/DroppingStreamTest.php +26 -0
  205. backend/vendor/guzzlehttp/streams/tests/Exception/SeekExceptionTest.php +16 -0
  206. backend/vendor/guzzlehttp/streams/tests/FnStreamTest.php +89 -0
  207. backend/vendor/guzzlehttp/streams/tests/GuzzleStreamWrapperTest.php +99 -0
  208. backend/vendor/guzzlehttp/streams/tests/InflateStreamTest.php +16 -0
  209. backend/vendor/guzzlehttp/streams/tests/LazyOpenStreamTest.php +64 -0
  210. backend/vendor/guzzlehttp/streams/tests/LimitStreamTest.php +133 -0
  211. backend/vendor/guzzlehttp/streams/tests/NoSeekStreamTest.php +41 -0
  212. backend/vendor/guzzlehttp/streams/tests/NullStreamTest.php +39 -0
  213. backend/vendor/guzzlehttp/streams/tests/PumpStreamTest.php +77 -0
  214. backend/vendor/guzzlehttp/streams/tests/StreamDecoratorTraitTest.php +147 -0
  215. backend/vendor/guzzlehttp/streams/tests/StreamTest.php +252 -0
  216. backend/vendor/guzzlehttp/streams/tests/UtilsTest.php +155 -0
  217. backend/vendor/react/promise/.gitignore +4 -0
  218. backend/vendor/react/promise/.travis.yml +13 -0
  219. backend/vendor/react/promise/CHANGELOG.md +60 -0
  220. backend/vendor/react/promise/LICENSE +22 -0
  221. backend/vendor/react/promise/README.md +824 -0
  222. backend/vendor/react/promise/composer.json +22 -0
  223. backend/vendor/react/promise/phpunit.xml.dist +25 -0
  224. backend/vendor/react/promise/src/CancellablePromiseInterface.php +11 -0
  225. backend/vendor/react/promise/src/Deferred.php +60 -0
  226. backend/vendor/react/promise/src/ExtendedPromiseInterface.php +26 -0
  227. backend/vendor/react/promise/src/FulfilledPromise.php +68 -0
  228. backend/vendor/react/promise/src/LazyPromise.php +58 -0
  229. backend/vendor/react/promise/src/Promise.php +182 -0
  230. backend/vendor/react/promise/src/PromiseInterface.php +11 -0
  231. backend/vendor/react/promise/src/PromisorInterface.php +11 -0
  232. backend/vendor/react/promise/src/RejectedPromise.php +74 -0
  233. backend/vendor/react/promise/src/UnhandledRejectionException.php +31 -0
  234. backend/vendor/react/promise/src/functions.php +196 -0
  235. backend/vendor/react/promise/src/functions_include.php +5 -0
  236. backend/vendor/react/promise/tests/DeferredTest.php +42 -0
  237. backend/vendor/react/promise/tests/FulfilledPromiseTest.php +50 -0
  238. backend/vendor/react/promise/tests/FunctionAllTest.php +97 -0
  239. backend/vendor/react/promise/tests/FunctionAnyTest.php +116 -0
  240. backend/vendor/react/promise/tests/FunctionCheckTypehintTest.php +118 -0
  241. backend/vendor/react/promise/tests/FunctionMapTest.php +125 -0
  242. backend/vendor/react/promise/tests/FunctionRaceTest.php +122 -0
  243. backend/vendor/react/promise/tests/FunctionReduceTest.php +0 -0
LICENSE.txt ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Heise Zeitschriften Verlag GmbH & Co. KG and other contributors.
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
13
+ all 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
21
+ THE SOFTWARE.
22
+
23
+ Copyright (c) 2014 by 3UU productions ("Ritze")
24
+ Same as above for my Wordpress plugin.
admin.css ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .shariff_admininfo_cross {
2
+ float:right;
3
+ margin-top:6px;
4
+ }
5
+ .shariff_cross_icon {
6
+ line-height: 1;
7
+ text-align: center;
8
+ width: 20px;
9
+ text-decoration: none;
10
+ }
11
+ .shariff_cross_icon::before {
12
+ content:"\00D7";
13
+ font-weight:bold;
14
+ font-size:2em;
15
+ }
backend/index.php ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once __DIR__.'/vendor/autoload.php';
3
+
4
+ use Heise\Shariff\Backend;
5
+ use Zend\Config\Reader\Json;
6
+
7
+ class Application{
8
+ public static function run(){
9
+ header('Content-type: application/json');
10
+ // exit if now host is given
11
+ if (!isset($_GET["url"])) { echo json_encode(null); return; }
12
+
13
+ // if we have a json config file
14
+ if(is_readable(dirname( __FILE__ ).'/shariff.json')){
15
+ $reader = new \Zend\Config\Reader\Json();
16
+ $tmp=$reader->fromFile(dirname( __FILE__ ).'/shariff.json');
17
+ }
18
+
19
+ // check, if user has changed it to his domain
20
+ if(($tmp['domain']=='www.example.com') || ($tmp['domain']=='www.heise.de') || empty($tmp['domain'])) $tmp['domain']=$_SERVER['HTTP_HOST'];
21
+ // check mandatory services array
22
+ if(!is_array($tmp["services"])) $tmp["services"]=array("0"=>"GooglePlus",
23
+ "1"=>"Twitter",
24
+ "2"=>"Facebook",
25
+ "3"=>"LinkedIn",
26
+ "4"=>"Reddit",
27
+ "5"=>"Flattr",
28
+ "6"=>"StumbleUpon",
29
+ "7"=>"Pinterest",
30
+ "8"=>"Xing");
31
+ // if we have a constant for the ttl (default is 60 s)
32
+ if(defined('SHARIFF_BACKEND_TTL'))$tmp["cache"]["ttl"]=SHARIFF_BACKEND_TTL;
33
+ // if we have a constant for the tmp-dir
34
+ if(defined('SHARIFF_BACKEND_TMPDIR'))$tmp["cache"]["cacheDir"]=SHARIFF_BACKEND_TMPDIR;
35
+ // if we do not have a tmp-dir, we use the content dir of WP
36
+ if( empty($tmp["cache"]["cacheDir"]) ){
37
+ // force a short init because we only need WP core
38
+ define( 'SHORTINIT', true );
39
+ // build the wp-load/-config.php path
40
+ $wp_root_path = dirname( dirname( dirname( dirname( dirname( __FILE__ ) ) ) ) );
41
+ // include the config
42
+ include ( $wp_root_path . '/wp-config.php' );
43
+ // include wp-load.php file (that loads wp-config.php and bootstraps WP)
44
+ require( $wp_root_path . '/wp-load.php' );
45
+ // include for needed untrailingslashit()
46
+ require( $wp_root_path . '/wp-includes/formatting.php');
47
+ // to avoid conficts with other plugins and actual uploads we use a fixed date in the past
48
+ // month of my birthday would be great ;-) The wp_upload_dir() create the dir if not exists.
49
+ $upload_dir = @wp_upload_dir('1970/01');
50
+ $tmp["cache"]["cacheDir"]=$upload_dir['basedir'].'/1970/01';
51
+ }
52
+
53
+ // final check that temp dir is usuable
54
+ if(!is_writable($tmp["cache"]["cacheDir"]))die("No usable tmp dir found. Please check ". $tmp["cache"]["cacheDir"]);
55
+
56
+ // start backend
57
+ $shariff = new Backend($tmp);
58
+ // draw result
59
+ echo json_encode($shariff->get($_GET["url"]));
60
+ }
61
+ }
62
+
63
+ Application::run();
backend/shariff.json.example ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cache": {
3
+ "ttl": 60,
4
+ "cacheDir": "/tmp"
5
+ },
6
+ "domain": "www.example.com",
7
+ "services": [
8
+ "GooglePlus",
9
+ "Twitter",
10
+ "Facebook",
11
+ "LinkedIn",
12
+ "Reddit",
13
+ "StumbleUpon",
14
+ "Flattr",
15
+ "Pinterest",
16
+ "Xing"
17
+ ]
18
+ }
backend/src/Backend.php ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Heise\Shariff;
4
+
5
+ use GuzzleHttp\Client;
6
+ use GuzzleHttp\Pool;
7
+ use Zend\Cache\Storage\Adapter\Filesystem;
8
+
9
+ class Backend
10
+ {
11
+
12
+ protected $baseCacheKey;
13
+ protected $cache;
14
+ protected $client;
15
+ protected $domain;
16
+ protected $services;
17
+
18
+ public function __construct($config)
19
+ {
20
+ $this->domain = $config["domain"];
21
+ $this->client = new Client();
22
+ $this->baseCacheKey = md5(json_encode($config));
23
+
24
+ $this->cache = new Filesystem();
25
+ $options = $this->cache->getOptions();
26
+ $options->setCacheDir(
27
+ array_key_exists("cacheDir", $config["cache"])
28
+ ? $config["cache"]["cacheDir"]
29
+ : sys_get_temp_dir()
30
+ );
31
+ $options->setNamespace('Shariff');
32
+ $options->setTtl($config["cache"]["ttl"]);
33
+
34
+ if (function_exists('register_postsend_function')) {
35
+ // for hhvm installations: executing after response / session close
36
+ register_postsend_function(function() {
37
+ $this->cache->clearExpired();
38
+ });
39
+ } else {
40
+ // default
41
+ $this->cache->clearExpired();
42
+ }
43
+
44
+ $this->services = $this->getServicesByName($config["services"]);
45
+ }
46
+
47
+ private function getServicesByName($serviceNames)
48
+ {
49
+ $services = array();
50
+ foreach ($serviceNames as $serviceName) {
51
+ $serviceName = 'Heise\Shariff\Backend\\'.$serviceName;
52
+ $services[] = new $serviceName();
53
+ }
54
+ return $services;
55
+ }
56
+
57
+ private function isValidDomain($url)
58
+ {
59
+ if ($this->domain) {
60
+ $parsed = parse_url($url);
61
+ if ($parsed["host"] != $this->domain) {
62
+ return false;
63
+ }
64
+ }
65
+ return true;
66
+ }
67
+
68
+ public function get($url)
69
+ {
70
+
71
+ // Aenderungen an der Konfiguration invalidieren den Cache
72
+ $cache_key = md5($url.$this->baseCacheKey);
73
+
74
+ if (!filter_var($url, FILTER_VALIDATE_URL)) {
75
+ return null;
76
+ }
77
+
78
+ if ($this->cache->hasItem($cache_key)) {
79
+ return json_decode($this->cache->getItem($cache_key), true);
80
+ }
81
+
82
+ if (!$this->isValidDomain($url)) {
83
+ return null;
84
+ }
85
+
86
+ $requests = array_map(
87
+ function ($service) use ($url) {
88
+ return $service->getRequest($url);
89
+ },
90
+ $this->services
91
+ );
92
+
93
+ $results = Pool::batch($this->client, $requests);
94
+
95
+ $counts = array();
96
+ $i = 0;
97
+ foreach ($this->services as $service) {
98
+ if (method_exists($results[$i], "json")) {
99
+ try {
100
+ $counts[ $service->getName() ] = intval($service->extractCount($results[$i]->json()));
101
+ } catch (\Exception $e) {
102
+ // Skip service if broken
103
+ }
104
+ }
105
+ $i++;
106
+ }
107
+
108
+ $this->cache->setItem($cache_key, json_encode($counts));
109
+
110
+ return $counts;
111
+ }
112
+ }
backend/src/Backend/Facebook.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Heise\Shariff\Backend;
4
+
5
+ class Facebook extends Request implements ServiceInterface
6
+ {
7
+
8
+ public function getName()
9
+ {
10
+ return 'facebook';
11
+ }
12
+
13
+ public function getRequest($url)
14
+ {
15
+ $fql = 'https://graph.facebook.com/fql?q=SELECT total_count FROM link_stat WHERE url="'.$url.'"';
16
+ return $this->createRequest($fql);
17
+ }
18
+
19
+ public function extractCount($data)
20
+ {
21
+ return (isset($data['data']) && isset($data['data'][0]) && isset($data['data'][0]['total_count']))
22
+ ? $data['data'][0]['total_count'] : 0;
23
+ }
24
+ }
backend/src/Backend/Flattr.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Heise\Shariff\Backend;
4
+
5
+ class Flattr extends Request implements ServiceInterface
6
+ {
7
+
8
+ public function getName()
9
+ {
10
+ return 'flattr';
11
+ }
12
+
13
+ public function getRequest($url)
14
+ {
15
+ $url = 'https://api.flattr.com/rest/v2/things/lookup/?url='.urlencode($url);
16
+ return $this->createRequest($url);
17
+ }
18
+
19
+ public function extractCount($data)
20
+ {
21
+ return (isset($data['flattrs'])) ? $data['flattrs'] : 0;
22
+ }
23
+ }
backend/src/Backend/GooglePlus.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Heise\Shariff\Backend;
4
+
5
+ class GooglePlus extends Request implements ServiceInterface
6
+ {
7
+
8
+ public function getName()
9
+ {
10
+ return 'googleplus';
11
+ }
12
+
13
+ public function getRequest($url)
14
+ {
15
+ $gPlusUrl = 'https://clients6.google.com/rpc?key=AIzaSyCKSbrvQasunBoV16zDH9R33D88CeLr9gQ';
16
+ $json = array(
17
+ 'method' => 'pos.plusones.get',
18
+ 'id' => 'p',
19
+ 'params' => array(
20
+ 'nolog' => 'true',
21
+ 'id' => $url,
22
+ 'source' => 'widget',
23
+ 'userId' => '@viewer',
24
+ 'groupId' => '@self'
25
+ ),
26
+ 'jsonrpc' => '2.0',
27
+ 'key' => 'p',
28
+ 'apiVersion' => 'v1'
29
+ );
30
+ return $this->createRequest($gPlusUrl, 'POST', array('json' => $json));
31
+ }
32
+
33
+ public function extractCount($data)
34
+ {
35
+ return $data['result']['metadata']['globalCounts']['count'];
36
+ }
37
+ }
backend/src/Backend/LinkedIn.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Heise\Shariff\Backend;
4
+
5
+ class LinkedIn extends Request implements ServiceInterface
6
+ {
7
+
8
+ public function getName()
9
+ {
10
+ return 'linkedin';
11
+ }
12
+
13
+ public function getRequest($url)
14
+ {
15
+ $url = 'https://www.linkedin.com/countserv/count/share?url='.urlencode($url).'&lang=de_DE&format=json';
16
+ return $this->createRequest($url);
17
+ }
18
+
19
+ public function extractCount($data)
20
+ {
21
+ return $data['count'];
22
+ }
23
+ }
backend/src/Backend/Pinterest.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Heise\Shariff\Backend;
4
+
5
+ use GuzzleHttp\Event\CompleteEvent;
6
+ use GuzzleHttp\Stream\Stream;
7
+ use GuzzleHttp\Message\Response;
8
+
9
+ class Pinterest extends Request implements ServiceInterface
10
+ {
11
+
12
+ public function getName()
13
+ {
14
+ return 'pinterest';
15
+ }
16
+
17
+ public function getRequest($url)
18
+ {
19
+ $url = 'http://api.pinterest.com/v1/urls/count.json?callback=x&url='.urlencode($url);
20
+ $request = $this->createRequest($url);
21
+ $request->getEmitter()->on('complete', function (CompleteEvent $e) {
22
+ // Stripping the 'callback function' from the response
23
+ $body = $e->getResponse()->getBody()->getContents();
24
+ $e->intercept(new Response(200, array(), (Stream::factory(mb_substr($body, 2, mb_strlen($body) - 3)))));
25
+ });
26
+ return $request;
27
+ }
28
+
29
+ public function extractCount($data)
30
+ {
31
+ return $data['count'];
32
+ }
33
+ }
backend/src/Backend/Reddit.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Heise\Shariff\Backend;
4
+
5
+ class Reddit extends Request implements ServiceInterface
6
+ {
7
+
8
+ public function getName()
9
+ {
10
+ return 'reddit';
11
+ }
12
+
13
+ public function getRequest($url)
14
+ {
15
+ return $this->createRequest('https://www.reddit.com/api/info.json?url='.urlencode($url));
16
+ }
17
+
18
+ public function extractCount($data)
19
+ {
20
+ $count = 0;
21
+ foreach ($data['data']['children'] as $child) {
22
+ $count += $child['data']['score'];
23
+ }
24
+ return $count;
25
+ }
26
+ }
backend/src/Backend/Request.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Heise\Shariff\Backend;
4
+
5
+ use GuzzleHttp\Client;
6
+
7
+ abstract class Request
8
+ {
9
+
10
+ protected $client;
11
+
12
+ public function __construct()
13
+ {
14
+ $this->client = new Client();
15
+ }
16
+
17
+ protected function createRequest($url, $method = 'GET', $options = array())
18
+ {
19
+ // $defaults = array('future' => true, 'debug' => true);
20
+ $defaults = array('future' => true);
21
+
22
+ $req = $this->client->createRequest(
23
+ $method,
24
+ $url,
25
+ array_merge($defaults, $options)
26
+ );
27
+
28
+ return $req;
29
+ }
30
+ }
backend/src/Backend/ServiceInterface.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Heise\Shariff\Backend;
4
+
5
+ interface ServiceInterface
6
+ {
7
+ public function getRequest($url);
8
+ public function extractCount($data);
9
+ public function getName();
10
+ }
backend/src/Backend/StumbleUpon.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Heise\Shariff\Backend;
4
+
5
+ class StumbleUpon extends Request implements ServiceInterface
6
+ {
7
+
8
+ public function getName()
9
+ {
10
+ return 'stumbleupon';
11
+ }
12
+
13
+ public function getRequest($url)
14
+ {
15
+ return $this->createRequest('https://www.stumbleupon.com/services/1.01/badge.getinfo?url='.urlencode($url));
16
+ }
17
+
18
+ public function extractCount($data)
19
+ {
20
+ return (isset($data['result']['views'])) ? $data['result']['views']+0 : 0;
21
+ }
22
+ }
backend/src/Backend/Twitter.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Heise\Shariff\Backend;
4
+
5
+ class Twitter extends Request implements ServiceInterface
6
+ {
7
+
8
+ public function getName()
9
+ {
10
+ return 'twitter';
11
+ }
12
+
13
+ public function getRequest($url)
14
+ {
15
+ return $this->createRequest('https://cdn.api.twitter.com/1/urls/count.json?url='.urlencode($url));
16
+ }
17
+
18
+ public function extractCount($data)
19
+ {
20
+ return $data['count'];
21
+ }
22
+ }
backend/src/Backend/Xing.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Heise\Shariff\Backend;
4
+
5
+ class Xing extends Request implements ServiceInterface
6
+ {
7
+
8
+ public function getName()
9
+ {
10
+ return 'xing';
11
+ }
12
+
13
+ public function getRequest($url)
14
+ {
15
+ $request = $this->createRequest('https://www.xing-share.com/spi/shares/statistics', 'POST');
16
+ $request->getBody()->setField('url', $url);
17
+ return $request;
18
+ }
19
+
20
+ public function extractCount($data)
21
+ {
22
+ return $data['share_counter'];
23
+ }
24
+ }
backend/vendor/autoload.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload.php @generated by Composer
4
+
5
+ require_once __DIR__ . '/composer' . '/autoload_real.php';
6
+
7
+ return ComposerAutoloaderInit42c773bd7263c301a8af262571b7982a::getLoader();
backend/vendor/composer/ClassLoader.php ADDED
@@ -0,0 +1,387 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Composer.
5
+ *
6
+ * (c) Nils Adermann <naderman@naderman.de>
7
+ * Jordi Boggiano <j.boggiano@seld.be>
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ namespace Composer\Autoload;
14
+
15
+ /**
16
+ * ClassLoader implements a PSR-0 class loader
17
+ *
18
+ * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
19
+ *
20
+ * $loader = new \Composer\Autoload\ClassLoader();
21
+ *
22
+ * // register classes with namespaces
23
+ * $loader->add('Symfony\Component', __DIR__.'/component');
24
+ * $loader->add('Symfony', __DIR__.'/framework');
25
+ *
26
+ * // activate the autoloader
27
+ * $loader->register();
28
+ *
29
+ * // to enable searching the include path (eg. for PEAR packages)
30
+ * $loader->setUseIncludePath(true);
31
+ *
32
+ * In this example, if you try to use a class in the Symfony\Component
33
+ * namespace or one of its children (Symfony\Component\Console for instance),
34
+ * the autoloader will first look for the class under the component/
35
+ * directory, and it will then fallback to the framework/ directory if not
36
+ * found before giving up.
37
+ *
38
+ * This class is loosely based on the Symfony UniversalClassLoader.
39
+ *
40
+ * @author Fabien Potencier <fabien@symfony.com>
41
+ * @author Jordi Boggiano <j.boggiano@seld.be>
42
+ */
43
+ class ClassLoader
44
+ {
45
+ // PSR-4
46
+ private $prefixLengthsPsr4 = array();
47
+ private $prefixDirsPsr4 = array();
48
+ private $fallbackDirsPsr4 = array();
49
+
50
+ // PSR-0
51
+ private $prefixesPsr0 = array();
52
+ private $fallbackDirsPsr0 = array();
53
+
54
+ private $useIncludePath = false;
55
+ private $classMap = array();
56
+
57
+ public function getPrefixes()
58
+ {
59
+ if (!empty($this->prefixesPsr0)) {
60
+ return call_user_func_array('array_merge', $this->prefixesPsr0);
61
+ }
62
+
63
+ return array();
64
+ }
65
+
66
+ public function getPrefixesPsr4()
67
+ {
68
+ return $this->prefixDirsPsr4;
69
+ }
70
+
71
+ public function getFallbackDirs()
72
+ {
73
+ return $this->fallbackDirsPsr0;
74
+ }
75
+
76
+ public function getFallbackDirsPsr4()
77
+ {
78
+ return $this->fallbackDirsPsr4;
79
+ }
80
+
81
+ public function getClassMap()
82
+ {
83
+ return $this->classMap;
84
+ }
85
+
86
+ /**
87
+ * @param array $classMap Class to filename map
88
+ */
89
+ public function addClassMap(array $classMap)
90
+ {
91
+ if ($this->classMap) {
92
+ $this->classMap = array_merge($this->classMap, $classMap);
93
+ } else {
94
+ $this->classMap = $classMap;
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Registers a set of PSR-0 directories for a given prefix, either
100
+ * appending or prepending to the ones previously set for this prefix.
101
+ *
102
+ * @param string $prefix The prefix
103
+ * @param array|string $paths The PSR-0 root directories
104
+ * @param bool $prepend Whether to prepend the directories
105
+ */
106
+ public function add($prefix, $paths, $prepend = false)
107
+ {
108
+ if (!$prefix) {
109
+ if ($prepend) {
110
+ $this->fallbackDirsPsr0 = array_merge(
111
+ (array) $paths,
112
+ $this->fallbackDirsPsr0
113
+ );
114
+ } else {
115
+ $this->fallbackDirsPsr0 = array_merge(
116
+ $this->fallbackDirsPsr0,
117
+ (array) $paths
118
+ );
119
+ }
120
+
121
+ return;
122
+ }
123
+
124
+ $first = $prefix[0];
125
+ if (!isset($this->prefixesPsr0[$first][$prefix])) {
126
+ $this->prefixesPsr0[$first][$prefix] = (array) $paths;
127
+
128
+ return;
129
+ }
130
+ if ($prepend) {
131
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
132
+ (array) $paths,
133
+ $this->prefixesPsr0[$first][$prefix]
134
+ );
135
+ } else {
136
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
137
+ $this->prefixesPsr0[$first][$prefix],
138
+ (array) $paths
139
+ );
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Registers a set of PSR-4 directories for a given namespace, either
145
+ * appending or prepending to the ones previously set for this namespace.
146
+ *
147
+ * @param string $prefix The prefix/namespace, with trailing '\\'
148
+ * @param array|string $paths The PSR-0 base directories
149
+ * @param bool $prepend Whether to prepend the directories
150
+ *
151
+ * @throws \InvalidArgumentException
152
+ */
153
+ public function addPsr4($prefix, $paths, $prepend = false)
154
+ {
155
+ if (!$prefix) {
156
+ // Register directories for the root namespace.
157
+ if ($prepend) {
158
+ $this->fallbackDirsPsr4 = array_merge(
159
+ (array) $paths,
160
+ $this->fallbackDirsPsr4
161
+ );
162
+ } else {
163
+ $this->fallbackDirsPsr4 = array_merge(
164
+ $this->fallbackDirsPsr4,
165
+ (array) $paths
166
+ );
167
+ }
168
+ } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
169
+ // Register directories for a new namespace.
170
+ $length = strlen($prefix);
171
+ if ('\\' !== $prefix[$length - 1]) {
172
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
173
+ }
174
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
175
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
176
+ } elseif ($prepend) {
177
+ // Prepend directories for an already registered namespace.
178
+ $this->prefixDirsPsr4[$prefix] = array_merge(
179
+ (array) $paths,
180
+ $this->prefixDirsPsr4[$prefix]
181
+ );
182
+ } else {
183
+ // Append directories for an already registered namespace.
184
+ $this->prefixDirsPsr4[$prefix] = array_merge(
185
+ $this->prefixDirsPsr4[$prefix],
186
+ (array) $paths
187
+ );
188
+ }
189
+ }
190
+
191
+ /**
192
+ * Registers a set of PSR-0 directories for a given prefix,
193
+ * replacing any others previously set for this prefix.
194
+ *
195
+ * @param string $prefix The prefix
196
+ * @param array|string $paths The PSR-0 base directories
197
+ */
198
+ public function set($prefix, $paths)
199
+ {
200
+ if (!$prefix) {
201
+ $this->fallbackDirsPsr0 = (array) $paths;
202
+ } else {
203
+ $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
204
+ }
205
+ }
206
+
207
+ /**
208
+ * Registers a set of PSR-4 directories for a given namespace,
209
+ * replacing any others previously set for this namespace.
210
+ *
211
+ * @param string $prefix The prefix/namespace, with trailing '\\'
212
+ * @param array|string $paths The PSR-4 base directories
213
+ *
214
+ * @throws \InvalidArgumentException
215
+ */
216
+ public function setPsr4($prefix, $paths)
217
+ {
218
+ if (!$prefix) {
219
+ $this->fallbackDirsPsr4 = (array) $paths;
220
+ } else {
221
+ $length = strlen($prefix);
222
+ if ('\\' !== $prefix[$length - 1]) {
223
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
224
+ }
225
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
226
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
227
+ }
228
+ }
229
+
230
+ /**
231
+ * Turns on searching the include path for class files.
232
+ *
233
+ * @param bool $useIncludePath
234
+ */
235
+ public function setUseIncludePath($useIncludePath)
236
+ {
237
+ $this->useIncludePath = $useIncludePath;
238
+ }
239
+
240
+ /**
241
+ * Can be used to check if the autoloader uses the include path to check
242
+ * for classes.
243
+ *
244
+ * @return bool
245
+ */
246
+ public function getUseIncludePath()
247
+ {
248
+ return $this->useIncludePath;
249
+ }
250
+
251
+ /**
252
+ * Registers this instance as an autoloader.
253
+ *
254
+ * @param bool $prepend Whether to prepend the autoloader or not
255
+ */
256
+ public function register($prepend = false)
257
+ {
258
+ spl_autoload_register(array($this, 'loadClass'), true, $prepend);
259
+ }
260
+
261
+ /**
262
+ * Unregisters this instance as an autoloader.
263
+ */
264
+ public function unregister()
265
+ {
266
+ spl_autoload_unregister(array($this, 'loadClass'));
267
+ }
268
+
269
+ /**
270
+ * Loads the given class or interface.
271
+ *
272
+ * @param string $class The name of the class
273
+ * @return bool|null True if loaded, null otherwise
274
+ */
275
+ public function loadClass($class)
276
+ {
277
+ if ($file = $this->findFile($class)) {
278
+ includeFile($file);
279
+
280
+ return true;
281
+ }
282
+ }
283
+
284
+ /**
285
+ * Finds the path to the file where the class is defined.
286
+ *
287
+ * @param string $class The name of the class
288
+ *
289
+ * @return string|false The path if found, false otherwise
290
+ */
291
+ public function findFile($class)
292
+ {
293
+ // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
294
+ if ('\\' == $class[0]) {
295
+ $class = substr($class, 1);
296
+ }
297
+
298
+ // class map lookup
299
+ if (isset($this->classMap[$class])) {
300
+ return $this->classMap[$class];
301
+ }
302
+
303
+ $file = $this->findFileWithExtension($class, '.php');
304
+
305
+ // Search for Hack files if we are running on HHVM
306
+ if ($file === null && defined('HHVM_VERSION')) {
307
+ $file = $this->findFileWithExtension($class, '.hh');
308
+ }
309
+
310
+ if ($file === null) {
311
+ // Remember that this class does not exist.
312
+ return $this->classMap[$class] = false;
313
+ }
314
+
315
+ return $file;
316
+ }
317
+
318
+ private function findFileWithExtension($class, $ext)
319
+ {
320
+ // PSR-4 lookup
321
+ $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
322
+
323
+ $first = $class[0];
324
+ if (isset($this->prefixLengthsPsr4[$first])) {
325
+ foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
326
+ if (0 === strpos($class, $prefix)) {
327
+ foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
328
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
329
+ return $file;
330
+ }
331
+ }
332
+ }
333
+ }
334
+ }
335
+
336
+ // PSR-4 fallback dirs
337
+ foreach ($this->fallbackDirsPsr4 as $dir) {
338
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
339
+ return $file;
340
+ }
341
+ }
342
+
343
+ // PSR-0 lookup
344
+ if (false !== $pos = strrpos($class, '\\')) {
345
+ // namespaced class name
346
+ $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
347
+ . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
348
+ } else {
349
+ // PEAR-like class name
350
+ $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
351
+ }
352
+
353
+ if (isset($this->prefixesPsr0[$first])) {
354
+ foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
355
+ if (0 === strpos($class, $prefix)) {
356
+ foreach ($dirs as $dir) {
357
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
358
+ return $file;
359
+ }
360
+ }
361
+ }
362
+ }
363
+ }
364
+
365
+ // PSR-0 fallback dirs
366
+ foreach ($this->fallbackDirsPsr0 as $dir) {
367
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
368
+ return $file;
369
+ }
370
+ }
371
+
372
+ // PSR-0 include paths.
373
+ if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
374
+ return $file;
375
+ }
376
+ }
377
+ }
378
+
379
+ /**
380
+ * Scope isolated include.
381
+ *
382
+ * Prevents access to $this/self from included files.
383
+ */
384
+ function includeFile($file)
385
+ {
386
+ include $file;
387
+ }
backend/vendor/composer/autoload_classmap.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_classmap.php @generated by Composer
4
+
5
+ $vendorDir = dirname(dirname(__FILE__));
6
+ $baseDir = dirname($vendorDir);
7
+
8
+ return array(
9
+ );
backend/vendor/composer/autoload_files.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_files.php @generated by Composer
4
+
5
+ $vendorDir = dirname(dirname(__FILE__));
6
+ $baseDir = dirname($vendorDir);
7
+
8
+ return array(
9
+ $vendorDir . '/react/promise/src/functions_include.php',
10
+ );
backend/vendor/composer/autoload_namespaces.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_namespaces.php @generated by Composer
4
+
5
+ $vendorDir = dirname(dirname(__FILE__));
6
+ $baseDir = dirname($vendorDir);
7
+
8
+ return array(
9
+ 'Zend\\Stdlib\\' => array($vendorDir . '/zendframework/zend-stdlib'),
10
+ 'Zend\\ServiceManager\\' => array($vendorDir . '/zendframework/zend-servicemanager'),
11
+ 'Zend\\Json\\' => array($vendorDir . '/zendframework/zend-json'),
12
+ 'Zend\\EventManager\\' => array($vendorDir . '/zendframework/zend-eventmanager'),
13
+ 'Zend\\Config\\' => array($vendorDir . '/zendframework/zend-config'),
14
+ 'Zend\\Cache\\' => array($vendorDir . '/zendframework/zend-cache'),
15
+ );
backend/vendor/composer/autoload_psr4.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_psr4.php @generated by Composer
4
+
5
+ $vendorDir = dirname(dirname(__FILE__));
6
+ $baseDir = dirname($vendorDir);
7
+
8
+ return array(
9
+ 'React\\Promise\\' => array($vendorDir . '/react/promise/src'),
10
+ 'Heise\\Shariff\\' => array($baseDir . '/src'),
11
+ 'GuzzleHttp\\Stream\\' => array($vendorDir . '/guzzlehttp/streams/src'),
12
+ 'GuzzleHttp\\Ring\\' => array($vendorDir . '/guzzlehttp/ringphp/src'),
13
+ 'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),
14
+ );
backend/vendor/composer/autoload_real.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_real.php @generated by Composer
4
+
5
+ class ComposerAutoloaderInit42c773bd7263c301a8af262571b7982a
6
+ {
7
+ private static $loader;
8
+
9
+ public static function loadClassLoader($class)
10
+ {
11
+ if ('Composer\Autoload\ClassLoader' === $class) {
12
+ require __DIR__ . '/ClassLoader.php';
13
+ }
14
+ }
15
+
16
+ public static function getLoader()
17
+ {
18
+ if (null !== self::$loader) {
19
+ return self::$loader;
20
+ }
21
+
22
+ spl_autoload_register(array('ComposerAutoloaderInit42c773bd7263c301a8af262571b7982a', 'loadClassLoader'), true, true);
23
+ self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInit42c773bd7263c301a8af262571b7982a', 'loadClassLoader'));
25
+
26
+ $map = require __DIR__ . '/autoload_namespaces.php';
27
+ foreach ($map as $namespace => $path) {
28
+ $loader->set($namespace, $path);
29
+ }
30
+
31
+ $map = require __DIR__ . '/autoload_psr4.php';
32
+ foreach ($map as $namespace => $path) {
33
+ $loader->setPsr4($namespace, $path);
34
+ }
35
+
36
+ $classMap = require __DIR__ . '/autoload_classmap.php';
37
+ if ($classMap) {
38
+ $loader->addClassMap($classMap);
39
+ }
40
+
41
+ $loader->register(true);
42
+
43
+ $includeFiles = require __DIR__ . '/autoload_files.php';
44
+ foreach ($includeFiles as $file) {
45
+ composerRequire42c773bd7263c301a8af262571b7982a($file);
46
+ }
47
+
48
+ return $loader;
49
+ }
50
+ }
51
+
52
+ function composerRequire42c773bd7263c301a8af262571b7982a($file)
53
+ {
54
+ require $file;
55
+ }
backend/vendor/composer/installed.json ADDED
@@ -0,0 +1,527 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "name": "guzzlehttp/streams",
4
+ "version": "3.0.0",
5
+ "version_normalized": "3.0.0.0",
6
+ "source": {
7
+ "type": "git",
8
+ "url": "https://github.com/guzzle/streams.git",
9
+ "reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5"
10
+ },
11
+ "dist": {
12
+ "type": "zip",
13
+ "url": "https://api.github.com/repos/guzzle/streams/zipball/47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5",
14
+ "reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5",
15
+ "shasum": ""
16
+ },
17
+ "require": {
18
+ "php": ">=5.4.0"
19
+ },
20
+ "require-dev": {
21
+ "phpunit/phpunit": "~4.0"
22
+ },
23
+ "time": "2014-10-12 19:18:40",
24
+ "type": "library",
25
+ "extra": {
26
+ "branch-alias": {
27
+ "dev-master": "3.0-dev"
28
+ }
29
+ },
30
+ "installation-source": "dist",
31
+ "autoload": {
32
+ "psr-4": {
33
+ "GuzzleHttp\\Stream\\": "src/"
34
+ }
35
+ },
36
+ "notification-url": "https://packagist.org/downloads/",
37
+ "license": [
38
+ "MIT"
39
+ ],
40
+ "authors": [
41
+ {
42
+ "name": "Michael Dowling",
43
+ "email": "mtdowling@gmail.com",
44
+ "homepage": "https://github.com/mtdowling"
45
+ }
46
+ ],
47
+ "description": "Provides a simple abstraction over streams of data",
48
+ "homepage": "http://guzzlephp.org/",
49
+ "keywords": [
50
+ "Guzzle",
51
+ "stream"
52
+ ]
53
+ },
54
+ {
55
+ "name": "zendframework/zend-stdlib",
56
+ "version": "2.3.3",
57
+ "version_normalized": "2.3.3.0",
58
+ "target-dir": "Zend/Stdlib",
59
+ "source": {
60
+ "type": "git",
61
+ "url": "https://github.com/zendframework/Component_ZendStdlib.git",
62
+ "reference": "fa33e6647f830d0d2a1cb451efcdfe1bb9a66c33"
63
+ },
64
+ "dist": {
65
+ "type": "zip",
66
+ "url": "https://api.github.com/repos/zendframework/Component_ZendStdlib/zipball/fa33e6647f830d0d2a1cb451efcdfe1bb9a66c33",
67
+ "reference": "fa33e6647f830d0d2a1cb451efcdfe1bb9a66c33",
68
+ "shasum": ""
69
+ },
70
+ "require": {
71
+ "php": ">=5.3.23"
72
+ },
73
+ "require-dev": {
74
+ "zendframework/zend-eventmanager": "self.version",
75
+ "zendframework/zend-serializer": "self.version",
76
+ "zendframework/zend-servicemanager": "self.version"
77
+ },
78
+ "suggest": {
79
+ "zendframework/zend-eventmanager": "To support aggregate hydrator usage",
80
+ "zendframework/zend-serializer": "Zend\\Serializer component",
81
+ "zendframework/zend-servicemanager": "To support hydrator plugin manager usage"
82
+ },
83
+ "time": "2014-09-16 22:58:11",
84
+ "type": "library",
85
+ "extra": {
86
+ "branch-alias": {
87
+ "dev-master": "2.3-dev",
88
+ "dev-develop": "2.4-dev"
89
+ }
90
+ },
91
+ "installation-source": "dist",
92
+ "autoload": {
93
+ "psr-0": {
94
+ "Zend\\Stdlib\\": ""
95
+ }
96
+ },
97
+ "notification-url": "https://packagist.org/downloads/",
98
+ "license": [
99
+ "BSD-3-Clause"
100
+ ],
101
+ "homepage": "https://github.com/zendframework/zf2",
102
+ "keywords": [
103
+ "stdlib",
104
+ "zf2"
105
+ ]
106
+ },
107
+ {
108
+ "name": "zendframework/zend-eventmanager",
109
+ "version": "2.3.3",
110
+ "version_normalized": "2.3.3.0",
111
+ "target-dir": "Zend/EventManager",
112
+ "source": {
113
+ "type": "git",
114
+ "url": "https://github.com/zendframework/Component_ZendEventManager.git",
115
+ "reference": "4110fe64b10616b9bb71429a206d8e9e6d99e3ba"
116
+ },
117
+ "dist": {
118
+ "type": "zip",
119
+ "url": "https://api.github.com/repos/zendframework/Component_ZendEventManager/zipball/4110fe64b10616b9bb71429a206d8e9e6d99e3ba",
120
+ "reference": "4110fe64b10616b9bb71429a206d8e9e6d99e3ba",
121
+ "shasum": ""
122
+ },
123
+ "require": {
124
+ "php": ">=5.3.23",
125
+ "zendframework/zend-stdlib": "self.version"
126
+ },
127
+ "time": "2014-09-16 22:58:11",
128
+ "type": "library",
129
+ "extra": {
130
+ "branch-alias": {
131
+ "dev-master": "2.3-dev",
132
+ "dev-develop": "2.4-dev"
133
+ }
134
+ },
135
+ "installation-source": "dist",
136
+ "autoload": {
137
+ "psr-0": {
138
+ "Zend\\EventManager\\": ""
139
+ }
140
+ },
141
+ "notification-url": "https://packagist.org/downloads/",
142
+ "license": [
143
+ "BSD-3-Clause"
144
+ ],
145
+ "homepage": "https://github.com/zendframework/zf2",
146
+ "keywords": [
147
+ "eventmanager",
148
+ "zf2"
149
+ ]
150
+ },
151
+ {
152
+ "name": "zendframework/zend-servicemanager",
153
+ "version": "2.3.3",
154
+ "version_normalized": "2.3.3.0",
155
+ "target-dir": "Zend/ServiceManager",
156
+ "source": {
157
+ "type": "git",
158
+ "url": "https://github.com/zendframework/Component_ZendServiceManager.git",
159
+ "reference": "559403e4fd10db2516641f20f129a568d7e6a993"
160
+ },
161
+ "dist": {
162
+ "type": "zip",
163
+ "url": "https://api.github.com/repos/zendframework/Component_ZendServiceManager/zipball/559403e4fd10db2516641f20f129a568d7e6a993",
164
+ "reference": "559403e4fd10db2516641f20f129a568d7e6a993",
165
+ "shasum": ""
166
+ },
167
+ "require": {
168
+ "php": ">=5.3.23"
169
+ },
170
+ "require-dev": {
171
+ "zendframework/zend-di": "self.version"
172
+ },
173
+ "suggest": {
174
+ "zendframework/zend-di": "Zend\\Di component"
175
+ },
176
+ "time": "2014-09-16 22:58:11",
177
+ "type": "library",
178
+ "extra": {
179
+ "branch-alias": {
180
+ "dev-master": "2.3-dev",
181
+ "dev-develop": "2.4-dev"
182
+ }
183
+ },
184
+ "installation-source": "dist",
185
+ "autoload": {
186
+ "psr-0": {
187
+ "Zend\\ServiceManager\\": ""
188
+ }
189
+ },
190
+ "notification-url": "https://packagist.org/downloads/",
191
+ "license": [
192
+ "BSD-3-Clause"
193
+ ],
194
+ "homepage": "https://github.com/zendframework/zf2",
195
+ "keywords": [
196
+ "servicemanager",
197
+ "zf2"
198
+ ]
199
+ },
200
+ {
201
+ "name": "zendframework/zend-cache",
202
+ "version": "2.3.3",
203
+ "version_normalized": "2.3.3.0",
204
+ "target-dir": "Zend/Cache",
205
+ "source": {
206
+ "type": "git",
207
+ "url": "https://github.com/zendframework/Component_ZendCache.git",
208
+ "reference": "1966038a1568ebeaeeeaa78ce27bc7b340e30747"
209
+ },
210
+ "dist": {
211
+ "type": "zip",
212
+ "url": "https://api.github.com/repos/zendframework/Component_ZendCache/zipball/1966038a1568ebeaeeeaa78ce27bc7b340e30747",
213
+ "reference": "1966038a1568ebeaeeeaa78ce27bc7b340e30747",
214
+ "shasum": ""
215
+ },
216
+ "require": {
217
+ "php": ">=5.3.23",
218
+ "zendframework/zend-eventmanager": "self.version",
219
+ "zendframework/zend-servicemanager": "self.version",
220
+ "zendframework/zend-stdlib": "self.version"
221
+ },
222
+ "require-dev": {
223
+ "zendframework/zend-serializer": "self.version",
224
+ "zendframework/zend-session": "self.version"
225
+ },
226
+ "suggest": {
227
+ "ext-apc": "APC >= 3.1.6 to use the APC storage adapter",
228
+ "ext-dba": "DBA, to use the DBA storage adapter",
229
+ "ext-memcached": "Memcached >= 1.0.0 to use the Memcached storage adapter",
230
+ "ext-wincache": "WinCache, to use the WinCache storage adapter",
231
+ "zendframework/zend-serializer": "Zend\\Serializer component",
232
+ "zendframework/zend-session": "Zend\\Session component"
233
+ },
234
+ "time": "2014-09-16 22:58:11",
235
+ "type": "library",
236
+ "extra": {
237
+ "branch-alias": {
238
+ "dev-master": "2.3-dev",
239
+ "dev-develop": "2.4-dev"
240
+ }
241
+ },
242
+ "installation-source": "dist",
243
+ "autoload": {
244
+ "psr-0": {
245
+ "Zend\\Cache\\": ""
246
+ }
247
+ },
248
+ "notification-url": "https://packagist.org/downloads/",
249
+ "license": [
250
+ "BSD-3-Clause"
251
+ ],
252
+ "description": "provides a generic way to cache any data",
253
+ "homepage": "https://github.com/zendframework/zf2",
254
+ "keywords": [
255
+ "cache",
256
+ "zf2"
257
+ ]
258
+ },
259
+ {
260
+ "name": "zendframework/zend-config",
261
+ "version": "2.3.3",
262
+ "version_normalized": "2.3.3.0",
263
+ "target-dir": "Zend/Config",
264
+ "source": {
265
+ "type": "git",
266
+ "url": "https://github.com/zendframework/Component_ZendConfig.git",
267
+ "reference": "a9ad512e1482461a5b500ee3fcf2d06ec9c7c7e8"
268
+ },
269
+ "dist": {
270
+ "type": "zip",
271
+ "url": "https://api.github.com/repos/zendframework/Component_ZendConfig/zipball/a9ad512e1482461a5b500ee3fcf2d06ec9c7c7e8",
272
+ "reference": "a9ad512e1482461a5b500ee3fcf2d06ec9c7c7e8",
273
+ "shasum": ""
274
+ },
275
+ "require": {
276
+ "php": ">=5.3.23",
277
+ "zendframework/zend-stdlib": "self.version"
278
+ },
279
+ "require-dev": {
280
+ "zendframework/zend-filter": "self.version",
281
+ "zendframework/zend-i18n": "self.version",
282
+ "zendframework/zend-json": "self.version",
283
+ "zendframework/zend-servicemanager": "self.version"
284
+ },
285
+ "suggest": {
286
+ "zendframework/zend-filter": "Zend\\Filter component",
287
+ "zendframework/zend-i18n": "Zend\\I18n component",
288
+ "zendframework/zend-json": "Zend\\Json to use the Json reader or writer classes",
289
+ "zendframework/zend-servicemanager": "Zend\\ServiceManager for use with the Config Factory to retrieve reader and writer instances"
290
+ },
291
+ "time": "2014-09-16 22:58:11",
292
+ "type": "library",
293
+ "extra": {
294
+ "branch-alias": {
295
+ "dev-master": "2.3-dev",
296
+ "dev-develop": "2.4-dev"
297
+ }
298
+ },
299
+ "installation-source": "dist",
300
+ "autoload": {
301
+ "psr-0": {
302
+ "Zend\\Config\\": ""
303
+ }
304
+ },
305
+ "notification-url": "https://packagist.org/downloads/",
306
+ "license": [
307
+ "BSD-3-Clause"
308
+ ],
309
+ "description": "provides a nested object property based user interface for accessing this configuration data within application code",
310
+ "homepage": "https://github.com/zendframework/zf2",
311
+ "keywords": [
312
+ "config",
313
+ "zf2"
314
+ ]
315
+ },
316
+ {
317
+ "name": "zendframework/zend-json",
318
+ "version": "2.3.3",
319
+ "version_normalized": "2.3.3.0",
320
+ "target-dir": "Zend/Json",
321
+ "source": {
322
+ "type": "git",
323
+ "url": "https://github.com/zendframework/Component_ZendJson.git",
324
+ "reference": "4093e5a0a166a5d02532bac6e5671a7b21d203b5"
325
+ },
326
+ "dist": {
327
+ "type": "zip",
328
+ "url": "https://api.github.com/repos/zendframework/Component_ZendJson/zipball/4093e5a0a166a5d02532bac6e5671a7b21d203b5",
329
+ "reference": "4093e5a0a166a5d02532bac6e5671a7b21d203b5",
330
+ "shasum": ""
331
+ },
332
+ "require": {
333
+ "php": ">=5.3.23",
334
+ "zendframework/zend-stdlib": "self.version"
335
+ },
336
+ "require-dev": {
337
+ "zendframework/zend-http": "self.version",
338
+ "zendframework/zend-server": "self.version"
339
+ },
340
+ "suggest": {
341
+ "zendframework/zend-http": "Zend\\Http component",
342
+ "zendframework/zend-server": "Zend\\Server component"
343
+ },
344
+ "time": "2014-09-16 22:58:11",
345
+ "type": "library",
346
+ "extra": {
347
+ "branch-alias": {
348
+ "dev-master": "2.3-dev",
349
+ "dev-develop": "2.4-dev"
350
+ }
351
+ },
352
+ "installation-source": "dist",
353
+ "autoload": {
354
+ "psr-0": {
355
+ "Zend\\Json\\": ""
356
+ }
357
+ },
358
+ "notification-url": "https://packagist.org/downloads/",
359
+ "license": [
360
+ "BSD-3-Clause"
361
+ ],
362
+ "description": "provides convenience methods for serializing native PHP to JSON and decoding JSON to native PHP",
363
+ "homepage": "https://github.com/zendframework/zf2",
364
+ "keywords": [
365
+ "json",
366
+ "zf2"
367
+ ]
368
+ },
369
+ {
370
+ "name": "react/promise",
371
+ "version": "v2.2.0",
372
+ "version_normalized": "2.2.0.0",
373
+ "source": {
374
+ "type": "git",
375
+ "url": "https://github.com/reactphp/promise.git",
376
+ "reference": "365fcee430dfa4ace1fbc75737ca60ceea7eeeef"
377
+ },
378
+ "dist": {
379
+ "type": "zip",
380
+ "url": "https://api.github.com/repos/reactphp/promise/zipball/365fcee430dfa4ace1fbc75737ca60ceea7eeeef",
381
+ "reference": "365fcee430dfa4ace1fbc75737ca60ceea7eeeef",
382
+ "shasum": ""
383
+ },
384
+ "require": {
385
+ "php": ">=5.4.0"
386
+ },
387
+ "time": "2014-12-30 13:32:42",
388
+ "type": "library",
389
+ "extra": {
390
+ "branch-alias": {
391
+ "dev-master": "2.0-dev"
392
+ }
393
+ },
394
+ "installation-source": "dist",
395
+ "autoload": {
396
+ "psr-4": {
397
+ "React\\Promise\\": "src/"
398
+ },
399
+ "files": [
400
+ "src/functions_include.php"
401
+ ]
402
+ },
403
+ "notification-url": "https://packagist.org/downloads/",
404
+ "license": [
405
+ "MIT"
406
+ ],
407
+ "authors": [
408
+ {
409
+ "name": "Jan Sorgalla",
410
+ "email": "jsorgalla@googlemail.com"
411
+ }
412
+ ],
413
+ "description": "A lightweight implementation of CommonJS Promises/A for PHP"
414
+ },
415
+ {
416
+ "name": "guzzlehttp/ringphp",
417
+ "version": "1.0.5",
418
+ "version_normalized": "1.0.5.0",
419
+ "source": {
420
+ "type": "git",
421
+ "url": "https://github.com/guzzle/RingPHP.git",
422
+ "reference": "a903f51b692427318bc813217c0e6505287e79a4"
423
+ },
424
+ "dist": {
425
+ "type": "zip",
426
+ "url": "https://api.github.com/repos/guzzle/RingPHP/zipball/a903f51b692427318bc813217c0e6505287e79a4",
427
+ "reference": "a903f51b692427318bc813217c0e6505287e79a4",
428
+ "shasum": ""
429
+ },
430
+ "require": {
431
+ "guzzlehttp/streams": "~3.0",
432
+ "php": ">=5.4.0",
433
+ "react/promise": "~2.0"
434
+ },
435
+ "require-dev": {
436
+ "ext-curl": "*",
437
+ "phpunit/phpunit": "~4.0"
438
+ },
439
+ "suggest": {
440
+ "ext-curl": "Guzzle will use specific adapters if cURL is present"
441
+ },
442
+ "time": "2014-12-11 05:50:32",
443
+ "type": "library",
444
+ "extra": {
445
+ "branch-alias": {
446
+ "dev-master": "1.0-dev"
447
+ }
448
+ },
449
+ "installation-source": "dist",
450
+ "autoload": {
451
+ "psr-4": {
452
+ "GuzzleHttp\\Ring\\": "src/"
453
+ }
454
+ },
455
+ "notification-url": "https://packagist.org/downloads/",
456
+ "license": [
457
+ "MIT"
458
+ ],
459
+ "authors": [
460
+ {
461
+ "name": "Michael Dowling",
462
+ "email": "mtdowling@gmail.com",
463
+ "homepage": "https://github.com/mtdowling"
464
+ }
465
+ ]
466
+ },
467
+ {
468
+ "name": "guzzlehttp/guzzle",
469
+ "version": "5.1.0",
470
+ "version_normalized": "5.1.0.0",
471
+ "source": {
472
+ "type": "git",
473
+ "url": "https://github.com/guzzle/guzzle.git",
474
+ "reference": "f1085bb4e023766a66b7b051914ec73bdf7202b5"
475
+ },
476
+ "dist": {
477
+ "type": "zip",
478
+ "url": "https://api.github.com/repos/guzzle/guzzle/zipball/f1085bb4e023766a66b7b051914ec73bdf7202b5",
479
+ "reference": "f1085bb4e023766a66b7b051914ec73bdf7202b5",
480
+ "shasum": ""
481
+ },
482
+ "require": {
483
+ "guzzlehttp/ringphp": "~1.0",
484
+ "php": ">=5.4.0"
485
+ },
486
+ "require-dev": {
487
+ "ext-curl": "*",
488
+ "phpunit/phpunit": "~4.0",
489
+ "psr/log": "~1.0"
490
+ },
491
+ "time": "2014-12-19 20:27:15",
492
+ "type": "library",
493
+ "extra": {
494
+ "branch-alias": {
495
+ "dev-master": "5.0-dev"
496
+ }
497
+ },
498
+ "installation-source": "dist",
499
+ "autoload": {
500
+ "psr-4": {
501
+ "GuzzleHttp\\": "src/"
502
+ }
503
+ },
504
+ "notification-url": "https://packagist.org/downloads/",
505
+ "license": [
506
+ "MIT"
507
+ ],
508
+ "authors": [
509
+ {
510
+ "name": "Michael Dowling",
511
+ "email": "mtdowling@gmail.com",
512
+ "homepage": "https://github.com/mtdowling"
513
+ }
514
+ ],
515
+ "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients",
516
+ "homepage": "http://guzzlephp.org/",
517
+ "keywords": [
518
+ "client",
519
+ "curl",
520
+ "framework",
521
+ "http",
522
+ "http client",
523
+ "rest",
524
+ "web service"
525
+ ]
526
+ }
527
+ ]
backend/vendor/guzzlehttp/guzzle/.gitignore ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ phpunit.xml
2
+ composer.phar
3
+ composer.lock
4
+ composer-test.lock
5
+ vendor/
6
+ build/artifacts/
7
+ artifacts/
8
+ docs/_build
9
+ docs/*.pyc
10
+ .idea
11
+ .DS_STORE
backend/vendor/guzzlehttp/guzzle/.travis.yml ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ language: php
2
+
3
+ php:
4
+ - 5.4
5
+ - 5.5
6
+ - 5.6
7
+ - hhvm
8
+
9
+ before_script:
10
+ - curl --version
11
+ - pear config-set php_ini ~/.phpenv/versions/`php -r 'echo phpversion();'`/etc/php.ini || echo 'Error modifying PEAR'
12
+ - pecl install uri_template || echo 'Error installing uri_template'
13
+ - composer self-update
14
+ - composer install --no-interaction --prefer-source --dev
15
+ - ~/.nvm/nvm.sh install v0.6.14
16
+ - ~/.nvm/nvm.sh run v0.6.14
17
+
18
+ script: make test
19
+
20
+ matrix:
21
+ allow_failures:
22
+ - php: hhvm
23
+ fast_finish: true
24
+
25
+ before_deploy:
26
+ - make package
27
+
28
+ deploy:
29
+ provider: releases
30
+ api_key:
31
+ secure: UpypqlYgsU68QT/x40YzhHXvzWjFwCNo9d+G8KAdm7U9+blFfcWhV1aMdzugvPMl6woXgvJj7qHq5tAL4v6oswCORhpSBfLgOQVFaica5LiHsvWlAedOhxGmnJqMTwuepjBCxXhs3+I8Kof1n4oUL9gKytXjOVCX/f7XU1HiinU=
32
+ file:
33
+ - build/artifacts/guzzle.phar
34
+ - build/artifacts/guzzle.zip
35
+ on:
36
+ repo: guzzle/guzzle
37
+ tags: true
38
+ all_branches: true
39
+ php: 5.4
backend/vendor/guzzlehttp/guzzle/CHANGELOG.md ADDED
@@ -0,0 +1,1033 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CHANGELOG
2
+
3
+ ## 5.1.0 - 2014-12-19
4
+
5
+ * Pool class no longer uses recursion when a request is intercepted.
6
+ * The size of a Pool can now be dynamically adjusted using a callback.
7
+ See https://github.com/guzzle/guzzle/pull/943.
8
+ * Setting a request option to `null` when creating a request with a client will
9
+ ensure that the option is not set. This allows you to overwrite default
10
+ request options on a per-request basis.
11
+ See https://github.com/guzzle/guzzle/pull/937.
12
+ * Added the ability to limit which protocols are allowed for redirects by
13
+ specifying a `protocols` array in the `allow_redirects` request option.
14
+ * Nested futures due to retries are now resolved when waiting for synchronous
15
+ responses. See https://github.com/guzzle/guzzle/pull/947.
16
+ * `"0"` is now an allowed URI path. See
17
+ https://github.com/guzzle/guzzle/pull/935.
18
+ * `Query` no longer typehints on the `$query` argument in the constructor,
19
+ allowing for strings and arrays.
20
+ * Exceptions thrown in the `end` event are now correctly wrapped with Guzzle
21
+ specific exceptions if necessary.
22
+
23
+ ## 5.0.3 - 2014-11-03
24
+
25
+ This change updates query strings so that they are treated as un-encoded values
26
+ by default where the value represents an un-encoded value to send over the
27
+ wire. A Query object then encodes the value before sending over the wire. This
28
+ means that even value query string values (e.g., ":") are url encoded. This
29
+ makes the Query class match PHP's http_build_query function. However, if you
30
+ want to send requests over the wire using valid query string characters that do
31
+ not need to be encoded, then you can provide a string to Url::setQuery() and
32
+ pass true as the second argument to specify that the query string is a raw
33
+ string that should not be parsed or encoded (unless a call to getQuery() is
34
+ subsequently made, forcing the query-string to be converted into a Query
35
+ object).
36
+
37
+ ## 5.0.2 - 2014-10-30
38
+
39
+ * Added a trailing `\r\n` to multipart/form-data payloads. See
40
+ https://github.com/guzzle/guzzle/pull/871
41
+ * Added a `GuzzleHttp\Pool::send()` convenience method to match the docs.
42
+ * Status codes are now returned as integers. See
43
+ https://github.com/guzzle/guzzle/issues/881
44
+ * No longer overwriting an existing `application/x-www-form-urlencoded` header
45
+ when sending POST requests, allowing for customized headers. See
46
+ https://github.com/guzzle/guzzle/issues/877
47
+ * Improved path URL serialization.
48
+
49
+ * No longer double percent-encoding characters in the path or query string if
50
+ they are already encoded.
51
+ * Now properly encoding the supplied path to a URL object, instead of only
52
+ encoding ' ' and '?'.
53
+ * Note: This has been changed in 5.0.3 to now encode query string values by
54
+ default unless the `rawString` argument is provided when setting the query
55
+ string on a URL: Now allowing many more characters to be present in the
56
+ query string without being percent encoded. See http://tools.ietf.org/html/rfc3986#appendix-A
57
+
58
+ ## 5.0.1 - 2014-10-16
59
+
60
+ Bugfix release.
61
+
62
+ * Fixed an issue where connection errors still returned response object in
63
+ error and end events event though the response is unusable. This has been
64
+ corrected so that a response is not returned in the `getResponse` method of
65
+ these events if the response did not complete. https://github.com/guzzle/guzzle/issues/867
66
+ * Fixed an issue where transfer statistics were not being populated in the
67
+ RingBridge. https://github.com/guzzle/guzzle/issues/866
68
+
69
+ ## 5.0.0 - 2014-10-12
70
+
71
+ Adding support for non-blocking responses and some minor API cleanup.
72
+
73
+ ### New Features
74
+
75
+ * Added support for non-blocking responses based on `guzzlehttp/guzzle-ring`.
76
+ * Added a public API for creating a default HTTP adapter.
77
+ * Updated the redirect plugin to be non-blocking so that redirects are sent
78
+ concurrently. Other plugins like this can now be updated to be non-blocking.
79
+ * Added a "progress" event so that you can get upload and download progress
80
+ events.
81
+ * Added `GuzzleHttp\Pool` which implements FutureInterface and transfers
82
+ requests concurrently using a capped pool size as efficiently as possible.
83
+ * Added `hasListeners()` to EmitterInterface.
84
+ * Removed `GuzzleHttp\ClientInterface::sendAll` and marked
85
+ `GuzzleHttp\Client::sendAll` as deprecated (it's still there, just not the
86
+ recommended way).
87
+
88
+ ### Breaking changes
89
+
90
+ The breaking changes in this release are relatively minor. The biggest thing to
91
+ look out for is that request and response objects no longer implement fluent
92
+ interfaces.
93
+
94
+ * Removed the fluent interfaces (i.e., ``return $this``) from requests,
95
+ responses, ``GuzzleHttp\Collection``, ``GuzzleHttp\Url``,
96
+ ``GuzzleHttp\Query``, ``GuzzleHttp\Post\PostBody``, and
97
+ ``GuzzleHttp\Cookie\SetCookie``. This blog post provides a good outline of
98
+ why I did this: http://ocramius.github.io/blog/fluent-interfaces-are-evil/.
99
+ This also makes the Guzzle message interfaces compatible with the current
100
+ PSR-7 message proposal.
101
+ * Removed "functions.php", so that Guzzle is truly PSR-4 compliant. Except
102
+ for the HTTP request functions from function.php, these functions are now
103
+ implemented in `GuzzleHttp\Utils` using camelCase. `GuzzleHttp\json_decode`
104
+ moved to `GuzzleHttp\Utils::jsonDecode`. `GuzzleHttp\get_path` moved to
105
+ `GuzzleHttp\Utils::getPath`. `GuzzleHttp\set_path` moved to
106
+ `GuzzleHttp\Utils::setPath`. `GuzzleHttp\batch` should now be
107
+ `GuzzleHttp\Pool::batch`, which returns an objectStorage`. Using functions.php
108
+ caused problems for many users: they aren't PSR-4 compliant, require an
109
+ explicit include, and needed an if-guard to ensure that the functions are not
110
+ declared multiple times.
111
+ * Rewrote adapter layer.
112
+ * Removing all classes from `GuzzleHttp\Adapter`, these are now
113
+ implemented as callables that are stored in `GuzzleHttp\Ring\Client`.
114
+ * Removed the concept of "parallel adapters". Sending requests serially or
115
+ concurrently is now handled using a single adapter.
116
+ * Moved `GuzzleHttp\Adapter\Transaction` to `GuzzleHttp\Transaction`. The
117
+ Transaction object now exposes the request, response, and client as public
118
+ properties. The getters and setters have been removed.
119
+ * Removed the "headers" event. This event was only useful for changing the
120
+ body a response once the headers of the response were known. You can implement
121
+ a similar behavior in a number of ways. One example might be to use a
122
+ FnStream that has access to the transaction being sent. For example, when the
123
+ first byte is written, you could check if the response headers match your
124
+ expectations, and if so, change the actual stream body that is being
125
+ written to.
126
+ * Removed the `asArray` parameter from
127
+ `GuzzleHttp\Message\MessageInterface::getHeader`. If you want to get a header
128
+ value as an array, then use the newly added ``getHeaderAsArray()`` method of
129
+ ``MessageInterface``. This change makes the Guzzle interfaces compatible with
130
+ the PSR-7 interfaces.
131
+ * ``GuzzleHttp\Message\MessageFactory`` no longer allows subclasses to add
132
+ custom request options using double-dispatch (this was an implementation
133
+ detail). Instead, you should now provide an associative array to the
134
+ constructor which is a mapping of the request option name mapping to a
135
+ function that applies the option value to a request.
136
+ * Removed the concept of "throwImmediately" from exceptions and error events.
137
+ This control mechanism was used to stop a transfer of concurrent requests
138
+ from completing. This can now be handled by throwing the exception or by
139
+ cancelling a pool of requests or each outstanding future request individually.
140
+ * Updated to "GuzzleHttp\Streams" 3.0.
141
+ * `GuzzleHttp\Stream\StreamInterface::getContents()` no longer accepts a
142
+ `maxLen` parameter. This update makes the Guzzle streams project
143
+ compatible with the current PSR-7 proposal.
144
+ * ``GuzzleHttp\Stream\Stream::__construct``,
145
+ ``GuzzleHttp\Stream\Stream::factory``, and
146
+ ``GuzzleHttp\Stream\Utils::create`` no longer accept a size in the second
147
+ argument. They now accept an associative array of options, including the
148
+ "size" key and "metadata" key which can be used to provide custom metadata.
149
+
150
+ ## 4.2.2 - 2014-09-08
151
+
152
+ * Fixed a memory leak in the CurlAdapter when reusing cURL handles.
153
+ * No longer using `request_fulluri` in stream adapter proxies.
154
+ * Relative redirects are now based on the last response, not the first response.
155
+
156
+ ## 4.2.1 - 2014-08-19
157
+
158
+ * Ensuring that the StreamAdapter does not always add a Content-Type header
159
+ * Adding automated github releases with a phar and zip
160
+
161
+ ## 4.2.0 - 2014-08-17
162
+
163
+ * Now merging in default options using a case-insensitive comparison.
164
+ Closes https://github.com/guzzle/guzzle/issues/767
165
+ * Added the ability to automatically decode `Content-Encoding` response bodies
166
+ using the `decode_content` request option. This is set to `true` by default
167
+ to decode the response body if it comes over the wire with a
168
+ `Content-Encoding`. Set this value to `false` to disable decoding the
169
+ response content, and pass a string to provide a request `Accept-Encoding`
170
+ header and turn on automatic response decoding. This feature now allows you
171
+ to pass an `Accept-Encoding` header in the headers of a request but still
172
+ disable automatic response decoding.
173
+ Closes https://github.com/guzzle/guzzle/issues/764
174
+ * Added the ability to throw an exception immediately when transferring
175
+ requests in parallel. Closes https://github.com/guzzle/guzzle/issues/760
176
+ * Updating guzzlehttp/streams dependency to ~2.1
177
+ * No longer utilizing the now deprecated namespaced methods from the stream
178
+ package.
179
+
180
+ ## 4.1.8 - 2014-08-14
181
+
182
+ * Fixed an issue in the CurlFactory that caused setting the `stream=false`
183
+ request option to throw an exception.
184
+ See: https://github.com/guzzle/guzzle/issues/769
185
+ * TransactionIterator now calls rewind on the inner iterator.
186
+ See: https://github.com/guzzle/guzzle/pull/765
187
+ * You can now set the `Content-Type` header to `multipart/form-data`
188
+ when creating POST requests to force multipart bodies.
189
+ See https://github.com/guzzle/guzzle/issues/768
190
+
191
+ ## 4.1.7 - 2014-08-07
192
+
193
+ * Fixed an error in the HistoryPlugin that caused the same request and response
194
+ to be logged multiple times when an HTTP protocol error occurs.
195
+ * Ensuring that cURL does not add a default Content-Type when no Content-Type
196
+ has been supplied by the user. This prevents the adapter layer from modifying
197
+ the request that is sent over the wire after any listeners may have already
198
+ put the request in a desired state (e.g., signed the request).
199
+ * Throwing an exception when you attempt to send requests that have the
200
+ "stream" set to true in parallel using the MultiAdapter.
201
+ * Only calling curl_multi_select when there are active cURL handles. This was
202
+ previously changed and caused performance problems on some systems due to PHP
203
+ always selecting until the maximum select timeout.
204
+ * Fixed a bug where multipart/form-data POST fields were not correctly
205
+ aggregated (e.g., values with "&").
206
+
207
+ ## 4.1.6 - 2014-08-03
208
+
209
+ * Added helper methods to make it easier to represent messages as strings,
210
+ including getting the start line and getting headers as a string.
211
+
212
+ ## 4.1.5 - 2014-08-02
213
+
214
+ * Automatically retrying cURL "Connection died, retrying a fresh connect"
215
+ errors when possible.
216
+ * cURL implementation cleanup
217
+ * Allowing multiple event subscriber listeners to be registered per event by
218
+ passing an array of arrays of listener configuration.
219
+
220
+ ## 4.1.4 - 2014-07-22
221
+
222
+ * Fixed a bug that caused multi-part POST requests with more than one field to
223
+ serialize incorrectly.
224
+ * Paths can now be set to "0"
225
+ * `ResponseInterface::xml` now accepts a `libxml_options` option and added a
226
+ missing default argument that was required when parsing XML response bodies.
227
+ * A `save_to` stream is now created lazily, which means that files are not
228
+ created on disk unless a request succeeds.
229
+
230
+ ## 4.1.3 - 2014-07-15
231
+
232
+ * Various fixes to multipart/form-data POST uploads
233
+ * Wrapping function.php in an if-statement to ensure Guzzle can be used
234
+ globally and in a Composer install
235
+ * Fixed an issue with generating and merging in events to an event array
236
+ * POST headers are only applied before sending a request to allow you to change
237
+ the query aggregator used before uploading
238
+ * Added much more robust query string parsing
239
+ * Fixed various parsing and normalization issues with URLs
240
+ * Fixing an issue where multi-valued headers were not being utilized correctly
241
+ in the StreamAdapter
242
+
243
+ ## 4.1.2 - 2014-06-18
244
+
245
+ * Added support for sending payloads with GET requests
246
+
247
+ ## 4.1.1 - 2014-06-08
248
+
249
+ * Fixed an issue related to using custom message factory options in subclasses
250
+ * Fixed an issue with nested form fields in a multi-part POST
251
+ * Fixed an issue with using the `json` request option for POST requests
252
+ * Added `ToArrayInterface` to `GuzzleHttp\Cookie\CookieJar`
253
+
254
+ ## 4.1.0 - 2014-05-27
255
+
256
+ * Added a `json` request option to easily serialize JSON payloads.
257
+ * Added a `GuzzleHttp\json_decode()` wrapper to safely parse JSON.
258
+ * Added `setPort()` and `getPort()` to `GuzzleHttp\Message\RequestInterface`.
259
+ * Added the ability to provide an emitter to a client in the client constructor.
260
+ * Added the ability to persist a cookie session using $_SESSION.
261
+ * Added a trait that can be used to add event listeners to an iterator.
262
+ * Removed request method constants from RequestInterface.
263
+ * Fixed warning when invalid request start-lines are received.
264
+ * Updated MessageFactory to work with custom request option methods.
265
+ * Updated cacert bundle to latest build.
266
+
267
+ 4.0.2 (2014-04-16)
268
+ ------------------
269
+
270
+ * Proxy requests using the StreamAdapter now properly use request_fulluri (#632)
271
+ * Added the ability to set scalars as POST fields (#628)
272
+
273
+ ## 4.0.1 - 2014-04-04
274
+
275
+ * The HTTP status code of a response is now set as the exception code of
276
+ RequestException objects.
277
+ * 303 redirects will now correctly switch from POST to GET requests.
278
+ * The default parallel adapter of a client now correctly uses the MultiAdapter.
279
+ * HasDataTrait now initializes the internal data array as an empty array so
280
+ that the toArray() method always returns an array.
281
+
282
+ ## 4.0.0 - 2014-03-29
283
+
284
+ * For more information on the 4.0 transition, see:
285
+ http://mtdowling.com/blog/2014/03/15/guzzle-4-rc/
286
+ * For information on changes and upgrading, see:
287
+ https://github.com/guzzle/guzzle/blob/master/UPGRADING.md#3x-to-40
288
+ * Added `GuzzleHttp\batch()` as a convenience function for sending requests in
289
+ parallel without needing to write asynchronous code.
290
+ * Restructured how events are added to `GuzzleHttp\ClientInterface::sendAll()`.
291
+ You can now pass a callable or an array of associative arrays where each
292
+ associative array contains the "fn", "priority", and "once" keys.
293
+
294
+ ## 4.0.0.rc-2 - 2014-03-25
295
+
296
+ * Removed `getConfig()` and `setConfig()` from clients to avoid confusion
297
+ around whether things like base_url, message_factory, etc. should be able to
298
+ be retrieved or modified.
299
+ * Added `getDefaultOption()` and `setDefaultOption()` to ClientInterface
300
+ * functions.php functions were renamed using snake_case to match PHP idioms
301
+ * Added support for `HTTP_PROXY`, `HTTPS_PROXY`, and
302
+ `GUZZLE_CURL_SELECT_TIMEOUT` environment variables
303
+ * Added the ability to specify custom `sendAll()` event priorities
304
+ * Added the ability to specify custom stream context options to the stream
305
+ adapter.
306
+ * Added a functions.php function for `get_path()` and `set_path()`
307
+ * CurlAdapter and MultiAdapter now use a callable to generate curl resources
308
+ * MockAdapter now properly reads a body and emits a `headers` event
309
+ * Updated Url class to check if a scheme and host are set before adding ":"
310
+ and "//". This allows empty Url (e.g., "") to be serialized as "".
311
+ * Parsing invalid XML no longer emits warnings
312
+ * Curl classes now properly throw AdapterExceptions
313
+ * Various performance optimizations
314
+ * Streams are created with the faster `Stream\create()` function
315
+ * Marked deprecation_proxy() as internal
316
+ * Test server is now a collection of static methods on a class
317
+
318
+ ## 4.0.0-rc.1 - 2014-03-15
319
+
320
+ * See https://github.com/guzzle/guzzle/blob/master/UPGRADING.md#3x-to-40
321
+
322
+ ## 3.8.1 - 2014-01-28
323
+
324
+ * Bug: Always using GET requests when redirecting from a 303 response
325
+ * Bug: CURLOPT_SSL_VERIFYHOST is now correctly set to false when setting `$certificateAuthority` to false in
326
+ `Guzzle\Http\ClientInterface::setSslVerification()`
327
+ * Bug: RedirectPlugin now uses strict RFC 3986 compliance when combining a base URL with a relative URL
328
+ * Bug: The body of a request can now be set to `"0"`
329
+ * Sending PHP stream requests no longer forces `HTTP/1.0`
330
+ * Adding more information to ExceptionCollection exceptions so that users have more context, including a stack trace of
331
+ each sub-exception
332
+ * Updated the `$ref` attribute in service descriptions to merge over any existing parameters of a schema (rather than
333
+ clobbering everything).
334
+ * Merging URLs will now use the query string object from the relative URL (thus allowing custom query aggregators)
335
+ * Query strings are now parsed in a way that they do no convert empty keys with no value to have a dangling `=`.
336
+ For example `foo&bar=baz` is now correctly parsed and recognized as `foo&bar=baz` rather than `foo=&bar=baz`.
337
+ * Now properly escaping the regular expression delimiter when matching Cookie domains.
338
+ * Network access is now disabled when loading XML documents
339
+
340
+ ## 3.8.0 - 2013-12-05
341
+
342
+ * Added the ability to define a POST name for a file
343
+ * JSON response parsing now properly walks additionalProperties
344
+ * cURL error code 18 is now retried automatically in the BackoffPlugin
345
+ * Fixed a cURL error when URLs contain fragments
346
+ * Fixed an issue in the BackoffPlugin retry event where it was trying to access all exceptions as if they were
347
+ CurlExceptions
348
+ * CURLOPT_PROGRESS function fix for PHP 5.5 (69fcc1e)
349
+ * Added the ability for Guzzle to work with older versions of cURL that do not support `CURLOPT_TIMEOUT_MS`
350
+ * Fixed a bug that was encountered when parsing empty header parameters
351
+ * UriTemplate now has a `setRegex()` method to match the docs
352
+ * The `debug` request parameter now checks if it is truthy rather than if it exists
353
+ * Setting the `debug` request parameter to true shows verbose cURL output instead of using the LogPlugin
354
+ * Added the ability to combine URLs using strict RFC 3986 compliance
355
+ * Command objects can now return the validation errors encountered by the command
356
+ * Various fixes to cache revalidation (#437 and 29797e5)
357
+ * Various fixes to the AsyncPlugin
358
+ * Cleaned up build scripts
359
+
360
+ ## 3.7.4 - 2013-10-02
361
+
362
+ * Bug fix: 0 is now an allowed value in a description parameter that has a default value (#430)
363
+ * Bug fix: SchemaFormatter now returns an integer when formatting to a Unix timestamp
364
+ (see https://github.com/aws/aws-sdk-php/issues/147)
365
+ * Bug fix: Cleaned up and fixed URL dot segment removal to properly resolve internal dots
366
+ * Minimum PHP version is now properly specified as 5.3.3 (up from 5.3.2) (#420)
367
+ * Updated the bundled cacert.pem (#419)
368
+ * OauthPlugin now supports adding authentication to headers or query string (#425)
369
+
370
+ ## 3.7.3 - 2013-09-08
371
+
372
+ * Added the ability to get the exception associated with a request/command when using `MultiTransferException` and
373
+ `CommandTransferException`.
374
+ * Setting `additionalParameters` of a response to false is now honored when parsing responses with a service description
375
+ * Schemas are only injected into response models when explicitly configured.
376
+ * No longer guessing Content-Type based on the path of a request. Content-Type is now only guessed based on the path of
377
+ an EntityBody.
378
+ * Bug fix: ChunkedIterator can now properly chunk a \Traversable as well as an \Iterator.
379
+ * Bug fix: FilterIterator now relies on `\Iterator` instead of `\Traversable`.
380
+ * Bug fix: Gracefully handling malformed responses in RequestMediator::writeResponseBody()
381
+ * Bug fix: Replaced call to canCache with canCacheRequest in the CallbackCanCacheStrategy of the CachePlugin
382
+ * Bug fix: Visiting XML attributes first before visiting XML children when serializing requests
383
+ * Bug fix: Properly parsing headers that contain commas contained in quotes
384
+ * Bug fix: mimetype guessing based on a filename is now case-insensitive
385
+
386
+ ## 3.7.2 - 2013-08-02
387
+
388
+ * Bug fix: Properly URL encoding paths when using the PHP-only version of the UriTemplate expander
389
+ See https://github.com/guzzle/guzzle/issues/371
390
+ * Bug fix: Cookie domains are now matched correctly according to RFC 6265
391
+ See https://github.com/guzzle/guzzle/issues/377
392
+ * Bug fix: GET parameters are now used when calculating an OAuth signature
393
+ * Bug fix: Fixed an issue with cache revalidation where the If-None-Match header was being double quoted
394
+ * `Guzzle\Common\AbstractHasDispatcher::dispatch()` now returns the event that was dispatched
395
+ * `Guzzle\Http\QueryString::factory()` now guesses the most appropriate query aggregator to used based on the input.
396
+ See https://github.com/guzzle/guzzle/issues/379
397
+ * Added a way to add custom domain objects to service description parsing using the `operation.parse_class` event. See
398
+ https://github.com/guzzle/guzzle/pull/380
399
+ * cURL multi cleanup and optimizations
400
+
401
+ ## 3.7.1 - 2013-07-05
402
+
403
+ * Bug fix: Setting default options on a client now works
404
+ * Bug fix: Setting options on HEAD requests now works. See #352
405
+ * Bug fix: Moving stream factory before send event to before building the stream. See #353
406
+ * Bug fix: Cookies no longer match on IP addresses per RFC 6265
407
+ * Bug fix: Correctly parsing header parameters that are in `<>` and quotes
408
+ * Added `cert` and `ssl_key` as request options
409
+ * `Host` header can now diverge from the host part of a URL if the header is set manually
410
+ * `Guzzle\Service\Command\LocationVisitor\Request\XmlVisitor` was rewritten to change from using SimpleXML to XMLWriter
411
+ * OAuth parameters are only added via the plugin if they aren't already set
412
+ * Exceptions are now thrown when a URL cannot be parsed
413
+ * Returning `false` if `Guzzle\Http\EntityBody::getContentMd5()` fails
414
+ * Not setting a `Content-MD5` on a command if calculating the Content-MD5 fails via the CommandContentMd5Plugin
415
+
416
+ ## 3.7.0 - 2013-06-10
417
+
418
+ * See UPGRADING.md for more information on how to upgrade.
419
+ * Requests now support the ability to specify an array of $options when creating a request to more easily modify a
420
+ request. You can pass a 'request.options' configuration setting to a client to apply default request options to
421
+ every request created by a client (e.g. default query string variables, headers, curl options, etc.).
422
+ * Added a static facade class that allows you to use Guzzle with static methods and mount the class to `\Guzzle`.
423
+ See `Guzzle\Http\StaticClient::mount`.
424
+ * Added `command.request_options` to `Guzzle\Service\Command\AbstractCommand` to pass request options to requests
425
+ created by a command (e.g. custom headers, query string variables, timeout settings, etc.).
426
+ * Stream size in `Guzzle\Stream\PhpStreamRequestFactory` will now be set if Content-Length is returned in the
427
+ headers of a response
428
+ * Added `Guzzle\Common\Collection::setPath($path, $value)` to set a value into an array using a nested key
429
+ (e.g. `$collection->setPath('foo/baz/bar', 'test'); echo $collection['foo']['bar']['bar'];`)
430
+ * ServiceBuilders now support storing and retrieving arbitrary data
431
+ * CachePlugin can now purge all resources for a given URI
432
+ * CachePlugin can automatically purge matching cached items when a non-idempotent request is sent to a resource
433
+ * CachePlugin now uses the Vary header to determine if a resource is a cache hit
434
+ * `Guzzle\Http\Message\Response` now implements `\Serializable`
435
+ * Added `Guzzle\Cache\CacheAdapterFactory::fromCache()` to more easily create cache adapters
436
+ * `Guzzle\Service\ClientInterface::execute()` now accepts an array, single command, or Traversable
437
+ * Fixed a bug in `Guzzle\Http\Message\Header\Link::addLink()`
438
+ * Better handling of calculating the size of a stream in `Guzzle\Stream\Stream` using fstat() and caching the size
439
+ * `Guzzle\Common\Exception\ExceptionCollection` now creates a more readable exception message
440
+ * Fixing BC break: Added back the MonologLogAdapter implementation rather than extending from PsrLog so that older
441
+ Symfony users can still use the old version of Monolog.
442
+ * Fixing BC break: Added the implementation back in for `Guzzle\Http\Message\AbstractMessage::getTokenizedHeader()`.
443
+ Now triggering an E_USER_DEPRECATED warning when used. Use `$message->getHeader()->parseParams()`.
444
+ * Several performance improvements to `Guzzle\Common\Collection`
445
+ * Added an `$options` argument to the end of the following methods of `Guzzle\Http\ClientInterface`:
446
+ createRequest, head, delete, put, patch, post, options, prepareRequest
447
+ * Added an `$options` argument to the end of `Guzzle\Http\Message\Request\RequestFactoryInterface::createRequest()`
448
+ * Added an `applyOptions()` method to `Guzzle\Http\Message\Request\RequestFactoryInterface`
449
+ * Changed `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $body = null)` to
450
+ `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $options = array())`. You can still pass in a
451
+ resource, string, or EntityBody into the $options parameter to specify the download location of the response.
452
+ * Changed `Guzzle\Common\Collection::__construct($data)` to no longer accepts a null value for `$data` but a
453
+ default `array()`
454
+ * Added `Guzzle\Stream\StreamInterface::isRepeatable`
455
+ * Removed `Guzzle\Http\ClientInterface::setDefaultHeaders(). Use
456
+ $client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`. or
457
+ $client->getConfig()->setPath('request.options/headers', array('header_name' => 'value'))`.
458
+ * Removed `Guzzle\Http\ClientInterface::getDefaultHeaders(). Use $client->getConfig()->getPath('request.options/headers')`.
459
+ * Removed `Guzzle\Http\ClientInterface::expandTemplate()`
460
+ * Removed `Guzzle\Http\ClientInterface::setRequestFactory()`
461
+ * Removed `Guzzle\Http\ClientInterface::getCurlMulti()`
462
+ * Removed `Guzzle\Http\Message\RequestInterface::canCache`
463
+ * Removed `Guzzle\Http\Message\RequestInterface::setIsRedirect`
464
+ * Removed `Guzzle\Http\Message\RequestInterface::isRedirect`
465
+ * Made `Guzzle\Http\Client::expandTemplate` and `getUriTemplate` protected methods.
466
+ * You can now enable E_USER_DEPRECATED warnings to see if you are using a deprecated method by setting
467
+ `Guzzle\Common\Version::$emitWarnings` to true.
468
+ * Marked `Guzzle\Http\Message\Request::isResponseBodyRepeatable()` as deprecated. Use
469
+ `$request->getResponseBody()->isRepeatable()` instead.
470
+ * Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use
471
+ `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead.
472
+ * Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use
473
+ `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead.
474
+ * Marked `Guzzle\Http\Message\Request::setIsRedirect()` as deprecated. Use the HistoryPlugin instead.
475
+ * Marked `Guzzle\Http\Message\Request::isRedirect()` as deprecated. Use the HistoryPlugin instead.
476
+ * Marked `Guzzle\Cache\CacheAdapterFactory::factory()` as deprecated
477
+ * Marked 'command.headers', 'command.response_body' and 'command.on_complete' as deprecated for AbstractCommand.
478
+ These will work through Guzzle 4.0
479
+ * Marked 'request.params' for `Guzzle\Http\Client` as deprecated. Use [request.options][params].
480
+ * Marked `Guzzle\Service\Client::enableMagicMethods()` as deprecated. Magic methods can no longer be disabled on a Guzzle\Service\Client.
481
+ * Marked `Guzzle\Service\Client::getDefaultHeaders()` as deprecated. Use $client->getConfig()->getPath('request.options/headers')`.
482
+ * Marked `Guzzle\Service\Client::setDefaultHeaders()` as deprecated. Use $client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`.
483
+ * Marked `Guzzle\Parser\Url\UrlParser` as deprecated. Just use PHP's `parse_url()` and percent encode your UTF-8.
484
+ * Marked `Guzzle\Common\Collection::inject()` as deprecated.
485
+ * Marked `Guzzle\Plugin\CurlAuth\CurlAuthPlugin` as deprecated. Use `$client->getConfig()->setPath('request.options/auth', array('user', 'pass', 'Basic|Digest');`
486
+ * CacheKeyProviderInterface and DefaultCacheKeyProvider are no longer used. All of this logic is handled in a
487
+ CacheStorageInterface. These two objects and interface will be removed in a future version.
488
+ * Always setting X-cache headers on cached responses
489
+ * Default cache TTLs are now handled by the CacheStorageInterface of a CachePlugin
490
+ * `CacheStorageInterface::cache($key, Response $response, $ttl = null)` has changed to `cache(RequestInterface
491
+ $request, Response $response);`
492
+ * `CacheStorageInterface::fetch($key)` has changed to `fetch(RequestInterface $request);`
493
+ * `CacheStorageInterface::delete($key)` has changed to `delete(RequestInterface $request);`
494
+ * Added `CacheStorageInterface::purge($url)`
495
+ * `DefaultRevalidation::__construct(CacheKeyProviderInterface $cacheKey, CacheStorageInterface $cache, CachePlugin
496
+ $plugin)` has changed to `DefaultRevalidation::__construct(CacheStorageInterface $cache,
497
+ CanCacheStrategyInterface $canCache = null)`
498
+ * Added `RevalidationInterface::shouldRevalidate(RequestInterface $request, Response $response)`
499
+
500
+ ## 3.6.0 - 2013-05-29
501
+
502
+ * ServiceDescription now implements ToArrayInterface
503
+ * Added command.hidden_params to blacklist certain headers from being treated as additionalParameters
504
+ * Guzzle can now correctly parse incomplete URLs
505
+ * Mixed casing of headers are now forced to be a single consistent casing across all values for that header.
506
+ * Messages internally use a HeaderCollection object to delegate handling case-insensitive header resolution
507
+ * Removed the whole changedHeader() function system of messages because all header changes now go through addHeader().
508
+ * Specific header implementations can be created for complex headers. When a message creates a header, it uses a
509
+ HeaderFactory which can map specific headers to specific header classes. There is now a Link header and
510
+ CacheControl header implementation.
511
+ * Removed from interface: Guzzle\Http\ClientInterface::setUriTemplate
512
+ * Removed from interface: Guzzle\Http\ClientInterface::setCurlMulti()
513
+ * Removed Guzzle\Http\Message\Request::receivedRequestHeader() and implemented this functionality in
514
+ Guzzle\Http\Curl\RequestMediator
515
+ * Removed the optional $asString parameter from MessageInterface::getHeader(). Just cast the header to a string.
516
+ * Removed the optional $tryChunkedTransfer option from Guzzle\Http\Message\EntityEnclosingRequestInterface
517
+ * Removed the $asObjects argument from Guzzle\Http\Message\MessageInterface::getHeaders()
518
+ * Removed Guzzle\Parser\ParserRegister::get(). Use getParser()
519
+ * Removed Guzzle\Parser\ParserRegister::set(). Use registerParser().
520
+ * All response header helper functions return a string rather than mixing Header objects and strings inconsistently
521
+ * Removed cURL blacklist support. This is no longer necessary now that Expect, Accept, etc. are managed by Guzzle
522
+ directly via interfaces
523
+ * Removed the injecting of a request object onto a response object. The methods to get and set a request still exist
524
+ but are a no-op until removed.
525
+ * Most classes that used to require a ``Guzzle\Service\Command\CommandInterface` typehint now request a
526
+ `Guzzle\Service\Command\ArrayCommandInterface`.
527
+ * Added `Guzzle\Http\Message\RequestInterface::startResponse()` to the RequestInterface to handle injecting a response
528
+ on a request while the request is still being transferred
529
+ * The ability to case-insensitively search for header values
530
+ * Guzzle\Http\Message\Header::hasExactHeader
531
+ * Guzzle\Http\Message\Header::raw. Use getAll()
532
+ * Deprecated cache control specific methods on Guzzle\Http\Message\AbstractMessage. Use the CacheControl header object
533
+ instead.
534
+ * `Guzzle\Service\Command\CommandInterface` now extends from ToArrayInterface and ArrayAccess
535
+ * Added the ability to cast Model objects to a string to view debug information.
536
+
537
+ ## 3.5.0 - 2013-05-13
538
+
539
+ * Bug: Fixed a regression so that request responses are parsed only once per oncomplete event rather than multiple times
540
+ * Bug: Better cleanup of one-time events across the board (when an event is meant to fire once, it will now remove
541
+ itself from the EventDispatcher)
542
+ * Bug: `Guzzle\Log\MessageFormatter` now properly writes "total_time" and "connect_time" values
543
+ * Bug: Cloning an EntityEnclosingRequest now clones the EntityBody too
544
+ * Bug: Fixed an undefined index error when parsing nested JSON responses with a sentAs parameter that reference a
545
+ non-existent key
546
+ * Bug: All __call() method arguments are now required (helps with mocking frameworks)
547
+ * Deprecating Response::getRequest() and now using a shallow clone of a request object to remove a circular reference
548
+ to help with refcount based garbage collection of resources created by sending a request
549
+ * Deprecating ZF1 cache and log adapters. These will be removed in the next major version.
550
+ * Deprecating `Response::getPreviousResponse()` (method signature still exists, but it'sdeprecated). Use the
551
+ HistoryPlugin for a history.
552
+ * Added a `responseBody` alias for the `response_body` location
553
+ * Refactored internals to no longer rely on Response::getRequest()
554
+ * HistoryPlugin can now be cast to a string
555
+ * HistoryPlugin now logs transactions rather than requests and responses to more accurately keep track of the requests
556
+ and responses that are sent over the wire
557
+ * Added `getEffectiveUrl()` and `getRedirectCount()` to Response objects
558
+
559
+ ## 3.4.3 - 2013-04-30
560
+
561
+ * Bug fix: Fixing bug introduced in 3.4.2 where redirect responses are duplicated on the final redirected response
562
+ * Added a check to re-extract the temp cacert bundle from the phar before sending each request
563
+
564
+ ## 3.4.2 - 2013-04-29
565
+
566
+ * Bug fix: Stream objects now work correctly with "a" and "a+" modes
567
+ * Bug fix: Removing `Transfer-Encoding: chunked` header when a Content-Length is present
568
+ * Bug fix: AsyncPlugin no longer forces HEAD requests
569
+ * Bug fix: DateTime timezones are now properly handled when using the service description schema formatter
570
+ * Bug fix: CachePlugin now properly handles stale-if-error directives when a request to the origin server fails
571
+ * Setting a response on a request will write to the custom request body from the response body if one is specified
572
+ * LogPlugin now writes to php://output when STDERR is undefined
573
+ * Added the ability to set multiple POST files for the same key in a single call
574
+ * application/x-www-form-urlencoded POSTs now use the utf-8 charset by default
575
+ * Added the ability to queue CurlExceptions to the MockPlugin
576
+ * Cleaned up how manual responses are queued on requests (removed "queued_response" and now using request.before_send)
577
+ * Configuration loading now allows remote files
578
+
579
+ ## 3.4.1 - 2013-04-16
580
+
581
+ * Large refactoring to how CurlMulti handles work. There is now a proxy that sits in front of a pool of CurlMulti
582
+ handles. This greatly simplifies the implementation, fixes a couple bugs, and provides a small performance boost.
583
+ * Exceptions are now properly grouped when sending requests in parallel
584
+ * Redirects are now properly aggregated when a multi transaction fails
585
+ * Redirects now set the response on the original object even in the event of a failure
586
+ * Bug fix: Model names are now properly set even when using $refs
587
+ * Added support for PHP 5.5's CurlFile to prevent warnings with the deprecated @ syntax
588
+ * Added support for oauth_callback in OAuth signatures
589
+ * Added support for oauth_verifier in OAuth signatures
590
+ * Added support to attempt to retrieve a command first literally, then ucfirst, the with inflection
591
+
592
+ ## 3.4.0 - 2013-04-11
593
+
594
+ * Bug fix: URLs are now resolved correctly based on http://tools.ietf.org/html/rfc3986#section-5.2. #289
595
+ * Bug fix: Absolute URLs with a path in a service description will now properly override the base URL. #289
596
+ * Bug fix: Parsing a query string with a single PHP array value will now result in an array. #263
597
+ * Bug fix: Better normalization of the User-Agent header to prevent duplicate headers. #264.
598
+ * Bug fix: Added `number` type to service descriptions.
599
+ * Bug fix: empty parameters are removed from an OAuth signature
600
+ * Bug fix: Revalidating a cache entry prefers the Last-Modified over the Date header
601
+ * Bug fix: Fixed "array to string" error when validating a union of types in a service description
602
+ * Bug fix: Removed code that attempted to determine the size of a stream when data is written to the stream
603
+ * Bug fix: Not including an `oauth_token` if the value is null in the OauthPlugin.
604
+ * Bug fix: Now correctly aggregating successful requests and failed requests in CurlMulti when a redirect occurs.
605
+ * The new default CURLOPT_TIMEOUT setting has been increased to 150 seconds so that Guzzle works on poor connections.
606
+ * Added a feature to EntityEnclosingRequest::setBody() that will automatically set the Content-Type of the request if
607
+ the Content-Type can be determined based on the entity body or the path of the request.
608
+ * Added the ability to overwrite configuration settings in a client when grabbing a throwaway client from a builder.
609
+ * Added support for a PSR-3 LogAdapter.
610
+ * Added a `command.after_prepare` event
611
+ * Added `oauth_callback` parameter to the OauthPlugin
612
+ * Added the ability to create a custom stream class when using a stream factory
613
+ * Added a CachingEntityBody decorator
614
+ * Added support for `additionalParameters` in service descriptions to define how custom parameters are serialized.
615
+ * The bundled SSL certificate is now provided in the phar file and extracted when running Guzzle from a phar.
616
+ * You can now send any EntityEnclosingRequest with POST fields or POST files and cURL will handle creating bodies
617
+ * POST requests using a custom entity body are now treated exactly like PUT requests but with a custom cURL method. This
618
+ means that the redirect behavior of POST requests with custom bodies will not be the same as POST requests that use
619
+ POST fields or files (the latter is only used when emulating a form POST in the browser).
620
+ * Lots of cleanup to CurlHandle::factory and RequestFactory::createRequest
621
+
622
+ ## 3.3.1 - 2013-03-10
623
+
624
+ * Added the ability to create PHP streaming responses from HTTP requests
625
+ * Bug fix: Running any filters when parsing response headers with service descriptions
626
+ * Bug fix: OauthPlugin fixes to allow for multi-dimensional array signing, and sorting parameters before signing
627
+ * Bug fix: Removed the adding of default empty arrays and false Booleans to responses in order to be consistent across
628
+ response location visitors.
629
+ * Bug fix: Removed the possibility of creating configuration files with circular dependencies
630
+ * RequestFactory::create() now uses the key of a POST file when setting the POST file name
631
+ * Added xmlAllowEmpty to serialize an XML body even if no XML specific parameters are set
632
+
633
+ ## 3.3.0 - 2013-03-03
634
+
635
+ * A large number of performance optimizations have been made
636
+ * Bug fix: Added 'wb' as a valid write mode for streams
637
+ * Bug fix: `Guzzle\Http\Message\Response::json()` now allows scalar values to be returned
638
+ * Bug fix: Fixed bug in `Guzzle\Http\Message\Response` where wrapping quotes were stripped from `getEtag()`
639
+ * BC: Removed `Guzzle\Http\Utils` class
640
+ * BC: Setting a service description on a client will no longer modify the client's command factories.
641
+ * BC: Emitting IO events from a RequestMediator is now a parameter that must be set in a request's curl options using
642
+ the 'emit_io' key. This was previously set under a request's parameters using 'curl.emit_io'
643
+ * BC: `Guzzle\Stream\Stream::getWrapper()` and `Guzzle\Stream\Stream::getSteamType()` are no longer converted to
644
+ lowercase
645
+ * Operation parameter objects are now lazy loaded internally
646
+ * Added ErrorResponsePlugin that can throw errors for responses defined in service description operations' errorResponses
647
+ * Added support for instantiating responseType=class responseClass classes. Classes must implement
648
+ `Guzzle\Service\Command\ResponseClassInterface`
649
+ * Added support for additionalProperties for top-level parameters in responseType=model responseClasses. These
650
+ additional properties also support locations and can be used to parse JSON responses where the outermost part of the
651
+ JSON is an array
652
+ * Added support for nested renaming of JSON models (rename sentAs to name)
653
+ * CachePlugin
654
+ * Added support for stale-if-error so that the CachePlugin can now serve stale content from the cache on error
655
+ * Debug headers can now added to cached response in the CachePlugin
656
+
657
+ ## 3.2.0 - 2013-02-14
658
+
659
+ * CurlMulti is no longer reused globally. A new multi object is created per-client. This helps to isolate clients.
660
+ * URLs with no path no longer contain a "/" by default
661
+ * Guzzle\Http\QueryString does no longer manages the leading "?". This is now handled in Guzzle\Http\Url.
662
+ * BadResponseException no longer includes the full request and response message
663
+ * Adding setData() to Guzzle\Service\Description\ServiceDescriptionInterface
664
+ * Adding getResponseBody() to Guzzle\Http\Message\RequestInterface
665
+ * Various updates to classes to use ServiceDescriptionInterface type hints rather than ServiceDescription
666
+ * Header values can now be normalized into distinct values when multiple headers are combined with a comma separated list
667
+ * xmlEncoding can now be customized for the XML declaration of a XML service description operation
668
+ * Guzzle\Http\QueryString now uses Guzzle\Http\QueryAggregator\QueryAggregatorInterface objects to add custom value
669
+ aggregation and no longer uses callbacks
670
+ * The URL encoding implementation of Guzzle\Http\QueryString can now be customized
671
+ * Bug fix: Filters were not always invoked for array service description parameters
672
+ * Bug fix: Redirects now use a target response body rather than a temporary response body
673
+ * Bug fix: The default exponential backoff BackoffPlugin was not giving when the request threshold was exceeded
674
+ * Bug fix: Guzzle now takes the first found value when grabbing Cache-Control directives
675
+
676
+ ## 3.1.2 - 2013-01-27
677
+
678
+ * Refactored how operation responses are parsed. Visitors now include a before() method responsible for parsing the
679
+ response body. For example, the XmlVisitor now parses the XML response into an array in the before() method.
680
+ * Fixed an issue where cURL would not automatically decompress responses when the Accept-Encoding header was sent
681
+ * CURLOPT_SSL_VERIFYHOST is never set to 1 because it is deprecated (see 5e0ff2ef20f839e19d1eeb298f90ba3598784444)
682
+ * Fixed a bug where redirect responses were not chained correctly using getPreviousResponse()
683
+ * Setting default headers on a client after setting the user-agent will not erase the user-agent setting
684
+
685
+ ## 3.1.1 - 2013-01-20
686
+
687
+ * Adding wildcard support to Guzzle\Common\Collection::getPath()
688
+ * Adding alias support to ServiceBuilder configs
689
+ * Adding Guzzle\Service\Resource\CompositeResourceIteratorFactory and cleaning up factory interface
690
+
691
+ ## 3.1.0 - 2013-01-12
692
+
693
+ * BC: CurlException now extends from RequestException rather than BadResponseException
694
+ * BC: Renamed Guzzle\Plugin\Cache\CanCacheStrategyInterface::canCache() to canCacheRequest() and added CanCacheResponse()
695
+ * Added getData to ServiceDescriptionInterface
696
+ * Added context array to RequestInterface::setState()
697
+ * Bug: Removing hard dependency on the BackoffPlugin from Guzzle\Http
698
+ * Bug: Adding required content-type when JSON request visitor adds JSON to a command
699
+ * Bug: Fixing the serialization of a service description with custom data
700
+ * Made it easier to deal with exceptions thrown when transferring commands or requests in parallel by providing
701
+ an array of successful and failed responses
702
+ * Moved getPath from Guzzle\Service\Resource\Model to Guzzle\Common\Collection
703
+ * Added Guzzle\Http\IoEmittingEntityBody
704
+ * Moved command filtration from validators to location visitors
705
+ * Added `extends` attributes to service description parameters
706
+ * Added getModels to ServiceDescriptionInterface
707
+
708
+ ## 3.0.7 - 2012-12-19
709
+
710
+ * Fixing phar detection when forcing a cacert to system if null or true
711
+ * Allowing filename to be passed to `Guzzle\Http\Message\Request::setResponseBody()`
712
+ * Cleaning up `Guzzle\Common\Collection::inject` method
713
+ * Adding a response_body location to service descriptions
714
+
715
+ ## 3.0.6 - 2012-12-09
716
+
717
+ * CurlMulti performance improvements
718
+ * Adding setErrorResponses() to Operation
719
+ * composer.json tweaks
720
+
721
+ ## 3.0.5 - 2012-11-18
722
+
723
+ * Bug: Fixing an infinite recursion bug caused from revalidating with the CachePlugin
724
+ * Bug: Response body can now be a string containing "0"
725
+ * Bug: Using Guzzle inside of a phar uses system by default but now allows for a custom cacert
726
+ * Bug: QueryString::fromString now properly parses query string parameters that contain equal signs
727
+ * Added support for XML attributes in service description responses
728
+ * DefaultRequestSerializer now supports array URI parameter values for URI template expansion
729
+ * Added better mimetype guessing to requests and post files
730
+
731
+ ## 3.0.4 - 2012-11-11
732
+
733
+ * Bug: Fixed a bug when adding multiple cookies to a request to use the correct glue value
734
+ * Bug: Cookies can now be added that have a name, domain, or value set to "0"
735
+ * Bug: Using the system cacert bundle when using the Phar
736
+ * Added json and xml methods to Response to make it easier to parse JSON and XML response data into data structures
737
+ * Enhanced cookie jar de-duplication
738
+ * Added the ability to enable strict cookie jars that throw exceptions when invalid cookies are added
739
+ * Added setStream to StreamInterface to actually make it possible to implement custom rewind behavior for entity bodies
740
+ * Added the ability to create any sort of hash for a stream rather than just an MD5 hash
741
+
742
+ ## 3.0.3 - 2012-11-04
743
+
744
+ * Implementing redirects in PHP rather than cURL
745
+ * Added PECL URI template extension and using as default parser if available
746
+ * Bug: Fixed Content-Length parsing of Response factory
747
+ * Adding rewind() method to entity bodies and streams. Allows for custom rewinding of non-repeatable streams.
748
+ * Adding ToArrayInterface throughout library
749
+ * Fixing OauthPlugin to create unique nonce values per request
750
+
751
+ ## 3.0.2 - 2012-10-25
752
+
753
+ * Magic methods are enabled by default on clients
754
+ * Magic methods return the result of a command
755
+ * Service clients no longer require a base_url option in the factory
756
+ * Bug: Fixed an issue with URI templates where null template variables were being expanded
757
+
758
+ ## 3.0.1 - 2012-10-22
759
+
760
+ * Models can now be used like regular collection objects by calling filter, map, etc.
761
+ * Models no longer require a Parameter structure or initial data in the constructor
762
+ * Added a custom AppendIterator to get around a PHP bug with the `\AppendIterator`
763
+
764
+ ## 3.0.0 - 2012-10-15
765
+
766
+ * Rewrote service description format to be based on Swagger
767
+ * Now based on JSON schema
768
+ * Added nested input structures and nested response models
769
+ * Support for JSON and XML input and output models
770
+ * Renamed `commands` to `operations`
771
+ * Removed dot class notation
772
+ * Removed custom types
773
+ * Broke the project into smaller top-level namespaces to be more component friendly
774
+ * Removed support for XML configs and descriptions. Use arrays or JSON files.
775
+ * Removed the Validation component and Inspector
776
+ * Moved all cookie code to Guzzle\Plugin\Cookie
777
+ * Magic methods on a Guzzle\Service\Client now return the command un-executed.
778
+ * Calling getResult() or getResponse() on a command will lazily execute the command if needed.
779
+ * Now shipping with cURL's CA certs and using it by default
780
+ * Added previousResponse() method to response objects
781
+ * No longer sending Accept and Accept-Encoding headers on every request
782
+ * Only sending an Expect header by default when a payload is greater than 1MB
783
+ * Added/moved client options:
784
+ * curl.blacklist to curl.option.blacklist
785
+ * Added ssl.certificate_authority
786
+ * Added a Guzzle\Iterator component
787
+ * Moved plugins from Guzzle\Http\Plugin to Guzzle\Plugin
788
+ * Added a more robust backoff retry strategy (replaced the ExponentialBackoffPlugin)
789
+ * Added a more robust caching plugin
790
+ * Added setBody to response objects
791
+ * Updating LogPlugin to use a more flexible MessageFormatter
792
+ * Added a completely revamped build process
793
+ * Cleaning up Collection class and removing default values from the get method
794
+ * Fixed ZF2 cache adapters
795
+
796
+ ## 2.8.8 - 2012-10-15
797
+
798
+ * Bug: Fixed a cookie issue that caused dot prefixed domains to not match where popular browsers did
799
+
800
+ ## 2.8.7 - 2012-09-30
801
+
802
+ * Bug: Fixed config file aliases for JSON includes
803
+ * Bug: Fixed cookie bug on a request object by using CookieParser to parse cookies on requests
804
+ * Bug: Removing the path to a file when sending a Content-Disposition header on a POST upload
805
+ * Bug: Hardening request and response parsing to account for missing parts
806
+ * Bug: Fixed PEAR packaging
807
+ * Bug: Fixed Request::getInfo
808
+ * Bug: Fixed cases where CURLM_CALL_MULTI_PERFORM return codes were causing curl transactions to fail
809
+ * Adding the ability for the namespace Iterator factory to look in multiple directories
810
+ * Added more getters/setters/removers from service descriptions
811
+ * Added the ability to remove POST fields from OAuth signatures
812
+ * OAuth plugin now supports 2-legged OAuth
813
+
814
+ ## 2.8.6 - 2012-09-05
815
+
816
+ * Added the ability to modify and build service descriptions
817
+ * Added the use of visitors to apply parameters to locations in service descriptions using the dynamic command
818
+ * Added a `json` parameter location
819
+ * Now allowing dot notation for classes in the CacheAdapterFactory
820
+ * Using the union of two arrays rather than an array_merge when extending service builder services and service params
821
+ * Ensuring that a service is a string before doing strpos() checks on it when substituting services for references
822
+ in service builder config files.
823
+ * Services defined in two different config files that include one another will by default replace the previously
824
+ defined service, but you can now create services that extend themselves and merge their settings over the previous
825
+ * The JsonLoader now supports aliasing filenames with different filenames. This allows you to alias something like
826
+ '_default' with a default JSON configuration file.
827
+
828
+ ## 2.8.5 - 2012-08-29
829
+
830
+ * Bug: Suppressed empty arrays from URI templates
831
+ * Bug: Added the missing $options argument from ServiceDescription::factory to enable caching
832
+ * Added support for HTTP responses that do not contain a reason phrase in the start-line
833
+ * AbstractCommand commands are now invokable
834
+ * Added a way to get the data used when signing an Oauth request before a request is sent
835
+
836
+ ## 2.8.4 - 2012-08-15
837
+
838
+ * Bug: Custom delay time calculations are no longer ignored in the ExponentialBackoffPlugin
839
+ * Added the ability to transfer entity bodies as a string rather than streamed. This gets around curl error 65. Set `body_as_string` in a request's curl options to enable.
840
+ * Added a StreamInterface, EntityBodyInterface, and added ftell() to Guzzle\Common\Stream
841
+ * Added an AbstractEntityBodyDecorator and a ReadLimitEntityBody decorator to transfer only a subset of a decorated stream
842
+ * Stream and EntityBody objects will now return the file position to the previous position after a read required operation (e.g. getContentMd5())
843
+ * Added additional response status codes
844
+ * Removed SSL information from the default User-Agent header
845
+ * DELETE requests can now send an entity body
846
+ * Added an EventDispatcher to the ExponentialBackoffPlugin and added an ExponentialBackoffLogger to log backoff retries
847
+ * Added the ability of the MockPlugin to consume mocked request bodies
848
+ * LogPlugin now exposes request and response objects in the extras array
849
+
850
+ ## 2.8.3 - 2012-07-30
851
+
852
+ * Bug: Fixed a case where empty POST requests were sent as GET requests
853
+ * Bug: Fixed a bug in ExponentialBackoffPlugin that caused fatal errors when retrying an EntityEnclosingRequest that does not have a body
854
+ * Bug: Setting the response body of a request to null after completing a request, not when setting the state of a request to new
855
+ * Added multiple inheritance to service description commands
856
+ * Added an ApiCommandInterface and added ``getParamNames()`` and ``hasParam()``
857
+ * Removed the default 2mb size cutoff from the Md5ValidatorPlugin so that it now defaults to validating everything
858
+ * Changed CurlMulti::perform to pass a smaller timeout to CurlMulti::executeHandles
859
+
860
+ ## 2.8.2 - 2012-07-24
861
+
862
+ * Bug: Query string values set to 0 are no longer dropped from the query string
863
+ * Bug: A Collection object is no longer created each time a call is made to ``Guzzle\Service\Command\AbstractCommand::getRequestHeaders()``
864
+ * Bug: ``+`` is now treated as an encoded space when parsing query strings
865
+ * QueryString and Collection performance improvements
866
+ * Allowing dot notation for class paths in filters attribute of a service descriptions
867
+
868
+ ## 2.8.1 - 2012-07-16
869
+
870
+ * Loosening Event Dispatcher dependency
871
+ * POST redirects can now be customized using CURLOPT_POSTREDIR
872
+
873
+ ## 2.8.0 - 2012-07-15
874
+
875
+ * BC: Guzzle\Http\Query
876
+ * Query strings with empty variables will always show an equal sign unless the variable is set to QueryString::BLANK (e.g. ?acl= vs ?acl)
877
+ * Changed isEncodingValues() and isEncodingFields() to isUrlEncoding()
878
+ * Changed setEncodeValues(bool) and setEncodeFields(bool) to useUrlEncoding(bool)
879
+ * Changed the aggregation functions of QueryString to be static methods
880
+ * Can now use fromString() with querystrings that have a leading ?
881
+ * cURL configuration values can be specified in service descriptions using ``curl.`` prefixed parameters
882
+ * Content-Length is set to 0 before emitting the request.before_send event when sending an empty request body
883
+ * Cookies are no longer URL decoded by default
884
+ * Bug: URI template variables set to null are no longer expanded
885
+
886
+ ## 2.7.2 - 2012-07-02
887
+
888
+ * BC: Moving things to get ready for subtree splits. Moving Inflection into Common. Moving Guzzle\Http\Parser to Guzzle\Parser.
889
+ * BC: Removing Guzzle\Common\Batch\Batch::count() and replacing it with isEmpty()
890
+ * CachePlugin now allows for a custom request parameter function to check if a request can be cached
891
+ * Bug fix: CachePlugin now only caches GET and HEAD requests by default
892
+ * Bug fix: Using header glue when transferring headers over the wire
893
+ * Allowing deeply nested arrays for composite variables in URI templates
894
+ * Batch divisors can now return iterators or arrays
895
+
896
+ ## 2.7.1 - 2012-06-26
897
+
898
+ * Minor patch to update version number in UA string
899
+ * Updating build process
900
+
901
+ ## 2.7.0 - 2012-06-25
902
+
903
+ * BC: Inflection classes moved to Guzzle\Inflection. No longer static methods. Can now inject custom inflectors into classes.
904
+ * BC: Removed magic setX methods from commands
905
+ * BC: Magic methods mapped to service description commands are now inflected in the command factory rather than the client __call() method
906
+ * Verbose cURL options are no longer enabled by default. Set curl.debug to true on a client to enable.
907
+ * Bug: Now allowing colons in a response start-line (e.g. HTTP/1.1 503 Service Unavailable: Back-end server is at capacity)
908
+ * Guzzle\Service\Resource\ResourceIteratorApplyBatched now internally uses the Guzzle\Common\Batch namespace
909
+ * Added Guzzle\Service\Plugin namespace and a PluginCollectionPlugin
910
+ * Added the ability to set POST fields and files in a service description
911
+ * Guzzle\Http\EntityBody::factory() now accepts objects with a __toString() method
912
+ * Adding a command.before_prepare event to clients
913
+ * Added BatchClosureTransfer and BatchClosureDivisor
914
+ * BatchTransferException now includes references to the batch divisor and transfer strategies
915
+ * Fixed some tests so that they pass more reliably
916
+ * Added Guzzle\Common\Log\ArrayLogAdapter
917
+
918
+ ## 2.6.6 - 2012-06-10
919
+
920
+ * BC: Removing Guzzle\Http\Plugin\BatchQueuePlugin
921
+ * BC: Removing Guzzle\Service\Command\CommandSet
922
+ * Adding generic batching system (replaces the batch queue plugin and command set)
923
+ * Updating ZF cache and log adapters and now using ZF's composer repository
924
+ * Bug: Setting the name of each ApiParam when creating through an ApiCommand
925
+ * Adding result_type, result_doc, deprecated, and doc_url to service descriptions
926
+ * Bug: Changed the default cookie header casing back to 'Cookie'
927
+
928
+ ## 2.6.5 - 2012-06-03
929
+
930
+ * BC: Renaming Guzzle\Http\Message\RequestInterface::getResourceUri() to getResource()
931
+ * BC: Removing unused AUTH_BASIC and AUTH_DIGEST constants from
932
+ * BC: Guzzle\Http\Cookie is now used to manage Set-Cookie data, not Cookie data
933
+ * BC: Renaming methods in the CookieJarInterface
934
+ * Moving almost all cookie logic out of the CookiePlugin and into the Cookie or CookieJar implementations
935
+ * Making the default glue for HTTP headers ';' instead of ','
936
+ * Adding a removeValue to Guzzle\Http\Message\Header
937
+ * Adding getCookies() to request interface.
938
+ * Making it easier to add event subscribers to HasDispatcherInterface classes. Can now directly call addSubscriber()
939
+
940
+ ## 2.6.4 - 2012-05-30
941
+
942
+ * BC: Cleaning up how POST files are stored in EntityEnclosingRequest objects. Adding PostFile class.
943
+ * BC: Moving ApiCommand specific functionality from the Inspector and on to the ApiCommand
944
+ * Bug: Fixing magic method command calls on clients
945
+ * Bug: Email constraint only validates strings
946
+ * Bug: Aggregate POST fields when POST files are present in curl handle
947
+ * Bug: Fixing default User-Agent header
948
+ * Bug: Only appending or prepending parameters in commands if they are specified
949
+ * Bug: Not requiring response reason phrases or status codes to match a predefined list of codes
950
+ * Allowing the use of dot notation for class namespaces when using instance_of constraint
951
+ * Added any_match validation constraint
952
+ * Added an AsyncPlugin
953
+ * Passing request object to the calculateWait method of the ExponentialBackoffPlugin
954
+ * Allowing the result of a command object to be changed
955
+ * Parsing location and type sub values when instantiating a service description rather than over and over at runtime
956
+
957
+ ## 2.6.3 - 2012-05-23
958
+
959
+ * [BC] Guzzle\Common\FromConfigInterface no longer requires any config options.
960
+ * [BC] Refactoring how POST files are stored on an EntityEnclosingRequest. They are now separate from POST fields.
961
+ * You can now use an array of data when creating PUT request bodies in the request factory.
962
+ * Removing the requirement that HTTPS requests needed a Cache-Control: public directive to be cacheable.
963
+ * [Http] Adding support for Content-Type in multipart POST uploads per upload
964
+ * [Http] Added support for uploading multiple files using the same name (foo[0], foo[1])
965
+ * Adding more POST data operations for easier manipulation of POST data.
966
+ * You can now set empty POST fields.
967
+ * The body of a request is only shown on EntityEnclosingRequest objects that do not use POST files.
968
+ * Split the Guzzle\Service\Inspector::validateConfig method into two methods. One to initialize when a command is created, and one to validate.
969
+ * CS updates
970
+
971
+ ## 2.6.2 - 2012-05-19
972
+
973
+ * [Http] Better handling of nested scope requests in CurlMulti. Requests are now always prepares in the send() method rather than the addRequest() method.
974
+
975
+ ## 2.6.1 - 2012-05-19
976
+
977
+ * [BC] Removing 'path' support in service descriptions. Use 'uri'.
978
+ * [BC] Guzzle\Service\Inspector::parseDocBlock is now protected. Adding getApiParamsForClass() with cache.
979
+ * [BC] Removing Guzzle\Common\NullObject. Use https://github.com/mtdowling/NullObject if you need it.
980
+ * [BC] Removing Guzzle\Common\XmlElement.
981
+ * All commands, both dynamic and concrete, have ApiCommand objects.
982
+ * Adding a fix for CurlMulti so that if all of the connections encounter some sort of curl error, then the loop exits.
983
+ * Adding checks to EntityEnclosingRequest so that empty POST files and fields are ignored.
984
+ * Making the method signature of Guzzle\Service\Builder\ServiceBuilder::factory more flexible.
985
+
986
+ ## 2.6.0 - 2012-05-15
987
+
988
+ * [BC] Moving Guzzle\Service\Builder to Guzzle\Service\Builder\ServiceBuilder
989
+ * [BC] Executing a Command returns the result of the command rather than the command
990
+ * [BC] Moving all HTTP parsing logic to Guzzle\Http\Parsers. Allows for faster C implementations if needed.
991
+ * [BC] Changing the Guzzle\Http\Message\Response::setProtocol() method to accept a protocol and version in separate args.
992
+ * [BC] Moving ResourceIterator* to Guzzle\Service\Resource
993
+ * [BC] Completely refactored ResourceIterators to iterate over a cloned command object
994
+ * [BC] Moved Guzzle\Http\UriTemplate to Guzzle\Http\Parser\UriTemplate\UriTemplate
995
+ * [BC] Guzzle\Guzzle is now deprecated
996
+ * Moving Guzzle\Common\Guzzle::inject to Guzzle\Common\Collection::inject
997
+ * Adding Guzzle\Version class to give version information about Guzzle
998
+ * Adding Guzzle\Http\Utils class to provide getDefaultUserAgent() and getHttpDate()
999
+ * Adding Guzzle\Curl\CurlVersion to manage caching curl_version() data
1000
+ * ServiceDescription and ServiceBuilder are now cacheable using similar configs
1001
+ * Changing the format of XML and JSON service builder configs. Backwards compatible.
1002
+ * Cleaned up Cookie parsing
1003
+ * Trimming the default Guzzle User-Agent header
1004
+ * Adding a setOnComplete() method to Commands that is called when a command completes
1005
+ * Keeping track of requests that were mocked in the MockPlugin
1006
+ * Fixed a caching bug in the CacheAdapterFactory
1007
+ * Inspector objects can be injected into a Command object
1008
+ * Refactoring a lot of code and tests to be case insensitive when dealing with headers
1009
+ * Adding Guzzle\Http\Message\HeaderComparison for easy comparison of HTTP headers using a DSL
1010
+ * Adding the ability to set global option overrides to service builder configs
1011
+ * Adding the ability to include other service builder config files from within XML and JSON files
1012
+ * Moving the parseQuery method out of Url and on to QueryString::fromString() as a static factory method.
1013
+
1014
+ ## 2.5.0 - 2012-05-08
1015
+
1016
+ * Major performance improvements
1017
+ * [BC] Simplifying Guzzle\Common\Collection. Please check to see if you are using features that are now deprecated.
1018
+ * [BC] Using a custom validation system that allows a flyweight implementation for much faster validation. No longer using Symfony2 Validation component.
1019
+ * [BC] No longer supporting "{{ }}" for injecting into command or UriTemplates. Use "{}"
1020
+ * Added the ability to passed parameters to all requests created by a client
1021
+ * Added callback functionality to the ExponentialBackoffPlugin
1022
+ * Using microtime in ExponentialBackoffPlugin to allow more granular backoff strategies.
1023
+ * Rewinding request stream bodies when retrying requests
1024
+ * Exception is thrown when JSON response body cannot be decoded
1025
+ * Added configurable magic method calls to clients and commands. This is off by default.
1026
+ * Fixed a defect that added a hash to every parsed URL part
1027
+ * Fixed duplicate none generation for OauthPlugin.
1028
+ * Emitting an event each time a client is generated by a ServiceBuilder
1029
+ * Using an ApiParams object instead of a Collection for parameters of an ApiCommand
1030
+ * cache.* request parameters should be renamed to params.cache.*
1031
+ * Added the ability to set arbitrary curl options on requests (disable_wire, progress, etc.). See CurlHandle.
1032
+ * Added the ability to disable type validation of service descriptions
1033
+ * ServiceDescriptions and ServiceBuilders are now Serializable
backend/vendor/guzzlehttp/guzzle/LICENSE ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright (c) 2014 Michael Dowling, https://github.com/mtdowling <mtdowling@gmail.com>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
backend/vendor/guzzlehttp/guzzle/Makefile ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ all: clean coverage docs
2
+
3
+ start-server:
4
+ cd vendor/guzzlehttp/ringphp && make start-server
5
+
6
+ stop-server:
7
+ cd vendor/guzzlehttp/ringphp && make stop-server
8
+
9
+ test: start-server
10
+ vendor/bin/phpunit
11
+ $(MAKE) stop-server
12
+
13
+ coverage: start-server
14
+ vendor/bin/phpunit --coverage-html=artifacts/coverage
15
+ $(MAKE) stop-server
16
+
17
+ view-coverage:
18
+ open artifacts/coverage/index.html
19
+
20
+ clean:
21
+ rm -rf artifacts/*
22
+
23
+ docs:
24
+ cd docs && make html && cd ..
25
+
26
+ view-docs:
27
+ open docs/_build/html/index.html
28
+
29
+ tag:
30
+ $(if $(TAG),,$(error TAG is not defined. Pass via "make tag TAG=4.2.1"))
31
+ @echo Tagging $(TAG)
32
+ chag update $(TAG)
33
+ sed -i '' -e "s/VERSION = '.*'/VERSION = '$(TAG)'/" src/ClientInterface.php
34
+ php -l src/ClientInterface.php
35
+ git add -A
36
+ git commit -m '$(TAG) release'
37
+ chag tag
38
+
39
+ perf: start-server
40
+ php tests/perf.php
41
+ $(MAKE) stop-server
42
+
43
+ package: burgomaster
44
+ php build/packager.php
45
+
46
+ burgomaster:
47
+ mkdir -p build/artifacts
48
+ curl -s https://raw.githubusercontent.com/mtdowling/Burgomaster/0.0.2/src/Burgomaster.php > build/artifacts/Burgomaster.php
49
+
50
+ .PHONY: docs burgomaster
backend/vendor/guzzlehttp/guzzle/README.md ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Guzzle, PHP HTTP client and webservice framework
2
+ ================================================
3
+
4
+ [![Build Status](https://secure.travis-ci.org/guzzle/guzzle.png?branch=master)](http://travis-ci.org/guzzle/guzzle)
5
+
6
+ Guzzle is a PHP HTTP client that makes it easy to send HTTP requests and
7
+ trivial to integrate with web services.
8
+
9
+ - Manages things like persistent connections, represents query strings as
10
+ collections, simplifies sending streaming POST requests with fields and
11
+ files, and abstracts away the underlying HTTP transport layer.
12
+ - Can send both synchronous and asynchronous requests using the same interface
13
+ without requiring a dependency on a specific event loop.
14
+ - Pluggable HTTP adapters allows Guzzle to integrate with any method you choose
15
+ for sending HTTP requests over the wire (e.g., cURL, sockets, PHP's stream
16
+ wrapper, non-blocking event loops like ReactPHP.
17
+ - Guzzle makes it so that you no longer need to fool around with cURL options,
18
+ stream contexts, or sockets.
19
+
20
+ ```php
21
+ $client = new GuzzleHttp\Client();
22
+ $response = $client->get('http://guzzlephp.org');
23
+ $res = $client->get('https://api.github.com/user', ['auth' => ['user', 'pass']]);
24
+ echo $res->getStatusCode();
25
+ // "200"
26
+ echo $res->getHeader('content-type');
27
+ // 'application/json; charset=utf8'
28
+ echo $res->getBody();
29
+ // {"type":"User"...'
30
+ var_export($res->json());
31
+ // Outputs the JSON decoded data
32
+
33
+ // Send an asynchronous request.
34
+ $req = $client->createRequest('GET', 'http://httpbin.org', ['future' => true]);
35
+ $client->send($req)->then(function ($response) {
36
+ echo 'I completed! ' . $response;
37
+ });
38
+ ```
39
+
40
+ Get more information and answers with the
41
+ [Documentation](http://guzzlephp.org/),
42
+ [Forums](https://groups.google.com/forum/?hl=en#!forum/guzzle),
43
+ and [Gitter](https://gitter.im/guzzle/guzzle).
44
+
45
+ ### Installing via Composer
46
+
47
+ The recommended way to install Guzzle is through
48
+ [Composer](http://getcomposer.org).
49
+
50
+ ```bash
51
+ # Install Composer
52
+ curl -sS https://getcomposer.org/installer | php
53
+ ```
54
+
55
+ Next, run the Composer command to install the latest stable version of Guzzle:
56
+
57
+ ```bash
58
+ composer require guzzlehttp/guzzle
59
+ ```
60
+
61
+ After installing, you need to require Composer's autoloader:
62
+
63
+ ```php
64
+ require 'vendor/autoload.php';
65
+ ```
66
+
67
+ ### Documentation
68
+
69
+ More information can be found in the online documentation at
70
+ http://guzzlephp.org/.
backend/vendor/guzzlehttp/guzzle/UPGRADING.md ADDED
@@ -0,0 +1,1050 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Guzzle Upgrade Guide
2
+ ====================
3
+
4
+ 4.x to 5.0
5
+ ----------
6
+
7
+ ## Rewritten Adapter Layer
8
+
9
+ Guzzle now uses `RingPHP <http://ringphp.readthedocs.org/en/latest/>`_ to send
10
+ HTTP requests. The `adapter` option in a `GuzzleHttp\Client` constructor
11
+ is still supported, but it has now been renamed to `handler`. Instead of
12
+ passing a `GuzzleHttp\Adapter\AdapterInterface`, you must now pass a PHP
13
+ `callable` that follows the RingPHP specification.
14
+
15
+ ## Removed Fluent Interfaces
16
+
17
+ `Fluent interfaces were removed <http://ocramius.github.io/blog/fluent-interfaces-are-evil/>`_
18
+ from the following classes:
19
+
20
+ - `GuzzleHttp\Collection`
21
+ - `GuzzleHttp\Url`
22
+ - `GuzzleHttp\Query`
23
+ - `GuzzleHttp\Post\PostBody`
24
+ - `GuzzleHttp\Cookie\SetCookie`
25
+
26
+ ## Removed functions.php
27
+
28
+ Removed "functions.php", so that Guzzle is truly PSR-4 compliant. The following
29
+ functions can be used as replacements.
30
+
31
+ - `GuzzleHttp\json_decode` -> `GuzzleHttp\Utils::jsonDecode`
32
+ - `GuzzleHttp\get_path` -> `GuzzleHttp\Utils::getPath`
33
+ - `GuzzleHttp\Utils::setPath` -> `GuzzleHttp\set_path`
34
+ - `GuzzleHttp\Pool::batch` -> `GuzzleHttp\batch`. This function is, however,
35
+ deprecated in favor of using `GuzzleHttp\Pool::batch()`.
36
+
37
+ The "procedural" global client has been removed with no replacement (e.g.,
38
+ `GuzzleHttp\get()`, `GuzzleHttp\post()`, etc.). Use a `GuzzleHttl\Client`
39
+ object as a replacement.
40
+
41
+ ## `throwImmediately` has been removed
42
+
43
+ The concept of "throwImmediately" has been removed from exceptions and error
44
+ events. This control mechanism was used to stop a transfer of concurrent
45
+ requests from completing. This can now be handled by throwing the exception or
46
+ by cancelling a pool of requests or each outstanding future request
47
+ individually.
48
+
49
+ ## headers event has been removed
50
+
51
+ Removed the "headers" event. This event was only useful for changing the
52
+ body a response once the headers of the response were known. You can implement
53
+ a similar behavior in a number of ways. One example might be to use a
54
+ FnStream that has access to the transaction being sent. For example, when the
55
+ first byte is written, you could check if the response headers match your
56
+ expectations, and if so, change the actual stream body that is being
57
+ written to.
58
+
59
+ ## Updates to HTTP Messages
60
+
61
+ Removed the `asArray` parameter from
62
+ `GuzzleHttp\Message\MessageInterface::getHeader`. If you want to get a header
63
+ value as an array, then use the newly added `getHeaderAsArray()` method of
64
+ `MessageInterface`. This change makes the Guzzle interfaces compatible with
65
+ the PSR-7 interfaces.
66
+
67
+ 3.x to 4.0
68
+ ----------
69
+
70
+ ## Overarching changes:
71
+
72
+ - Now requires PHP 5.4 or greater.
73
+ - No longer requires cURL to send requests.
74
+ - Guzzle no longer wraps every exception it throws. Only exceptions that are
75
+ recoverable are now wrapped by Guzzle.
76
+ - Various namespaces have been removed or renamed.
77
+ - No longer requiring the Symfony EventDispatcher. A custom event dispatcher
78
+ based on the Symfony EventDispatcher is
79
+ now utilized in `GuzzleHttp\Event\EmitterInterface` (resulting in significant
80
+ speed and functionality improvements).
81
+
82
+ Changes per Guzzle 3.x namespace are described below.
83
+
84
+ ## Batch
85
+
86
+ The `Guzzle\Batch` namespace has been removed. This is best left to
87
+ third-parties to implement on top of Guzzle's core HTTP library.
88
+
89
+ ## Cache
90
+
91
+ The `Guzzle\Cache` namespace has been removed. (Todo: No suitable replacement
92
+ has been implemented yet, but hoping to utilize a PSR cache interface).
93
+
94
+ ## Common
95
+
96
+ - Removed all of the wrapped exceptions. It's better to use the standard PHP
97
+ library for unrecoverable exceptions.
98
+ - `FromConfigInterface` has been removed.
99
+ - `Guzzle\Common\Version` has been removed. The VERSION constant can be found
100
+ at `GuzzleHttp\ClientInterface::VERSION`.
101
+
102
+ ### Collection
103
+
104
+ - `getAll` has been removed. Use `toArray` to convert a collection to an array.
105
+ - `inject` has been removed.
106
+ - `keySearch` has been removed.
107
+ - `getPath` no longer supports wildcard expressions. Use something better like
108
+ JMESPath for this.
109
+ - `setPath` now supports appending to an existing array via the `[]` notation.
110
+
111
+ ### Events
112
+
113
+ Guzzle no longer requires Symfony's EventDispatcher component. Guzzle now uses
114
+ `GuzzleHttp\Event\Emitter`.
115
+
116
+ - `Symfony\Component\EventDispatcher\EventDispatcherInterface` is replaced by
117
+ `GuzzleHttp\Event\EmitterInterface`.
118
+ - `Symfony\Component\EventDispatcher\EventDispatcher` is replaced by
119
+ `GuzzleHttp\Event\Emitter`.
120
+ - `Symfony\Component\EventDispatcher\Event` is replaced by
121
+ `GuzzleHttp\Event\Event`, and Guzzle now has an EventInterface in
122
+ `GuzzleHttp\Event\EventInterface`.
123
+ - `AbstractHasDispatcher` has moved to a trait, `HasEmitterTrait`, and
124
+ `HasDispatcherInterface` has moved to `HasEmitterInterface`. Retrieving the
125
+ event emitter of a request, client, etc. now uses the `getEmitter` method
126
+ rather than the `getDispatcher` method.
127
+
128
+ #### Emitter
129
+
130
+ - Use the `once()` method to add a listener that automatically removes itself
131
+ the first time it is invoked.
132
+ - Use the `listeners()` method to retrieve a list of event listeners rather than
133
+ the `getListeners()` method.
134
+ - Use `emit()` instead of `dispatch()` to emit an event from an emitter.
135
+ - Use `attach()` instead of `addSubscriber()` and `detach()` instead of
136
+ `removeSubscriber()`.
137
+
138
+ ```php
139
+ $mock = new Mock();
140
+ // 3.x
141
+ $request->getEventDispatcher()->addSubscriber($mock);
142
+ $request->getEventDispatcher()->removeSubscriber($mock);
143
+ // 4.x
144
+ $request->getEmitter()->attach($mock);
145
+ $request->getEmitter()->detach($mock);
146
+ ```
147
+
148
+ Use the `on()` method to add a listener rather than the `addListener()` method.
149
+
150
+ ```php
151
+ // 3.x
152
+ $request->getEventDispatcher()->addListener('foo', function (Event $event) { /* ... */ } );
153
+ // 4.x
154
+ $request->getEmitter()->on('foo', function (Event $event, $name) { /* ... */ } );
155
+ ```
156
+
157
+ ## Http
158
+
159
+ ### General changes
160
+
161
+ - The cacert.pem certificate has been moved to `src/cacert.pem`.
162
+ - Added the concept of adapters that are used to transfer requests over the
163
+ wire.
164
+ - Simplified the event system.
165
+ - Sending requests in parallel is still possible, but batching is no longer a
166
+ concept of the HTTP layer. Instead, you must use the `complete` and `error`
167
+ events to asynchronously manage parallel request transfers.
168
+ - `Guzzle\Http\Url` has moved to `GuzzleHttp\Url`.
169
+ - `Guzzle\Http\QueryString` has moved to `GuzzleHttp\Query`.
170
+ - QueryAggregators have been rewritten so that they are simply callable
171
+ functions.
172
+ - `GuzzleHttp\StaticClient` has been removed. Use the functions provided in
173
+ `functions.php` for an easy to use static client instance.
174
+ - Exceptions in `GuzzleHttp\Exception` have been updated to all extend from
175
+ `GuzzleHttp\Exception\TransferException`.
176
+
177
+ ### Client
178
+
179
+ Calling methods like `get()`, `post()`, `head()`, etc. no longer create and
180
+ return a request, but rather creates a request, sends the request, and returns
181
+ the response.
182
+
183
+ ```php
184
+ // 3.0
185
+ $request = $client->get('/');
186
+ $response = $request->send();
187
+
188
+ // 4.0
189
+ $response = $client->get('/');
190
+
191
+ // or, to mirror the previous behavior
192
+ $request = $client->createRequest('GET', '/');
193
+ $response = $client->send($request);
194
+ ```
195
+
196
+ `GuzzleHttp\ClientInterface` has changed.
197
+
198
+ - The `send` method no longer accepts more than one request. Use `sendAll` to
199
+ send multiple requests in parallel.
200
+ - `setUserAgent()` has been removed. Use a default request option instead. You
201
+ could, for example, do something like:
202
+ `$client->setConfig('defaults/headers/User-Agent', 'Foo/Bar ' . $client::getDefaultUserAgent())`.
203
+ - `setSslVerification()` has been removed. Use default request options instead,
204
+ like `$client->setConfig('defaults/verify', true)`.
205
+
206
+ `GuzzleHttp\Client` has changed.
207
+
208
+ - The constructor now accepts only an associative array. You can include a
209
+ `base_url` string or array to use a URI template as the base URL of a client.
210
+ You can also specify a `defaults` key that is an associative array of default
211
+ request options. You can pass an `adapter` to use a custom adapter,
212
+ `batch_adapter` to use a custom adapter for sending requests in parallel, or
213
+ a `message_factory` to change the factory used to create HTTP requests and
214
+ responses.
215
+ - The client no longer emits a `client.create_request` event.
216
+ - Creating requests with a client no longer automatically utilize a URI
217
+ template. You must pass an array into a creational method (e.g.,
218
+ `createRequest`, `get`, `put`, etc.) in order to expand a URI template.
219
+
220
+ ### Messages
221
+
222
+ Messages no longer have references to their counterparts (i.e., a request no
223
+ longer has a reference to it's response, and a response no loger has a
224
+ reference to its request). This association is now managed through a
225
+ `GuzzleHttp\Adapter\TransactionInterface` object. You can get references to
226
+ these transaction objects using request events that are emitted over the
227
+ lifecycle of a request.
228
+
229
+ #### Requests with a body
230
+
231
+ - `GuzzleHttp\Message\EntityEnclosingRequest` and
232
+ `GuzzleHttp\Message\EntityEnclosingRequestInterface` have been removed. The
233
+ separation between requests that contain a body and requests that do not
234
+ contain a body has been removed, and now `GuzzleHttp\Message\RequestInterface`
235
+ handles both use cases.
236
+ - Any method that previously accepts a `GuzzleHttp\Response` object now accept a
237
+ `GuzzleHttp\Message\ResponseInterface`.
238
+ - `GuzzleHttp\Message\RequestFactoryInterface` has been renamed to
239
+ `GuzzleHttp\Message\MessageFactoryInterface`. This interface is used to create
240
+ both requests and responses and is implemented in
241
+ `GuzzleHttp\Message\MessageFactory`.
242
+ - POST field and file methods have been removed from the request object. You
243
+ must now use the methods made available to `GuzzleHttp\Post\PostBodyInterface`
244
+ to control the format of a POST body. Requests that are created using a
245
+ standard `GuzzleHttp\Message\MessageFactoryInterface` will automatically use
246
+ a `GuzzleHttp\Post\PostBody` body if the body was passed as an array or if
247
+ the method is POST and no body is provided.
248
+
249
+ ```php
250
+ $request = $client->createRequest('POST', '/');
251
+ $request->getBody()->setField('foo', 'bar');
252
+ $request->getBody()->addFile(new PostFile('file_key', fopen('/path/to/content', 'r')));
253
+ ```
254
+
255
+ #### Headers
256
+
257
+ - `GuzzleHttp\Message\Header` has been removed. Header values are now simply
258
+ represented by an array of values or as a string. Header values are returned
259
+ as a string by default when retrieving a header value from a message. You can
260
+ pass an optional argument of `true` to retrieve a header value as an array
261
+ of strings instead of a single concatenated string.
262
+ - `GuzzleHttp\PostFile` and `GuzzleHttp\PostFileInterface` have been moved to
263
+ `GuzzleHttp\Post`. This interface has been simplified and now allows the
264
+ addition of arbitrary headers.
265
+ - Custom headers like `GuzzleHttp\Message\Header\Link` have been removed. Most
266
+ of the custom headers are now handled separately in specific
267
+ subscribers/plugins, and `GuzzleHttp\Message\HeaderValues::parseParams()` has
268
+ been updated to properly handle headers that contain parameters (like the
269
+ `Link` header).
270
+
271
+ #### Responses
272
+
273
+ - `GuzzleHttp\Message\Response::getInfo()` and
274
+ `GuzzleHttp\Message\Response::setInfo()` have been removed. Use the event
275
+ system to retrieve this type of information.
276
+ - `GuzzleHttp\Message\Response::getRawHeaders()` has been removed.
277
+ - `GuzzleHttp\Message\Response::getMessage()` has been removed.
278
+ - `GuzzleHttp\Message\Response::calculateAge()` and other cache specific
279
+ methods have moved to the CacheSubscriber.
280
+ - Header specific helper functions like `getContentMd5()` have been removed.
281
+ Just use `getHeader('Content-MD5')` instead.
282
+ - `GuzzleHttp\Message\Response::setRequest()` and
283
+ `GuzzleHttp\Message\Response::getRequest()` have been removed. Use the event
284
+ system to work with request and response objects as a transaction.
285
+ - `GuzzleHttp\Message\Response::getRedirectCount()` has been removed. Use the
286
+ Redirect subscriber instead.
287
+ - `GuzzleHttp\Message\Response::isSuccessful()` and other related methods have
288
+ been removed. Use `getStatusCode()` instead.
289
+
290
+ #### Streaming responses
291
+
292
+ Streaming requests can now be created by a client directly, returning a
293
+ `GuzzleHttp\Message\ResponseInterface` object that contains a body stream
294
+ referencing an open PHP HTTP stream.
295
+
296
+ ```php
297
+ // 3.0
298
+ use Guzzle\Stream\PhpStreamRequestFactory;
299
+ $request = $client->get('/');
300
+ $factory = new PhpStreamRequestFactory();
301
+ $stream = $factory->fromRequest($request);
302
+ $data = $stream->read(1024);
303
+
304
+ // 4.0
305
+ $response = $client->get('/', ['stream' => true]);
306
+ // Read some data off of the stream in the response body
307
+ $data = $response->getBody()->read(1024);
308
+ ```
309
+
310
+ #### Redirects
311
+
312
+ The `configureRedirects()` method has been removed in favor of a
313
+ `allow_redirects` request option.
314
+
315
+ ```php
316
+ // Standard redirects with a default of a max of 5 redirects
317
+ $request = $client->createRequest('GET', '/', ['allow_redirects' => true]);
318
+
319
+ // Strict redirects with a custom number of redirects
320
+ $request = $client->createRequest('GET', '/', [
321
+ 'allow_redirects' => ['max' => 5, 'strict' => true]
322
+ ]);
323
+ ```
324
+
325
+ #### EntityBody
326
+
327
+ EntityBody interfaces and classes have been removed or moved to
328
+ `GuzzleHttp\Stream`. All classes and interfaces that once required
329
+ `GuzzleHttp\EntityBodyInterface` now require
330
+ `GuzzleHttp\Stream\StreamInterface`. Creating a new body for a request no
331
+ longer uses `GuzzleHttp\EntityBody::factory` but now uses
332
+ `GuzzleHttp\Stream\Stream::factory` or even better:
333
+ `GuzzleHttp\Stream\create()`.
334
+
335
+ - `Guzzle\Http\EntityBodyInterface` is now `GuzzleHttp\Stream\StreamInterface`
336
+ - `Guzzle\Http\EntityBody` is now `GuzzleHttp\Stream\Stream`
337
+ - `Guzzle\Http\CachingEntityBody` is now `GuzzleHttp\Stream\CachingStream`
338
+ - `Guzzle\Http\ReadLimitEntityBody` is now `GuzzleHttp\Stream\LimitStream`
339
+ - `Guzzle\Http\IoEmittyinEntityBody` has been removed.
340
+
341
+ #### Request lifecycle events
342
+
343
+ Requests previously submitted a large number of requests. The number of events
344
+ emitted over the lifecycle of a request has been significantly reduced to make
345
+ it easier to understand how to extend the behavior of a request. All events
346
+ emitted during the lifecycle of a request now emit a custom
347
+ `GuzzleHttp\Event\EventInterface` object that contains context providing
348
+ methods and a way in which to modify the transaction at that specific point in
349
+ time (e.g., intercept the request and set a response on the transaction).
350
+
351
+ - `request.before_send` has been renamed to `before` and now emits a
352
+ `GuzzleHttp\Event\BeforeEvent`
353
+ - `request.complete` has been renamed to `complete` and now emits a
354
+ `GuzzleHttp\Event\CompleteEvent`.
355
+ - `request.sent` has been removed. Use `complete`.
356
+ - `request.success` has been removed. Use `complete`.
357
+ - `error` is now an event that emits a `GuzzleHttp\Event\ErrorEvent`.
358
+ - `request.exception` has been removed. Use `error`.
359
+ - `request.receive.status_line` has been removed.
360
+ - `curl.callback.progress` has been removed. Use a custom `StreamInterface` to
361
+ maintain a status update.
362
+ - `curl.callback.write` has been removed. Use a custom `StreamInterface` to
363
+ intercept writes.
364
+ - `curl.callback.read` has been removed. Use a custom `StreamInterface` to
365
+ intercept reads.
366
+
367
+ `headers` is a new event that is emitted after the response headers of a
368
+ request have been received before the body of the response is downloaded. This
369
+ event emits a `GuzzleHttp\Event\HeadersEvent`.
370
+
371
+ You can intercept a request and inject a response using the `intercept()` event
372
+ of a `GuzzleHttp\Event\BeforeEvent`, `GuzzleHttp\Event\CompleteEvent`, and
373
+ `GuzzleHttp\Event\ErrorEvent` event.
374
+
375
+ See: http://docs.guzzlephp.org/en/latest/events.html
376
+
377
+ ## Inflection
378
+
379
+ The `Guzzle\Inflection` namespace has been removed. This is not a core concern
380
+ of Guzzle.
381
+
382
+ ## Iterator
383
+
384
+ The `Guzzle\Iterator` namespace has been removed.
385
+
386
+ - `Guzzle\Iterator\AppendIterator`, `Guzzle\Iterator\ChunkedIterator`, and
387
+ `Guzzle\Iterator\MethodProxyIterator` are nice, but not a core requirement of
388
+ Guzzle itself.
389
+ - `Guzzle\Iterator\FilterIterator` is no longer needed because an equivalent
390
+ class is shipped with PHP 5.4.
391
+ - `Guzzle\Iterator\MapIterator` is not really needed when using PHP 5.5 because
392
+ it's easier to just wrap an iterator in a generator that maps values.
393
+
394
+ For a replacement of these iterators, see https://github.com/nikic/iter
395
+
396
+ ## Log
397
+
398
+ The LogPlugin has moved to https://github.com/guzzle/log-subscriber. The
399
+ `Guzzle\Log` namespace has been removed. Guzzle now relies on
400
+ `Psr\Log\LoggerInterface` for all logging. The MessageFormatter class has been
401
+ moved to `GuzzleHttp\Subscriber\Log\Formatter`.
402
+
403
+ ## Parser
404
+
405
+ The `Guzzle\Parser` namespace has been removed. This was previously used to
406
+ make it possible to plug in custom parsers for cookies, messages, URI
407
+ templates, and URLs; however, this level of complexity is not needed in Guzzle
408
+ so it has been removed.
409
+
410
+ - Cookie: Cookie parsing logic has been moved to
411
+ `GuzzleHttp\Cookie\SetCookie::fromString`.
412
+ - Message: Message parsing logic for both requests and responses has been moved
413
+ to `GuzzleHttp\Message\MessageFactory::fromMessage`. Message parsing is only
414
+ used in debugging or deserializing messages, so it doesn't make sense for
415
+ Guzzle as a library to add this level of complexity to parsing messages.
416
+ - UriTemplate: URI template parsing has been moved to
417
+ `GuzzleHttp\UriTemplate`. The Guzzle library will automatically use the PECL
418
+ URI template library if it is installed.
419
+ - Url: URL parsing is now performed in `GuzzleHttp\Url::fromString` (previously
420
+ it was `Guzzle\Http\Url::factory()`). If custom URL parsing is necessary,
421
+ then developers are free to subclass `GuzzleHttp\Url`.
422
+
423
+ ## Plugin
424
+
425
+ The `Guzzle\Plugin` namespace has been renamed to `GuzzleHttp\Subscriber`.
426
+ Several plugins are shipping with the core Guzzle library under this namespace.
427
+
428
+ - `GuzzleHttp\Subscriber\Cookie`: Replaces the old CookiePlugin. Cookie jar
429
+ code has moved to `GuzzleHttp\Cookie`.
430
+ - `GuzzleHttp\Subscriber\History`: Replaces the old HistoryPlugin.
431
+ - `GuzzleHttp\Subscriber\HttpError`: Throws errors when a bad HTTP response is
432
+ received.
433
+ - `GuzzleHttp\Subscriber\Mock`: Replaces the old MockPlugin.
434
+ - `GuzzleHttp\Subscriber\Prepare`: Prepares the body of a request just before
435
+ sending. This subscriber is attached to all requests by default.
436
+ - `GuzzleHttp\Subscriber\Redirect`: Replaces the RedirectPlugin.
437
+
438
+ The following plugins have been removed (third-parties are free to re-implement
439
+ these if needed):
440
+
441
+ - `GuzzleHttp\Plugin\Async` has been removed.
442
+ - `GuzzleHttp\Plugin\CurlAuth` has been removed.
443
+ - `GuzzleHttp\Plugin\ErrorResponse\ErrorResponsePlugin` has been removed. This
444
+ functionality should instead be implemented with event listeners that occur
445
+ after normal response parsing occurs in the guzzle/command package.
446
+
447
+ The following plugins are not part of the core Guzzle package, but are provided
448
+ in separate repositories:
449
+
450
+ - `Guzzle\Http\Plugin\BackoffPlugin` has been rewritten to be muchs simpler
451
+ to build custom retry policies using simple functions rather than various
452
+ chained classes. See: https://github.com/guzzle/retry-subscriber
453
+ - `Guzzle\Http\Plugin\Cache\CachePlugin` has moved to
454
+ https://github.com/guzzle/cache-subscriber
455
+ - `Guzzle\Http\Plugin\Log\LogPlugin` has moved to
456
+ https://github.com/guzzle/log-subscriber
457
+ - `Guzzle\Http\Plugin\Md5\Md5Plugin` has moved to
458
+ https://github.com/guzzle/message-integrity-subscriber
459
+ - `Guzzle\Http\Plugin\Mock\MockPlugin` has moved to
460
+ `GuzzleHttp\Subscriber\MockSubscriber`.
461
+ - `Guzzle\Http\Plugin\Oauth\OauthPlugin` has moved to
462
+ https://github.com/guzzle/oauth-subscriber
463
+
464
+ ## Service
465
+
466
+ The service description layer of Guzzle has moved into two separate packages:
467
+
468
+ - http://github.com/guzzle/command Provides a high level abstraction over web
469
+ services by representing web service operations using commands.
470
+ - http://github.com/guzzle/guzzle-services Provides an implementation of
471
+ guzzle/command that provides request serialization and response parsing using
472
+ Guzzle service descriptions.
473
+
474
+ ## Stream
475
+
476
+ Stream have moved to a separate package available at
477
+ https://github.com/guzzle/streams.
478
+
479
+ `Guzzle\Stream\StreamInterface` has been given a large update to cleanly take
480
+ on the responsibilities of `Guzzle\Http\EntityBody` and
481
+ `Guzzle\Http\EntityBodyInterface` now that they have been removed. The number
482
+ of methods implemented by the `StreamInterface` has been drastically reduced to
483
+ allow developers to more easily extend and decorate stream behavior.
484
+
485
+ ## Removed methods from StreamInterface
486
+
487
+ - `getStream` and `setStream` have been removed to better encapsulate streams.
488
+ - `getMetadata` and `setMetadata` have been removed in favor of
489
+ `GuzzleHttp\Stream\MetadataStreamInterface`.
490
+ - `getWrapper`, `getWrapperData`, `getStreamType`, and `getUri` have all been
491
+ removed. This data is accessible when
492
+ using streams that implement `GuzzleHttp\Stream\MetadataStreamInterface`.
493
+ - `rewind` has been removed. Use `seek(0)` for a similar behavior.
494
+
495
+ ## Renamed methods
496
+
497
+ - `detachStream` has been renamed to `detach`.
498
+ - `feof` has been renamed to `eof`.
499
+ - `ftell` has been renamed to `tell`.
500
+ - `readLine` has moved from an instance method to a static class method of
501
+ `GuzzleHttp\Stream\Stream`.
502
+
503
+ ## Metadata streams
504
+
505
+ `GuzzleHttp\Stream\MetadataStreamInterface` has been added to denote streams
506
+ that contain additional metadata accessible via `getMetadata()`.
507
+ `GuzzleHttp\Stream\StreamInterface::getMetadata` and
508
+ `GuzzleHttp\Stream\StreamInterface::setMetadata` have been removed.
509
+
510
+ ## StreamRequestFactory
511
+
512
+ The entire concept of the StreamRequestFactory has been removed. The way this
513
+ was used in Guzzle 3 broke the actual interface of sending streaming requests
514
+ (instead of getting back a Response, you got a StreamInterface). Streeaming
515
+ PHP requests are now implemented throught the `GuzzleHttp\Adapter\StreamAdapter`.
516
+
517
+ 3.6 to 3.7
518
+ ----------
519
+
520
+ ### Deprecations
521
+
522
+ - You can now enable E_USER_DEPRECATED warnings to see if you are using any deprecated methods.:
523
+
524
+ ```php
525
+ \Guzzle\Common\Version::$emitWarnings = true;
526
+ ```
527
+
528
+ The following APIs and options have been marked as deprecated:
529
+
530
+ - Marked `Guzzle\Http\Message\Request::isResponseBodyRepeatable()` as deprecated. Use `$request->getResponseBody()->isRepeatable()` instead.
531
+ - Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead.
532
+ - Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead.
533
+ - Marked `Guzzle\Http\Message\Request::setIsRedirect()` as deprecated. Use the HistoryPlugin instead.
534
+ - Marked `Guzzle\Http\Message\Request::isRedirect()` as deprecated. Use the HistoryPlugin instead.
535
+ - Marked `Guzzle\Cache\CacheAdapterFactory::factory()` as deprecated
536
+ - Marked `Guzzle\Service\Client::enableMagicMethods()` as deprecated. Magic methods can no longer be disabled on a Guzzle\Service\Client.
537
+ - Marked `Guzzle\Parser\Url\UrlParser` as deprecated. Just use PHP's `parse_url()` and percent encode your UTF-8.
538
+ - Marked `Guzzle\Common\Collection::inject()` as deprecated.
539
+ - Marked `Guzzle\Plugin\CurlAuth\CurlAuthPlugin` as deprecated. Use
540
+ `$client->getConfig()->setPath('request.options/auth', array('user', 'pass', 'Basic|Digest|NTLM|Any'));` or
541
+ `$client->setDefaultOption('auth', array('user', 'pass', 'Basic|Digest|NTLM|Any'));`
542
+
543
+ 3.7 introduces `request.options` as a parameter for a client configuration and as an optional argument to all creational
544
+ request methods. When paired with a client's configuration settings, these options allow you to specify default settings
545
+ for various aspects of a request. Because these options make other previous configuration options redundant, several
546
+ configuration options and methods of a client and AbstractCommand have been deprecated.
547
+
548
+ - Marked `Guzzle\Service\Client::getDefaultHeaders()` as deprecated. Use `$client->getDefaultOption('headers')`.
549
+ - Marked `Guzzle\Service\Client::setDefaultHeaders()` as deprecated. Use `$client->setDefaultOption('headers/{header_name}', 'value')`.
550
+ - Marked 'request.params' for `Guzzle\Http\Client` as deprecated. Use `$client->setDefaultOption('params/{param_name}', 'value')`
551
+ - Marked 'command.headers', 'command.response_body' and 'command.on_complete' as deprecated for AbstractCommand. These will work through Guzzle 4.0
552
+
553
+ $command = $client->getCommand('foo', array(
554
+ 'command.headers' => array('Test' => '123'),
555
+ 'command.response_body' => '/path/to/file'
556
+ ));
557
+
558
+ // Should be changed to:
559
+
560
+ $command = $client->getCommand('foo', array(
561
+ 'command.request_options' => array(
562
+ 'headers' => array('Test' => '123'),
563
+ 'save_as' => '/path/to/file'
564
+ )
565
+ ));
566
+
567
+ ### Interface changes
568
+
569
+ Additions and changes (you will need to update any implementations or subclasses you may have created):
570
+
571
+ - Added an `$options` argument to the end of the following methods of `Guzzle\Http\ClientInterface`:
572
+ createRequest, head, delete, put, patch, post, options, prepareRequest
573
+ - Added an `$options` argument to the end of `Guzzle\Http\Message\Request\RequestFactoryInterface::createRequest()`
574
+ - Added an `applyOptions()` method to `Guzzle\Http\Message\Request\RequestFactoryInterface`
575
+ - Changed `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $body = null)` to
576
+ `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $options = array())`. You can still pass in a
577
+ resource, string, or EntityBody into the $options parameter to specify the download location of the response.
578
+ - Changed `Guzzle\Common\Collection::__construct($data)` to no longer accepts a null value for `$data` but a
579
+ default `array()`
580
+ - Added `Guzzle\Stream\StreamInterface::isRepeatable`
581
+ - Made `Guzzle\Http\Client::expandTemplate` and `getUriTemplate` protected methods.
582
+
583
+ The following methods were removed from interfaces. All of these methods are still available in the concrete classes
584
+ that implement them, but you should update your code to use alternative methods:
585
+
586
+ - Removed `Guzzle\Http\ClientInterface::setDefaultHeaders(). Use
587
+ `$client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`. or
588
+ `$client->getConfig()->setPath('request.options/headers', array('header_name' => 'value'))` or
589
+ `$client->setDefaultOption('headers/{header_name}', 'value')`. or
590
+ `$client->setDefaultOption('headers', array('header_name' => 'value'))`.
591
+ - Removed `Guzzle\Http\ClientInterface::getDefaultHeaders(). Use `$client->getConfig()->getPath('request.options/headers')`.
592
+ - Removed `Guzzle\Http\ClientInterface::expandTemplate()`. This is an implementation detail.
593
+ - Removed `Guzzle\Http\ClientInterface::setRequestFactory()`. This is an implementation detail.
594
+ - Removed `Guzzle\Http\ClientInterface::getCurlMulti()`. This is a very specific implementation detail.
595
+ - Removed `Guzzle\Http\Message\RequestInterface::canCache`. Use the CachePlugin.
596
+ - Removed `Guzzle\Http\Message\RequestInterface::setIsRedirect`. Use the HistoryPlugin.
597
+ - Removed `Guzzle\Http\Message\RequestInterface::isRedirect`. Use the HistoryPlugin.
598
+
599
+ ### Cache plugin breaking changes
600
+
601
+ - CacheKeyProviderInterface and DefaultCacheKeyProvider are no longer used. All of this logic is handled in a
602
+ CacheStorageInterface. These two objects and interface will be removed in a future version.
603
+ - Always setting X-cache headers on cached responses
604
+ - Default cache TTLs are now handled by the CacheStorageInterface of a CachePlugin
605
+ - `CacheStorageInterface::cache($key, Response $response, $ttl = null)` has changed to `cache(RequestInterface
606
+ $request, Response $response);`
607
+ - `CacheStorageInterface::fetch($key)` has changed to `fetch(RequestInterface $request);`
608
+ - `CacheStorageInterface::delete($key)` has changed to `delete(RequestInterface $request);`
609
+ - Added `CacheStorageInterface::purge($url)`
610
+ - `DefaultRevalidation::__construct(CacheKeyProviderInterface $cacheKey, CacheStorageInterface $cache, CachePlugin
611
+ $plugin)` has changed to `DefaultRevalidation::__construct(CacheStorageInterface $cache,
612
+ CanCacheStrategyInterface $canCache = null)`
613
+ - Added `RevalidationInterface::shouldRevalidate(RequestInterface $request, Response $response)`
614
+
615
+ 3.5 to 3.6
616
+ ----------
617
+
618
+ * Mixed casing of headers are now forced to be a single consistent casing across all values for that header.
619
+ * Messages internally use a HeaderCollection object to delegate handling case-insensitive header resolution
620
+ * Removed the whole changedHeader() function system of messages because all header changes now go through addHeader().
621
+ For example, setHeader() first removes the header using unset on a HeaderCollection and then calls addHeader().
622
+ Keeping the Host header and URL host in sync is now handled by overriding the addHeader method in Request.
623
+ * Specific header implementations can be created for complex headers. When a message creates a header, it uses a
624
+ HeaderFactory which can map specific headers to specific header classes. There is now a Link header and
625
+ CacheControl header implementation.
626
+ * Moved getLinks() from Response to just be used on a Link header object.
627
+
628
+ If you previously relied on Guzzle\Http\Message\Header::raw(), then you will need to update your code to use the
629
+ HeaderInterface (e.g. toArray(), getAll(), etc.).
630
+
631
+ ### Interface changes
632
+
633
+ * Removed from interface: Guzzle\Http\ClientInterface::setUriTemplate
634
+ * Removed from interface: Guzzle\Http\ClientInterface::setCurlMulti()
635
+ * Removed Guzzle\Http\Message\Request::receivedRequestHeader() and implemented this functionality in
636
+ Guzzle\Http\Curl\RequestMediator
637
+ * Removed the optional $asString parameter from MessageInterface::getHeader(). Just cast the header to a string.
638
+ * Removed the optional $tryChunkedTransfer option from Guzzle\Http\Message\EntityEnclosingRequestInterface
639
+ * Removed the $asObjects argument from Guzzle\Http\Message\MessageInterface::getHeaders()
640
+
641
+ ### Removed deprecated functions
642
+
643
+ * Removed Guzzle\Parser\ParserRegister::get(). Use getParser()
644
+ * Removed Guzzle\Parser\ParserRegister::set(). Use registerParser().
645
+
646
+ ### Deprecations
647
+
648
+ * The ability to case-insensitively search for header values
649
+ * Guzzle\Http\Message\Header::hasExactHeader
650
+ * Guzzle\Http\Message\Header::raw. Use getAll()
651
+ * Deprecated cache control specific methods on Guzzle\Http\Message\AbstractMessage. Use the CacheControl header object
652
+ instead.
653
+
654
+ ### Other changes
655
+
656
+ * All response header helper functions return a string rather than mixing Header objects and strings inconsistently
657
+ * Removed cURL blacklist support. This is no longer necessary now that Expect, Accept, etc. are managed by Guzzle
658
+ directly via interfaces
659
+ * Removed the injecting of a request object onto a response object. The methods to get and set a request still exist
660
+ but are a no-op until removed.
661
+ * Most classes that used to require a `Guzzle\Service\Command\CommandInterface` typehint now request a
662
+ `Guzzle\Service\Command\ArrayCommandInterface`.
663
+ * Added `Guzzle\Http\Message\RequestInterface::startResponse()` to the RequestInterface to handle injecting a response
664
+ on a request while the request is still being transferred
665
+ * `Guzzle\Service\Command\CommandInterface` now extends from ToArrayInterface and ArrayAccess
666
+
667
+ 3.3 to 3.4
668
+ ----------
669
+
670
+ Base URLs of a client now follow the rules of http://tools.ietf.org/html/rfc3986#section-5.2.2 when merging URLs.
671
+
672
+ 3.2 to 3.3
673
+ ----------
674
+
675
+ ### Response::getEtag() quote stripping removed
676
+
677
+ `Guzzle\Http\Message\Response::getEtag()` no longer strips quotes around the ETag response header
678
+
679
+ ### Removed `Guzzle\Http\Utils`
680
+
681
+ The `Guzzle\Http\Utils` class was removed. This class was only used for testing.
682
+
683
+ ### Stream wrapper and type
684
+
685
+ `Guzzle\Stream\Stream::getWrapper()` and `Guzzle\Stream\Stream::getStreamType()` are no longer converted to lowercase.
686
+
687
+ ### curl.emit_io became emit_io
688
+
689
+ Emitting IO events from a RequestMediator is now a parameter that must be set in a request's curl options using the
690
+ 'emit_io' key. This was previously set under a request's parameters using 'curl.emit_io'
691
+
692
+ 3.1 to 3.2
693
+ ----------
694
+
695
+ ### CurlMulti is no longer reused globally
696
+
697
+ Before 3.2, the same CurlMulti object was reused globally for each client. This can cause issue where plugins added
698
+ to a single client can pollute requests dispatched from other clients.
699
+
700
+ If you still wish to reuse the same CurlMulti object with each client, then you can add a listener to the
701
+ ServiceBuilder's `service_builder.create_client` event to inject a custom CurlMulti object into each client as it is
702
+ created.
703
+
704
+ ```php
705
+ $multi = new Guzzle\Http\Curl\CurlMulti();
706
+ $builder = Guzzle\Service\Builder\ServiceBuilder::factory('/path/to/config.json');
707
+ $builder->addListener('service_builder.create_client', function ($event) use ($multi) {
708
+ $event['client']->setCurlMulti($multi);
709
+ }
710
+ });
711
+ ```
712
+
713
+ ### No default path
714
+
715
+ URLs no longer have a default path value of '/' if no path was specified.
716
+
717
+ Before:
718
+
719
+ ```php
720
+ $request = $client->get('http://www.foo.com');
721
+ echo $request->getUrl();
722
+ // >> http://www.foo.com/
723
+ ```
724
+
725
+ After:
726
+
727
+ ```php
728
+ $request = $client->get('http://www.foo.com');
729
+ echo $request->getUrl();
730
+ // >> http://www.foo.com
731
+ ```
732
+
733
+ ### Less verbose BadResponseException
734
+
735
+ The exception message for `Guzzle\Http\Exception\BadResponseException` no longer contains the full HTTP request and
736
+ response information. You can, however, get access to the request and response object by calling `getRequest()` or
737
+ `getResponse()` on the exception object.
738
+
739
+ ### Query parameter aggregation
740
+
741
+ Multi-valued query parameters are no longer aggregated using a callback function. `Guzzle\Http\Query` now has a
742
+ setAggregator() method that accepts a `Guzzle\Http\QueryAggregator\QueryAggregatorInterface` object. This object is
743
+ responsible for handling the aggregation of multi-valued query string variables into a flattened hash.
744
+
745
+ 2.8 to 3.x
746
+ ----------
747
+
748
+ ### Guzzle\Service\Inspector
749
+
750
+ Change `\Guzzle\Service\Inspector::fromConfig` to `\Guzzle\Common\Collection::fromConfig`
751
+
752
+ **Before**
753
+
754
+ ```php
755
+ use Guzzle\Service\Inspector;
756
+
757
+ class YourClient extends \Guzzle\Service\Client
758
+ {
759
+ public static function factory($config = array())
760
+ {
761
+ $default = array();
762
+ $required = array('base_url', 'username', 'api_key');
763
+ $config = Inspector::fromConfig($config, $default, $required);
764
+
765
+ $client = new self(
766
+ $config->get('base_url'),
767
+ $config->get('username'),
768
+ $config->get('api_key')
769
+ );
770
+ $client->setConfig($config);
771
+
772
+ $client->setDescription(ServiceDescription::factory(__DIR__ . DIRECTORY_SEPARATOR . 'client.json'));
773
+
774
+ return $client;
775
+ }
776
+ ```
777
+
778
+ **After**
779
+
780
+ ```php
781
+ use Guzzle\Common\Collection;
782
+
783
+ class YourClient extends \Guzzle\Service\Client
784
+ {
785
+ public static function factory($config = array())
786
+ {
787
+ $default = array();
788
+ $required = array('base_url', 'username', 'api_key');
789
+ $config = Collection::fromConfig($config, $default, $required);
790
+
791
+ $client = new self(
792
+ $config->get('base_url'),
793
+ $config->get('username'),
794
+ $config->get('api_key')
795
+ );
796
+ $client->setConfig($config);
797
+
798
+ $client->setDescription(ServiceDescription::factory(__DIR__ . DIRECTORY_SEPARATOR . 'client.json'));
799
+
800
+ return $client;
801
+ }
802
+ ```
803
+
804
+ ### Convert XML Service Descriptions to JSON
805
+
806
+ **Before**
807
+
808
+ ```xml
809
+ <?xml version="1.0" encoding="UTF-8"?>
810
+ <client>
811
+ <commands>
812
+ <!-- Groups -->
813
+ <command name="list_groups" method="GET" uri="groups.json">
814
+ <doc>Get a list of groups</doc>
815
+ </command>
816
+ <command name="search_groups" method="GET" uri='search.json?query="{{query}} type:group"'>
817
+ <doc>Uses a search query to get a list of groups</doc>
818
+ <param name="query" type="string" required="true" />
819
+ </command>
820
+ <command name="create_group" method="POST" uri="groups.json">
821
+ <doc>Create a group</doc>
822
+ <param name="data" type="array" location="body" filters="json_encode" doc="Group JSON"/>
823
+ <param name="Content-Type" location="header" static="application/json"/>
824
+ </command>
825
+ <command name="delete_group" method="DELETE" uri="groups/{{id}}.json">
826
+ <doc>Delete a group by ID</doc>
827
+ <param name="id" type="integer" required="true"/>
828
+ </command>
829
+ <command name="get_group" method="GET" uri="groups/{{id}}.json">
830
+ <param name="id" type="integer" required="true"/>
831
+ </command>
832
+ <command name="update_group" method="PUT" uri="groups/{{id}}.json">
833
+ <doc>Update a group</doc>
834
+ <param name="id" type="integer" required="true"/>
835
+ <param name="data" type="array" location="body" filters="json_encode" doc="Group JSON"/>
836
+ <param name="Content-Type" location="header" static="application/json"/>
837
+ </command>
838
+ </commands>
839
+ </client>
840
+ ```
841
+
842
+ **After**
843
+
844
+ ```json
845
+ {
846
+ "name": "Zendesk REST API v2",
847
+ "apiVersion": "2012-12-31",
848
+ "description":"Provides access to Zendesk views, groups, tickets, ticket fields, and users",
849
+ "operations": {
850
+ "list_groups": {
851
+ "httpMethod":"GET",
852
+ "uri": "groups.json",
853
+ "summary": "Get a list of groups"
854
+ },
855
+ "search_groups":{
856
+ "httpMethod":"GET",
857
+ "uri": "search.json?query=\"{query} type:group\"",
858
+ "summary": "Uses a search query to get a list of groups",
859
+ "parameters":{
860
+ "query":{
861
+ "location": "uri",
862
+ "description":"Zendesk Search Query",
863
+ "type": "string",
864
+ "required": true
865
+ }
866
+ }
867
+ },
868
+ "create_group": {
869
+ "httpMethod":"POST",
870
+ "uri": "groups.json",
871
+ "summary": "Create a group",
872
+ "parameters":{
873
+ "data": {
874
+ "type": "array",
875
+ "location": "body",
876
+ "description":"Group JSON",
877
+ "filters": "json_encode",
878
+ "required": true
879
+ },
880
+ "Content-Type":{
881
+ "type": "string",
882
+ "location":"header",
883
+ "static": "application/json"
884
+ }
885
+ }
886
+ },
887
+ "delete_group": {
888
+ "httpMethod":"DELETE",
889
+ "uri": "groups/{id}.json",
890
+ "summary": "Delete a group",
891
+ "parameters":{
892
+ "id":{
893
+ "location": "uri",
894
+ "description":"Group to delete by ID",
895
+ "type": "integer",
896
+ "required": true
897
+ }
898
+ }
899
+ },
900
+ "get_group": {
901
+ "httpMethod":"GET",
902
+ "uri": "groups/{id}.json",
903
+ "summary": "Get a ticket",
904
+ "parameters":{
905
+ "id":{
906
+ "location": "uri",
907
+ "description":"Group to get by ID",
908
+ "type": "integer",
909
+ "required": true
910
+ }
911
+ }
912
+ },
913
+ "update_group": {
914
+ "httpMethod":"PUT",
915
+ "uri": "groups/{id}.json",
916
+ "summary": "Update a group",
917
+ "parameters":{
918
+ "id": {
919
+ "location": "uri",
920
+ "description":"Group to update by ID",
921
+ "type": "integer",
922
+ "required": true
923
+ },
924
+ "data": {
925
+ "type": "array",
926
+ "location": "body",
927
+ "description":"Group JSON",
928
+ "filters": "json_encode",
929
+ "required": true
930
+ },
931
+ "Content-Type":{
932
+ "type": "string",
933
+ "location":"header",
934
+ "static": "application/json"
935
+ }
936
+ }
937
+ }
938
+ }
939
+ ```
940
+
941
+ ### Guzzle\Service\Description\ServiceDescription
942
+
943
+ Commands are now called Operations
944
+
945
+ **Before**
946
+
947
+ ```php
948
+ use Guzzle\Service\Description\ServiceDescription;
949
+
950
+ $sd = new ServiceDescription();
951
+ $sd->getCommands(); // @returns ApiCommandInterface[]
952
+ $sd->hasCommand($name);
953
+ $sd->getCommand($name); // @returns ApiCommandInterface|null
954
+ $sd->addCommand($command); // @param ApiCommandInterface $command
955
+ ```
956
+
957
+ **After**
958
+
959
+ ```php
960
+ use Guzzle\Service\Description\ServiceDescription;
961
+
962
+ $sd = new ServiceDescription();
963
+ $sd->getOperations(); // @returns OperationInterface[]
964
+ $sd->hasOperation($name);
965
+ $sd->getOperation($name); // @returns OperationInterface|null
966
+ $sd->addOperation($operation); // @param OperationInterface $operation
967
+ ```
968
+
969
+ ### Guzzle\Common\Inflection\Inflector
970
+
971
+ Namespace is now `Guzzle\Inflection\Inflector`
972
+
973
+ ### Guzzle\Http\Plugin
974
+
975
+ Namespace is now `Guzzle\Plugin`. Many other changes occur within this namespace and are detailed in their own sections below.
976
+
977
+ ### Guzzle\Http\Plugin\LogPlugin and Guzzle\Common\Log
978
+
979
+ Now `Guzzle\Plugin\Log\LogPlugin` and `Guzzle\Log` respectively.
980
+
981
+ **Before**
982
+
983
+ ```php
984
+ use Guzzle\Common\Log\ClosureLogAdapter;
985
+ use Guzzle\Http\Plugin\LogPlugin;
986
+
987
+ /** @var \Guzzle\Http\Client */
988
+ $client;
989
+
990
+ // $verbosity is an integer indicating desired message verbosity level
991
+ $client->addSubscriber(new LogPlugin(new ClosureLogAdapter(function($m) { echo $m; }, $verbosity = LogPlugin::LOG_VERBOSE);
992
+ ```
993
+
994
+ **After**
995
+
996
+ ```php
997
+ use Guzzle\Log\ClosureLogAdapter;
998
+ use Guzzle\Log\MessageFormatter;
999
+ use Guzzle\Plugin\Log\LogPlugin;
1000
+
1001
+ /** @var \Guzzle\Http\Client */
1002
+ $client;
1003
+
1004
+ // $format is a string indicating desired message format -- @see MessageFormatter
1005
+ $client->addSubscriber(new LogPlugin(new ClosureLogAdapter(function($m) { echo $m; }, $format = MessageFormatter::DEBUG_FORMAT);
1006
+ ```
1007
+
1008
+ ### Guzzle\Http\Plugin\CurlAuthPlugin
1009
+
1010
+ Now `Guzzle\Plugin\CurlAuth\CurlAuthPlugin`.
1011
+
1012
+ ### Guzzle\Http\Plugin\ExponentialBackoffPlugin
1013
+
1014
+ Now `Guzzle\Plugin\Backoff\BackoffPlugin`, and other changes.
1015
+
1016
+ **Before**
1017
+
1018
+ ```php
1019
+ use Guzzle\Http\Plugin\ExponentialBackoffPlugin;
1020
+
1021
+ $backoffPlugin = new ExponentialBackoffPlugin($maxRetries, array_merge(
1022
+ ExponentialBackoffPlugin::getDefaultFailureCodes(), array(429)
1023
+ ));
1024
+
1025
+ $client->addSubscriber($backoffPlugin);
1026
+ ```
1027
+
1028
+ **After**
1029
+
1030
+ ```php
1031
+ use Guzzle\Plugin\Backoff\BackoffPlugin;
1032
+ use Guzzle\Plugin\Backoff\HttpBackoffStrategy;
1033
+
1034
+ // Use convenient factory method instead -- see implementation for ideas of what
1035
+ // you can do with chaining backoff strategies
1036
+ $backoffPlugin = BackoffPlugin::getExponentialBackoff($maxRetries, array_merge(
1037
+ HttpBackoffStrategy::getDefaultFailureCodes(), array(429)
1038
+ ));
1039
+ $client->addSubscriber($backoffPlugin);
1040
+ ```
1041
+
1042
+ ### Known Issues
1043
+
1044
+ #### [BUG] Accept-Encoding header behavior changed unintentionally.
1045
+
1046
+ (See #217) (Fixed in 09daeb8c666fb44499a0646d655a8ae36456575e)
1047
+
1048
+ In version 2.8 setting the `Accept-Encoding` header would set the CURLOPT_ENCODING option, which permitted cURL to
1049
+ properly handle gzip/deflate compressed responses from the server. In versions affected by this bug this does not happen.
1050
+ See issue #217 for a workaround, or use a version containing the fix.
backend/vendor/guzzlehttp/guzzle/build/packager.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require __DIR__ . '/artifacts/Burgomaster.php';
3
+
4
+ $stageDirectory = __DIR__ . '/artifacts/staging';
5
+ $projectRoot = __DIR__ . '/../';
6
+ $packager = new \Burgomaster($stageDirectory, $projectRoot);
7
+
8
+ // Copy basic files to the stage directory. Note that we have chdir'd onto
9
+ // the $projectRoot directory, so use relative paths.
10
+ foreach (['README.md', 'LICENSE'] as $file) {
11
+ $packager->deepCopy($file, $file);
12
+ }
13
+
14
+ // Copy each dependency to the staging directory. Copy *.php and *.pem files.
15
+ $packager->recursiveCopy('src', 'GuzzleHttp', ['php']);
16
+ $packager->recursiveCopy('vendor/react/promise/src', 'React/Promise');
17
+ $packager->recursiveCopy('vendor/guzzlehttp/ringphp/src', 'GuzzleHttp/Ring');
18
+ $packager->recursiveCopy('vendor/guzzlehttp/streams/src', 'GuzzleHttp/Stream');
19
+ $packager->createAutoloader(['React/Promise/functions.php']);
20
+ $packager->createPhar(__DIR__ . '/artifacts/guzzle.phar');
21
+ $packager->createZip(__DIR__ . '/artifacts/guzzle.zip');
backend/vendor/guzzlehttp/guzzle/composer.json ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "guzzlehttp/guzzle",
3
+ "type": "library",
4
+ "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients",
5
+ "keywords": ["framework", "http", "rest", "web service", "curl", "client", "HTTP client"],
6
+ "homepage": "http://guzzlephp.org/",
7
+ "license": "MIT",
8
+ "authors": [
9
+ {
10
+ "name": "Michael Dowling",
11
+ "email": "mtdowling@gmail.com",
12
+ "homepage": "https://github.com/mtdowling"
13
+ }
14
+ ],
15
+ "require": {
16
+ "php": ">=5.4.0",
17
+ "guzzlehttp/ringphp": "~1.0"
18
+ },
19
+ "require-dev": {
20
+ "ext-curl": "*",
21
+ "psr/log": "~1.0",
22
+ "phpunit/phpunit": "~4.0"
23
+ },
24
+ "autoload": {
25
+ "psr-4": {
26
+ "GuzzleHttp\\": "src/"
27
+ }
28
+ },
29
+ "autoload-dev": {
30
+ "psr-4": {
31
+ "GuzzleHttp\\Tests\\": "tests/"
32
+ }
33
+ },
34
+ "extra": {
35
+ "branch-alias": {
36
+ "dev-master": "5.0-dev"
37
+ }
38
+ }
39
+ }
backend/vendor/guzzlehttp/guzzle/docs/Makefile ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Makefile for Sphinx documentation
2
+ #
3
+
4
+ # You can set these variables from the command line.
5
+ SPHINXOPTS =
6
+ SPHINXBUILD = sphinx-build
7
+ PAPER =
8
+ BUILDDIR = _build
9
+
10
+ # Internal variables.
11
+ PAPEROPT_a4 = -D latex_paper_size=a4
12
+ PAPEROPT_letter = -D latex_paper_size=letter
13
+ ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
14
+ # the i18n builder cannot share the environment and doctrees with the others
15
+ I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
16
+
17
+ .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
18
+
19
+ help:
20
+ @echo "Please use \`make <target>' where <target> is one of"
21
+ @echo " html to make standalone HTML files"
22
+ @echo " dirhtml to make HTML files named index.html in directories"
23
+ @echo " singlehtml to make a single large HTML file"
24
+ @echo " pickle to make pickle files"
25
+ @echo " json to make JSON files"
26
+ @echo " htmlhelp to make HTML files and a HTML help project"
27
+ @echo " qthelp to make HTML files and a qthelp project"
28
+ @echo " devhelp to make HTML files and a Devhelp project"
29
+ @echo " epub to make an epub"
30
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
31
+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
32
+ @echo " text to make text files"
33
+ @echo " man to make manual pages"
34
+ @echo " texinfo to make Texinfo files"
35
+ @echo " info to make Texinfo files and run them through makeinfo"
36
+ @echo " gettext to make PO message catalogs"
37
+ @echo " changes to make an overview of all changed/added/deprecated items"
38
+ @echo " linkcheck to check all external links for integrity"
39
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
40
+
41
+ clean:
42
+ -rm -rf $(BUILDDIR)/*
43
+
44
+ html:
45
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
46
+ @echo
47
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
48
+
49
+ dirhtml:
50
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
51
+ @echo
52
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
53
+
54
+ singlehtml:
55
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
56
+ @echo
57
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
58
+
59
+ pickle:
60
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
61
+ @echo
62
+ @echo "Build finished; now you can process the pickle files."
63
+
64
+ json:
65
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
66
+ @echo
67
+ @echo "Build finished; now you can process the JSON files."
68
+
69
+ htmlhelp:
70
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
71
+ @echo
72
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
73
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
74
+
75
+ qthelp:
76
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
77
+ @echo
78
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
79
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
80
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Guzzle.qhcp"
81
+ @echo "To view the help file:"
82
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Guzzle.qhc"
83
+
84
+ devhelp:
85
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
86
+ @echo
87
+ @echo "Build finished."
88
+ @echo "To view the help file:"
89
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/Guzzle"
90
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Guzzle"
91
+ @echo "# devhelp"
92
+
93
+ epub:
94
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
95
+ @echo
96
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
97
+
98
+ latex:
99
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
100
+ @echo
101
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
102
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
103
+ "(use \`make latexpdf' here to do that automatically)."
104
+
105
+ latexpdf:
106
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
107
+ @echo "Running LaTeX files through pdflatex..."
108
+ $(MAKE) -C $(BUILDDIR)/latex all-pdf
109
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
110
+
111
+ text:
112
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
113
+ @echo
114
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
115
+
116
+ man:
117
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
118
+ @echo
119
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
120
+
121
+ texinfo:
122
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
123
+ @echo
124
+ @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
125
+ @echo "Run \`make' in that directory to run these through makeinfo" \
126
+ "(use \`make info' here to do that automatically)."
127
+
128
+ info:
129
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
130
+ @echo "Running Texinfo files through makeinfo..."
131
+ make -C $(BUILDDIR)/texinfo info
132
+ @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
133
+
134
+ gettext:
135
+ $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
136
+ @echo
137
+ @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
138
+
139
+ changes:
140
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
141
+ @echo
142
+ @echo "The overview file is in $(BUILDDIR)/changes."
143
+
144
+ linkcheck:
145
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
146
+ @echo
147
+ @echo "Link check complete; look for any errors in the above output " \
148
+ "or in $(BUILDDIR)/linkcheck/output.txt."
149
+
150
+ doctest:
151
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
152
+ @echo "Testing of doctests in the sources finished, look at the " \
153
+ "results in $(BUILDDIR)/doctest/output.txt."
backend/vendor/guzzlehttp/guzzle/docs/_static/guzzle-icon.png ADDED
Binary file
backend/vendor/guzzlehttp/guzzle/docs/_static/logo.png ADDED
Binary file
backend/vendor/guzzlehttp/guzzle/docs/_templates/nav_links.html ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <li><a href="https://github.com/guzzle/guzzle">GitHub</a></li>
2
+ <li><a href="https://groups.google.com/forum/?hl=en#!forum/guzzle">Forum</a></li>
3
+ <li><a href="irc:irc.freenode.com/#guzzlephp">IRC</a></li>
backend/vendor/guzzlehttp/guzzle/docs/clients.rst ADDED
@@ -0,0 +1,1315 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ =======
2
+ Clients
3
+ =======
4
+
5
+ Clients are used to create requests, create transactions, send requests
6
+ through an HTTP handler, and return a response. You can add default request
7
+ options to a client that are applied to every request (e.g., default headers,
8
+ default query string parameters, etc.), and you can add event listeners and
9
+ subscribers to every request created by a client.
10
+
11
+ Creating a client
12
+ =================
13
+
14
+ The constructor of a client accepts an associative array of configuration
15
+ options.
16
+
17
+ base_url
18
+ Configures a base URL for the client so that requests created
19
+ using a relative URL are combined with the ``base_url`` of the client
20
+ according to section `5.2 of RFC 3986 <http://tools.ietf.org/html/rfc3986#section-5.2>`_.
21
+
22
+ .. code-block:: php
23
+
24
+ // Create a client with a base URL
25
+ $client = new GuzzleHttp\Client(['base_url' => 'https://github.com']);
26
+ // Send a request to https://github.com/notifications
27
+ $response = $client->get('/notifications');
28
+
29
+ `Absolute URLs <http://tools.ietf.org/html/rfc3986#section-4.3>`_ sent
30
+ through a client will not use the base URL of the client.
31
+
32
+ handler
33
+ Configures the `RingPHP handler <http://ringphp.readthedocs.org>`_
34
+ used to transfer the HTTP requests of a client. Guzzle will, by default,
35
+ utilize a stacked handlers that chooses the best handler to use based on the
36
+ provided request options and based on the extensions available in the
37
+ environment.
38
+
39
+ message_factory
40
+ Specifies the factory used to create HTTP requests and responses
41
+ (``GuzzleHttp\Message\MessageFactoryInterface``).
42
+
43
+ defaults
44
+ Associative array of :ref:`request-options` that are applied to every
45
+ request created by the client. This allows you to specify things like
46
+ default headers (e.g., User-Agent), default query string parameters, SSL
47
+ configurations, and any other supported request options.
48
+
49
+ emitter
50
+ Specifies an event emitter (``GuzzleHttp\Event\EmitterInterface``) instance
51
+ to be used by the client to emit request events. This option is useful if
52
+ you need to inject an emitter with listeners/subscribers already attached.
53
+
54
+ Here's an example of creating a client with various options.
55
+
56
+ .. code-block:: php
57
+
58
+ use GuzzleHttp\Client;
59
+
60
+ $client = new Client([
61
+ 'base_url' => ['https://api.twitter.com/{version}/', ['version' => 'v1.1']],
62
+ 'defaults' => [
63
+ 'headers' => ['Foo' => 'Bar'],
64
+ 'query' => ['testing' => '123'],
65
+ 'auth' => ['username', 'password'],
66
+ 'proxy' => 'tcp://localhost:80'
67
+ ]
68
+ ]);
69
+
70
+ Sending Requests
71
+ ================
72
+
73
+ Requests can be created using various methods of a client. You can create
74
+ **and** send requests using one of the following methods:
75
+
76
+ - ``GuzzleHttp\Client::get``: Sends a GET request.
77
+ - ``GuzzleHttp\Client::head``: Sends a HEAD request
78
+ - ``GuzzleHttp\Client::post``: Sends a POST request
79
+ - ``GuzzleHttp\Client::put``: Sends a PUT request
80
+ - ``GuzzleHttp\Client::delete``: Sends a DELETE request
81
+ - ``GuzzleHttp\Client::options``: Sends an OPTIONS request
82
+
83
+ Each of the above methods accepts a URL as the first argument and an optional
84
+ associative array of :ref:`request-options` as the second argument.
85
+
86
+ Synchronous Requests
87
+ --------------------
88
+
89
+ Guzzle sends synchronous (blocking) requests when the ``future`` request option
90
+ is not specified. This means that the request will complete immediately, and if
91
+ an error is encountered, a ``GuzzleHttp\Exception\RequestException`` will be
92
+ thrown.
93
+
94
+ .. code-block:: php
95
+
96
+ $client = new GuzzleHttp\Client();
97
+
98
+ $client->put('http://httpbin.org', [
99
+ 'headers' => ['X-Foo' => 'Bar'],
100
+ 'body' => 'this is the body!',
101
+ 'save_to' => '/path/to/local/file',
102
+ 'allow_redirects' => false,
103
+ 'timeout' => 5
104
+ ]);
105
+
106
+ Synchronous Error Handling
107
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
108
+
109
+ When a recoverable error is encountered while calling the ``send()`` method of
110
+ a client, a ``GuzzleHttp\Exception\RequestException`` is thrown.
111
+
112
+ .. code-block:: php
113
+
114
+ use GuzzleHttp\Client;
115
+ use GuzzleHttp\Exception\RequestException;
116
+
117
+ $client = new Client();
118
+
119
+ try {
120
+ $client->get('http://httpbin.org');
121
+ } catch (RequestException $e) {
122
+ echo $e->getRequest() . "\n";
123
+ if ($e->hasResponse()) {
124
+ echo $e->getResponse() . "\n";
125
+ }
126
+ }
127
+
128
+ ``GuzzleHttp\Exception\RequestException`` always contains a
129
+ ``GuzzleHttp\Message\RequestInterface`` object that can be accessed using the
130
+ exception's ``getRequest()`` method.
131
+
132
+ A response might be present in the exception. In the event of a networking
133
+ error, no response will be received. You can check if a ``RequestException``
134
+ has a response using the ``hasResponse()`` method. If the exception has a
135
+ response, then you can access the associated
136
+ ``GuzzleHttp\Message\ResponseInterface`` using the ``getResponse()`` method of
137
+ the exception.
138
+
139
+ Asynchronous Requests
140
+ ---------------------
141
+
142
+ You can send asynchronous requests by setting the ``future`` request option
143
+ to ``true`` (or a string that your handler understands). This creates a
144
+ ``GuzzleHttp\Message\FutureResponse`` object that has not yet completed. Once
145
+ you have a future response, you can use a promise object obtained by calling
146
+ the ``then`` method of the response to take an action when the response has
147
+ completed or encounters an error.
148
+
149
+ .. code-block:: php
150
+
151
+ $response = $client->put('http://httpbin.org/get', ['future' => true]);
152
+
153
+ // Call the function when the response completes
154
+ $response->then(function ($response) {
155
+ echo $response->getStatusCode();
156
+ });
157
+
158
+ You can call the ``wait()`` method of a future response to block until it has
159
+ completed. You also use a future response object just like a normal response
160
+ object by accessing the methods of the response. Using a future response like a
161
+ normal response object, also known as *dereferencing*, will block until the
162
+ response has completed.
163
+
164
+ .. code-block:: php
165
+
166
+ $response = $client->put('http://httpbin.org/get', ['future' => true]);
167
+
168
+ // Block until the response has completed
169
+ echo $response->getStatusCode();
170
+
171
+ .. important::
172
+
173
+ If an exception occurred while transferring the future response, then the
174
+ exception encountered will be thrown when dereferencing.
175
+
176
+ .. note::
177
+
178
+ It depends on the RingPHP handler used by a client, but you typically need
179
+ to use the same RingPHP handler in order to utilize asynchronous requests
180
+ across multiple clients.
181
+
182
+ Asynchronous Error Handling
183
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
184
+
185
+ Handling errors with future response object promises is a bit different. When
186
+ using a promise, exceptions are forwarded to the ``$onError`` function provided
187
+ to the second argument of the ``then()`` function.
188
+
189
+ .. code-block:: php
190
+
191
+ $response = $client->put('http://httpbin.org/get', ['future' => true]);
192
+
193
+ $response
194
+ ->then(
195
+ function ($response) {
196
+ // This is called when the request succeeded
197
+ echo 'Success: ' . $response->getStatusCode();
198
+ // Returning a value will forward the value to the next promise
199
+ // in the chain.
200
+ return $response;
201
+ },
202
+ function ($error) {
203
+ // This is called when the exception failed.
204
+ echo 'Exception: ' . $error->getMessage();
205
+ // Throwing will "forward" the exception to the next promise
206
+ // in the chain.
207
+ throw $error;
208
+ }
209
+ )
210
+ ->then(
211
+ function($response) {
212
+ // This is called after the first promise in the chain. It
213
+ // receives the value returned from the first promise.
214
+ echo $response->getReasonPhrase();
215
+ },
216
+ function ($error) {
217
+ // This is called if the first promise error handler in the
218
+ // chain rethrows the exception.
219
+ echo 'Error: ' . $error->getMessage();
220
+ }
221
+ );
222
+
223
+ Please see the `React/Promises project documentation <https://github.com/reactphp/promise>`_
224
+ for more information on how promise resolution and rejection forwarding works.
225
+
226
+ HTTP Errors
227
+ -----------
228
+
229
+ If the ``exceptions`` request option is not set to ``false``, then exceptions
230
+ are thrown for HTTP protocol errors as well:
231
+ ``GuzzleHttp\Exception\ClientErrorResponseException`` for 4xx level HTTP
232
+ responses and ``GuzzleHttp\Exception\ServerException`` for 5xx level responses,
233
+ both of which extend from ``GuzzleHttp\Exception\BadResponseException``.
234
+
235
+ Creating Requests
236
+ -----------------
237
+
238
+ You can create a request without sending it. This is useful for building up
239
+ requests over time or sending requests in concurrently.
240
+
241
+ .. code-block:: php
242
+
243
+ $request = $client->createRequest('GET', 'http://httpbin.org', [
244
+ 'headers' => ['X-Foo' => 'Bar']
245
+ ]);
246
+
247
+ // Modify the request as needed
248
+ $request->setHeader('Baz', 'bar');
249
+
250
+ After creating a request, you can send it with the client's ``send()`` method.
251
+
252
+ .. code-block:: php
253
+
254
+ $response = $client->send($request);
255
+
256
+ Sending Requests With a Pool
257
+ ============================
258
+
259
+ You can send requests concurrently using a fixed size pool via the
260
+ ``GuzzleHttp\Pool`` class. The Pool class is an implementation of
261
+ ``GuzzleHttp\Ring\Future\FutureInterface``, meaning it can be dereferenced at a
262
+ later time or cancelled before sending. The Pool constructor accepts a client
263
+ object, iterator or array that yields ``GuzzleHttp\Message\RequestInterface``
264
+ objects, and an optional associative array of options that can be used to
265
+ affect the transfer.
266
+
267
+ .. code-block:: php
268
+
269
+ use GuzzleHttp\Pool;
270
+
271
+ $requests = [
272
+ $client->createRequest('GET', 'http://httpbin.org'),
273
+ $client->createRequest('DELETE', 'http://httpbin.org/delete'),
274
+ $client->createRequest('PUT', 'http://httpbin.org/put', ['body' => 'test'])
275
+ ];
276
+
277
+ $options = [];
278
+
279
+ // Create a pool. Note: the options array is optional.
280
+ $pool = new Pool($client, $requests, $options);
281
+
282
+ // Send the requests
283
+ $pool->wait();
284
+
285
+ The Pool constructor accepts the following associative array of options:
286
+
287
+ - **pool_size**: Integer representing the maximum number of requests that are
288
+ allowed to be sent concurrently.
289
+ - **before**: Callable or array representing the event listeners to add to
290
+ each request's :ref:`before_event` event.
291
+ - **complete**: Callable or array representing the event listeners to add to
292
+ each request's :ref:`complete_event` event.
293
+ - **error**: Callable or array representing the event listeners to add to
294
+ each request's :ref:`error_event` event.
295
+ - **end**: Callable or array representing the event listeners to add to
296
+ each request's :ref:`end_event` event.
297
+
298
+ The "before", "complete", "error", and "end" event options accept a callable or
299
+ an array of associative arrays where each associative array contains a "fn" key
300
+ with a callable value, an optional "priority" key representing the event
301
+ priority (with a default value of 0), and an optional "once" key that can be
302
+ set to true so that the event listener will be removed from the request after
303
+ it is first triggered.
304
+
305
+ .. code-block:: php
306
+
307
+ use GuzzleHttp\Pool;
308
+ use GuzzleHttp\Event\CompleteEvent;
309
+
310
+ // Add a single event listener using a callable.
311
+ Pool::send($client, $requests, [
312
+ 'complete' => function (CompleteEvent $event) {
313
+ echo 'Completed request to ' . $event->getRequest()->getUrl() . "\n";
314
+ echo 'Response: ' . $event->getResponse()->getBody() . "\n\n";
315
+ }
316
+ ]);
317
+
318
+ // The above is equivalent to the following, but the following structure
319
+ // allows you to add multiple event listeners to the same event name.
320
+ Pool::send($client, $requests, [
321
+ 'complete' => [
322
+ [
323
+ 'fn' => function (CompleteEvent $event) { /* ... */ },
324
+ 'priority' => 0, // Optional
325
+ 'once' => false // Optional
326
+ ]
327
+ ]
328
+ ]);
329
+
330
+ Asynchronous Response Handling
331
+ ------------------------------
332
+
333
+ When sending requests concurrently using a pool, the request/response/error
334
+ lifecycle must be handled asynchronously. This means that you give the Pool
335
+ multiple requests and handle the response or errors that is associated with the
336
+ request using event callbacks.
337
+
338
+ .. code-block:: php
339
+
340
+ use GuzzleHttp\Pool;
341
+ use GuzzleHttp\Event\ErrorEvent;
342
+
343
+ Pool::send($client, $requests, [
344
+ 'complete' => function (CompleteEvent $event) {
345
+ echo 'Completed request to ' . $event->getRequest()->getUrl() . "\n";
346
+ echo 'Response: ' . $event->getResponse()->getBody() . "\n\n";
347
+ // Do something with the completion of the request...
348
+ },
349
+ 'error' => function (ErrorEvent $event) {
350
+ echo 'Request failed: ' . $event->getRequest()->getUrl() . "\n";
351
+ echo $event->getException();
352
+ // Do something to handle the error...
353
+ }
354
+ ]);
355
+
356
+ The ``GuzzleHttp\Event\ErrorEvent`` event object is emitted when an error
357
+ occurs during a transfer. With this event, you have access to the request that
358
+ was sent, the response that was received (if one was received), access to
359
+ transfer statistics, and the ability to intercept the exception with a
360
+ different ``GuzzleHttp\Message\ResponseInterface`` object. See :doc:`events`
361
+ for more information.
362
+
363
+ Handling Errors After Transferring
364
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
365
+
366
+ It sometimes might be easier to handle all of the errors that occurred during a
367
+ transfer after all of the requests have been sent. Here we are adding each
368
+ failed request to an array that we can use to process errors later.
369
+
370
+ .. code-block:: php
371
+
372
+ use GuzzleHttp\Pool;
373
+ use GuzzleHttp\Event\ErrorEvent;
374
+
375
+ $errors = [];
376
+ Pool::send($client, $requests, [
377
+ 'error' => function (ErrorEvent $event) use (&$errors) {
378
+ $errors[] = $event;
379
+ }
380
+ ]);
381
+
382
+ foreach ($errors as $error) {
383
+ // Handle the error...
384
+ }
385
+
386
+ .. _batch-requests:
387
+
388
+ Batching Requests
389
+ -----------------
390
+
391
+ Sometimes you just want to send a few requests concurrently and then process
392
+ the results all at once after they've been sent. Guzzle provides a convenience
393
+ function ``GuzzleHttp\Pool::batch()`` that makes this very simple:
394
+
395
+ .. code-block:: php
396
+
397
+ use GuzzleHttp\Pool;
398
+ use GuzzleHttp\Client;
399
+
400
+ $client = new Client();
401
+
402
+ $requests = [
403
+ $client->createRequest('GET', 'http://httpbin.org/get'),
404
+ $client->createRequest('HEAD', 'http://httpbin.org/get'),
405
+ $client->createRequest('PUT', 'http://httpbin.org/put'),
406
+ ];
407
+
408
+ // Results is a GuzzleHttp\BatchResults object.
409
+ $results = Pool::batch($client, $requests);
410
+
411
+ // Can be accessed by index.
412
+ echo $results[0]->getStatusCode();
413
+
414
+ // Can be accessed by request.
415
+ echo $results->getResult($requests[0])->getStatusCode();
416
+
417
+ // Retrieve all successful responses
418
+ foreach ($results->getSuccessful() as $response) {
419
+ echo $response->getStatusCode() . "\n";
420
+ }
421
+
422
+ // Retrieve all failures.
423
+ foreach ($results->getFailures() as $requestException) {
424
+ echo $requestException->getMessage() . "\n";
425
+ }
426
+
427
+ ``GuzzleHttp\Pool::batch()`` accepts an optional associative array of options
428
+ in the third argument that allows you to specify the 'before', 'complete',
429
+ 'error', and 'end' events as well as specify the maximum number of requests to
430
+ send concurrently using the 'pool_size' option key.
431
+
432
+ .. _request-options:
433
+
434
+ Request Options
435
+ ===============
436
+
437
+ You can customize requests created by a client using **request options**.
438
+ Request options control various aspects of a request including, headers,
439
+ query string parameters, timeout settings, the body of a request, and much
440
+ more.
441
+
442
+ All of the following examples use the following client:
443
+
444
+ .. code-block:: php
445
+
446
+ $client = new GuzzleHttp\Client(['base_url' => 'http://httpbin.org']);
447
+
448
+ headers
449
+ -------
450
+
451
+ :Summary: Associative array of headers to add to the request. Each key is the
452
+ name of a header, and each value is a string or array of strings
453
+ representing the header field values.
454
+ :Types: array
455
+ :Defaults: None
456
+
457
+ .. code-block:: php
458
+
459
+ // Set various headers on a request
460
+ $client->get('/get', [
461
+ 'headers' => [
462
+ 'User-Agent' => 'testing/1.0',
463
+ 'Accept' => 'application/json',
464
+ 'X-Foo' => ['Bar', 'Baz']
465
+ ]
466
+ ]);
467
+
468
+ body
469
+ ----
470
+
471
+ :Summary: The ``body`` option is used to control the body of an entity
472
+ enclosing request (e.g., PUT, POST, PATCH).
473
+ :Types:
474
+ - string
475
+ - ``fopen()`` resource
476
+ - ``GuzzleHttp\Stream\StreamInterface``
477
+ - ``GuzzleHttp\Post\PostBodyInterface``
478
+ :Default: None
479
+
480
+ This setting can be set to any of the following types:
481
+
482
+ - string
483
+
484
+ .. code-block:: php
485
+
486
+ // You can send requests that use a string as the message body.
487
+ $client->put('/put', ['body' => 'foo']);
488
+
489
+ - resource returned from ``fopen()``
490
+
491
+ .. code-block:: php
492
+
493
+ // You can send requests that use a stream resource as the body.
494
+ $resource = fopen('http://httpbin.org', 'r');
495
+ $client->put('/put', ['body' => $resource]);
496
+
497
+ - Array
498
+
499
+ Use an array to send POST style requests that use a
500
+ ``GuzzleHttp\Post\PostBodyInterface`` object as the body.
501
+
502
+ .. code-block:: php
503
+
504
+ // You can send requests that use a POST body containing fields & files.
505
+ $client->post('/post', [
506
+ 'body' => [
507
+ 'field' => 'abc',
508
+ 'other_field' => '123',
509
+ 'file_name' => fopen('/path/to/file', 'r')
510
+ ]
511
+ ]);
512
+
513
+ - ``GuzzleHttp\Stream\StreamInterface``
514
+
515
+ .. code-block:: php
516
+
517
+ // You can send requests that use a Guzzle stream object as the body
518
+ $stream = GuzzleHttp\Stream\Stream::factory('contents...');
519
+ $client->post('/post', ['body' => $stream]);
520
+
521
+ json
522
+ ----
523
+
524
+ :Summary: The ``json`` option is used to easily upload JSON encoded data as the
525
+ body of a request. A Content-Type header of ``application/json`` will be
526
+ added if no Content-Type header is already present on the message.
527
+ :Types:
528
+ Any PHP type that can be operated on by PHP's ``json_encode()`` function.
529
+ :Default: None
530
+
531
+ .. code-block:: php
532
+
533
+ $request = $client->createRequest('PUT', '/put', ['json' => ['foo' => 'bar']]);
534
+ echo $request->getHeader('Content-Type');
535
+ // application/json
536
+ echo $request->getBody();
537
+ // {"foo":"bar"}
538
+
539
+ .. note::
540
+
541
+ This request option does not support customizing the Content-Type header
542
+ or any of the options from PHP's `json_encode() <http://www.php.net/manual/en/function.json-encode.php>`_
543
+ function. If you need to customize these settings, then you must pass the
544
+ JSON encoded data into the request yourself using the ``body`` request
545
+ option and you must specify the correct Content-Type header using the
546
+ ``headers`` request option.
547
+
548
+ query
549
+ -----
550
+
551
+ :Summary: Associative array of query string values to add to the request.
552
+ :Types:
553
+ - array
554
+ - ``GuzzleHttp\Query``
555
+ :Default: None
556
+
557
+ .. code-block:: php
558
+
559
+ // Send a GET request to /get?foo=bar
560
+ $client->get('/get', ['query' => ['foo' => 'bar']]);
561
+
562
+ Query strings specified in the ``query`` option are combined with any query
563
+ string values that are parsed from the URL.
564
+
565
+ .. code-block:: php
566
+
567
+ // Send a GET request to /get?abc=123&foo=bar
568
+ $client->get('/get?abc=123', ['query' => ['foo' => 'bar']]);
569
+
570
+ auth
571
+ ----
572
+
573
+ :Summary: Pass an array of HTTP authentication parameters to use with the
574
+ request. The array must contain the username in index [0], the password in
575
+ index [1], and you can optionally provide a built-in authentication type in
576
+ index [2]. Pass ``null`` to disable authentication for a request.
577
+ :Types:
578
+ - array
579
+ - string
580
+ - null
581
+ :Default: None
582
+
583
+ The built-in authentication types are as follows:
584
+
585
+ basic
586
+ Use `basic HTTP authentication <http://www.ietf.org/rfc/rfc2069.txt>`_ in
587
+ the ``Authorization`` header (the default setting used if none is
588
+ specified).
589
+
590
+ .. code-block:: php
591
+
592
+ $client->get('/get', ['auth' => ['username', 'password']]);
593
+
594
+ digest
595
+ Use `digest authentication <http://www.ietf.org/rfc/rfc2069.txt>`_ (must be
596
+ supported by the HTTP handler).
597
+
598
+ .. code-block:: php
599
+
600
+ $client->get('/get', ['auth' => ['username', 'password', 'digest']]);
601
+
602
+ *This is currently only supported when using the cURL handler, but creating
603
+ a replacement that can be used with any HTTP handler is planned.*
604
+
605
+ .. important::
606
+
607
+ The authentication type (whether it's provided as a string or as the third
608
+ option in an array) is always converted to a lowercase string. Take this
609
+ into account when implementing custom authentication types and when
610
+ implementing custom message factories.
611
+
612
+ Custom Authentication Schemes
613
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
614
+
615
+ You can also provide a string representing a custom authentication type name.
616
+ When using a custom authentication type string, you will need to implement
617
+ the authentication method in an event listener that checks the ``auth`` request
618
+ option of a request before it is sent. Authentication listeners that require
619
+ a request is not modified after they are signed should have a very low priority
620
+ to ensure that they are fired last or near last in the event chain.
621
+
622
+ .. code-block:: php
623
+
624
+ use GuzzleHttp\Event\BeforeEvent;
625
+ use GuzzleHttp\Event\RequestEvents;
626
+
627
+ /**
628
+ * Custom authentication listener that handles the "foo" auth type.
629
+ *
630
+ * Listens to the "before" event of a request and only modifies the request
631
+ * when the "auth" config setting of the request is "foo".
632
+ */
633
+ class FooAuth implements GuzzleHttp\Event\SubscriberInterface
634
+ {
635
+ private $password;
636
+
637
+ public function __construct($password)
638
+ {
639
+ $this->password = $password;
640
+ }
641
+
642
+ public function getEvents()
643
+ {
644
+ return ['before' => ['sign', RequestEvents::SIGN_REQUEST]];
645
+ }
646
+
647
+ public function sign(BeforeEvent $e)
648
+ {
649
+ if ($e->getRequest()->getConfig()['auth'] == 'foo') {
650
+ $e->getRequest()->setHeader('X-Foo', 'Foo ' . $this->password);
651
+ }
652
+ }
653
+ }
654
+
655
+ $client->getEmitter()->attach(new FooAuth('password'));
656
+ $client->get('/', ['auth' => 'foo']);
657
+
658
+ Adapter Specific Authentication Schemes
659
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
660
+
661
+ If you need to use authentication methods provided by cURL (e.g., NTLM, GSS,
662
+ etc.), then you need to specify a curl handler option in the ``options``
663
+ request option array. See :ref:`config-option` for more information.
664
+
665
+ .. _cookies-option:
666
+
667
+ cookies
668
+ -------
669
+
670
+ :Summary: Specifies whether or not cookies are used in a request or what cookie
671
+ jar to use or what cookies to send.
672
+ :Types:
673
+ - bool
674
+ - array
675
+ - ``GuzzleHttp\Cookie\CookieJarInterface``
676
+ :Default: None
677
+
678
+ Set to ``true`` to use a shared cookie session associated with the client.
679
+
680
+ .. code-block:: php
681
+
682
+ // Enable cookies using the shared cookie jar of the client.
683
+ $client->get('/get', ['cookies' => true]);
684
+
685
+ Pass an associative array containing cookies to send in the request and start a
686
+ new cookie session.
687
+
688
+ .. code-block:: php
689
+
690
+ // Enable cookies and send specific cookies
691
+ $client->get('/get', ['cookies' => ['foo' => 'bar']]);
692
+
693
+ Set to a ``GuzzleHttp\Cookie\CookieJarInterface`` object to use an existing
694
+ cookie jar.
695
+
696
+ .. code-block:: php
697
+
698
+ $jar = new GuzzleHttp\Cookie\CookieJar();
699
+ $client->get('/get', ['cookies' => $jar]);
700
+
701
+ .. _allow_redirects-option:
702
+
703
+ allow_redirects
704
+ ---------------
705
+
706
+ :Summary: Describes the redirect behavior of a request
707
+ :Types:
708
+ - bool
709
+ - array
710
+ :Default:
711
+ ::
712
+
713
+ [
714
+ 'max' => 5,
715
+ 'strict' => false,
716
+ 'referer' => true,
717
+ 'protocols' => ['http', 'https']
718
+ ]
719
+
720
+ Set to ``false`` to disable redirects.
721
+
722
+ .. code-block:: php
723
+
724
+ $res = $client->get('/redirect/3', ['allow_redirects' => false]);
725
+ echo $res->getStatusCode();
726
+ // 302
727
+
728
+ Set to ``true`` (the default setting) to enable normal redirects with a maximum
729
+ number of 5 redirects.
730
+
731
+ .. code-block:: php
732
+
733
+ $res = $client->get('/redirect/3');
734
+ echo $res->getStatusCode();
735
+ // 200
736
+
737
+ Pass an associative array containing the 'max' key to specify the maximum
738
+ number of redirects, provide a 'strict' key value to specify whether or not to
739
+ use strict RFC compliant redirects (meaning redirect POST requests with POST
740
+ requests vs. doing what most browsers do which is redirect POST requests with
741
+ GET requests), provide a 'referer' key to specify whether or not the "Referer"
742
+ header should be added when redirecting, and provide a 'protocols' array that
743
+ specifies which protocols are supported for redirects (defaults to
744
+ ``['http', 'https']``).
745
+
746
+ .. code-block:: php
747
+
748
+ $res = $client->get('/redirect/3', [
749
+ 'allow_redirects' => [
750
+ 'max' => 10, // allow at most 10 redirects.
751
+ 'strict' => true, // use "strict" RFC compliant redirects.
752
+ 'referer' => true, // add a Referer header
753
+ 'protocols' => ['https'] // only allow https URLs
754
+ ]
755
+ ]);
756
+ echo $res->getStatusCode();
757
+ // 200
758
+
759
+ decode_content
760
+ --------------
761
+
762
+ :Summary: Specify whether or not ``Content-Encoding`` responses (gzip,
763
+ deflate, etc.) are automatically decoded.
764
+ :Types:
765
+ - string
766
+ - bool
767
+ :Default: ``true``
768
+
769
+ This option can be used to control how content-encoded response bodies are
770
+ handled. By default, ``decode_content`` is set to true, meaning any gzipped
771
+ or deflated response will be decoded by Guzzle.
772
+
773
+ When set to ``false``, the body of a response is never decoded, meaning the
774
+ bytes pass through the handler unchanged.
775
+
776
+ .. code-block:: php
777
+
778
+ // Request gzipped data, but do not decode it while downloading
779
+ $client->get('/foo.js', [
780
+ 'headers' => ['Accept-Encoding' => 'gzip'],
781
+ 'decode_content' => false
782
+ ]);
783
+
784
+ When set to a string, the bytes of a response are decoded and the string value
785
+ provided to the ``decode_content`` option is passed as the ``Accept-Encoding``
786
+ header of the request.
787
+
788
+ .. code-block:: php
789
+
790
+ // Pass "gzip" as the Accept-Encoding header.
791
+ $client->get('/foo.js', ['decode_content' => 'gzip']);
792
+
793
+ .. _save_to-option:
794
+
795
+ save_to
796
+ -------
797
+
798
+ :Summary: Specify where the body of a response will be saved.
799
+ :Types:
800
+ - string
801
+ - ``fopen()`` resource
802
+ - ``GuzzleHttp\Stream\StreamInterface``
803
+ :Default: PHP temp stream
804
+
805
+ Pass a string to specify the path to a file that will store the contents of the
806
+ response body:
807
+
808
+ .. code-block:: php
809
+
810
+ $client->get('/stream/20', ['save_to' => '/path/to/file']);
811
+
812
+ Pass a resource returned from ``fopen()`` to write the response to a PHP stream:
813
+
814
+ .. code-block:: php
815
+
816
+ $resource = fopen('/path/to/file', 'w');
817
+ $client->get('/stream/20', ['save_to' => $resource]);
818
+
819
+ Pass a ``GuzzleHttp\Stream\StreamInterface`` object to stream the response body
820
+ to an open Guzzle stream:
821
+
822
+ .. code-block:: php
823
+
824
+ $resource = fopen('/path/to/file', 'w');
825
+ $stream = GuzzleHttp\Stream\Stream::factory($resource);
826
+ $client->get('/stream/20', ['save_to' => $stream]);
827
+
828
+ .. _events-option:
829
+
830
+ events
831
+ ------
832
+
833
+ :Summary: An associative array mapping event names to a callable. Or an
834
+ associative array containing the 'fn' key that maps to a callable, an
835
+ optional 'priority' key used to specify the event priority, and an optional
836
+ 'once' key used to specify if the event should remove itself the first time
837
+ it is triggered.
838
+ :Types: array
839
+ :Default: None
840
+
841
+ .. code-block:: php
842
+
843
+ use GuzzleHttp\Event\BeforeEvent;
844
+ use GuzzleHttp\Event\HeadersEvent;
845
+ use GuzzleHttp\Event\CompleteEvent;
846
+ use GuzzleHttp\Event\ErrorEvent;
847
+
848
+ $client->get('/', [
849
+ 'events' => [
850
+ 'before' => function (BeforeEvent $e) { echo 'Before'; },
851
+ 'complete' => function (CompleteEvent $e) { echo 'Complete'; },
852
+ 'error' => function (ErrorEvent $e) { echo 'Error'; },
853
+ ]
854
+ ]);
855
+
856
+ Here's an example of using the associative array format for control over the
857
+ priority and whether or not an event should be triggered more than once.
858
+
859
+ .. code-block:: php
860
+
861
+ $client->get('/', [
862
+ 'events' => [
863
+ 'before' => [
864
+ 'fn' => function (BeforeEvent $e) { echo 'Before'; },
865
+ 'priority' => 100,
866
+ 'once' => true
867
+ ]
868
+ ]
869
+ ]);
870
+
871
+ .. _subscribers-option:
872
+
873
+ subscribers
874
+ -----------
875
+
876
+ :Summary: Array of event subscribers to add to the request. Each value in the
877
+ array must be an instance of ``GuzzleHttp\Event\SubscriberInterface``.
878
+ :Types: array
879
+ :Default: None
880
+
881
+ .. code-block:: php
882
+
883
+ use GuzzleHttp\Subscriber\History;
884
+ use GuzzleHttp\Subscriber\Mock;
885
+ use GuzzleHttp\Message\Response;
886
+
887
+ $history = new History();
888
+ $mock = new Mock([new Response(200)]);
889
+ $client->get('/', ['subscribers' => [$history, $mock]]);
890
+
891
+ echo $history;
892
+ // Outputs the request and response history
893
+
894
+ .. _exceptions-option:
895
+
896
+ exceptions
897
+ ----------
898
+
899
+ :Summary: Set to ``false`` to disable throwing exceptions on an HTTP protocol
900
+ errors (i.e., 4xx and 5xx responses). Exceptions are thrown by default when
901
+ HTTP protocol errors are encountered.
902
+ :Types: bool
903
+ :Default: ``true``
904
+
905
+ .. code-block:: php
906
+
907
+ $client->get('/status/500');
908
+ // Throws a GuzzleHttp\Exception\ServerException
909
+
910
+ $res = $client->get('/status/500', ['exceptions' => false]);
911
+ echo $res->getStatusCode();
912
+ // 500
913
+
914
+ .. _timeout-option:
915
+
916
+ timeout
917
+ -------
918
+
919
+ :Summary: Float describing the timeout of the request in seconds. Use ``0``
920
+ to wait indefinitely (the default behavior).
921
+ :Types: float
922
+ :Default: ``0``
923
+
924
+ .. code-block:: php
925
+
926
+ // Timeout if a server does not return a response in 3.14 seconds.
927
+ $client->get('/delay/5', ['timeout' => 3.14]);
928
+ // PHP Fatal error: Uncaught exception 'GuzzleHttp\Exception\RequestException'
929
+
930
+ .. _connect_timeout-option:
931
+
932
+ connect_timeout
933
+ ---------------
934
+
935
+ :Summary: Float describing the number of seconds to wait while trying to connect
936
+ to a server. Use ``0`` to wait indefinitely (the default behavior).
937
+ :Types: float
938
+ :Default: ``0``
939
+
940
+ .. code-block:: php
941
+
942
+ // Timeout if the client fails to connect to the server in 3.14 seconds.
943
+ $client->get('/delay/5', ['connect_timeout' => 3.14]);
944
+
945
+ .. note::
946
+
947
+ This setting must be supported by the HTTP handler used to send a request.
948
+ ``connect_timeout`` is currently only supported by the built-in cURL
949
+ handler.
950
+
951
+ .. _verify-option:
952
+
953
+ verify
954
+ ------
955
+
956
+ :Summary: Describes the SSL certificate verification behavior of a request.
957
+
958
+ - Set to ``true`` to enable SSL certificate verification and use the default
959
+ CA bundle provided by operating system.
960
+ - Set to ``false`` to disable certificate verification (this is insecure!).
961
+ - Set to a string to provide the path to a CA bundle to enable verification
962
+ using a custom certificate.
963
+ :Types:
964
+ - bool
965
+ - string
966
+ :Default: ``true``
967
+
968
+ .. code-block:: php
969
+
970
+ // Use the system's CA bundle (this is the default setting)
971
+ $client->get('/', ['verify' => true]);
972
+
973
+ // Use a custom SSL certificate on disk.
974
+ $client->get('/', ['verify' => '/path/to/cert.pem']);
975
+
976
+ // Disable validation entirely (don't do this!).
977
+ $client->get('/', ['verify' => false]);
978
+
979
+ Not all system's have a known CA bundle on disk. For example, Windows and
980
+ OS X do not have a single common location for CA bundles. When setting
981
+ "verify" to ``true``, Guzzle will do its best to find the most appropriate
982
+ CA bundle on your system. When using cURL or the PHP stream wrapper on PHP
983
+ versions >= 5.6, this happens by default. When using the PHP stream
984
+ wrapper on versions < 5.6, Guzzle tries to find your CA bundle in the
985
+ following order:
986
+
987
+ 1. Check if ``openssl.cafile`` is set in your php.ini file.
988
+ 2. Check if ``curl.cainfo`` is set in your php.ini file.
989
+ 3. Check if ``/etc/pki/tls/certs/ca-bundle.crt`` exists (Red Hat, CentOS,
990
+ Fedora; provided by the ca-certificates package)
991
+ 4. Check if ``/etc/ssl/certs/ca-certificates.crt`` exists (Ubuntu, Debian;
992
+ provided by the ca-certificates package)
993
+ 5. Check if ``/usr/local/share/certs/ca-root-nss.crt`` exists (FreeBSD;
994
+ provided by the ca_root_nss package)
995
+ 6. Check if ``/usr/local/etc/openssl/cert.pem`` (OS X; provided by homebrew)
996
+ 7. Check if ``C:\windows\system32\curl-ca-bundle.crt`` exists (Windows)
997
+ 8. Check if ``C:\windows\curl-ca-bundle.crt`` exists (Windows)
998
+
999
+ The result of this lookup is cached in memory so that subsequent calls
1000
+ in the same process will return very quickly. However, when sending only
1001
+ a single request per-process in something like Apache, you should consider
1002
+ setting the ``openssl.cafile`` environment variable to the path on disk
1003
+ to the file so that this entire process is skipped.
1004
+
1005
+ If you do not need a specific certificate bundle, then Mozilla provides a
1006
+ commonly used CA bundle which can be downloaded
1007
+ `here <https://raw.githubusercontent.com/bagder/ca-bundle/master/ca-bundle.crt>`_
1008
+ (provided by the maintainer of cURL). Once you have a CA bundle available on
1009
+ disk, you can set the "openssl.cafile" PHP ini setting to point to the path to
1010
+ the file, allowing you to omit the "verify" request option. Much more detail on
1011
+ SSL certificates can be found on the
1012
+ `cURL website <http://curl.haxx.se/docs/sslcerts.html>`_.
1013
+
1014
+ .. _cert-option:
1015
+
1016
+ cert
1017
+ ----
1018
+
1019
+ :Summary: Set to a string to specify the path to a file containing a PEM
1020
+ formatted client side certificate. If a password is required, then set to
1021
+ an array containing the path to the PEM file in the first array element
1022
+ followed by the password required for the certificate in the second array
1023
+ element.
1024
+ :Types:
1025
+ - string
1026
+ - array
1027
+ :Default: None
1028
+
1029
+ .. code-block:: php
1030
+
1031
+ $client->get('/', ['cert' => ['/path/server.pem', 'password']]);
1032
+
1033
+ .. _ssl_key-option:
1034
+
1035
+ ssl_key
1036
+ -------
1037
+
1038
+ :Summary: Specify the path to a file containing a private SSL key in PEM
1039
+ format. If a password is required, then set to an array containing the path
1040
+ to the SSL key in the first array element followed by the password required
1041
+ for the certificate in the second element.
1042
+ :Types:
1043
+ - string
1044
+ - array
1045
+ :Default: None
1046
+
1047
+ .. note::
1048
+
1049
+ ``ssl_key`` is implemented by HTTP handlers. This is currently only
1050
+ supported by the cURL handler, but might be supported by other third-part
1051
+ handlers.
1052
+
1053
+ .. _proxy-option:
1054
+
1055
+ proxy
1056
+ -----
1057
+
1058
+ :Summary: Pass a string to specify an HTTP proxy, or an array to specify
1059
+ different proxies for different protocols.
1060
+ :Types:
1061
+ - string
1062
+ - array
1063
+ :Default: None
1064
+
1065
+ Pass a string to specify a proxy for all protocols.
1066
+
1067
+ .. code-block:: php
1068
+
1069
+ $client->get('/', ['proxy' => 'tcp://localhost:8125']);
1070
+
1071
+ Pass an associative array to specify HTTP proxies for specific URI schemes
1072
+ (i.e., "http", "https").
1073
+
1074
+ .. code-block:: php
1075
+
1076
+ $client->get('/', [
1077
+ 'proxy' => [
1078
+ 'http' => 'tcp://localhost:8125', // Use this proxy with "http"
1079
+ 'https' => 'tcp://localhost:9124' // Use this proxy with "https"
1080
+ ]
1081
+ ]);
1082
+
1083
+ .. note::
1084
+
1085
+ You can provide proxy URLs that contain a scheme, username, and password.
1086
+ For example, ``"http://username:password@192.168.16.1:10"``.
1087
+
1088
+ .. _debug-option:
1089
+
1090
+ debug
1091
+ -----
1092
+
1093
+ :Summary: Set to ``true`` or set to a PHP stream returned by ``fopen()`` to
1094
+ enable debug output with the handler used to send a request. For example,
1095
+ when using cURL to transfer requests, cURL's verbose of ``CURLOPT_VERBOSE``
1096
+ will be emitted. When using the PHP stream wrapper, stream wrapper
1097
+ notifications will be emitted. If set to true, the output is written to
1098
+ PHP's STDOUT. If a PHP stream is provided, output is written to the stream.
1099
+ :Types:
1100
+ - bool
1101
+ - ``fopen()`` resource
1102
+ :Default: None
1103
+
1104
+ .. code-block:: php
1105
+
1106
+ $client->get('/get', ['debug' => true]);
1107
+
1108
+ Running the above example would output something like the following:
1109
+
1110
+ ::
1111
+
1112
+ * About to connect() to httpbin.org port 80 (#0)
1113
+ * Trying 107.21.213.98... * Connected to httpbin.org (107.21.213.98) port 80 (#0)
1114
+ > GET /get HTTP/1.1
1115
+ Host: httpbin.org
1116
+ User-Agent: Guzzle/4.0 curl/7.21.4 PHP/5.5.7
1117
+
1118
+ < HTTP/1.1 200 OK
1119
+ < Access-Control-Allow-Origin: *
1120
+ < Content-Type: application/json
1121
+ < Date: Sun, 16 Feb 2014 06:50:09 GMT
1122
+ < Server: gunicorn/0.17.4
1123
+ < Content-Length: 335
1124
+ < Connection: keep-alive
1125
+ <
1126
+ * Connection #0 to host httpbin.org left intact
1127
+
1128
+ .. _stream-option:
1129
+
1130
+ stream
1131
+ ------
1132
+
1133
+ :Summary: Set to ``true`` to stream a response rather than download it all
1134
+ up-front.
1135
+ :Types: bool
1136
+ :Default: ``false``
1137
+
1138
+ .. code-block:: php
1139
+
1140
+ $response = $client->get('/stream/20', ['stream' => true]);
1141
+ // Read bytes off of the stream until the end of the stream is reached
1142
+ $body = $response->getBody();
1143
+ while (!$body->eof()) {
1144
+ echo $body->read(1024);
1145
+ }
1146
+
1147
+ .. note::
1148
+
1149
+ Streaming response support must be implemented by the HTTP handler used by
1150
+ a client. This option might not be supported by every HTTP handler, but the
1151
+ interface of the response object remains the same regardless of whether or
1152
+ not it is supported by the handler.
1153
+
1154
+ .. _expect-option:
1155
+
1156
+ expect
1157
+ ------
1158
+
1159
+ :Summary: Controls the behavior of the "Expect: 100-Continue" header.
1160
+ :Types:
1161
+ - bool
1162
+ - integer
1163
+ :Default: ``1048576``
1164
+
1165
+ Set to ``true`` to enable the "Expect: 100-Continue" header for all requests
1166
+ that sends a body. Set to ``false`` to disable the "Expect: 100-Continue"
1167
+ header for all requests. Set to a number so that the size of the payload must
1168
+ be greater than the number in order to send the Expect header. Setting to a
1169
+ number will send the Expect header for all requests in which the size of the
1170
+ payload cannot be determined or where the body is not rewindable.
1171
+
1172
+ By default, Guzzle will add the "Expect: 100-Continue" header when the size of
1173
+ the body of a request is greater than 1 MB and a request is using HTTP/1.1.
1174
+
1175
+ .. note::
1176
+
1177
+ This option only takes effect when using HTTP/1.1. The HTTP/1.0 and
1178
+ HTTP/2.0 protocols do not support the "Expect: 100-Continue" header.
1179
+ Support for handling the "Expect: 100-Continue" workflow must be
1180
+ implemented by Guzzle HTTP handlers used by a client.
1181
+
1182
+ .. _version-option:
1183
+
1184
+ version
1185
+ -------
1186
+
1187
+ :Summary: Protocol version to use with the request.
1188
+ :Types: string, float
1189
+ :Default: ``1.1``
1190
+
1191
+ .. code-block:: php
1192
+
1193
+ // Force HTTP/1.0
1194
+ $request = $client->createRequest('GET', '/get', ['version' => 1.0]);
1195
+ echo $request->getProtocolVersion();
1196
+ // 1.0
1197
+
1198
+ .. _config-option:
1199
+
1200
+ config
1201
+ ------
1202
+
1203
+ :Summary: Associative array of config options that are forwarded to a request's
1204
+ configuration collection. These values are used as configuration options
1205
+ that can be consumed by plugins and handlers.
1206
+ :Types: array
1207
+ :Default: None
1208
+
1209
+ .. code-block:: php
1210
+
1211
+ $request = $client->createRequest('GET', '/get', ['config' => ['foo' => 'bar']]);
1212
+ echo $request->getConfig('foo');
1213
+ // 'bar'
1214
+
1215
+ Some HTTP handlers allow you to specify custom handler-specific settings. For
1216
+ example, you can pass custom cURL options to requests by passing an associative
1217
+ array in the ``config`` request option under the ``curl`` key.
1218
+
1219
+ .. code-block:: php
1220
+
1221
+ // Use custom cURL options with the request. This example uses NTLM auth
1222
+ // to authenticate with a server.
1223
+ $client->get('/', [
1224
+ 'config' => [
1225
+ 'curl' => [
1226
+ CURLOPT_HTTPAUTH => CURLAUTH_NTLM,
1227
+ CURLOPT_USERPWD => 'username:password'
1228
+ ]
1229
+ ]
1230
+ ]);
1231
+
1232
+ future
1233
+ ------
1234
+
1235
+ :Summary: Specifies whether or not a response SHOULD be an instance of a
1236
+ ``GuzzleHttp\Message\FutureResponse`` object.
1237
+ :Types:
1238
+ - bool
1239
+ - string
1240
+ :Default: ``false``
1241
+
1242
+ By default, Guzzle requests should be synchronous. You can create asynchronous
1243
+ future responses by passing the ``future`` request option as ``true``. The
1244
+ response will only be executed when it is used like a normal response, the
1245
+ ``wait()`` method of the response is called, or the corresponding handler that
1246
+ created the response is destructing and there are futures that have not been
1247
+ resolved.
1248
+
1249
+ .. important::
1250
+
1251
+ This option only has an effect if your handler can create and return future
1252
+ responses. However, even if a response is completed synchronously, Guzzle
1253
+ will ensure that a FutureResponse object is returned for API consistency.
1254
+
1255
+ .. code-block:: php
1256
+
1257
+ $response = $client->get('/foo', ['future' => true])
1258
+ ->then(function ($response) {
1259
+ echo 'I got a response! ' . $response;
1260
+ });
1261
+
1262
+ Event Subscribers
1263
+ =================
1264
+
1265
+ Requests emit lifecycle events when they are transferred. A client object has a
1266
+ ``GuzzleHttp\Common\EventEmitter`` object that can be used to add event
1267
+ *listeners* and event *subscribers* to all requests created by the client.
1268
+
1269
+ .. important::
1270
+
1271
+ **Every** event listener or subscriber added to a client will be added to
1272
+ every request created by the client.
1273
+
1274
+ .. code-block:: php
1275
+
1276
+ use GuzzleHttp\Client;
1277
+ use GuzzleHttp\Event\BeforeEvent;
1278
+
1279
+ $client = new Client();
1280
+
1281
+ // Add a listener that will echo out requests before they are sent
1282
+ $client->getEmitter()->on('before', function (BeforeEvent $e) {
1283
+ echo 'About to send request: ' . $e->getRequest();
1284
+ });
1285
+
1286
+ $client->get('http://httpbin.org/get');
1287
+ // Outputs the request as a string because of the event
1288
+
1289
+ See :doc:`events` for more information on the event system used in Guzzle.
1290
+
1291
+ Environment Variables
1292
+ =====================
1293
+
1294
+ Guzzle exposes a few environment variables that can be used to customize the
1295
+ behavior of the library.
1296
+
1297
+ ``GUZZLE_CURL_SELECT_TIMEOUT``
1298
+ Controls the duration in seconds that a curl_multi_* handler will use when
1299
+ selecting on curl handles using ``curl_multi_select()``. Some systems
1300
+ have issues with PHP's implementation of ``curl_multi_select()`` where
1301
+ calling this function always results in waiting for the maximum duration of
1302
+ the timeout.
1303
+ ``HTTP_PROXY``
1304
+ Defines the proxy to use when sending requests using the "http" protocol.
1305
+ ``HTTPS_PROXY``
1306
+ Defines the proxy to use when sending requests using the "https" protocol.
1307
+
1308
+ Relevant ini Settings
1309
+ ---------------------
1310
+
1311
+ Guzzle can utilize PHP ini settings when configuring clients.
1312
+
1313
+ ``openssl.cafile``
1314
+ Specifies the path on disk to a CA file in PEM format to use when sending
1315
+ requests over "https". See: https://wiki.php.net/rfc/tls-peer-verification#phpini_defaults
backend/vendor/guzzlehttp/guzzle/docs/conf.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys, os
2
+ from sphinx.highlighting import lexers
3
+ from pygments.lexers.web import PhpLexer
4
+
5
+
6
+ lexers['php'] = PhpLexer(startinline=True, linenos=1)
7
+ lexers['php-annotations'] = PhpLexer(startinline=True, linenos=1)
8
+ primary_domain = 'php'
9
+
10
+ extensions = []
11
+ templates_path = ['_templates']
12
+ source_suffix = '.rst'
13
+ master_doc = 'index'
14
+ project = u'Guzzle'
15
+ copyright = u'2014, Michael Dowling'
16
+ version = '5.0.0'
17
+ html_title = "Guzzle Documentation"
18
+ html_short_title = "Guzzle"
19
+
20
+ exclude_patterns = ['_build']
21
+ html_static_path = ['_static']
22
+
23
+ on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
24
+
25
+ if not on_rtd: # only import and set the theme if we're building docs locally
26
+ import sphinx_rtd_theme
27
+ html_theme = 'sphinx_rtd_theme'
28
+ html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
backend/vendor/guzzlehttp/guzzle/docs/events.rst ADDED
@@ -0,0 +1,520 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ============
2
+ Event System
3
+ ============
4
+
5
+ Guzzle uses an event emitter to allow you to easily extend the behavior of a
6
+ request, change the response associated with a request, and implement custom
7
+ error handling. All events in Guzzle are managed and emitted by an
8
+ **event emitter**.
9
+
10
+ Event Emitters
11
+ ==============
12
+
13
+ Clients, requests, and any other class that implements the
14
+ ``GuzzleHttp\Event\HasEmitterInterface`` interface have a
15
+ ``GuzzleHttp\Event\Emitter`` object. You can add event *listeners* and
16
+ event *subscribers* to an event *emitter*.
17
+
18
+ emitter
19
+ An object that implements ``GuzzleHttp\Event\EmitterInterface``. This
20
+ object emits named events to event listeners. You may register event
21
+ listeners on subscribers on an emitter.
22
+
23
+ event listeners
24
+ Callable functions that are registered on an event emitter for specific
25
+ events. Event listeners are registered on an emitter with a *priority*
26
+ setting. If no priority is provided, ``0`` is used by default.
27
+
28
+ event subscribers
29
+ Classes that tell an event emitter what methods to listen to and what
30
+ functions on the class to invoke when the event is triggered. Event
31
+ subscribers subscribe event listeners to an event emitter. They should be
32
+ used when creating more complex event based logic in applications (i.e.,
33
+ cookie handling is implemented using an event subscriber because it's
34
+ easier to share a subscriber than an anonymous function and because
35
+ handling cookies is a complex process).
36
+
37
+ priority
38
+ Describes the order in which event listeners are invoked when an event is
39
+ emitted. The higher a priority value, the earlier the event listener will
40
+ be invoked (a higher priority means the listener is more important). If
41
+ no priority is provided, the priority is assumed to be ``0``.
42
+
43
+ When specifying an event priority, you can pass ``"first"`` or ``"last"`` to
44
+ dynamically specify the priority based on the current event priorities
45
+ associated with the given event name in the emitter. Use ``"first"`` to set
46
+ the priority to the current highest priority plus one. Use ``"last"`` to
47
+ set the priority to the current lowest event priority minus one. It is
48
+ important to remember that these dynamic priorities are calculated only at
49
+ the point of insertion into the emitter and they are not rearranged after
50
+ subsequent listeners are added to an emitter.
51
+
52
+ propagation
53
+ Describes whether or not other event listeners are triggered. Event
54
+ emitters will trigger every event listener registered to a specific event
55
+ in priority order until all of the listeners have been triggered **or**
56
+ until the propagation of an event is stopped.
57
+
58
+ Getting an EventEmitter
59
+ -----------------------
60
+
61
+ You can get the event emitter of ``GuzzleHttp\Event\HasEmitterInterface``
62
+ object using the the ``getEmitter()`` method. Here's an example of getting a
63
+ client object's event emitter.
64
+
65
+ .. code-block:: php
66
+
67
+ $client = new GuzzleHttp\Client();
68
+ $emitter = $client->getEmitter();
69
+
70
+ .. note::
71
+
72
+ You'll notice that the event emitter used in Guzzle is very similar to the
73
+ `Symfony2 EventDispatcher component <https://github.com/symfony/symfony/tree/master/src/Symfony/Component/EventDispatcher>`_.
74
+ This is because the Guzzle event system is based on the Symfony2 event
75
+ system with several changes. Guzzle uses its own event emitter to improve
76
+ performance, isolate Guzzle from changes to the Symfony, and provide a few
77
+ improvements that make it easier to use for an HTTP client (e.g., the
78
+ addition of the ``once()`` method).
79
+
80
+ Adding Event Listeners
81
+ ----------------------
82
+
83
+ After you have the emitter, you can register event listeners that listen to
84
+ specific events using the ``on()`` method. When registering an event listener,
85
+ you must tell the emitter what event to listen to (e.g., "before", "after",
86
+ "progress", "complete", "error", etc.), what callable to invoke when the
87
+ event is triggered, and optionally provide a priority.
88
+
89
+ .. code-block:: php
90
+
91
+ use GuzzleHttp\Event\BeforeEvent;
92
+
93
+ $emitter->on('before', function (BeforeEvent $event) {
94
+ echo $event->getRequest();
95
+ });
96
+
97
+ When a listener is triggered, it is passed an event that implements the
98
+ ``GuzzleHttp\Event\EventInterface`` interface, the name of the event, and the
99
+ event emitter itself. The above example could more verbosely be written as
100
+ follows:
101
+
102
+ .. code-block:: php
103
+
104
+ use GuzzleHttp\Event\BeforeEvent;
105
+
106
+ $emitter->on('before', function (
107
+ BeforeEvent $event,
108
+ $name,
109
+ EmitterInterface $emitter
110
+ ) {
111
+ echo $event->getRequest();
112
+ });
113
+
114
+ You can add an event listener that automatically removes itself after it is
115
+ triggered using the ``once()`` method of an event emitter.
116
+
117
+ .. code-block:: php
118
+
119
+ $client = new GuzzleHttp\Client();
120
+ $client->getEmitter()->once('before', function () {
121
+ echo 'This will only happen once... per request!';
122
+ });
123
+
124
+ Event Propagation
125
+ -----------------
126
+
127
+ Event listeners can prevent other event listeners from being triggered by
128
+ stopping an event's propagation.
129
+
130
+ Stopping event propagation can be useful, for example, if an event listener has
131
+ changed the state of the subject to such an extent that allowing subsequent
132
+ event listeners to be triggered could place the subject in an inconsistent
133
+ state. This technique is used in Guzzle extensively when intercepting error
134
+ events with responses.
135
+
136
+ You can stop the propagation of an event using the ``stopPropagation()`` method
137
+ of a ``GuzzleHttp\Event\EventInterface`` object:
138
+
139
+ .. code-block:: php
140
+
141
+ use GuzzleHttp\Event\ErrorEvent;
142
+
143
+ $emitter->on('error', function (ErrorEvent $event) {
144
+ $event->stopPropagation();
145
+ });
146
+
147
+ After stopping the propagation of an event, any subsequent event listeners that
148
+ have not yet been triggered will not be triggered. You can check to see if the
149
+ propagation of an event was stopped using the ``isPropagationStopped()`` method
150
+ of the event.
151
+
152
+ .. code-block:: php
153
+
154
+ $client = new GuzzleHttp\Client();
155
+ $emitter = $client->getEmitter();
156
+ // Note: assume that the $errorEvent was created
157
+ if ($emitter->emit('error', $errorEvent)->isPropagationStopped()) {
158
+ echo 'It was stopped!';
159
+ }
160
+
161
+ .. hint::
162
+
163
+ When emitting events, the event that was emitted is returned from the
164
+ emitter. This allows you to easily chain calls as shown in the above
165
+ example.
166
+
167
+ Event Subscribers
168
+ -----------------
169
+
170
+ Event subscribers are classes that implement the
171
+ ``GuzzleHttp\Event\SubscriberInterface`` object. They are used to register
172
+ one or more event listeners to methods of the class. Event subscribers tell
173
+ event emitters exactly which events to listen to and what method to invoke on
174
+ the class when the event is triggered by called the ``getEvents()`` method of
175
+ a subscriber.
176
+
177
+ The following example registers event listeners to the ``before`` and
178
+ ``complete`` event of a request. When the ``before`` event is emitted, the
179
+ ``onBefore`` instance method of the subscriber is invoked. When the
180
+ ``complete`` event is emitted, the ``onComplete`` event of the subscriber is
181
+ invoked. Each array value in the ``getEvents()`` return value MUST
182
+ contain the name of the method to invoke and can optionally contain the
183
+ priority of the listener (as shown in the ``before`` listener in the example).
184
+
185
+ .. code-block:: php
186
+
187
+ use GuzzleHttp\Event\EmitterInterface;
188
+ use GuzzleHttp\Event\SubscriberInterface;
189
+ use GuzzleHttp\Event\BeforeEvent;
190
+ use GuzzleHttp\Event\CompleteEvent;
191
+
192
+ class SimpleSubscriber implements SubscriberInterface
193
+ {
194
+ public function getEvents()
195
+ {
196
+ return [
197
+ // Provide name and optional priority
198
+ 'before' => ['onBefore', 100],
199
+ 'complete' => ['onComplete'],
200
+ // You can pass a list of listeners with different priorities
201
+ 'error' => [['beforeError', 'first'], ['afterError', 'last']]
202
+ ];
203
+ }
204
+
205
+ public function onBefore(BeforeEvent $event, $name)
206
+ {
207
+ echo 'Before!';
208
+ }
209
+
210
+ public function onComplete(CompleteEvent $event, $name)
211
+ {
212
+ echo 'Complete!';
213
+ }
214
+ }
215
+
216
+ To register the listeners the subscriber needs to be attached to the emitter:
217
+
218
+ .. code-block:: php
219
+
220
+ $client = new GuzzleHttp\Client();
221
+ $emitter = $client->getEmitter();
222
+ $subscriber = new SimpleSubscriber();
223
+ $emitter->attach($subscriber);
224
+
225
+ //to remove the listeners
226
+ $emitter->detach($subscriber);
227
+
228
+ .. note::
229
+
230
+ You can specify event priorities using integers or ``"first"`` and
231
+ ``"last"`` to dynamically determine the priority.
232
+
233
+ Event Priorities
234
+ ================
235
+
236
+ When adding event listeners or subscribers, you can provide an optional event
237
+ priority. This priority is used to determine how early or late a listener is
238
+ triggered. Specifying the correct priority is an important aspect of ensuring
239
+ a listener behaves as expected. For example, if you wanted to ensure that
240
+ cookies associated with a redirect were added to a cookie jar, you'd need to
241
+ make sure that the listener that collects the cookies is triggered before the
242
+ listener that performs the redirect.
243
+
244
+ In order to help make the process of determining the correct event priority of
245
+ a listener easier, Guzzle provides several pre-determined named event
246
+ priorities. These priorities are exposed as constants on the
247
+ ``GuzzleHttp\Event\RequestEvents`` object.
248
+
249
+ last
250
+ Use ``"last"`` as an event priority to set the priority to the current
251
+ lowest event priority minus one.
252
+
253
+ first
254
+ Use ``"first"`` as an event priority to set the priority to the current
255
+ highest priority plus one.
256
+
257
+ ``GuzzleHttp\Event\RequestEvents::EARLY``
258
+ Used when you want a listener to be triggered as early as possible in the
259
+ event chain.
260
+
261
+ ``GuzzleHttp\Event\RequestEvents::LATE``
262
+ Used when you want a listener to be to be triggered as late as possible in
263
+ the event chain.
264
+
265
+ ``GuzzleHttp\Event\RequestEvents::PREPARE_REQUEST``
266
+ Used when you want a listener to be trigger while a request is being
267
+ prepared during the ``before`` event. This event priority is used by the
268
+ ``GuzzleHttp\Subscriber\Prepare`` event subscriber which is responsible for
269
+ guessing a Content-Type, Content-Length, and Expect header of a request.
270
+ You should subscribe after this event is triggered if you want to ensure
271
+ that this subscriber has already been triggered.
272
+
273
+ ``GuzzleHttp\Event\RequestEvents::SIGN_REQUEST``
274
+ Used when you want a listener to be triggered when a request is about to be
275
+ signed. Any listener triggered at this point should expect that the request
276
+ object will no longer be mutated. If you are implementing a custom
277
+ signature subscriber, then you should use this event priority to sign
278
+ requests.
279
+
280
+ ``GuzzleHttp\Event\RequestEvents::VERIFY_RESPONSE``
281
+ Used when you want a listener to be triggered when a response is being
282
+ validated during the ``complete`` event. The
283
+ ``GuzzleHttp\Subscriber\HttpError`` event subscriber uses this event
284
+ priority to check if an exception should be thrown due to a 4xx or 5xx
285
+ level response status code. If you are doing any kind of verification of a
286
+ response during the complete event, it should happen at this priority.
287
+
288
+ ``GuzzleHttp\Event\RequestEvents::REDIRECT_RESPONSE``
289
+ Used when you want a listener to be triggered when a response is being
290
+ redirected during the ``complete`` event. The
291
+ ``GuzzleHttp\Subscriber\Redirect`` event subscriber uses this event
292
+ priority when performing redirects.
293
+
294
+ You can use the above event priorities as a guideline for determining the
295
+ priority of you event listeners. You can use these constants and add to or
296
+ subtract from them to ensure that a listener happens before or after the named
297
+ priority.
298
+
299
+ .. note::
300
+
301
+ "first" and "last" priorities are not adjusted after they added to an
302
+ emitter. For example, if you add a listener with a priority of "first",
303
+ you can still add subsequent listeners with a higher priority which would
304
+ be triggered before the listener added with a priority of "first".
305
+
306
+ Working With Request Events
307
+ ===========================
308
+
309
+ Requests emit lifecycle events when they are transferred.
310
+
311
+ .. important::
312
+
313
+ Excluding the ``end`` event, request lifecycle events may be triggered
314
+ multiple times due to redirects, retries, or reusing a request multiple
315
+ times. Use the ``once()`` method want the event to be triggered once. You
316
+ can also remove an event listener from an emitter by using the emitter which
317
+ is provided to the listener.
318
+
319
+ .. _before_event:
320
+
321
+ before
322
+ ------
323
+
324
+ The ``before`` event is emitted before a request is sent. The event emitted is
325
+ a ``GuzzleHttp\Event\BeforeEvent``.
326
+
327
+ .. code-block:: php
328
+
329
+ use GuzzleHttp\Client;
330
+ use GuzzleHttp\Event\EmitterInterface;
331
+ use GuzzleHttp\Event\BeforeEvent;
332
+
333
+ $client = new Client(['base_url' => 'http://httpbin.org']);
334
+ $request = $client->createRequest('GET', '/');
335
+ $request->getEmitter()->on(
336
+ 'before',
337
+ function (BeforeEvent $e, $name, EmitterInterface $emitter) {
338
+ echo $name . "\n";
339
+ // "before"
340
+ echo $e->getRequest()->getMethod() . "\n";
341
+ // "GET" / "POST" / "PUT" / etc.
342
+ echo get_class($e->getClient());
343
+ // "GuzzleHttp\Client"
344
+ }
345
+ );
346
+
347
+ You can intercept a request with a response before the request is sent over the
348
+ wire. The ``intercept()`` method of the ``BeforeEvent`` accepts a
349
+ ``GuzzleHttp\Message\ResponseInterface``. Intercepting the event will prevent
350
+ the request from being sent over the wire and stops the propagation of the
351
+ ``before`` event, preventing subsequent event listeners from being invoked.
352
+
353
+ .. code-block:: php
354
+
355
+ use GuzzleHttp\Client;
356
+ use GuzzleHttp\Event\BeforeEvent;
357
+ use GuzzleHttp\Message\Response;
358
+
359
+ $client = new Client(['base_url' => 'http://httpbin.org']);
360
+ $request = $client->createRequest('GET', '/status/500');
361
+ $request->getEmitter()->on('before', function (BeforeEvent $e) {
362
+ $response = new Response(200);
363
+ $e->intercept($response);
364
+ });
365
+
366
+ $response = $client->send($request);
367
+ echo $response->getStatusCode();
368
+ // 200
369
+
370
+ .. attention::
371
+
372
+ Any exception encountered while executing the ``before`` event will trigger
373
+ the ``error`` event of a request.
374
+
375
+ .. _complete_event:
376
+
377
+ complete
378
+ --------
379
+
380
+ The ``complete`` event is emitted after a transaction completes and an entire
381
+ response has been received. The event is a ``GuzzleHttp\Event\CompleteEvent``.
382
+
383
+ You can intercept the ``complete`` event with a different response if needed
384
+ using the ``intercept()`` method of the event. This can be useful, for example,
385
+ for changing the response for caching.
386
+
387
+ .. code-block:: php
388
+
389
+ use GuzzleHttp\Client;
390
+ use GuzzleHttp\Event\CompleteEvent;
391
+ use GuzzleHttp\Message\Response;
392
+
393
+ $client = new Client(['base_url' => 'http://httpbin.org']);
394
+ $request = $client->createRequest('GET', '/status/302');
395
+ $cachedResponse = new Response(200);
396
+
397
+ $request->getEmitter()->on(
398
+ 'complete',
399
+ function (CompleteEvent $e) use ($cachedResponse) {
400
+ if ($e->getResponse()->getStatusCode() == 302) {
401
+ // Intercept the original transaction with the new response
402
+ $e->intercept($cachedResponse);
403
+ }
404
+ }
405
+ );
406
+
407
+ $response = $client->send($request);
408
+ echo $response->getStatusCode();
409
+ // 200
410
+
411
+ .. attention::
412
+
413
+ Any ``GuzzleHttp\Exception\RequestException`` encountered while executing
414
+ the ``complete`` event will trigger the ``error`` event of a request.
415
+
416
+ .. _error_event:
417
+
418
+ error
419
+ -----
420
+
421
+ The ``error`` event is emitted when a request fails (whether it's from a
422
+ networking error or an HTTP protocol error). The event emitted is a
423
+ ``GuzzleHttp\Event\ErrorEvent``.
424
+
425
+ This event is useful for retrying failed requests. Here's an example of
426
+ retrying failed basic auth requests by re-sending the original request with
427
+ a username and password.
428
+
429
+ .. code-block:: php
430
+
431
+ use GuzzleHttp\Client;
432
+ use GuzzleHttp\Event\ErrorEvent;
433
+
434
+ $client = new Client(['base_url' => 'http://httpbin.org']);
435
+ $request = $client->createRequest('GET', '/basic-auth/foo/bar');
436
+ $request->getEmitter()->on('error', function (ErrorEvent $e) {
437
+ if ($e->getResponse()->getStatusCode() == 401) {
438
+ // Add authentication stuff as needed and retry the request
439
+ $e->getRequest()->setHeader('Authorization', 'Basic ' . base64_encode('foo:bar'));
440
+ // Get the client of the event and retry the request
441
+ $newResponse = $e->getClient()->send($e->getRequest());
442
+ // Intercept the original transaction with the new response
443
+ $e->intercept($newResponse);
444
+ }
445
+ });
446
+
447
+ .. attention::
448
+
449
+ If an ``error`` event is intercepted with a response, then the ``complete``
450
+ event of a request is triggered. If the ``complete`` event fails, then the
451
+ ``error`` event is triggered once again.
452
+
453
+ .. _progress_event:
454
+
455
+ progress
456
+ --------
457
+
458
+ The ``progress`` event is emitted when data is uploaded or downloaded. The
459
+ event emitted is a ``GuzzleHttp\Event\ProgressEvent``.
460
+
461
+ You can access the emitted progress values using the corresponding public
462
+ properties of the event object:
463
+
464
+ - ``$downloadSize``: The number of bytes that will be downloaded (if known)
465
+ - ``$downloaded``: The number of bytes that have been downloaded
466
+ - ``$uploadSize``: The number of bytes that will be uploaded (if known)
467
+ - ``$uploaded``: The number of bytes that have been uploaded
468
+
469
+ This event cannot be intercepted.
470
+
471
+ .. code-block:: php
472
+
473
+ use GuzzleHttp\Client;
474
+ use GuzzleHttp\Event\ProgressEvent;
475
+
476
+ $client = new Client(['base_url' => 'http://httpbin.org']);
477
+ $request = $client->createRequest('PUT', '/put', [
478
+ 'body' => str_repeat('.', 100000)
479
+ ]);
480
+
481
+ $request->getEmitter()->on('progress', function (ProgressEvent $e) {
482
+ echo 'Downloaded ' . $e->downloaded . ' of ' . $e->downloadSize . ' '
483
+ . 'Uploaded ' . $e->uploaded . ' of ' . $e->uploadSize . "\r";
484
+ });
485
+
486
+ $client->send($request);
487
+ echo "\n";
488
+
489
+ .. _end_event:
490
+
491
+ end
492
+ ---
493
+
494
+ The ``end`` event is a terminal event, emitted once per request, that provides
495
+ access to the response that was received or the exception that was encountered.
496
+ The event emitted is a ``GuzzleHttp\Event\EndEvent``.
497
+
498
+ This event can be intercepted, but keep in mind that the ``complete`` event
499
+ will not fire after intercepting this event.
500
+
501
+ .. code-block:: php
502
+
503
+ use GuzzleHttp\Client;
504
+ use GuzzleHttp\Event\EndEvent;
505
+
506
+ $client = new Client(['base_url' => 'http://httpbin.org']);
507
+ $request = $client->createRequest('PUT', '/put', [
508
+ 'body' => str_repeat('.', 100000)
509
+ ]);
510
+
511
+ $request->getEmitter()->on('end', function (EndEvent $e) {
512
+ if ($e->getException()) {
513
+ echo 'Error: ' . $e->getException()->getMessage();
514
+ } else {
515
+ echo 'Response: ' . $e->getResponse();
516
+ }
517
+ });
518
+
519
+ $client->send($request);
520
+ echo "\n";
backend/vendor/guzzlehttp/guzzle/docs/faq.rst ADDED
@@ -0,0 +1,199 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ===
2
+ FAQ
3
+ ===
4
+
5
+ Why should I use Guzzle?
6
+ ========================
7
+
8
+ Guzzle makes it easy to send HTTP requests and super simple to integrate with
9
+ web services. Guzzle manages things like persistent connections, represents
10
+ query strings as collections, makes it simple to send streaming POST requests
11
+ with fields and files, and abstracts away the underlying HTTP transport layer.
12
+ By providing an object oriented interface for HTTP clients, requests, responses,
13
+ headers, and message bodies, Guzzle makes it so that you no longer need to fool
14
+ around with cURL options, stream contexts, or sockets.
15
+
16
+ **Asynchronous and Synchronous Requests**
17
+
18
+ Guzzle allows you to send both asynchronous and synchronous requests using the
19
+ same interface and no direct dependency on an event loop. This flexibility
20
+ allows Guzzle to send an HTTP request using the most appropriate HTTP handler
21
+ based on the request being sent. For example, when sending synchronous
22
+ requests, Guzzle will by default send requests using cURL easy handles to
23
+ ensure you're using the fastest possible method for serially transferring HTTP
24
+ requests. When sending asynchronous requests, Guzzle might use cURL's multi
25
+ interface or any other asynchronous handler you configure. When you request
26
+ streaming data, Guzzle will by default use PHP's stream wrapper.
27
+
28
+ **Streams**
29
+
30
+ Request and response message bodies use :doc:`Guzzle Streams <streams>`,
31
+ allowing you to stream data without needing to load it all into memory.
32
+ Guzzle's stream layer provides a large suite of functionality:
33
+
34
+ - You can modify streams at runtime using custom or a number of
35
+ pre-made decorators.
36
+ - You can emit progress events as data is read from a stream.
37
+ - You can validate the integrity of a stream using a rolling hash as data is
38
+ read from a stream.
39
+
40
+ **Event System and Plugins**
41
+
42
+ Guzzle's event system allows you to completely modify the behavior of a client
43
+ or request at runtime to cater them for any API. You can send a request with a
44
+ client, and the client can do things like automatically retry your request if
45
+ it fails, automatically redirect, log HTTP messages that are sent over the
46
+ wire, emit progress events as data is uploaded and downloaded, sign requests
47
+ using OAuth 1.0, verify the integrity of messages before and after they are
48
+ sent over the wire, and anything else you might need.
49
+
50
+ **Testable**
51
+
52
+ Another important aspect of Guzzle is that it's really
53
+ :doc:`easy to test clients <testing>`. You can mock HTTP responses and when
54
+ testing an handler implementation, Guzzle provides a mock node.js web server.
55
+
56
+ **Ecosystem**
57
+
58
+ Guzzle has a large `ecosystem of plugins <http://guzzle.readthedocs.org/en/latest/index.html#http-components>`_,
59
+ including `service descriptions <https://github.com/guzzle/guzzle-services>`_
60
+ which allows you to abstract web services using service descriptions. These
61
+ service descriptions define how to serialize an HTTP request and how to parse
62
+ an HTTP response into a more meaningful model object.
63
+
64
+ - `Guzzle Command <https://github.com/guzzle/command>`_: Provides the building
65
+ blocks for service description abstraction.
66
+ - `Guzzle Services <https://github.com/guzzle/guzzle-services>`_: Provides an
67
+ implementation of "Guzzle Command" that utilizes Guzzle's service description
68
+ format.
69
+
70
+ Does Guzzle require cURL?
71
+ =========================
72
+
73
+ No. Guzzle can use any HTTP handler to send requests. This means that Guzzle
74
+ can be used with cURL, PHP's stream wrapper, sockets, and non-blocking libraries
75
+ like `React <http://reactphp.org/>`_. You just need to configure a
76
+ `RingPHP <http://guzzle-ring.readthedocs.org/en/latest/>`_ handler to use a
77
+ different method of sending requests.
78
+
79
+ .. note::
80
+
81
+ Guzzle has historically only utilized cURL to send HTTP requests. cURL is
82
+ an amazing HTTP client (arguably the best), and Guzzle will continue to use
83
+ it by default when it is available. It is rare, but some developers don't
84
+ have cURL installed on their systems or run into version specific issues.
85
+ By allowing swappable HTTP handlers, Guzzle is now much more customizable
86
+ and able to adapt to fit the needs of more developers.
87
+
88
+ Can Guzzle send asynchronous requests?
89
+ ======================================
90
+
91
+ Yes. Pass the ``future`` true request option to a request to send it
92
+ asynchronously. Guzzle will then return a ``GuzzleHttp\Message\FutureResponse``
93
+ object that can be used synchronously by accessing the response object like a
94
+ normal response, and it can be used asynchronously using a promise that is
95
+ notified when the response is resolved with a real response or rejected with an
96
+ exception.
97
+
98
+ .. code-block:: php
99
+
100
+ $request = $client->createRequest('GET', ['future' => true]);
101
+ $client->send($request)->then(function ($response) {
102
+ echo 'Got a response! ' . $response;
103
+ });
104
+
105
+ You can force an asynchronous response to complete using the ``wait()`` method
106
+ of a response.
107
+
108
+ .. code-block:: php
109
+
110
+ $request = $client->createRequest('GET', ['future' => true]);
111
+ $futureResponse = $client->send($request);
112
+ $futureResponse->wait();
113
+
114
+ How can I add custom cURL options?
115
+ ==================================
116
+
117
+ cURL offer a huge number of `customizable options <http://us1.php.net/curl_setopt>`_.
118
+ While Guzzle normalizes many of these options across different handlers, there
119
+ are times when you need to set custom cURL options. This can be accomplished
120
+ by passing an associative array of cURL settings in the **curl** key of the
121
+ **config** request option.
122
+
123
+ For example, let's say you need to customize the outgoing network interface
124
+ used with a client.
125
+
126
+ .. code-block:: php
127
+
128
+ $client->get('/', [
129
+ 'config' => [
130
+ 'curl' => [
131
+ CURLOPT_INTERFACE => 'xxx.xxx.xxx.xxx'
132
+ ]
133
+ ]
134
+ ]);
135
+
136
+ How can I add custom stream context options?
137
+ ============================================
138
+
139
+ You can pass custom `stream context options <http://www.php.net/manual/en/context.php>`_
140
+ using the **stream_context** key of the **config** request option. The
141
+ **stream_context** array is an associative array where each key is a PHP
142
+ transport, and each value is an associative array of transport options.
143
+
144
+ For example, let's say you need to customize the outgoing network interface
145
+ used with a client and allow self-signed certificates.
146
+
147
+ .. code-block:: php
148
+
149
+ $client->get('/', [
150
+ 'stream' => true,
151
+ 'config' => [
152
+ 'stream_context' => [
153
+ 'ssl' => [
154
+ 'allow_self_signed' => true
155
+ ],
156
+ 'socket' => [
157
+ 'bindto' => 'xxx.xxx.xxx.xxx'
158
+ ]
159
+ ]
160
+ ]
161
+ ]);
162
+
163
+ Why am I getting an SSL verification error?
164
+ ===========================================
165
+
166
+ You need to specify the path on disk to the CA bundle used by Guzzle for
167
+ verifying the peer certificate. See :ref:`verify-option`.
168
+
169
+ What is this Maximum function nesting error?
170
+ ============================================
171
+
172
+ Maximum function nesting level of '100' reached, aborting
173
+
174
+ You could run into this error if you have the XDebug extension installed and
175
+ you execute a lot of requests in callbacks. This error message comes
176
+ specifically from the XDebug extension. PHP itself does not have a function
177
+ nesting limit. Change this setting in your php.ini to increase the limit::
178
+
179
+ xdebug.max_nesting_level = 1000
180
+
181
+ Why am I getting a 417 error response?
182
+ ======================================
183
+
184
+ This can occur for a number of reasons, but if you are sending PUT, POST, or
185
+ PATCH requests with an ``Expect: 100-Continue`` header, a server that does not
186
+ support this header will return a 417 response. You can work around this by
187
+ setting the ``expect`` request option to ``false``:
188
+
189
+ .. code-block:: php
190
+
191
+ $client = new GuzzleHttp\Client();
192
+
193
+ // Disable the expect header on a single request
194
+ $response = $client->put('/', [], 'the body', [
195
+ 'expect' => false
196
+ ]);
197
+
198
+ // Disable the expect header on all client requests
199
+ $client->setDefaultOption('expect', false)
backend/vendor/guzzlehttp/guzzle/docs/handlers.rst ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ================
2
+ RingPHP Handlers
3
+ ================
4
+
5
+ Guzzle uses RingPHP handlers to send HTTP requests over the wire.
6
+ RingPHP provides a low-level library that can be used to "glue" Guzzle with
7
+ any transport method you choose. By default, Guzzle utilizes cURL and PHP's
8
+ stream wrappers to send HTTP requests.
9
+
10
+ RingPHP handlers makes it extremely simple to integrate Guzzle with any
11
+ HTTP transport. For example, you could quite easily bridge Guzzle and React
12
+ to use Guzzle in React's event loop.
13
+
14
+ Using a handler
15
+ ---------------
16
+
17
+ You can change the handler used by a client using the ``handler`` option in the
18
+ ``GuzzleHttp\Client`` constructor.
19
+
20
+ .. code-block:: php
21
+
22
+ use GuzzleHttp\Client;
23
+ use GuzzleHttp\Ring\Client\MockHandler;
24
+
25
+ // Create a mock handler that always returns a 200 response.
26
+ $handler = new MockHandler(['status' => 200]);
27
+
28
+ // Configure to client to use the mock handler.
29
+ $client = new Client(['handler' => $handler]);
30
+
31
+ At its core, handlers are simply PHP callables that accept a request array
32
+ and return a ``GuzzleHttp\Ring\Future\FutureArrayInterface``. This future array
33
+ can be used just like a normal PHP array, causing it to block, or you can use
34
+ the promise interface using the ``then()`` method of the future. Guzzle hooks
35
+ up to the RingPHP project using a very simple bridge class
36
+ (``GuzzleHttp\RingBridge``).
37
+
38
+ Creating a handler
39
+ ------------------
40
+
41
+ See the `RingPHP <http://ringphp.readthedocs.org>`_ project
42
+ documentation for more information on creating custom handlers that can be
43
+ used with Guzzle clients.
backend/vendor/guzzlehttp/guzzle/docs/http-messages.rst ADDED
@@ -0,0 +1,483 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ =============================
2
+ Request and Response Messages
3
+ =============================
4
+
5
+ Guzzle is an HTTP client that sends HTTP requests to a server and receives HTTP
6
+ responses. Both requests and responses are referred to as messages.
7
+
8
+ Headers
9
+ =======
10
+
11
+ Both request and response messages contain HTTP headers.
12
+
13
+ Complex Headers
14
+ ---------------
15
+
16
+ Some headers contain additional key value pair information. For example, Link
17
+ headers contain a link and several key value pairs:
18
+
19
+ ::
20
+
21
+ <http://foo.com>; rel="thing"; type="image/jpeg"
22
+
23
+ Guzzle provides a convenience feature that can be used to parse these types of
24
+ headers:
25
+
26
+ .. code-block:: php
27
+
28
+ use GuzzleHttp\Message\Request;
29
+
30
+ $request = new Request('GET', '/', [
31
+ 'Link' => '<http:/.../front.jpeg>; rel="front"; type="image/jpeg"'
32
+ ]);
33
+
34
+ $parsed = Request::parseHeader($request, 'Link');
35
+ var_export($parsed);
36
+
37
+ Will output:
38
+
39
+ .. code-block:: php
40
+
41
+ array (
42
+ 0 =>
43
+ array (
44
+ 0 => '<http:/.../front.jpeg>',
45
+ 'rel' => 'front',
46
+ 'type' => 'image/jpeg',
47
+ ),
48
+ )
49
+
50
+ The result contains a hash of key value pairs. Header values that have no key
51
+ (i.e., the link) are indexed numerically while headers parts that form a key
52
+ value pair are added as a key value pair.
53
+
54
+ See :ref:`headers` for information on how the headers of a request and response
55
+ can be accessed and modified.
56
+
57
+ Body
58
+ ====
59
+
60
+ Both request and response messages can contain a body.
61
+
62
+ You can check to see if a request or response has a body using the
63
+ ``getBody()`` method:
64
+
65
+ .. code-block:: php
66
+
67
+ $response = GuzzleHttp\get('http://httpbin.org/get');
68
+ if ($response->getBody()) {
69
+ echo $response->getBody();
70
+ // JSON string: { ... }
71
+ }
72
+
73
+ The body used in request and response objects is a
74
+ ``GuzzleHttp\Stream\StreamInterface``. This stream is used for both uploading
75
+ data and downloading data. Guzzle will, by default, store the body of a message
76
+ in a stream that uses PHP temp streams. When the size of the body exceeds
77
+ 2 MB, the stream will automatically switch to storing data on disk rather than
78
+ in memory (protecting your application from memory exhaustion).
79
+
80
+ You can change the body used in a request or response using the ``setBody()``
81
+ method:
82
+
83
+ .. code-block:: php
84
+
85
+ use GuzzleHttp\Stream\Stream;
86
+ $request = $client->createRequest('PUT', 'http://httpbin.org/put');
87
+ $request->setBody(Stream::factory('foo'));
88
+
89
+ The easiest way to create a body for a request is using the static
90
+ ``GuzzleHttp\Stream\Stream::factory()`` method. This method accepts various
91
+ inputs like strings, resources returned from ``fopen()``, and other
92
+ ``GuzzleHttp\Stream\StreamInterface`` objects.
93
+
94
+ The body of a request or response can be cast to a string or you can read and
95
+ write bytes off of the stream as needed.
96
+
97
+ .. code-block:: php
98
+
99
+ use GuzzleHttp\Stream\Stream;
100
+ $request = $client->createRequest('PUT', 'http://httpbin.org/put', ['body' => 'testing...']);
101
+
102
+ echo $request->getBody()->read(4);
103
+ // test
104
+ echo $request->getBody()->read(4);
105
+ // ing.
106
+ echo $request->getBody()->read(1024);
107
+ // ..
108
+ var_export($request->eof());
109
+ // true
110
+
111
+ You can find out more about Guzzle stream objects in :doc:`streams`.
112
+
113
+ Requests
114
+ ========
115
+
116
+ Requests are sent from a client to a server. Requests include the method to
117
+ be applied to a resource, the identifier of the resource, and the protocol
118
+ version to use.
119
+
120
+ Clients are used to create request messages. More precisely, clients use
121
+ a ``GuzzleHttp\Message\MessageFactoryInterface`` to create request messages.
122
+ You create requests with a client using the ``createRequest()`` method.
123
+
124
+ .. code-block:: php
125
+
126
+ // Create a request but don't send it immediately
127
+ $request = $client->createRequest('GET', 'http://httpbin.org/get');
128
+
129
+ Request Methods
130
+ ---------------
131
+
132
+ When creating a request, you are expected to provide the HTTP method you wish
133
+ to perform. You can specify any method you'd like, including a custom method
134
+ that might not be part of RFC 7231 (like "MOVE").
135
+
136
+ .. code-block:: php
137
+
138
+ // Create a request using a completely custom HTTP method
139
+ $request = $client->createRequest('MOVE', 'http://httpbin.org/move', ['exceptions' => false]);
140
+
141
+ echo $request->getMethod();
142
+ // MOVE
143
+
144
+ $response = $client->send($request);
145
+ echo $response->getStatusCode();
146
+ // 405
147
+
148
+ You can create and send a request using methods on a client that map to the
149
+ HTTP method you wish to use.
150
+
151
+ :GET: ``$client->get('http://httpbin.org/get', [/** options **/])``
152
+ :POST: ``$client->post('http://httpbin.org/post', [/** options **/])``
153
+ :HEAD: ``$client->head('http://httpbin.org/get', [/** options **/])``
154
+ :PUT: ``$client->put('http://httpbin.org/put', [/** options **/])``
155
+ :DELETE: ``$client->delete('http://httpbin.org/delete', [/** options **/])``
156
+ :OPTIONS: ``$client->options('http://httpbin.org/get', [/** options **/])``
157
+ :PATCH: ``$client->patch('http://httpbin.org/put', [/** options **/])``
158
+
159
+ .. code-block:: php
160
+
161
+ $response = $client->patch('http://httpbin.org/patch', ['body' => 'content']);
162
+
163
+ Request URI
164
+ -----------
165
+
166
+ The resource you are requesting with an HTTP request is identified by the
167
+ path of the request, the query string, and the "Host" header of the request.
168
+
169
+ When creating a request, you can provide the entire resource URI as a URL.
170
+
171
+ .. code-block:: php
172
+
173
+ $response = $client->get('http://httbin.org/get?q=foo');
174
+
175
+ Using the above code, you will send a request that uses ``httpbin.org`` as
176
+ the Host header, sends the request over port 80, uses ``/get`` as the path,
177
+ and sends ``?q=foo`` as the query string. All of this is parsed automatically
178
+ from the provided URI.
179
+
180
+ Sometimes you don't know what the entire request will be when it is created.
181
+ In these cases, you can modify the request as needed before sending it using
182
+ the ``createRequest()`` method of the client and methods on the request that
183
+ allow you to change it.
184
+
185
+ .. code-block:: php
186
+
187
+ $request = $client->createRequest('GET', 'http://httbin.org');
188
+
189
+ You can change the path of the request using ``setPath()``:
190
+
191
+ .. code-block:: php
192
+
193
+ $request->setPath('/get');
194
+ echo $request->getPath();
195
+ // /get
196
+ echo $request->getUrl();
197
+ // http://httpbin.com/get
198
+
199
+ Scheme
200
+ ~~~~~~
201
+
202
+ The `scheme <http://tools.ietf.org/html/rfc3986#section-3.1>`_ of a request
203
+ specifies the protocol to use when sending the request. When using Guzzle, the
204
+ scheme can be set to "http" or "https".
205
+
206
+ You can change the scheme of the request using the ``setScheme()`` method:
207
+
208
+ .. code-block:: php
209
+
210
+ $request = $client->createRequest('GET', 'http://httbin.org');
211
+ $request->setScheme('https');
212
+ echo $request->getScheme();
213
+ // https
214
+ echo $request->getUrl();
215
+ // https://httpbin.com/get
216
+
217
+ Port
218
+ ~~~~
219
+
220
+ No port is necessary when using the "http" or "https" schemes, but you can
221
+ override the port using ``setPort()``. If you need to modify the port used with
222
+ the specified scheme from the default setting, then you must use the
223
+ ``setPort()`` method.
224
+
225
+ .. code-block:: php
226
+
227
+ $request = $client->createRequest('GET', 'http://httbin.org');
228
+ $request->setPort(8080);
229
+ echo $request->getPort();
230
+ // 8080
231
+ echo $request->getUrl();
232
+ // https://httpbin.com:8080/get
233
+
234
+ // Set the port back to the default value for the scheme
235
+ $request->setPort(443);
236
+ echo $request->getUrl();
237
+ // https://httpbin.com/get
238
+
239
+ Query string
240
+ ~~~~~~~~~~~~
241
+
242
+ You can get the query string of the request using the ``getQuery()`` method.
243
+ This method returns a ``GuzzleHttp\Query`` object. A Query object can be
244
+ accessed like a PHP array, iterated in a foreach statement like a PHP array,
245
+ and cast to a string.
246
+
247
+ .. code-block:: php
248
+
249
+ $request = $client->createRequest('GET', 'http://httbin.org');
250
+ $query = $request->getQuery();
251
+ $query['foo'] = 'bar';
252
+ $query['baz'] = 'bam';
253
+ $query['bam'] = ['test' => 'abc'];
254
+
255
+ echo $request->getQuery();
256
+ // foo=bar&baz=bam&bam%5Btest%5D=abc
257
+
258
+ echo $request->getQuery()['foo'];
259
+ // bar
260
+ echo $request->getQuery()->get('foo');
261
+ // bar
262
+ echo $request->getQuery()->get('foo');
263
+ // bar
264
+
265
+ var_export($request->getQuery()['bam']);
266
+ // array('test' => 'abc')
267
+
268
+ foreach ($query as $key => $value) {
269
+ var_export($value);
270
+ }
271
+
272
+ echo $request->getUrl();
273
+ // https://httpbin.com/get?foo=bar&baz=bam&bam%5Btest%5D=abc
274
+
275
+ Query Aggregators
276
+ ^^^^^^^^^^^^^^^^^
277
+
278
+ Query objects can store scalar values or arrays of values. When an array of
279
+ values is added to a query object, the query object uses a query aggregator to
280
+ convert the complex structure into a string. Query objects will use
281
+ `PHP style query strings <http://www.php.net/http_build_query>`_ when complex
282
+ query string parameters are converted to a string. You can customize how
283
+ complex query string parameters are aggregated using the ``setAggregator()``
284
+ method of a query string object.
285
+
286
+ .. code-block:: php
287
+
288
+ $query->setAggregator($query::duplicateAggregator());
289
+
290
+ In the above example, we've changed the query object to use the
291
+ "duplicateAggregator". This aggregator will allow duplicate entries to appear
292
+ in a query string rather than appending "[n]" to each value. So if you had a
293
+ query string with ``['a' => ['b', 'c']]``, the duplicate aggregator would
294
+ convert this to "a=b&a=c" while the default aggregator would convert this to
295
+ "a[0]=b&a[1]=c" (with urlencoded brackets).
296
+
297
+ The ``setAggregator()`` method accepts a ``callable`` which is used to convert
298
+ a deeply nested array of query string variables into a flattened array of key
299
+ value pairs. The callable accepts an array of query data and returns a
300
+ flattened array of key value pairs where each value is an array of strings.
301
+ You can use the ``GuzzleHttp\Query::walkQuery()`` static function to easily
302
+ create custom query aggregators.
303
+
304
+ Host
305
+ ~~~~
306
+
307
+ You can change the host header of the request in a predictable way using the
308
+ ``setHost()`` method of a request:
309
+
310
+ .. code-block:: php
311
+
312
+ $request->setHost('www.google.com');
313
+ echo $request->getHost();
314
+ // www.google.com
315
+ echo $request->getUrl();
316
+ // https://www.google.com/get?foo=bar&baz=bam
317
+
318
+ .. note::
319
+
320
+ The Host header can also be changed by modifying the Host header of a
321
+ request directly, but modifying the Host header directly could result in
322
+ sending a request to a different Host than what is specified in the Host
323
+ header (sometimes this is actually the desired behavior).
324
+
325
+ Resource
326
+ ~~~~~~~~
327
+
328
+ You can use the ``getResource()`` method of a request to return the path and
329
+ query string of a request in a single string.
330
+
331
+ .. code-block:: php
332
+
333
+ $request = $client->createRequest('GET', 'http://httpbin.org/get?baz=bar');
334
+ echo $request->getResource();
335
+ // /get?baz=bar
336
+
337
+ Request Config
338
+ --------------
339
+
340
+ Request messages contain a configuration collection that can be used by
341
+ event listeners and HTTP handlers to modify how a request behaves or is
342
+ transferred over the wire. For example, many of the request options that are
343
+ specified when creating a request are actually set as config options that are
344
+ only acted upon by handlers and listeners when the request is sent.
345
+
346
+ You can get access to the request's config object using the ``getConfig()``
347
+ method of a request.
348
+
349
+ .. code-block:: php
350
+
351
+ $request = $client->createRequest('GET', '/');
352
+ $config = $request->getConfig();
353
+
354
+ The config object is a ``GuzzleHttp\Collection`` object that acts like
355
+ an associative array. You can grab values from the collection using array like
356
+ access. You can also modify and remove values using array like access.
357
+
358
+ .. code-block:: php
359
+
360
+ $config['foo'] = 'bar';
361
+ echo $config['foo'];
362
+ // bar
363
+
364
+ var_export(isset($config['foo']));
365
+ // true
366
+
367
+ unset($config['foo']);
368
+ var_export(isset($config['foo']));
369
+ // false
370
+
371
+ var_export($config['foo']);
372
+ // NULL
373
+
374
+ HTTP handlers and event listeners can expose additional customization options
375
+ through request config settings. For example, in order to specify custom cURL
376
+ options to the cURL handler, you need to specify an associative array in the
377
+ ``curl`` ``config`` request option.
378
+
379
+ .. code-block:: php
380
+
381
+ $client->get('/', [
382
+ 'config' => [
383
+ 'curl' => [
384
+ CURLOPT_HTTPAUTH => CURLAUTH_NTLM,
385
+ CURLOPT_USERPWD => 'username:password'
386
+ ]
387
+ ]
388
+ ]);
389
+
390
+ Consult the HTTP handlers and event listeners you are using to see if they
391
+ allow customization through request configuration options.
392
+
393
+ Event Emitter
394
+ -------------
395
+
396
+ Request objects implement ``GuzzleHttp\Event\HasEmitterInterface``, so they
397
+ have a method called ``getEmitter()`` that can be used to get an event emitter
398
+ used by the request. Any listener or subscriber attached to a request will only
399
+ be triggered for the lifecycle events of a specific request. Conversely, adding
400
+ an event listener or subscriber to a client will listen to all lifecycle events
401
+ of all requests created by the client.
402
+
403
+ See :doc:`events` for more information.
404
+
405
+ Responses
406
+ =========
407
+
408
+ Responses are the HTTP messages a client receives from a server after sending
409
+ an HTTP request message.
410
+
411
+ Start-Line
412
+ ----------
413
+
414
+ The start-line of a response contains the protocol and protocol version,
415
+ status code, and reason phrase.
416
+
417
+ .. code-block:: php
418
+
419
+ $response = GuzzleHttp\get('http://httpbin.org/get');
420
+ echo $response->getStatusCode();
421
+ // 200
422
+ echo $response->getReasonPhrase();
423
+ // OK
424
+ echo $response->getProtocolVersion();
425
+ // 1.1
426
+
427
+ Body
428
+ ----
429
+
430
+ As described earlier, you can get the body of a response using the
431
+ ``getBody()`` method.
432
+
433
+ .. code-block:: php
434
+
435
+ if ($body = $response->getBody()) {
436
+ echo $body;
437
+ // Cast to a string: { ... }
438
+ $body->seek(0);
439
+ // Rewind the body
440
+ $body->read(1024);
441
+ // Read bytes of the body
442
+ }
443
+
444
+ When working with JSON responses, you can use the ``json()`` method of a
445
+ response:
446
+
447
+ .. code-block:: php
448
+
449
+ $json = $response->json();
450
+
451
+ .. note::
452
+
453
+ Guzzle uses the ``json_decode()`` method of PHP and uses arrays rather than
454
+ ``stdClass`` objects for objects.
455
+
456
+ You can use the ``xml()`` method when working with XML data.
457
+
458
+ .. code-block:: php
459
+
460
+ $xml = $response->xml();
461
+
462
+ .. note::
463
+
464
+ Guzzle uses the ``SimpleXMLElement`` objects when converting response
465
+ bodies to XML.
466
+
467
+ Effective URL
468
+ -------------
469
+
470
+ The URL that was ultimately accessed that returned a response can be accessed
471
+ using the ``getEffectiveUrl()`` method of a response. This method will return
472
+ the URL of a request or the URL of the last redirected URL if any redirects
473
+ occurred while transferring a request.
474
+
475
+ .. code-block:: php
476
+
477
+ $response = GuzzleHttp\get('http://httpbin.org/get');
478
+ echo $response->getEffectiveUrl();
479
+ // http://httpbin.org/get
480
+
481
+ $response = GuzzleHttp\get('http://httpbin.org/redirect-to?url=http://www.google.com');
482
+ echo $response->getEffectiveUrl();
483
+ // http://www.google.com
backend/vendor/guzzlehttp/guzzle/docs/index.rst ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .. title:: Guzzle | PHP HTTP client and framework for consuming RESTful web services
2
+
3
+ ======
4
+ Guzzle
5
+ ======
6
+
7
+ Guzzle is a PHP HTTP client that makes it easy to send HTTP requests and
8
+ trivial to integrate with web services.
9
+
10
+ - Manages things like persistent connections, represents query strings as
11
+ collections, simplifies sending streaming POST requests with fields and
12
+ files, and abstracts away the underlying HTTP transport layer.
13
+ - Can send both synchronous and asynchronous requests using the same interface
14
+ without requiring a dependency on a specific event loop.
15
+ - Pluggable HTTP handlers allows Guzzle to integrate with any method you choose
16
+ for sending HTTP requests over the wire (e.g., cURL, sockets, PHP's stream
17
+ wrapper, non-blocking event loops like `React <http://reactphp.org/>`_, etc.).
18
+ - Guzzle makes it so that you no longer need to fool around with cURL options,
19
+ stream contexts, or sockets.
20
+
21
+ .. code-block:: php
22
+
23
+ $client = new GuzzleHttp\Client();
24
+ $response = $client->get('http://guzzlephp.org');
25
+ $res = $client->get('https://api.github.com/user', ['auth' => ['user', 'pass']]);
26
+ echo $res->getStatusCode();
27
+ // "200"
28
+ echo $res->getHeader('content-type');
29
+ // 'application/json; charset=utf8'
30
+ echo $res->getBody();
31
+ // {"type":"User"...'
32
+ var_export($res->json());
33
+ // Outputs the JSON decoded data
34
+
35
+ // Send an asynchronous request.
36
+ $req = $client->createRequest('GET', 'http://httpbin.org', ['future' => true]);
37
+ $client->send($req)->then(function ($response) {
38
+ echo 'I completed! ' . $response;
39
+ });
40
+
41
+ User guide
42
+ ----------
43
+
44
+ .. toctree::
45
+ :maxdepth: 2
46
+
47
+ overview
48
+ quickstart
49
+ clients
50
+ http-messages
51
+ events
52
+ streams
53
+ handlers
54
+ testing
55
+ faq
56
+
57
+ HTTP Components
58
+ ---------------
59
+
60
+ There are a number of optional libraries you can use along with Guzzle's HTTP
61
+ layer to add capabilities to the client.
62
+
63
+ `Log Subscriber <https://github.com/guzzle/log-subscriber>`_
64
+ Logs HTTP requests and responses sent over the wire using customizable
65
+ log message templates.
66
+
67
+ `OAuth Subscriber <https://github.com/guzzle/oauth-subscriber>`_
68
+ Signs requests using OAuth 1.0.
69
+
70
+ `Cache Subscriber <https://github.com/guzzle/cache-subscriber>`_
71
+ Implements a private transparent proxy cache that caches HTTP responses.
72
+
73
+ `Retry Subscriber <https://github.com/guzzle/retry-subscriber>`_
74
+ Retries failed requests using customizable retry strategies (e.g., retry
75
+ based on response status code, cURL error codes, etc.)
76
+
77
+ `Message Integrity Subscriber <https://github.com/guzzle/message-integrity-subscriber>`_
78
+ Verifies the message integrity of HTTP responses using customizable
79
+ validators. This plugin can be used, for example, to verify the Content-MD5
80
+ headers of responses.
81
+
82
+ Service Description Commands
83
+ ----------------------------
84
+
85
+ You can use the **Guzzle Command** library to encapsulate interaction with a
86
+ web service using command objects. Building on top of Guzzle's command
87
+ abstraction allows you to easily implement things like service description that
88
+ can be used to serialize requests and parse responses using a meta-description
89
+ of a web service.
90
+
91
+ `Guzzle Command <https://github.com/guzzle/command>`_
92
+ Provides the foundational elements used to build high-level, command based,
93
+ web service clients with Guzzle.
94
+
95
+ `Guzzle Services <https://github.com/guzzle/guzzle-services>`_
96
+ Provides an implementation of the *Guzzle Command* library that uses
97
+ Guzzle service descriptions to describe web services, serialize requests,
98
+ and parse responses into easy to use model structures.
backend/vendor/guzzlehttp/guzzle/docs/overview.rst ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ========
2
+ Overview
3
+ ========
4
+
5
+ Requirements
6
+ ============
7
+
8
+ #. PHP 5.4.0
9
+ #. To use the PHP stream handler, ``allow_url_fopen`` must be enabled in your
10
+ system's php.ini.
11
+ #. To use the cURL handler, you must have a recent version of cURL >= 7.16.2
12
+ compiled with OpenSSL and zlib.
13
+
14
+ .. note::
15
+
16
+ Guzzle no longer requires cURL in order to send HTTP requests. Guzzle will
17
+ use the PHP stream wrapper to send HTTP requests if cURL is not installed.
18
+ Alternatively, you can provide your own HTTP handler used to send requests.
19
+
20
+ .. _installation:
21
+
22
+ Installation
23
+ ============
24
+
25
+ The recommended way to install Guzzle is with `Composer <http://getcomposer.org>`_. Composer is a dependency
26
+ management tool for PHP that allows you to declare the dependencies your project needs and installs them into your
27
+ project.
28
+
29
+ .. code-block:: bash
30
+
31
+ # Install Composer
32
+ curl -sS https://getcomposer.org/installer | php
33
+
34
+ You can add Guzzle as a dependency using the composer.phar CLI:
35
+
36
+ .. code-block:: bash
37
+
38
+ php composer.phar require guzzlehttp/guzzle:~5.0
39
+
40
+ Alternatively, you can specify Guzzle as a dependency in your project's
41
+ existing composer.json file:
42
+
43
+ .. code-block:: js
44
+
45
+ {
46
+ "require": {
47
+ "guzzlehttp/guzzle": "~5.0"
48
+ }
49
+ }
50
+
51
+ After installing, you need to require Composer's autoloader:
52
+
53
+ .. code-block:: php
54
+
55
+ require 'vendor/autoload.php';
56
+
57
+ You can find out more on how to install Composer, configure autoloading, and
58
+ other best-practices for defining dependencies at `getcomposer.org <http://getcomposer.org>`_.
59
+
60
+ Bleeding edge
61
+ -------------
62
+
63
+ During your development, you can keep up with the latest changes on the master
64
+ branch by setting the version requirement for Guzzle to ``~5.0@dev``.
65
+
66
+ .. code-block:: js
67
+
68
+ {
69
+ "require": {
70
+ "guzzlehttp/guzzle": "~5.0@dev"
71
+ }
72
+ }
73
+
74
+ License
75
+ =======
76
+
77
+ Licensed using the `MIT license <http://opensource.org/licenses/MIT>`_.
78
+
79
+ Copyright (c) 2014 Michael Dowling <https://github.com/mtdowling>
80
+
81
+ Permission is hereby granted, free of charge, to any person obtaining a copy
82
+ of this software and associated documentation files (the "Software"), to deal
83
+ in the Software without restriction, including without limitation the rights
84
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
85
+ copies of the Software, and to permit persons to whom the Software is
86
+ furnished to do so, subject to the following conditions:
87
+
88
+ The above copyright notice and this permission notice shall be included in
89
+ all copies or substantial portions of the Software.
90
+
91
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
92
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
93
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
94
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
95
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
96
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
97
+ THE SOFTWARE.
98
+
99
+ Contributing
100
+ ============
101
+
102
+ Guidelines
103
+ ----------
104
+
105
+ 1. Guzzle follows PSR-0, PSR-1, and PSR-2.
106
+ 2. Guzzle is meant to be lean and fast with very few dependencies.
107
+ 3. Guzzle has a minimum PHP version requirement of PHP 5.4. Pull requests must
108
+ not require a PHP version greater than PHP 5.4.
109
+ 4. All pull requests must include unit tests to ensure the change works as
110
+ expected and to prevent regressions.
111
+
112
+ Running the tests
113
+ -----------------
114
+
115
+ In order to contribute, you'll need to checkout the source from GitHub and
116
+ install Guzzle's dependencies using Composer:
117
+
118
+ .. code-block:: bash
119
+
120
+ git clone https://github.com/guzzle/guzzle.git
121
+ cd guzzle && curl -s http://getcomposer.org/installer | php && ./composer.phar install --dev
122
+
123
+ Guzzle is unit tested with PHPUnit. Run the tests using the vendored PHPUnit
124
+ binary:
125
+
126
+ .. code-block:: bash
127
+
128
+ vendor/bin/phpunit
129
+
130
+ .. note::
131
+
132
+ You'll need to install node.js v0.5.0 or newer in order to perform
133
+ integration tests on Guzzle's HTTP handlers.
134
+
135
+ Reporting a security vulnerability
136
+ ==================================
137
+
138
+ We want to ensure that Guzzle is a secure HTTP client library for everyone. If
139
+ you've discovered a security vulnerability in Guzzle, we appreciate your help
140
+ in disclosing it to us in a `responsible manner <http://en.wikipedia.org/wiki/Responsible_disclosure>`_.
141
+
142
+ Publicly disclosing a vulnerability can put the entire community at risk. If
143
+ you've discovered a security concern, please email us at
144
+ security@guzzlephp.org. We'll work with you to make sure that we understand the
145
+ scope of the issue, and that we fully address your concern. We consider
146
+ correspondence sent to security@guzzlephp.org our highest priority, and work to
147
+ address any issues that arise as quickly as possible.
148
+
149
+ After a security vulnerability has been corrected, a security hotfix release will
150
+ be deployed as soon as possible.
backend/vendor/guzzlehttp/guzzle/docs/quickstart.rst ADDED
@@ -0,0 +1,448 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ==========
2
+ Quickstart
3
+ ==========
4
+
5
+ This page provides a quick introduction to Guzzle and introductory examples.
6
+ If you have not already installed, Guzzle, head over to the :ref:`installation`
7
+ page.
8
+
9
+ Make a Request
10
+ ==============
11
+
12
+ You can send requests with Guzzle using a ``GuzzleHttp\ClientInterface``
13
+ object.
14
+
15
+ Creating a Client
16
+ -----------------
17
+
18
+ The procedural API is simple but not very testable; it's best left for quick
19
+ prototyping. If you want to use Guzzle in a more flexible and testable way,
20
+ then you'll need to use a ``GuzzleHttp\ClientInterface`` object.
21
+
22
+ .. code-block:: php
23
+
24
+ use GuzzleHttp\Client;
25
+
26
+ $client = new Client();
27
+ $response = $client->get('http://httpbin.org/get');
28
+
29
+ // You can use the same methods you saw in the procedural API
30
+ $response = $client->delete('http://httpbin.org/delete');
31
+ $response = $client->head('http://httpbin.org/get');
32
+ $response = $client->options('http://httpbin.org/get');
33
+ $response = $client->patch('http://httpbin.org/patch');
34
+ $response = $client->post('http://httpbin.org/post');
35
+ $response = $client->put('http://httpbin.org/put');
36
+
37
+ You can create a request with a client and then send the request with the
38
+ client when you're ready.
39
+
40
+ .. code-block:: php
41
+
42
+ $request = $client->createRequest('GET', 'http://www.foo.com');
43
+ $response = $client->send($request);
44
+
45
+ Client objects provide a great deal of flexibility in how request are
46
+ transferred including default request options, subscribers that are attached
47
+ to each request, and a base URL that allows you to send requests with relative
48
+ URLs. You can find out all about clients in the :doc:`clients` page of the
49
+ documentation.
50
+
51
+ Using Responses
52
+ ===============
53
+
54
+ In the previous examples, we retrieved a ``$response`` variable. This value is
55
+ actually a ``GuzzleHttp\Message\ResponseInterface`` object and contains lots
56
+ of helpful information.
57
+
58
+ You can get the status code and reason phrase of the response.
59
+
60
+ .. code-block:: php
61
+
62
+ $code = $response->getStatusCode();
63
+ // 200
64
+
65
+ $reason = $response->getReasonPhrase();
66
+ // OK
67
+
68
+ By providing the ``future`` request option to a request, you can send requests
69
+ asynchronously using the promise interface of a future response.
70
+
71
+ .. code-block:: php
72
+
73
+ $client->get('http://httpbin.org', ['future' => true])
74
+ ->then(function ($response) {
75
+ echo $response->getStatusCode();
76
+ });
77
+
78
+ Response Body
79
+ -------------
80
+
81
+ The body of a response can be retrieved and cast to a string.
82
+
83
+ .. code-block:: php
84
+
85
+ $body = $response->getBody();
86
+ echo $body;
87
+ // { "some_json_data" ...}
88
+
89
+ You can also read read bytes from body of a response like a stream.
90
+
91
+ .. code-block:: php
92
+
93
+ $body = $response->getBody();
94
+
95
+ while (!$body->eof()) {
96
+ echo $body->read(1024);
97
+ }
98
+
99
+ JSON Responses
100
+ ~~~~~~~~~~~~~~
101
+
102
+ You can more easily work with JSON responses using the ``json()`` method of a
103
+ response.
104
+
105
+ .. code-block:: php
106
+
107
+ $response = $client->get('http://httpbin.org/get');
108
+ $json = $response->json();
109
+ var_dump($json[0]['origin']);
110
+
111
+ Guzzle internally uses PHP's ``json_decode()`` function to parse responses. If
112
+ Guzzle is unable to parse the JSON response body, then a
113
+ ``GuzzleHttp\Exception\ParseException`` is thrown.
114
+
115
+ XML Responses
116
+ ~~~~~~~~~~~~~
117
+
118
+ You can use a response's ``xml()`` method to more easily work with responses
119
+ that contain XML data.
120
+
121
+ .. code-block:: php
122
+
123
+ $response = $client->get('https://github.com/mtdowling.atom');
124
+ $xml = $response->xml();
125
+ echo $xml->id;
126
+ // tag:github.com,2008:/mtdowling
127
+
128
+ Guzzle internally uses a ``SimpleXMLElement`` object to parse responses. If
129
+ Guzzle is unable to parse the XML response body, then a
130
+ ``GuzzleHttp\Exception\ParseException`` is thrown.
131
+
132
+ Query String Parameters
133
+ =======================
134
+
135
+ Sending query string parameters with a request is easy. You can set query
136
+ string parameters in the request's URL.
137
+
138
+ .. code-block:: php
139
+
140
+ $response = $client->get('http://httpbin.org?foo=bar');
141
+
142
+ You can also specify the query string parameters using the ``query`` request
143
+ option.
144
+
145
+ .. code-block:: php
146
+
147
+ $client->get('http://httpbin.org', [
148
+ 'query' => ['foo' => 'bar']
149
+ ]);
150
+
151
+ And finally, you can build up the query string of a request as needed by
152
+ calling the ``getQuery()`` method of a request and modifying the request's
153
+ ``GuzzleHttp\Query`` object as needed.
154
+
155
+ .. code-block:: php
156
+
157
+ $request = $client->createRequest('GET', 'http://httpbin.org');
158
+ $query = $request->getQuery();
159
+ $query->set('foo', 'bar');
160
+
161
+ // You can use the query string object like an array
162
+ $query['baz'] = 'bam';
163
+
164
+ // The query object can be cast to a string
165
+ echo $query;
166
+ // foo=bar&baz=bam
167
+
168
+ // Setting a value to false or null will cause the "=" sign to be omitted
169
+ $query['empty'] = null;
170
+ echo $query;
171
+ // foo=bar&baz=bam&empty
172
+
173
+ // Use an empty string to include the "=" sign with an empty value
174
+ $query['empty'] = '';
175
+ echo $query;
176
+ // foo=bar&baz=bam&empty=
177
+
178
+ .. _headers:
179
+
180
+ Request and Response Headers
181
+ ----------------------------
182
+
183
+ You can specify request headers when sending or creating requests with a
184
+ client. In the following example, we send the ``X-Foo-Header`` with a value of
185
+ ``value`` by setting the ``headers`` request option.
186
+
187
+ .. code-block:: php
188
+
189
+ $response = $client->get('http://httpbin.org/get', [
190
+ 'headers' => ['X-Foo-Header' => 'value']
191
+ ]);
192
+
193
+ You can view the headers of a response using header specific methods of a
194
+ response class. Headers work exactly the same way for request and response
195
+ object.
196
+
197
+ You can retrieve a header from a request or response using the ``getHeader()``
198
+ method of the object. This method is case-insensitive and by default will
199
+ return a string containing the header field value.
200
+
201
+ .. code-block:: php
202
+
203
+ $response = $client->get('http://www.yahoo.com');
204
+ $length = $response->getHeader('Content-Length');
205
+
206
+ Header fields that contain multiple values can be retrieved as a string or as
207
+ an array. Retrieving the field values as a string will naively concatenate all
208
+ of the header values together with a comma. Because not all header fields
209
+ should be represented this way (e.g., ``Set-Cookie``), you can pass an optional
210
+ flag to the ``getHeader()`` method to retrieve the header values as an array.
211
+
212
+ .. code-block:: php
213
+
214
+ $values = $response->getHeader('Set-Cookie', true);
215
+ foreach ($values as $value) {
216
+ echo $value;
217
+ }
218
+
219
+ You can test if a request or response has a specific header using the
220
+ ``hasHeader()`` method. This method accepts a case-insensitive string and
221
+ returns true if the header is present or false if it is not.
222
+
223
+ You can retrieve all of the headers of a message using the ``getHeaders()``
224
+ method of a request or response. The return value is an associative array where
225
+ the keys represent the header name as it will be sent over the wire, and each
226
+ value is an array of strings associated with the header.
227
+
228
+ .. code-block:: php
229
+
230
+ $headers = $response->getHeaders();
231
+ foreach ($message->getHeaders() as $name => $values) {
232
+ echo $name . ": " . implode(", ", $values);
233
+ }
234
+
235
+ Modifying headers
236
+ -----------------
237
+
238
+ The headers of a message can be modified using the ``setHeader()``,
239
+ ``addHeader()``, ``setHeaders()``, and ``removeHeader()`` methods of a request
240
+ or response object.
241
+
242
+ .. code-block:: php
243
+
244
+ $request = $client->createRequest('GET', 'http://httpbin.org/get');
245
+
246
+ // Set a single value for a header
247
+ $request->setHeader('User-Agent', 'Testing!');
248
+
249
+ // Set multiple values for a header in one call
250
+ $request->setHeader('X-Foo', ['Baz', 'Bar']);
251
+
252
+ // Add a header to the message
253
+ $request->addHeader('X-Foo', 'Bam');
254
+
255
+ echo $request->getHeader('X-Foo');
256
+ // Baz, Bar, Bam
257
+
258
+ // Remove a specific header using a case-insensitive name
259
+ $request->removeHeader('x-foo');
260
+ echo $request->getHeader('X-Foo');
261
+ // Echoes an empty string: ''
262
+
263
+ Uploading Data
264
+ ==============
265
+
266
+ Guzzle provides several methods of uploading data.
267
+
268
+ You can send requests that contain a stream of data by passing a string,
269
+ resource returned from ``fopen``, or a ``GuzzleHttp\Stream\StreamInterface``
270
+ object to the ``body`` request option.
271
+
272
+ .. code-block:: php
273
+
274
+ $r = $client->post('http://httpbin.org/post', ['body' => 'raw data']);
275
+
276
+ You can easily upload JSON data using the ``json`` request option.
277
+
278
+ .. code-block:: php
279
+
280
+ $r = $client->put('http://httpbin.org/put', ['json' => ['foo' => 'bar']]);
281
+
282
+ POST Requests
283
+ -------------
284
+
285
+ In addition to specifying the raw data of a request using the ``body`` request
286
+ option, Guzzle provides helpful abstractions over sending POST data.
287
+
288
+ Sending POST Fields
289
+ ~~~~~~~~~~~~~~~~~~~
290
+
291
+ Sending ``application/x-www-form-urlencoded`` POST requests requires that you
292
+ specify the body of a POST request as an array.
293
+
294
+ .. code-block:: php
295
+
296
+ $response = $client->post('http://httpbin.org/post', [
297
+ 'body' => [
298
+ 'field_name' => 'abc',
299
+ 'other_field' => '123'
300
+ ]
301
+ ]);
302
+
303
+ You can also build up POST requests before sending them.
304
+
305
+ .. code-block:: php
306
+
307
+ $request = $client->createRequest('POST', 'http://httpbin.org/post');
308
+ $postBody = $request->getBody();
309
+
310
+ // $postBody is an instance of GuzzleHttp\Post\PostBodyInterface
311
+ $postBody->setField('foo', 'bar');
312
+ echo $postBody->getField('foo');
313
+ // 'bar'
314
+
315
+ echo json_encode($postBody->getFields());
316
+ // {"foo": "bar"}
317
+
318
+ // Send the POST request
319
+ $response = $client->send($request);
320
+
321
+ Sending POST Files
322
+ ~~~~~~~~~~~~~~~~~~
323
+
324
+ Sending ``multipart/form-data`` POST requests (POST requests that contain
325
+ files) is the same as sending ``application/x-www-form-urlencoded``, except
326
+ some of the array values of the POST fields map to PHP ``fopen`` resources, or
327
+ ``GuzzleHttp\Stream\StreamInterface``, or
328
+ ``GuzzleHttp\Post\PostFileInterface`` objects.
329
+
330
+ .. code-block:: php
331
+
332
+ use GuzzleHttp\Post\PostFile;
333
+
334
+ $response = $client->post('http://httpbin.org/post', [
335
+ 'body' => [
336
+ 'field_name' => 'abc',
337
+ 'file_filed' => fopen('/path/to/file', 'r'),
338
+ 'other_file' => new PostFile('other_file', 'this is the content')
339
+ ]
340
+ ]);
341
+
342
+ Just like when sending POST fields, you can also build up POST requests with
343
+ files before sending them.
344
+
345
+ .. code-block:: php
346
+
347
+ use GuzzleHttp\Post\PostFile;
348
+
349
+ $request = $client->createRequest('POST', 'http://httpbin.org/post');
350
+ $postBody = $request->getBody();
351
+ $postBody->setField('foo', 'bar');
352
+ $postBody->addFile(new PostFile('test', fopen('/path/to/file', 'r')));
353
+ $response = $client->send($request);
354
+
355
+ Cookies
356
+ =======
357
+
358
+ Guzzle can maintain a cookie session for you if instructed using the
359
+ ``cookies`` request option.
360
+
361
+ - Set to ``true`` to use a shared cookie session associated with the client.
362
+ - Pass an associative array containing cookies to send in the request and start
363
+ a new cookie session.
364
+ - Set to a ``GuzzleHttp\Subscriber\CookieJar\CookieJarInterface`` object to use
365
+ an existing cookie jar.
366
+
367
+ Redirects
368
+ =========
369
+
370
+ Guzzle will automatically follow redirects unless you tell it not to. You can
371
+ customize the redirect behavior using the ``allow_redirects`` request option.
372
+
373
+ - Set to true to enable normal redirects with a maximum number of 5 redirects.
374
+ This is the default setting.
375
+ - Set to false to disable redirects.
376
+ - Pass an associative array containing the 'max' key to specify the maximum
377
+ number of redirects and optionally provide a 'strict' key value to specify
378
+ whether or not to use strict RFC compliant redirects (meaning redirect POST
379
+ requests with POST requests vs. doing what most browsers do which is
380
+ redirect POST requests with GET requests).
381
+
382
+ .. code-block:: php
383
+
384
+ $response = $client->get('http://github.com');
385
+ echo $response->getStatusCode();
386
+ // 200
387
+ echo $response->getEffectiveUrl();
388
+ // 'https://github.com/'
389
+
390
+ The following example shows that redirects can be disabled.
391
+
392
+ .. code-block:: php
393
+
394
+ $response = $client->get('http://github.com', ['allow_redirects' => false]);
395
+ echo $response->getStatusCode();
396
+ // 301
397
+ echo $response->getEffectiveUrl();
398
+ // 'http://github.com/'
399
+
400
+ Exceptions
401
+ ==========
402
+
403
+ Guzzle throws exceptions for errors that occur during a transfer.
404
+
405
+ - In the event of a networking error (connection timeout, DNS errors, etc.),
406
+ a ``GuzzleHttp\Exception\RequestException`` is thrown. This exception
407
+ extends from ``GuzzleHttp\Exception\TransferException``. Catching this
408
+ exception will catch any exception that can be thrown while transferring
409
+ (non-parallel) requests.
410
+
411
+ .. code-block:: php
412
+
413
+ use GuzzleHttp\Exception\RequestException;
414
+
415
+ try {
416
+ $client->get('https://github.com/_abc_123_404');
417
+ } catch (RequestException $e) {
418
+ echo $e->getRequest();
419
+ if ($e->hasResponse()) {
420
+ echo $e->getResponse();
421
+ }
422
+ }
423
+
424
+ - A ``GuzzleHttp\Exception\ClientException`` is thrown for 400
425
+ level errors if the ``exceptions`` request option is set to true. This
426
+ exception extends from ``GuzzleHttp\Exception\BadResponseException`` and
427
+ ``GuzzleHttp\Exception\BadResponseException`` extends from
428
+ ``GuzzleHttp\Exception\RequestException``.
429
+
430
+ .. code-block:: php
431
+
432
+ use GuzzleHttp\Exception\ClientException;
433
+
434
+ try {
435
+ $client->get('https://github.com/_abc_123_404');
436
+ } catch (ClientException $e) {
437
+ echo $e->getRequest();
438
+ echo $e->getResponse();
439
+ }
440
+
441
+ - A ``GuzzleHttp\Exception\ServerException`` is thrown for 500 level
442
+ errors if the ``exceptions`` request option is set to true. This
443
+ exception extends from ``GuzzleHttp\Exception\BadResponseException``.
444
+ - A ``GuzzleHttp\Exception\TooManyRedirectsException`` is thrown when too
445
+ many redirects are followed. This exception extends from ``GuzzleHttp\Exception\RequestException``.
446
+
447
+ All of the above exceptions extend from
448
+ ``GuzzleHttp\Exception\TransferException``.
backend/vendor/guzzlehttp/guzzle/docs/requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
1
+ Sphinx>=1.2b1
2
+ guzzle_sphinx_theme>=0.6.0
backend/vendor/guzzlehttp/guzzle/docs/streams.rst ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ =======
2
+ Streams
3
+ =======
4
+
5
+ Guzzle uses stream objects to represent request and response message bodies.
6
+ These stream objects allow you to work with various types of data all using a
7
+ common interface.
8
+
9
+ HTTP messages consist of a start-line, headers, and a body. The body of an HTTP
10
+ message can be very small or extremely large. Attempting to represent the body
11
+ of a message as a string can easily consume more memory than intended because
12
+ the body must be stored completely in memory. Attempting to store the body of a
13
+ request or response in memory would preclude the use of that implementation from
14
+ being able to work with large message bodies. The StreamInterface is used in
15
+ order to hide the implementation details of where a stream of data is read from
16
+ or written to.
17
+
18
+ Guzzle's StreamInterface exposes several methods that enable streams to be read
19
+ from, written to, and traversed effectively.
20
+
21
+ Streams expose their capabilities using three methods: ``isReadable()``,
22
+ ``isWritable()``, and ``isSeekable()``. These methods can be used by stream
23
+ collaborators to determine if a stream is capable of their requirements.
24
+
25
+ Each stream instance has various capabilities: they can be read-only,
26
+ write-only, read-write, allow arbitrary random access (seeking forwards or
27
+ backwards to any location), or only allow sequential access (for example in the
28
+ case of a socket or pipe).
29
+
30
+ Creating Streams
31
+ ================
32
+
33
+ The best way to create a stream is using the static factory method,
34
+ ``GuzzleHttp\Stream\Stream::factory()``. This factory accepts strings,
35
+ resources returned from ``fopen()``, an object that implements
36
+ ``__toString()``, and an object that implements
37
+ ``GuzzleHttp\Stream\StreamInterface``.
38
+
39
+ .. code-block:: php
40
+
41
+ use GuzzleHttp\Stream\Stream;
42
+
43
+ $stream = Stream::factory('string data');
44
+ echo $stream;
45
+ // string data
46
+ echo $stream->read(3);
47
+ // str
48
+ echo $stream->getContents();
49
+ // ing data
50
+ var_export($stream->eof());
51
+ // true
52
+ var_export($stream->tell());
53
+ // 11
54
+
55
+ Metadata
56
+ ========
57
+
58
+ Guzzle streams expose stream metadata through the ``getMetadata()`` method.
59
+ This method provides the data you would retrieve when calling PHP's
60
+ `stream_get_meta_data() function <http://php.net/manual/en/function.stream-get-meta-data.php>`_,
61
+ and can optionally expose other custom data.
62
+
63
+ .. code-block:: php
64
+
65
+ use GuzzleHttp\Stream\Stream;
66
+
67
+ $resource = fopen('/path/to/file', 'r');
68
+ $stream = Stream::factory($resource);
69
+ echo $stream->getMetadata('uri');
70
+ // /path/to/file
71
+ var_export($stream->isReadable());
72
+ // true
73
+ var_export($stream->isWritable());
74
+ // false
75
+ var_export($stream->isSeekable());
76
+ // true
77
+
78
+ Stream Decorators
79
+ =================
80
+
81
+ With the small and focused interface, add custom functionality to streams is
82
+ very simple with stream decorators. Guzzle provides several built-in decorators
83
+ that provide additional stream functionality.
84
+
85
+ CachingStream
86
+ -------------
87
+
88
+ The CachingStream is used to allow seeking over previously read bytes on
89
+ non-seekable streams. This can be useful when transferring a non-seekable
90
+ entity body fails due to needing to rewind the stream (for example, resulting
91
+ from a redirect). Data that is read from the remote stream will be buffered in
92
+ a PHP temp stream so that previously read bytes are cached first in memory,
93
+ then on disk.
94
+
95
+ .. code-block:: php
96
+
97
+ use GuzzleHttp\Stream\Stream;
98
+ use GuzzleHttp\Stream\CachingStream;
99
+
100
+ $original = Stream::factory(fopen('http://www.google.com', 'r'));
101
+ $stream = new CachingStream($original);
102
+
103
+ $stream->read(1024);
104
+ echo $stream->tell();
105
+ // 1024
106
+
107
+ $stream->seek(0);
108
+ echo $stream->tell();
109
+ // 0
110
+
111
+ LimitStream
112
+ -----------
113
+
114
+ LimitStream can be used to read a subset or slice of an existing stream object.
115
+ This can be useful for breaking a large file into smaller pieces to be sent in
116
+ chunks (e.g. Amazon S3's multipart upload API).
117
+
118
+ .. code-block:: php
119
+
120
+ use GuzzleHttp\Stream\Stream;
121
+ use GuzzleHttp\Stream\LimitStream;
122
+
123
+ $original = Stream::factory(fopen('/tmp/test.txt', 'r+'));
124
+ echo $original->getSize();
125
+ // >>> 1048576
126
+
127
+ // Limit the size of the body to 1024 bytes and start reading from byte 2048
128
+ $stream = new LimitStream($original, 1024, 2048);
129
+ echo $stream->getSize();
130
+ // >>> 1024
131
+ echo $stream->tell();
132
+ // >>> 0
133
+
134
+ NoSeekStream
135
+ ------------
136
+
137
+ NoSeekStream wraps a stream and does not allow seeking.
138
+
139
+ .. code-block:: php
140
+
141
+ use GuzzleHttp\Stream\Stream;
142
+ use GuzzleHttp\Stream\LimitStream;
143
+
144
+ $original = Stream::factory('foo');
145
+ $noSeek = new NoSeekStream($original);
146
+
147
+ echo $noSeek->read(3);
148
+ // foo
149
+ var_export($noSeek->isSeekable());
150
+ // false
151
+ $noSeek->seek(0);
152
+ var_export($noSeek->read(3));
153
+ // NULL
154
+
155
+ Creating Custom Decorators
156
+ --------------------------
157
+
158
+ Creating a stream decorator is very easy thanks to the
159
+ ``GuzzleHttp\Stream\StreamDecoratorTrait``. This trait provides methods that
160
+ implement ``GuzzleHttp\Stream\StreamInterface`` by proxying to an underlying
161
+ stream. Just ``use`` the ``StreamDecoratorTrait`` and implement your custom
162
+ methods.
163
+
164
+ For example, let's say we wanted to call a specific function each time the last
165
+ byte is read from a stream. This could be implemented by overriding the
166
+ ``read()`` method.
167
+
168
+ .. code-block:: php
169
+
170
+ use GuzzleHttp\Stream\StreamDecoratorTrait;
171
+
172
+ class EofCallbackStream implements StreamInterface
173
+ {
174
+ use StreamDecoratorTrait;
175
+
176
+ private $callback;
177
+
178
+ public function __construct(StreamInterface $stream, callable $callback)
179
+ {
180
+ $this->stream = $stream;
181
+ $this->callback = $callback;
182
+ }
183
+
184
+ public function read($length)
185
+ {
186
+ $result = $this->stream->read($length);
187
+
188
+ // Invoke the callback when EOF is hit.
189
+ if ($this->eof()) {
190
+ call_user_func($this->callback);
191
+ }
192
+
193
+ return $result;
194
+ }
195
+ }
196
+
197
+ This decorator could be added to any existing stream and used like so:
198
+
199
+ .. code-block:: php
200
+
201
+ use GuzzleHttp\Stream\Stream;
202
+
203
+ $original = Stream::factory('foo');
204
+ $eofStream = new EofCallbackStream($original, function () {
205
+ echo 'EOF!';
206
+ });
207
+
208
+ $eofStream->read(2);
209
+ $eofStream->read(1);
210
+ // echoes "EOF!"
211
+ $eofStream->seek(0);
212
+ $eofStream->read(3);
213
+ // echoes "EOF!"
backend/vendor/guzzlehttp/guzzle/docs/testing.rst ADDED
@@ -0,0 +1,232 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ======================
2
+ Testing Guzzle Clients
3
+ ======================
4
+
5
+ Guzzle provides several tools that will enable you to easily mock the HTTP
6
+ layer without needing to send requests over the internet.
7
+
8
+ * Mock subscriber
9
+ * Mock handler
10
+ * Node.js web server for integration testing
11
+
12
+ Mock Subscriber
13
+ ===============
14
+
15
+ When testing HTTP clients, you often need to simulate specific scenarios like
16
+ returning a successful response, returning an error, or returning specific
17
+ responses in a certain order. Because unit tests need to be predictable, easy
18
+ to bootstrap, and fast, hitting an actual remote API is a test smell.
19
+
20
+ Guzzle provides a mock subscriber that can be attached to clients or requests
21
+ that allows you to queue up a list of responses to use rather than hitting a
22
+ remote API.
23
+
24
+ .. code-block:: php
25
+
26
+ use GuzzleHttp\Client;
27
+ use GuzzleHttp\Subscriber\Mock;
28
+ use GuzzleHttp\Message\Response;
29
+
30
+ $client = new Client();
31
+
32
+ // Create a mock subscriber and queue two responses.
33
+ $mock = new Mock([
34
+ new Response(200, ['X-Foo' => 'Bar']), // Use response object
35
+ "HTTP/1.1 202 OK\r\nContent-Length: 0\r\n\r\n" // Use a response string
36
+ ]);
37
+
38
+ // Add the mock subscriber to the client.
39
+ $client->getEmitter()->attach($mock);
40
+ // The first request is intercepted with the first response.
41
+ echo $client->get('/')->getStatusCode();
42
+ //> 200
43
+ // The second request is intercepted with the second response.
44
+ echo $client->get('/')->getStatusCode();
45
+ //> 202
46
+
47
+ When no more responses are in the queue and a request is sent, an
48
+ ``OutOfBoundsException`` is thrown.
49
+
50
+ History Subscriber
51
+ ==================
52
+
53
+ When using things like the ``Mock`` subscriber, you often need to know if the
54
+ requests you expected to send were sent exactly as you intended. While the mock
55
+ subscriber responds with mocked responses, the ``GuzzleHttp\Subscriber\History``
56
+ subscriber maintains a history of the requests that were sent by a client.
57
+
58
+ .. code-block:: php
59
+
60
+ use GuzzleHttp\Client;
61
+ use GuzzleHttp\Subscriber\History;
62
+
63
+ $client = new Client();
64
+ $history = new History();
65
+
66
+ // Add the history subscriber to the client.
67
+ $client->getEmitter()->attach($history);
68
+
69
+ $client->get('http://httpbin.org/get');
70
+ $client->head('http://httpbin.org/get');
71
+
72
+ // Count the number of transactions
73
+ echo count($history);
74
+ //> 2
75
+ // Get the last request
76
+ $lastRequest = $history->getLastRequest();
77
+ // Get the last response
78
+ $lastRequest = $history->getLastResponse();
79
+
80
+ // Iterate over the transactions that were sent
81
+ foreach ($history as $transaction) {
82
+ echo $transaction['request']->getMethod();
83
+ //> GET, HEAD
84
+ echo $transaction['response']->getStatusCode();
85
+ //> 200, 200
86
+ }
87
+
88
+ The history subscriber can also be printed, revealing the requests and
89
+ responses that were sent as a string, in order.
90
+
91
+ .. code-block:: php
92
+
93
+ echo $history;
94
+
95
+ ::
96
+
97
+ > GET /get HTTP/1.1
98
+ Host: httpbin.org
99
+ User-Agent: Guzzle/4.0-dev curl/7.21.4 PHP/5.5.8
100
+
101
+ < HTTP/1.1 200 OK
102
+ Access-Control-Allow-Origin: *
103
+ Content-Type: application/json
104
+ Date: Tue, 25 Mar 2014 03:53:27 GMT
105
+ Server: gunicorn/0.17.4
106
+ Content-Length: 270
107
+ Connection: keep-alive
108
+
109
+ {
110
+ "headers": {
111
+ "Connection": "close",
112
+ "X-Request-Id": "3d0f7d5c-c937-4394-8248-2b8e03fcccdb",
113
+ "User-Agent": "Guzzle/4.0-dev curl/7.21.4 PHP/5.5.8",
114
+ "Host": "httpbin.org"
115
+ },
116
+ "origin": "76.104.247.1",
117
+ "args": {},
118
+ "url": "http://httpbin.org/get"
119
+ }
120
+
121
+ > HEAD /get HTTP/1.1
122
+ Host: httpbin.org
123
+ User-Agent: Guzzle/4.0-dev curl/7.21.4 PHP/5.5.8
124
+
125
+ < HTTP/1.1 200 OK
126
+ Access-Control-Allow-Origin: *
127
+ Content-length: 270
128
+ Content-Type: application/json
129
+ Date: Tue, 25 Mar 2014 03:53:27 GMT
130
+ Server: gunicorn/0.17.4
131
+ Connection: keep-alive
132
+
133
+ Mock Adapter
134
+ ============
135
+
136
+ In addition to using the Mock subscriber, you can use the
137
+ ``GuzzleHttp\Ring\Client\MockAdapter`` as the handler of a client to return the
138
+ same response over and over or return the result of a callable function.
139
+
140
+ Test Web Server
141
+ ===============
142
+
143
+ Using mock responses is almost always enough when testing a web service client.
144
+ When implementing custom :doc:`HTTP handlers <handlers>`, you'll need to send
145
+ actual HTTP requests in order to sufficiently test the handler. However, a
146
+ best practice is to contact a local web server rather than a server over the
147
+ internet.
148
+
149
+ - Tests are more reliable
150
+ - Tests do not require a network connection
151
+ - Tests have no external dependencies
152
+
153
+ Using the test server
154
+ ---------------------
155
+
156
+ .. warning::
157
+
158
+ The following functionality is provided to help developers of Guzzle
159
+ develop HTTP handlers. There is no promise of backwards compatibility
160
+ when it comes to the node.js test server or the ``GuzzleHttp\Tests\Server``
161
+ class. If you are using the test server or ``Server`` class outside of
162
+ guzzlehttp/guzzle, then you will need to configure autoloading and
163
+ ensure the web server is started manually.
164
+
165
+ .. hint::
166
+
167
+ You almost never need to use this test web server. You should only ever
168
+ consider using it when developing HTTP handlers. The test web server
169
+ is not necessary for mocking requests. For that, please use the
170
+ Mock subcribers and History subscriber.
171
+
172
+ Guzzle ships with a node.js test server that receives requests and returns
173
+ responses from a queue. The test server exposes a simple API that is used to
174
+ enqueue responses and inspect the requests that it has received.
175
+
176
+ Any operation on the ``Server`` object will ensure that
177
+ the server is running and wait until it is able to receive requests before
178
+ returning.
179
+
180
+ .. code-block:: php
181
+
182
+ use GuzzleHttp\Client;
183
+ use GuzzleHttp\Tests\Server;
184
+
185
+ // Start the server and queue a response
186
+ Server::enqueue("HTTP/1.1 200 OK\r\n\Content-Length: 0r\n\r\n");
187
+
188
+ $client = new Client(['base_url' => Server::$url]);
189
+ echo $client->get('/foo')->getStatusCode();
190
+ // 200
191
+
192
+ ``GuzzleHttp\Tests\Server`` provides a static interface to the test server. You
193
+ can queue an HTTP response or an array of responses by calling
194
+ ``Server::enqueue()``. This method accepts a string representing an HTTP
195
+ response message, a ``GuzzleHttp\Message\ResponseInterface``, or an array of
196
+ HTTP message strings / ``GuzzleHttp\Message\ResponseInterface`` objects.
197
+
198
+ .. code-block:: php
199
+
200
+ // Queue single response
201
+ Server::enqueue("HTTP/1.1 200 OK\r\n\Content-Length: 0r\n\r\n");
202
+
203
+ // Clear the queue and queue an array of responses
204
+ Server::enqueue([
205
+ "HTTP/1.1 200 OK\r\n\Content-Length: 0r\n\r\n",
206
+ "HTTP/1.1 404 Not Found\r\n\Content-Length: 0r\n\r\n"
207
+ ]);
208
+
209
+ When a response is queued on the test server, the test server will remove any
210
+ previously queued responses. As the server receives requests, queued responses
211
+ are dequeued and returned to the request. When the queue is empty, the server
212
+ will return a 500 response.
213
+
214
+ You can inspect the requests that the server has retrieved by calling
215
+ ``Server::received()``. This method accepts an optional ``$hydrate`` parameter
216
+ that specifies if you are retrieving an array of HTTP requests as strings or an
217
+ array of ``GuzzleHttp\Message\RequestInterface`` objects.
218
+
219
+ .. code-block:: php
220
+
221
+ foreach (Server::received() as $response) {
222
+ echo $response;
223
+ }
224
+
225
+ You can clear the list of received requests from the web server using the
226
+ ``Server::flush()`` method.
227
+
228
+ .. code-block:: php
229
+
230
+ Server::flush();
231
+ echo count(Server::received());
232
+ // 0
backend/vendor/guzzlehttp/guzzle/phpunit.xml.dist ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <phpunit bootstrap="./tests/bootstrap.php"
3
+ colors="true">
4
+ <testsuites>
5
+ <testsuite>
6
+ <directory>tests</directory>
7
+ </testsuite>
8
+ </testsuites>
9
+ <filter>
10
+ <whitelist>
11
+ <directory suffix=".php">src</directory>
12
+ <exclude>
13
+ <directory suffix="Interface.php">src/</directory>
14
+ </exclude>
15
+ </whitelist>
16
+ </filter>
17
+ </phpunit>
backend/vendor/guzzlehttp/guzzle/src/BatchResults.php ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ /**
5
+ * Represents the result of a batch operation. This result container is
6
+ * iterable, countable, and you can can get a result by value using the
7
+ * getResult function.
8
+ *
9
+ * Successful results are anything other than exceptions. Failure results are
10
+ * exceptions.
11
+ *
12
+ * @package GuzzleHttp
13
+ */
14
+ class BatchResults implements \Countable, \IteratorAggregate, \ArrayAccess
15
+ {
16
+ private $hash;
17
+
18
+ /**
19
+ * @param \SplObjectStorage $hash Hash of key objects to result values.
20
+ */
21
+ public function __construct(\SplObjectStorage $hash)
22
+ {
23
+ $this->hash = $hash;
24
+ }
25
+
26
+ /**
27
+ * Get the keys that are available on the batch result.
28
+ *
29
+ * @return array
30
+ */
31
+ public function getKeys()
32
+ {
33
+ return iterator_to_array($this->hash);
34
+ }
35
+
36
+ /**
37
+ * Gets a result from the container for the given object. When getting
38
+ * results for a batch of requests, provide the request object.
39
+ *
40
+ * @param object $forObject Object to retrieve the result for.
41
+ *
42
+ * @return mixed|null
43
+ */
44
+ public function getResult($forObject)
45
+ {
46
+ return isset($this->hash[$forObject]) ? $this->hash[$forObject] : null;
47
+ }
48
+
49
+ /**
50
+ * Get an array of successful results.
51
+ *
52
+ * @return array
53
+ */
54
+ public function getSuccessful()
55
+ {
56
+ $results = [];
57
+ foreach ($this->hash as $key) {
58
+ if (!($this->hash[$key] instanceof \Exception)) {
59
+ $results[] = $this->hash[$key];
60
+ }
61
+ }
62
+
63
+ return $results;
64
+ }
65
+
66
+ /**
67
+ * Get an array of failed results.
68
+ *
69
+ * @return array
70
+ */
71
+ public function getFailures()
72
+ {
73
+ $results = [];
74
+ foreach ($this->hash as $key) {
75
+ if ($this->hash[$key] instanceof \Exception) {
76
+ $results[] = $this->hash[$key];
77
+ }
78
+ }
79
+
80
+ return $results;
81
+ }
82
+
83
+ /**
84
+ * Allows iteration over all batch result values.
85
+ *
86
+ * @return \ArrayIterator
87
+ */
88
+ public function getIterator()
89
+ {
90
+ $results = [];
91
+ foreach ($this->hash as $key) {
92
+ $results[] = $this->hash[$key];
93
+ }
94
+
95
+ return new \ArrayIterator($results);
96
+ }
97
+
98
+ /**
99
+ * Counts the number of elements in the batch result.
100
+ *
101
+ * @return int
102
+ */
103
+ public function count()
104
+ {
105
+ return count($this->hash);
106
+ }
107
+
108
+ /**
109
+ * Checks if the batch contains a specific numerical array index.
110
+ *
111
+ * @param int $key Index to access
112
+ *
113
+ * @return bool
114
+ */
115
+ public function offsetExists($key)
116
+ {
117
+ return $key < count($this->hash);
118
+ }
119
+
120
+ /**
121
+ * Allows access of the batch using a numerical array index.
122
+ *
123
+ * @param int $key Index to access.
124
+ *
125
+ * @return mixed|null
126
+ */
127
+ public function offsetGet($key)
128
+ {
129
+ $i = -1;
130
+ foreach ($this->hash as $obj) {
131
+ if ($key === ++$i) {
132
+ return $this->hash[$obj];
133
+ }
134
+ }
135
+
136
+ return null;
137
+ }
138
+
139
+ public function offsetUnset($key)
140
+ {
141
+ throw new \RuntimeException('Not implemented');
142
+ }
143
+
144
+ public function offsetSet($key, $value)
145
+ {
146
+ throw new \RuntimeException('Not implemented');
147
+ }
148
+ }
backend/vendor/guzzlehttp/guzzle/src/Client.php ADDED
@@ -0,0 +1,394 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Event\HasEmitterTrait;
5
+ use GuzzleHttp\Message\MessageFactory;
6
+ use GuzzleHttp\Message\MessageFactoryInterface;
7
+ use GuzzleHttp\Message\RequestInterface;
8
+ use GuzzleHttp\Message\FutureResponse;
9
+ use GuzzleHttp\Ring\Client\Middleware;
10
+ use GuzzleHttp\Ring\Client\CurlMultiHandler;
11
+ use GuzzleHttp\Ring\Client\CurlHandler;
12
+ use GuzzleHttp\Ring\Client\StreamHandler;
13
+ use GuzzleHttp\Ring\Core;
14
+ use GuzzleHttp\Ring\Future\FutureInterface;
15
+ use GuzzleHttp\Exception\RequestException;
16
+ use React\Promise\FulfilledPromise;
17
+ use React\Promise\RejectedPromise;
18
+
19
+ /**
20
+ * HTTP client
21
+ */
22
+ class Client implements ClientInterface
23
+ {
24
+ use HasEmitterTrait;
25
+
26
+ /** @var MessageFactoryInterface Request factory used by the client */
27
+ private $messageFactory;
28
+
29
+ /** @var Url Base URL of the client */
30
+ private $baseUrl;
31
+
32
+ /** @var array Default request options */
33
+ private $defaults;
34
+
35
+ /** @var callable Request state machine */
36
+ private $fsm;
37
+
38
+ /**
39
+ * Clients accept an array of constructor parameters.
40
+ *
41
+ * Here's an example of creating a client using an URI template for the
42
+ * client's base_url and an array of default request options to apply
43
+ * to each request:
44
+ *
45
+ * $client = new Client([
46
+ * 'base_url' => [
47
+ * 'http://www.foo.com/{version}/',
48
+ * ['version' => '123']
49
+ * ],
50
+ * 'defaults' => [
51
+ * 'timeout' => 10,
52
+ * 'allow_redirects' => false,
53
+ * 'proxy' => '192.168.16.1:10'
54
+ * ]
55
+ * ]);
56
+ *
57
+ * @param array $config Client configuration settings
58
+ * - base_url: Base URL of the client that is merged into relative URLs.
59
+ * Can be a string or an array that contains a URI template followed
60
+ * by an associative array of expansion variables to inject into the
61
+ * URI template.
62
+ * - handler: callable RingPHP handler used to transfer requests
63
+ * - message_factory: Factory used to create request and response object
64
+ * - defaults: Default request options to apply to each request
65
+ * - emitter: Event emitter used for request events
66
+ * - fsm: (internal use only) The request finite state machine. A
67
+ * function that accepts a transaction and optional final state. The
68
+ * function is responsible for transitioning a request through its
69
+ * lifecycle events.
70
+ */
71
+ public function __construct(array $config = [])
72
+ {
73
+ $this->configureBaseUrl($config);
74
+ $this->configureDefaults($config);
75
+
76
+ if (isset($config['emitter'])) {
77
+ $this->emitter = $config['emitter'];
78
+ }
79
+
80
+ $this->messageFactory = isset($config['message_factory'])
81
+ ? $config['message_factory']
82
+ : new MessageFactory();
83
+
84
+ if (isset($config['fsm'])) {
85
+ $this->fsm = $config['fsm'];
86
+ } else {
87
+ if (isset($config['handler'])) {
88
+ $handler = $config['handler'];
89
+ } elseif (isset($config['adapter'])) {
90
+ $handler = $config['adapter'];
91
+ } else {
92
+ $handler = static::getDefaultHandler();
93
+ }
94
+ $this->fsm = new RequestFsm($handler, $this->messageFactory);
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Create a default handler to use based on the environment
100
+ *
101
+ * @throws \RuntimeException if no viable Handler is available.
102
+ */
103
+ public static function getDefaultHandler()
104
+ {
105
+ $default = $future = $streaming = null;
106
+
107
+ if (extension_loaded('curl')) {
108
+ $config = [
109
+ 'select_timeout' => getenv('GUZZLE_CURL_SELECT_TIMEOUT') ?: 1
110
+ ];
111
+ if ($maxHandles = getenv('GUZZLE_CURL_MAX_HANDLES')) {
112
+ $config['max_handles'] = $maxHandles;
113
+ }
114
+ $future = new CurlMultiHandler($config);
115
+ if (function_exists('curl_reset')) {
116
+ $default = new CurlHandler();
117
+ }
118
+ }
119
+
120
+ if (ini_get('allow_url_fopen')) {
121
+ $streaming = new StreamHandler();
122
+ }
123
+
124
+ if (!($default = ($default ?: $future) ?: $streaming)) {
125
+ throw new \RuntimeException('Guzzle requires cURL, the '
126
+ . 'allow_url_fopen ini setting, or a custom HTTP handler.');
127
+ }
128
+
129
+ $handler = $default;
130
+
131
+ if ($streaming && $streaming !== $default) {
132
+ $handler = Middleware::wrapStreaming($default, $streaming);
133
+ }
134
+
135
+ if ($future) {
136
+ $handler = Middleware::wrapFuture($handler, $future);
137
+ }
138
+
139
+ return $handler;
140
+ }
141
+
142
+ /**
143
+ * Get the default User-Agent string to use with Guzzle
144
+ *
145
+ * @return string
146
+ */
147
+ public static function getDefaultUserAgent()
148
+ {
149
+ static $defaultAgent = '';
150
+ if (!$defaultAgent) {
151
+ $defaultAgent = 'Guzzle/' . self::VERSION;
152
+ if (extension_loaded('curl')) {
153
+ $defaultAgent .= ' curl/' . curl_version()['version'];
154
+ }
155
+ $defaultAgent .= ' PHP/' . PHP_VERSION;
156
+ }
157
+
158
+ return $defaultAgent;
159
+ }
160
+
161
+ public function getDefaultOption($keyOrPath = null)
162
+ {
163
+ return $keyOrPath === null
164
+ ? $this->defaults
165
+ : Utils::getPath($this->defaults, $keyOrPath);
166
+ }
167
+
168
+ public function setDefaultOption($keyOrPath, $value)
169
+ {
170
+ Utils::setPath($this->defaults, $keyOrPath, $value);
171
+ }
172
+
173
+ public function getBaseUrl()
174
+ {
175
+ return (string) $this->baseUrl;
176
+ }
177
+
178
+ public function createRequest($method, $url = null, array $options = [])
179
+ {
180
+ $options = $this->mergeDefaults($options);
181
+ // Use a clone of the client's emitter
182
+ $options['config']['emitter'] = clone $this->getEmitter();
183
+ $url = $url || (is_string($url) && strlen($url))
184
+ ? $this->buildUrl($url)
185
+ : (string) $this->baseUrl;
186
+
187
+ return $this->messageFactory->createRequest($method, $url, $options);
188
+ }
189
+
190
+ public function get($url = null, $options = [])
191
+ {
192
+ return $this->send($this->createRequest('GET', $url, $options));
193
+ }
194
+
195
+ public function head($url = null, array $options = [])
196
+ {
197
+ return $this->send($this->createRequest('HEAD', $url, $options));
198
+ }
199
+
200
+ public function delete($url = null, array $options = [])
201
+ {
202
+ return $this->send($this->createRequest('DELETE', $url, $options));
203
+ }
204
+
205
+ public function put($url = null, array $options = [])
206
+ {
207
+ return $this->send($this->createRequest('PUT', $url, $options));
208
+ }
209
+
210
+ public function patch($url = null, array $options = [])
211
+ {
212
+ return $this->send($this->createRequest('PATCH', $url, $options));
213
+ }
214
+
215
+ public function post($url = null, array $options = [])
216
+ {
217
+ return $this->send($this->createRequest('POST', $url, $options));
218
+ }
219
+
220
+ public function options($url = null, array $options = [])
221
+ {
222
+ return $this->send($this->createRequest('OPTIONS', $url, $options));
223
+ }
224
+
225
+ public function send(RequestInterface $request)
226
+ {
227
+ $isFuture = $request->getConfig()->get('future');
228
+ $trans = new Transaction($this, $request, $isFuture);
229
+ $fn = $this->fsm;
230
+
231
+ // Ensure a future response is returned if one was requested.
232
+ if ($isFuture) {
233
+ try {
234
+ $fn($trans);
235
+ // Turn the normal response into a future if needed.
236
+ return $trans->response instanceof FutureInterface
237
+ ? $trans->response
238
+ : new FutureResponse(new FulfilledPromise($trans->response));
239
+ } catch (RequestException $e) {
240
+ // Wrap the exception in a promise if the user asked for a future.
241
+ return new FutureResponse(new RejectedPromise($e));
242
+ }
243
+ } else {
244
+ try {
245
+ $fn($trans);
246
+ return $trans->response instanceof FutureInterface
247
+ ? $trans->response->wait()
248
+ : $trans->response;
249
+ } catch (\Exception $e) {
250
+ throw RequestException::wrapException($trans->request, $e);
251
+ }
252
+ }
253
+ }
254
+
255
+ /**
256
+ * Get an array of default options to apply to the client
257
+ *
258
+ * @return array
259
+ */
260
+ protected function getDefaultOptions()
261
+ {
262
+ $settings = [
263
+ 'allow_redirects' => true,
264
+ 'exceptions' => true,
265
+ 'decode_content' => true,
266
+ 'verify' => true
267
+ ];
268
+
269
+ // Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set
270
+ if ($proxy = getenv('HTTP_PROXY')) {
271
+ $settings['proxy']['http'] = $proxy;
272
+ }
273
+
274
+ if ($proxy = getenv('HTTPS_PROXY')) {
275
+ $settings['proxy']['https'] = $proxy;
276
+ }
277
+
278
+ return $settings;
279
+ }
280
+
281
+ /**
282
+ * Expand a URI template and inherit from the base URL if it's relative
283
+ *
284
+ * @param string|array $url URL or URI template to expand
285
+ *
286
+ * @return string
287
+ */
288
+ private function buildUrl($url)
289
+ {
290
+ // URI template (absolute or relative)
291
+ if (!is_array($url)) {
292
+ return strpos($url, '://')
293
+ ? (string) $url
294
+ : (string) $this->baseUrl->combine($url);
295
+ }
296
+
297
+ // Absolute URL
298
+ if (strpos($url[0], '://')) {
299
+ return Utils::uriTemplate($url[0], $url[1]);
300
+ }
301
+
302
+ // Combine the relative URL with the base URL
303
+ return (string) $this->baseUrl->combine(
304
+ Utils::uriTemplate($url[0], $url[1])
305
+ );
306
+ }
307
+
308
+ private function configureBaseUrl(&$config)
309
+ {
310
+ if (!isset($config['base_url'])) {
311
+ $this->baseUrl = new Url('', '');
312
+ } elseif (is_array($config['base_url'])) {
313
+ $this->baseUrl = Url::fromString(
314
+ Utils::uriTemplate(
315
+ $config['base_url'][0],
316
+ $config['base_url'][1]
317
+ )
318
+ );
319
+ $config['base_url'] = (string) $this->baseUrl;
320
+ } else {
321
+ $this->baseUrl = Url::fromString($config['base_url']);
322
+ }
323
+ }
324
+
325
+ private function configureDefaults($config)
326
+ {
327
+ if (!isset($config['defaults'])) {
328
+ $this->defaults = $this->getDefaultOptions();
329
+ } else {
330
+ $this->defaults = array_replace(
331
+ $this->getDefaultOptions(),
332
+ $config['defaults']
333
+ );
334
+ }
335
+
336
+ // Add the default user-agent header
337
+ if (!isset($this->defaults['headers'])) {
338
+ $this->defaults['headers'] = [
339
+ 'User-Agent' => static::getDefaultUserAgent()
340
+ ];
341
+ } elseif (!Core::hasHeader($this->defaults, 'User-Agent')) {
342
+ // Add the User-Agent header if one was not already set
343
+ $this->defaults['headers']['User-Agent'] = static::getDefaultUserAgent();
344
+ }
345
+ }
346
+
347
+ /**
348
+ * Merges default options into the array passed by reference.
349
+ *
350
+ * @param array $options Options to modify by reference
351
+ *
352
+ * @return array
353
+ */
354
+ private function mergeDefaults($options)
355
+ {
356
+ $defaults = $this->defaults;
357
+
358
+ // Case-insensitively merge in default headers if both defaults and
359
+ // options have headers specified.
360
+ if (!empty($defaults['headers']) && !empty($options['headers'])) {
361
+ // Create a set of lowercased keys that are present.
362
+ $lkeys = [];
363
+ foreach (array_keys($options['headers']) as $k) {
364
+ $lkeys[strtolower($k)] = true;
365
+ }
366
+ // Merge in lowercase default keys when not present in above set.
367
+ foreach ($defaults['headers'] as $key => $value) {
368
+ if (!isset($lkeys[strtolower($key)])) {
369
+ $options['headers'][$key] = $value;
370
+ }
371
+ }
372
+ // No longer need to merge in headers.
373
+ unset($defaults['headers']);
374
+ }
375
+
376
+ $result = array_replace_recursive($defaults, $options);
377
+ foreach ($options as $k => $v) {
378
+ if ($v === null) {
379
+ unset($result[$k]);
380
+ }
381
+ }
382
+
383
+ return $result;
384
+ }
385
+
386
+ /**
387
+ * @deprecated Use {@see GuzzleHttp\Pool} instead.
388
+ * @see GuzzleHttp\Pool
389
+ */
390
+ public function sendAll($requests, array $options = [])
391
+ {
392
+ (new Pool($this, $requests, $options))->wait();
393
+ }
394
+ }
backend/vendor/guzzlehttp/guzzle/src/ClientInterface.php ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Event\HasEmitterInterface;
5
+ use GuzzleHttp\Exception\RequestException;
6
+ use GuzzleHttp\Message\RequestInterface;
7
+ use GuzzleHttp\Message\ResponseInterface;
8
+
9
+ /**
10
+ * Client interface for sending HTTP requests
11
+ */
12
+ interface ClientInterface extends HasEmitterInterface
13
+ {
14
+ const VERSION = '5.1.0';
15
+
16
+ /**
17
+ * Create and return a new {@see RequestInterface} object.
18
+ *
19
+ * Use an absolute path to override the base path of the client, or a
20
+ * relative path to append to the base path of the client. The URL can
21
+ * contain the query string as well. Use an array to provide a URL
22
+ * template and additional variables to use in the URL template expansion.
23
+ *
24
+ * @param string $method HTTP method
25
+ * @param string|array|Url $url URL or URI template
26
+ * @param array $options Array of request options to apply.
27
+ *
28
+ * @return RequestInterface
29
+ */
30
+ public function createRequest($method, $url = null, array $options = []);
31
+
32
+ /**
33
+ * Send a GET request
34
+ *
35
+ * @param string|array|Url $url URL or URI template
36
+ * @param array $options Array of request options to apply.
37
+ *
38
+ * @return ResponseInterface
39
+ * @throws RequestException When an error is encountered
40
+ */
41
+ public function get($url = null, $options = []);
42
+
43
+ /**
44
+ * Send a HEAD request
45
+ *
46
+ * @param string|array|Url $url URL or URI template
47
+ * @param array $options Array of request options to apply.
48
+ *
49
+ * @return ResponseInterface
50
+ * @throws RequestException When an error is encountered
51
+ */
52
+ public function head($url = null, array $options = []);
53
+
54
+ /**
55
+ * Send a DELETE request
56
+ *
57
+ * @param string|array|Url $url URL or URI template
58
+ * @param array $options Array of request options to apply.
59
+ *
60
+ * @return ResponseInterface
61
+ * @throws RequestException When an error is encountered
62
+ */
63
+ public function delete($url = null, array $options = []);
64
+
65
+ /**
66
+ * Send a PUT request
67
+ *
68
+ * @param string|array|Url $url URL or URI template
69
+ * @param array $options Array of request options to apply.
70
+ *
71
+ * @return ResponseInterface
72
+ * @throws RequestException When an error is encountered
73
+ */
74
+ public function put($url = null, array $options = []);
75
+
76
+ /**
77
+ * Send a PATCH request
78
+ *
79
+ * @param string|array|Url $url URL or URI template
80
+ * @param array $options Array of request options to apply.
81
+ *
82
+ * @return ResponseInterface
83
+ * @throws RequestException When an error is encountered
84
+ */
85
+ public function patch($url = null, array $options = []);
86
+
87
+ /**
88
+ * Send a POST request
89
+ *
90
+ * @param string|array|Url $url URL or URI template
91
+ * @param array $options Array of request options to apply.
92
+ *
93
+ * @return ResponseInterface
94
+ * @throws RequestException When an error is encountered
95
+ */
96
+ public function post($url = null, array $options = []);
97
+
98
+ /**
99
+ * Send an OPTIONS request
100
+ *
101
+ * @param string|array|Url $url URL or URI template
102
+ * @param array $options Array of request options to apply.
103
+ *
104
+ * @return ResponseInterface
105
+ * @throws RequestException When an error is encountered
106
+ */
107
+ public function options($url = null, array $options = []);
108
+
109
+ /**
110
+ * Sends a single request
111
+ *
112
+ * @param RequestInterface $request Request to send
113
+ *
114
+ * @return \GuzzleHttp\Message\ResponseInterface
115
+ * @throws \LogicException When the handler does not populate a response
116
+ * @throws RequestException When an error is encountered
117
+ */
118
+ public function send(RequestInterface $request);
119
+
120
+ /**
121
+ * Get default request options of the client.
122
+ *
123
+ * @param string|null $keyOrPath The Path to a particular default request
124
+ * option to retrieve or pass null to retrieve all default request
125
+ * options. The syntax uses "/" to denote a path through nested PHP
126
+ * arrays. For example, "headers/content-type".
127
+ *
128
+ * @return mixed
129
+ */
130
+ public function getDefaultOption($keyOrPath = null);
131
+
132
+ /**
133
+ * Set a default request option on the client so that any request created
134
+ * by the client will use the provided default value unless overridden
135
+ * explicitly when creating a request.
136
+ *
137
+ * @param string|null $keyOrPath The Path to a particular configuration
138
+ * value to set. The syntax uses a path notation that allows you to
139
+ * specify nested configuration values (e.g., 'headers/content-type').
140
+ * @param mixed $value Default request option value to set
141
+ */
142
+ public function setDefaultOption($keyOrPath, $value);
143
+
144
+ /**
145
+ * Get the base URL of the client.
146
+ *
147
+ * @return string Returns the base URL if present
148
+ */
149
+ public function getBaseUrl();
150
+ }
backend/vendor/guzzlehttp/guzzle/src/Collection.php ADDED
@@ -0,0 +1,236 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ /**
5
+ * Key value pair collection object
6
+ */
7
+ class Collection implements
8
+ \ArrayAccess,
9
+ \IteratorAggregate,
10
+ \Countable,
11
+ ToArrayInterface
12
+ {
13
+ use HasDataTrait;
14
+
15
+ /**
16
+ * @param array $data Associative array of data to set
17
+ */
18
+ public function __construct(array $data = [])
19
+ {
20
+ $this->data = $data;
21
+ }
22
+
23
+ /**
24
+ * Create a new collection from an array, validate the keys, and add default
25
+ * values where missing
26
+ *
27
+ * @param array $config Configuration values to apply.
28
+ * @param array $defaults Default parameters
29
+ * @param array $required Required parameter names
30
+ *
31
+ * @return self
32
+ * @throws \InvalidArgumentException if a parameter is missing
33
+ */
34
+ public static function fromConfig(
35
+ array $config = [],
36
+ array $defaults = [],
37
+ array $required = []
38
+ ) {
39
+ $data = $config + $defaults;
40
+
41
+ if ($missing = array_diff($required, array_keys($data))) {
42
+ throw new \InvalidArgumentException(
43
+ 'Config is missing the following keys: ' .
44
+ implode(', ', $missing));
45
+ }
46
+
47
+ return new self($data);
48
+ }
49
+
50
+ /**
51
+ * Removes all key value pairs
52
+ */
53
+ public function clear()
54
+ {
55
+ $this->data = [];
56
+ }
57
+
58
+ /**
59
+ * Get a specific key value.
60
+ *
61
+ * @param string $key Key to retrieve.
62
+ *
63
+ * @return mixed|null Value of the key or NULL
64
+ */
65
+ public function get($key)
66
+ {
67
+ return isset($this->data[$key]) ? $this->data[$key] : null;
68
+ }
69
+
70
+ /**
71
+ * Set a key value pair
72
+ *
73
+ * @param string $key Key to set
74
+ * @param mixed $value Value to set
75
+ */
76
+ public function set($key, $value)
77
+ {
78
+ $this->data[$key] = $value;
79
+ }
80
+
81
+ /**
82
+ * Add a value to a key. If a key of the same name has already been added,
83
+ * the key value will be converted into an array and the new value will be
84
+ * pushed to the end of the array.
85
+ *
86
+ * @param string $key Key to add
87
+ * @param mixed $value Value to add to the key
88
+ */
89
+ public function add($key, $value)
90
+ {
91
+ if (!array_key_exists($key, $this->data)) {
92
+ $this->data[$key] = $value;
93
+ } elseif (is_array($this->data[$key])) {
94
+ $this->data[$key][] = $value;
95
+ } else {
96
+ $this->data[$key] = array($this->data[$key], $value);
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Remove a specific key value pair
102
+ *
103
+ * @param string $key A key to remove
104
+ */
105
+ public function remove($key)
106
+ {
107
+ unset($this->data[$key]);
108
+ }
109
+
110
+ /**
111
+ * Get all keys in the collection
112
+ *
113
+ * @return array
114
+ */
115
+ public function getKeys()
116
+ {
117
+ return array_keys($this->data);
118
+ }
119
+
120
+ /**
121
+ * Returns whether or not the specified key is present.
122
+ *
123
+ * @param string $key The key for which to check the existence.
124
+ *
125
+ * @return bool
126
+ */
127
+ public function hasKey($key)
128
+ {
129
+ return array_key_exists($key, $this->data);
130
+ }
131
+
132
+ /**
133
+ * Checks if any keys contains a certain value
134
+ *
135
+ * @param string $value Value to search for
136
+ *
137
+ * @return mixed Returns the key if the value was found FALSE if the value
138
+ * was not found.
139
+ */
140
+ public function hasValue($value)
141
+ {
142
+ return array_search($value, $this->data, true);
143
+ }
144
+
145
+ /**
146
+ * Replace the data of the object with the value of an array
147
+ *
148
+ * @param array $data Associative array of data
149
+ */
150
+ public function replace(array $data)
151
+ {
152
+ $this->data = $data;
153
+ }
154
+
155
+ /**
156
+ * Add and merge in a Collection or array of key value pair data.
157
+ *
158
+ * @param Collection|array $data Associative array of key value pair data
159
+ */
160
+ public function merge($data)
161
+ {
162
+ foreach ($data as $key => $value) {
163
+ $this->add($key, $value);
164
+ }
165
+ }
166
+
167
+ /**
168
+ * Overwrite key value pairs in this collection with all of the data from
169
+ * an array or collection.
170
+ *
171
+ * @param array|\Traversable $data Values to override over this config
172
+ */
173
+ public function overwriteWith($data)
174
+ {
175
+ if (is_array($data)) {
176
+ $this->data = $data + $this->data;
177
+ } elseif ($data instanceof Collection) {
178
+ $this->data = $data->toArray() + $this->data;
179
+ } else {
180
+ foreach ($data as $key => $value) {
181
+ $this->data[$key] = $value;
182
+ }
183
+ }
184
+ }
185
+
186
+ /**
187
+ * Returns a Collection containing all the elements of the collection after
188
+ * applying the callback function to each one.
189
+ *
190
+ * The callable should accept three arguments:
191
+ * - (string) $key
192
+ * - (string) $value
193
+ * - (array) $context
194
+ *
195
+ * The callable must return a the altered or unaltered value.
196
+ *
197
+ * @param callable $closure Map function to apply
198
+ * @param array $context Context to pass to the callable
199
+ *
200
+ * @return Collection
201
+ */
202
+ public function map(callable $closure, array $context = [])
203
+ {
204
+ $collection = new static();
205
+ foreach ($this as $key => $value) {
206
+ $collection[$key] = $closure($key, $value, $context);
207
+ }
208
+
209
+ return $collection;
210
+ }
211
+
212
+ /**
213
+ * Iterates over each key value pair in the collection passing them to the
214
+ * callable. If the callable returns true, the current value from input is
215
+ * returned into the result Collection.
216
+ *
217
+ * The callable must accept two arguments:
218
+ * - (string) $key
219
+ * - (string) $value
220
+ *
221
+ * @param callable $closure Evaluation function
222
+ *
223
+ * @return Collection
224
+ */
225
+ public function filter(callable $closure)
226
+ {
227
+ $collection = new static();
228
+ foreach ($this->data as $key => $value) {
229
+ if ($closure($key, $value)) {
230
+ $collection[$key] = $value;
231
+ }
232
+ }
233
+
234
+ return $collection;
235
+ }
236
+ }
backend/vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php ADDED
@@ -0,0 +1,248 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Cookie;
3
+
4
+ use GuzzleHttp\Message\RequestInterface;
5
+ use GuzzleHttp\Message\ResponseInterface;
6
+ use GuzzleHttp\ToArrayInterface;
7
+
8
+ /**
9
+ * Cookie jar that stores cookies an an array
10
+ */
11
+ class CookieJar implements CookieJarInterface, ToArrayInterface
12
+ {
13
+ /** @var SetCookie[] Loaded cookie data */
14
+ private $cookies = [];
15
+
16
+ /** @var bool */
17
+ private $strictMode;
18
+
19
+ /**
20
+ * @param bool $strictMode Set to true to throw exceptions when invalid
21
+ * cookies are added to the cookie jar.
22
+ * @param array $cookieArray Array of SetCookie objects or a hash of arrays
23
+ * that can be used with the SetCookie constructor
24
+ */
25
+ public function __construct($strictMode = false, $cookieArray = [])
26
+ {
27
+ $this->strictMode = $strictMode;
28
+
29
+ foreach ($cookieArray as $cookie) {
30
+ if (!($cookie instanceof SetCookie)) {
31
+ $cookie = new SetCookie($cookie);
32
+ }
33
+ $this->setCookie($cookie);
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Create a new Cookie jar from an associative array and domain.
39
+ *
40
+ * @param array $cookies Cookies to create the jar from
41
+ * @param string $domain Domain to set the cookies to
42
+ *
43
+ * @return self
44
+ */
45
+ public static function fromArray(array $cookies, $domain)
46
+ {
47
+ $cookieJar = new self();
48
+ foreach ($cookies as $name => $value) {
49
+ $cookieJar->setCookie(new SetCookie([
50
+ 'Domain' => $domain,
51
+ 'Name' => $name,
52
+ 'Value' => $value,
53
+ 'Discard' => true
54
+ ]));
55
+ }
56
+
57
+ return $cookieJar;
58
+ }
59
+
60
+ /**
61
+ * Quote the cookie value if it is not already quoted and it contains
62
+ * problematic characters.
63
+ *
64
+ * @param string $value Value that may or may not need to be quoted
65
+ *
66
+ * @return string
67
+ */
68
+ public static function getCookieValue($value)
69
+ {
70
+ if (substr($value, 0, 1) !== '"' &&
71
+ substr($value, -1, 1) !== '"' &&
72
+ strpbrk($value, ';,')
73
+ ) {
74
+ $value = '"' . $value . '"';
75
+ }
76
+
77
+ return $value;
78
+ }
79
+
80
+ public function toArray()
81
+ {
82
+ return array_map(function (SetCookie $cookie) {
83
+ return $cookie->toArray();
84
+ }, $this->getIterator()->getArrayCopy());
85
+ }
86
+
87
+ public function clear($domain = null, $path = null, $name = null)
88
+ {
89
+ if (!$domain) {
90
+ $this->cookies = [];
91
+ return;
92
+ } elseif (!$path) {
93
+ $this->cookies = array_filter(
94
+ $this->cookies,
95
+ function (SetCookie $cookie) use ($path, $domain) {
96
+ return !$cookie->matchesDomain($domain);
97
+ }
98
+ );
99
+ } elseif (!$name) {
100
+ $this->cookies = array_filter(
101
+ $this->cookies,
102
+ function (SetCookie $cookie) use ($path, $domain) {
103
+ return !($cookie->matchesPath($path) &&
104
+ $cookie->matchesDomain($domain));
105
+ }
106
+ );
107
+ } else {
108
+ $this->cookies = array_filter(
109
+ $this->cookies,
110
+ function (SetCookie $cookie) use ($path, $domain, $name) {
111
+ return !($cookie->getName() == $name &&
112
+ $cookie->matchesPath($path) &&
113
+ $cookie->matchesDomain($domain));
114
+ }
115
+ );
116
+ }
117
+ }
118
+
119
+ public function clearSessionCookies()
120
+ {
121
+ $this->cookies = array_filter(
122
+ $this->cookies,
123
+ function (SetCookie $cookie) {
124
+ return !$cookie->getDiscard() && $cookie->getExpires();
125
+ }
126
+ );
127
+ }
128
+
129
+ public function setCookie(SetCookie $cookie)
130
+ {
131
+ // Only allow cookies with set and valid domain, name, value
132
+ $result = $cookie->validate();
133
+ if ($result !== true) {
134
+ if ($this->strictMode) {
135
+ throw new \RuntimeException('Invalid cookie: ' . $result);
136
+ } else {
137
+ $this->removeCookieIfEmpty($cookie);
138
+ return false;
139
+ }
140
+ }
141
+
142
+ // Resolve conflicts with previously set cookies
143
+ foreach ($this->cookies as $i => $c) {
144
+
145
+ // Two cookies are identical, when their path, and domain are
146
+ // identical.
147
+ if ($c->getPath() != $cookie->getPath() ||
148
+ $c->getDomain() != $cookie->getDomain() ||
149
+ $c->getName() != $cookie->getName()
150
+ ) {
151
+ continue;
152
+ }
153
+
154
+ // The previously set cookie is a discard cookie and this one is
155
+ // not so allow the new cookie to be set
156
+ if (!$cookie->getDiscard() && $c->getDiscard()) {
157
+ unset($this->cookies[$i]);
158
+ continue;
159
+ }
160
+
161
+ // If the new cookie's expiration is further into the future, then
162
+ // replace the old cookie
163
+ if ($cookie->getExpires() > $c->getExpires()) {
164
+ unset($this->cookies[$i]);
165
+ continue;
166
+ }
167
+
168
+ // If the value has changed, we better change it
169
+ if ($cookie->getValue() !== $c->getValue()) {
170
+ unset($this->cookies[$i]);
171
+ continue;
172
+ }
173
+
174
+ // The cookie exists, so no need to continue
175
+ return false;
176
+ }
177
+
178
+ $this->cookies[] = $cookie;
179
+
180
+ return true;
181
+ }
182
+
183
+ public function count()
184
+ {
185
+ return count($this->cookies);
186
+ }
187
+
188
+ public function getIterator()
189
+ {
190
+ return new \ArrayIterator(array_values($this->cookies));
191
+ }
192
+
193
+ public function extractCookies(
194
+ RequestInterface $request,
195
+ ResponseInterface $response
196
+ ) {
197
+ if ($cookieHeader = $response->getHeaderAsArray('Set-Cookie')) {
198
+ foreach ($cookieHeader as $cookie) {
199
+ $sc = SetCookie::fromString($cookie);
200
+ if (!$sc->getDomain()) {
201
+ $sc->setDomain($request->getHost());
202
+ }
203
+ $this->setCookie($sc);
204
+ }
205
+ }
206
+ }
207
+
208
+ public function addCookieHeader(RequestInterface $request)
209
+ {
210
+ $values = [];
211
+ $scheme = $request->getScheme();
212
+ $host = $request->getHost();
213
+ $path = $request->getPath();
214
+
215
+ foreach ($this->cookies as $cookie) {
216
+ if ($cookie->matchesPath($path) &&
217
+ $cookie->matchesDomain($host) &&
218
+ !$cookie->isExpired() &&
219
+ (!$cookie->getSecure() || $scheme == 'https')
220
+ ) {
221
+ $values[] = $cookie->getName() . '='
222
+ . self::getCookieValue($cookie->getValue());
223
+ }
224
+ }
225
+
226
+ if ($values) {
227
+ $request->setHeader('Cookie', implode('; ', $values));
228
+ }
229
+ }
230
+
231
+ /**
232
+ * If a cookie already exists and the server asks to set it again with a
233
+ * null value, the cookie must be deleted.
234
+ *
235
+ * @param SetCookie $cookie
236
+ */
237
+ private function removeCookieIfEmpty(SetCookie $cookie)
238
+ {
239
+ $cookieValue = $cookie->getValue();
240
+ if ($cookieValue === null || $cookieValue === '') {
241
+ $this->clear(
242
+ $cookie->getDomain(),
243
+ $cookie->getPath(),
244
+ $cookie->getName()
245
+ );
246
+ }
247
+ }
248
+ }
backend/vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Cookie;
3
+
4
+ use GuzzleHttp\Message\RequestInterface;
5
+ use GuzzleHttp\Message\ResponseInterface;
6
+
7
+ /**
8
+ * Stores HTTP cookies.
9
+ *
10
+ * It extracts cookies from HTTP requests, and returns them in HTTP responses.
11
+ * CookieJarInterface instances automatically expire contained cookies when
12
+ * necessary. Subclasses are also responsible for storing and retrieving
13
+ * cookies from a file, database, etc.
14
+ *
15
+ * @link http://docs.python.org/2/library/cookielib.html Inspiration
16
+ */
17
+ interface CookieJarInterface extends \Countable, \IteratorAggregate
18
+ {
19
+ /**
20
+ * Add a Cookie header to a request.
21
+ *
22
+ * If no matching cookies are found in the cookie jar, then no Cookie
23
+ * header is added to the request.
24
+ *
25
+ * @param RequestInterface $request Request object to update
26
+ */
27
+ public function addCookieHeader(RequestInterface $request);
28
+
29
+ /**
30
+ * Extract cookies from an HTTP response and store them in the CookieJar.
31
+ *
32
+ * @param RequestInterface $request Request that was sent
33
+ * @param ResponseInterface $response Response that was received
34
+ */
35
+ public function extractCookies(
36
+ RequestInterface $request,
37
+ ResponseInterface $response
38
+ );
39
+
40
+ /**
41
+ * Sets a cookie in the cookie jar.
42
+ *
43
+ * @param SetCookie $cookie Cookie to set.
44
+ *
45
+ * @return bool Returns true on success or false on failure
46
+ */
47
+ public function setCookie(SetCookie $cookie);
48
+
49
+ /**
50
+ * Remove cookies currently held in the cookie jar.
51
+ *
52
+ * Invoking this method without arguments will empty the whole cookie jar.
53
+ * If given a $domain argument only cookies belonging to that domain will
54
+ * be removed. If given a $domain and $path argument, cookies belonging to
55
+ * the specified path within that domain are removed. If given all three
56
+ * arguments, then the cookie with the specified name, path and domain is
57
+ * removed.
58
+ *
59
+ * @param string $domain Clears cookies matching a domain
60
+ * @param string $path Clears cookies matching a domain and path
61
+ * @param string $name Clears cookies matching a domain, path, and name
62
+ *
63
+ * @return CookieJarInterface
64
+ */
65
+ public function clear($domain = null, $path = null, $name = null);
66
+
67
+ /**
68
+ * Discard all sessions cookies.
69
+ *
70
+ * Removes cookies that don't have an expire field or a have a discard
71
+ * field set to true. To be called when the user agent shuts down according
72
+ * to RFC 2965.
73
+ */
74
+ public function clearSessionCookies();
75
+ }
backend/vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Cookie;
3
+
4
+ use GuzzleHttp\Utils;
5
+
6
+ /**
7
+ * Persists non-session cookies using a JSON formatted file
8
+ */
9
+ class FileCookieJar extends CookieJar
10
+ {
11
+ /** @var string filename */
12
+ private $filename;
13
+
14
+ /**
15
+ * Create a new FileCookieJar object
16
+ *
17
+ * @param string $cookieFile File to store the cookie data
18
+ *
19
+ * @throws \RuntimeException if the file cannot be found or created
20
+ */
21
+ public function __construct($cookieFile)
22
+ {
23
+ $this->filename = $cookieFile;
24
+
25
+ if (file_exists($cookieFile)) {
26
+ $this->load($cookieFile);
27
+ }
28
+ }
29
+
30
+ /**
31
+ * Saves the file when shutting down
32
+ */
33
+ public function __destruct()
34
+ {
35
+ $this->save($this->filename);
36
+ }
37
+
38
+ /**
39
+ * Saves the cookies to a file.
40
+ *
41
+ * @param string $filename File to save
42
+ * @throws \RuntimeException if the file cannot be found or created
43
+ */
44
+ public function save($filename)
45
+ {
46
+ $json = [];
47
+ foreach ($this as $cookie) {
48
+ if ($cookie->getExpires() && !$cookie->getDiscard()) {
49
+ $json[] = $cookie->toArray();
50
+ }
51
+ }
52
+
53
+ if (false === file_put_contents($filename, json_encode($json))) {
54
+ // @codeCoverageIgnoreStart
55
+ throw new \RuntimeException("Unable to save file {$filename}");
56
+ // @codeCoverageIgnoreEnd
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Load cookies from a JSON formatted file.
62
+ *
63
+ * Old cookies are kept unless overwritten by newly loaded ones.
64
+ *
65
+ * @param string $filename Cookie file to load.
66
+ * @throws \RuntimeException if the file cannot be loaded.
67
+ */
68
+ public function load($filename)
69
+ {
70
+ $json = file_get_contents($filename);
71
+ if (false === $json) {
72
+ // @codeCoverageIgnoreStart
73
+ throw new \RuntimeException("Unable to load file {$filename}");
74
+ // @codeCoverageIgnoreEnd
75
+ }
76
+
77
+ $data = Utils::jsonDecode($json, true);
78
+ if (is_array($data)) {
79
+ foreach (Utils::jsonDecode($json, true) as $cookie) {
80
+ $this->setCookie(new SetCookie($cookie));
81
+ }
82
+ } elseif (strlen($data)) {
83
+ throw new \RuntimeException("Invalid cookie file: {$filename}");
84
+ }
85
+ }
86
+ }
backend/vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Cookie;
3
+
4
+ use GuzzleHttp\Utils;
5
+
6
+ /**
7
+ * Persists cookies in the client session
8
+ */
9
+ class SessionCookieJar extends CookieJar
10
+ {
11
+ /** @var string session key */
12
+ private $sessionKey;
13
+
14
+ /**
15
+ * Create a new SessionCookieJar object
16
+ *
17
+ * @param string $sessionKey Session key name to store the cookie data in session
18
+ */
19
+ public function __construct($sessionKey)
20
+ {
21
+ $this->sessionKey = $sessionKey;
22
+ $this->load();
23
+ }
24
+
25
+ /**
26
+ * Saves cookies to session when shutting down
27
+ */
28
+ public function __destruct()
29
+ {
30
+ $this->save();
31
+ }
32
+
33
+ /**
34
+ * Save cookies to the client session
35
+ */
36
+ public function save()
37
+ {
38
+ $json = [];
39
+ foreach ($this as $cookie) {
40
+ if ($cookie->getExpires() && !$cookie->getDiscard()) {
41
+ $json[] = $cookie->toArray();
42
+ }
43
+ }
44
+
45
+ $_SESSION[$this->sessionKey] = json_encode($json);
46
+ }
47
+
48
+ /**
49
+ * Load the contents of the client session into the data array
50
+ */
51
+ protected function load()
52
+ {
53
+ $cookieJar = isset($_SESSION[$this->sessionKey])
54
+ ? $_SESSION[$this->sessionKey]
55
+ : null;
56
+
57
+ $data = Utils::jsonDecode($cookieJar, true);
58
+ if (is_array($data)) {
59
+ foreach ($data as $cookie) {
60
+ $this->setCookie(new SetCookie($cookie));
61
+ }
62
+ } elseif (strlen($data)) {
63
+ throw new \RuntimeException("Invalid cookie data");
64
+ }
65
+ }
66
+ }
backend/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php ADDED
@@ -0,0 +1,373 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Cookie;
3
+
4
+ use GuzzleHttp\ToArrayInterface;
5
+
6
+ /**
7
+ * Set-Cookie object
8
+ */
9
+ class SetCookie implements ToArrayInterface
10
+ {
11
+ /** @var array */
12
+ private static $defaults = [
13
+ 'Name' => null,
14
+ 'Value' => null,
15
+ 'Domain' => null,
16
+ 'Path' => '/',
17
+ 'Max-Age' => null,
18
+ 'Expires' => null,
19
+ 'Secure' => false,
20
+ 'Discard' => false,
21
+ 'HttpOnly' => false
22
+ ];
23
+
24
+ /** @var array Cookie data */
25
+ private $data;
26
+
27
+ /**
28
+ * Create a new SetCookie object from a string
29
+ *
30
+ * @param string $cookie Set-Cookie header string
31
+ *
32
+ * @return self
33
+ */
34
+ public static function fromString($cookie)
35
+ {
36
+ // Create the default return array
37
+ $data = self::$defaults;
38
+ // Explode the cookie string using a series of semicolons
39
+ $pieces = array_filter(array_map('trim', explode(';', $cookie)));
40
+ // The name of the cookie (first kvp) must include an equal sign.
41
+ if (empty($pieces) || !strpos($pieces[0], '=')) {
42
+ return new self($data);
43
+ }
44
+
45
+ // Add the cookie pieces into the parsed data array
46
+ foreach ($pieces as $part) {
47
+
48
+ $cookieParts = explode('=', $part, 2);
49
+ $key = trim($cookieParts[0]);
50
+ $value = isset($cookieParts[1])
51
+ ? trim($cookieParts[1], " \n\r\t\0\x0B\"")
52
+ : true;
53
+
54
+ // Only check for non-cookies when cookies have been found
55
+ if (empty($data['Name'])) {
56
+ $data['Name'] = $key;
57
+ $data['Value'] = $value;
58
+ } else {
59
+ foreach (array_keys(self::$defaults) as $search) {
60
+ if (!strcasecmp($search, $key)) {
61
+ $data[$search] = $value;
62
+ continue 2;
63
+ }
64
+ }
65
+ $data[$key] = $value;
66
+ }
67
+ }
68
+
69
+ return new self($data);
70
+ }
71
+
72
+ /**
73
+ * @param array $data Array of cookie data provided by a Cookie parser
74
+ */
75
+ public function __construct(array $data = [])
76
+ {
77
+ $this->data = array_replace(self::$defaults, $data);
78
+ // Extract the Expires value and turn it into a UNIX timestamp if needed
79
+ if (!$this->getExpires() && $this->getMaxAge()) {
80
+ // Calculate the Expires date
81
+ $this->setExpires(time() + $this->getMaxAge());
82
+ } elseif ($this->getExpires() && !is_numeric($this->getExpires())) {
83
+ $this->setExpires($this->getExpires());
84
+ }
85
+ }
86
+
87
+ public function __toString()
88
+ {
89
+ $str = $this->data['Name'] . '=' . $this->data['Value'] . '; ';
90
+ foreach ($this->data as $k => $v) {
91
+ if ($k != 'Name' && $k != 'Value' && $v !== null && $v !== false) {
92
+ if ($k == 'Expires') {
93
+ $str .= 'Expires=' . gmdate('D, d M Y H:i:s \G\M\T', $v) . '; ';
94
+ } else {
95
+ $str .= ($v === true ? $k : "{$k}={$v}") . '; ';
96
+ }
97
+ }
98
+ }
99
+
100
+ return rtrim($str, '; ');
101
+ }
102
+
103
+ public function toArray()
104
+ {
105
+ return $this->data;
106
+ }
107
+
108
+ /**
109
+ * Get the cookie name
110
+ *
111
+ * @return string
112
+ */
113
+ public function getName()
114
+ {
115
+ return $this->data['Name'];
116
+ }
117
+
118
+ /**
119
+ * Set the cookie name
120
+ *
121
+ * @param string $name Cookie name
122
+ */
123
+ public function setName($name)
124
+ {
125
+ $this->data['Name'] = $name;
126
+ }
127
+
128
+ /**
129
+ * Get the cookie value
130
+ *
131
+ * @return string
132
+ */
133
+ public function getValue()
134
+ {
135
+ return $this->data['Value'];
136
+ }
137
+
138
+ /**
139
+ * Set the cookie value
140
+ *
141
+ * @param string $value Cookie value
142
+ */
143
+ public function setValue($value)
144
+ {
145
+ $this->data['Value'] = $value;
146
+ }
147
+
148
+ /**
149
+ * Get the domain
150
+ *
151
+ * @return string|null
152
+ */
153
+ public function getDomain()
154
+ {
155
+ return $this->data['Domain'];
156
+ }
157
+
158
+ /**
159
+ * Set the domain of the cookie
160
+ *
161
+ * @param string $domain
162
+ */
163
+ public function setDomain($domain)
164
+ {
165
+ $this->data['Domain'] = $domain;
166
+ }
167
+
168
+ /**
169
+ * Get the path
170
+ *
171
+ * @return string
172
+ */
173
+ public function getPath()
174
+ {
175
+ return $this->data['Path'];
176
+ }
177
+
178
+ /**
179
+ * Set the path of the cookie
180
+ *
181
+ * @param string $path Path of the cookie
182
+ */
183
+ public function setPath($path)
184
+ {
185
+ $this->data['Path'] = $path;
186
+ }
187
+
188
+ /**
189
+ * Maximum lifetime of the cookie in seconds
190
+ *
191
+ * @return int|null
192
+ */
193
+ public function getMaxAge()
194
+ {
195
+ return $this->data['Max-Age'];
196
+ }
197
+
198
+ /**
199
+ * Set the max-age of the cookie
200
+ *
201
+ * @param int $maxAge Max age of the cookie in seconds
202
+ */
203
+ public function setMaxAge($maxAge)
204
+ {
205
+ $this->data['Max-Age'] = $maxAge;
206
+ }
207
+
208
+ /**
209
+ * The UNIX timestamp when the cookie Expires
210
+ *
211
+ * @return mixed
212
+ */
213
+ public function getExpires()
214
+ {
215
+ return $this->data['Expires'];
216
+ }
217
+
218
+ /**
219
+ * Set the unix timestamp for which the cookie will expire
220
+ *
221
+ * @param int $timestamp Unix timestamp
222
+ */
223
+ public function setExpires($timestamp)
224
+ {
225
+ $this->data['Expires'] = is_numeric($timestamp)
226
+ ? (int) $timestamp
227
+ : strtotime($timestamp);
228
+ }
229
+
230
+ /**
231
+ * Get whether or not this is a secure cookie
232
+ *
233
+ * @return null|bool
234
+ */
235
+ public function getSecure()
236
+ {
237
+ return $this->data['Secure'];
238
+ }
239
+
240
+ /**
241
+ * Set whether or not the cookie is secure
242
+ *
243
+ * @param bool $secure Set to true or false if secure
244
+ */
245
+ public function setSecure($secure)
246
+ {
247
+ $this->data['Secure'] = $secure;
248
+ }
249
+
250
+ /**
251
+ * Get whether or not this is a session cookie
252
+ *
253
+ * @return null|bool
254
+ */
255
+ public function getDiscard()
256
+ {
257
+ return $this->data['Discard'];
258
+ }
259
+
260
+ /**
261
+ * Set whether or not this is a session cookie
262
+ *
263
+ * @param bool $discard Set to true or false if this is a session cookie
264
+ */
265
+ public function setDiscard($discard)
266
+ {
267
+ $this->data['Discard'] = $discard;
268
+ }
269
+
270
+ /**
271
+ * Get whether or not this is an HTTP only cookie
272
+ *
273
+ * @return bool
274
+ */
275
+ public function getHttpOnly()
276
+ {
277
+ return $this->data['HttpOnly'];
278
+ }
279
+
280
+ /**
281
+ * Set whether or not this is an HTTP only cookie
282
+ *
283
+ * @param bool $httpOnly Set to true or false if this is HTTP only
284
+ */
285
+ public function setHttpOnly($httpOnly)
286
+ {
287
+ $this->data['HttpOnly'] = $httpOnly;
288
+ }
289
+
290
+ /**
291
+ * Check if the cookie matches a path value
292
+ *
293
+ * @param string $path Path to check against
294
+ *
295
+ * @return bool
296
+ */
297
+ public function matchesPath($path)
298
+ {
299
+ return !$this->getPath() || 0 === stripos($path, $this->getPath());
300
+ }
301
+
302
+ /**
303
+ * Check if the cookie matches a domain value
304
+ *
305
+ * @param string $domain Domain to check against
306
+ *
307
+ * @return bool
308
+ */
309
+ public function matchesDomain($domain)
310
+ {
311
+ // Remove the leading '.' as per spec in RFC 6265.
312
+ // http://tools.ietf.org/html/rfc6265#section-5.2.3
313
+ $cookieDomain = ltrim($this->getDomain(), '.');
314
+
315
+ // Domain not set or exact match.
316
+ if (!$cookieDomain || !strcasecmp($domain, $cookieDomain)) {
317
+ return true;
318
+ }
319
+
320
+ // Matching the subdomain according to RFC 6265.
321
+ // http://tools.ietf.org/html/rfc6265#section-5.1.3
322
+ if (filter_var($domain, FILTER_VALIDATE_IP)) {
323
+ return false;
324
+ }
325
+
326
+ return (bool) preg_match('/\.' . preg_quote($cookieDomain) . '$/i', $domain);
327
+ }
328
+
329
+ /**
330
+ * Check if the cookie is expired
331
+ *
332
+ * @return bool
333
+ */
334
+ public function isExpired()
335
+ {
336
+ return $this->getExpires() && time() > $this->getExpires();
337
+ }
338
+
339
+ /**
340
+ * Check if the cookie is valid according to RFC 6265
341
+ *
342
+ * @return bool|string Returns true if valid or an error message if invalid
343
+ */
344
+ public function validate()
345
+ {
346
+ // Names must not be empty, but can be 0
347
+ $name = $this->getName();
348
+ if (empty($name) && !is_numeric($name)) {
349
+ return 'The cookie name must not be empty';
350
+ }
351
+
352
+ // Check if any of the invalid characters are present in the cookie name
353
+ if (preg_match("/[=,; \t\r\n\013\014]/", $name)) {
354
+ return "Cookie name must not cannot invalid characters: =,; \\t\\r\\n\\013\\014";
355
+ }
356
+
357
+ // Value must not be empty, but can be 0
358
+ $value = $this->getValue();
359
+ if (empty($value) && !is_numeric($value)) {
360
+ return 'The cookie value must not be empty';
361
+ }
362
+
363
+ // Domains must not be empty, but can be 0
364
+ // A "0" is not a valid internet domain, but may be used as server name
365
+ // in a private network.
366
+ $domain = $this->getDomain();
367
+ if (empty($domain) && !is_numeric($domain)) {
368
+ return 'The cookie domain must not be empty';
369
+ }
370
+
371
+ return true;
372
+ }
373
+ }
backend/vendor/guzzlehttp/guzzle/src/Event/AbstractEvent.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ /**
5
+ * Basic event class that can be extended.
6
+ */
7
+ abstract class AbstractEvent implements EventInterface
8
+ {
9
+ private $propagationStopped = false;
10
+
11
+ public function isPropagationStopped()
12
+ {
13
+ return $this->propagationStopped;
14
+ }
15
+
16
+ public function stopPropagation()
17
+ {
18
+ $this->propagationStopped = true;
19
+ }
20
+ }
backend/vendor/guzzlehttp/guzzle/src/Event/AbstractRequestEvent.php ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ use GuzzleHttp\Transaction;
5
+ use GuzzleHttp\ClientInterface;
6
+ use GuzzleHttp\Message\RequestInterface;
7
+
8
+ /**
9
+ * Base class for request events, providing a request and client getter.
10
+ */
11
+ abstract class AbstractRequestEvent extends AbstractEvent
12
+ {
13
+ /** @var Transaction */
14
+ protected $transaction;
15
+
16
+ /**
17
+ * @param Transaction $transaction
18
+ */
19
+ public function __construct(Transaction $transaction)
20
+ {
21
+ $this->transaction = $transaction;
22
+ }
23
+
24
+ /**
25
+ * Get the HTTP client associated with the event.
26
+ *
27
+ * @return ClientInterface
28
+ */
29
+ public function getClient()
30
+ {
31
+ return $this->transaction->client;
32
+ }
33
+
34
+ /**
35
+ * Get the request object
36
+ *
37
+ * @return RequestInterface
38
+ */
39
+ public function getRequest()
40
+ {
41
+ return $this->transaction->request;
42
+ }
43
+
44
+ /**
45
+ * @return Transaction
46
+ */
47
+ protected function getTransaction()
48
+ {
49
+ return $this->transaction;
50
+ }
51
+ }
backend/vendor/guzzlehttp/guzzle/src/Event/AbstractRetryableEvent.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ /**
5
+ * Abstract request event that can be retried.
6
+ */
7
+ class AbstractRetryableEvent extends AbstractTransferEvent
8
+ {
9
+ /**
10
+ * Mark the request as needing a retry and stop event propagation.
11
+ *
12
+ * This action allows you to retry a request without emitting the "end"
13
+ * event multiple times for a given request. When retried, the request
14
+ * emits a before event and is then sent again using the client that sent
15
+ * the original request.
16
+ *
17
+ * When retrying, it is important to limit the number of retries you allow
18
+ * to prevent infinite loops.
19
+ *
20
+ * This action can only be taken during the "complete" and "error" events.
21
+ *
22
+ * @param int $afterDelay If specified, the amount of time in milliseconds
23
+ * to delay before retrying. Note that this must
24
+ * be supported by the underlying RingPHP handler
25
+ * to work properly. Set to 0 or provide no value
26
+ * to retry immediately.
27
+ */
28
+ public function retry($afterDelay = 0)
29
+ {
30
+ // Setting the transition state to 'retry' will cause the next state
31
+ // transition of the transaction to retry the request.
32
+ $this->transaction->state = 'retry';
33
+
34
+ if ($afterDelay) {
35
+ $this->transaction->request->getConfig()->set('delay', $afterDelay);
36
+ }
37
+
38
+ $this->stopPropagation();
39
+ }
40
+ }
backend/vendor/guzzlehttp/guzzle/src/Event/AbstractTransferEvent.php ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ use GuzzleHttp\Message\ResponseInterface;
5
+ use GuzzleHttp\Ring\Future\FutureInterface;
6
+
7
+ /**
8
+ * Event that contains transfer statistics, and can be intercepted.
9
+ */
10
+ abstract class AbstractTransferEvent extends AbstractRequestEvent
11
+ {
12
+ /**
13
+ * Get all transfer information as an associative array if no $name
14
+ * argument is supplied, or gets a specific transfer statistic if
15
+ * a $name attribute is supplied (e.g., 'total_time').
16
+ *
17
+ * @param string $name Name of the transfer stat to retrieve
18
+ *
19
+ * @return mixed|null|array
20
+ */
21
+ public function getTransferInfo($name = null)
22
+ {
23
+ if (!$name) {
24
+ return $this->transaction->transferInfo;
25
+ }
26
+
27
+ return isset($this->transaction->transferInfo[$name])
28
+ ? $this->transaction->transferInfo[$name]
29
+ : null;
30
+ }
31
+
32
+ /**
33
+ * Get the number of transaction retries.
34
+ *
35
+ * @return int
36
+ */
37
+ public function getRetryCount()
38
+ {
39
+ return $this->transaction->retries;
40
+ }
41
+
42
+ /**
43
+ * Returns true/false if a response is available.
44
+ *
45
+ * @return bool
46
+ */
47
+ public function hasResponse()
48
+ {
49
+ return !($this->transaction->response instanceof FutureInterface);
50
+ }
51
+
52
+ /**
53
+ * Get the response.
54
+ *
55
+ * @return ResponseInterface|null
56
+ */
57
+ public function getResponse()
58
+ {
59
+ return $this->hasResponse() ? $this->transaction->response : null;
60
+ }
61
+
62
+ /**
63
+ * Intercept the request and associate a response
64
+ *
65
+ * @param ResponseInterface $response Response to set
66
+ */
67
+ public function intercept(ResponseInterface $response)
68
+ {
69
+ $this->transaction->response = $response;
70
+ $this->transaction->exception = null;
71
+ $this->stopPropagation();
72
+ }
73
+ }
backend/vendor/guzzlehttp/guzzle/src/Event/BeforeEvent.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ use GuzzleHttp\Message\ResponseInterface;
5
+
6
+ /**
7
+ * Event object emitted before a request is sent.
8
+ *
9
+ * This event MAY be emitted multiple times (i.e., if a request is retried).
10
+ * You MAY change the Response associated with the request using the
11
+ * intercept() method of the event.
12
+ */
13
+ class BeforeEvent extends AbstractRequestEvent
14
+ {
15
+ /**
16
+ * Intercept the request and associate a response
17
+ *
18
+ * @param ResponseInterface $response Response to set
19
+ */
20
+ public function intercept(ResponseInterface $response)
21
+ {
22
+ $this->transaction->response = $response;
23
+ $this->transaction->exception = null;
24
+ $this->stopPropagation();
25
+ }
26
+ }
backend/vendor/guzzlehttp/guzzle/src/Event/CompleteEvent.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ /**
5
+ * Event object emitted after a request has been completed.
6
+ *
7
+ * This event MAY be emitted multiple times for a single request. You MAY
8
+ * change the Response associated with the request using the intercept()
9
+ * method of the event.
10
+ *
11
+ * This event allows the request to be retried if necessary using the retry()
12
+ * method of the event.
13
+ */
14
+ class CompleteEvent extends AbstractRetryableEvent {}
backend/vendor/guzzlehttp/guzzle/src/Event/Emitter.php ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ /**
5
+ * Guzzle event emitter.
6
+ *
7
+ * Some of this class is based on the Symfony EventDispatcher component, which
8
+ * ships with the following license:
9
+ *
10
+ * This file is part of the Symfony package.
11
+ *
12
+ * (c) Fabien Potencier <fabien@symfony.com>
13
+ *
14
+ * For the full copyright and license information, please view the LICENSE
15
+ * file that was distributed with this source code.
16
+ *
17
+ * @link https://github.com/symfony/symfony/tree/master/src/Symfony/Component/EventDispatcher
18
+ */
19
+ class Emitter implements EmitterInterface
20
+ {
21
+ /** @var array */
22
+ private $listeners = [];
23
+
24
+ /** @var array */
25
+ private $sorted = [];
26
+
27
+ public function on($eventName, callable $listener, $priority = 0)
28
+ {
29
+ if ($priority === 'first') {
30
+ $priority = isset($this->listeners[$eventName])
31
+ ? max(array_keys($this->listeners[$eventName])) + 1
32
+ : 1;
33
+ } elseif ($priority === 'last') {
34
+ $priority = isset($this->listeners[$eventName])
35
+ ? min(array_keys($this->listeners[$eventName])) - 1
36
+ : -1;
37
+ }
38
+
39
+ $this->listeners[$eventName][$priority][] = $listener;
40
+ unset($this->sorted[$eventName]);
41
+ }
42
+
43
+ public function once($eventName, callable $listener, $priority = 0)
44
+ {
45
+ $onceListener = function (
46
+ EventInterface $event,
47
+ $eventName
48
+ ) use (&$onceListener, $eventName, $listener, $priority) {
49
+ $this->removeListener($eventName, $onceListener);
50
+ $listener($event, $eventName, $this);
51
+ };
52
+
53
+ $this->on($eventName, $onceListener, $priority);
54
+ }
55
+
56
+ public function removeListener($eventName, callable $listener)
57
+ {
58
+ if (empty($this->listeners[$eventName])) {
59
+ return;
60
+ }
61
+
62
+ foreach ($this->listeners[$eventName] as $priority => $listeners) {
63
+ if (false !== ($key = array_search($listener, $listeners, true))) {
64
+ unset(
65
+ $this->listeners[$eventName][$priority][$key],
66
+ $this->sorted[$eventName]
67
+ );
68
+ }
69
+ }
70
+ }
71
+
72
+ public function listeners($eventName = null)
73
+ {
74
+ // Return all events in a sorted priority order
75
+ if ($eventName === null) {
76
+ foreach (array_keys($this->listeners) as $eventName) {
77
+ if (empty($this->sorted[$eventName])) {
78
+ $this->listeners($eventName);
79
+ }
80
+ }
81
+ return $this->sorted;
82
+ }
83
+
84
+ // Return the listeners for a specific event, sorted in priority order
85
+ if (empty($this->sorted[$eventName])) {
86
+ $this->sorted[$eventName] = [];
87
+ if (isset($this->listeners[$eventName])) {
88
+ krsort($this->listeners[$eventName], SORT_NUMERIC);
89
+ foreach ($this->listeners[$eventName] as $listeners) {
90
+ foreach ($listeners as $listener) {
91
+ $this->sorted[$eventName][] = $listener;
92
+ }
93
+ }
94
+ }
95
+ }
96
+
97
+ return $this->sorted[$eventName];
98
+ }
99
+
100
+ public function hasListeners($eventName)
101
+ {
102
+ return !empty($this->listeners[$eventName]);
103
+ }
104
+
105
+ public function emit($eventName, EventInterface $event)
106
+ {
107
+ if (isset($this->listeners[$eventName])) {
108
+ foreach ($this->listeners($eventName) as $listener) {
109
+ $listener($event, $eventName);
110
+ if ($event->isPropagationStopped()) {
111
+ break;
112
+ }
113
+ }
114
+ }
115
+
116
+ return $event;
117
+ }
118
+
119
+ public function attach(SubscriberInterface $subscriber)
120
+ {
121
+ foreach ($subscriber->getEvents() as $eventName => $listeners) {
122
+ if (is_array($listeners[0])) {
123
+ foreach ($listeners as $listener) {
124
+ $this->on(
125
+ $eventName,
126
+ [$subscriber, $listener[0]],
127
+ isset($listener[1]) ? $listener[1] : 0
128
+ );
129
+ }
130
+ } else {
131
+ $this->on(
132
+ $eventName,
133
+ [$subscriber, $listeners[0]],
134
+ isset($listeners[1]) ? $listeners[1] : 0
135
+ );
136
+ }
137
+ }
138
+ }
139
+
140
+ public function detach(SubscriberInterface $subscriber)
141
+ {
142
+ foreach ($subscriber->getEvents() as $eventName => $listener) {
143
+ $this->removeListener($eventName, [$subscriber, $listener[0]]);
144
+ }
145
+ }
146
+ }
backend/vendor/guzzlehttp/guzzle/src/Event/EmitterInterface.php ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ /**
5
+ * Guzzle event emitter.
6
+ */
7
+ interface EmitterInterface
8
+ {
9
+ /**
10
+ * Binds a listener to a specific event.
11
+ *
12
+ * @param string $eventName Name of the event to bind to.
13
+ * @param callable $listener Listener to invoke when triggered.
14
+ * @param int|string $priority The higher this value, the earlier an event
15
+ * listener will be triggered in the chain (defaults to 0). You can
16
+ * pass "first" or "last" to dynamically specify the event priority
17
+ * based on the current event priorities associated with the given
18
+ * event name in the emitter. Use "first" to set the priority to the
19
+ * current highest priority plus one. Use "last" to set the priority to
20
+ * the current lowest event priority minus one.
21
+ */
22
+ public function on($eventName, callable $listener, $priority = 0);
23
+
24
+ /**
25
+ * Binds a listener to a specific event. After the listener is triggered
26
+ * once, it is removed as a listener.
27
+ *
28
+ * @param string $eventName Name of the event to bind to.
29
+ * @param callable $listener Listener to invoke when triggered.
30
+ * @param int $priority The higher this value, the earlier an event
31
+ * listener will be triggered in the chain (defaults to 0)
32
+ */
33
+ public function once($eventName, callable $listener, $priority = 0);
34
+
35
+ /**
36
+ * Removes an event listener from the specified event.
37
+ *
38
+ * @param string $eventName The event to remove a listener from
39
+ * @param callable $listener The listener to remove
40
+ */
41
+ public function removeListener($eventName, callable $listener);
42
+
43
+ /**
44
+ * Gets the listeners of a specific event or all listeners if no event is
45
+ * specified.
46
+ *
47
+ * @param string $eventName The name of the event. Pass null (the default)
48
+ * to retrieve all listeners.
49
+ *
50
+ * @return array The event listeners for the specified event, or all event
51
+ * listeners by event name. The format of the array when retrieving a
52
+ * specific event list is an array of callables. The format of the array
53
+ * when retrieving all listeners is an associative array of arrays of
54
+ * callables.
55
+ */
56
+ public function listeners($eventName = null);
57
+
58
+ /**
59
+ * Checks if the emitter has listeners by the given name.
60
+ *
61
+ * @param string $eventName The name of the event to check.
62
+ *
63
+ * @return bool
64
+ */
65
+ public function hasListeners($eventName);
66
+
67
+ /**
68
+ * Emits an event to all registered listeners.
69
+ *
70
+ * Each event that is bound to the emitted eventName receives a
71
+ * EventInterface, the name of the event, and the event emitter.
72
+ *
73
+ * @param string $eventName The name of the event to dispatch.
74
+ * @param EventInterface $event The event to pass to the event handlers/listeners.
75
+ *
76
+ * @return EventInterface Returns the provided event object
77
+ */
78
+ public function emit($eventName, EventInterface $event);
79
+
80
+ /**
81
+ * Attaches an event subscriber.
82
+ *
83
+ * The subscriber is asked for all the events it is interested in and added
84
+ * as an event listener for each event.
85
+ *
86
+ * @param SubscriberInterface $subscriber Subscriber to attach.
87
+ */
88
+ public function attach(SubscriberInterface $subscriber);
89
+
90
+ /**
91
+ * Detaches an event subscriber.
92
+ *
93
+ * @param SubscriberInterface $subscriber Subscriber to detach.
94
+ */
95
+ public function detach(SubscriberInterface $subscriber);
96
+ }
backend/vendor/guzzlehttp/guzzle/src/Event/EndEvent.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ /**
5
+ * A terminal event that is emitted when a request transaction has ended.
6
+ *
7
+ * This event is emitted for both successful responses and responses that
8
+ * encountered an exception. You need to check if an exception is present
9
+ * in your listener to know the difference.
10
+ *
11
+ * You MAY intercept the response associated with the event if needed, but keep
12
+ * in mind that the "complete" event will not be triggered as a result.
13
+ */
14
+ class EndEvent extends AbstractTransferEvent
15
+ {
16
+ /**
17
+ * Get the exception that was encountered (if any).
18
+ *
19
+ * This method should be used to check if the request was sent successfully
20
+ * or if it encountered errors.
21
+ *
22
+ * @return \Exception|null
23
+ */
24
+ public function getException()
25
+ {
26
+ return $this->transaction->exception;
27
+ }
28
+ }
backend/vendor/guzzlehttp/guzzle/src/Event/ErrorEvent.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ use GuzzleHttp\Exception\RequestException;
5
+
6
+ /**
7
+ * Event emitted when an error occurs while sending a request.
8
+ *
9
+ * This event MAY be emitted multiple times. You MAY intercept the exception
10
+ * and inject a response into the event to rescue the request using the
11
+ * intercept() method of the event.
12
+ *
13
+ * This event allows the request to be retried using the "retry" method of the
14
+ * event.
15
+ */
16
+ class ErrorEvent extends AbstractRetryableEvent
17
+ {
18
+ /**
19
+ * Get the exception that was encountered
20
+ *
21
+ * @return RequestException
22
+ */
23
+ public function getException()
24
+ {
25
+ return $this->transaction->exception;
26
+ }
27
+ }
backend/vendor/guzzlehttp/guzzle/src/Event/EventInterface.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ /**
5
+ * Base event interface used when dispatching events to listeners using an
6
+ * event emitter.
7
+ */
8
+ interface EventInterface
9
+ {
10
+ /**
11
+ * Returns whether or not stopPropagation was called on the event.
12
+ *
13
+ * @return bool
14
+ * @see Event::stopPropagation
15
+ */
16
+ public function isPropagationStopped();
17
+
18
+ /**
19
+ * Stops the propagation of the event, preventing subsequent listeners
20
+ * registered to the same event from being invoked.
21
+ */
22
+ public function stopPropagation();
23
+ }
backend/vendor/guzzlehttp/guzzle/src/Event/HasEmitterInterface.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ /**
5
+ * Holds an event emitter
6
+ */
7
+ interface HasEmitterInterface
8
+ {
9
+ /**
10
+ * Get the event emitter of the object
11
+ *
12
+ * @return EmitterInterface
13
+ */
14
+ public function getEmitter();
15
+ }
backend/vendor/guzzlehttp/guzzle/src/Event/HasEmitterTrait.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ /**
5
+ * Trait that implements the methods of HasEmitterInterface
6
+ */
7
+ trait HasEmitterTrait
8
+ {
9
+ /** @var EmitterInterface */
10
+ private $emitter;
11
+
12
+ public function getEmitter()
13
+ {
14
+ if (!$this->emitter) {
15
+ $this->emitter = new Emitter();
16
+ }
17
+
18
+ return $this->emitter;
19
+ }
20
+ }
backend/vendor/guzzlehttp/guzzle/src/Event/ListenerAttacherTrait.php ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ /**
5
+ * Trait that provides methods for extract event listeners specified in an array
6
+ * and attaching them to an emitter owned by the object or one of its direct
7
+ * dependencies.
8
+ */
9
+ trait ListenerAttacherTrait
10
+ {
11
+ /**
12
+ * Attaches event listeners and properly sets their priorities and whether
13
+ * or not they are are only executed once.
14
+ *
15
+ * @param HasEmitterInterface $object Object that has the event emitter.
16
+ * @param array $listeners Array of hashes representing event
17
+ * event listeners. Each item contains
18
+ * "name", "fn", "priority", & "once".
19
+ */
20
+ private function attachListeners(HasEmitterInterface $object, array $listeners)
21
+ {
22
+ $emitter = $object->getEmitter();
23
+ foreach ($listeners as $el) {
24
+ if ($el['once']) {
25
+ $emitter->once($el['name'], $el['fn'], $el['priority']);
26
+ } else {
27
+ $emitter->on($el['name'], $el['fn'], $el['priority']);
28
+ }
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Extracts the allowed events from the provided array, and ignores anything
34
+ * else in the array. The event listener must be specified as a callable or
35
+ * as an array of event listener data ("name", "fn", "priority", "once").
36
+ *
37
+ * @param array $source Array containing callables or hashes of data to be
38
+ * prepared as event listeners.
39
+ * @param array $events Names of events to look for in the provided $source
40
+ * array. Other keys are ignored.
41
+ * @return array
42
+ */
43
+ private function prepareListeners(array $source, array $events)
44
+ {
45
+ $listeners = [];
46
+ foreach ($events as $name) {
47
+ if (isset($source[$name])) {
48
+ $this->buildListener($name, $source[$name], $listeners);
49
+ }
50
+ }
51
+
52
+ return $listeners;
53
+ }
54
+
55
+ /**
56
+ * Creates a complete event listener definition from the provided array of
57
+ * listener data. Also works recursively if more than one listeners are
58
+ * contained in the provided array.
59
+ *
60
+ * @param string $name Name of the event the listener is for.
61
+ * @param array|callable $data Event listener data to prepare.
62
+ * @param array $listeners Array of listeners, passed by reference.
63
+ *
64
+ * @throws \InvalidArgumentException if the event data is malformed.
65
+ */
66
+ private function buildListener($name, $data, &$listeners)
67
+ {
68
+ static $defaults = ['priority' => 0, 'once' => false];
69
+
70
+ // If a callable is provided, normalize it to the array format.
71
+ if (is_callable($data)) {
72
+ $data = ['fn' => $data];
73
+ }
74
+
75
+ // Prepare the listener and add it to the array, recursively.
76
+ if (isset($data['fn'])) {
77
+ $data['name'] = $name;
78
+ $listeners[] = $data + $defaults;
79
+ } elseif (is_array($data)) {
80
+ foreach ($data as $listenerData) {
81
+ $this->buildListener($name, $listenerData, $listeners);
82
+ }
83
+ } else {
84
+ throw new \InvalidArgumentException('Each event listener must be a '
85
+ . 'callable or an associative array containing a "fn" key.');
86
+ }
87
+ }
88
+ }
backend/vendor/guzzlehttp/guzzle/src/Event/ProgressEvent.php ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ use GuzzleHttp\Transaction;
5
+
6
+ /**
7
+ * Event object emitted when upload or download progress is made.
8
+ *
9
+ * You can access the progress values using their corresponding public
10
+ * properties:
11
+ *
12
+ * - $downloadSize: The number of bytes that will be downloaded (if known)
13
+ * - $downloaded: The number of bytes that have been downloaded
14
+ * - $uploadSize: The number of bytes that will be uploaded (if known)
15
+ * - $uploaded: The number of bytes that have been uploaded
16
+ */
17
+ class ProgressEvent extends AbstractRequestEvent
18
+ {
19
+ /** @var int Amount of data to be downloaded */
20
+ public $downloadSize;
21
+
22
+ /** @var int Amount of data that has been downloaded */
23
+ public $downloaded;
24
+
25
+ /** @var int Amount of data to upload */
26
+ public $uploadSize;
27
+
28
+ /** @var int Amount of data that has been uploaded */
29
+ public $uploaded;
30
+
31
+ /**
32
+ * @param Transaction $transaction Transaction being sent.
33
+ * @param int $downloadSize Amount of data to download (if known)
34
+ * @param int $downloaded Amount of data that has been downloaded
35
+ * @param int $uploadSize Amount of data to upload (if known)
36
+ * @param int $uploaded Amount of data that had been uploaded
37
+ */
38
+ public function __construct(
39
+ Transaction $transaction,
40
+ $downloadSize,
41
+ $downloaded,
42
+ $uploadSize,
43
+ $uploaded
44
+ ) {
45
+ parent::__construct($transaction);
46
+ $this->downloadSize = $downloadSize;
47
+ $this->downloaded = $downloaded;
48
+ $this->uploadSize = $uploadSize;
49
+ $this->uploaded = $uploaded;
50
+ }
51
+ }
backend/vendor/guzzlehttp/guzzle/src/Event/RequestEvents.php ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ /**
5
+ * Contains methods used to manage the request event lifecycle.
6
+ */
7
+ final class RequestEvents
8
+ {
9
+ // Generic event priorities
10
+ const EARLY = 10000;
11
+ const LATE = -10000;
12
+
13
+ // "before" priorities
14
+ const PREPARE_REQUEST = -100;
15
+ const SIGN_REQUEST = -10000;
16
+
17
+ // "complete" and "error" response priorities
18
+ const VERIFY_RESPONSE = 100;
19
+ const REDIRECT_RESPONSE = 200;
20
+
21
+ /**
22
+ * Converts an array of event options into a formatted array of valid event
23
+ * configuration.
24
+ *
25
+ * @param array $options Event array to convert
26
+ * @param array $events Event names to convert in the options array.
27
+ * @param mixed $handler Event handler to utilize
28
+ *
29
+ * @return array
30
+ * @throws \InvalidArgumentException if the event config is invalid
31
+ * @internal
32
+ */
33
+ public static function convertEventArray(
34
+ array $options,
35
+ array $events,
36
+ $handler
37
+ ) {
38
+ foreach ($events as $name) {
39
+ if (!isset($options[$name])) {
40
+ $options[$name] = [$handler];
41
+ } elseif (is_callable($options[$name])) {
42
+ $options[$name] = [$options[$name], $handler];
43
+ } elseif (is_array($options[$name])) {
44
+ if (isset($options[$name]['fn'])) {
45
+ $options[$name] = [$options[$name], $handler];
46
+ } else {
47
+ $options[$name][] = $handler;
48
+ }
49
+ } else {
50
+ throw new \InvalidArgumentException('Invalid event format');
51
+ }
52
+ }
53
+
54
+ return $options;
55
+ }
56
+ }
backend/vendor/guzzlehttp/guzzle/src/Event/SubscriberInterface.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ /**
5
+ * SubscriberInterface provides an array of events to an
6
+ * EventEmitterInterface when it is registered. The emitter then binds the
7
+ * listeners specified by the EventSubscriber.
8
+ *
9
+ * This interface is based on the SubscriberInterface of the Symfony.
10
+ * @link https://github.com/symfony/symfony/tree/master/src/Symfony/Component/EventDispatcher
11
+ */
12
+ interface SubscriberInterface
13
+ {
14
+ /**
15
+ * Returns an array of event names this subscriber wants to listen to.
16
+ *
17
+ * The returned array keys MUST map to an event name. Each array value
18
+ * MUST be an array in which the first element is the name of a function
19
+ * on the EventSubscriber OR an array of arrays in the aforementioned
20
+ * format. The second element in the array is optional, and if specified,
21
+ * designates the event priority.
22
+ *
23
+ * For example, the following are all valid:
24
+ *
25
+ * - ['eventName' => ['methodName']]
26
+ * - ['eventName' => ['methodName', $priority]]
27
+ * - ['eventName' => [['methodName'], ['otherMethod']]
28
+ * - ['eventName' => [['methodName'], ['otherMethod', $priority]]
29
+ * - ['eventName' => [['methodName', $priority], ['otherMethod', $priority]]
30
+ *
31
+ * @return array
32
+ */
33
+ public function getEvents();
34
+ }
backend/vendor/guzzlehttp/guzzle/src/Exception/BadResponseException.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ /**
5
+ * Exception when an HTTP error occurs (4xx or 5xx error)
6
+ */
7
+ class BadResponseException extends RequestException {}
backend/vendor/guzzlehttp/guzzle/src/Exception/ClientException.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ /**
5
+ * Exception when a client error is encountered (4xx codes)
6
+ */
7
+ class ClientException extends BadResponseException {}
backend/vendor/guzzlehttp/guzzle/src/Exception/ConnectException.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ class ConnectException extends RequestException {}
backend/vendor/guzzlehttp/guzzle/src/Exception/CouldNotRewindStreamException.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ class CouldNotRewindStreamException extends RequestException {}
backend/vendor/guzzlehttp/guzzle/src/Exception/ParseException.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ use GuzzleHttp\Message\ResponseInterface;
5
+
6
+ /**
7
+ * Exception when a client is unable to parse the response body as XML or JSON
8
+ */
9
+ class ParseException extends TransferException
10
+ {
11
+ /** @var ResponseInterface */
12
+ private $response;
13
+
14
+ public function __construct(
15
+ $message = '',
16
+ ResponseInterface $response = null,
17
+ \Exception $previous = null
18
+ ) {
19
+ parent::__construct($message, 0, $previous);
20
+ $this->response = $response;
21
+ }
22
+ /**
23
+ * Get the associated response
24
+ *
25
+ * @return ResponseInterface|null
26
+ */
27
+ public function getResponse()
28
+ {
29
+ return $this->response;
30
+ }
31
+ }
backend/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ use GuzzleHttp\Message\RequestInterface;
5
+ use GuzzleHttp\Message\ResponseInterface;
6
+ use GuzzleHttp\Ring\Exception\ConnectException;
7
+ use GuzzleHttp\Exception\ConnectException as HttpConnectException;
8
+ use GuzzleHttp\Ring\Future\FutureInterface;
9
+
10
+ /**
11
+ * HTTP Request exception
12
+ */
13
+ class RequestException extends TransferException
14
+ {
15
+ /** @var RequestInterface */
16
+ private $request;
17
+
18
+ /** @var ResponseInterface */
19
+ private $response;
20
+
21
+ public function __construct(
22
+ $message,
23
+ RequestInterface $request,
24
+ ResponseInterface $response = null,
25
+ \Exception $previous = null
26
+ ) {
27
+ // Set the code of the exception if the response is set and not future.
28
+ $code = $response && !($response instanceof FutureInterface)
29
+ ? $response->getStatusCode()
30
+ : 0;
31
+ parent::__construct($message, $code, $previous);
32
+ $this->request = $request;
33
+ $this->response = $response;
34
+ }
35
+
36
+ /**
37
+ * Wrap non-RequesExceptions with a RequestException
38
+ *
39
+ * @param RequestInterface $request
40
+ * @param \Exception $e
41
+ *
42
+ * @return RequestException
43
+ */
44
+ public static function wrapException(RequestInterface $request, \Exception $e)
45
+ {
46
+ if ($e instanceof RequestException) {
47
+ return $e;
48
+ } elseif ($e instanceof ConnectException) {
49
+ return new HttpConnectException($e->getMessage(), $request, null, $e);
50
+ } else {
51
+ return new RequestException($e->getMessage(), $request, null, $e);
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Factory method to create a new exception with a normalized error message
57
+ *
58
+ * @param RequestInterface $request Request
59
+ * @param ResponseInterface $response Response received
60
+ * @param \Exception $previous Previous exception
61
+ *
62
+ * @return self
63
+ */
64
+ public static function create(
65
+ RequestInterface $request,
66
+ ResponseInterface $response = null,
67
+ \Exception $previous = null
68
+ ) {
69
+ if (!$response) {
70
+ return new self('Error completing request', $request, null, $previous);
71
+ }
72
+
73
+ $level = floor($response->getStatusCode() / 100);
74
+ if ($level == '4') {
75
+ $label = 'Client error response';
76
+ $className = __NAMESPACE__ . '\\ClientException';
77
+ } elseif ($level == '5') {
78
+ $label = 'Server error response';
79
+ $className = __NAMESPACE__ . '\\ServerException';
80
+ } else {
81
+ $label = 'Unsuccessful response';
82
+ $className = __CLASS__;
83
+ }
84
+
85
+ $message = $label . ' [url] ' . $request->getUrl()
86
+ . ' [status code] ' . $response->getStatusCode()
87
+ . ' [reason phrase] ' . $response->getReasonPhrase();
88
+
89
+ return new $className($message, $request, $response, $previous);
90
+ }
91
+
92
+ /**
93
+ * Get the request that caused the exception
94
+ *
95
+ * @return RequestInterface
96
+ */
97
+ public function getRequest()
98
+ {
99
+ return $this->request;
100
+ }
101
+
102
+ /**
103
+ * Get the associated response
104
+ *
105
+ * @return ResponseInterface|null
106
+ */
107
+ public function getResponse()
108
+ {
109
+ return $this->response;
110
+ }
111
+
112
+ /**
113
+ * Check if a response was received
114
+ *
115
+ * @return bool
116
+ */
117
+ public function hasResponse()
118
+ {
119
+ return $this->response !== null;
120
+ }
121
+ }
backend/vendor/guzzlehttp/guzzle/src/Exception/ServerException.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ /**
5
+ * Exception when a server error is encountered (5xx codes)
6
+ */
7
+ class ServerException extends BadResponseException {}
backend/vendor/guzzlehttp/guzzle/src/Exception/StateException.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ class StateException extends TransferException {};
backend/vendor/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ class TooManyRedirectsException extends RequestException {}
backend/vendor/guzzlehttp/guzzle/src/Exception/TransferException.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ class TransferException extends \RuntimeException {}
backend/vendor/guzzlehttp/guzzle/src/Exception/XmlParseException.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace GuzzleHttp\Exception;
4
+
5
+ use GuzzleHttp\Message\ResponseInterface;
6
+
7
+ /**
8
+ * Exception when a client is unable to parse the response body as XML
9
+ */
10
+ class XmlParseException extends ParseException
11
+ {
12
+ /** @var \LibXMLError */
13
+ protected $error;
14
+
15
+ public function __construct(
16
+ $message = '',
17
+ ResponseInterface $response = null,
18
+ \Exception $previous = null,
19
+ \LibXMLError $error = null
20
+ ) {
21
+ parent::__construct($message, $response, $previous);
22
+ $this->error = $error;
23
+ }
24
+
25
+ /**
26
+ * Get the associated error
27
+ *
28
+ * @return \LibXMLError|null
29
+ */
30
+ public function getError()
31
+ {
32
+ return $this->error;
33
+ }
34
+ }
backend/vendor/guzzlehttp/guzzle/src/HasDataTrait.php ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ /**
5
+ * Trait implementing ToArrayInterface, \ArrayAccess, \Countable,
6
+ * \IteratorAggregate, and some path style methods.
7
+ */
8
+ trait HasDataTrait
9
+ {
10
+ /** @var array */
11
+ protected $data = [];
12
+
13
+ public function getIterator()
14
+ {
15
+ return new \ArrayIterator($this->data);
16
+ }
17
+
18
+ public function offsetGet($offset)
19
+ {
20
+ return isset($this->data[$offset]) ? $this->data[$offset] : null;
21
+ }
22
+
23
+ public function offsetSet($offset, $value)
24
+ {
25
+ $this->data[$offset] = $value;
26
+ }
27
+
28
+ public function offsetExists($offset)
29
+ {
30
+ return isset($this->data[$offset]);
31
+ }
32
+
33
+ public function offsetUnset($offset)
34
+ {
35
+ unset($this->data[$offset]);
36
+ }
37
+
38
+ public function toArray()
39
+ {
40
+ return $this->data;
41
+ }
42
+
43
+ public function count()
44
+ {
45
+ return count($this->data);
46
+ }
47
+
48
+ /**
49
+ * Get a value from the collection using a path syntax to retrieve nested
50
+ * data.
51
+ *
52
+ * @param string $path Path to traverse and retrieve a value from
53
+ *
54
+ * @return mixed|null
55
+ */
56
+ public function getPath($path)
57
+ {
58
+ return Utils::getPath($this->data, $path);
59
+ }
60
+
61
+ /**
62
+ * Set a value into a nested array key. Keys will be created as needed to
63
+ * set the value.
64
+ *
65
+ * @param string $path Path to set
66
+ * @param mixed $value Value to set at the key
67
+ *
68
+ * @throws \RuntimeException when trying to setPath using a nested path
69
+ * that travels through a scalar value
70
+ */
71
+ public function setPath($path, $value)
72
+ {
73
+ Utils::setPath($this->data, $path, $value);
74
+ }
75
+ }
backend/vendor/guzzlehttp/guzzle/src/Message/AbstractMessage.php ADDED
@@ -0,0 +1,253 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Message;
3
+
4
+ use GuzzleHttp\Stream\StreamInterface;
5
+
6
+ abstract class AbstractMessage implements MessageInterface
7
+ {
8
+ /** @var array HTTP header collection */
9
+ private $headers = [];
10
+
11
+ /** @var array mapping a lowercase header name to its name over the wire */
12
+ private $headerNames = [];
13
+
14
+ /** @var StreamInterface Message body */
15
+ private $body;
16
+
17
+ /** @var string HTTP protocol version of the message */
18
+ private $protocolVersion = '1.1';
19
+
20
+ public function __toString()
21
+ {
22
+ return static::getStartLineAndHeaders($this)
23
+ . "\r\n\r\n" . $this->getBody();
24
+ }
25
+
26
+ public function getProtocolVersion()
27
+ {
28
+ return $this->protocolVersion;
29
+ }
30
+
31
+ public function getBody()
32
+ {
33
+ return $this->body;
34
+ }
35
+
36
+ public function setBody(StreamInterface $body = null)
37
+ {
38
+ if ($body === null) {
39
+ // Setting a null body will remove the body of the request
40
+ $this->removeHeader('Content-Length');
41
+ $this->removeHeader('Transfer-Encoding');
42
+ }
43
+
44
+ $this->body = $body;
45
+ }
46
+
47
+ public function addHeader($header, $value)
48
+ {
49
+ if (is_array($value)) {
50
+ $current = array_merge($this->getHeaderAsArray($header), $value);
51
+ } else {
52
+ $current = $this->getHeaderAsArray($header);
53
+ $current[] = (string) $value;
54
+ }
55
+
56
+ $this->setHeader($header, $current);
57
+ }
58
+
59
+ public function addHeaders(array $headers)
60
+ {
61
+ foreach ($headers as $name => $header) {
62
+ $this->addHeader($name, $header);
63
+ }
64
+ }
65
+
66
+ public function getHeader($header)
67
+ {
68
+ $name = strtolower($header);
69
+ return isset($this->headers[$name])
70
+ ? implode(', ', $this->headers[$name])
71
+ : '';
72
+ }
73
+
74
+ public function getHeaderAsArray($header)
75
+ {
76
+ $name = strtolower($header);
77
+ return isset($this->headers[$name]) ? $this->headers[$name] : [];
78
+ }
79
+
80
+ public function getHeaders()
81
+ {
82
+ $headers = [];
83
+ foreach ($this->headers as $name => $values) {
84
+ $headers[$this->headerNames[$name]] = $values;
85
+ }
86
+
87
+ return $headers;
88
+ }
89
+
90
+ public function setHeader($header, $value)
91
+ {
92
+ $header = trim($header);
93
+ $name = strtolower($header);
94
+ $this->headerNames[$name] = $header;
95
+
96
+ if (is_array($value)) {
97
+ foreach ($value as &$v) {
98
+ $v = trim($v);
99
+ }
100
+ $this->headers[$name] = $value;
101
+ } else {
102
+ $this->headers[$name] = [trim($value)];
103
+ }
104
+ }
105
+
106
+ public function setHeaders(array $headers)
107
+ {
108
+ $this->headers = $this->headerNames = [];
109
+ foreach ($headers as $key => $value) {
110
+ $this->setHeader($key, $value);
111
+ }
112
+ }
113
+
114
+ public function hasHeader($header)
115
+ {
116
+ return isset($this->headers[strtolower($header)]);
117
+ }
118
+
119
+ public function removeHeader($header)
120
+ {
121
+ $name = strtolower($header);
122
+ unset($this->headers[$name], $this->headerNames[$name]);
123
+ }
124
+
125
+ /**
126
+ * Parse an array of header values containing ";" separated data into an
127
+ * array of associative arrays representing the header key value pair
128
+ * data of the header. When a parameter does not contain a value, but just
129
+ * contains a key, this function will inject a key with a '' string value.
130
+ *
131
+ * @param MessageInterface $message That contains the header
132
+ * @param string $header Header to retrieve from the message
133
+ *
134
+ * @return array Returns the parsed header values.
135
+ */
136
+ public static function parseHeader(MessageInterface $message, $header)
137
+ {
138
+ static $trimmed = "\"' \n\t\r";
139
+ $params = $matches = [];
140
+
141
+ foreach (self::normalizeHeader($message, $header) as $val) {
142
+ $part = [];
143
+ foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) as $kvp) {
144
+ if (preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches)) {
145
+ $m = $matches[0];
146
+ if (isset($m[1])) {
147
+ $part[trim($m[0], $trimmed)] = trim($m[1], $trimmed);
148
+ } else {
149
+ $part[] = trim($m[0], $trimmed);
150
+ }
151
+ }
152
+ }
153
+ if ($part) {
154
+ $params[] = $part;
155
+ }
156
+ }
157
+
158
+ return $params;
159
+ }
160
+
161
+ /**
162
+ * Converts an array of header values that may contain comma separated
163
+ * headers into an array of headers with no comma separated values.
164
+ *
165
+ * @param MessageInterface $message That contains the header
166
+ * @param string $header Header to retrieve from the message
167
+ *
168
+ * @return array Returns the normalized header field values.
169
+ */
170
+ public static function normalizeHeader(MessageInterface $message, $header)
171
+ {
172
+ $h = $message->getHeaderAsArray($header);
173
+ for ($i = 0, $total = count($h); $i < $total; $i++) {
174
+ if (strpos($h[$i], ',') === false) {
175
+ continue;
176
+ }
177
+ foreach (preg_split('/,(?=([^"]*"[^"]*")*[^"]*$)/', $h[$i]) as $v) {
178
+ $h[] = trim($v);
179
+ }
180
+ unset($h[$i]);
181
+ }
182
+
183
+ return $h;
184
+ }
185
+
186
+ /**
187
+ * Gets the start-line and headers of a message as a string
188
+ *
189
+ * @param MessageInterface $message
190
+ *
191
+ * @return string
192
+ */
193
+ public static function getStartLineAndHeaders(MessageInterface $message)
194
+ {
195
+ return static::getStartLine($message)
196
+ . self::getHeadersAsString($message);
197
+ }
198
+
199
+ /**
200
+ * Gets the headers of a message as a string
201
+ *
202
+ * @param MessageInterface $message
203
+ *
204
+ * @return string
205
+ */
206
+ public static function getHeadersAsString(MessageInterface $message)
207
+ {
208
+ $result = '';
209
+ foreach ($message->getHeaders() as $name => $values) {
210
+ $result .= "\r\n{$name}: " . implode(', ', $values);
211
+ }
212
+
213
+ return $result;
214
+ }
215
+
216
+ /**
217
+ * Gets the start line of a message
218
+ *
219
+ * @param MessageInterface $message
220
+ *
221
+ * @return string
222
+ * @throws \InvalidArgumentException
223
+ */
224
+ public static function getStartLine(MessageInterface $message)
225
+ {
226
+ if ($message instanceof RequestInterface) {
227
+ return trim($message->getMethod() . ' '
228
+ . $message->getResource())
229
+ . ' HTTP/' . $message->getProtocolVersion();
230
+ } elseif ($message instanceof ResponseInterface) {
231
+ return 'HTTP/' . $message->getProtocolVersion() . ' '
232
+ . $message->getStatusCode() . ' '
233
+ . $message->getReasonPhrase();
234
+ } else {
235
+ throw new \InvalidArgumentException('Unknown message type');
236
+ }
237
+ }
238
+
239
+ /**
240
+ * Accepts and modifies the options provided to the message in the
241
+ * constructor.
242
+ *
243
+ * Can be overridden in subclasses as necessary.
244
+ *
245
+ * @param array $options Options array passed by reference.
246
+ */
247
+ protected function handleOptions(array &$options)
248
+ {
249
+ if (isset($options['protocol_version'])) {
250
+ $this->protocolVersion = $options['protocol_version'];
251
+ }
252
+ }
253
+ }
backend/vendor/guzzlehttp/guzzle/src/Message/FutureResponse.php ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Message;
3
+
4
+ use GuzzleHttp\Ring\Future\MagicFutureTrait;
5
+ use GuzzleHttp\Ring\Future\FutureInterface;
6
+ use GuzzleHttp\Stream\StreamInterface;
7
+
8
+ /**
9
+ * Represents a response that has not been fulfilled.
10
+ *
11
+ * When created, you must provide a function that is used to dereference the
12
+ * future result and return it's value. The function has no arguments and MUST
13
+ * return an instance of a {@see GuzzleHttp\Message\ResponseInterface} object.
14
+ *
15
+ * You can optionally provide a function in the constructor that can be used to
16
+ * cancel the future from completing if possible. This function has no
17
+ * arguments and returns a boolean value representing whether or not the
18
+ * response could be cancelled.
19
+ *
20
+ * @property ResponseInterface $_value
21
+ */
22
+ class FutureResponse implements ResponseInterface, FutureInterface
23
+ {
24
+ use MagicFutureTrait;
25
+
26
+ /**
27
+ * Returns a FutureResponse that wraps another future.
28
+ *
29
+ * @param FutureInterface $future Future to wrap with a new future
30
+ * @param callable $onFulfilled Invoked when the future fulfilled
31
+ * @param callable $onRejected Invoked when the future rejected
32
+ * @param callable $onProgress Invoked when the future progresses
33
+ *
34
+ * @return FutureResponse
35
+ */
36
+ public static function proxy(
37
+ FutureInterface $future,
38
+ callable $onFulfilled = null,
39
+ callable $onRejected = null,
40
+ callable $onProgress = null
41
+ ) {
42
+ return new FutureResponse(
43
+ $future->then($onFulfilled, $onRejected, $onProgress),
44
+ [$future, 'wait'],
45
+ [$future, 'cancel']
46
+ );
47
+ }
48
+
49
+ public function getStatusCode()
50
+ {
51
+ return $this->_value->getStatusCode();
52
+ }
53
+
54
+ public function setStatusCode($code)
55
+ {
56
+ $this->_value->setStatusCode($code);
57
+ }
58
+
59
+ public function getReasonPhrase()
60
+ {
61
+ return $this->_value->getReasonPhrase();
62
+ }
63
+
64
+ public function setReasonPhrase($phrase)
65
+ {
66
+ $this->_value->setReasonPhrase($phrase);
67
+ }
68
+
69
+ public function getEffectiveUrl()
70
+ {
71
+ return $this->_value->getEffectiveUrl();
72
+ }
73
+
74
+ public function setEffectiveUrl($url)
75
+ {
76
+ $this->_value->setEffectiveUrl($url);
77
+ }
78
+
79
+ public function json(array $config = [])
80
+ {
81
+ return $this->_value->json($config);
82
+ }
83
+
84
+ public function xml(array $config = [])
85
+ {
86
+ return $this->_value->xml($config);
87
+ }
88
+
89
+ public function __toString()
90
+ {
91
+ try {
92
+ return $this->_value->__toString();
93
+ } catch (\Exception $e) {
94
+ trigger_error($e->getMessage(), E_USER_WARNING);
95
+ return '';
96
+ }
97
+ }
98
+
99
+ public function getProtocolVersion()
100
+ {
101
+ return $this->_value->getProtocolVersion();
102
+ }
103
+
104
+ public function setBody(StreamInterface $body = null)
105
+ {
106
+ $this->_value->setBody($body);
107
+ }
108
+
109
+ public function getBody()
110
+ {
111
+ return $this->_value->getBody();
112
+ }
113
+
114
+ public function getHeaders()
115
+ {
116
+ return $this->_value->getHeaders();
117
+ }
118
+
119
+ public function getHeader($header)
120
+ {
121
+ return $this->_value->getHeader($header);
122
+ }
123
+
124
+ public function getHeaderAsArray($header)
125
+ {
126
+ return $this->_value->getHeaderAsArray($header);
127
+ }
128
+
129
+ public function hasHeader($header)
130
+ {
131
+ return $this->_value->hasHeader($header);
132
+ }
133
+
134
+ public function removeHeader($header)
135
+ {
136
+ $this->_value->removeHeader($header);
137
+ }
138
+
139
+ public function addHeader($header, $value)
140
+ {
141
+ $this->_value->addHeader($header, $value);
142
+ }
143
+
144
+ public function addHeaders(array $headers)
145
+ {
146
+ $this->_value->addHeaders($headers);
147
+ }
148
+
149
+ public function setHeader($header, $value)
150
+ {
151
+ $this->_value->setHeader($header, $value);
152
+ }
153
+
154
+ public function setHeaders(array $headers)
155
+ {
156
+ $this->_value->setHeaders($headers);
157
+ }
158
+ }
backend/vendor/guzzlehttp/guzzle/src/Message/MessageFactory.php ADDED
@@ -0,0 +1,364 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Message;
3
+
4
+ use GuzzleHttp\Cookie\CookieJar;
5
+ use GuzzleHttp\Cookie\CookieJarInterface;
6
+ use GuzzleHttp\Event\ListenerAttacherTrait;
7
+ use GuzzleHttp\Post\PostBody;
8
+ use GuzzleHttp\Post\PostFile;
9
+ use GuzzleHttp\Post\PostFileInterface;
10
+ use GuzzleHttp\Query;
11
+ use GuzzleHttp\Stream\Stream;
12
+ use GuzzleHttp\Subscriber\Cookie;
13
+ use GuzzleHttp\Subscriber\HttpError;
14
+ use GuzzleHttp\Subscriber\Redirect;
15
+ use GuzzleHttp\Url;
16
+ use \InvalidArgumentException as Iae;
17
+
18
+ /**
19
+ * Default HTTP request factory used to create Request and Response objects.
20
+ */
21
+ class MessageFactory implements MessageFactoryInterface
22
+ {
23
+ use ListenerAttacherTrait;
24
+
25
+ /** @var HttpError */
26
+ private $errorPlugin;
27
+
28
+ /** @var Redirect */
29
+ private $redirectPlugin;
30
+
31
+ /** @var array */
32
+ private $customOptions;
33
+
34
+ /** @var array Request options passed through to request Config object */
35
+ private static $configMap = [
36
+ 'connect_timeout' => 1, 'timeout' => 1, 'verify' => 1, 'ssl_key' => 1,
37
+ 'cert' => 1, 'proxy' => 1, 'debug' => 1, 'save_to' => 1, 'stream' => 1,
38
+ 'expect' => 1, 'future' => 1
39
+ ];
40
+
41
+ /** @var array Default allow_redirects request option settings */
42
+ private static $defaultRedirect = [
43
+ 'max' => 5,
44
+ 'strict' => false,
45
+ 'referer' => false,
46
+ 'protocols' => ['http', 'https']
47
+ ];
48
+
49
+ /**
50
+ * @param array $customOptions Associative array of custom request option
51
+ * names mapping to functions used to apply
52
+ * the option. The function accepts the request
53
+ * and the option value to apply.
54
+ */
55
+ public function __construct(array $customOptions = [])
56
+ {
57
+ $this->errorPlugin = new HttpError();
58
+ $this->redirectPlugin = new Redirect();
59
+ $this->customOptions = $customOptions;
60
+ }
61
+
62
+ public function createResponse(
63
+ $statusCode,
64
+ array $headers = [],
65
+ $body = null,
66
+ array $options = []
67
+ ) {
68
+ if (null !== $body) {
69
+ $body = Stream::factory($body);
70
+ }
71
+
72
+ return new Response($statusCode, $headers, $body, $options);
73
+ }
74
+
75
+ public function createRequest($method, $url, array $options = [])
76
+ {
77
+ // Handle the request protocol version option that needs to be
78
+ // specified in the request constructor.
79
+ if (isset($options['version'])) {
80
+ $options['config']['protocol_version'] = $options['version'];
81
+ unset($options['version']);
82
+ }
83
+
84
+ $request = new Request($method, $url, [], null,
85
+ isset($options['config']) ? $options['config'] : []);
86
+
87
+ unset($options['config']);
88
+
89
+ // Use a POST body by default
90
+ if ($method == 'POST'
91
+ && !isset($options['body'])
92
+ && !isset($options['json'])
93
+ ) {
94
+ $options['body'] = [];
95
+ }
96
+
97
+ if ($options) {
98
+ $this->applyOptions($request, $options);
99
+ }
100
+
101
+ return $request;
102
+ }
103
+
104
+ /**
105
+ * Create a request or response object from an HTTP message string
106
+ *
107
+ * @param string $message Message to parse
108
+ *
109
+ * @return RequestInterface|ResponseInterface
110
+ * @throws \InvalidArgumentException if unable to parse a message
111
+ */
112
+ public function fromMessage($message)
113
+ {
114
+ static $parser;
115
+ if (!$parser) {
116
+ $parser = new MessageParser();
117
+ }
118
+
119
+ // Parse a response
120
+ if (strtoupper(substr($message, 0, 4)) == 'HTTP') {
121
+ $data = $parser->parseResponse($message);
122
+ return $this->createResponse(
123
+ $data['code'],
124
+ $data['headers'],
125
+ $data['body'] === '' ? null : $data['body'],
126
+ $data
127
+ );
128
+ }
129
+
130
+ // Parse a request
131
+ if (!($data = ($parser->parseRequest($message)))) {
132
+ throw new \InvalidArgumentException('Unable to parse request');
133
+ }
134
+
135
+ return $this->createRequest(
136
+ $data['method'],
137
+ Url::buildUrl($data['request_url']),
138
+ [
139
+ 'headers' => $data['headers'],
140
+ 'body' => $data['body'] === '' ? null : $data['body'],
141
+ 'config' => [
142
+ 'protocol_version' => $data['protocol_version']
143
+ ]
144
+ ]
145
+ );
146
+ }
147
+
148
+ /**
149
+ * Apply POST fields and files to a request to attempt to give an accurate
150
+ * representation.
151
+ *
152
+ * @param RequestInterface $request Request to update
153
+ * @param array $body Body to apply
154
+ */
155
+ protected function addPostData(RequestInterface $request, array $body)
156
+ {
157
+ static $fields = ['string' => true, 'array' => true, 'NULL' => true,
158
+ 'boolean' => true, 'double' => true, 'integer' => true];
159
+
160
+ $post = new PostBody();
161
+ foreach ($body as $key => $value) {
162
+ if (isset($fields[gettype($value)])) {
163
+ $post->setField($key, $value);
164
+ } elseif ($value instanceof PostFileInterface) {
165
+ $post->addFile($value);
166
+ } else {
167
+ $post->addFile(new PostFile($key, $value));
168
+ }
169
+ }
170
+
171
+ if ($request->getHeader('Content-Type') == 'multipart/form-data') {
172
+ $post->forceMultipartUpload(true);
173
+ }
174
+
175
+ $request->setBody($post);
176
+ }
177
+
178
+ protected function applyOptions(
179
+ RequestInterface $request,
180
+ array $options = []
181
+ ) {
182
+ $config = $request->getConfig();
183
+ $emitter = $request->getEmitter();
184
+
185
+ foreach ($options as $key => $value) {
186
+
187
+ if (isset(self::$configMap[$key])) {
188
+ $config[$key] = $value;
189
+ continue;
190
+ }
191
+
192
+ switch ($key) {
193
+
194
+ case 'allow_redirects':
195
+
196
+ if ($value === false) {
197
+ continue;
198
+ }
199
+
200
+ if ($value === true) {
201
+ $value = self::$defaultRedirect;
202
+ } elseif (!is_array($value)) {
203
+ throw new Iae('allow_redirects must be true, false, or array');
204
+ } else {
205
+ // Merge the default settings with the provided settings
206
+ $value += self::$defaultRedirect;
207
+ }
208
+
209
+ $config['redirect'] = $value;
210
+ $emitter->attach($this->redirectPlugin);
211
+ break;
212
+
213
+ case 'decode_content':
214
+
215
+ if ($value === false) {
216
+ continue;
217
+ }
218
+
219
+ $config['decode_content'] = true;
220
+ if ($value !== true) {
221
+ $request->setHeader('Accept-Encoding', $value);
222
+ }
223
+ break;
224
+
225
+ case 'headers':
226
+
227
+ if (!is_array($value)) {
228
+ throw new Iae('header value must be an array');
229
+ }
230
+ foreach ($value as $k => $v) {
231
+ $request->setHeader($k, $v);
232
+ }
233
+ break;
234
+
235
+ case 'exceptions':
236
+
237
+ if ($value === true) {
238
+ $emitter->attach($this->errorPlugin);
239
+ }
240
+ break;
241
+
242
+ case 'body':
243
+
244
+ if (is_array($value)) {
245
+ $this->addPostData($request, $value);
246
+ } elseif ($value !== null) {
247
+ $request->setBody(Stream::factory($value));
248
+ }
249
+ break;
250
+
251
+ case 'auth':
252
+
253
+ if (!$value) {
254
+ continue;
255
+ }
256
+
257
+ if (is_array($value)) {
258
+ $type = isset($value[2]) ? strtolower($value[2]) : 'basic';
259
+ } else {
260
+ $type = strtolower($value);
261
+ }
262
+
263
+ $config['auth'] = $value;
264
+
265
+ if ($type == 'basic') {
266
+ $request->setHeader(
267
+ 'Authorization',
268
+ 'Basic ' . base64_encode("$value[0]:$value[1]")
269
+ );
270
+ } elseif ($type == 'digest') {
271
+ // @todo: Do not rely on curl
272
+ $config->setPath('curl/' . CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
273
+ $config->setPath('curl/' . CURLOPT_USERPWD, "$value[0]:$value[1]");
274
+ }
275
+ break;
276
+
277
+ case 'query':
278
+
279
+ if ($value instanceof Query) {
280
+ $original = $request->getQuery();
281
+ // Do not overwrite existing query string variables by
282
+ // overwriting the object with the query string data passed
283
+ // in the URL
284
+ $value->overwriteWith($original->toArray());
285
+ $request->setQuery($value);
286
+ } elseif (is_array($value)) {
287
+ // Do not overwrite existing query string variables
288
+ $query = $request->getQuery();
289
+ foreach ($value as $k => $v) {
290
+ if (!isset($query[$k])) {
291
+ $query[$k] = $v;
292
+ }
293
+ }
294
+ } else {
295
+ throw new Iae('query must be an array or Query object');
296
+ }
297
+ break;
298
+
299
+ case 'cookies':
300
+
301
+ if ($value === true) {
302
+ static $cookie = null;
303
+ if (!$cookie) {
304
+ $cookie = new Cookie();
305
+ }
306
+ $emitter->attach($cookie);
307
+ } elseif (is_array($value)) {
308
+ $emitter->attach(
309
+ new Cookie(CookieJar::fromArray($value, $request->getHost()))
310
+ );
311
+ } elseif ($value instanceof CookieJarInterface) {
312
+ $emitter->attach(new Cookie($value));
313
+ } elseif ($value !== false) {
314
+ throw new Iae('cookies must be an array, true, or CookieJarInterface');
315
+ }
316
+ break;
317
+
318
+ case 'events':
319
+
320
+ if (!is_array($value)) {
321
+ throw new Iae('events must be an array');
322
+ }
323
+
324
+ $this->attachListeners($request,
325
+ $this->prepareListeners(
326
+ $value,
327
+ ['before', 'complete', 'error', 'progress', 'end']
328
+ )
329
+ );
330
+ break;
331
+
332
+ case 'subscribers':
333
+
334
+ if (!is_array($value)) {
335
+ throw new Iae('subscribers must be an array');
336
+ }
337
+
338
+ foreach ($value as $subscribers) {
339
+ $emitter->attach($subscribers);
340
+ }
341
+ break;
342
+
343
+ case 'json':
344
+
345
+ $request->setBody(Stream::factory(json_encode($value)));
346
+ if (!$request->hasHeader('Content-Type')) {
347
+ $request->setHeader('Content-Type', 'application/json');
348
+ }
349
+ break;
350
+
351
+ default:
352
+
353
+ // Check for custom handler functions.
354
+ if (isset($this->customOptions[$key])) {
355
+ $fn = $this->customOptions[$key];
356
+ $fn($request, $value);
357
+ continue;
358
+ }
359
+
360
+ throw new Iae("No method can handle the {$key} config key");
361
+ }
362
+ }
363
+ }
364
+ }
backend/vendor/guzzlehttp/guzzle/src/Message/MessageFactoryInterface.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Message;
3
+
4
+ use GuzzleHttp\Url;
5
+
6
+ /**
7
+ * Request and response factory
8
+ */
9
+ interface MessageFactoryInterface
10
+ {
11
+ /**
12
+ * Creates a response
13
+ *
14
+ * @param string $statusCode HTTP status code
15
+ * @param array $headers Response headers
16
+ * @param mixed $body Response body
17
+ * @param array $options Response options
18
+ * - protocol_version: HTTP protocol version
19
+ * - header_factory: Factory used to create headers
20
+ * - And any other options used by a concrete message implementation
21
+ *
22
+ * @return ResponseInterface
23
+ */
24
+ public function createResponse(
25
+ $statusCode,
26
+ array $headers = [],
27
+ $body = null,
28
+ array $options = []
29
+ );
30
+
31
+ /**
32
+ * Create a new request based on the HTTP method.
33
+ *
34
+ * This method accepts an associative array of request options. Below is a
35
+ * brief description of each parameter. See
36
+ * http://docs.guzzlephp.org/clients.html#request-options for a much more
37
+ * in-depth description of each parameter.
38
+ *
39
+ * - headers: Associative array of headers to add to the request
40
+ * - body: string|resource|array|StreamInterface request body to send
41
+ * - json: mixed Uploads JSON encoded data using an application/json Content-Type header.
42
+ * - query: Associative array of query string values to add to the request
43
+ * - auth: array|string HTTP auth settings (user, pass[, type="basic"])
44
+ * - version: The HTTP protocol version to use with the request
45
+ * - cookies: true|false|CookieJarInterface To enable or disable cookies
46
+ * - allow_redirects: true|false|array Controls HTTP redirects
47
+ * - save_to: string|resource|StreamInterface Where the response is saved
48
+ * - events: Associative array of event names to callables or arrays
49
+ * - subscribers: Array of event subscribers to add to the request
50
+ * - exceptions: Specifies whether or not exceptions are thrown for HTTP protocol errors
51
+ * - timeout: Timeout of the request in seconds. Use 0 to wait indefinitely
52
+ * - connect_timeout: Number of seconds to wait while trying to connect. (0 to wait indefinitely)
53
+ * - verify: SSL validation. True/False or the path to a PEM file
54
+ * - cert: Path a SSL cert or array of (path, pwd)
55
+ * - ssl_key: Path to a private SSL key or array of (path, pwd)
56
+ * - proxy: Specify an HTTP proxy or hash of protocols to proxies
57
+ * - debug: Set to true or a resource to view handler specific debug info
58
+ * - stream: Set to true to stream a response body rather than download it all up front
59
+ * - expect: true/false/integer Controls the "Expect: 100-Continue" header
60
+ * - config: Associative array of request config collection options
61
+ * - decode_content: true/false/string to control decoding content-encoding responses
62
+ *
63
+ * @param string $method HTTP method (GET, POST, PUT, etc.)
64
+ * @param string|Url $url HTTP URL to connect to
65
+ * @param array $options Array of options to apply to the request
66
+ *
67
+ * @return RequestInterface
68
+ * @link http://docs.guzzlephp.org/clients.html#request-options
69
+ */
70
+ public function createRequest($method, $url, array $options = []);
71
+ }
backend/vendor/guzzlehttp/guzzle/src/Message/MessageInterface.php ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Message;
3
+
4
+ use GuzzleHttp\Stream\StreamInterface;
5
+
6
+ /**
7
+ * Request and response message interface
8
+ */
9
+ interface MessageInterface
10
+ {
11
+ /**
12
+ * Get a string representation of the message
13
+ *
14
+ * @return string
15
+ */
16
+ public function __toString();
17
+
18
+ /**
19
+ * Get the HTTP protocol version of the message
20
+ *
21
+ * @return string
22
+ */
23
+ public function getProtocolVersion();
24
+
25
+ /**
26
+ * Sets the body of the message.
27
+ *
28
+ * The body MUST be a StreamInterface object. Setting the body to null MUST
29
+ * remove the existing body.
30
+ *
31
+ * @param StreamInterface|null $body Body.
32
+ */
33
+ public function setBody(StreamInterface $body = null);
34
+
35
+ /**
36
+ * Get the body of the message
37
+ *
38
+ * @return StreamInterface|null
39
+ */
40
+ public function getBody();
41
+
42
+ /**
43
+ * Gets all message headers.
44
+ *
45
+ * The keys represent the header name as it will be sent over the wire, and
46
+ * each value is an array of strings associated with the header.
47
+ *
48
+ * // Represent the headers as a string
49
+ * foreach ($message->getHeaders() as $name => $values) {
50
+ * echo $name . ": " . implode(", ", $values);
51
+ * }
52
+ *
53
+ * @return array Returns an associative array of the message's headers.
54
+ */
55
+ public function getHeaders();
56
+
57
+ /**
58
+ * Retrieve a header by the given case-insensitive name.
59
+ *
60
+ * @param string $header Case-insensitive header name.
61
+ *
62
+ * @return string
63
+ */
64
+ public function getHeader($header);
65
+
66
+ /**
67
+ * Retrieves a header by the given case-insensitive name as an array of strings.
68
+ *
69
+ * @param string $header Case-insensitive header name.
70
+ *
71
+ * @return string[]
72
+ */
73
+ public function getHeaderAsArray($header);
74
+
75
+ /**
76
+ * Checks if a header exists by the given case-insensitive name.
77
+ *
78
+ * @param string $header Case-insensitive header name.
79
+ *
80
+ * @return bool Returns true if any header names match the given header
81
+ * name using a case-insensitive string comparison. Returns false if
82
+ * no matching header name is found in the message.
83
+ */
84
+ public function hasHeader($header);
85
+
86
+ /**
87
+ * Remove a specific header by case-insensitive name.
88
+ *
89
+ * @param string $header Case-insensitive header name.
90
+ */
91
+ public function removeHeader($header);
92
+
93
+ /**
94
+ * Appends a header value to any existing values associated with the
95
+ * given header name.
96
+ *
97
+ * @param string $header Header name to add
98
+ * @param string $value Value of the header
99
+ */
100
+ public function addHeader($header, $value);
101
+
102
+ /**
103
+ * Merges in an associative array of headers.
104
+ *
105
+ * Each array key MUST be a string representing the case-insensitive name
106
+ * of a header. Each value MUST be either a string or an array of strings.
107
+ * For each value, the value is appended to any existing header of the same
108
+ * name, or, if a header does not already exist by the given name, then the
109
+ * header is added.
110
+ *
111
+ * @param array $headers Associative array of headers to add to the message
112
+ */
113
+ public function addHeaders(array $headers);
114
+
115
+ /**
116
+ * Sets a header, replacing any existing values of any headers with the
117
+ * same case-insensitive name.
118
+ *
119
+ * The header values MUST be a string or an array of strings.
120
+ *
121
+ * @param string $header Header name
122
+ * @param string|array $value Header value(s)
123
+ */
124
+ public function setHeader($header, $value);
125
+
126
+ /**
127
+ * Sets headers, replacing any headers that have already been set on the
128
+ * message.
129
+ *
130
+ * The array keys MUST be a string. The array values must be either a
131
+ * string or an array of strings.
132
+ *
133
+ * @param array $headers Headers to set.
134
+ */
135
+ public function setHeaders(array $headers);
136
+ }
backend/vendor/guzzlehttp/guzzle/src/Message/MessageParser.php ADDED
@@ -0,0 +1,171 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Message;
3
+
4
+ /**
5
+ * Request and response parser used by Guzzle
6
+ */
7
+ class MessageParser
8
+ {
9
+ /**
10
+ * Parse an HTTP request message into an associative array of parts.
11
+ *
12
+ * @param string $message HTTP request to parse
13
+ *
14
+ * @return array|bool Returns false if the message is invalid
15
+ */
16
+ public function parseRequest($message)
17
+ {
18
+ if (!($parts = $this->parseMessage($message))) {
19
+ return false;
20
+ }
21
+
22
+ // Parse the protocol and protocol version
23
+ if (isset($parts['start_line'][2])) {
24
+ $startParts = explode('/', $parts['start_line'][2]);
25
+ $protocol = strtoupper($startParts[0]);
26
+ $version = isset($startParts[1]) ? $startParts[1] : '1.1';
27
+ } else {
28
+ $protocol = 'HTTP';
29
+ $version = '1.1';
30
+ }
31
+
32
+ $parsed = [
33
+ 'method' => strtoupper($parts['start_line'][0]),
34
+ 'protocol' => $protocol,
35
+ 'protocol_version' => $version,
36
+ 'headers' => $parts['headers'],
37
+ 'body' => $parts['body']
38
+ ];
39
+
40
+ $parsed['request_url'] = $this->getUrlPartsFromMessage(
41
+ (isset($parts['start_line'][1]) ? $parts['start_line'][1] : ''), $parsed);
42
+
43
+ return $parsed;
44
+ }
45
+
46
+ /**
47
+ * Parse an HTTP response message into an associative array of parts.
48
+ *
49
+ * @param string $message HTTP response to parse
50
+ *
51
+ * @return array|bool Returns false if the message is invalid
52
+ */
53
+ public function parseResponse($message)
54
+ {
55
+ if (!($parts = $this->parseMessage($message))) {
56
+ return false;
57
+ }
58
+
59
+ list($protocol, $version) = explode('/', trim($parts['start_line'][0]));
60
+
61
+ return [
62
+ 'protocol' => $protocol,
63
+ 'protocol_version' => $version,
64
+ 'code' => $parts['start_line'][1],
65
+ 'reason_phrase' => isset($parts['start_line'][2]) ? $parts['start_line'][2] : '',
66
+ 'headers' => $parts['headers'],
67
+ 'body' => $parts['body']
68
+ ];
69
+ }
70
+
71
+ /**
72
+ * Parse a message into parts
73
+ *
74
+ * @param string $message Message to parse
75
+ *
76
+ * @return array|bool
77
+ */
78
+ private function parseMessage($message)
79
+ {
80
+ if (!$message) {
81
+ return false;
82
+ }
83
+
84
+ $startLine = null;
85
+ $headers = [];
86
+ $body = '';
87
+
88
+ // Iterate over each line in the message, accounting for line endings
89
+ $lines = preg_split('/(\\r?\\n)/', $message, -1, PREG_SPLIT_DELIM_CAPTURE);
90
+ for ($i = 0, $totalLines = count($lines); $i < $totalLines; $i += 2) {
91
+
92
+ $line = $lines[$i];
93
+
94
+ // If two line breaks were encountered, then this is the end of body
95
+ if (empty($line)) {
96
+ if ($i < $totalLines - 1) {
97
+ $body = implode('', array_slice($lines, $i + 2));
98
+ }
99
+ break;
100
+ }
101
+
102
+ // Parse message headers
103
+ if (!$startLine) {
104
+ $startLine = explode(' ', $line, 3);
105
+ } elseif (strpos($line, ':')) {
106
+ $parts = explode(':', $line, 2);
107
+ $key = trim($parts[0]);
108
+ $value = isset($parts[1]) ? trim($parts[1]) : '';
109
+ if (!isset($headers[$key])) {
110
+ $headers[$key] = $value;
111
+ } elseif (!is_array($headers[$key])) {
112
+ $headers[$key] = [$headers[$key], $value];
113
+ } else {
114
+ $headers[$key][] = $value;
115
+ }
116
+ }
117
+ }
118
+
119
+ return [
120
+ 'start_line' => $startLine,
121
+ 'headers' => $headers,
122
+ 'body' => $body
123
+ ];
124
+ }
125
+
126
+ /**
127
+ * Create URL parts from HTTP message parts
128
+ *
129
+ * @param string $requestUrl Associated URL
130
+ * @param array $parts HTTP message parts
131
+ *
132
+ * @return array
133
+ */
134
+ private function getUrlPartsFromMessage($requestUrl, array $parts)
135
+ {
136
+ // Parse the URL information from the message
137
+ $urlParts = ['path' => $requestUrl, 'scheme' => 'http'];
138
+
139
+ // Check for the Host header
140
+ if (isset($parts['headers']['Host'])) {
141
+ $urlParts['host'] = $parts['headers']['Host'];
142
+ } elseif (isset($parts['headers']['host'])) {
143
+ $urlParts['host'] = $parts['headers']['host'];
144
+ } else {
145
+ $urlParts['host'] = null;
146
+ }
147
+
148
+ if (false === strpos($urlParts['host'], ':')) {
149
+ $urlParts['port'] = '';
150
+ } else {
151
+ $hostParts = explode(':', $urlParts['host']);
152
+ $urlParts['host'] = trim($hostParts[0]);
153
+ $urlParts['port'] = (int) trim($hostParts[1]);
154
+ if ($urlParts['port'] == 443) {
155
+ $urlParts['scheme'] = 'https';
156
+ }
157
+ }
158
+
159
+ // Check if a query is present
160
+ $path = $urlParts['path'];
161
+ $qpos = strpos($path, '?');
162
+ if ($qpos) {
163
+ $urlParts['query'] = substr($path, $qpos + 1);
164
+ $urlParts['path'] = substr($path, 0, $qpos);
165
+ } else {
166
+ $urlParts['query'] = '';
167
+ }
168
+
169
+ return $urlParts;
170
+ }
171
+ }
backend/vendor/guzzlehttp/guzzle/src/Message/Request.php ADDED
@@ -0,0 +1,195 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Message;
3
+
4
+ use GuzzleHttp\Collection;
5
+ use GuzzleHttp\Event\HasEmitterTrait;
6
+ use GuzzleHttp\Subscriber\Prepare;
7
+ use GuzzleHttp\Url;
8
+
9
+ /**
10
+ * HTTP request class to send requests
11
+ */
12
+ class Request extends AbstractMessage implements RequestInterface
13
+ {
14
+ use HasEmitterTrait;
15
+
16
+ /** @var Url HTTP Url */
17
+ private $url;
18
+
19
+ /** @var string HTTP method */
20
+ private $method;
21
+
22
+ /** @var Collection Transfer options */
23
+ private $transferOptions;
24
+
25
+ /**
26
+ * @param string $method HTTP method
27
+ * @param string|Url $url HTTP URL to connect to. The URI scheme,
28
+ * host header, and URI are parsed from the full URL. If query string
29
+ * parameters are present they will be parsed as well.
30
+ * @param array|Collection $headers HTTP headers
31
+ * @param mixed $body Body to send with the request
32
+ * @param array $options Array of options to use with the request
33
+ * - emitter: Event emitter to use with the request
34
+ */
35
+ public function __construct(
36
+ $method,
37
+ $url,
38
+ $headers = [],
39
+ $body = null,
40
+ array $options = []
41
+ ) {
42
+ $this->setUrl($url);
43
+ $this->method = strtoupper($method);
44
+ $this->handleOptions($options);
45
+ $this->transferOptions = new Collection($options);
46
+ $this->addPrepareEvent();
47
+
48
+ if ($body !== null) {
49
+ $this->setBody($body);
50
+ }
51
+
52
+ if ($headers) {
53
+ foreach ($headers as $key => $value) {
54
+ $this->setHeader($key, $value);
55
+ }
56
+ }
57
+ }
58
+
59
+ public function __clone()
60
+ {
61
+ if ($this->emitter) {
62
+ $this->emitter = clone $this->emitter;
63
+ }
64
+ $this->transferOptions = clone $this->transferOptions;
65
+ $this->url = clone $this->url;
66
+ }
67
+
68
+ public function setUrl($url)
69
+ {
70
+ $this->url = $url instanceof Url ? $url : Url::fromString($url);
71
+ $this->updateHostHeaderFromUrl();
72
+ }
73
+
74
+ public function getUrl()
75
+ {
76
+ return (string) $this->url;
77
+ }
78
+
79
+ public function setQuery($query)
80
+ {
81
+ $this->url->setQuery($query);
82
+ }
83
+
84
+ public function getQuery()
85
+ {
86
+ return $this->url->getQuery();
87
+ }
88
+
89
+ public function setMethod($method)
90
+ {
91
+ $this->method = strtoupper($method);
92
+ }
93
+
94
+ public function getMethod()
95
+ {
96
+ return $this->method;
97
+ }
98
+
99
+ public function getScheme()
100
+ {
101
+ return $this->url->getScheme();
102
+ }
103
+
104
+ public function setScheme($scheme)
105
+ {
106
+ $this->url->setScheme($scheme);
107
+ }
108
+
109
+ public function getPort()
110
+ {
111
+ return $this->url->getPort();
112
+ }
113
+
114
+ public function setPort($port)
115
+ {
116
+ $this->url->setPort($port);
117
+ $this->updateHostHeaderFromUrl();
118
+ }
119
+
120
+ public function getHost()
121
+ {
122
+ return $this->url->getHost();
123
+ }
124
+
125
+ public function setHost($host)
126
+ {
127
+ $this->url->setHost($host);
128
+ $this->updateHostHeaderFromUrl();
129
+ }
130
+
131
+ public function getPath()
132
+ {
133
+ return '/' . ltrim($this->url->getPath(), '/');
134
+ }
135
+
136
+ public function setPath($path)
137
+ {
138
+ $this->url->setPath($path);
139
+ }
140
+
141
+ public function getResource()
142
+ {
143
+ $resource = $this->getPath();
144
+ if ($query = (string) $this->url->getQuery()) {
145
+ $resource .= '?' . $query;
146
+ }
147
+
148
+ return $resource;
149
+ }
150
+
151
+ public function getConfig()
152
+ {
153
+ return $this->transferOptions;
154
+ }
155
+
156
+ protected function handleOptions(array &$options)
157
+ {
158
+ parent::handleOptions($options);
159
+ // Use a custom emitter if one is specified, and remove it from
160
+ // options that are exposed through getConfig()
161
+ if (isset($options['emitter'])) {
162
+ $this->emitter = $options['emitter'];
163
+ unset($options['emitter']);
164
+ }
165
+ }
166
+
167
+ /**
168
+ * Adds a subscriber that ensures a request's body is prepared before
169
+ * sending.
170
+ */
171
+ private function addPrepareEvent()
172
+ {
173
+ static $subscriber;
174
+ if (!$subscriber) {
175
+ $subscriber = new Prepare();
176
+ }
177
+
178
+ $this->getEmitter()->attach($subscriber);
179
+ }
180
+
181
+ private function updateHostHeaderFromUrl()
182
+ {
183
+ $port = $this->url->getPort();
184
+ $scheme = $this->url->getScheme();
185
+ if ($host = $this->url->getHost()) {
186
+ if (($port == 80 && $scheme == 'http') ||
187
+ ($port == 443 && $scheme == 'https')
188
+ ) {
189
+ $this->setHeader('Host', $host);
190
+ } else {
191
+ $this->setHeader('Host', "{$host}:{$port}");
192
+ }
193
+ }
194
+ }
195
+ }
backend/vendor/guzzlehttp/guzzle/src/Message/RequestInterface.php ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Message;
3
+
4
+ use GuzzleHttp\Event\HasEmitterInterface;
5
+ use GuzzleHttp\Query;
6
+
7
+ /**
8
+ * Generic HTTP request interface
9
+ */
10
+ interface RequestInterface extends MessageInterface, HasEmitterInterface
11
+ {
12
+ /**
13
+ * Sets the request URL.
14
+ *
15
+ * The URL MUST be a string, or an object that implements the
16
+ * `__toString()` method.
17
+ *
18
+ * @param string $url Request URL.
19
+ *
20
+ * @throws \InvalidArgumentException If the URL is invalid.
21
+ */
22
+ public function setUrl($url);
23
+
24
+ /**
25
+ * Gets the request URL as a string.
26
+ *
27
+ * @return string Returns the URL as a string.
28
+ */
29
+ public function getUrl();
30
+
31
+ /**
32
+ * Get the resource part of the the request, including the path, query
33
+ * string, and fragment.
34
+ *
35
+ * @return string
36
+ */
37
+ public function getResource();
38
+
39
+ /**
40
+ * Get the collection of key value pairs that will be used as the query
41
+ * string in the request.
42
+ *
43
+ * @return Query
44
+ */
45
+ public function getQuery();
46
+
47
+ /**
48
+ * Set the query string used by the request
49
+ *
50
+ * @param array|Query $query Query to set
51
+ */
52
+ public function setQuery($query);
53
+
54
+ /**
55
+ * Get the HTTP method of the request.
56
+ *
57
+ * @return string
58
+ */
59
+ public function getMethod();
60
+
61
+ /**
62
+ * Set the HTTP method of the request.
63
+ *
64
+ * @param string $method HTTP method
65
+ */
66
+ public function setMethod($method);
67
+
68
+ /**
69
+ * Get the URI scheme of the request (http, https, etc.).
70
+ *
71
+ * @return string
72
+ */
73
+ public function getScheme();
74
+
75
+ /**
76
+ * Set the URI scheme of the request (http, https, etc.).
77
+ *
78
+ * @param string $scheme Scheme to set
79
+ */
80
+ public function setScheme($scheme);
81
+
82
+ /**
83
+ * Get the port scheme of the request (e.g., 80, 443, etc.).
84
+ *
85
+ * @return int
86
+ */
87
+ public function getPort();
88
+
89
+ /**
90
+ * Set the port of the request.
91
+ *
92
+ * Setting a port modifies the Host header of a request as necessary.
93
+ *
94
+ * @param int $port Port to set
95
+ */
96
+ public function setPort($port);
97
+
98
+ /**
99
+ * Get the host of the request.
100
+ *
101
+ * @return string
102
+ */
103
+ public function getHost();
104
+
105
+ /**
106
+ * Set the host of the request including an optional port.
107
+ *
108
+ * Including a port in the host argument will explicitly change the port of
109
+ * the request. If no port is found, the default port of the current
110
+ * request scheme will be utilized.
111
+ *
112
+ * @param string $host Host to set (e.g. www.yahoo.com, www.yahoo.com:80)
113
+ */
114
+ public function setHost($host);
115
+
116
+ /**
117
+ * Get the path of the request (e.g. '/', '/index.html').
118
+ *
119
+ * @return string
120
+ */
121
+ public function getPath();
122
+
123
+ /**
124
+ * Set the path of the request (e.g. '/', '/index.html').
125
+ *
126
+ * @param string|array $path Path to set or array of segments to implode
127
+ */
128
+ public function setPath($path);
129
+
130
+ /**
131
+ * Get the request's configuration options.
132
+ *
133
+ * @return \GuzzleHttp\Collection
134
+ */
135
+ public function getConfig();
136
+ }
backend/vendor/guzzlehttp/guzzle/src/Message/Response.php ADDED
@@ -0,0 +1,208 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Message;
3
+
4
+ use GuzzleHttp\Exception\ParseException;
5
+ use GuzzleHttp\Exception\XmlParseException;
6
+ use GuzzleHttp\Stream\StreamInterface;
7
+ use GuzzleHttp\Utils;
8
+
9
+ /**
10
+ * Guzzle HTTP response object
11
+ */
12
+ class Response extends AbstractMessage implements ResponseInterface
13
+ {
14
+ /** @var array Mapping of status codes to reason phrases */
15
+ private static $statusTexts = [
16
+ 100 => 'Continue',
17
+ 101 => 'Switching Protocols',
18
+ 102 => 'Processing',
19
+ 200 => 'OK',
20
+ 201 => 'Created',
21
+ 202 => 'Accepted',
22
+ 203 => 'Non-Authoritative Information',
23
+ 204 => 'No Content',
24
+ 205 => 'Reset Content',
25
+ 206 => 'Partial Content',
26
+ 207 => 'Multi-Status',
27
+ 208 => 'Already Reported',
28
+ 226 => 'IM Used',
29
+ 300 => 'Multiple Choices',
30
+ 301 => 'Moved Permanently',
31
+ 302 => 'Found',
32
+ 303 => 'See Other',
33
+ 304 => 'Not Modified',
34
+ 305 => 'Use Proxy',
35
+ 307 => 'Temporary Redirect',
36
+ 308 => 'Permanent Redirect',
37
+ 400 => 'Bad Request',
38
+ 401 => 'Unauthorized',
39
+ 402 => 'Payment Required',
40
+ 403 => 'Forbidden',
41
+ 404 => 'Not Found',
42
+ 405 => 'Method Not Allowed',
43
+ 406 => 'Not Acceptable',
44
+ 407 => 'Proxy Authentication Required',
45
+ 408 => 'Request Timeout',
46
+ 409 => 'Conflict',
47
+ 410 => 'Gone',
48
+ 411 => 'Length Required',
49
+ 412 => 'Precondition Failed',
50
+ 413 => 'Request Entity Too Large',
51
+ 414 => 'Request-URI Too Long',
52
+ 415 => 'Unsupported Media Type',
53
+ 416 => 'Requested Range Not Satisfiable',
54
+ 417 => 'Expectation Failed',
55
+ 422 => 'Unprocessable Entity',
56
+ 423 => 'Locked',
57
+ 424 => 'Failed Dependency',
58
+ 425 => 'Reserved for WebDAV advanced collections expired proposal',
59
+ 426 => 'Upgrade required',
60
+ 428 => 'Precondition Required',
61
+ 429 => 'Too Many Requests',
62
+ 431 => 'Request Header Fields Too Large',
63
+ 500 => 'Internal Server Error',
64
+ 501 => 'Not Implemented',
65
+ 502 => 'Bad Gateway',
66
+ 503 => 'Service Unavailable',
67
+ 504 => 'Gateway Timeout',
68
+ 505 => 'HTTP Version Not Supported',
69
+ 506 => 'Variant Also Negotiates (Experimental)',
70
+ 507 => 'Insufficient Storage',
71
+ 508 => 'Loop Detected',
72
+ 510 => 'Not Extended',
73
+ 511 => 'Network Authentication Required',
74
+ ];
75
+
76
+ /** @var string The reason phrase of the response (human readable code) */
77
+ private $reasonPhrase;
78
+
79
+ /** @var string The status code of the response */
80
+ private $statusCode;
81
+
82
+ /** @var string The effective URL that returned this response */
83
+ private $effectiveUrl;
84
+
85
+ /**
86
+ * @param int|string $statusCode The response status code (e.g. 200)
87
+ * @param array $headers The response headers
88
+ * @param StreamInterface $body The body of the response
89
+ * @param array $options Response message options
90
+ * - reason_phrase: Set a custom reason phrase
91
+ * - protocol_version: Set a custom protocol version
92
+ */
93
+ public function __construct(
94
+ $statusCode,
95
+ array $headers = [],
96
+ StreamInterface $body = null,
97
+ array $options = []
98
+ ) {
99
+ $this->statusCode = (int) $statusCode;
100
+ $this->handleOptions($options);
101
+
102
+ // Assume a reason phrase if one was not applied as an option
103
+ if (!$this->reasonPhrase &&
104
+ isset(self::$statusTexts[$this->statusCode])
105
+ ) {
106
+ $this->reasonPhrase = self::$statusTexts[$this->statusCode];
107
+ }
108
+
109
+ if ($headers) {
110
+ $this->setHeaders($headers);
111
+ }
112
+
113
+ if ($body) {
114
+ $this->setBody($body);
115
+ }
116
+ }
117
+
118
+ public function getStatusCode()
119
+ {
120
+ return $this->statusCode;
121
+ }
122
+
123
+ public function setStatusCode($code)
124
+ {
125
+ return $this->statusCode = (int) $code;
126
+ }
127
+
128
+ public function getReasonPhrase()
129
+ {
130
+ return $this->reasonPhrase;
131
+ }
132
+
133
+ public function setReasonPhrase($phrase)
134
+ {
135
+ return $this->reasonPhrase = $phrase;
136
+ }
137
+
138
+ public function json(array $config = [])
139
+ {
140
+ try {
141
+ return Utils::jsonDecode(
142
+ (string) $this->getBody(),
143
+ isset($config['object']) ? !$config['object'] : true,
144
+ 512,
145
+ isset($config['big_int_strings']) ? JSON_BIGINT_AS_STRING : 0
146
+ );
147
+ } catch (\InvalidArgumentException $e) {
148
+ throw new ParseException(
149
+ $e->getMessage(),
150
+ $this
151
+ );
152
+ }
153
+ }
154
+
155
+ public function xml(array $config = [])
156
+ {
157
+ $disableEntities = libxml_disable_entity_loader(true);
158
+ $internalErrors = libxml_use_internal_errors(true);
159
+
160
+ try {
161
+ // Allow XML to be retrieved even if there is no response body
162
+ $xml = new \SimpleXMLElement(
163
+ (string) $this->getBody() ?: '<root />',
164
+ isset($config['libxml_options']) ? $config['libxml_options'] : LIBXML_NONET,
165
+ false,
166
+ isset($config['ns']) ? $config['ns'] : '',
167
+ isset($config['ns_is_prefix']) ? $config['ns_is_prefix'] : false
168
+ );
169
+ libxml_disable_entity_loader($disableEntities);
170
+ libxml_use_internal_errors($internalErrors);
171
+ } catch (\Exception $e) {
172
+ libxml_disable_entity_loader($disableEntities);
173
+ libxml_use_internal_errors($internalErrors);
174
+ throw new XmlParseException(
175
+ 'Unable to parse response body into XML: ' . $e->getMessage(),
176
+ $this,
177
+ $e,
178
+ (libxml_get_last_error()) ?: null
179
+ );
180
+ }
181
+
182
+ return $xml;
183
+ }
184
+
185
+ public function getEffectiveUrl()
186
+ {
187
+ return $this->effectiveUrl;
188
+ }
189
+
190
+ public function setEffectiveUrl($url)
191
+ {
192
+ $this->effectiveUrl = $url;
193
+ }
194
+
195
+ /**
196
+ * Accepts and modifies the options provided to the response in the
197
+ * constructor.
198
+ *
199
+ * @param array $options Options array passed by reference.
200
+ */
201
+ protected function handleOptions(array &$options = [])
202
+ {
203
+ parent::handleOptions($options);
204
+ if (isset($options['reason_phrase'])) {
205
+ $this->reasonPhrase = $options['reason_phrase'];
206
+ }
207
+ }
208
+ }
backend/vendor/guzzlehttp/guzzle/src/Message/ResponseInterface.php ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Message;
3
+
4
+ /**
5
+ * Represents an HTTP response message.
6
+ */
7
+ interface ResponseInterface extends MessageInterface
8
+ {
9
+ /**
10
+ * Gets the response Status-Code.
11
+ *
12
+ * The Status-Code is a 3-digit integer result code of the server's attempt
13
+ * to understand and satisfy the request.
14
+ *
15
+ * @return int Status code.
16
+ */
17
+ public function getStatusCode();
18
+
19
+ /**
20
+ * Sets the status code of this response.
21
+ *
22
+ * @param int $code The 3-digit integer result code to set.
23
+ */
24
+ public function setStatusCode($code);
25
+
26
+ /**
27
+ * Gets the response Reason-Phrase, a short textual description of the
28
+ * Status-Code.
29
+ *
30
+ * Because a Reason-Phrase is not a required element in response
31
+ * Status-Line, the Reason-Phrase value MAY be null. Implementations MAY
32
+ * choose to return the default RFC 2616 recommended reason phrase for the
33
+ * response's Status-Code.
34
+ *
35
+ * @return string|null Reason phrase, or null if unknown.
36
+ */
37
+ public function getReasonPhrase();
38
+
39
+ /**
40
+ * Sets the Reason-Phrase of the response.
41
+ *
42
+ * If no Reason-Phrase is specified, implementations MAY choose to default
43
+ * to the RFC 2616 recommended reason phrase for the response's Status-Code.
44
+ *
45
+ * @param string $phrase The Reason-Phrase to set.
46
+ */
47
+ public function setReasonPhrase($phrase);
48
+
49
+ /**
50
+ * Get the effective URL that resulted in this response (e.g. the last
51
+ * redirect URL).
52
+ *
53
+ * @return string
54
+ */
55
+ public function getEffectiveUrl();
56
+
57
+ /**
58
+ * Set the effective URL that resulted in this response (e.g. the last
59
+ * redirect URL).
60
+ *
61
+ * @param string $url Effective URL
62
+ */
63
+ public function setEffectiveUrl($url);
64
+
65
+ /**
66
+ * Parse the JSON response body and return the JSON decoded data.
67
+ *
68
+ * @param array $config Associative array of configuration settings used
69
+ * to control how the JSON data is parsed. Concrete implementations MAY
70
+ * add further configuration settings as needed, but they MUST implement
71
+ * functionality for the following options:
72
+ *
73
+ * - object: Set to true to parse JSON objects as PHP objects rather
74
+ * than associative arrays. Defaults to false.
75
+ * - big_int_strings: When set to true, large integers are converted to
76
+ * strings rather than floats. Defaults to false.
77
+ *
78
+ * Implementations are free to add further configuration settings as
79
+ * needed.
80
+ *
81
+ * @return mixed Returns the JSON decoded data based on the provided
82
+ * parse settings.
83
+ * @throws \RuntimeException if the response body is not in JSON format
84
+ */
85
+ public function json(array $config = []);
86
+
87
+ /**
88
+ * Parse the XML response body and return a \SimpleXMLElement.
89
+ *
90
+ * In order to prevent XXE attacks, this method disables loading external
91
+ * entities. If you rely on external entities, then you must parse the
92
+ * XML response manually by accessing the response body directly.
93
+ *
94
+ * @param array $config Associative array of configuration settings used
95
+ * to control how the XML is parsed. Concrete implementations MAY add
96
+ * further configuration settings as needed, but they MUST implement
97
+ * functionality for the following options:
98
+ *
99
+ * - ns: Set to a string to represent the namespace prefix or URI
100
+ * - ns_is_prefix: Set to true to specify that the NS is a prefix rather
101
+ * than a URI (defaults to false).
102
+ * - libxml_options: Bitwise OR of the libxml option constants
103
+ * listed at http://php.net/manual/en/libxml.constants.php
104
+ * (defaults to LIBXML_NONET)
105
+ *
106
+ * @return \SimpleXMLElement
107
+ * @throws \RuntimeException if the response body is not in XML format
108
+ * @link http://websec.io/2012/08/27/Preventing-XXE-in-PHP.html
109
+ */
110
+ public function xml(array $config = []);
111
+ }
backend/vendor/guzzlehttp/guzzle/src/Mimetypes.php ADDED
@@ -0,0 +1,963 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ /**
5
+ * Provides mappings of file extensions to mimetypes
6
+ * @link http://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x/conf/mime.types
7
+ */
8
+ class Mimetypes
9
+ {
10
+ /** @var self */
11
+ protected static $instance;
12
+
13
+ /** @var array Mapping of extension to mimetype */
14
+ protected $mimetypes = array(
15
+ '3dml' => 'text/vnd.in3d.3dml',
16
+ '3g2' => 'video/3gpp2',
17
+ '3gp' => 'video/3gpp',
18
+ '7z' => 'application/x-7z-compressed',
19
+ 'aab' => 'application/x-authorware-bin',
20
+ 'aac' => 'audio/x-aac',
21
+ 'aam' => 'application/x-authorware-map',
22
+ 'aas' => 'application/x-authorware-seg',
23
+ 'abw' => 'application/x-abiword',
24
+ 'ac' => 'application/pkix-attr-cert',
25
+ 'acc' => 'application/vnd.americandynamics.acc',
26
+ 'ace' => 'application/x-ace-compressed',
27
+ 'acu' => 'application/vnd.acucobol',
28
+ 'acutc' => 'application/vnd.acucorp',
29
+ 'adp' => 'audio/adpcm',
30
+ 'aep' => 'application/vnd.audiograph',
31
+ 'afm' => 'application/x-font-type1',
32
+ 'afp' => 'application/vnd.ibm.modcap',
33
+ 'ahead' => 'application/vnd.ahead.space',
34
+ 'ai' => 'application/postscript',
35
+ 'aif' => 'audio/x-aiff',
36
+ 'aifc' => 'audio/x-aiff',
37
+ 'aiff' => 'audio/x-aiff',
38
+ 'air' => 'application/vnd.adobe.air-application-installer-package+zip',
39
+ 'ait' => 'application/vnd.dvb.ait',
40
+ 'ami' => 'application/vnd.amiga.ami',
41
+ 'apk' => 'application/vnd.android.package-archive',
42
+ 'application' => 'application/x-ms-application',
43
+ 'apr' => 'application/vnd.lotus-approach',
44
+ 'asa' => 'text/plain',
45
+ 'asax' => 'application/octet-stream',
46
+ 'asc' => 'application/pgp-signature',
47
+ 'ascx' => 'text/plain',
48
+ 'asf' => 'video/x-ms-asf',
49
+ 'ashx' => 'text/plain',
50
+ 'asm' => 'text/x-asm',
51
+ 'asmx' => 'text/plain',
52
+ 'aso' => 'application/vnd.accpac.simply.aso',
53
+ 'asp' => 'text/plain',
54
+ 'aspx' => 'text/plain',
55
+ 'asx' => 'video/x-ms-asf',
56
+ 'atc' => 'application/vnd.acucorp',
57
+ 'atom' => 'application/atom+xml',
58
+ 'atomcat' => 'application/atomcat+xml',
59
+ 'atomsvc' => 'application/atomsvc+xml',
60
+ 'atx' => 'application/vnd.antix.game-component',
61
+ 'au' => 'audio/basic',
62
+ 'avi' => 'video/x-msvideo',
63
+ 'aw' => 'application/applixware',
64
+ 'axd' => 'text/plain',
65
+ 'azf' => 'application/vnd.airzip.filesecure.azf',
66
+ 'azs' => 'application/vnd.airzip.filesecure.azs',
67
+ 'azw' => 'application/vnd.amazon.ebook',
68
+ 'bat' => 'application/x-msdownload',
69
+ 'bcpio' => 'application/x-bcpio',
70
+ 'bdf' => 'application/x-font-bdf',
71
+ 'bdm' => 'application/vnd.syncml.dm+wbxml',
72
+ 'bed' => 'application/vnd.realvnc.bed',
73
+ 'bh2' => 'application/vnd.fujitsu.oasysprs',
74
+ 'bin' => 'application/octet-stream',
75
+ 'bmi' => 'application/vnd.bmi',
76
+ 'bmp' => 'image/bmp',
77
+ 'book' => 'application/vnd.framemaker',
78
+ 'box' => 'application/vnd.previewsystems.box',
79
+ 'boz' => 'application/x-bzip2',
80
+ 'bpk' => 'application/octet-stream',
81
+ 'btif' => 'image/prs.btif',
82
+ 'bz' => 'application/x-bzip',
83
+ 'bz2' => 'application/x-bzip2',
84
+ 'c' => 'text/x-c',
85
+ 'c11amc' => 'application/vnd.cluetrust.cartomobile-config',
86
+ 'c11amz' => 'application/vnd.cluetrust.cartomobile-config-pkg',
87
+ 'c4d' => 'application/vnd.clonk.c4group',
88
+ 'c4f' => 'application/vnd.clonk.c4group',
89
+ 'c4g' => 'application/vnd.clonk.c4group',
90
+ 'c4p' => 'application/vnd.clonk.c4group',
91
+ 'c4u' => 'application/vnd.clonk.c4group',
92
+ 'cab' => 'application/vnd.ms-cab-compressed',
93
+ 'car' => 'application/vnd.curl.car',
94
+ 'cat' => 'application/vnd.ms-pki.seccat',
95
+ 'cc' => 'text/x-c',
96
+ 'cct' => 'application/x-director',
97
+ 'ccxml' => 'application/ccxml+xml',
98
+ 'cdbcmsg' => 'application/vnd.contact.cmsg',
99
+ 'cdf' => 'application/x-netcdf',
100
+ 'cdkey' => 'application/vnd.mediastation.cdkey',
101
+ 'cdmia' => 'application/cdmi-capability',
102
+ 'cdmic' => 'application/cdmi-container',
103
+ 'cdmid' => 'application/cdmi-domain',
104
+ 'cdmio' => 'application/cdmi-object',
105
+ 'cdmiq' => 'application/cdmi-queue',
106
+ 'cdx' => 'chemical/x-cdx',
107
+ 'cdxml' => 'application/vnd.chemdraw+xml',
108
+ 'cdy' => 'application/vnd.cinderella',
109
+ 'cer' => 'application/pkix-cert',
110
+ 'cfc' => 'application/x-coldfusion',
111
+ 'cfm' => 'application/x-coldfusion',
112
+ 'cgm' => 'image/cgm',
113
+ 'chat' => 'application/x-chat',
114
+ 'chm' => 'application/vnd.ms-htmlhelp',
115
+ 'chrt' => 'application/vnd.kde.kchart',
116
+ 'cif' => 'chemical/x-cif',
117
+ 'cii' => 'application/vnd.anser-web-certificate-issue-initiation',
118
+ 'cil' => 'application/vnd.ms-artgalry',
119
+ 'cla' => 'application/vnd.claymore',
120
+ 'class' => 'application/java-vm',
121
+ 'clkk' => 'application/vnd.crick.clicker.keyboard',
122
+ 'clkp' => 'application/vnd.crick.clicker.palette',
123
+ 'clkt' => 'application/vnd.crick.clicker.template',
124
+ 'clkw' => 'application/vnd.crick.clicker.wordbank',
125
+ 'clkx' => 'application/vnd.crick.clicker',
126
+ 'clp' => 'application/x-msclip',
127
+ 'cmc' => 'application/vnd.cosmocaller',
128
+ 'cmdf' => 'chemical/x-cmdf',
129
+ 'cml' => 'chemical/x-cml',
130
+ 'cmp' => 'application/vnd.yellowriver-custom-menu',
131
+ 'cmx' => 'image/x-cmx',
132
+ 'cod' => 'application/vnd.rim.cod',
133
+ 'com' => 'application/x-msdownload',
134
+ 'conf' => 'text/plain',
135
+ 'cpio' => 'application/x-cpio',
136
+ 'cpp' => 'text/x-c',
137
+ 'cpt' => 'application/mac-compactpro',
138
+ 'crd' => 'application/x-mscardfile',
139
+ 'crl' => 'application/pkix-crl',
140
+ 'crt' => 'application/x-x509-ca-cert',
141
+ 'cryptonote' => 'application/vnd.rig.cryptonote',
142
+ 'cs' => 'text/plain',
143
+ 'csh' => 'application/x-csh',
144
+ 'csml' => 'chemical/x-csml',
145
+ 'csp' => 'application/vnd.commonspace',
146
+ 'css' => 'text/css',
147
+ 'cst' => 'application/x-director',
148
+ 'csv' => 'text/csv',
149
+ 'cu' => 'application/cu-seeme',
150
+ 'curl' => 'text/vnd.curl',
151
+ 'cww' => 'application/prs.cww',
152
+ 'cxt' => 'application/x-director',
153
+ 'cxx' => 'text/x-c',
154
+ 'dae' => 'model/vnd.collada+xml',
155
+ 'daf' => 'application/vnd.mobius.daf',
156
+ 'dataless' => 'application/vnd.fdsn.seed',
157
+ 'davmount' => 'application/davmount+xml',
158
+ 'dcr' => 'application/x-director',
159
+ 'dcurl' => 'text/vnd.curl.dcurl',
160
+ 'dd2' => 'application/vnd.oma.dd2+xml',
161
+ 'ddd' => 'application/vnd.fujixerox.ddd',
162
+ 'deb' => 'application/x-debian-package',
163
+ 'def' => 'text/plain',
164
+ 'deploy' => 'application/octet-stream',
165
+ 'der' => 'application/x-x509-ca-cert',
166
+ 'dfac' => 'application/vnd.dreamfactory',
167
+ 'dic' => 'text/x-c',
168
+ 'dir' => 'application/x-director',
169
+ 'dis' => 'application/vnd.mobius.dis',
170
+ 'dist' => 'application/octet-stream',
171
+ 'distz' => 'application/octet-stream',
172
+ 'djv' => 'image/vnd.djvu',
173
+ 'djvu' => 'image/vnd.djvu',
174
+ 'dll' => 'application/x-msdownload',
175
+ 'dmg' => 'application/octet-stream',
176
+ 'dms' => 'application/octet-stream',
177
+ 'dna' => 'application/vnd.dna',
178
+ 'doc' => 'application/msword',
179
+ 'docm' => 'application/vnd.ms-word.document.macroenabled.12',
180
+ 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
181
+ 'dot' => 'application/msword',
182
+ 'dotm' => 'application/vnd.ms-word.template.macroenabled.12',
183
+ 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
184
+ 'dp' => 'application/vnd.osgi.dp',
185
+ 'dpg' => 'application/vnd.dpgraph',
186
+ 'dra' => 'audio/vnd.dra',
187
+ 'dsc' => 'text/prs.lines.tag',
188
+ 'dssc' => 'application/dssc+der',
189
+ 'dtb' => 'application/x-dtbook+xml',
190
+ 'dtd' => 'application/xml-dtd',
191
+ 'dts' => 'audio/vnd.dts',
192
+ 'dtshd' => 'audio/vnd.dts.hd',
193
+ 'dump' => 'application/octet-stream',
194
+ 'dvi' => 'application/x-dvi',
195
+ 'dwf' => 'model/vnd.dwf',
196
+ 'dwg' => 'image/vnd.dwg',
197
+ 'dxf' => 'image/vnd.dxf',
198
+ 'dxp' => 'application/vnd.spotfire.dxp',
199
+ 'dxr' => 'application/x-director',
200
+ 'ecelp4800' => 'audio/vnd.nuera.ecelp4800',
201
+ 'ecelp7470' => 'audio/vnd.nuera.ecelp7470',
202
+ 'ecelp9600' => 'audio/vnd.nuera.ecelp9600',
203
+ 'ecma' => 'application/ecmascript',
204
+ 'edm' => 'application/vnd.novadigm.edm',
205
+ 'edx' => 'application/vnd.novadigm.edx',
206
+ 'efif' => 'application/vnd.picsel',
207
+ 'ei6' => 'application/vnd.pg.osasli',
208
+ 'elc' => 'application/octet-stream',
209
+ 'eml' => 'message/rfc822',
210
+ 'emma' => 'application/emma+xml',
211
+ 'eol' => 'audio/vnd.digital-winds',
212
+ 'eot' => 'application/vnd.ms-fontobject',
213
+ 'eps' => 'application/postscript',
214
+ 'epub' => 'application/epub+zip',
215
+ 'es3' => 'application/vnd.eszigno3+xml',
216
+ 'esf' => 'application/vnd.epson.esf',
217
+ 'et3' => 'application/vnd.eszigno3+xml',
218
+ 'etx' => 'text/x-setext',
219
+ 'exe' => 'application/x-msdownload',
220
+ 'exi' => 'application/exi',
221
+ 'ext' => 'application/vnd.novadigm.ext',
222
+ 'ez' => 'application/andrew-inset',
223
+ 'ez2' => 'application/vnd.ezpix-album',
224
+ 'ez3' => 'application/vnd.ezpix-package',
225
+ 'f' => 'text/x-fortran',
226
+ 'f4v' => 'video/x-f4v',
227
+ 'f77' => 'text/x-fortran',
228
+ 'f90' => 'text/x-fortran',
229
+ 'fbs' => 'image/vnd.fastbidsheet',
230
+ 'fcs' => 'application/vnd.isac.fcs',
231
+ 'fdf' => 'application/vnd.fdf',
232
+ 'fe_launch' => 'application/vnd.denovo.fcselayout-link',
233
+ 'fg5' => 'application/vnd.fujitsu.oasysgp',
234
+ 'fgd' => 'application/x-director',
235
+ 'fh' => 'image/x-freehand',
236
+ 'fh4' => 'image/x-freehand',
237
+ 'fh5' => 'image/x-freehand',
238
+ 'fh7' => 'image/x-freehand',
239
+ 'fhc' => 'image/x-freehand',
240
+ 'fig' => 'application/x-xfig',
241
+ 'fli' => 'video/x-fli',
242
+ 'flo' => 'application/vnd.micrografx.flo',
243
+ 'flv' => 'video/x-flv',
244
+ 'flw' => 'application/vnd.kde.kivio',
245
+ 'flx' => 'text/vnd.fmi.flexstor',
246
+ 'fly' => 'text/vnd.fly',
247
+ 'fm' => 'application/vnd.framemaker',
248
+ 'fnc' => 'application/vnd.frogans.fnc',
249
+ 'for' => 'text/x-fortran',
250
+ 'fpx' => 'image/vnd.fpx',
251
+ 'frame' => 'application/vnd.framemaker',
252
+ 'fsc' => 'application/vnd.fsc.weblaunch',
253
+ 'fst' => 'image/vnd.fst',
254
+ 'ftc' => 'application/vnd.fluxtime.clip',
255
+ 'fti' => 'application/vnd.anser-web-funds-transfer-initiation',
256
+ 'fvt' => 'video/vnd.fvt',
257
+ 'fxp' => 'application/vnd.adobe.fxp',
258
+ 'fxpl' => 'application/vnd.adobe.fxp',
259
+ 'fzs' => 'application/vnd.fuzzysheet',
260
+ 'g2w' => 'application/vnd.geoplan',
261
+ 'g3' => 'image/g3fax',
262
+ 'g3w' => 'application/vnd.geospace',
263
+ 'gac' => 'application/vnd.groove-account',
264
+ 'gdl' => 'model/vnd.gdl',
265
+ 'geo' => 'application/vnd.dynageo',
266
+ 'gex' => 'application/vnd.geometry-explorer',
267
+ 'ggb' => 'application/vnd.geogebra.file',
268
+ 'ggt' => 'application/vnd.geogebra.tool',
269
+ 'ghf' => 'application/vnd.groove-help',
270
+ 'gif' => 'image/gif',
271
+ 'gim' => 'application/vnd.groove-identity-message',
272
+ 'gmx' => 'application/vnd.gmx',
273
+ 'gnumeric' => 'application/x-gnumeric',
274
+ 'gph' => 'application/vnd.flographit',
275
+ 'gqf' => 'application/vnd.grafeq',
276
+ 'gqs' => 'application/vnd.grafeq',
277
+ 'gram' => 'application/srgs',
278
+ 'gre' => 'application/vnd.geometry-explorer',
279
+ 'grv' => 'application/vnd.groove-injector',
280
+ 'grxml' => 'application/srgs+xml',
281
+ 'gsf' => 'application/x-font-ghostscript',
282
+ 'gtar' => 'application/x-gtar',
283
+ 'gtm' => 'application/vnd.groove-tool-message',
284
+ 'gtw' => 'model/vnd.gtw',
285
+ 'gv' => 'text/vnd.graphviz',
286
+ 'gxt' => 'application/vnd.geonext',
287
+ 'h' => 'text/x-c',
288
+ 'h261' => 'video/h261',
289
+ 'h263' => 'video/h263',
290
+ 'h264' => 'video/h264',
291
+ 'hal' => 'application/vnd.hal+xml',
292
+ 'hbci' => 'application/vnd.hbci',
293
+ 'hdf' => 'application/x-hdf',
294
+ 'hh' => 'text/x-c',
295
+ 'hlp' => 'application/winhlp',
296
+ 'hpgl' => 'application/vnd.hp-hpgl',
297
+ 'hpid' => 'application/vnd.hp-hpid',
298
+ 'hps' => 'application/vnd.hp-hps',
299
+ 'hqx' => 'application/mac-binhex40',
300
+ 'hta' => 'application/octet-stream',
301
+ 'htc' => 'text/html',
302
+ 'htke' => 'application/vnd.kenameaapp',
303
+ 'htm' => 'text/html',
304
+ 'html' => 'text/html',
305
+ 'hvd' => 'application/vnd.yamaha.hv-dic',
306
+ 'hvp' => 'application/vnd.yamaha.hv-voice',
307
+ 'hvs' => 'application/vnd.yamaha.hv-script',
308
+ 'i2g' => 'application/vnd.intergeo',
309
+ 'icc' => 'application/vnd.iccprofile',
310
+ 'ice' => 'x-conference/x-cooltalk',
311
+ 'icm' => 'application/vnd.iccprofile',
312
+ 'ico' => 'image/x-icon',
313
+ 'ics' => 'text/calendar',
314
+ 'ief' => 'image/ief',
315
+ 'ifb' => 'text/calendar',
316
+ 'ifm' => 'application/vnd.shana.informed.formdata',
317
+ 'iges' => 'model/iges',
318
+ 'igl' => 'application/vnd.igloader',
319
+ 'igm' => 'application/vnd.insors.igm',
320
+ 'igs' => 'model/iges',
321
+ 'igx' => 'application/vnd.micrografx.igx',
322
+ 'iif' => 'application/vnd.shana.informed.interchange',
323
+ 'imp' => 'application/vnd.accpac.simply.imp',
324
+ 'ims' => 'application/vnd.ms-ims',
325
+ 'in' => 'text/plain',
326
+ 'ini' => 'text/plain',
327
+ 'ipfix' => 'application/ipfix',
328
+ 'ipk' => 'application/vnd.shana.informed.package',
329
+ 'irm' => 'application/vnd.ibm.rights-management',
330
+ 'irp' => 'application/vnd.irepository.package+xml',
331
+ 'iso' => 'application/octet-stream',
332
+ 'itp' => 'application/vnd.shana.informed.formtemplate',
333
+ 'ivp' => 'application/vnd.immervision-ivp',
334
+ 'ivu' => 'application/vnd.immervision-ivu',
335
+ 'jad' => 'text/vnd.sun.j2me.app-descriptor',
336
+ 'jam' => 'application/vnd.jam',
337
+ 'jar' => 'application/java-archive',
338
+ 'java' => 'text/x-java-source',
339
+ 'jisp' => 'application/vnd.jisp',
340
+ 'jlt' => 'application/vnd.hp-jlyt',
341
+ 'jnlp' => 'application/x-java-jnlp-file',
342
+ 'joda' => 'application/vnd.joost.joda-archive',
343
+ 'jpe' => 'image/jpeg',
344
+ 'jpeg' => 'image/jpeg',
345
+ 'jpg' => 'image/jpeg',
346
+ 'jpgm' => 'video/jpm',
347
+ 'jpgv' => 'video/jpeg',
348
+ 'jpm' => 'video/jpm',
349
+ 'js' => 'text/javascript',
350
+ 'json' => 'application/json',
351
+ 'kar' => 'audio/midi',
352
+ 'karbon' => 'application/vnd.kde.karbon',
353
+ 'kfo' => 'application/vnd.kde.kformula',
354
+ 'kia' => 'application/vnd.kidspiration',
355
+ 'kml' => 'application/vnd.google-earth.kml+xml',
356
+ 'kmz' => 'application/vnd.google-earth.kmz',
357
+ 'kne' => 'application/vnd.kinar',
358
+ 'knp' => 'application/vnd.kinar',
359
+ 'kon' => 'application/vnd.kde.kontour',
360
+ 'kpr' => 'application/vnd.kde.kpresenter',
361
+ 'kpt' => 'application/vnd.kde.kpresenter',
362
+ 'ksp' => 'application/vnd.kde.kspread',
363
+ 'ktr' => 'application/vnd.kahootz',
364
+ 'ktx' => 'image/ktx',
365
+ 'ktz' => 'application/vnd.kahootz',
366
+ 'kwd' => 'application/vnd.kde.kword',
367
+ 'kwt' => 'application/vnd.kde.kword',
368
+ 'lasxml' => 'application/vnd.las.las+xml',
369
+ 'latex' => 'application/x-latex',
370
+ 'lbd' => 'application/vnd.llamagraphics.life-balance.desktop',
371
+ 'lbe' => 'application/vnd.llamagraphics.life-balance.exchange+xml',
372
+ 'les' => 'application/vnd.hhe.lesson-player',
373
+ 'lha' => 'application/octet-stream',
374
+ 'link66' => 'application/vnd.route66.link66+xml',
375
+ 'list' => 'text/plain',
376
+ 'list3820' => 'application/vnd.ibm.modcap',
377
+ 'listafp' => 'application/vnd.ibm.modcap',
378
+ 'log' => 'text/plain',
379
+ 'lostxml' => 'application/lost+xml',
380
+ 'lrf' => 'application/octet-stream',
381
+ 'lrm' => 'application/vnd.ms-lrm',
382
+ 'ltf' => 'application/vnd.frogans.ltf',
383
+ 'lvp' => 'audio/vnd.lucent.voice',
384
+ 'lwp' => 'application/vnd.lotus-wordpro',
385
+ 'lzh' => 'application/octet-stream',
386
+ 'm13' => 'application/x-msmediaview',
387
+ 'm14' => 'application/x-msmediaview',
388
+ 'm1v' => 'video/mpeg',
389
+ 'm21' => 'application/mp21',
390
+ 'm2a' => 'audio/mpeg',
391
+ 'm2v' => 'video/mpeg',
392
+ 'm3a' => 'audio/mpeg',
393
+ 'm3u' => 'audio/x-mpegurl',
394
+ 'm3u8' => 'application/vnd.apple.mpegurl',
395
+ 'm4a' => 'audio/mp4',
396
+ 'm4u' => 'video/vnd.mpegurl',
397
+ 'm4v' => 'video/mp4',
398
+ 'ma' => 'application/mathematica',
399
+ 'mads' => 'application/mads+xml',
400
+ 'mag' => 'application/vnd.ecowin.chart',
401
+ 'maker' => 'application/vnd.framemaker',
402
+ 'man' => 'text/troff',
403
+ 'mathml' => 'application/mathml+xml',
404
+ 'mb' => 'application/mathematica',
405
+ 'mbk' => 'application/vnd.mobius.mbk',
406
+ 'mbox' => 'application/mbox',
407
+ 'mc1' => 'application/vnd.medcalcdata',
408
+ 'mcd' => 'application/vnd.mcd',
409
+ 'mcurl' => 'text/vnd.curl.mcurl',
410
+ 'mdb' => 'application/x-msaccess',
411
+ 'mdi' => 'image/vnd.ms-modi',
412
+ 'me' => 'text/troff',
413
+ 'mesh' => 'model/mesh',
414
+ 'meta4' => 'application/metalink4+xml',
415
+ 'mets' => 'application/mets+xml',
416
+ 'mfm' => 'application/vnd.mfmp',
417
+ 'mgp' => 'application/vnd.osgeo.mapguide.package',
418
+ 'mgz' => 'application/vnd.proteus.magazine',
419
+ 'mid' => 'audio/midi',
420
+ 'midi' => 'audio/midi',
421
+ 'mif' => 'application/vnd.mif',
422
+ 'mime' => 'message/rfc822',
423
+ 'mj2' => 'video/mj2',
424
+ 'mjp2' => 'video/mj2',
425
+ 'mlp' => 'application/vnd.dolby.mlp',
426
+ 'mmd' => 'application/vnd.chipnuts.karaoke-mmd',
427
+ 'mmf' => 'application/vnd.smaf',
428
+ 'mmr' => 'image/vnd.fujixerox.edmics-mmr',
429
+ 'mny' => 'application/x-msmoney',
430
+ 'mobi' => 'application/x-mobipocket-ebook',
431
+ 'mods' => 'application/mods+xml',
432
+ 'mov' => 'video/quicktime',
433
+ 'movie' => 'video/x-sgi-movie',
434
+ 'mp2' => 'audio/mpeg',
435
+ 'mp21' => 'application/mp21',
436
+ 'mp2a' => 'audio/mpeg',
437
+ 'mp3' => 'audio/mpeg',
438
+ 'mp4' => 'video/mp4',
439
+ 'mp4a' => 'audio/mp4',
440
+ 'mp4s' => 'application/mp4',
441
+ 'mp4v' => 'video/mp4',
442
+ 'mpc' => 'application/vnd.mophun.certificate',
443
+ 'mpe' => 'video/mpeg',
444
+ 'mpeg' => 'video/mpeg',
445
+ 'mpg' => 'video/mpeg',
446
+ 'mpg4' => 'video/mp4',
447
+ 'mpga' => 'audio/mpeg',
448
+ 'mpkg' => 'application/vnd.apple.installer+xml',
449
+ 'mpm' => 'application/vnd.blueice.multipass',
450
+ 'mpn' => 'application/vnd.mophun.application',
451
+ 'mpp' => 'application/vnd.ms-project',
452
+ 'mpt' => 'application/vnd.ms-project',
453
+ 'mpy' => 'application/vnd.ibm.minipay',
454
+ 'mqy' => 'application/vnd.mobius.mqy',
455
+ 'mrc' => 'application/marc',
456
+ 'mrcx' => 'application/marcxml+xml',
457
+ 'ms' => 'text/troff',
458
+ 'mscml' => 'application/mediaservercontrol+xml',
459
+ 'mseed' => 'application/vnd.fdsn.mseed',
460
+ 'mseq' => 'application/vnd.mseq',
461
+ 'msf' => 'application/vnd.epson.msf',
462
+ 'msh' => 'model/mesh',
463
+ 'msi' => 'application/x-msdownload',
464
+ 'msl' => 'application/vnd.mobius.msl',
465
+ 'msty' => 'application/vnd.muvee.style',
466
+ 'mts' => 'model/vnd.mts',
467
+ 'mus' => 'application/vnd.musician',
468
+ 'musicxml' => 'application/vnd.recordare.musicxml+xml',
469
+ 'mvb' => 'application/x-msmediaview',
470
+ 'mwf' => 'application/vnd.mfer',
471
+ 'mxf' => 'application/mxf',
472
+ 'mxl' => 'application/vnd.recordare.musicxml',
473
+ 'mxml' => 'application/xv+xml',
474
+ 'mxs' => 'application/vnd.triscape.mxs',
475
+ 'mxu' => 'video/vnd.mpegurl',
476
+ 'n-gage' => 'application/vnd.nokia.n-gage.symbian.install',
477
+ 'n3' => 'text/n3',
478
+ 'nb' => 'application/mathematica',
479
+ 'nbp' => 'application/vnd.wolfram.player',
480
+ 'nc' => 'application/x-netcdf',
481
+ 'ncx' => 'application/x-dtbncx+xml',
482
+ 'ngdat' => 'application/vnd.nokia.n-gage.data',
483
+ 'nlu' => 'application/vnd.neurolanguage.nlu',
484
+ 'nml' => 'application/vnd.enliven',
485
+ 'nnd' => 'application/vnd.noblenet-directory',
486
+ 'nns' => 'application/vnd.noblenet-sealer',
487
+ 'nnw' => 'application/vnd.noblenet-web',
488
+ 'npx' => 'image/vnd.net-fpx',
489
+ 'nsf' => 'application/vnd.lotus-notes',
490
+ 'oa2' => 'application/vnd.fujitsu.oasys2',
491
+ 'oa3' => 'application/vnd.fujitsu.oasys3',
492
+ 'oas' => 'application/vnd.fujitsu.oasys',
493
+ 'obd' => 'application/x-msbinder',
494
+ 'oda' => 'application/oda',
495
+ 'odb' => 'application/vnd.oasis.opendocument.database',
496
+ 'odc' => 'application/vnd.oasis.opendocument.chart',
497
+ 'odf' => 'application/vnd.oasis.opendocument.formula',
498
+ 'odft' => 'application/vnd.oasis.opendocument.formula-template',
499
+ 'odg' => 'application/vnd.oasis.opendocument.graphics',
500
+ 'odi' => 'application/vnd.oasis.opendocument.image',
501
+ 'odm' => 'application/vnd.oasis.opendocument.text-master',
502
+ 'odp' => 'application/vnd.oasis.opendocument.presentation',
503
+ 'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
504
+ 'odt' => 'application/vnd.oasis.opendocument.text',
505
+ 'oga' => 'audio/ogg',
506
+ 'ogg' => 'audio/ogg',
507
+ 'ogv' => 'video/ogg',
508
+ 'ogx' => 'application/ogg',
509
+ 'onepkg' => 'application/onenote',
510
+ 'onetmp' => 'application/onenote',
511
+ 'onetoc' => 'application/onenote',
512
+ 'onetoc2' => 'application/onenote',
513
+ 'opf' => 'application/oebps-package+xml',
514
+ 'oprc' => 'application/vnd.palm',
515
+ 'org' => 'application/vnd.lotus-organizer',
516
+ 'osf' => 'application/vnd.yamaha.openscoreformat',
517
+ 'osfpvg' => 'application/vnd.yamaha.openscoreformat.osfpvg+xml',
518
+ 'otc' => 'application/vnd.oasis.opendocument.chart-template',
519
+ 'otf' => 'application/x-font-otf',
520
+ 'otg' => 'application/vnd.oasis.opendocument.graphics-template',
521
+ 'oth' => 'application/vnd.oasis.opendocument.text-web',
522
+ 'oti' => 'application/vnd.oasis.opendocument.image-template',
523
+ 'otp' => 'application/vnd.oasis.opendocument.presentation-template',
524
+ 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template',
525
+ 'ott' => 'application/vnd.oasis.opendocument.text-template',
526
+ 'oxt' => 'application/vnd.openofficeorg.extension',
527
+ 'p' => 'text/x-pascal',
528
+ 'p10' => 'application/pkcs10',
529
+ 'p12' => 'application/x-pkcs12',
530
+ 'p7b' => 'application/x-pkcs7-certificates',
531
+ 'p7c' => 'application/pkcs7-mime',
532
+ 'p7m' => 'application/pkcs7-mime',
533
+ 'p7r' => 'application/x-pkcs7-certreqresp',
534
+ 'p7s' => 'application/pkcs7-signature',
535
+ 'p8' => 'application/pkcs8',
536
+ 'pas' => 'text/x-pascal',
537
+ 'paw' => 'application/vnd.pawaafile',
538
+ 'pbd' => 'application/vnd.powerbuilder6',
539
+ 'pbm' => 'image/x-portable-bitmap',
540
+ 'pcf' => 'application/x-font-pcf',
541
+ 'pcl' => 'application/vnd.hp-pcl',
542
+ 'pclxl' => 'application/vnd.hp-pclxl',
543
+ 'pct' => 'image/x-pict',
544
+ 'pcurl' => 'application/vnd.curl.pcurl',
545
+ 'pcx' => 'image/x-pcx',
546
+ 'pdb' => 'application/vnd.palm',
547
+ 'pdf' => 'application/pdf',
548
+ 'pfa' => 'application/x-font-type1',
549
+ 'pfb' => 'application/x-font-type1',
550
+ 'pfm' => 'application/x-font-type1',
551
+ 'pfr' => 'application/font-tdpfr',
552
+ 'pfx' => 'application/x-pkcs12',
553
+ 'pgm' => 'image/x-portable-graymap',
554
+ 'pgn' => 'application/x-chess-pgn',
555
+ 'pgp' => 'application/pgp-encrypted',
556
+ 'php' => 'text/x-php',
557
+ 'phps' => 'application/x-httpd-phps',
558
+ 'pic' => 'image/x-pict',
559
+ 'pkg' => 'application/octet-stream',
560
+ 'pki' => 'application/pkixcmp',
561
+ 'pkipath' => 'application/pkix-pkipath',
562
+ 'plb' => 'application/vnd.3gpp.pic-bw-large',
563
+ 'plc' => 'application/vnd.mobius.plc',
564
+ 'plf' => 'application/vnd.pocketlearn',
565
+ 'pls' => 'application/pls+xml',
566
+ 'pml' => 'application/vnd.ctc-posml',
567
+ 'png' => 'image/png',
568
+ 'pnm' => 'image/x-portable-anymap',
569
+ 'portpkg' => 'application/vnd.macports.portpkg',
570
+ 'pot' => 'application/vnd.ms-powerpoint',
571
+ 'potm' => 'application/vnd.ms-powerpoint.template.macroenabled.12',
572
+ 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
573
+ 'ppam' => 'application/vnd.ms-powerpoint.addin.macroenabled.12',
574
+ 'ppd' => 'application/vnd.cups-ppd',
575
+ 'ppm' => 'image/x-portable-pixmap',
576
+ 'pps' => 'application/vnd.ms-powerpoint',
577
+ 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroenabled.12',
578
+ 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
579
+ 'ppt' => 'application/vnd.ms-powerpoint',
580
+ 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroenabled.12',
581
+ 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
582
+ 'pqa' => 'application/vnd.palm',
583
+ 'prc' => 'application/x-mobipocket-ebook',
584
+ 'pre' => 'application/vnd.lotus-freelance',
585
+ 'prf' => 'application/pics-rules',
586
+ 'ps' => 'application/postscript',
587
+ 'psb' => 'application/vnd.3gpp.pic-bw-small',
588
+ 'psd' => 'image/vnd.adobe.photoshop',
589
+ 'psf' => 'application/x-font-linux-psf',
590
+ 'pskcxml' => 'application/pskc+xml',
591
+ 'ptid' => 'application/vnd.pvi.ptid1',
592
+ 'pub' => 'application/x-mspublisher',
593
+ 'pvb' => 'application/vnd.3gpp.pic-bw-var',
594
+ 'pwn' => 'application/vnd.3m.post-it-notes',
595
+ 'pya' => 'audio/vnd.ms-playready.media.pya',
596
+ 'pyv' => 'video/vnd.ms-playready.media.pyv',
597
+ 'qam' => 'application/vnd.epson.quickanime',
598
+ 'qbo' => 'application/vnd.intu.qbo',
599
+ 'qfx' => 'application/vnd.intu.qfx',
600
+ 'qps' => 'application/vnd.publishare-delta-tree',
601
+ 'qt' => 'video/quicktime',
602
+ 'qwd' => 'application/vnd.quark.quarkxpress',
603
+ 'qwt' => 'application/vnd.quark.quarkxpress',
604
+ 'qxb' => 'application/vnd.quark.quarkxpress',
605
+ 'qxd' => 'application/vnd.quark.quarkxpress',
606
+ 'qxl' => 'application/vnd.quark.quarkxpress',
607
+ 'qxt' => 'application/vnd.quark.quarkxpress',
608
+ 'ra' => 'audio/x-pn-realaudio',
609
+ 'ram' => 'audio/x-pn-realaudio',
610
+ 'rar' => 'application/x-rar-compressed',
611
+ 'ras' => 'image/x-cmu-raster',
612
+ 'rb' => 'text/plain',
613
+ 'rcprofile' => 'application/vnd.ipunplugged.rcprofile',
614
+ 'rdf' => 'application/rdf+xml',
615
+ 'rdz' => 'application/vnd.data-vision.rdz',
616
+ 'rep' => 'application/vnd.businessobjects',
617
+ 'res' => 'application/x-dtbresource+xml',
618
+ 'resx' => 'text/xml',
619
+ 'rgb' => 'image/x-rgb',
620
+ 'rif' => 'application/reginfo+xml',
621
+ 'rip' => 'audio/vnd.rip',
622
+ 'rl' => 'application/resource-lists+xml',
623
+ 'rlc' => 'image/vnd.fujixerox.edmics-rlc',
624
+ 'rld' => 'application/resource-lists-diff+xml',
625
+ 'rm' => 'application/vnd.rn-realmedia',
626
+ 'rmi' => 'audio/midi',
627
+ 'rmp' => 'audio/x-pn-realaudio-plugin',
628
+ 'rms' => 'application/vnd.jcp.javame.midlet-rms',
629
+ 'rnc' => 'application/relax-ng-compact-syntax',
630
+ 'roff' => 'text/troff',
631
+ 'rp9' => 'application/vnd.cloanto.rp9',
632
+ 'rpss' => 'application/vnd.nokia.radio-presets',
633
+ 'rpst' => 'application/vnd.nokia.radio-preset',
634
+ 'rq' => 'application/sparql-query',
635
+ 'rs' => 'application/rls-services+xml',
636
+ 'rsd' => 'application/rsd+xml',
637
+ 'rss' => 'application/rss+xml',
638
+ 'rtf' => 'application/rtf',
639
+ 'rtx' => 'text/richtext',
640
+ 's' => 'text/x-asm',
641
+ 'saf' => 'application/vnd.yamaha.smaf-audio',
642
+ 'sbml' => 'application/sbml+xml',
643
+ 'sc' => 'application/vnd.ibm.secure-container',
644
+ 'scd' => 'application/x-msschedule',
645
+ 'scm' => 'application/vnd.lotus-screencam',
646
+ 'scq' => 'application/scvp-cv-request',
647
+ 'scs' => 'application/scvp-cv-response',
648
+ 'scurl' => 'text/vnd.curl.scurl',
649
+ 'sda' => 'application/vnd.stardivision.draw',
650
+ 'sdc' => 'application/vnd.stardivision.calc',
651
+ 'sdd' => 'application/vnd.stardivision.impress',
652
+ 'sdkd' => 'application/vnd.solent.sdkm+xml',
653
+ 'sdkm' => 'application/vnd.solent.sdkm+xml',
654
+ 'sdp' => 'application/sdp',
655
+ 'sdw' => 'application/vnd.stardivision.writer',
656
+ 'see' => 'application/vnd.seemail',
657
+ 'seed' => 'application/vnd.fdsn.seed',
658
+ 'sema' => 'application/vnd.sema',
659
+ 'semd' => 'application/vnd.semd',
660
+ 'semf' => 'application/vnd.semf',
661
+ 'ser' => 'application/java-serialized-object',
662
+ 'setpay' => 'application/set-payment-initiation',
663
+ 'setreg' => 'application/set-registration-initiation',
664
+ 'sfd-hdstx' => 'application/vnd.hydrostatix.sof-data',
665
+ 'sfs' => 'application/vnd.spotfire.sfs',
666
+ 'sgl' => 'application/vnd.stardivision.writer-global',
667
+ 'sgm' => 'text/sgml',
668
+ 'sgml' => 'text/sgml',
669
+ 'sh' => 'application/x-sh',
670
+ 'shar' => 'application/x-shar',
671
+ 'shf' => 'application/shf+xml',
672
+ 'sig' => 'application/pgp-signature',
673
+ 'silo' => 'model/mesh',
674
+ 'sis' => 'application/vnd.symbian.install',
675
+ 'sisx' => 'application/vnd.symbian.install',
676
+ 'sit' => 'application/x-stuffit',
677
+ 'sitx' => 'application/x-stuffitx',
678
+ 'skd' => 'application/vnd.koan',
679
+ 'skm' => 'application/vnd.koan',
680
+ 'skp' => 'application/vnd.koan',
681
+ 'skt' => 'application/vnd.koan',
682
+ 'sldm' => 'application/vnd.ms-powerpoint.slide.macroenabled.12',
683
+ 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
684
+ 'slt' => 'application/vnd.epson.salt',
685
+ 'sm' => 'application/vnd.stepmania.stepchart',
686
+ 'smf' => 'application/vnd.stardivision.math',
687
+ 'smi' => 'application/smil+xml',
688
+ 'smil' => 'application/smil+xml',
689
+ 'snd' => 'audio/basic',
690
+ 'snf' => 'application/x-font-snf',
691
+ 'so' => 'application/octet-stream',
692
+ 'spc' => 'application/x-pkcs7-certificates',
693
+ 'spf' => 'application/vnd.yamaha.smaf-phrase',
694
+ 'spl' => 'application/x-futuresplash',
695
+ 'spot' => 'text/vnd.in3d.spot',
696
+ 'spp' => 'application/scvp-vp-response',
697
+ 'spq' => 'application/scvp-vp-request',
698
+ 'spx' => 'audio/ogg',
699
+ 'src' => 'application/x-wais-source',
700
+ 'sru' => 'application/sru+xml',
701
+ 'srx' => 'application/sparql-results+xml',
702
+ 'sse' => 'application/vnd.kodak-descriptor',
703
+ 'ssf' => 'application/vnd.epson.ssf',
704
+ 'ssml' => 'application/ssml+xml',
705
+ 'st' => 'application/vnd.sailingtracker.track',
706
+ 'stc' => 'application/vnd.sun.xml.calc.template',
707
+ 'std' => 'application/vnd.sun.xml.draw.template',
708
+ 'stf' => 'application/vnd.wt.stf',
709
+ 'sti' => 'application/vnd.sun.xml.impress.template',
710
+ 'stk' => 'application/hyperstudio',
711
+ 'stl' => 'application/vnd.ms-pki.stl',
712
+ 'str' => 'application/vnd.pg.format',
713
+ 'stw' => 'application/vnd.sun.xml.writer.template',
714
+ 'sub' => 'image/vnd.dvb.subtitle',
715
+ 'sus' => 'application/vnd.sus-calendar',
716
+ 'susp' => 'application/vnd.sus-calendar',
717
+ 'sv4cpio' => 'application/x-sv4cpio',
718
+ 'sv4crc' => 'application/x-sv4crc',
719
+ 'svc' => 'application/vnd.dvb.service',
720
+ 'svd' => 'application/vnd.svd',
721
+ 'svg' => 'image/svg+xml',
722
+ 'svgz' => 'image/svg+xml',
723
+ 'swa' => 'application/x-director',
724
+ 'swf' => 'application/x-shockwave-flash',
725
+ 'swi' => 'application/vnd.aristanetworks.swi',
726
+ 'sxc' => 'application/vnd.sun.xml.calc',
727
+ 'sxd' => 'application/vnd.sun.xml.draw',
728
+ 'sxg' => 'application/vnd.sun.xml.writer.global',
729
+ 'sxi' => 'application/vnd.sun.xml.impress',
730
+ 'sxm' => 'application/vnd.sun.xml.math',
731
+ 'sxw' => 'application/vnd.sun.xml.writer',
732
+ 't' => 'text/troff',
733
+ 'tao' => 'application/vnd.tao.intent-module-archive',
734
+ 'tar' => 'application/x-tar',
735
+ 'tcap' => 'application/vnd.3gpp2.tcap',
736
+ 'tcl' => 'application/x-tcl',
737
+ 'teacher' => 'application/vnd.smart.teacher',
738
+ 'tei' => 'application/tei+xml',
739
+ 'teicorpus' => 'application/tei+xml',
740
+ 'tex' => 'application/x-tex',
741
+ 'texi' => 'application/x-texinfo',
742
+ 'texinfo' => 'application/x-texinfo',
743
+ 'text' => 'text/plain',
744
+ 'tfi' => 'application/thraud+xml',
745
+ 'tfm' => 'application/x-tex-tfm',
746
+ 'thmx' => 'application/vnd.ms-officetheme',
747
+ 'tif' => 'image/tiff',
748
+ 'tiff' => 'image/tiff',
749
+ 'tmo' => 'application/vnd.tmobile-livetv',
750
+ 'torrent' => 'application/x-bittorrent',
751
+ 'tpl' => 'application/vnd.groove-tool-template',
752
+ 'tpt' => 'application/vnd.trid.tpt',
753
+ 'tr' => 'text/troff',
754
+ 'tra' => 'application/vnd.trueapp',
755
+ 'trm' => 'application/x-msterminal',
756
+ 'tsd' => 'application/timestamped-data',
757
+ 'tsv' => 'text/tab-separated-values',
758
+ 'ttc' => 'application/x-font-ttf',
759
+ 'ttf' => 'application/x-font-ttf',
760
+ 'ttl' => 'text/turtle',
761
+ 'twd' => 'application/vnd.simtech-mindmapper',
762
+ 'twds' => 'application/vnd.simtech-mindmapper',
763
+ 'txd' => 'application/vnd.genomatix.tuxedo',
764
+ 'txf' => 'application/vnd.mobius.txf',
765
+ 'txt' => 'text/plain',
766
+ 'u32' => 'application/x-authorware-bin',
767
+ 'udeb' => 'application/x-debian-package',
768
+ 'ufd' => 'application/vnd.ufdl',
769
+ 'ufdl' => 'application/vnd.ufdl',
770
+ 'umj' => 'application/vnd.umajin',
771
+ 'unityweb' => 'application/vnd.unity',
772
+ 'uoml' => 'application/vnd.uoml+xml',
773
+ 'uri' => 'text/uri-list',
774
+ 'uris' => 'text/uri-list',
775
+ 'urls' => 'text/uri-list',
776
+ 'ustar' => 'application/x-ustar',
777
+ 'utz' => 'application/vnd.uiq.theme',
778
+ 'uu' => 'text/x-uuencode',
779
+ 'uva' => 'audio/vnd.dece.audio',
780
+ 'uvd' => 'application/vnd.dece.data',
781
+ 'uvf' => 'application/vnd.dece.data',
782
+ 'uvg' => 'image/vnd.dece.graphic',
783
+ 'uvh' => 'video/vnd.dece.hd',
784
+ 'uvi' => 'image/vnd.dece.graphic',
785
+ 'uvm' => 'video/vnd.dece.mobile',
786
+ 'uvp' => 'video/vnd.dece.pd',
787
+ 'uvs' => 'video/vnd.dece.sd',
788
+ 'uvt' => 'application/vnd.dece.ttml+xml',
789
+ 'uvu' => 'video/vnd.uvvu.mp4',
790
+ 'uvv' => 'video/vnd.dece.video',
791
+ 'uvva' => 'audio/vnd.dece.audio',
792
+ 'uvvd' => 'application/vnd.dece.data',
793
+ 'uvvf' => 'application/vnd.dece.data',
794
+ 'uvvg' => 'image/vnd.dece.graphic',
795
+ 'uvvh' => 'video/vnd.dece.hd',
796
+ 'uvvi' => 'image/vnd.dece.graphic',
797
+ 'uvvm' => 'video/vnd.dece.mobile',
798
+ 'uvvp' => 'video/vnd.dece.pd',
799
+ 'uvvs' => 'video/vnd.dece.sd',
800
+ 'uvvt' => 'application/vnd.dece.ttml+xml',
801
+ 'uvvu' => 'video/vnd.uvvu.mp4',
802
+ 'uvvv' => 'video/vnd.dece.video',
803
+ 'uvvx' => 'application/vnd.dece.unspecified',
804
+ 'uvx' => 'application/vnd.dece.unspecified',
805
+ 'vcd' => 'application/x-cdlink',
806
+ 'vcf' => 'text/x-vcard',
807
+ 'vcg' => 'application/vnd.groove-vcard',
808
+ 'vcs' => 'text/x-vcalendar',
809
+ 'vcx' => 'application/vnd.vcx',
810
+ 'vis' => 'application/vnd.visionary',
811
+ 'viv' => 'video/vnd.vivo',
812
+ 'vor' => 'application/vnd.stardivision.writer',
813
+ 'vox' => 'application/x-authorware-bin',
814
+ 'vrml' => 'model/vrml',
815
+ 'vsd' => 'application/vnd.visio',
816
+ 'vsf' => 'application/vnd.vsf',
817
+ 'vss' => 'application/vnd.visio',
818
+ 'vst' => 'application/vnd.visio',
819
+ 'vsw' => 'application/vnd.visio',
820
+ 'vtu' => 'model/vnd.vtu',
821
+ 'vxml' => 'application/voicexml+xml',
822
+ 'w3d' => 'application/x-director',
823
+ 'wad' => 'application/x-doom',
824
+ 'wav' => 'audio/x-wav',
825
+ 'wax' => 'audio/x-ms-wax',
826
+ 'wbmp' => 'image/vnd.wap.wbmp',
827
+ 'wbs' => 'application/vnd.criticaltools.wbs+xml',
828
+ 'wbxml' => 'application/vnd.wap.wbxml',
829
+ 'wcm' => 'application/vnd.ms-works',
830
+ 'wdb' => 'application/vnd.ms-works',
831
+ 'weba' => 'audio/webm',
832
+ 'webm' => 'video/webm',
833
+ 'webp' => 'image/webp',
834
+ 'wg' => 'application/vnd.pmi.widget',
835
+ 'wgt' => 'application/widget',
836
+ 'wks' => 'application/vnd.ms-works',
837
+ 'wm' => 'video/x-ms-wm',
838
+ 'wma' => 'audio/x-ms-wma',
839
+ 'wmd' => 'application/x-ms-wmd',
840
+ 'wmf' => 'application/x-msmetafile',
841
+ 'wml' => 'text/vnd.wap.wml',
842
+ 'wmlc' => 'application/vnd.wap.wmlc',
843
+ 'wmls' => 'text/vnd.wap.wmlscript',
844
+ 'wmlsc' => 'application/vnd.wap.wmlscriptc',
845
+ 'wmv' => 'video/x-ms-wmv',
846
+ 'wmx' => 'video/x-ms-wmx',
847
+ 'wmz' => 'application/x-ms-wmz',
848
+ 'woff' => 'application/x-font-woff',
849
+ 'wpd' => 'application/vnd.wordperfect',
850
+ 'wpl' => 'application/vnd.ms-wpl',
851
+ 'wps' => 'application/vnd.ms-works',
852
+ 'wqd' => 'application/vnd.wqd',
853
+ 'wri' => 'application/x-mswrite',
854
+ 'wrl' => 'model/vrml',
855
+ 'wsdl' => 'application/wsdl+xml',
856
+ 'wspolicy' => 'application/wspolicy+xml',
857
+ 'wtb' => 'application/vnd.webturbo',
858
+ 'wvx' => 'video/x-ms-wvx',
859
+ 'x32' => 'application/x-authorware-bin',
860
+ 'x3d' => 'application/vnd.hzn-3d-crossword',
861
+ 'xap' => 'application/x-silverlight-app',
862
+ 'xar' => 'application/vnd.xara',
863
+ 'xbap' => 'application/x-ms-xbap',
864
+ 'xbd' => 'application/vnd.fujixerox.docuworks.binder',
865
+ 'xbm' => 'image/x-xbitmap',
866
+ 'xdf' => 'application/xcap-diff+xml',
867
+ 'xdm' => 'application/vnd.syncml.dm+xml',
868
+ 'xdp' => 'application/vnd.adobe.xdp+xml',
869
+ 'xdssc' => 'application/dssc+xml',
870
+ 'xdw' => 'application/vnd.fujixerox.docuworks',
871
+ 'xenc' => 'application/xenc+xml',
872
+ 'xer' => 'application/patch-ops-error+xml',
873
+ 'xfdf' => 'application/vnd.adobe.xfdf',
874
+ 'xfdl' => 'application/vnd.xfdl',
875
+ 'xht' => 'application/xhtml+xml',
876
+ 'xhtml' => 'application/xhtml+xml',
877
+ 'xhvml' => 'application/xv+xml',
878
+ 'xif' => 'image/vnd.xiff',
879
+ 'xla' => 'application/vnd.ms-excel',
880
+ 'xlam' => 'application/vnd.ms-excel.addin.macroenabled.12',
881
+ 'xlc' => 'application/vnd.ms-excel',
882
+ 'xlm' => 'application/vnd.ms-excel',
883
+ 'xls' => 'application/vnd.ms-excel',
884
+ 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroenabled.12',
885
+ 'xlsm' => 'application/vnd.ms-excel.sheet.macroenabled.12',
886
+ 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
887
+ 'xlt' => 'application/vnd.ms-excel',
888
+ 'xltm' => 'application/vnd.ms-excel.template.macroenabled.12',
889
+ 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
890
+ 'xlw' => 'application/vnd.ms-excel',
891
+ 'xml' => 'application/xml',
892
+ 'xo' => 'application/vnd.olpc-sugar',
893
+ 'xop' => 'application/xop+xml',
894
+ 'xpi' => 'application/x-xpinstall',
895
+ 'xpm' => 'image/x-xpixmap',
896
+ 'xpr' => 'application/vnd.is-xpr',
897
+ 'xps' => 'application/vnd.ms-xpsdocument',
898
+ 'xpw' => 'application/vnd.intercon.formnet',
899
+ 'xpx' => 'application/vnd.intercon.formnet',
900
+ 'xsl' => 'application/xml',
901
+ 'xslt' => 'application/xslt+xml',
902
+ 'xsm' => 'application/vnd.syncml+xml',
903
+ 'xspf' => 'application/xspf+xml',
904
+ 'xul' => 'application/vnd.mozilla.xul+xml',
905
+ 'xvm' => 'application/xv+xml',
906
+ 'xvml' => 'application/xv+xml',
907
+ 'xwd' => 'image/x-xwindowdump',
908
+ 'xyz' => 'chemical/x-xyz',
909
+ 'yaml' => 'text/yaml',
910
+ 'yang' => 'application/yang',
911
+ 'yin' => 'application/yin+xml',
912
+ 'yml' => 'text/yaml',
913
+ 'zaz' => 'application/vnd.zzazz.deck+xml',
914
+ 'zip' => 'application/zip',
915
+ 'zir' => 'application/vnd.zul',
916
+ 'zirz' => 'application/vnd.zul',
917
+ 'zmm' => 'application/vnd.handheld-entertainment+xml'
918
+ );
919
+
920
+ /**
921
+ * Get a singleton instance of the class
922
+ *
923
+ * @return self
924
+ * @codeCoverageIgnore
925
+ */
926
+ public static function getInstance()
927
+ {
928
+ if (!self::$instance) {
929
+ self::$instance = new self();
930
+ }
931
+
932
+ return self::$instance;
933
+ }
934
+
935
+ /**
936
+ * Get a mimetype value from a file extension
937
+ *
938
+ * @param string $extension File extension
939
+ *
940
+ * @return string|null
941
+ *
942
+ */
943
+ public function fromExtension($extension)
944
+ {
945
+ $extension = strtolower($extension);
946
+
947
+ return isset($this->mimetypes[$extension])
948
+ ? $this->mimetypes[$extension]
949
+ : null;
950
+ }
951
+
952
+ /**
953
+ * Get a mimetype from a filename
954
+ *
955
+ * @param string $filename Filename to generate a mimetype from
956
+ *
957
+ * @return string|null
958
+ */
959
+ public function fromFilename($filename)
960
+ {
961
+ return $this->fromExtension(pathinfo($filename, PATHINFO_EXTENSION));
962
+ }
963
+ }
backend/vendor/guzzlehttp/guzzle/src/Pool.php ADDED
@@ -0,0 +1,322 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Event\RequestEvents;
5
+ use GuzzleHttp\Message\RequestInterface;
6
+ use GuzzleHttp\Message\ResponseInterface;
7
+ use GuzzleHttp\Ring\Core;
8
+ use GuzzleHttp\Ring\Future\FutureInterface;
9
+ use GuzzleHttp\Event\ListenerAttacherTrait;
10
+ use GuzzleHttp\Event\EndEvent;
11
+ use React\Promise\Deferred;
12
+ use React\Promise\FulfilledPromise;
13
+ use React\Promise\PromiseInterface;
14
+ use React\Promise\RejectedPromise;
15
+
16
+ /**
17
+ * Sends and iterator of requests concurrently using a capped pool size.
18
+ *
19
+ * The Pool object implements FutureInterface, meaning it can be used later
20
+ * when necessary, the requests provided to the pool can be cancelled, and
21
+ * you can check the state of the pool to know if it has been dereferenced
22
+ * (sent) or has been cancelled.
23
+ *
24
+ * When sending the pool, keep in mind that no results are returned: callers
25
+ * are expected to handle results asynchronously using Guzzle's event system.
26
+ * When requests complete, more are added to the pool to ensure that the
27
+ * requested pool size is always filled as much as possible.
28
+ *
29
+ * IMPORTANT: Do not provide a pool size greater that what the utilized
30
+ * underlying RingPHP handler can support. This will result is extremely poor
31
+ * performance.
32
+ */
33
+ class Pool implements FutureInterface
34
+ {
35
+ use ListenerAttacherTrait;
36
+
37
+ /** @var \GuzzleHttp\ClientInterface */
38
+ private $client;
39
+
40
+ /** @var \Iterator Yields requests */
41
+ private $iter;
42
+
43
+ /** @var Deferred */
44
+ private $deferred;
45
+
46
+ /** @var PromiseInterface */
47
+ private $promise;
48
+
49
+ private $waitQueue = [];
50
+ private $eventListeners = [];
51
+ private $poolSize;
52
+ private $isRealized = false;
53
+
54
+ /**
55
+ * The option values for 'before', 'complete', 'error' and 'end' can be a
56
+ * callable, an associative array containing event data, or an array of
57
+ * event data arrays. Event data arrays contain the following keys:
58
+ *
59
+ * - fn: callable to invoke that receives the event
60
+ * - priority: Optional event priority (defaults to 0)
61
+ * - once: Set to true so that the event is removed after it is triggered
62
+ *
63
+ * @param ClientInterface $client Client used to send the requests.
64
+ * @param array|\Iterator $requests Requests to send in parallel
65
+ * @param array $options Associative array of options
66
+ * - pool_size: (callable|int) Maximum number of requests to send
67
+ * concurrently, or a callback that receives
68
+ * the current queue size and returns the
69
+ * number of new requests to send
70
+ * - before: (callable|array) Receives a BeforeEvent
71
+ * - complete: (callable|array) Receives a CompleteEvent
72
+ * - error: (callable|array) Receives a ErrorEvent
73
+ * - end: (callable|array) Receives an EndEvent
74
+ */
75
+ public function __construct(
76
+ ClientInterface $client,
77
+ $requests,
78
+ array $options = []
79
+ ) {
80
+ $this->client = $client;
81
+ $this->iter = $this->coerceIterable($requests);
82
+ $this->deferred = new Deferred();
83
+ $this->promise = $this->deferred->promise();
84
+ $this->poolSize = isset($options['pool_size'])
85
+ ? $options['pool_size'] : 25;
86
+ $this->eventListeners = $this->prepareListeners(
87
+ $options,
88
+ ['before', 'complete', 'error', 'end']
89
+ );
90
+ }
91
+
92
+ /**
93
+ * Sends multiple requests in parallel and returns an array of responses
94
+ * and exceptions that uses the same ordering as the provided requests.
95
+ *
96
+ * IMPORTANT: This method keeps every request and response in memory, and
97
+ * as such, is NOT recommended when sending a large number or an
98
+ * indeterminate number of requests concurrently.
99
+ *
100
+ * @param ClientInterface $client Client used to send the requests
101
+ * @param array|\Iterator $requests Requests to send in parallel
102
+ * @param array $options Passes through the options available in
103
+ * {@see GuzzleHttp\Pool::__construct}
104
+ *
105
+ * @return BatchResults Returns a container for the results.
106
+ * @throws \InvalidArgumentException if the event format is incorrect.
107
+ */
108
+ public static function batch(
109
+ ClientInterface $client,
110
+ $requests,
111
+ array $options = []
112
+ ) {
113
+ $hash = new \SplObjectStorage();
114
+ foreach ($requests as $request) {
115
+ $hash->attach($request);
116
+ }
117
+
118
+ // In addition to the normally run events when requests complete, add
119
+ // and event to continuously track the results of transfers in the hash.
120
+ (new self($client, $requests, RequestEvents::convertEventArray(
121
+ $options,
122
+ ['end'],
123
+ [
124
+ 'priority' => RequestEvents::LATE,
125
+ 'fn' => function (EndEvent $e) use ($hash) {
126
+ $hash[$e->getRequest()] = $e->getException()
127
+ ? $e->getException()
128
+ : $e->getResponse();
129
+ }
130
+ ]
131
+ )))->wait();
132
+
133
+ return new BatchResults($hash);
134
+ }
135
+
136
+ /**
137
+ * Creates a Pool and immediately sends the requests.
138
+ *
139
+ * @param ClientInterface $client Client used to send the requests
140
+ * @param array|\Iterator $requests Requests to send in parallel
141
+ * @param array $options Passes through the options available in
142
+ * {@see GuzzleHttp\Pool::__construct}
143
+ */
144
+ public static function send(
145
+ ClientInterface $client,
146
+ $requests,
147
+ array $options = []
148
+ ) {
149
+ (new self($client, $requests, $options))->wait();
150
+ }
151
+
152
+ private function getPoolSize()
153
+ {
154
+ return is_callable($this->poolSize)
155
+ ? call_user_func($this->poolSize, count($this->waitQueue))
156
+ : $this->poolSize;
157
+ }
158
+
159
+ /**
160
+ * Add as many requests as possible up to the current pool limit.
161
+ */
162
+ private function addNextRequests()
163
+ {
164
+ $limit = max($this->getPoolSize() - count($this->waitQueue), 0);
165
+ while ($limit--) {
166
+ if (!$this->addNextRequest()) {
167
+ break;
168
+ }
169
+ }
170
+ }
171
+
172
+ public function wait()
173
+ {
174
+ if ($this->isRealized) {
175
+ return false;
176
+ }
177
+
178
+ // Seed the pool with N number of requests.
179
+ $this->addNextRequests();
180
+
181
+ // Stop if the pool was cancelled while transferring requests.
182
+ if ($this->isRealized) {
183
+ return false;
184
+ }
185
+
186
+ // Wait on any outstanding FutureResponse objects.
187
+ while ($response = array_pop($this->waitQueue)) {
188
+ try {
189
+ $response->wait();
190
+ } catch (\Exception $e) {
191
+ // Eat exceptions because they should be handled asynchronously
192
+ }
193
+ }
194
+
195
+ // Clean up no longer needed state.
196
+ $this->isRealized = true;
197
+ $this->waitQueue = $this->eventListeners = [];
198
+ $this->client = $this->iter = null;
199
+ $this->deferred->resolve(true);
200
+
201
+ return true;
202
+ }
203
+
204
+ /**
205
+ * {@inheritdoc}
206
+ *
207
+ * Attempt to cancel all outstanding requests (requests that are queued for
208
+ * dereferencing). Returns true if all outstanding requests can be
209
+ * cancelled.
210
+ *
211
+ * @return bool
212
+ */
213
+ public function cancel()
214
+ {
215
+ if ($this->isRealized) {
216
+ return false;
217
+ }
218
+
219
+ $success = $this->isRealized = true;
220
+ foreach ($this->waitQueue as $response) {
221
+ if (!$response->cancel()) {
222
+ $success = false;
223
+ }
224
+ }
225
+
226
+ return $success;
227
+ }
228
+
229
+ /**
230
+ * Returns a promise that is invoked when the pool completed. There will be
231
+ * no passed value.
232
+ *
233
+ * {@inheritdoc}
234
+ */
235
+ public function then(
236
+ callable $onFulfilled = null,
237
+ callable $onRejected = null,
238
+ callable $onProgress = null
239
+ ) {
240
+ return $this->promise->then($onFulfilled, $onRejected, $onProgress);
241
+ }
242
+
243
+ public function promise()
244
+ {
245
+ return $this->promise;
246
+ }
247
+
248
+ private function coerceIterable($requests)
249
+ {
250
+ if ($requests instanceof \Iterator) {
251
+ return $requests;
252
+ } elseif (is_array($requests)) {
253
+ return new \ArrayIterator($requests);
254
+ }
255
+
256
+ throw new \InvalidArgumentException('Expected Iterator or array. '
257
+ . 'Found ' . Core::describeType($requests));
258
+ }
259
+
260
+ /**
261
+ * Adds the next request to pool and tracks what requests need to be
262
+ * dereferenced when completing the pool.
263
+ */
264
+ private function addNextRequest()
265
+ {
266
+ add_next:
267
+
268
+ if ($this->isRealized || !$this->iter || !$this->iter->valid()) {
269
+ return false;
270
+ }
271
+
272
+ $request = $this->iter->current();
273
+ $this->iter->next();
274
+
275
+ if (!($request instanceof RequestInterface)) {
276
+ throw new \InvalidArgumentException(sprintf(
277
+ 'All requests in the provided iterator must implement '
278
+ . 'RequestInterface. Found %s',
279
+ Core::describeType($request)
280
+ ));
281
+ }
282
+
283
+ // Be sure to use "lazy" futures, meaning they do not send right away.
284
+ $request->getConfig()->set('future', 'lazy');
285
+ $this->attachListeners($request, $this->eventListeners);
286
+ $response = $this->client->send($request);
287
+ $hash = spl_object_hash($request);
288
+ $this->waitQueue[$hash] = $response;
289
+ $promise = $response->promise();
290
+
291
+ // Don't recursively call itself for completed or rejected responses.
292
+ if ($promise instanceof FulfilledPromise
293
+ || $promise instanceof RejectedPromise
294
+ ) {
295
+ try {
296
+ $this->finishResponse($request, $response->wait(), $hash);
297
+ } catch (\Exception $e) {
298
+ $this->finishResponse($request, $e, $hash);
299
+ }
300
+ goto add_next;
301
+ }
302
+
303
+ // Use this function for both resolution and rejection.
304
+ $thenFn = function ($value) use ($request, $hash) {
305
+ $this->finishResponse($request, $value, $hash);
306
+ $this->addNextRequests();
307
+ };
308
+
309
+ $promise->then($thenFn, $thenFn);
310
+
311
+ return true;
312
+ }
313
+
314
+ private function finishResponse($request, $value, $hash)
315
+ {
316
+ unset($this->waitQueue[$hash]);
317
+ $result = $value instanceof ResponseInterface
318
+ ? ['request' => $request, 'response' => $value, 'error' => null]
319
+ : ['request' => $request, 'response' => null, 'error' => $value];
320
+ $this->deferred->progress($result);
321
+ }
322
+ }
backend/vendor/guzzlehttp/guzzle/src/Post/MultipartBody.php ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Post;
3
+
4
+ use GuzzleHttp\Stream\AppendStream;
5
+ use GuzzleHttp\Stream\Stream;
6
+ use GuzzleHttp\Stream\StreamDecoratorTrait;
7
+ use GuzzleHttp\Stream\StreamInterface;
8
+
9
+ /**
10
+ * Stream that when read returns bytes for a streaming multipart/form-data body
11
+ */
12
+ class MultipartBody implements StreamInterface
13
+ {
14
+ use StreamDecoratorTrait;
15
+
16
+ private $boundary;
17
+
18
+ /**
19
+ * @param array $fields Associative array of field names to values where
20
+ * each value is a string or array of strings.
21
+ * @param array $files Associative array of PostFileInterface objects
22
+ * @param string $boundary You can optionally provide a specific boundary
23
+ * @throws \InvalidArgumentException
24
+ */
25
+ public function __construct(
26
+ array $fields = [],
27
+ array $files = [],
28
+ $boundary = null
29
+ ) {
30
+ $this->boundary = $boundary ?: uniqid();
31
+ $this->stream = $this->createStream($fields, $files);
32
+ }
33
+
34
+ /**
35
+ * Get the boundary
36
+ *
37
+ * @return string
38
+ */
39
+ public function getBoundary()
40
+ {
41
+ return $this->boundary;
42
+ }
43
+
44
+ public function isWritable()
45
+ {
46
+ return false;
47
+ }
48
+
49
+ /**
50
+ * Get the string needed to transfer a POST field
51
+ */
52
+ private function getFieldString($name, $value)
53
+ {
54
+ return sprintf(
55
+ "--%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n%s\r\n",
56
+ $this->boundary,
57
+ $name,
58
+ $value
59
+ );
60
+ }
61
+
62
+ /**
63
+ * Get the headers needed before transferring the content of a POST file
64
+ */
65
+ private function getFileHeaders(PostFileInterface $file)
66
+ {
67
+ $headers = '';
68
+ foreach ($file->getHeaders() as $key => $value) {
69
+ $headers .= "{$key}: {$value}\r\n";
70
+ }
71
+
72
+ return "--{$this->boundary}\r\n" . trim($headers) . "\r\n\r\n";
73
+ }
74
+
75
+ /**
76
+ * Create the aggregate stream that will be used to upload the POST data
77
+ */
78
+ protected function createStream(array $fields, array $files)
79
+ {
80
+ $stream = new AppendStream();
81
+
82
+ foreach ($fields as $name => $fieldValues) {
83
+ foreach ((array) $fieldValues as $value) {
84
+ $stream->addStream(
85
+ Stream::factory($this->getFieldString($name, $value))
86
+ );
87
+ }
88
+ }
89
+
90
+ foreach ($files as $file) {
91
+
92
+ if (!$file instanceof PostFileInterface) {
93
+ throw new \InvalidArgumentException('All POST fields must '
94
+ . 'implement PostFieldInterface');
95
+ }
96
+
97
+ $stream->addStream(
98
+ Stream::factory($this->getFileHeaders($file))
99
+ );
100
+ $stream->addStream($file->getContent());
101
+ $stream->addStream(Stream::factory("\r\n"));
102
+ }
103
+
104
+ // Add the trailing boundary with CRLF
105
+ $stream->addStream(Stream::factory("--{$this->boundary}--\r\n"));
106
+
107
+ return $stream;
108
+ }
109
+ }
backend/vendor/guzzlehttp/guzzle/src/Post/PostBody.php ADDED
@@ -0,0 +1,287 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Post;
3
+
4
+ use GuzzleHttp\Message\RequestInterface;
5
+ use GuzzleHttp\Stream\Exception\CannotAttachException;
6
+ use GuzzleHttp\Stream\StreamInterface;
7
+ use GuzzleHttp\Stream\Stream;
8
+ use GuzzleHttp\Query;
9
+
10
+ /**
11
+ * Holds POST fields and files and creates a streaming body when read methods
12
+ * are called on the object.
13
+ */
14
+ class PostBody implements PostBodyInterface
15
+ {
16
+ /** @var StreamInterface */
17
+ private $body;
18
+
19
+ /** @var callable */
20
+ private $aggregator;
21
+
22
+ private $fields = [];
23
+
24
+ /** @var PostFileInterface[] */
25
+ private $files = [];
26
+ private $forceMultipart = false;
27
+ private $detached = false;
28
+
29
+ /**
30
+ * Applies request headers to a request based on the POST state
31
+ *
32
+ * @param RequestInterface $request Request to update
33
+ */
34
+ public function applyRequestHeaders(RequestInterface $request)
35
+ {
36
+ if ($this->files || $this->forceMultipart) {
37
+ $request->setHeader(
38
+ 'Content-Type',
39
+ 'multipart/form-data; boundary=' . $this->getBody()->getBoundary()
40
+ );
41
+ } elseif ($this->fields && !$request->hasHeader('Content-Type')) {
42
+ $request->setHeader(
43
+ 'Content-Type',
44
+ 'application/x-www-form-urlencoded'
45
+ );
46
+ }
47
+
48
+ if ($size = $this->getSize()) {
49
+ $request->setHeader('Content-Length', $size);
50
+ }
51
+ }
52
+
53
+ public function forceMultipartUpload($force)
54
+ {
55
+ $this->forceMultipart = $force;
56
+ }
57
+
58
+ public function setAggregator(callable $aggregator)
59
+ {
60
+ $this->aggregator = $aggregator;
61
+ }
62
+
63
+ public function setField($name, $value)
64
+ {
65
+ $this->fields[$name] = $value;
66
+ $this->mutate();
67
+ }
68
+
69
+ public function replaceFields(array $fields)
70
+ {
71
+ $this->fields = $fields;
72
+ $this->mutate();
73
+ }
74
+
75
+ public function getField($name)
76
+ {
77
+ return isset($this->fields[$name]) ? $this->fields[$name] : null;
78
+ }
79
+
80
+ public function removeField($name)
81
+ {
82
+ unset($this->fields[$name]);
83
+ $this->mutate();
84
+ }
85
+
86
+ public function getFields($asString = false)
87
+ {
88
+ if (!$asString) {
89
+ return $this->fields;
90
+ }
91
+
92
+ $query = new Query($this->fields);
93
+ $query->setEncodingType(Query::RFC1738);
94
+ $query->setAggregator($this->getAggregator());
95
+
96
+ return (string) $query;
97
+ }
98
+
99
+ public function hasField($name)
100
+ {
101
+ return isset($this->fields[$name]);
102
+ }
103
+
104
+ public function getFile($name)
105
+ {
106
+ foreach ($this->files as $file) {
107
+ if ($file->getName() == $name) {
108
+ return $file;
109
+ }
110
+ }
111
+
112
+ return null;
113
+ }
114
+
115
+ public function getFiles()
116
+ {
117
+ return $this->files;
118
+ }
119
+
120
+ public function addFile(PostFileInterface $file)
121
+ {
122
+ $this->files[] = $file;
123
+ $this->mutate();
124
+ }
125
+
126
+ public function clearFiles()
127
+ {
128
+ $this->files = [];
129
+ $this->mutate();
130
+ }
131
+
132
+ /**
133
+ * Returns the numbers of fields + files
134
+ *
135
+ * @return int
136
+ */
137
+ public function count()
138
+ {
139
+ return count($this->files) + count($this->fields);
140
+ }
141
+
142
+ public function __toString()
143
+ {
144
+ return (string) $this->getBody();
145
+ }
146
+
147
+ public function getContents($maxLength = -1)
148
+ {
149
+ return $this->getBody()->getContents();
150
+ }
151
+
152
+ public function close()
153
+ {
154
+ $this->detach();
155
+ }
156
+
157
+ public function detach()
158
+ {
159
+ $this->detached = true;
160
+ $this->fields = $this->files = [];
161
+
162
+ if ($this->body) {
163
+ $this->body->close();
164
+ $this->body = null;
165
+ }
166
+ }
167
+
168
+ public function attach($stream)
169
+ {
170
+ throw new CannotAttachException();
171
+ }
172
+
173
+ public function eof()
174
+ {
175
+ return $this->getBody()->eof();
176
+ }
177
+
178
+ public function tell()
179
+ {
180
+ return $this->body ? $this->body->tell() : 0;
181
+ }
182
+
183
+ public function isSeekable()
184
+ {
185
+ return true;
186
+ }
187
+
188
+ public function isReadable()
189
+ {
190
+ return true;
191
+ }
192
+
193
+ public function isWritable()
194
+ {
195
+ return false;
196
+ }
197
+
198
+ public function getSize()
199
+ {
200
+ return $this->getBody()->getSize();
201
+ }
202
+
203
+ public function seek($offset, $whence = SEEK_SET)
204
+ {
205
+ return $this->getBody()->seek($offset, $whence);
206
+ }
207
+
208
+ public function read($length)
209
+ {
210
+ return $this->getBody()->read($length);
211
+ }
212
+
213
+ public function write($string)
214
+ {
215
+ return false;
216
+ }
217
+
218
+ public function getMetadata($key = null)
219
+ {
220
+ return $key ? null : [];
221
+ }
222
+
223
+ /**
224
+ * Return a stream object that is built from the POST fields and files.
225
+ *
226
+ * If one has already been created, the previously created stream will be
227
+ * returned.
228
+ */
229
+ private function getBody()
230
+ {
231
+ if ($this->body) {
232
+ return $this->body;
233
+ } elseif ($this->files || $this->forceMultipart) {
234
+ return $this->body = $this->createMultipart();
235
+ } elseif ($this->fields) {
236
+ return $this->body = $this->createUrlEncoded();
237
+ } else {
238
+ return $this->body = Stream::factory();
239
+ }
240
+ }
241
+
242
+ /**
243
+ * Get the aggregator used to join multi-valued field parameters
244
+ *
245
+ * @return callable
246
+ */
247
+ final protected function getAggregator()
248
+ {
249
+ if (!$this->aggregator) {
250
+ $this->aggregator = Query::phpAggregator();
251
+ }
252
+
253
+ return $this->aggregator;
254
+ }
255
+
256
+ /**
257
+ * Creates a multipart/form-data body stream
258
+ *
259
+ * @return MultipartBody
260
+ */
261
+ private function createMultipart()
262
+ {
263
+ // Flatten the nested query string values using the correct aggregator
264
+ return new MultipartBody(
265
+ call_user_func($this->getAggregator(), $this->fields),
266
+ $this->files
267
+ );
268
+ }
269
+
270
+ /**
271
+ * Creates an application/x-www-form-urlencoded stream body
272
+ *
273
+ * @return StreamInterface
274
+ */
275
+ private function createUrlEncoded()
276
+ {
277
+ return Stream::factory($this->getFields(true));
278
+ }
279
+
280
+ /**
281
+ * Get rid of any cached data
282
+ */
283
+ private function mutate()
284
+ {
285
+ $this->body = null;
286
+ }
287
+ }
backend/vendor/guzzlehttp/guzzle/src/Post/PostBodyInterface.php ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Post;
3
+
4
+ use GuzzleHttp\Message\RequestInterface;
5
+ use GuzzleHttp\Stream\StreamInterface;
6
+
7
+ /**
8
+ * Represents a POST body that is sent as either a multipart/form-data stream
9
+ * or application/x-www-urlencoded stream.
10
+ */
11
+ interface PostBodyInterface extends StreamInterface, \Countable
12
+ {
13
+ /**
14
+ * Apply headers to the request appropriate for the current state of the object
15
+ *
16
+ * @param RequestInterface $request Request
17
+ */
18
+ public function applyRequestHeaders(RequestInterface $request);
19
+
20
+ /**
21
+ * Set a specific field
22
+ *
23
+ * @param string $name Name of the field to set
24
+ * @param string|array $value Value to set
25
+ */
26
+ public function setField($name, $value);
27
+
28
+ /**
29
+ * Set the aggregation strategy that will be used to turn multi-valued
30
+ * fields into a string.
31
+ *
32
+ * The aggregation function accepts a deeply nested array of query string
33
+ * values and returns a flattened associative array of key value pairs.
34
+ *
35
+ * @param callable $aggregator
36
+ */
37
+ public function setAggregator(callable $aggregator);
38
+
39
+ /**
40
+ * Set to true to force a multipart upload even if there are no files.
41
+ *
42
+ * @param bool $force Set to true to force multipart uploads or false to
43
+ * remove this flag.
44
+ */
45
+ public function forceMultipartUpload($force);
46
+
47
+ /**
48
+ * Replace all existing form fields with an array of fields
49
+ *
50
+ * @param array $fields Associative array of fields to set
51
+ */
52
+ public function replaceFields(array $fields);
53
+
54
+ /**
55
+ * Get a specific field by name
56
+ *
57
+ * @param string $name Name of the POST field to retrieve
58
+ *
59
+ * @return string|null
60
+ */
61
+ public function getField($name);
62
+
63
+ /**
64
+ * Remove a field by name
65
+ *
66
+ * @param string $name Name of the field to remove
67
+ */
68
+ public function removeField($name);
69
+
70
+ /**
71
+ * Returns an associative array of names to values or a query string.
72
+ *
73
+ * @param bool $asString Set to true to retrieve the fields as a query
74
+ * string.
75
+ *
76
+ * @return array|string
77
+ */
78
+ public function getFields($asString = false);
79
+
80
+ /**
81
+ * Returns true if a field is set
82
+ *
83
+ * @param string $name Name of the field to set
84
+ *
85
+ * @return bool
86
+ */
87
+ public function hasField($name);
88
+
89
+ /**
90
+ * Get all of the files
91
+ *
92
+ * @return array Returns an array of PostFileInterface objects
93
+ */
94
+ public function getFiles();
95
+
96
+ /**
97
+ * Get a POST file by name.
98
+ *
99
+ * @param string $name Name of the POST file to retrieve
100
+ *
101
+ * @return PostFileInterface|null
102
+ */
103
+ public function getFile($name);
104
+
105
+ /**
106
+ * Add a file to the POST
107
+ *
108
+ * @param PostFileInterface $file File to add
109
+ */
110
+ public function addFile(PostFileInterface $file);
111
+
112
+ /**
113
+ * Remove all files from the collection
114
+ */
115
+ public function clearFiles();
116
+ }
backend/vendor/guzzlehttp/guzzle/src/Post/PostFile.php ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Post;
3
+
4
+ use GuzzleHttp\Mimetypes;
5
+ use GuzzleHttp\Stream\StreamInterface;
6
+ use GuzzleHttp\Stream\Stream;
7
+
8
+ /**
9
+ * Post file upload
10
+ */
11
+ class PostFile implements PostFileInterface
12
+ {
13
+ private $name;
14
+ private $filename;
15
+ private $content;
16
+ private $headers = [];
17
+
18
+ /**
19
+ * @param string $name Name of the form field
20
+ * @param mixed $content Data to send
21
+ * @param string|null $filename Filename content-disposition attribute
22
+ * @param array $headers Array of headers to set on the file
23
+ * (can override any default headers)
24
+ * @throws \RuntimeException when filename is not passed or can't be determined
25
+ */
26
+ public function __construct(
27
+ $name,
28
+ $content,
29
+ $filename = null,
30
+ array $headers = []
31
+ ) {
32
+ $this->headers = $headers;
33
+ $this->name = $name;
34
+ $this->prepareContent($content);
35
+ $this->prepareFilename($filename);
36
+ $this->prepareDefaultHeaders();
37
+ }
38
+
39
+ public function getName()
40
+ {
41
+ return $this->name;
42
+ }
43
+
44
+ public function getFilename()
45
+ {
46
+ return $this->filename;
47
+ }
48
+
49
+ public function getContent()
50
+ {
51
+ return $this->content;
52
+ }
53
+
54
+ public function getHeaders()
55
+ {
56
+ return $this->headers;
57
+ }
58
+
59
+ /**
60
+ * Prepares the contents of a POST file.
61
+ *
62
+ * @param mixed $content Content of the POST file
63
+ */
64
+ private function prepareContent($content)
65
+ {
66
+ $this->content = $content;
67
+
68
+ if (!($this->content instanceof StreamInterface)) {
69
+ $this->content = Stream::factory($this->content);
70
+ } elseif ($this->content instanceof MultipartBody) {
71
+ if (!$this->hasHeader('Content-Disposition')) {
72
+ $disposition = 'form-data; name="' . $this->name .'"';
73
+ $this->headers['Content-Disposition'] = $disposition;
74
+ }
75
+
76
+ if (!$this->hasHeader('Content-Type')) {
77
+ $this->headers['Content-Type'] = sprintf(
78
+ "multipart/form-data; boundary=%s",
79
+ $this->content->getBoundary()
80
+ );
81
+ }
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Applies a file name to the POST file based on various checks.
87
+ *
88
+ * @param string|null $filename Filename to apply (or null to guess)
89
+ */
90
+ private function prepareFilename($filename)
91
+ {
92
+ $this->filename = $filename;
93
+
94
+ if (!$this->filename) {
95
+ $this->filename = $this->content->getMetadata('uri');
96
+ }
97
+
98
+ if (!$this->filename || substr($this->filename, 0, 6) === 'php://') {
99
+ $this->filename = $this->name;
100
+ }
101
+ }
102
+
103
+ /**
104
+ * Applies default Content-Disposition and Content-Type headers if needed.
105
+ */
106
+ private function prepareDefaultHeaders()
107
+ {
108
+ // Set a default content-disposition header if one was no provided
109
+ if (!$this->hasHeader('Content-Disposition')) {
110
+ $this->headers['Content-Disposition'] = sprintf(
111
+ 'form-data; name="%s"; filename="%s"',
112
+ $this->name,
113
+ basename($this->filename)
114
+ );
115
+ }
116
+
117
+ // Set a default Content-Type if one was not supplied
118
+ if (!$this->hasHeader('Content-Type')) {
119
+ $this->headers['Content-Type'] = Mimetypes::getInstance()
120
+ ->fromFilename($this->filename) ?: 'text/plain';
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Check if a specific header exists on the POST file by name.
126
+ *
127
+ * @param string $name Case-insensitive header to check
128
+ *
129
+ * @return bool
130
+ */
131
+ private function hasHeader($name)
132
+ {
133
+ return isset(array_change_key_case($this->headers)[strtolower($name)]);
134
+ }
135
+ }
backend/vendor/guzzlehttp/guzzle/src/Post/PostFileInterface.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Post;
3
+
4
+ use GuzzleHttp\Stream\StreamInterface;
5
+
6
+ /**
7
+ * Post file upload interface
8
+ */
9
+ interface PostFileInterface
10
+ {
11
+ /**
12
+ * Get the name of the form field
13
+ *
14
+ * @return string
15
+ */
16
+ public function getName();
17
+
18
+ /**
19
+ * Get the full path to the file
20
+ *
21
+ * @return string
22
+ */
23
+ public function getFilename();
24
+
25
+ /**
26
+ * Get the content
27
+ *
28
+ * @return StreamInterface
29
+ */
30
+ public function getContent();
31
+
32
+ /**
33
+ * Gets all POST file headers.
34
+ *
35
+ * The keys represent the header name as it will be sent over the wire, and
36
+ * each value is a string.
37
+ *
38
+ * @return array Returns an associative array of the file's headers.
39
+ */
40
+ public function getHeaders();
41
+ }
backend/vendor/guzzlehttp/guzzle/src/Query.php ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ /**
5
+ * Manages query string variables and can aggregate them into a string
6
+ */
7
+ class Query extends Collection
8
+ {
9
+ const RFC3986 = 'RFC3986';
10
+ const RFC1738 = 'RFC1738';
11
+
12
+ /** @var callable Encoding function */
13
+ private $encoding = 'rawurlencode';
14
+ /** @var callable */
15
+ private $aggregator;
16
+
17
+ /**
18
+ * Parse a query string into a Query object
19
+ *
20
+ * $urlEncoding is used to control how the query string is parsed and how
21
+ * it is ultimately serialized. The value can be set to one of the
22
+ * following:
23
+ *
24
+ * - true: (default) Parse query strings using RFC 3986 while still
25
+ * converting "+" to " ".
26
+ * - false: Disables URL decoding of the input string and URL encoding when
27
+ * the query string is serialized.
28
+ * - 'RFC3986': Use RFC 3986 URL encoding/decoding
29
+ * - 'RFC1738': Use RFC 1738 URL encoding/decoding
30
+ *
31
+ * @param string $query Query string to parse
32
+ * @param bool|string $urlEncoding Controls how the input string is decoded
33
+ * and encoded.
34
+ * @return self
35
+ */
36
+ public static function fromString($query, $urlEncoding = true)
37
+ {
38
+ static $qp;
39
+ if (!$qp) {
40
+ $qp = new QueryParser();
41
+ }
42
+
43
+ $q = new static();
44
+
45
+ if ($urlEncoding !== true) {
46
+ $q->setEncodingType($urlEncoding);
47
+ }
48
+
49
+ $qp->parseInto($q, $query, $urlEncoding);
50
+
51
+ return $q;
52
+ }
53
+
54
+ /**
55
+ * Convert the query string parameters to a query string string
56
+ *
57
+ * @return string
58
+ */
59
+ public function __toString()
60
+ {
61
+ if (!$this->data) {
62
+ return '';
63
+ }
64
+
65
+ // The default aggregator is statically cached
66
+ static $defaultAggregator;
67
+
68
+ if (!$this->aggregator) {
69
+ if (!$defaultAggregator) {
70
+ $defaultAggregator = self::phpAggregator();
71
+ }
72
+ $this->aggregator = $defaultAggregator;
73
+ }
74
+
75
+ $result = '';
76
+ $aggregator = $this->aggregator;
77
+ $encoder = $this->encoding;
78
+
79
+ foreach ($aggregator($this->data) as $key => $values) {
80
+ foreach ($values as $value) {
81
+ if ($result) {
82
+ $result .= '&';
83
+ }
84
+ $result .= $encoder($key);
85
+ if ($value !== null) {
86
+ $result .= '=' . $encoder($value);
87
+ }
88
+ }
89
+ }
90
+
91
+ return $result;
92
+ }
93
+
94
+ /**
95
+ * Controls how multi-valued query string parameters are aggregated into a
96
+ * string.
97
+ *
98
+ * $query->setAggregator($query::duplicateAggregator());
99
+ *
100
+ * @param callable $aggregator Callable used to convert a deeply nested
101
+ * array of query string variables into a flattened array of key value
102
+ * pairs. The callable accepts an array of query data and returns a
103
+ * flattened array of key value pairs where each value is an array of
104
+ * strings.
105
+ */
106
+ public function setAggregator(callable $aggregator)
107
+ {
108
+ $this->aggregator = $aggregator;
109
+ }
110
+
111
+ /**
112
+ * Specify how values are URL encoded
113
+ *
114
+ * @param string|bool $type One of 'RFC1738', 'RFC3986', or false to disable encoding
115
+ *
116
+ * @throws \InvalidArgumentException
117
+ */
118
+ public function setEncodingType($type)
119
+ {
120
+ switch ($type) {
121
+ case self::RFC3986:
122
+ $this->encoding = 'rawurlencode';
123
+ break;
124
+ case self::RFC1738:
125
+ $this->encoding = 'urlencode';
126
+ break;
127
+ case false:
128
+ $this->encoding = function ($v) { return $v; };
129
+ break;
130
+ default:
131
+ throw new \InvalidArgumentException('Invalid URL encoding type');
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Query string aggregator that does not aggregate nested query string
137
+ * values and allows duplicates in the resulting array.
138
+ *
139
+ * Example: http://test.com?q=1&q=2
140
+ *
141
+ * @return callable
142
+ */
143
+ public static function duplicateAggregator()
144
+ {
145
+ return function (array $data) {
146
+ return self::walkQuery($data, '', function ($key, $prefix) {
147
+ return is_int($key) ? $prefix : "{$prefix}[{$key}]";
148
+ });
149
+ };
150
+ }
151
+
152
+ /**
153
+ * Aggregates nested query string variables using the same technique as
154
+ * ``http_build_query()``.
155
+ *
156
+ * @param bool $numericIndices Pass false to not include numeric indices
157
+ * when multi-values query string parameters are present.
158
+ *
159
+ * @return callable
160
+ */
161
+ public static function phpAggregator($numericIndices = true)
162
+ {
163
+ return function (array $data) use ($numericIndices) {
164
+ return self::walkQuery(
165
+ $data,
166
+ '',
167
+ function ($key, $prefix) use ($numericIndices) {
168
+ return !$numericIndices && is_int($key)
169
+ ? "{$prefix}[]"
170
+ : "{$prefix}[{$key}]";
171
+ }
172
+ );
173
+ };
174
+ }
175
+
176
+ /**
177
+ * Easily create query aggregation functions by providing a key prefix
178
+ * function to this query string array walker.
179
+ *
180
+ * @param array $query Query string to walk
181
+ * @param string $keyPrefix Key prefix (start with '')
182
+ * @param callable $prefixer Function used to create a key prefix
183
+ *
184
+ * @return array
185
+ */
186
+ public static function walkQuery(array $query, $keyPrefix, callable $prefixer)
187
+ {
188
+ $result = [];
189
+ foreach ($query as $key => $value) {
190
+ if ($keyPrefix) {
191
+ $key = $prefixer($key, $keyPrefix);
192
+ }
193
+ if (is_array($value)) {
194
+ $result += self::walkQuery($value, $key, $prefixer);
195
+ } elseif (isset($result[$key])) {
196
+ $result[$key][] = $value;
197
+ } else {
198
+ $result[$key] = array($value);
199
+ }
200
+ }
201
+
202
+ return $result;
203
+ }
204
+ }
backend/vendor/guzzlehttp/guzzle/src/QueryParser.php ADDED
@@ -0,0 +1,163 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ /**
5
+ * Parses query strings into a Query object.
6
+ *
7
+ * While parsing, the parser will attempt to determine the most appropriate
8
+ * query string aggregator to use when serializing the parsed query string
9
+ * object back into a string. The hope is that parsing then serializing a
10
+ * query string should be a lossless operation.
11
+ *
12
+ * @internal Use Query::fromString()
13
+ */
14
+ class QueryParser
15
+ {
16
+ private $duplicates;
17
+ private $numericIndices;
18
+
19
+ /**
20
+ * Parse a query string into a Query object.
21
+ *
22
+ * @param Query $query Query object to populate
23
+ * @param string $str Query string to parse
24
+ * @param bool|string $urlEncoding How the query string is encoded
25
+ */
26
+ public function parseInto(Query $query, $str, $urlEncoding = true)
27
+ {
28
+ if ($str === '') {
29
+ return;
30
+ }
31
+
32
+ $result = [];
33
+ $this->duplicates = false;
34
+ $this->numericIndices = true;
35
+ $decoder = self::getDecoder($urlEncoding);
36
+
37
+ foreach (explode('&', $str) as $kvp) {
38
+
39
+ $parts = explode('=', $kvp, 2);
40
+ $key = $decoder($parts[0]);
41
+ $value = isset($parts[1]) ? $decoder($parts[1]) : null;
42
+
43
+ // Special handling needs to be taken for PHP nested array syntax
44
+ if (strpos($key, '[') !== false) {
45
+ $this->parsePhpValue($key, $value, $result);
46
+ continue;
47
+ }
48
+
49
+ if (!isset($result[$key])) {
50
+ $result[$key] = $value;
51
+ } else {
52
+ $this->duplicates = true;
53
+ if (!is_array($result[$key])) {
54
+ $result[$key] = [$result[$key]];
55
+ }
56
+ $result[$key][] = $value;
57
+ }
58
+ }
59
+
60
+ $query->replace($result);
61
+
62
+ if (!$this->numericIndices) {
63
+ $query->setAggregator(Query::phpAggregator(false));
64
+ } elseif ($this->duplicates) {
65
+ $query->setAggregator(Query::duplicateAggregator());
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Returns a callable that is used to URL decode query keys and values.
71
+ *
72
+ * @param string|bool $type One of true, false, RFC3986, and RFC1738
73
+ *
74
+ * @return callable|string
75
+ */
76
+ private static function getDecoder($type)
77
+ {
78
+ if ($type === true) {
79
+ return function ($value) {
80
+ return rawurldecode(str_replace('+', ' ', $value));
81
+ };
82
+ } elseif ($type == Query::RFC3986) {
83
+ return 'rawurldecode';
84
+ } elseif ($type == Query::RFC1738) {
85
+ return 'urldecode';
86
+ } else {
87
+ return function ($str) { return $str; };
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Parses a PHP style key value pair.
93
+ *
94
+ * @param string $key Key to parse (e.g., "foo[a][b]")
95
+ * @param string|null $value Value to set
96
+ * @param array $result Result to modify by reference
97
+ */
98
+ private function parsePhpValue($key, $value, array &$result)
99
+ {
100
+ $node =& $result;
101
+ $keyBuffer = '';
102
+
103
+ for ($i = 0, $t = strlen($key); $i < $t; $i++) {
104
+ switch ($key[$i]) {
105
+ case '[':
106
+ if ($keyBuffer) {
107
+ $this->prepareNode($node, $keyBuffer);
108
+ $node =& $node[$keyBuffer];
109
+ $keyBuffer = '';
110
+ }
111
+ break;
112
+ case ']':
113
+ $k = $this->cleanKey($node, $keyBuffer);
114
+ $this->prepareNode($node, $k);
115
+ $node =& $node[$k];
116
+ $keyBuffer = '';
117
+ break;
118
+ default:
119
+ $keyBuffer .= $key[$i];
120
+ break;
121
+ }
122
+ }
123
+
124
+ if (isset($node)) {
125
+ $this->duplicates = true;
126
+ $node[] = $value;
127
+ } else {
128
+ $node = $value;
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Prepares a value in the array at the given key.
134
+ *
135
+ * If the key already exists, the key value is converted into an array.
136
+ *
137
+ * @param array $node Result node to modify
138
+ * @param string $key Key to add or modify in the node
139
+ */
140
+ private function prepareNode(&$node, $key)
141
+ {
142
+ if (!isset($node[$key])) {
143
+ $node[$key] = null;
144
+ } elseif (!is_array($node[$key])) {
145
+ $node[$key] = [$node[$key]];
146
+ }
147
+ }
148
+
149
+ /**
150
+ * Returns the appropriate key based on the node and key.
151
+ */
152
+ private function cleanKey($node, $key)
153
+ {
154
+ if ($key === '') {
155
+ $key = $node ? (string) count($node) : 0;
156
+ // Found a [] key, so track this to ensure that we disable numeric
157
+ // indexing of keys in the resolved query aggregator.
158
+ $this->numericIndices = false;
159
+ }
160
+
161
+ return $key;
162
+ }
163
+ }
backend/vendor/guzzlehttp/guzzle/src/RequestFsm.php ADDED
@@ -0,0 +1,233 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Event\BeforeEvent;
5
+ use GuzzleHttp\Event\ErrorEvent;
6
+ use GuzzleHttp\Event\CompleteEvent;
7
+ use GuzzleHttp\Event\EndEvent;
8
+ use GuzzleHttp\Exception\StateException;
9
+ use GuzzleHttp\Exception\RequestException;
10
+ use GuzzleHttp\Message\FutureResponse;
11
+ use GuzzleHttp\Message\MessageFactoryInterface;
12
+ use GuzzleHttp\Ring\Future\FutureInterface;
13
+
14
+ /**
15
+ * Responsible for transitioning requests through lifecycle events.
16
+ */
17
+ class RequestFsm
18
+ {
19
+ private $handler;
20
+ private $mf;
21
+ private $maxTransitions;
22
+
23
+ private $states = [
24
+ // When a mock intercepts the emitted "before" event, then we
25
+ // transition to the "complete" intercept state.
26
+ 'before' => [
27
+ 'success' => 'send',
28
+ 'intercept' => 'complete',
29
+ 'error' => 'error'
30
+ ],
31
+ // The complete and error events are handled using the "then" of
32
+ // the RingPHP request, so we exit the FSM.
33
+ 'send' => ['error' => 'error'],
34
+ 'complete' => [
35
+ 'success' => 'end',
36
+ 'intercept' => 'retry',
37
+ 'error' => 'error'
38
+ ],
39
+ 'error' => [
40
+ 'success' => 'complete',
41
+ 'intercept' => 'retry',
42
+ 'error' => 'end'
43
+ ],
44
+ 'retry' => ['success' => 'before'],
45
+ 'end' => [],
46
+ ];
47
+
48
+ public function __construct(
49
+ callable $handler,
50
+ MessageFactoryInterface $messageFactory,
51
+ $maxTransitions = 200
52
+ ) {
53
+ $this->mf = $messageFactory;
54
+ $this->maxTransitions = $maxTransitions;
55
+ $this->handler = $handler;
56
+ }
57
+
58
+ /**
59
+ * Runs the state machine until a terminal state is entered or the
60
+ * optionally supplied $finalState is entered.
61
+ *
62
+ * @param Transaction $trans Transaction being transitioned.
63
+ * @param string $finalState The state to stop on. If unspecified,
64
+ * runs until a terminal state is found.
65
+ *
66
+ * @throws \Exception if a terminal state throws an exception.
67
+ */
68
+ public function __invoke(Transaction $trans, $finalState = null)
69
+ {
70
+ $trans->_transitionCount = 1;
71
+
72
+ if (!$trans->state) {
73
+ $trans->state = 'before';
74
+ }
75
+
76
+ while ($trans->state !== $finalState) {
77
+
78
+ if (!isset($this->states[$trans->state])) {
79
+ throw new StateException("Invalid state: {$trans->state}");
80
+ } elseif (++$trans->_transitionCount > $this->maxTransitions) {
81
+ throw new StateException('Too many state transitions were '
82
+ . 'encountered ({$trans->_transitionCount}). This likely '
83
+ . 'means that a combination of event listeners are in an '
84
+ . 'infinite loop.');
85
+ }
86
+
87
+ $state = $this->states[$trans->state];
88
+
89
+ try {
90
+ /** @var callable $fn */
91
+ $fn = [$this, $trans->state];
92
+ if ($fn($trans)) {
93
+ // Handles transitioning to the "intercept" state.
94
+ if (isset($state['intercept'])) {
95
+ $trans->state = $state['intercept'];
96
+ continue;
97
+ }
98
+ throw new StateException('Invalid intercept state '
99
+ . 'transition from ' . $trans->state);
100
+ }
101
+
102
+ if (isset($state['success'])) {
103
+ // Transition to the success state
104
+ $trans->state = $state['success'];
105
+ } else {
106
+ // Break: this is a terminal state with no transition.
107
+ break;
108
+ }
109
+
110
+ } catch (StateException $e) {
111
+ // State exceptions are thrown no matter what.
112
+ throw $e;
113
+ } catch (\Exception $e) {
114
+ $trans->exception = $e;
115
+ // Terminal error states throw the exception.
116
+ if (!isset($state['error'])) {
117
+ throw $e;
118
+ }
119
+ // Transition to the error state.
120
+ $trans->state = $state['error'];
121
+ }
122
+ }
123
+ }
124
+
125
+ private function before(Transaction $trans)
126
+ {
127
+ $trans->request->getEmitter()->emit('before', new BeforeEvent($trans));
128
+
129
+ // When a response is set during the before event (i.e., a mock), then
130
+ // we don't need to send anything. Skip ahead to the complete event
131
+ // by returning to to go to the intercept state.
132
+ return (bool) $trans->response;
133
+ }
134
+
135
+ private function retry(Transaction $trans)
136
+ {
137
+ $trans->response = $trans->exception = null;
138
+ $trans->retries++;
139
+ }
140
+
141
+ private function send(Transaction $trans)
142
+ {
143
+ $fn = $this->handler;
144
+ $trans->response = FutureResponse::proxy(
145
+ $fn(RingBridge::prepareRingRequest($trans)),
146
+ function ($value) use ($trans) {
147
+ RingBridge::completeRingResponse($trans, $value, $this->mf, $this);
148
+ // Resolve deep futures if this is not a future transaction.
149
+ // This accounts for things like retries that would otherwise
150
+ // not have an immediate side-effect.
151
+ if (!$trans->future && $trans->response instanceof FutureInterface) {
152
+ $trans->response = $trans->response->wait();
153
+ }
154
+ return $trans->response;
155
+ }
156
+ );
157
+ }
158
+
159
+ /**
160
+ * Emits the error event and ensures that the exception is set and is an
161
+ * instance of RequestException. If the error event is not intercepted,
162
+ * then the exception is thrown and we transition to the "end" event. This
163
+ * event also allows requests to be retried, and when retried, transitions
164
+ * to the "before" event. Otherwise, when no retries, and the exception is
165
+ * intercepted, transition to the "complete" event.
166
+ */
167
+ private function error(Transaction $trans)
168
+ {
169
+ // Convert non-request exception to a wrapped exception
170
+ if (!($trans->exception instanceof RequestException)) {
171
+ $trans->exception = RequestException::wrapException(
172
+ $trans->request, $trans->exception
173
+ );
174
+ }
175
+
176
+ // Dispatch an event and allow interception
177
+ $event = new ErrorEvent($trans);
178
+ $trans->request->getEmitter()->emit('error', $event);
179
+
180
+ if ($trans->state === 'retry') {
181
+ return true;
182
+ }
183
+
184
+ if ($trans->exception) {
185
+ throw $trans->exception;
186
+ }
187
+
188
+ return false;
189
+ }
190
+
191
+ /**
192
+ * Emits a complete event, and if a request is marked for a retry during
193
+ * the complete event, then the "before" state is transitioned to.
194
+ */
195
+ private function complete(Transaction $trans)
196
+ {
197
+ // Futures will have their own end events emitted when dereferenced.
198
+ if ($trans->response instanceof FutureInterface) {
199
+ return false;
200
+ }
201
+
202
+ $trans->response->setEffectiveUrl($trans->request->getUrl());
203
+ $trans->request->getEmitter()->emit('complete', new CompleteEvent($trans));
204
+
205
+ // Return true to transition to the 'before' state. False otherwise.
206
+ return $trans->state === 'retry';
207
+ }
208
+
209
+ /**
210
+ * Emits the "end" event and throws an exception if one is present.
211
+ */
212
+ private function end(Transaction $trans)
213
+ {
214
+ // Futures will have their own end events emitted when dereferenced,
215
+ // but still emit, even for futures, when an exception is present.
216
+ if (!$trans->exception && $trans->response instanceof FutureInterface) {
217
+ return;
218
+ }
219
+
220
+ $trans->request->getEmitter()->emit('end', new EndEvent($trans));
221
+
222
+ // Throw exceptions in the terminal event if the exception was not
223
+ // handled by an "end" event listener.
224
+ if ($trans->exception) {
225
+ if (!($trans->exception instanceof RequestException)) {
226
+ $trans->exception = RequestException::wrapException(
227
+ $trans->request, $trans->exception
228
+ );
229
+ }
230
+ throw $trans->exception;
231
+ }
232
+ }
233
+ }
backend/vendor/guzzlehttp/guzzle/src/RingBridge.php ADDED
@@ -0,0 +1,170 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Message\MessageFactoryInterface;
5
+ use GuzzleHttp\Message\RequestInterface;
6
+ use GuzzleHttp\Event\ProgressEvent;
7
+ use GuzzleHttp\Message\Request;
8
+ use GuzzleHttp\Ring\Core;
9
+ use GuzzleHttp\Stream\Stream;
10
+ use GuzzleHttp\Exception\RequestException;
11
+
12
+ /**
13
+ * Provides the bridge between Guzzle requests and responses and Guzzle Ring.
14
+ */
15
+ class RingBridge
16
+ {
17
+ /**
18
+ * Creates a Ring request from a request object.
19
+ *
20
+ * This function does not hook up the "then" and "progress" events that
21
+ * would be required for actually sending a Guzzle request through a
22
+ * RingPHP handler.
23
+ *
24
+ * @param RequestInterface $request Request to convert.
25
+ *
26
+ * @return array Converted Guzzle Ring request.
27
+ */
28
+ public static function createRingRequest(RequestInterface $request)
29
+ {
30
+ $options = $request->getConfig()->toArray();
31
+ $url = $request->getUrl();
32
+ // No need to calculate the query string twice (in URL and query).
33
+ $qs = ($pos = strpos($url, '?')) ? substr($url, $pos + 1) : null;
34
+
35
+ return [
36
+ 'scheme' => $request->getScheme(),
37
+ 'http_method' => $request->getMethod(),
38
+ 'url' => $url,
39
+ 'uri' => $request->getPath(),
40
+ 'headers' => $request->getHeaders(),
41
+ 'body' => $request->getBody(),
42
+ 'version' => $request->getProtocolVersion(),
43
+ 'client' => $options,
44
+ 'query_string' => $qs,
45
+ 'future' => isset($options['future']) ? $options['future'] : false
46
+ ];
47
+ }
48
+
49
+ /**
50
+ * Creates a Ring request from a request object AND prepares the callbacks.
51
+ *
52
+ * @param Transaction $trans Transaction to update.
53
+ *
54
+ * @return array Converted Guzzle Ring request.
55
+ */
56
+ public static function prepareRingRequest(Transaction $trans)
57
+ {
58
+ // Clear out the transaction state when initiating.
59
+ $trans->exception = null;
60
+ $request = self::createRingRequest($trans->request);
61
+
62
+ // Emit progress events if any progress listeners are registered.
63
+ if ($trans->request->getEmitter()->hasListeners('progress')) {
64
+ $emitter = $trans->request->getEmitter();
65
+ $request['client']['progress'] = function ($a, $b, $c, $d) use ($trans, $emitter) {
66
+ $emitter->emit('progress', new ProgressEvent($trans, $a, $b, $c, $d));
67
+ };
68
+ }
69
+
70
+ return $request;
71
+ }
72
+
73
+ /**
74
+ * Handles the process of processing a response received from a ring
75
+ * handler. The created response is added to the transaction, and any
76
+ * necessary events are emitted based on the ring response.
77
+ *
78
+ * @param Transaction $trans Owns request and response.
79
+ * @param array $response Ring response array
80
+ * @param MessageFactoryInterface $messageFactory Creates response objects.
81
+ * @param callable $fsm Request FSM function.
82
+ */
83
+ public static function completeRingResponse(
84
+ Transaction $trans,
85
+ array $response,
86
+ MessageFactoryInterface $messageFactory,
87
+ callable $fsm
88
+ ) {
89
+ $trans->state = 'complete';
90
+ $trans->transferInfo = isset($response['transfer_stats'])
91
+ ? $response['transfer_stats'] : [];
92
+
93
+ if (!empty($response['status'])) {
94
+ $options = [];
95
+ if (isset($response['version'])) {
96
+ $options['protocol_version'] = $response['version'];
97
+ }
98
+ if (isset($response['reason'])) {
99
+ $options['reason_phrase'] = $response['reason'];
100
+ }
101
+ $trans->response = $messageFactory->createResponse(
102
+ $response['status'],
103
+ isset($response['headers']) ? $response['headers'] : [],
104
+ isset($response['body']) ? $response['body'] : null,
105
+ $options
106
+ );
107
+ if (isset($response['effective_url'])) {
108
+ $trans->response->setEffectiveUrl($response['effective_url']);
109
+ }
110
+ } elseif (empty($response['error'])) {
111
+ // When nothing was returned, then we need to add an error.
112
+ $response['error'] = self::getNoRingResponseException($trans->request);
113
+ }
114
+
115
+ if (isset($response['error'])) {
116
+ $trans->state = 'error';
117
+ $trans->exception = $response['error'];
118
+ }
119
+
120
+ // Complete the lifecycle of the request.
121
+ $fsm($trans);
122
+ }
123
+
124
+ /**
125
+ * Creates a Guzzle request object using a ring request array.
126
+ *
127
+ * @param array $request Ring request
128
+ *
129
+ * @return Request
130
+ * @throws \InvalidArgumentException for incomplete requests.
131
+ */
132
+ public static function fromRingRequest(array $request)
133
+ {
134
+ $options = [];
135
+ if (isset($request['version'])) {
136
+ $options['protocol_version'] = $request['version'];
137
+ }
138
+
139
+ if (!isset($request['http_method'])) {
140
+ throw new \InvalidArgumentException('No http_method');
141
+ }
142
+
143
+ return new Request(
144
+ $request['http_method'],
145
+ Core::url($request),
146
+ isset($request['headers']) ? $request['headers'] : [],
147
+ isset($request['body']) ? Stream::factory($request['body']) : null,
148
+ $options
149
+ );
150
+ }
151
+
152
+ /**
153
+ * Get an exception that can be used when a RingPHP handler does not
154
+ * populate a response.
155
+ *
156
+ * @param RequestInterface $request
157
+ *
158
+ * @return RequestException
159
+ */
160
+ public static function getNoRingResponseException(RequestInterface $request)
161
+ {
162
+ $message = <<<EOT
163
+ Sending the request did not return a response, exception, or populate the
164
+ transaction with a response. This is most likely due to an incorrectly
165
+ implemented RingPHP handler. If you are simply trying to mock responses,
166
+ then it is recommneded to use the GuzzleHttp\Ring\Client\MockHandler.
167
+ EOT;
168
+ return new RequestException($message, $request);
169
+ }
170
+ }
backend/vendor/guzzlehttp/guzzle/src/Subscriber/Cookie.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Subscriber;
3
+
4
+ use GuzzleHttp\Cookie\CookieJar;
5
+ use GuzzleHttp\Cookie\CookieJarInterface;
6
+ use GuzzleHttp\Event\BeforeEvent;
7
+ use GuzzleHttp\Event\CompleteEvent;
8
+ use GuzzleHttp\Event\RequestEvents;
9
+ use GuzzleHttp\Event\SubscriberInterface;
10
+
11
+ /**
12
+ * Adds, extracts, and persists cookies between HTTP requests
13
+ */
14
+ class Cookie implements SubscriberInterface
15
+ {
16
+ /** @var CookieJarInterface */
17
+ private $cookieJar;
18
+
19
+ /**
20
+ * @param CookieJarInterface $cookieJar Cookie jar used to hold cookies
21
+ */
22
+ public function __construct(CookieJarInterface $cookieJar = null)
23
+ {
24
+ $this->cookieJar = $cookieJar ?: new CookieJar();
25
+ }
26
+
27
+ public function getEvents()
28
+ {
29
+ // Fire the cookie plugin complete event before redirecting
30
+ return [
31
+ 'before' => ['onBefore'],
32
+ 'complete' => ['onComplete', RequestEvents::REDIRECT_RESPONSE + 10]
33
+ ];
34
+ }
35
+
36
+ /**
37
+ * Get the cookie cookieJar
38
+ *
39
+ * @return CookieJarInterface
40
+ */
41
+ public function getCookieJar()
42
+ {
43
+ return $this->cookieJar;
44
+ }
45
+
46
+ public function onBefore(BeforeEvent $event)
47
+ {
48
+ $this->cookieJar->addCookieHeader($event->getRequest());
49
+ }
50
+
51
+ public function onComplete(CompleteEvent $event)
52
+ {
53
+ $this->cookieJar->extractCookies(
54
+ $event->getRequest(),
55
+ $event->getResponse()
56
+ );
57
+ }
58
+ }
backend/vendor/guzzlehttp/guzzle/src/Subscriber/History.php ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Subscriber;
3
+
4
+ use GuzzleHttp\Event\CompleteEvent;
5
+ use GuzzleHttp\Event\ErrorEvent;
6
+ use GuzzleHttp\Event\RequestEvents;
7
+ use GuzzleHttp\Event\SubscriberInterface;
8
+ use GuzzleHttp\Message\RequestInterface;
9
+ use GuzzleHttp\Message\ResponseInterface;
10
+
11
+ /**
12
+ * Maintains a list of requests and responses sent using a request or client
13
+ */
14
+ class History implements SubscriberInterface, \IteratorAggregate, \Countable
15
+ {
16
+ /** @var int The maximum number of requests to maintain in the history */
17
+ private $limit;
18
+
19
+ /** @var array Requests and responses that have passed through the plugin */
20
+ private $transactions = [];
21
+
22
+ public function __construct($limit = 10)
23
+ {
24
+ $this->limit = $limit;
25
+ }
26
+
27
+ public function getEvents()
28
+ {
29
+ return [
30
+ 'complete' => ['onComplete', RequestEvents::EARLY],
31
+ 'error' => ['onError', RequestEvents::EARLY],
32
+ ];
33
+ }
34
+
35
+ /**
36
+ * Convert to a string that contains all request and response headers
37
+ *
38
+ * @return string
39
+ */
40
+ public function __toString()
41
+ {
42
+ $lines = array();
43
+ foreach ($this->transactions as $entry) {
44
+ $response = isset($entry['response']) ? $entry['response'] : '';
45
+ $lines[] = '> ' . trim($entry['sent_request'])
46
+ . "\n\n< " . trim($response) . "\n";
47
+ }
48
+
49
+ return implode("\n", $lines);
50
+ }
51
+
52
+ public function onComplete(CompleteEvent $event)
53
+ {
54
+ $this->add($event->getRequest(), $event->getResponse());
55
+ }
56
+
57
+ public function onError(ErrorEvent $event)
58
+ {
59
+ // Only track when no response is present, meaning this didn't ever
60
+ // emit a complete event
61
+ if (!$event->getResponse()) {
62
+ $this->add($event->getRequest());
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Returns an Iterator that yields associative array values where each
68
+ * associative array contains the following key value pairs:
69
+ *
70
+ * - request: Representing the actual request that was received.
71
+ * - sent_request: A clone of the request that will not be mutated.
72
+ * - response: The response that was received (if available).
73
+ *
74
+ * @return \Iterator
75
+ */
76
+ public function getIterator()
77
+ {
78
+ return new \ArrayIterator($this->transactions);
79
+ }
80
+
81
+ /**
82
+ * Get all of the requests sent through the plugin.
83
+ *
84
+ * Requests can be modified after they are logged by the history
85
+ * subscriber. By default this method will return the actual request
86
+ * instances that were received. Pass true to this method if you wish to
87
+ * get copies of the requests that represent the request state when it was
88
+ * initially logged by the history subscriber.
89
+ *
90
+ * @param bool $asSent Set to true to get clones of the requests that have
91
+ * not been mutated since the request was received by
92
+ * the history subscriber.
93
+ *
94
+ * @return RequestInterface[]
95
+ */
96
+ public function getRequests($asSent = false)
97
+ {
98
+ return array_map(function ($t) use ($asSent) {
99
+ return $asSent ? $t['sent_request'] : $t['request'];
100
+ }, $this->transactions);
101
+ }
102
+
103
+ /**
104
+ * Get the number of requests in the history
105
+ *
106
+ * @return int
107
+ */
108
+ public function count()
109
+ {
110
+ return count($this->transactions);
111
+ }
112
+
113
+ /**
114
+ * Get the last request sent.
115
+ *
116
+ * Requests can be modified after they are logged by the history
117
+ * subscriber. By default this method will return the actual request
118
+ * instance that was received. Pass true to this method if you wish to get
119
+ * a copy of the request that represents the request state when it was
120
+ * initially logged by the history subscriber.
121
+ *
122
+ * @param bool $asSent Set to true to get a clone of the last request that
123
+ * has not been mutated since the request was received
124
+ * by the history subscriber.
125
+ *
126
+ * @return RequestInterface
127
+ */
128
+ public function getLastRequest($asSent = false)
129
+ {
130
+ return $asSent
131
+ ? end($this->transactions)['sent_request']
132
+ : end($this->transactions)['request'];
133
+ }
134
+
135
+ /**
136
+ * Get the last response in the history
137
+ *
138
+ * @return ResponseInterface|null
139
+ */
140
+ public function getLastResponse()
141
+ {
142
+ return end($this->transactions)['response'];
143
+ }
144
+
145
+ /**
146
+ * Clears the history
147
+ */
148
+ public function clear()
149
+ {
150
+ $this->transactions = array();
151
+ }
152
+
153
+ /**
154
+ * Add a request to the history
155
+ *
156
+ * @param RequestInterface $request Request to add
157
+ * @param ResponseInterface $response Response of the request
158
+ */
159
+ private function add(
160
+ RequestInterface $request,
161
+ ResponseInterface $response = null
162
+ ) {
163
+ $this->transactions[] = [
164
+ 'request' => $request,
165
+ 'sent_request' => clone $request,
166
+ 'response' => $response
167
+ ];
168
+ if (count($this->transactions) > $this->limit) {
169
+ array_shift($this->transactions);
170
+ }
171
+ }
172
+ }
backend/vendor/guzzlehttp/guzzle/src/Subscriber/HttpError.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Subscriber;
3
+
4
+ use GuzzleHttp\Event\CompleteEvent;
5
+ use GuzzleHttp\Event\RequestEvents;
6
+ use GuzzleHttp\Event\SubscriberInterface;
7
+ use GuzzleHttp\Exception\RequestException;
8
+
9
+ /**
10
+ * Throws exceptions when a 4xx or 5xx response is received
11
+ */
12
+ class HttpError implements SubscriberInterface
13
+ {
14
+ public function getEvents()
15
+ {
16
+ return ['complete' => ['onComplete', RequestEvents::VERIFY_RESPONSE]];
17
+ }
18
+
19
+ /**
20
+ * Throw a RequestException on an HTTP protocol error
21
+ *
22
+ * @param CompleteEvent $event Emitted event
23
+ * @throws RequestException
24
+ */
25
+ public function onComplete(CompleteEvent $event)
26
+ {
27
+ $code = (string) $event->getResponse()->getStatusCode();
28
+ // Throw an exception for an unsuccessful response
29
+ if ($code[0] >= 4) {
30
+ throw RequestException::create(
31
+ $event->getRequest(),
32
+ $event->getResponse()
33
+ );
34
+ }
35
+ }
36
+ }
backend/vendor/guzzlehttp/guzzle/src/Subscriber/Mock.php ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Subscriber;
3
+
4
+ use GuzzleHttp\Event\RequestEvents;
5
+ use GuzzleHttp\Event\SubscriberInterface;
6
+ use GuzzleHttp\Event\BeforeEvent;
7
+ use GuzzleHttp\Exception\RequestException;
8
+ use GuzzleHttp\Message\MessageFactory;
9
+ use GuzzleHttp\Message\ResponseInterface;
10
+
11
+ /**
12
+ * Queues mock responses or exceptions and delivers mock responses or
13
+ * exceptions in a fifo order.
14
+ */
15
+ class Mock implements SubscriberInterface, \Countable
16
+ {
17
+ /** @var array Array of mock responses / exceptions */
18
+ private $queue = [];
19
+
20
+ /** @var bool Whether or not to consume an entity body when mocking */
21
+ private $readBodies;
22
+
23
+ /** @var MessageFactory */
24
+ private $factory;
25
+
26
+ /**
27
+ * @param array $items Array of responses or exceptions to queue
28
+ * @param bool $readBodies Set to false to not consume the entity body of
29
+ * a request when a mock is served.
30
+ */
31
+ public function __construct(array $items = [], $readBodies = true)
32
+ {
33
+ $this->factory = new MessageFactory();
34
+ $this->readBodies = $readBodies;
35
+ $this->addMultiple($items);
36
+ }
37
+
38
+ public function getEvents()
39
+ {
40
+ // Fire the event last, after signing
41
+ return ['before' => ['onBefore', RequestEvents::SIGN_REQUEST - 10]];
42
+ }
43
+
44
+ /**
45
+ * @throws \OutOfBoundsException|\Exception
46
+ */
47
+ public function onBefore(BeforeEvent $event)
48
+ {
49
+ if (!$item = array_shift($this->queue)) {
50
+ throw new \OutOfBoundsException('Mock queue is empty');
51
+ } elseif ($item instanceof RequestException) {
52
+ throw $item;
53
+ }
54
+
55
+ // Emulate reading a response body
56
+ $request = $event->getRequest();
57
+ if ($this->readBodies && $request->getBody()) {
58
+ while (!$request->getBody()->eof()) {
59
+ $request->getBody()->read(8096);
60
+ }
61
+ }
62
+
63
+ $event->intercept($item);
64
+ }
65
+
66
+ public function count()
67
+ {
68
+ return count($this->queue);
69
+ }
70
+
71
+ /**
72
+ * Add a response to the end of the queue
73
+ *
74
+ * @param string|ResponseInterface $response Response or path to response file
75
+ *
76
+ * @return self
77
+ * @throws \InvalidArgumentException if a string or Response is not passed
78
+ */
79
+ public function addResponse($response)
80
+ {
81
+ if (is_string($response)) {
82
+ $response = file_exists($response)
83
+ ? $this->factory->fromMessage(file_get_contents($response))
84
+ : $this->factory->fromMessage($response);
85
+ } elseif (!($response instanceof ResponseInterface)) {
86
+ throw new \InvalidArgumentException('Response must a message '
87
+ . 'string, response object, or path to a file');
88
+ }
89
+
90
+ $this->queue[] = $response;
91
+
92
+ return $this;
93
+ }
94
+
95
+ /**
96
+ * Add an exception to the end of the queue
97
+ *
98
+ * @param RequestException $e Exception to throw when the request is executed
99
+ *
100
+ * @return self
101
+ */
102
+ public function addException(RequestException $e)
103
+ {
104
+ $this->queue[] = $e;
105
+
106
+ return $this;
107
+ }
108
+
109
+ /**
110
+ * Add multiple items to the queue
111
+ *
112
+ * @param array $items Items to add
113
+ */
114
+ public function addMultiple(array $items)
115
+ {
116
+ foreach ($items as $item) {
117
+ if ($item instanceof RequestException) {
118
+ $this->addException($item);
119
+ } else {
120
+ $this->addResponse($item);
121
+ }
122
+ }
123
+ }
124
+
125
+ /**
126
+ * Clear the queue
127
+ */
128
+ public function clearQueue()
129
+ {
130
+ $this->queue = [];
131
+ }
132
+ }
backend/vendor/guzzlehttp/guzzle/src/Subscriber/Prepare.php ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Subscriber;
3
+
4
+ use GuzzleHttp\Event\BeforeEvent;
5
+ use GuzzleHttp\Event\RequestEvents;
6
+ use GuzzleHttp\Event\SubscriberInterface;
7
+ use GuzzleHttp\Message\RequestInterface;
8
+ use GuzzleHttp\Mimetypes;
9
+ use GuzzleHttp\Post\PostBodyInterface;
10
+ use GuzzleHttp\Stream\StreamInterface;
11
+
12
+ /**
13
+ * Prepares requests with a body before sending
14
+ *
15
+ * **Request Options**
16
+ *
17
+ * - expect: Set to true to enable the "Expect: 100-Continue" header for a
18
+ * request that send a body. Set to false to disable "Expect: 100-Continue".
19
+ * Set to a number so that the size of the payload must be greater than the
20
+ * number in order to send the Expect header. Setting to a number will send
21
+ * the Expect header for all requests in which the size of the payload cannot
22
+ * be determined or where the body is not rewindable.
23
+ */
24
+ class Prepare implements SubscriberInterface
25
+ {
26
+ public function getEvents()
27
+ {
28
+ return ['before' => ['onBefore', RequestEvents::PREPARE_REQUEST]];
29
+ }
30
+
31
+ public function onBefore(BeforeEvent $event)
32
+ {
33
+ $request = $event->getRequest();
34
+
35
+ // Set the appropriate Content-Type for a request if one is not set and
36
+ // there are form fields
37
+ if (!($body = $request->getBody())) {
38
+ return;
39
+ }
40
+
41
+ $this->addContentLength($request, $body);
42
+
43
+ if ($body instanceof PostBodyInterface) {
44
+ // Synchronize the POST body with the request's headers
45
+ $body->applyRequestHeaders($request);
46
+ } elseif (!$request->hasHeader('Content-Type')) {
47
+ $this->addContentType($request, $body);
48
+ }
49
+
50
+ $this->addExpectHeader($request, $body);
51
+ }
52
+
53
+ private function addContentType(
54
+ RequestInterface $request,
55
+ StreamInterface $body
56
+ ) {
57
+ if (!($uri = $body->getMetadata('uri'))) {
58
+ return;
59
+ }
60
+
61
+ // Guess the content-type based on the stream's "uri" metadata value.
62
+ // The file extension is used to determine the appropriate mime-type.
63
+ if ($contentType = Mimetypes::getInstance()->fromFilename($uri)) {
64
+ $request->setHeader('Content-Type', $contentType);
65
+ }
66
+ }
67
+
68
+ private function addContentLength(
69
+ RequestInterface $request,
70
+ StreamInterface $body
71
+ ) {
72
+ // Set the Content-Length header if it can be determined, and never
73
+ // send a Transfer-Encoding: chunked and Content-Length header in
74
+ // the same request.
75
+ if ($request->hasHeader('Content-Length')) {
76
+ // Remove transfer-encoding if content-length is set.
77
+ $request->removeHeader('Transfer-Encoding');
78
+ return;
79
+ }
80
+
81
+ if ($request->hasHeader('Transfer-Encoding')) {
82
+ return;
83
+ }
84
+
85
+ if (null !== ($size = $body->getSize())) {
86
+ $request->setHeader('Content-Length', $size);
87
+ $request->removeHeader('Transfer-Encoding');
88
+ } elseif ('1.1' == $request->getProtocolVersion()) {
89
+ // Use chunked Transfer-Encoding if there is no determinable
90
+ // content-length header and we're using HTTP/1.1.
91
+ $request->setHeader('Transfer-Encoding', 'chunked');
92
+ $request->removeHeader('Content-Length');
93
+ }
94
+ }
95
+
96
+ private function addExpectHeader(
97
+ RequestInterface $request,
98
+ StreamInterface $body
99
+ ) {
100
+ // Determine if the Expect header should be used
101
+ if ($request->hasHeader('Expect')) {
102
+ return;
103
+ }
104
+
105
+ $expect = $request->getConfig()['expect'];
106
+
107
+ // Return if disabled or if you're not using HTTP/1.1
108
+ if ($expect === false || $request->getProtocolVersion() !== '1.1') {
109
+ return;
110
+ }
111
+
112
+ // The expect header is unconditionally enabled
113
+ if ($expect === true) {
114
+ $request->setHeader('Expect', '100-Continue');
115
+ return;
116
+ }
117
+
118
+ // By default, send the expect header when the payload is > 1mb
119
+ if ($expect === null) {
120
+ $expect = 1048576;
121
+ }
122
+
123
+ // Always add if the body cannot be rewound, the size cannot be
124
+ // determined, or the size is greater than the cutoff threshold
125
+ $size = $body->getSize();
126
+ if ($size === null || $size >= (int) $expect || !$body->isSeekable()) {
127
+ $request->setHeader('Expect', '100-Continue');
128
+ }
129
+ }
130
+ }
backend/vendor/guzzlehttp/guzzle/src/Subscriber/Redirect.php ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Subscriber;
3
+
4
+ use GuzzleHttp\Event\CompleteEvent;
5
+ use GuzzleHttp\Event\RequestEvents;
6
+ use GuzzleHttp\Event\SubscriberInterface;
7
+ use GuzzleHttp\Exception\BadResponseException;
8
+ use GuzzleHttp\Exception\CouldNotRewindStreamException;
9
+ use GuzzleHttp\Exception\TooManyRedirectsException;
10
+ use GuzzleHttp\Message\RequestInterface;
11
+ use GuzzleHttp\Message\ResponseInterface;
12
+ use GuzzleHttp\Url;
13
+
14
+ /**
15
+ * Subscriber used to implement HTTP redirects.
16
+ *
17
+ * **Request options**
18
+ *
19
+ * - redirect: Associative array containing the 'max', 'strict', and 'referer'
20
+ * keys.
21
+ *
22
+ * - max: Maximum number of redirects allowed per-request
23
+ * - strict: You can use strict redirects by setting this value to ``true``.
24
+ * Strict redirects adhere to strict RFC compliant redirection (e.g.,
25
+ * redirect POST with POST) vs doing what most clients do (e.g., redirect
26
+ * POST request with a GET request).
27
+ * - referer: Set to true to automatically add the "Referer" header when a
28
+ * redirect request is sent.
29
+ * - protocols: Array of allowed protocols. Defaults to 'http' and 'https'.
30
+ * When a redirect attempts to utilize a protocol that is not white listed,
31
+ * an exception is thrown.
32
+ */
33
+ class Redirect implements SubscriberInterface
34
+ {
35
+ public function getEvents()
36
+ {
37
+ return ['complete' => ['onComplete', RequestEvents::REDIRECT_RESPONSE]];
38
+ }
39
+
40
+ /**
41
+ * Rewind the entity body of the request if needed
42
+ *
43
+ * @param RequestInterface $redirectRequest
44
+ * @throws CouldNotRewindStreamException
45
+ */
46
+ public static function rewindEntityBody(RequestInterface $redirectRequest)
47
+ {
48
+ // Rewind the entity body of the request if needed
49
+ if ($body = $redirectRequest->getBody()) {
50
+ // Only rewind the body if some of it has been read already, and
51
+ // throw an exception if the rewind fails
52
+ if ($body->tell() && !$body->seek(0)) {
53
+ throw new CouldNotRewindStreamException(
54
+ 'Unable to rewind the non-seekable request body after redirecting',
55
+ $redirectRequest
56
+ );
57
+ }
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Called when a request receives a redirect response
63
+ *
64
+ * @param CompleteEvent $event Event emitted
65
+ * @throws TooManyRedirectsException
66
+ */
67
+ public function onComplete(CompleteEvent $event)
68
+ {
69
+ $response = $event->getResponse();
70
+
71
+ if (substr($response->getStatusCode(), 0, 1) != '3'
72
+ || !$response->hasHeader('Location')
73
+ ) {
74
+ return;
75
+ }
76
+
77
+ $request = $event->getRequest();
78
+ $config = $request->getConfig();
79
+
80
+ // Increment the redirect and initialize the redirect state.
81
+ if ($redirectCount = $config['redirect_count']) {
82
+ $config['redirect_count'] = ++$redirectCount;
83
+ } else {
84
+ $config['redirect_scheme'] = $request->getScheme();
85
+ $config['redirect_count'] = $redirectCount = 1;
86
+ }
87
+
88
+ $max = $config->getPath('redirect/max') ?: 5;
89
+
90
+ if ($redirectCount > $max) {
91
+ throw new TooManyRedirectsException(
92
+ "Will not follow more than {$redirectCount} redirects",
93
+ $request
94
+ );
95
+ }
96
+
97
+ $this->modifyRedirectRequest($request, $response);
98
+ $event->retry();
99
+ }
100
+
101
+ private function modifyRedirectRequest(
102
+ RequestInterface $request,
103
+ ResponseInterface $response
104
+ ) {
105
+ $config = $request->getConfig();
106
+ $protocols = $config->getPath('redirect/protocols') ?: ['http', 'https'];
107
+
108
+ // Use a GET request if this is an entity enclosing request and we are
109
+ // not forcing RFC compliance, but rather emulating what all browsers
110
+ // would do.
111
+ $statusCode = $response->getStatusCode();
112
+ if ($statusCode == 303 ||
113
+ ($statusCode <= 302 && $request->getBody() && !$config->getPath('redirect/strict'))
114
+ ) {
115
+ $request->setMethod('GET');
116
+ $request->setBody(null);
117
+ }
118
+
119
+ $previousUrl = $request->getUrl();
120
+ $this->setRedirectUrl($request, $response, $protocols);
121
+ $this->rewindEntityBody($request);
122
+
123
+ // Add the Referer header if it is told to do so and only
124
+ // add the header if we are not redirecting from https to http.
125
+ if ($config->getPath('redirect/referer')
126
+ && ($request->getScheme() == 'https' || $request->getScheme() == $config['redirect_scheme'])
127
+ ) {
128
+ $url = Url::fromString($previousUrl);
129
+ $url->setUsername(null);
130
+ $url->setPassword(null);
131
+ $request->setHeader('Referer', (string) $url);
132
+ } else {
133
+ $request->removeHeader('Referer');
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Set the appropriate URL on the request based on the location header
139
+ *
140
+ * @param RequestInterface $request
141
+ * @param ResponseInterface $response
142
+ * @param array $protocols
143
+ */
144
+ private function setRedirectUrl(
145
+ RequestInterface $request,
146
+ ResponseInterface $response,
147
+ array $protocols
148
+ ) {
149
+ $location = $response->getHeader('Location');
150
+ $location = Url::fromString($location);
151
+
152
+ // Combine location with the original URL if it is not absolute.
153
+ if (!$location->isAbsolute()) {
154
+ $originalUrl = Url::fromString($request->getUrl());
155
+ // Remove query string parameters and just take what is present on
156
+ // the redirect Location header
157
+ $originalUrl->getQuery()->clear();
158
+ $location = $originalUrl->combine($location);
159
+ }
160
+
161
+ // Ensure that the redirect URL is allowed based on the protocols.
162
+ if (!in_array($location->getScheme(), $protocols)) {
163
+ throw new BadResponseException(
164
+ sprintf(
165
+ 'Redirect URL, %s, does not use one of the allowed redirect protocols: %s',
166
+ $location,
167
+ implode(', ', $protocols)
168
+ ),
169
+ $request,
170
+ $response
171
+ );
172
+ }
173
+
174
+ $request->setUrl($location);
175
+ }
176
+ }
backend/vendor/guzzlehttp/guzzle/src/ToArrayInterface.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ /**
5
+ * An object that can be represented as an array
6
+ */
7
+ interface ToArrayInterface
8
+ {
9
+ /**
10
+ * Get the array representation of an object
11
+ *
12
+ * @return array
13
+ */
14
+ public function toArray();
15
+ }
backend/vendor/guzzlehttp/guzzle/src/Transaction.php ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Message\RequestInterface;
5
+ use GuzzleHttp\Message\ResponseInterface;
6
+
7
+ /**
8
+ * Represents the relationship between a client, request, and response.
9
+ *
10
+ * You can access the request, response, and client using their corresponding
11
+ * public properties.
12
+ */
13
+ class Transaction
14
+ {
15
+ /**
16
+ * HTTP client used to transfer the request.
17
+ *
18
+ * @var ClientInterface
19
+ */
20
+ public $client;
21
+
22
+ /**
23
+ * The request that is being sent.
24
+ *
25
+ * @var RequestInterface
26
+ */
27
+ public $request;
28
+
29
+ /**
30
+ * The response associated with the transaction. A response will not be
31
+ * present when a networking error occurs or an error occurs before sending
32
+ * the request.
33
+ *
34
+ * @var ResponseInterface|null
35
+ */
36
+ public $response;
37
+
38
+ /**
39
+ * Exception associated with the transaction. If this exception is present
40
+ * when processing synchronous or future commands, then it is thrown. When
41
+ * intercepting a failed transaction, you MUST set this value to null in
42
+ * order to prevent the exception from being thrown.
43
+ *
44
+ * @var \Exception
45
+ */
46
+ public $exception;
47
+
48
+ /**
49
+ * Associative array of handler specific transfer statistics and custom
50
+ * key value pair information. When providing similar information, handlers
51
+ * should follow the same key value pair naming conventions as PHP's
52
+ * curl_getinfo() (http://php.net/manual/en/function.curl-getinfo.php).
53
+ *
54
+ * @var array
55
+ */
56
+ public $transferInfo = [];
57
+
58
+ /**
59
+ * The number of transaction retries.
60
+ *
61
+ * @var int
62
+ */
63
+ public $retries = 0;
64
+
65
+ /**
66
+ * The transaction's current state.
67
+ *
68
+ * @var string
69
+ */
70
+ public $state;
71
+
72
+ /**
73
+ * Whether or not this is a future transaction. This value should not be
74
+ * changed after the future is constructed.
75
+ *
76
+ * @var bool
77
+ */
78
+ public $future;
79
+
80
+ /**
81
+ * The number of state transitions that this transaction has been through.
82
+ *
83
+ * @var int
84
+ * @internal This is for internal use only. If you modify this, then you
85
+ * are asking for trouble.
86
+ */
87
+ public $_transitionCount = 0;
88
+
89
+ /**
90
+ * @param ClientInterface $client Client that is used to send the requests
91
+ * @param RequestInterface $request Request to send
92
+ * @param bool $future Whether or not this is a future request.
93
+ */
94
+ public function __construct(
95
+ ClientInterface $client,
96
+ RequestInterface $request,
97
+ $future = false
98
+ ) {
99
+ $this->client = $client;
100
+ $this->request = $request;
101
+ $this->_future = $future;
102
+ }
103
+ }
backend/vendor/guzzlehttp/guzzle/src/UriTemplate.php ADDED
@@ -0,0 +1,241 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ /**
5
+ * Expands URI templates. Userland implementation of PECL uri_template.
6
+ *
7
+ * @link http://tools.ietf.org/html/rfc6570
8
+ */
9
+ class UriTemplate
10
+ {
11
+ /** @var string URI template */
12
+ private $template;
13
+
14
+ /** @var array Variables to use in the template expansion */
15
+ private $variables;
16
+
17
+ /** @var array Hash for quick operator lookups */
18
+ private static $operatorHash = array(
19
+ '' => array('prefix' => '', 'joiner' => ',', 'query' => false),
20
+ '+' => array('prefix' => '', 'joiner' => ',', 'query' => false),
21
+ '#' => array('prefix' => '#', 'joiner' => ',', 'query' => false),
22
+ '.' => array('prefix' => '.', 'joiner' => '.', 'query' => false),
23
+ '/' => array('prefix' => '/', 'joiner' => '/', 'query' => false),
24
+ ';' => array('prefix' => ';', 'joiner' => ';', 'query' => true),
25
+ '?' => array('prefix' => '?', 'joiner' => '&', 'query' => true),
26
+ '&' => array('prefix' => '&', 'joiner' => '&', 'query' => true)
27
+ );
28
+
29
+ /** @var array Delimiters */
30
+ private static $delims = array(':', '/', '?', '#', '[', ']', '@', '!', '$',
31
+ '&', '\'', '(', ')', '*', '+', ',', ';', '=');
32
+
33
+ /** @var array Percent encoded delimiters */
34
+ private static $delimsPct = array('%3A', '%2F', '%3F', '%23', '%5B', '%5D',
35
+ '%40', '%21', '%24', '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C',
36
+ '%3B', '%3D');
37
+
38
+ public function expand($template, array $variables)
39
+ {
40
+ if (false === strpos($template, '{')) {
41
+ return $template;
42
+ }
43
+
44
+ $this->template = $template;
45
+ $this->variables = $variables;
46
+
47
+ return preg_replace_callback(
48
+ '/\{([^\}]+)\}/',
49
+ [$this, 'expandMatch'],
50
+ $this->template
51
+ );
52
+ }
53
+
54
+ /**
55
+ * Parse an expression into parts
56
+ *
57
+ * @param string $expression Expression to parse
58
+ *
59
+ * @return array Returns an associative array of parts
60
+ */
61
+ private function parseExpression($expression)
62
+ {
63
+ $result = array();
64
+
65
+ if (isset(self::$operatorHash[$expression[0]])) {
66
+ $result['operator'] = $expression[0];
67
+ $expression = substr($expression, 1);
68
+ } else {
69
+ $result['operator'] = '';
70
+ }
71
+
72
+ foreach (explode(',', $expression) as $value) {
73
+ $value = trim($value);
74
+ $varspec = array();
75
+ if ($colonPos = strpos($value, ':')) {
76
+ $varspec['value'] = substr($value, 0, $colonPos);
77
+ $varspec['modifier'] = ':';
78
+ $varspec['position'] = (int) substr($value, $colonPos + 1);
79
+ } elseif (substr($value, -1) == '*') {
80
+ $varspec['modifier'] = '*';
81
+ $varspec['value'] = substr($value, 0, -1);
82
+ } else {
83
+ $varspec['value'] = (string) $value;
84
+ $varspec['modifier'] = '';
85
+ }
86
+ $result['values'][] = $varspec;
87
+ }
88
+
89
+ return $result;
90
+ }
91
+
92
+ /**
93
+ * Process an expansion
94
+ *
95
+ * @param array $matches Matches met in the preg_replace_callback
96
+ *
97
+ * @return string Returns the replacement string
98
+ */
99
+ private function expandMatch(array $matches)
100
+ {
101
+ static $rfc1738to3986 = array('+' => '%20', '%7e' => '~');
102
+
103
+ $replacements = array();
104
+ $parsed = self::parseExpression($matches[1]);
105
+ $prefix = self::$operatorHash[$parsed['operator']]['prefix'];
106
+ $joiner = self::$operatorHash[$parsed['operator']]['joiner'];
107
+ $useQuery = self::$operatorHash[$parsed['operator']]['query'];
108
+
109
+ foreach ($parsed['values'] as $value) {
110
+
111
+ if (!isset($this->variables[$value['value']])) {
112
+ continue;
113
+ }
114
+
115
+ $variable = $this->variables[$value['value']];
116
+ $actuallyUseQuery = $useQuery;
117
+ $expanded = '';
118
+
119
+ if (is_array($variable)) {
120
+
121
+ $isAssoc = $this->isAssoc($variable);
122
+ $kvp = array();
123
+ foreach ($variable as $key => $var) {
124
+
125
+ if ($isAssoc) {
126
+ $key = rawurlencode($key);
127
+ $isNestedArray = is_array($var);
128
+ } else {
129
+ $isNestedArray = false;
130
+ }
131
+
132
+ if (!$isNestedArray) {
133
+ $var = rawurlencode($var);
134
+ if ($parsed['operator'] == '+' ||
135
+ $parsed['operator'] == '#'
136
+ ) {
137
+ $var = $this->decodeReserved($var);
138
+ }
139
+ }
140
+
141
+ if ($value['modifier'] == '*') {
142
+ if ($isAssoc) {
143
+ if ($isNestedArray) {
144
+ // Nested arrays must allow for deeply nested
145
+ // structures.
146
+ $var = strtr(
147
+ http_build_query([$key => $var]),
148
+ $rfc1738to3986
149
+ );
150
+ } else {
151
+ $var = $key . '=' . $var;
152
+ }
153
+ } elseif ($key > 0 && $actuallyUseQuery) {
154
+ $var = $value['value'] . '=' . $var;
155
+ }
156
+ }
157
+
158
+ $kvp[$key] = $var;
159
+ }
160
+
161
+ if (empty($variable)) {
162
+ $actuallyUseQuery = false;
163
+ } elseif ($value['modifier'] == '*') {
164
+ $expanded = implode($joiner, $kvp);
165
+ if ($isAssoc) {
166
+ // Don't prepend the value name when using the explode
167
+ // modifier with an associative array.
168
+ $actuallyUseQuery = false;
169
+ }
170
+ } else {
171
+ if ($isAssoc) {
172
+ // When an associative array is encountered and the
173
+ // explode modifier is not set, then the result must be
174
+ // a comma separated list of keys followed by their
175
+ // respective values.
176
+ foreach ($kvp as $k => &$v) {
177
+ $v = $k . ',' . $v;
178
+ }
179
+ }
180
+ $expanded = implode(',', $kvp);
181
+ }
182
+
183
+ } else {
184
+ if ($value['modifier'] == ':') {
185
+ $variable = substr($variable, 0, $value['position']);
186
+ }
187
+ $expanded = rawurlencode($variable);
188
+ if ($parsed['operator'] == '+' || $parsed['operator'] == '#') {
189
+ $expanded = $this->decodeReserved($expanded);
190
+ }
191
+ }
192
+
193
+ if ($actuallyUseQuery) {
194
+ if (!$expanded && $joiner != '&') {
195
+ $expanded = $value['value'];
196
+ } else {
197
+ $expanded = $value['value'] . '=' . $expanded;
198
+ }
199
+ }
200
+
201
+ $replacements[] = $expanded;
202
+ }
203
+
204
+ $ret = implode($joiner, $replacements);
205
+ if ($ret && $prefix) {
206
+ return $prefix . $ret;
207
+ }
208
+
209
+ return $ret;
210
+ }
211
+
212
+ /**
213
+ * Determines if an array is associative.
214
+ *
215
+ * This makes the assumption that input arrays are sequences or hashes.
216
+ * This assumption is a tradeoff for accuracy in favor of speed, but it
217
+ * should work in almost every case where input is supplied for a URI
218
+ * template.
219
+ *
220
+ * @param array $array Array to check
221
+ *
222
+ * @return bool
223
+ */
224
+ private function isAssoc(array $array)
225
+ {
226
+ return $array && array_keys($array)[0] !== 0;
227
+ }
228
+
229
+ /**
230
+ * Removes percent encoding on reserved characters (used with + and #
231
+ * modifiers).
232
+ *
233
+ * @param string $string String to fix
234
+ *
235
+ * @return string
236
+ */
237
+ private function decodeReserved($string)
238
+ {
239
+ return str_replace(self::$delimsPct, self::$delims, $string);
240
+ }
241
+ }
backend/vendor/guzzlehttp/guzzle/src/Url.php ADDED
@@ -0,0 +1,595 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Ring\Core;
5
+
6
+ /**
7
+ * Parses and generates URLs based on URL parts
8
+ */
9
+ class Url
10
+ {
11
+ private $scheme;
12
+ private $host;
13
+ private $port;
14
+ private $username;
15
+ private $password;
16
+ private $path = '';
17
+ private $fragment;
18
+ private static $defaultPorts = ['http' => 80, 'https' => 443, 'ftp' => 21];
19
+ private static $pathPattern = '/[^a-zA-Z0-9\-\._~!\$&\'\(\)\*\+,;=%:@\/]+|%(?![A-Fa-f0-9]{2})/';
20
+ private static $queryPattern = '/[^a-zA-Z0-9\-\._~!\$\'\(\)\*\+,;%:@\/\?=&]+|%(?![A-Fa-f0-9]{2})/';
21
+ /** @var Query|string Query part of the URL */
22
+ private $query;
23
+
24
+ /**
25
+ * Factory method to create a new URL from a URL string
26
+ *
27
+ * @param string $url Full URL used to create a Url object
28
+ *
29
+ * @return Url
30
+ * @throws \InvalidArgumentException
31
+ */
32
+ public static function fromString($url)
33
+ {
34
+ static $defaults = ['scheme' => null, 'host' => null,
35
+ 'path' => null, 'port' => null, 'query' => null,
36
+ 'user' => null, 'pass' => null, 'fragment' => null];
37
+
38
+ if (false === ($parts = parse_url($url))) {
39
+ throw new \InvalidArgumentException('Unable to parse malformed '
40
+ . 'url: ' . $url);
41
+ }
42
+
43
+ $parts += $defaults;
44
+
45
+ // Convert the query string into a Query object
46
+ if ($parts['query'] || 0 !== strlen($parts['query'])) {
47
+ $parts['query'] = Query::fromString($parts['query']);
48
+ }
49
+
50
+ return new static($parts['scheme'], $parts['host'], $parts['user'],
51
+ $parts['pass'], $parts['port'], $parts['path'], $parts['query'],
52
+ $parts['fragment']);
53
+ }
54
+
55
+ /**
56
+ * Build a URL from parse_url parts. The generated URL will be a relative
57
+ * URL if a scheme or host are not provided.
58
+ *
59
+ * @param array $parts Array of parse_url parts
60
+ *
61
+ * @return string
62
+ */
63
+ public static function buildUrl(array $parts)
64
+ {
65
+ $url = $scheme = '';
66
+
67
+ if (!empty($parts['scheme'])) {
68
+ $scheme = $parts['scheme'];
69
+ $url .= $scheme . ':';
70
+ }
71
+
72
+ if (!empty($parts['host'])) {
73
+ $url .= '//';
74
+ if (isset($parts['user'])) {
75
+ $url .= $parts['user'];
76
+ if (isset($parts['pass'])) {
77
+ $url .= ':' . $parts['pass'];
78
+ }
79
+ $url .= '@';
80
+ }
81
+
82
+ $url .= $parts['host'];
83
+
84
+ // Only include the port if it is not the default port of the scheme
85
+ if (isset($parts['port']) &&
86
+ (!isset(self::$defaultPorts[$scheme]) ||
87
+ $parts['port'] != self::$defaultPorts[$scheme])
88
+ ) {
89
+ $url .= ':' . $parts['port'];
90
+ }
91
+ }
92
+
93
+ // Add the path component if present
94
+ if (isset($parts['path']) && strlen($parts['path'])) {
95
+ // Always ensure that the path begins with '/' if set and something
96
+ // is before the path
97
+ if (!empty($parts['host']) && $parts['path'][0] != '/') {
98
+ $url .= '/';
99
+ }
100
+ $url .= $parts['path'];
101
+ }
102
+
103
+ // Add the query string if present
104
+ if (isset($parts['query'])) {
105
+ $queryStr = (string) $parts['query'];
106
+ if ($queryStr || $queryStr === '0') {
107
+ $url .= '?' . $queryStr;
108
+ }
109
+ }
110
+
111
+ // Ensure that # is only added to the url if fragment contains anything.
112
+ if (isset($parts['fragment'])) {
113
+ $url .= '#' . $parts['fragment'];
114
+ }
115
+
116
+ return $url;
117
+ }
118
+
119
+ /**
120
+ * Create a new URL from URL parts
121
+ *
122
+ * @param string $scheme Scheme of the URL
123
+ * @param string $host Host of the URL
124
+ * @param string $username Username of the URL
125
+ * @param string $password Password of the URL
126
+ * @param int $port Port of the URL
127
+ * @param string $path Path of the URL
128
+ * @param Query|array|string $query Query string of the URL
129
+ * @param string $fragment Fragment of the URL
130
+ */
131
+ public function __construct(
132
+ $scheme,
133
+ $host,
134
+ $username = null,
135
+ $password = null,
136
+ $port = null,
137
+ $path = null,
138
+ $query = null,
139
+ $fragment = null
140
+ ) {
141
+ $this->scheme = $scheme;
142
+ $this->host = $host;
143
+ $this->port = $port;
144
+ $this->username = $username;
145
+ $this->password = $password;
146
+ $this->fragment = $fragment;
147
+
148
+ if ($query) {
149
+ $this->setQuery($query);
150
+ }
151
+
152
+ $this->setPath($path);
153
+ }
154
+
155
+ /**
156
+ * Clone the URL
157
+ */
158
+ public function __clone()
159
+ {
160
+ if ($this->query instanceof Query) {
161
+ $this->query = clone $this->query;
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Returns the URL as a URL string
167
+ *
168
+ * @return string
169
+ */
170
+ public function __toString()
171
+ {
172
+ return static::buildUrl($this->getParts());
173
+ }
174
+
175
+ /**
176
+ * Get the parts of the URL as an array
177
+ *
178
+ * @return array
179
+ */
180
+ public function getParts()
181
+ {
182
+ return array(
183
+ 'scheme' => $this->scheme,
184
+ 'user' => $this->username,
185
+ 'pass' => $this->password,
186
+ 'host' => $this->host,
187
+ 'port' => $this->port,
188
+ 'path' => $this->path,
189
+ 'query' => $this->query,
190
+ 'fragment' => $this->fragment,
191
+ );
192
+ }
193
+
194
+ /**
195
+ * Set the host of the request.
196
+ *
197
+ * @param string $host Host to set (e.g. www.yahoo.com, yahoo.com)
198
+ *
199
+ * @return Url
200
+ */
201
+ public function setHost($host)
202
+ {
203
+ if (strpos($host, ':') === false) {
204
+ $this->host = $host;
205
+ } else {
206
+ list($host, $port) = explode(':', $host);
207
+ $this->host = $host;
208
+ $this->setPort($port);
209
+ }
210
+ }
211
+
212
+ /**
213
+ * Get the host part of the URL
214
+ *
215
+ * @return string
216
+ */
217
+ public function getHost()
218
+ {
219
+ return $this->host;
220
+ }
221
+
222
+ /**
223
+ * Set the scheme part of the URL (http, https, ftp, etc.)
224
+ *
225
+ * @param string $scheme Scheme to set
226
+ */
227
+ public function setScheme($scheme)
228
+ {
229
+ // Remove the default port if one is specified
230
+ if ($this->port
231
+ && isset(self::$defaultPorts[$this->scheme])
232
+ && self::$defaultPorts[$this->scheme] == $this->port
233
+ ) {
234
+ $this->port = null;
235
+ }
236
+
237
+ $this->scheme = $scheme;
238
+ }
239
+
240
+ /**
241
+ * Get the scheme part of the URL
242
+ *
243
+ * @return string
244
+ */
245
+ public function getScheme()
246
+ {
247
+ return $this->scheme;
248
+ }
249
+
250
+ /**
251
+ * Set the port part of the URL
252
+ *
253
+ * @param int $port Port to set
254
+ */
255
+ public function setPort($port)
256
+ {
257
+ $this->port = $port;
258
+ }
259
+
260
+ /**
261
+ * Get the port part of the URl.
262
+ *
263
+ * If no port was set, this method will return the default port for the
264
+ * scheme of the URI.
265
+ *
266
+ * @return int|null
267
+ */
268
+ public function getPort()
269
+ {
270
+ if ($this->port) {
271
+ return $this->port;
272
+ } elseif (isset(self::$defaultPorts[$this->scheme])) {
273
+ return self::$defaultPorts[$this->scheme];
274
+ }
275
+
276
+ return null;
277
+ }
278
+
279
+ /**
280
+ * Set the path part of the URL.
281
+ *
282
+ * The provided URL is URL encoded as necessary.
283
+ *
284
+ * @param string $path Path string to set
285
+ */
286
+ public function setPath($path)
287
+ {
288
+ $this->path = self::encodePath($path);
289
+ }
290
+
291
+ /**
292
+ * Removes dot segments from a URL
293
+ * @link http://tools.ietf.org/html/rfc3986#section-5.2.4
294
+ */
295
+ public function removeDotSegments()
296
+ {
297
+ static $noopPaths = ['' => true, '/' => true, '*' => true];
298
+ static $ignoreSegments = ['.' => true, '..' => true];
299
+
300
+ if (isset($noopPaths[$this->path])) {
301
+ return;
302
+ }
303
+
304
+ $results = [];
305
+ $segments = $this->getPathSegments();
306
+ foreach ($segments as $segment) {
307
+ if ($segment == '..') {
308
+ array_pop($results);
309
+ } elseif (!isset($ignoreSegments[$segment])) {
310
+ $results[] = $segment;
311
+ }
312
+ }
313
+
314
+ $newPath = implode('/', $results);
315
+
316
+ // Add the leading slash if necessary
317
+ if (substr($this->path, 0, 1) === '/' &&
318
+ substr($newPath, 0, 1) !== '/'
319
+ ) {
320
+ $newPath = '/' . $newPath;
321
+ }
322
+
323
+ // Add the trailing slash if necessary
324
+ if ($newPath != '/' && isset($ignoreSegments[end($segments)])) {
325
+ $newPath .= '/';
326
+ }
327
+
328
+ $this->path = $newPath;
329
+ }
330
+
331
+ /**
332
+ * Add a relative path to the currently set path.
333
+ *
334
+ * @param string $relativePath Relative path to add
335
+ */
336
+ public function addPath($relativePath)
337
+ {
338
+ if ($relativePath != '/' &&
339
+ is_string($relativePath) &&
340
+ strlen($relativePath) > 0
341
+ ) {
342
+ // Add a leading slash if needed
343
+ if ($relativePath[0] !== '/' &&
344
+ substr($this->path, -1, 1) !== '/'
345
+ ) {
346
+ $relativePath = '/' . $relativePath;
347
+ }
348
+
349
+ $this->setPath($this->path . $relativePath);
350
+ }
351
+ }
352
+
353
+ /**
354
+ * Get the path part of the URL
355
+ *
356
+ * @return string
357
+ */
358
+ public function getPath()
359
+ {
360
+ return $this->path;
361
+ }
362
+
363
+ /**
364
+ * Get the path segments of the URL as an array
365
+ *
366
+ * @return array
367
+ */
368
+ public function getPathSegments()
369
+ {
370
+ return explode('/', $this->path);
371
+ }
372
+
373
+ /**
374
+ * Set the password part of the URL
375
+ *
376
+ * @param string $password Password to set
377
+ */
378
+ public function setPassword($password)
379
+ {
380
+ $this->password = $password;
381
+ }
382
+
383
+ /**
384
+ * Get the password part of the URL
385
+ *
386
+ * @return null|string
387
+ */
388
+ public function getPassword()
389
+ {
390
+ return $this->password;
391
+ }
392
+
393
+ /**
394
+ * Set the username part of the URL
395
+ *
396
+ * @param string $username Username to set
397
+ */
398
+ public function setUsername($username)
399
+ {
400
+ $this->username = $username;
401
+ }
402
+
403
+ /**
404
+ * Get the username part of the URl
405
+ *
406
+ * @return null|string
407
+ */
408
+ public function getUsername()
409
+ {
410
+ return $this->username;
411
+ }
412
+
413
+ /**
414
+ * Get the query part of the URL as a Query object
415
+ *
416
+ * @return Query
417
+ */
418
+ public function getQuery()
419
+ {
420
+ // Convert the query string to a query object if not already done.
421
+ if (!$this->query instanceof Query) {
422
+ $this->query = $this->query === null
423
+ ? new Query()
424
+ : Query::fromString($this->query);
425
+ }
426
+
427
+ return $this->query;
428
+ }
429
+
430
+ /**
431
+ * Set the query part of the URL.
432
+ *
433
+ * You may provide a query string as a string and pass $rawString as true
434
+ * to provide a query string that is not parsed until a call to getQuery()
435
+ * is made. Setting a raw query string will still encode invalid characters
436
+ * in a query string.
437
+ *
438
+ * @param Query|string|array $query Query string value to set. Can
439
+ * be a string that will be parsed into a Query object, an array
440
+ * of key value pairs, or a Query object.
441
+ * @param bool $rawString Set to true when providing a raw query string.
442
+ *
443
+ * @throws \InvalidArgumentException
444
+ */
445
+ public function setQuery($query, $rawString = false)
446
+ {
447
+ if ($query instanceof Query) {
448
+ $this->query = $query;
449
+ } elseif (is_string($query)) {
450
+ if (!$rawString) {
451
+ $this->query = Query::fromString($query);
452
+ } else {
453
+ // Ensure the query does not have illegal characters.
454
+ $this->query = preg_replace_callback(
455
+ self::$queryPattern,
456
+ [__CLASS__, 'encodeMatch'],
457
+ $query
458
+ );
459
+ }
460
+
461
+ } elseif (is_array($query)) {
462
+ $this->query = new Query($query);
463
+ } else {
464
+ throw new \InvalidArgumentException('Query must be a Query, '
465
+ . 'array, or string. Got ' . Core::describeType($query));
466
+ }
467
+ }
468
+
469
+ /**
470
+ * Get the fragment part of the URL
471
+ *
472
+ * @return null|string
473
+ */
474
+ public function getFragment()
475
+ {
476
+ return $this->fragment;
477
+ }
478
+
479
+ /**
480
+ * Set the fragment part of the URL
481
+ *
482
+ * @param string $fragment Fragment to set
483
+ */
484
+ public function setFragment($fragment)
485
+ {
486
+ $this->fragment = $fragment;
487
+ }
488
+
489
+ /**
490
+ * Check if this is an absolute URL
491
+ *
492
+ * @return bool
493
+ */
494
+ public function isAbsolute()
495
+ {
496
+ return $this->scheme && $this->host;
497
+ }
498
+
499
+ /**
500
+ * Combine the URL with another URL and return a new URL instance.
501
+ *
502
+ * Follows the rules specific in RFC 3986 section 5.4.
503
+ *
504
+ * @param string $url Relative URL to combine with
505
+ *
506
+ * @return Url
507
+ * @throws \InvalidArgumentException
508
+ * @link http://tools.ietf.org/html/rfc3986#section-5.4
509
+ */
510
+ public function combine($url)
511
+ {
512
+ $url = static::fromString($url);
513
+
514
+ // Use the more absolute URL as the base URL
515
+ if (!$this->isAbsolute() && $url->isAbsolute()) {
516
+ $url = $url->combine($this);
517
+ }
518
+
519
+ $parts = $url->getParts();
520
+
521
+ // Passing a URL with a scheme overrides everything
522
+ if ($parts['scheme']) {
523
+ return clone $url;
524
+ }
525
+
526
+ // Setting a host overrides the entire rest of the URL
527
+ if ($parts['host']) {
528
+ return new static(
529
+ $this->scheme,
530
+ $parts['host'],
531
+ $parts['user'],
532
+ $parts['pass'],
533
+ $parts['port'],
534
+ $parts['path'],
535
+ $parts['query'] instanceof Query
536
+ ? clone $parts['query']
537
+ : $parts['query'],
538
+ $parts['fragment']
539
+ );
540
+ }
541
+
542
+ if (!$parts['path'] && $parts['path'] !== '0') {
543
+ // The relative URL has no path, so check if it is just a query
544
+ $path = $this->path ?: '';
545
+ $query = $parts['query'] ?: $this->query;
546
+ } else {
547
+ $query = $parts['query'];
548
+ if ($parts['path'][0] == '/' || !$this->path) {
549
+ // Overwrite the existing path if the rel path starts with "/"
550
+ $path = $parts['path'];
551
+ } else {
552
+ // If the relative URL does not have a path or the base URL
553
+ // path does not end in a "/" then overwrite the existing path
554
+ // up to the last "/"
555
+ $path = substr($this->path, 0, strrpos($this->path, '/') + 1) . $parts['path'];
556
+ }
557
+ }
558
+
559
+ $result = new self(
560
+ $this->scheme,
561
+ $this->host,
562
+ $this->username,
563
+ $this->password,
564
+ $this->port,
565
+ $path,
566
+ $query instanceof Query ? clone $query : $query,
567
+ $parts['fragment']
568
+ );
569
+
570
+ if ($path) {
571
+ $result->removeDotSegments();
572
+ }
573
+
574
+ return $result;
575
+ }
576
+
577
+ /**
578
+ * Encodes the path part of a URL without double-encoding percent-encoded
579
+ * key value pairs.
580
+ *
581
+ * @param string $path Path to encode
582
+ *
583
+ * @return string
584
+ */
585
+ public static function encodePath($path)
586
+ {
587
+ static $cb = [__CLASS__, 'encodeMatch'];
588
+ return preg_replace_callback(self::$pathPattern, $cb, $path);
589
+ }
590
+
591
+ private static function encodeMatch(array $match)
592
+ {
593
+ return rawurlencode($match[0]);
594
+ }
595
+ }
backend/vendor/guzzlehttp/guzzle/src/Utils.php ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ /**
5
+ * Utility methods used throughout Guzzle.
6
+ */
7
+ final class Utils
8
+ {
9
+ /**
10
+ * Gets a value from an array using a path syntax to retrieve nested data.
11
+ *
12
+ * This method does not allow for keys that contain "/". You must traverse
13
+ * the array manually or using something more advanced like JMESPath to
14
+ * work with keys that contain "/".
15
+ *
16
+ * // Get the bar key of a set of nested arrays.
17
+ * // This is equivalent to $collection['foo']['baz']['bar'] but won't
18
+ * // throw warnings for missing keys.
19
+ * GuzzleHttp\get_path($data, 'foo/baz/bar');
20
+ *
21
+ * @param array $data Data to retrieve values from
22
+ * @param string $path Path to traverse and retrieve a value from
23
+ *
24
+ * @return mixed|null
25
+ */
26
+ public static function getPath($data, $path)
27
+ {
28
+ $path = explode('/', $path);
29
+
30
+ while (null !== ($part = array_shift($path))) {
31
+ if (!is_array($data) || !isset($data[$part])) {
32
+ return null;
33
+ }
34
+ $data = $data[$part];
35
+ }
36
+
37
+ return $data;
38
+ }
39
+
40
+ /**
41
+ * Set a value in a nested array key. Keys will be created as needed to set
42
+ * the value.
43
+ *
44
+ * This function does not support keys that contain "/" or "[]" characters
45
+ * because these are special tokens used when traversing the data structure.
46
+ * A value may be prepended to an existing array by using "[]" as the final
47
+ * key of a path.
48
+ *
49
+ * GuzzleHttp\get_path($data, 'foo/baz'); // null
50
+ * GuzzleHttp\set_path($data, 'foo/baz/[]', 'a');
51
+ * GuzzleHttp\set_path($data, 'foo/baz/[]', 'b');
52
+ * GuzzleHttp\get_path($data, 'foo/baz');
53
+ * // Returns ['a', 'b']
54
+ *
55
+ * @param array $data Data to modify by reference
56
+ * @param string $path Path to set
57
+ * @param mixed $value Value to set at the key
58
+ *
59
+ * @throws \RuntimeException when trying to setPath using a nested path
60
+ * that travels through a scalar value.
61
+ */
62
+ public static function setPath(&$data, $path, $value)
63
+ {
64
+ $current =& $data;
65
+ $queue = explode('/', $path);
66
+ while (null !== ($key = array_shift($queue))) {
67
+ if (!is_array($current)) {
68
+ throw new \RuntimeException("Trying to setPath {$path}, but "
69
+ . "{$key} is set and is not an array");
70
+ } elseif (!$queue) {
71
+ if ($key == '[]') {
72
+ $current[] = $value;
73
+ } else {
74
+ $current[$key] = $value;
75
+ }
76
+ } elseif (isset($current[$key])) {
77
+ $current =& $current[$key];
78
+ } else {
79
+ $current[$key] = [];
80
+ $current =& $current[$key];
81
+ }
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Expands a URI template
87
+ *
88
+ * @param string $template URI template
89
+ * @param array $variables Template variables
90
+ *
91
+ * @return string
92
+ */
93
+ public static function uriTemplate($template, array $variables)
94
+ {
95
+ if (function_exists('\\uri_template')) {
96
+ return \uri_template($template, $variables);
97
+ }
98
+
99
+ static $uriTemplate;
100
+ if (!$uriTemplate) {
101
+ $uriTemplate = new UriTemplate();
102
+ }
103
+
104
+ return $uriTemplate->expand($template, $variables);
105
+ }
106
+
107
+ /**
108
+ * Wrapper for JSON decode that implements error detection with helpful
109
+ * error messages.
110
+ *
111
+ * @param string $json JSON data to parse
112
+ * @param bool $assoc When true, returned objects will be converted
113
+ * into associative arrays.
114
+ * @param int $depth User specified recursion depth.
115
+ * @param int $options Bitmask of JSON decode options.
116
+ *
117
+ * @return mixed
118
+ * @throws \InvalidArgumentException if the JSON cannot be parsed.
119
+ * @link http://www.php.net/manual/en/function.json-decode.php
120
+ */
121
+ public static function jsonDecode($json, $assoc = false, $depth = 512, $options = 0)
122
+ {
123
+ static $jsonErrors = [
124
+ JSON_ERROR_DEPTH => 'JSON_ERROR_DEPTH - Maximum stack depth exceeded',
125
+ JSON_ERROR_STATE_MISMATCH => 'JSON_ERROR_STATE_MISMATCH - Underflow or the modes mismatch',
126
+ JSON_ERROR_CTRL_CHAR => 'JSON_ERROR_CTRL_CHAR - Unexpected control character found',
127
+ JSON_ERROR_SYNTAX => 'JSON_ERROR_SYNTAX - Syntax error, malformed JSON',
128
+ JSON_ERROR_UTF8 => 'JSON_ERROR_UTF8 - Malformed UTF-8 characters, possibly incorrectly encoded'
129
+ ];
130
+
131
+ $data = \json_decode($json, $assoc, $depth, $options);
132
+
133
+ if (JSON_ERROR_NONE !== json_last_error()) {
134
+ $last = json_last_error();
135
+ throw new \InvalidArgumentException(
136
+ 'Unable to parse JSON data: '
137
+ . (isset($jsonErrors[$last])
138
+ ? $jsonErrors[$last]
139
+ : 'Unknown error')
140
+ );
141
+ }
142
+
143
+ return $data;
144
+ }
145
+ }
backend/vendor/guzzlehttp/ringphp/.gitignore ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ vendor
2
+ build/artifacts/
3
+ composer.lock
4
+ docs/_build/
backend/vendor/guzzlehttp/ringphp/.travis.yml ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ language: php
2
+
3
+ php:
4
+ - 5.4
5
+ - 5.5
6
+ - 5.6
7
+ - hhvm
8
+
9
+ before_script:
10
+ - composer self-update
11
+ - composer install --no-interaction --prefer-source --dev
12
+ - ~/.nvm/nvm.sh install v0.6.14
13
+ - ~/.nvm/nvm.sh run v0.6.14
14
+
15
+ script:
16
+ - make test
17
+
18
+ matrix:
19
+ allow_failures:
20
+ - php: hhvm
21
+ fast_finish: true
backend/vendor/guzzlehttp/ringphp/CHANGELOG.md ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CHANGELOG
2
+
3
+ ## 1.0.5 - 2014-12-10
4
+
5
+ * Adding more error information to PHP stream wrapper exceptions.
6
+ * Added digest auth integration test support to test server.
7
+
8
+ ## 1.0.4 - 2014-12-01
9
+
10
+ * Added support for older versions of cURL that do not have CURLOPT_TIMEOUT_MS.
11
+ * Setting debug to `false` does not enable debug output.
12
+ * Added a fix to the StreamHandler to return a `FutureArrayInterface` when an
13
+ error occurs.
14
+
15
+ ## 1.0.3 - 2014-11-03
16
+
17
+ * Setting the `header` stream option as a string to be compatible with GAE.
18
+ * Header parsing now ensures that header order is maintained in the parsed
19
+ message.
20
+
21
+ ## 1.0.2 - 2014-10-28
22
+
23
+ * Now correctly honoring a `version` option is supplied in a request.
24
+ See https://github.com/guzzle/RingPHP/pull/8
25
+
26
+ ## 1.0.1 - 2014-10-26
27
+
28
+ * Fixed a header parsing issue with the `CurlHandler` and `CurlMultiHandler`
29
+ that caused cURL requests with multiple responses to merge repsonses together
30
+ (e.g., requests with digest authentication).
31
+
32
+ ## 1.0.0 - 2014-10-12
33
+
34
+ * Initial release.
backend/vendor/guzzlehttp/ringphp/LICENSE ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright (c) 2014 Michael Dowling, https://github.com/mtdowling <mtdowling@gmail.com>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
backend/vendor/guzzlehttp/ringphp/Makefile ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ all: clean coverage docs
2
+
3
+ docs:
4
+ cd docs && make html
5
+
6
+ view-docs:
7
+ open docs/_build/html/index.html
8
+
9
+ start-server: stop-server
10
+ node tests/Client/server.js &> /dev/null &
11
+
12
+ stop-server:
13
+ @PID=$(shell ps axo pid,command \
14
+ | grep 'tests/Client/server.js' \
15
+ | grep -v grep \
16
+ | cut -f 1 -d " "\
17
+ ) && [ -n "$$PID" ] && kill $$PID || true
18
+
19
+ test: start-server
20
+ vendor/bin/phpunit $(TEST)
21
+ $(MAKE) stop-server
22
+
23
+ coverage: start-server
24
+ vendor/bin/phpunit --coverage-html=build/artifacts/coverage $(TEST)
25
+ $(MAKE) stop-server
26
+
27
+ view-coverage:
28
+ open build/artifacts/coverage/index.html
29
+
30
+ clean:
31
+ rm -rf build/artifacts/*
32
+ cd docs && make clean
33
+
34
+ tag:
35
+ $(if $(TAG),,$(error TAG is not defined. Pass via "make tag TAG=4.2.1"))
36
+ @echo Tagging $(TAG)
37
+ chag update -m '$(TAG) ()'
38
+ git add -A
39
+ git commit -m '$(TAG) release'
40
+ chag tag
41
+
42
+ perf: start-server
43
+ php tests/perf.php
44
+ $(MAKE) stop-server
45
+
46
+ .PHONY: docs
backend/vendor/guzzlehttp/ringphp/README.rst ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ =======
2
+ RingPHP
3
+ =======
4
+
5
+ Provides a simple API and specification that abstracts away the details of HTTP
6
+ into a single PHP function. RingPHP be used to power HTTP clients and servers
7
+ through a PHP function that accepts a request hash and returns a response hash
8
+ that is fulfilled using a `promise <https://github.com/reactphp/promise>`_,
9
+ allowing RingPHP to support both synchronous and asynchronous workflows.
10
+
11
+ By abstracting the implementation details of different HTTP clients and
12
+ servers, RingPHP allows you to utilize pluggable HTTP clients and servers
13
+ without tying your application to a specific implementation.
14
+
15
+ .. code-block:: php
16
+
17
+ <?php
18
+ require 'vendor/autoload.php';
19
+
20
+ use GuzzleHttp\Ring\Client\CurlHandler;
21
+
22
+ $handler = new CurlHandler();
23
+ $response = $handler([
24
+ 'http_method' => 'GET',
25
+ 'uri' => '/',
26
+ 'headers' => [
27
+ 'host' => ['www.google.com'],
28
+ 'x-foo' => ['baz']
29
+ ]
30
+ ]);
31
+
32
+ $response->then(function (array $response) {
33
+ echo $response['status'];
34
+ });
35
+
36
+ $response->wait();
37
+
38
+ RingPHP is inspired by Clojure's `Ring <https://github.com/ring-clojure/ring>`_,
39
+ which, in turn, was inspired by Python's WSGI and Ruby's Rack. RingPHP is
40
+ utilized as the handler layer in `Guzzle <http://guzzlephp.org>`_ 5.0+ to send
41
+ HTTP requests.
42
+
43
+ Documentation
44
+ -------------
45
+
46
+ See http://ringphp.readthedocs.org/ for the full online documentation.
backend/vendor/guzzlehttp/ringphp/composer.json ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "guzzlehttp/ringphp",
3
+ "license": "MIT",
4
+ "authors": [
5
+ {
6
+ "name": "Michael Dowling",
7
+ "email": "mtdowling@gmail.com",
8
+ "homepage": "https://github.com/mtdowling"
9
+ }
10
+ ],
11
+ "require": {
12
+ "php": ">=5.4.0",
13
+ "guzzlehttp/streams": "~3.0",
14
+ "react/promise": "~2.0"
15
+ },
16
+ "require-dev": {
17
+ "ext-curl": "*",
18
+ "phpunit/phpunit": "~4.0"
19
+ },
20
+ "suggest": {
21
+ "ext-curl": "Guzzle will use specific adapters if cURL is present"
22
+ },
23
+ "autoload": {
24
+ "psr-4": {
25
+ "GuzzleHttp\\Ring\\": "src/"
26
+ }
27
+ },
28
+ "autoload-dev": {
29
+ "psr-4": {
30
+ "GuzzleHttp\\Tests\\Ring\\": "tests/"
31
+ }
32
+ },
33
+ "extra": {
34
+ "branch-alias": {
35
+ "dev-master": "1.0-dev"
36
+ }
37
+ }
38
+ }
backend/vendor/guzzlehttp/ringphp/docs/Makefile ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Makefile for Sphinx documentation
2
+ #
3
+
4
+ # You can set these variables from the command line.
5
+ SPHINXOPTS =
6
+ SPHINXBUILD = sphinx-build
7
+ PAPER =
8
+ BUILDDIR = _build
9
+
10
+ # Internal variables.
11
+ PAPEROPT_a4 = -D latex_paper_size=a4
12
+ PAPEROPT_letter = -D latex_paper_size=letter
13
+ ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
14
+ # the i18n builder cannot share the environment and doctrees with the others
15
+ I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
16
+
17
+ .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
18
+
19
+ help:
20
+ @echo "Please use \`make <target>' where <target> is one of"
21
+ @echo " html to make standalone HTML files"
22
+ @echo " dirhtml to make HTML files named index.html in directories"
23
+ @echo " singlehtml to make a single large HTML file"
24
+ @echo " pickle to make pickle files"
25
+ @echo " json to make JSON files"
26
+ @echo " htmlhelp to make HTML files and a HTML help project"
27
+ @echo " qthelp to make HTML files and a qthelp project"
28
+ @echo " devhelp to make HTML files and a Devhelp project"
29
+ @echo " epub to make an epub"
30
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
31
+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
32
+ @echo " text to make text files"
33
+ @echo " man to make manual pages"
34
+ @echo " texinfo to make Texinfo files"
35
+ @echo " info to make Texinfo files and run them through makeinfo"
36
+ @echo " gettext to make PO message catalogs"
37
+ @echo " changes to make an overview of all changed/added/deprecated items"
38
+ @echo " linkcheck to check all external links for integrity"
39
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
40
+
41
+ clean:
42
+ -rm -rf $(BUILDDIR)/*
43
+
44
+ html:
45
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
46
+ @echo
47
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
48
+
49
+ dirhtml:
50
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
51
+ @echo
52
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
53
+
54
+ singlehtml:
55
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
56
+ @echo
57
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
58
+
59
+ pickle:
60
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
61
+ @echo
62
+ @echo "Build finished; now you can process the pickle files."
63
+
64
+ json:
65
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
66
+ @echo
67
+ @echo "Build finished; now you can process the JSON files."
68
+
69
+ htmlhelp:
70
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
71
+ @echo
72
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
73
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
74
+
75
+ qthelp:
76
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
77
+ @echo
78
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
79
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
80
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/GuzzleRing.qhcp"
81
+ @echo "To view the help file:"
82
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/GuzzleRing.qhc"
83
+
84
+ devhelp:
85
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
86
+ @echo
87
+ @echo "Build finished."
88
+ @echo "To view the help file:"
89
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/GuzzleRing"
90
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/GuzzleRing"
91
+ @echo "# devhelp"
92
+
93
+ epub:
94
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
95
+ @echo
96
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
97
+
98
+ latex:
99
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
100
+ @echo
101
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
102
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
103
+ "(use \`make latexpdf' here to do that automatically)."
104
+
105
+ latexpdf:
106
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
107
+ @echo "Running LaTeX files through pdflatex..."
108
+ $(MAKE) -C $(BUILDDIR)/latex all-pdf
109
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
110
+
111
+ text:
112
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
113
+ @echo
114
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
115
+
116
+ man:
117
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
118
+ @echo
119
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
120
+
121
+ texinfo:
122
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
123
+ @echo
124
+ @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
125
+ @echo "Run \`make' in that directory to run these through makeinfo" \
126
+ "(use \`make info' here to do that automatically)."
127
+
128
+ info:
129
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
130
+ @echo "Running Texinfo files through makeinfo..."
131
+ make -C $(BUILDDIR)/texinfo info
132
+ @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
133
+
134
+ gettext:
135
+ $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
136
+ @echo
137
+ @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
138
+
139
+ changes:
140
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
141
+ @echo
142
+ @echo "The overview file is in $(BUILDDIR)/changes."
143
+
144
+ linkcheck:
145
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
146
+ @echo
147
+ @echo "Link check complete; look for any errors in the above output " \
148
+ "or in $(BUILDDIR)/linkcheck/output.txt."
149
+
150
+ doctest:
151
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
152
+ @echo "Testing of doctests in the sources finished, look at the " \
153
+ "results in $(BUILDDIR)/doctest/output.txt."
backend/vendor/guzzlehttp/ringphp/docs/client_handlers.rst ADDED
@@ -0,0 +1,173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ===============
2
+ Client Handlers
3
+ ===============
4
+
5
+ Client handlers accept a request array and return a future response array that
6
+ can be used synchronously as an array or asynchronously using a promise.
7
+
8
+ Built-In Handlers
9
+ -----------------
10
+
11
+ RingPHP comes with three built-in client handlers.
12
+
13
+ Stream Handler
14
+ ~~~~~~~~~~~~~~
15
+
16
+ The ``GuzzleHttp\Ring\Client\StreamHandler`` uses PHP's
17
+ `http stream wrapper <http://php.net/manual/en/wrappers.http.php>`_ to send
18
+ requests.
19
+
20
+ .. note::
21
+
22
+ This handler cannot send requests concurrently.
23
+
24
+ You can provide an associative array of custom stream context options to the
25
+ StreamHandler using the ``stream_context`` key of the ``client`` request
26
+ option.
27
+
28
+ .. code-block:: php
29
+
30
+ use GuzzleHttp\Ring\Client\StreamHandler;
31
+
32
+ $response = $handler([
33
+ 'http_method' => 'GET',
34
+ 'uri' => '/',
35
+ 'headers' => ['host' => ['httpbin.org']],
36
+ 'client' => [
37
+ 'stream_context' => [
38
+ 'http' => [
39
+ 'request_fulluri' => true,
40
+ 'method' => 'HEAD'
41
+ ],
42
+ 'socket' => [
43
+ 'bindto' => '127.0.0.1:0'
44
+ ],
45
+ 'ssl' => [
46
+ 'verify_peer' => false
47
+ ]
48
+ ]
49
+ ]
50
+ ]);
51
+
52
+ // Even though it's already completed, you can still use a promise
53
+ $response->then(function ($response) {
54
+ echo $response['status']; // 200
55
+ });
56
+
57
+ // Or access the response using the future interface
58
+ echo $response['status']; // 200
59
+
60
+ cURL Handler
61
+ ~~~~~~~~~~~~
62
+
63
+ The ``GuzzleHttp\Ring\Client\CurlHandler`` can be used with PHP 5.5+ to send
64
+ requests using cURL easy handles. This handler is great for sending requests
65
+ one at a time because the execute and select loop is implemented in C code
66
+ which executes faster and consumes less memory than using PHP's
67
+ ``curl_multi_*`` interface.
68
+
69
+ .. note::
70
+
71
+ This handler cannot send requests concurrently.
72
+
73
+ When using the CurlHandler, custom curl options can be specified as an
74
+ associative array of `cURL option constants <http://php.net/manual/en/curl.constants.php>`_
75
+ mapping to values in the ``client`` option of a requst using the **curl** key.
76
+
77
+ .. code-block:: php
78
+
79
+ use GuzzleHttp\Ring\Client\CurlHandler;
80
+
81
+ $handler = new CurlHandler();
82
+
83
+ $request = [
84
+ 'http_method' => 'GET',
85
+ 'headers' => ['host' => [Server::$host]],
86
+ 'client' => ['curl' => [CURLOPT_LOW_SPEED_LIMIT => 10]]
87
+ ];
88
+
89
+ $response = $handler($request);
90
+
91
+ // The response can be used directly as an array.
92
+ echo $response['status']; // 200
93
+
94
+ // Or, it can be used as a promise (that has already fulfilled).
95
+ $response->then(function ($response) {
96
+ echo $response['status']; // 200
97
+ });
98
+
99
+ cURL Multi Handler
100
+ ~~~~~~~~~~~~~~~~~~
101
+
102
+ The ``GuzzleHttp\Ring\Client\CurlMultiHandler`` transfers requests using
103
+ cURL's `multi API <http://curl.haxx.se/libcurl/c/libcurl-multi.html>`_. The
104
+ ``CurlMultiHandler`` is great for sending requests concurrently.
105
+
106
+ .. code-block:: php
107
+
108
+ use GuzzleHttp\Ring\Client\CurlMultiHandler;
109
+
110
+ $handler = new CurlMultiHandler();
111
+
112
+ $request = [
113
+ 'http_method' => 'GET',
114
+ 'headers' => ['host' => [Server::$host]]
115
+ ];
116
+
117
+ // this call returns a future array immediately.
118
+ $response = $handler($request);
119
+
120
+ // Ideally, you should use the promise API to not block.
121
+ $response
122
+ ->then(function ($response) {
123
+ // Got the response at some point in the future
124
+ echo $response['status']; // 200
125
+ // Don't break the chain
126
+ return $response;
127
+ })->then(function ($response) {
128
+ // ...
129
+ });
130
+
131
+ // If you really need to block, then you can use the response as an
132
+ // associative array. This will block until it has completed.
133
+ echo $response['status']; // 200
134
+
135
+ Just like the ``CurlHandler``, the ``CurlMultiHandler`` accepts custom curl
136
+ option in the ``curl`` key of the ``client`` request option.
137
+
138
+ Mock Handler
139
+ ~~~~~~~~~~~~
140
+
141
+ The ``GuzzleHttp\Ring\Client\MockHandler`` is used to return mock responses.
142
+ When constructed, the handler can be configured to return the same response
143
+ array over and over, a future response, or a the evaluation of a callback
144
+ function.
145
+
146
+ .. code-block:: php
147
+
148
+ use GuzzleHttp\Ring\Client\MockHandler;
149
+
150
+ // Return a canned response.
151
+ $mock = new MockHandler(['status' => 200]);
152
+ $response = $mock([]);
153
+ assert(200 == $response['status']);
154
+ assert([] == $response['headers']);
155
+
156
+ Implementing Handlers
157
+ ---------------------
158
+
159
+ Client handlers are just PHP callables (functions or classes that have the
160
+ ``__invoke`` magic method). The callable accepts a request array and MUST
161
+ return an instance of ``GuzzleHttp\Ring\Future\FutureArrayInterface`` so that
162
+ the response can be used by both blocking and non-blocking consumers.
163
+
164
+ Handlers need to follow a few simple rules:
165
+
166
+ 1. Do not throw exceptions. If an error is encountered, return an array that
167
+ contains the ``error`` key that maps to an ``\Exception`` value.
168
+ 2. If the request has a ``delay`` client option, then the handler should only
169
+ send the request after the specified delay time in seconds. Blocking
170
+ handlers may find it convenient to just let the
171
+ ``GuzzleHttp\Ring\Core::doSleep($request)`` function handle this for them.
172
+ 3. Always return an instance of ``GuzzleHttp\Ring\Future\FutureArrayInterface``.
173
+ 4. Complete any outstanding requests when the handler is destructed.
backend/vendor/guzzlehttp/ringphp/docs/client_middleware.rst ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ =================
2
+ Client Middleware
3
+ =================
4
+
5
+ Middleware intercepts requests before they are sent over the wire and can be
6
+ used to add functionality to handlers.
7
+
8
+ Modifying Requests
9
+ ------------------
10
+
11
+ Let's say you wanted to modify requests before they are sent over the wire
12
+ so that they always add specific headers. This can be accomplished by creating
13
+ a function that accepts a handler and returns a new function that adds the
14
+ composed behavior.
15
+
16
+ .. code-block:: php
17
+
18
+ use GuzzleHttp\Ring\Client\CurlHandler;
19
+
20
+ $handler = new CurlHandler();
21
+
22
+ $addHeaderHandler = function (callable $handler, array $headers = []) {
23
+ return function (array $request) use ($handler, $headers) {
24
+ // Add our custom headers
25
+ foreach ($headers as $key => $value) {
26
+ $request['headers'][$key] = $value;
27
+ }
28
+
29
+ // Send the request using the handler and return the response.
30
+ return $handler($request);
31
+ }
32
+ };
33
+
34
+ // Create a new handler that adds headers to each request.
35
+ $handler = $addHeaderHandler($handler, [
36
+ 'X-AddMe' => 'hello',
37
+ 'Authorization' => 'Basic xyz'
38
+ ]);
39
+
40
+ $response = $handler([
41
+ 'http_method' => 'GET',
42
+ 'headers' => ['Host' => ['httpbin.org']
43
+ ]);
44
+
45
+ Modifying Responses
46
+ -------------------
47
+
48
+ You can change a response as it's returned from a middleware. Remember that
49
+ responses returned from an handler (including middleware) must implement
50
+ ``GuzzleHttp\Ring\Future\FutureArrayInterface``. In order to be a good citizen,
51
+ you should not expect that the responses returned through your middleware will
52
+ be completed synchronously. Instead, you should use the
53
+ ``GuzzleHttp\Ring\Core::proxy()`` function to modify the response when the
54
+ underlying promise is resolved. This function is a helper function that makes it
55
+ easy to create a new instance of ``FutureArrayInterface`` that wraps an existing
56
+ ``FutureArrayInterface`` object.
57
+
58
+ Let's say you wanted to add headers to a response as they are returned from
59
+ your middleware, but you want to make sure you aren't causing future
60
+ responses to be dereferenced right away. You can achieve this by modifying the
61
+ incoming request and using the ``Core::proxy`` function.
62
+
63
+ .. code-block:: php
64
+
65
+ use GuzzleHttp\Ring\Core;
66
+ use GuzzleHttp\Ring\Client\CurlHandler;
67
+
68
+ $handler = new CurlHandler();
69
+
70
+ $responseHeaderHandler = function (callable $handler, array $headers) {
71
+ return function (array $request) use ($handler, $headers) {
72
+ // Send the request using the wrapped handler.
73
+ return Core::proxy($handler($request), function ($response) use ($headers) {
74
+ // Add the headers to the response when it is available.
75
+ foreach ($headers as $key => $value) {
76
+ $response['headers'][$key] = (array) $value;
77
+ }
78
+ // Note that you can return a regular response array when using
79
+ // the proxy method.
80
+ return $response;
81
+ });
82
+ }
83
+ };
84
+
85
+ // Create a new handler that adds headers to each response.
86
+ $handler = $responseHeaderHandler($handler, ['X-Header' => 'hello!']);
87
+
88
+ $response = $handler([
89
+ 'http_method' => 'GET',
90
+ 'headers' => ['Host' => ['httpbin.org']
91
+ ]);
92
+
93
+ assert($response['headers']['X-Header'] == 'hello!');
94
+
95
+ Built-In Middleware
96
+ -------------------
97
+
98
+ RingPHP comes with a few basic client middlewares that modify requests
99
+ and responses.
100
+
101
+ Streaming Middleware
102
+ ~~~~~~~~~~~~~~~~~~~~
103
+
104
+ If you want to send all requests with the ``streaming`` option to a specific
105
+ handler but other requests to a different handler, then use the streaming
106
+ middleware.
107
+
108
+ .. code-block:: php
109
+
110
+ use GuzzleHttp\Ring\Client\CurlHandler;
111
+ use GuzzleHttp\Ring\Client\StreamHandler;
112
+ use GuzzleHttp\Ring\Client\Middleware;
113
+
114
+ $defaultHandler = new CurlHandler();
115
+ $streamingHandler = new StreamHandler();
116
+ $streamingHandler = Middleware::wrapStreaming(
117
+ $defaultHandler,
118
+ $streamingHandler
119
+ );
120
+
121
+ // Send the request using the streaming handler.
122
+ $response = $streamingHandler([
123
+ 'http_method' => 'GET',
124
+ 'headers' => ['Host' => ['www.google.com'],
125
+ 'stream' => true
126
+ ]);
127
+
128
+ // Send the request using the default handler.
129
+ $response = $streamingHandler([
130
+ 'http_method' => 'GET',
131
+ 'headers' => ['Host' => ['www.google.com']
132
+ ]);
133
+
134
+ Future Middleware
135
+ ~~~~~~~~~~~~~~~~~
136
+
137
+ If you want to send all requests with the ``future`` option to a specific
138
+ handler but other requests to a different handler, then use the future
139
+ middleware.
140
+
141
+ .. code-block:: php
142
+
143
+ use GuzzleHttp\Ring\Client\CurlHandler;
144
+ use GuzzleHttp\Ring\Client\CurlMultiHandler;
145
+ use GuzzleHttp\Ring\Client\Middleware;
146
+
147
+ $defaultHandler = new CurlHandler();
148
+ $futureHandler = new CurlMultiHandler();
149
+ $futureHandler = Middleware::wrapFuture(
150
+ $defaultHandler,
151
+ $futureHandler
152
+ );
153
+
154
+ // Send the request using the blocking CurlHandler.
155
+ $response = $futureHandler([
156
+ 'http_method' => 'GET',
157
+ 'headers' => ['Host' => ['www.google.com']
158
+ ]);
159
+
160
+ // Send the request using the non-blocking CurlMultiHandler.
161
+ $response = $futureHandler([
162
+ 'http_method' => 'GET',
163
+ 'headers' => ['Host' => ['www.google.com'],
164
+ 'future' => true
165
+ ]);
backend/vendor/guzzlehttp/ringphp/docs/conf.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys, os
2
+ import sphinx_rtd_theme
3
+ from sphinx.highlighting import lexers
4
+ from pygments.lexers.web import PhpLexer
5
+
6
+
7
+ lexers['php'] = PhpLexer(startinline=True, linenos=1)
8
+ lexers['php-annotations'] = PhpLexer(startinline=True, linenos=1)
9
+ primary_domain = 'php'
10
+
11
+ extensions = []
12
+ templates_path = ['_templates']
13
+ source_suffix = '.rst'
14
+ master_doc = 'index'
15
+ project = u'RingPHP'
16
+ copyright = u'2014, Michael Dowling'
17
+ version = '1.0.0-alpha'
18
+ exclude_patterns = ['_build']
19
+
20
+ html_title = "RingPHP"
21
+ html_short_title = "RingPHP"
22
+ html_theme = "sphinx_rtd_theme"
23
+ html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
backend/vendor/guzzlehttp/ringphp/docs/futures.rst ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ =======
2
+ Futures
3
+ =======
4
+
5
+ Futures represent a computation that may have not yet completed. RingPHP
6
+ uses hybrid of futures and promises to provide a consistent API that can be
7
+ used for both blocking and non-blocking consumers.
8
+
9
+ Promises
10
+ --------
11
+
12
+ You can get the result of a future when it is ready using the promise interface
13
+ of a future. Futures expose a promise API via a ``then()`` method that utilizes
14
+ `React's promise library <https://github.com/reactphp/promise>`_. You should
15
+ use this API when you do not wish to block.
16
+
17
+ .. code-block:: php
18
+
19
+ use GuzzleHttp\Ring\Client\CurlMultiHandler;
20
+
21
+ $request = [
22
+ 'http_method' => 'GET',
23
+ 'uri' => '/',
24
+ 'headers' => ['host' => ['httpbin.org']]
25
+ ];
26
+
27
+ $response = $handler($request);
28
+
29
+ // Use the then() method to use the promise API of the future.
30
+ $response->then(function ($response) {
31
+ echo $response['status'];
32
+ });
33
+
34
+ You can get the promise used by a future, an instance of
35
+ ``React\Promise\PromiseInterface``, by calling the ``promise()`` method.
36
+
37
+ .. code-block:: php
38
+
39
+ $response = $handler($request);
40
+ $promise = $response->promise();
41
+ $promise->then(function ($response) {
42
+ echo $response['status'];
43
+ });
44
+
45
+ This promise value can be used with React's
46
+ `aggregate promise functions <https://github.com/reactphp/promise#functions>`_.
47
+
48
+ Waiting
49
+ -------
50
+
51
+ You can wait on a future to complete and retrieve the value, or *dereference*
52
+ the future, using the ``wait()`` method. Calling the ``wait()`` method of a
53
+ future will block until the result is available. The result is then returned or
54
+ an exception is thrown if and exception was encountered while waiting on the
55
+ the result. Subsequent calls to dereference a future will return the previously
56
+ completed result or throw the previously encountered exception. Futures can be
57
+ cancelled, which stops the computation if possible.
58
+
59
+ .. code-block:: php
60
+
61
+ use GuzzleHttp\Ring\Client\CurlMultiHandler;
62
+
63
+ $response = $handler([
64
+ 'http_method' => 'GET',
65
+ 'uri' => '/',
66
+ 'headers' => ['host' => ['httpbin.org']]
67
+ ]);
68
+
69
+ // You can explicitly call block to wait on a result.
70
+ $realizedResponse = $response->wait();
71
+
72
+ // Future responses can be used like a regular PHP array.
73
+ echo $response['status'];
74
+
75
+ In addition to explicitly calling the ``wait()`` function, using a future like
76
+ a normal value will implicitly trigger the ``wait()`` function.
77
+
78
+ Future Responses
79
+ ----------------
80
+
81
+ RingPHP uses futures to return asynchronous responses immediately. Client
82
+ handlers always return future responses that implement
83
+ ``GuzzleHttp\Ring\Future\ArrayFutureInterface``. These future responses act
84
+ just like normal PHP associative arrays for blocking access and provide a
85
+ promise interface for non-blocking access.
86
+
87
+ .. code-block:: php
88
+
89
+ use GuzzleHttp\Ring\Client\CurlMultiHandler;
90
+
91
+ $handler = new CurlMultiHandler();
92
+
93
+ $request = [
94
+ 'http_method' => 'GET',
95
+ 'uri' => '/',
96
+ 'headers' => ['Host' => ['www.google.com']]
97
+ ];
98
+
99
+ $response = $handler($request);
100
+
101
+ // Use the promise API for non-blocking access to the response. The actual
102
+ // response value will be delivered to the promise.
103
+ $response->then(function ($response) {
104
+ echo $response['status'];
105
+ });
106
+
107
+ // You can wait (block) until the future is completed.
108
+ $response->wait();
109
+
110
+ // This will implicitly call wait(), and will block too!
111
+ $response['status'];
112
+
113
+ .. important::
114
+
115
+ Futures that are not completed by the time the underlying handler is
116
+ destructed will be completed when the handler is shutting down.
117
+
118
+ Cancelling
119
+ ----------
120
+
121
+ Futures can be cancelled if they have not already been dereferenced.
122
+
123
+ RingPHP futures are typically implemented with the
124
+ ``GuzzleHttp\Ring\Future\BaseFutureTrait``. This trait provides the cancellation
125
+ functionality that should be common to most implementations. Cancelling a
126
+ future response will try to prevent the request from sending over the wire.
127
+
128
+ When a future is cancelled, the cancellation function is invoked and performs
129
+ the actual work needed to cancel the request from sending if possible
130
+ (e.g., telling an event loop to stop sending a request or to close a socket).
131
+ If no cancellation function is provided, then a request cannot be cancelled. If
132
+ a cancel function is provided, then it should accept the future as an argument
133
+ and return true if the future was successfully cancelled or false if it could
134
+ not be cancelled.
135
+
136
+ Wrapping an existing Promise
137
+ ----------------------------
138
+
139
+ You can easily create a future from any existing promise using the
140
+ ``GuzzleHttp\Ring\Future\FutureValue`` class. This class's constructor
141
+ accepts a promise as the first argument, a wait function as the second
142
+ argument, and a cancellation function as the third argument. The dereference
143
+ function is used to force the promise to resolve (for example, manually ticking
144
+ an event loop). The cancel function is optional and is used to tell the thing
145
+ that created the promise that it can stop computing the result (for example,
146
+ telling an event loop to stop transferring a request).
147
+
148
+ .. code-block:: php
149
+
150
+ use GuzzleHttp\Ring\Future\FutureValue;
151
+ use React\Promise\Deferred;
152
+
153
+ $deferred = new Deferred();
154
+ $promise = $deferred->promise();
155
+
156
+ $f = new FutureValue(
157
+ $promise,
158
+ function () use ($deferred) {
159
+ // This function is responsible for blocking and resolving the
160
+ // promise. Here we pass in a reference to the deferred so that
161
+ // it can be resolved or rejected.
162
+ $deferred->resolve('foo');
163
+ }
164
+ );
backend/vendor/guzzlehttp/ringphp/docs/index.rst ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ =======
2
+ RingPHP
3
+ =======
4
+
5
+ Provides a simple API and specification that abstracts away the details of HTTP
6
+ into a single PHP function. RingPHP be used to power HTTP clients and servers
7
+ through a PHP function that accepts a request hash and returns a response hash
8
+ that is fulfilled using a `promise <https://github.com/reactphp/promise>`_,
9
+ allowing RingPHP to support both synchronous and asynchronous workflows.
10
+
11
+ By abstracting the implementation details of different HTTP clients and
12
+ servers, RingPHP allows you to utilize pluggable HTTP clients and servers
13
+ without tying your application to a specific implementation.
14
+
15
+ .. toctree::
16
+ :maxdepth: 2
17
+
18
+ spec
19
+ futures
20
+ client_middleware
21
+ client_handlers
22
+ testing
23
+
24
+ .. code-block:: php
25
+
26
+ <?php
27
+ require 'vendor/autoload.php';
28
+
29
+ use GuzzleHttp\Ring\Client\CurlHandler;
30
+
31
+ $handler = new CurlHandler();
32
+ $response = $handler([
33
+ 'http_method' => 'GET',
34
+ 'uri' => '/',
35
+ 'headers' => [
36
+ 'host' => ['www.google.com'],
37
+ 'x-foo' => ['baz']
38
+ ]
39
+ ]);
40
+
41
+ $response->then(function (array $response) {
42
+ echo $response['status'];
43
+ });
44
+
45
+ $response->wait();
46
+
47
+ RingPHP is inspired by Clojure's `Ring <https://github.com/ring-clojure/ring>`_,
48
+ which, in turn, was inspired by Python's WSGI and Ruby's Rack. RingPHP is
49
+ utilized as the handler layer in `Guzzle <http://guzzlephp.org>`_ 5.0+ to send
50
+ HTTP requests.
backend/vendor/guzzlehttp/ringphp/docs/requirements.txt ADDED
@@ -0,0 +1 @@
 
1
+ sphinx_rtd_theme
backend/vendor/guzzlehttp/ringphp/docs/spec.rst ADDED
@@ -0,0 +1,311 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ =============
2
+ Specification
3
+ =============
4
+
5
+ RingPHP applications consist of handlers, requests, responses, and
6
+ middleware.
7
+
8
+ Handlers
9
+ --------
10
+
11
+ Handlers are implemented as a PHP ``callable`` that accept a request array
12
+ and return a response array (``GuzzleHttp\Ring\Future\FutureArrayInterface``).
13
+
14
+ For example:
15
+
16
+ .. code-block:: php
17
+
18
+ use GuzzleHttp\Ring\Future\CompletedFutureArray;
19
+
20
+ $mockHandler = function (array $request) {
21
+ return new CompletedFutureArray([
22
+ 'status' => 200,
23
+ 'headers' => ['X-Foo' => ['Bar']],
24
+ 'body' => 'Hello!'
25
+ ]);
26
+ };
27
+
28
+ This handler returns the same response each time it is invoked. All RingPHP
29
+ handlers must return a ``GuzzleHttp\Ring\Future\FutureArrayInterface``. Use
30
+ ``GuzzleHttp\Ring\Future\CompletedFutureArray`` when returning a response that
31
+ has already completed.
32
+
33
+ Requests
34
+ --------
35
+
36
+ A request array is a PHP associative array that contains the configuration
37
+ settings need to send a request.
38
+
39
+ .. code-block:: php
40
+
41
+ $request = [
42
+ 'http_method' => 'GET',
43
+ 'scheme' => 'http',
44
+ 'uri' => '/',
45
+ 'body' => 'hello!',
46
+ 'client' => ['timeout' => 1.0],
47
+ 'headers' => [
48
+ 'host' => ['httpbin.org'],
49
+ 'X-Foo' => ['baz', 'bar']
50
+ ]
51
+ ];
52
+
53
+ The request array contains the following key value pairs:
54
+
55
+ request_method
56
+ (string, required) The HTTP request method, must be all caps corresponding
57
+ to a HTTP request method, such as ``GET`` or ``POST``.
58
+
59
+ scheme
60
+ (string) The transport protocol, must be one of ``http`` or ``https``.
61
+ Defaults to ``http``.
62
+
63
+ uri
64
+ (string, required) The request URI excluding the query string. Must
65
+ start with "/".
66
+
67
+ query_string
68
+ (string) The query string, if present (e.g., ``foo=bar``).
69
+
70
+ version
71
+ (string) HTTP protocol version. Defaults to ``1.1``.
72
+
73
+ headers
74
+ (required, array) Associative array of headers. Each key represents the
75
+ header name. Each value contains an array of strings where each entry of
76
+ the array SHOULD be sent over the wire on a separate header line.
77
+
78
+ body
79
+ (string, fopen resource, ``Iterator``, ``GuzzleHttp\Stream\StreamInterface``)
80
+ The body of the request, if present. Can be a string, resource returned
81
+ from fopen, an ``Iterator`` that yields chunks of data, an object that
82
+ implemented ``__toString``, or a ``GuzzleHttp\Stream\StreamInterface``.
83
+
84
+ future
85
+ (bool, string) Controls the asynchronous behavior of a response.
86
+
87
+ Set to ``true`` or omit the ``future`` option to *request* that a request
88
+ will be completed asynchronously. Keep in mind that your request might not
89
+ necessarily be completed asynchronously based on the handler you are using.
90
+ Set the ``future`` option to ``false`` to request that a synchronous
91
+ response be provided.
92
+
93
+ You can provide a string value to specify fine-tuned future behaviors that
94
+ may be specific to the underlying handlers you are using. There are,
95
+ however, some common future options that handlers should implement if
96
+ possible.
97
+
98
+ lazy
99
+ Requests that the handler does not open and send the request
100
+ immediately, but rather only opens and sends the request once the
101
+ future is dereferenced. This option is often useful for sending a large
102
+ number of requests concurrently to allow handlers to take better
103
+ advantage of non-blocking transfers by first building up a pool of
104
+ requests.
105
+
106
+ If an handler does not implement or understand a provided string value,
107
+ then the request MUST be treated as if the user provided ``true`` rather
108
+ than the string value.
109
+
110
+ Future responses created by asynchronous handlers MUST attempt to complete
111
+ any outstanding future responses when they are destructed. Asynchronous
112
+ handlers MAY choose to automatically complete responses when the number
113
+ of outstanding requests reaches an handler-specific threshold.
114
+
115
+ Client Specific Options
116
+ ~~~~~~~~~~~~~~~~~~~~~~~
117
+
118
+ The following options are only used in ring client handlers.
119
+
120
+ .. _client-options:
121
+
122
+ client
123
+ (array) Associative array of client specific transfer options. The
124
+ ``client`` request key value pair can contain the following keys:
125
+
126
+ cert
127
+ (string, array) Set to a string to specify the path to a file
128
+ containing a PEM formatted SSL client side certificate. If a password
129
+ is required, then set ``cert`` to an array containing the path to the
130
+ PEM file in the first array element followed by the certificate
131
+ password in the second array element.
132
+
133
+ connect_timeout
134
+ (float) Float describing the number of seconds to wait while trying to
135
+ connect to a server. Use ``0`` to wait indefinitely (the default
136
+ behavior).
137
+
138
+ debug
139
+ (bool, fopen() resource) Set to true or set to a PHP stream returned by
140
+ fopen() to enable debug output with the handler used to send a request.
141
+ If set to ``true``, the output is written to PHP's STDOUT. If a PHP
142
+ ``fopen`` resource handle is provided, the output is written to the
143
+ stream.
144
+
145
+ "Debug output" is handler specific: different handlers will yield
146
+ different output and various various level of detail. For example, when
147
+ using cURL to transfer requests, cURL's `CURLOPT_VERBOSE <http://curl.haxx.se/libcurl/c/CURLOPT_VERBOSE.html>`_
148
+ will be used. When using the PHP stream wrapper, `stream notifications <http://php.net/manual/en/function.stream-notification-callback.php>`_
149
+ will be emitted.
150
+
151
+ decode_content
152
+ (bool) Specify whether or not ``Content-Encoding`` responses
153
+ (gzip, deflate, etc.) are automatically decoded. Set to ``true`` to
154
+ automatically decode encoded responses. Set to ``false`` to not decode
155
+ responses. By default, content is *not* decoded automatically.
156
+
157
+ delay
158
+ (int) The number of milliseconds to delay before sending the request.
159
+ This is often used for delaying before retrying a request. Handlers
160
+ SHOULD implement this if possible, but it is not a strict requirement.
161
+
162
+ progress
163
+ (function) Defines a function to invoke when transfer progress is made.
164
+ The function accepts the following arguments:
165
+
166
+ 1. The total number of bytes expected to be downloaded
167
+ 2. The number of bytes downloaded so far
168
+ 3. The number of bytes expected to be uploaded
169
+ 4. The number of bytes uploaded so far
170
+
171
+ proxy
172
+ (string, array) Pass a string to specify an HTTP proxy, or an
173
+ associative array to specify different proxies for different protocols
174
+ where the scheme is the key and the value is the proxy address.
175
+
176
+ .. code-block:: php
177
+
178
+ $request = [
179
+ 'http_method' => 'GET',
180
+ 'headers' => ['host' => ['httpbin.org']],
181
+ 'client' => [
182
+ // Use different proxies for different URI schemes.
183
+ 'proxy' => [
184
+ 'http' => 'http://proxy.example.com:5100',
185
+ 'https' => 'https://proxy.example.com:6100'
186
+ ]
187
+ ]
188
+ ];
189
+
190
+ ssl_key
191
+ (string, array) Specify the path to a file containing a private SSL key
192
+ in PEM format. If a password is required, then set to an array
193
+ containing the path to the SSL key in the first array element followed
194
+ by the password required for the certificate in the second element.
195
+
196
+ save_to
197
+ (string, fopen resource, ``GuzzleHttp\Stream\StreamInterface``)
198
+ Specifies where the body of the response is downloaded. Pass a string to
199
+ open a local file on disk and save the output to the file. Pass an fopen
200
+ resource to save the output to a PHP stream resource. Pass a
201
+ ``GuzzleHttp\Stream\StreamInterface`` to save the output to a Guzzle
202
+ StreamInterface. Omitting this option will typically save the body of a
203
+ response to a PHP temp stream.
204
+
205
+ stream
206
+ (bool) Set to true to stream a response rather than download it all
207
+ up-front. This option will only be utilized when the corresponding
208
+ handler supports it.
209
+
210
+ timeout
211
+ (float) Float describing the timeout of the request in seconds. Use 0 to
212
+ wait indefinitely (the default behavior).
213
+
214
+ verify
215
+ (bool, string) Describes the SSL certificate verification behavior of a
216
+ request. Set to true to enable SSL certificate verification using the
217
+ system CA bundle when available (the default). Set to false to disable
218
+ certificate verification (this is insecure!). Set to a string to provide
219
+ the path to a CA bundle on disk to enable verification using a custom
220
+ certificate.
221
+
222
+ version
223
+ (string) HTTP protocol version to use with the request.
224
+
225
+ Server Specific Options
226
+ ~~~~~~~~~~~~~~~~~~~~~~~
227
+
228
+ The following options are only used in ring server handlers.
229
+
230
+ server_port
231
+ (integer) The port on which the request is being handled. This is only
232
+ used with ring servers, and is required.
233
+
234
+ server_name
235
+ (string) The resolved server name, or the server IP address. Required when
236
+ using a Ring server.
237
+
238
+ remote_addr
239
+ (string) The IP address of the client or the last proxy that sent the
240
+ request. Required when using a Ring server.
241
+
242
+ Responses
243
+ ---------
244
+
245
+ A response is an array-like object that implements
246
+ ``GuzzleHttp\Ring\Future\FutureArrayInterface``. Responses contain the
247
+ following key value pairs:
248
+
249
+ body
250
+ (string, fopen resource, ``Iterator``, ``GuzzleHttp\Stream\StreamInterface``)
251
+ The body of the response, if present. Can be a string, resource returned
252
+ from fopen, an ``Iterator`` that yields chunks of data, an object that
253
+ implemented ``__toString``, or a ``GuzzleHttp\Stream\StreamInterface``.
254
+
255
+ effective_url
256
+ (string) The URL that returned the resulting response.
257
+
258
+ error
259
+ (``\Exception``) Contains an exception describing any errors that were
260
+ encountered during the transfer.
261
+
262
+ headers
263
+ (Required, array) Associative array of headers. Each key represents the
264
+ header name. Each value contains an array of strings where each entry of
265
+ the array is a header line. The headers array MAY be an empty array in the
266
+ event an error occurred before a response was received.
267
+
268
+ reason
269
+ (string) Optional reason phrase. This option should be provided when the
270
+ reason phrase does not match the typical reason phrase associated with the
271
+ ``status`` code. See `RFC 7231 <http://tools.ietf.org/html/rfc7231#section-6.1>`_
272
+ for a list of HTTP reason phrases mapped to status codes.
273
+
274
+ status
275
+ (Required, integer) The HTTP status code. The status code MAY be set to
276
+ ``null`` in the event an error occurred before a response was received
277
+ (e.g., a networking error).
278
+
279
+ transfer_stats
280
+ (array) Provides an associative array of arbitrary transfer statistics if
281
+ provided by the underlying handler.
282
+
283
+ version
284
+ (string) HTTP protocol version. Defaults to ``1.1``.
285
+
286
+ Middleware
287
+ ----------
288
+
289
+ Ring middleware augments the functionality of handlers by invoking them in the
290
+ process of generating responses. Middleware is typically implemented as a
291
+ higher-order function that takes one or more handlers as arguments followed by
292
+ an optional associative array of options as the last argument, returning a new
293
+ handler with the desired compound behavior.
294
+
295
+ Here's an example of a middleware that adds a Content-Type header to each
296
+ request.
297
+
298
+ .. code-block:: php
299
+
300
+ use GuzzleHttp\Ring\Client\CurlHandler;
301
+ use GuzzleHttp\Ring\Core;
302
+
303
+ $contentTypeHandler = function(callable $handler, $contentType) {
304
+ return function (array $request) use ($handler, $contentType) {
305
+ return $handler(Core::setHeader('Content-Type', $contentType));
306
+ };
307
+ };
308
+
309
+ $baseHandler = new CurlHandler();
310
+ $wrappedHandler = $contentTypeHandler($baseHandler, 'text/html');
311
+ $response = $wrappedHandler([/** request hash **/]);
backend/vendor/guzzlehttp/ringphp/docs/testing.rst ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ =======
2
+ Testing
3
+ =======
4
+
5
+ RingPHP tests client handlers using `PHPUnit <https://phpunit.de/>`_ and a
6
+ built-in node.js web server.
7
+
8
+ Running Tests
9
+ -------------
10
+
11
+ First, install the dependencies using `Composer <https://getcomposer.org>`_.
12
+
13
+ composer.phar install
14
+
15
+ Next, run the unit tests using ``Make``.
16
+
17
+ make test
18
+
19
+ The tests are also run on Travis-CI on each commit: https://travis-ci.org/guzzle/guzzle-ring
20
+
21
+ Test Server
22
+ -----------
23
+
24
+ Testing client handlers usually involves actually sending HTTP requests.
25
+ RingPHP provides a node.js web server that returns canned responses and
26
+ keep a list of the requests that have been received. The server can then
27
+ be queried to get a list of the requests that were sent by the client so that
28
+ you can ensure that the client serialized and transferred requests as intended.
29
+
30
+ The server keeps a list of queued responses and returns responses that are
31
+ popped off of the queue as HTTP requests are received. When there are not
32
+ more responses to serve, the server returns a 500 error response.
33
+
34
+ The test server uses the ``GuzzleHttp\Tests\Ring\Client\Server`` class to
35
+ control the server.
36
+
37
+ .. code-block:: php
38
+
39
+ use GuzzleHttp\Ring\Client\StreamHandler;
40
+ use GuzzleHttp\Tests\Ring\Client\Server;
41
+
42
+ // First return a 200 followed by a 404 response.
43
+ Server::enqueue([
44
+ ['status' => 200],
45
+ ['status' => 404]
46
+ ]);
47
+
48
+ $handler = new StreamHandler();
49
+
50
+ $response = $handler([
51
+ 'http_method' => 'GET',
52
+ 'headers' => ['host' => [Server::$host]],
53
+ 'uri' => '/'
54
+ ]);
55
+
56
+ assert(200 == $response['status']);
57
+
58
+ $response = $handler([
59
+ 'http_method' => 'HEAD',
60
+ 'headers' => ['host' => [Server::$host]],
61
+ 'uri' => '/'
62
+ ]);
63
+
64
+ assert(404 == $response['status']);
65
+
66
+ After requests have been sent, you can get a list of the requests as they
67
+ were sent over the wire to ensure they were sent correctly.
68
+
69
+ .. code-block:: php
70
+
71
+ $received = Server::received();
72
+
73
+ assert('GET' == $received[0]['http_method']);
74
+ assert('HEAD' == $received[1]['http_method']);
backend/vendor/guzzlehttp/ringphp/phpunit.xml.dist ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <phpunit bootstrap="./tests/bootstrap.php"
3
+ colors="true">
4
+ <testsuites>
5
+ <testsuite>
6
+ <directory>tests</directory>
7
+ </testsuite>
8
+ </testsuites>
9
+ <filter>
10
+ <whitelist>
11
+ <directory suffix=".php">src</directory>
12
+ </whitelist>
13
+ </filter>
14
+ </phpunit>
backend/vendor/guzzlehttp/ringphp/src/Client/ClientUtils.php ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Ring\Client;
3
+
4
+ /**
5
+ * Client specific utility functions.
6
+ */
7
+ class ClientUtils
8
+ {
9
+ /**
10
+ * Returns the default cacert bundle for the current system.
11
+ *
12
+ * First, the openssl.cafile and curl.cainfo php.ini settings are checked.
13
+ * If those settings are not configured, then the common locations for
14
+ * bundles found on Red Hat, CentOS, Fedora, Ubuntu, Debian, FreeBSD, OS X
15
+ * and Windows are checked. If any of these file locations are found on
16
+ * disk, they will be utilized.
17
+ *
18
+ * Note: the result of this function is cached for subsequent calls.
19
+ *
20
+ * @return string
21
+ * @throws \RuntimeException if no bundle can be found.
22
+ */
23
+ public static function getDefaultCaBundle()
24
+ {
25
+ static $cached = null;
26
+ static $cafiles = [
27
+ // Red Hat, CentOS, Fedora (provided by the ca-certificates package)
28
+ '/etc/pki/tls/certs/ca-bundle.crt',
29
+ // Ubuntu, Debian (provided by the ca-certificates package)
30
+ '/etc/ssl/certs/ca-certificates.crt',
31
+ // FreeBSD (provided by the ca_root_nss package)
32
+ '/usr/local/share/certs/ca-root-nss.crt',
33
+ // OS X provided by homebrew (using the default path)
34
+ '/usr/local/etc/openssl/cert.pem',
35
+ // Windows?
36
+ 'C:\\windows\\system32\\curl-ca-bundle.crt',
37
+ 'C:\\windows\\curl-ca-bundle.crt',
38
+ ];
39
+
40
+ if ($cached) {
41
+ return $cached;
42
+ }
43
+
44
+ if ($ca = ini_get('openssl.cafile')) {
45
+ return $cached = $ca;
46
+ }
47
+
48
+ if ($ca = ini_get('curl.cainfo')) {
49
+ return $cached = $ca;
50
+ }
51
+
52
+ foreach ($cafiles as $filename) {
53
+ if (file_exists($filename)) {
54
+ return $cached = $filename;
55
+ }
56
+ }
57
+
58
+ throw new \RuntimeException(self::CA_ERR);
59
+ }
60
+
61
+ const CA_ERR = "
62
+ No system CA bundle could be found in any of the the common system locations.
63
+ PHP versions earlier than 5.6 are not properly configured to use the system's
64
+ CA bundle by default. In order to verify peer certificates, you will need to
65
+ supply the path on disk to a certificate bundle to the 'verify' request
66
+ option: http://docs.guzzlephp.org/en/latest/clients.html#verify. If you do not
67
+ need a specific certificate bundle, then Mozilla provides a commonly used CA
68
+ bundle which can be downloaded here (provided by the maintainer of cURL):
69
+ https://raw.githubusercontent.com/bagder/ca-bundle/master/ca-bundle.crt. Once
70
+ you have a CA bundle available on disk, you can set the 'openssl.cafile' PHP
71
+ ini setting to point to the path to the file, allowing you to omit the 'verify'
72
+ request option. See http://curl.haxx.se/docs/sslcerts.html for more
73
+ information.";
74
+ }
backend/vendor/guzzlehttp/ringphp/src/Client/CurlFactory.php ADDED
@@ -0,0 +1,546 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Ring\Client;
3
+
4
+ use GuzzleHttp\Ring\Core;
5
+ use GuzzleHttp\Ring\Exception\ConnectException;
6
+ use GuzzleHttp\Ring\Exception\RingException;
7
+ use GuzzleHttp\Stream\LazyOpenStream;
8
+ use GuzzleHttp\Stream\StreamInterface;
9
+
10
+ /**
11
+ * Creates curl resources from a request
12
+ */
13
+ class CurlFactory
14
+ {
15
+ /**
16
+ * Creates a cURL handle, header resource, and body resource based on a
17
+ * transaction.
18
+ *
19
+ * @param array $request Request hash
20
+ * @param null|resource $handle Optionally provide a curl handle to modify
21
+ *
22
+ * @return array Returns an array of the curl handle, headers array, and
23
+ * response body handle.
24
+ * @throws \RuntimeException when an option cannot be applied
25
+ */
26
+ public function __invoke(array $request, $handle = null)
27
+ {
28
+ $headers = [];
29
+ $options = $this->getDefaultOptions($request, $headers);
30
+ $this->applyMethod($request, $options);
31
+
32
+ if (isset($request['client'])) {
33
+ $this->applyHandlerOptions($request, $options);
34
+ }
35
+
36
+ $this->applyHeaders($request, $options);
37
+ unset($options['_headers']);
38
+
39
+ // Add handler options from the request's configuration options
40
+ if (isset($request['client']['curl'])) {
41
+ $options = $this->applyCustomCurlOptions(
42
+ $request['client']['curl'],
43
+ $options
44
+ );
45
+ }
46
+
47
+ if (!$handle) {
48
+ $handle = curl_init();
49
+ }
50
+
51
+ $body = $this->getOutputBody($request, $options);
52
+ curl_setopt_array($handle, $options);
53
+
54
+ return [$handle, &$headers, $body];
55
+ }
56
+
57
+ /**
58
+ * Creates a response hash from a cURL result.
59
+ *
60
+ * @param callable $handler Handler that was used.
61
+ * @param array $request Request that sent.
62
+ * @param array $response Response hash to update.
63
+ * @param array $headers Headers received during transfer.
64
+ * @param resource $body Body fopen response.
65
+ *
66
+ * @return array
67
+ */
68
+ public static function createResponse(
69
+ callable $handler,
70
+ array $request,
71
+ array $response,
72
+ array $headers,
73
+ $body
74
+ ) {
75
+ if (isset($response['transfer_stats']['url'])) {
76
+ $response['effective_url'] = $response['transfer_stats']['url'];
77
+ }
78
+
79
+ if (!empty($headers)) {
80
+ $startLine = explode(' ', array_shift($headers), 3);
81
+ $headerList = Core::headersFromLines($headers);
82
+ $response['headers'] = $headerList;
83
+ $response['status'] = isset($startLine[1]) ? (int) $startLine[1] : null;
84
+ $response['reason'] = isset($startLine[2]) ? $startLine[2] : null;
85
+ $response['body'] = $body;
86
+ Core::rewindBody($response);
87
+ }
88
+
89
+ return !empty($response['curl']['errno']) || !isset($response['status'])
90
+ ? self::createErrorResponse($handler, $request, $response)
91
+ : $response;
92
+ }
93
+
94
+ private static function createErrorResponse(
95
+ callable $handler,
96
+ array $request,
97
+ array $response
98
+ ) {
99
+ static $connectionErrors = [
100
+ CURLE_OPERATION_TIMEOUTED => true,
101
+ CURLE_COULDNT_RESOLVE_HOST => true,
102
+ CURLE_COULDNT_CONNECT => true,
103
+ CURLE_SSL_CONNECT_ERROR => true,
104
+ CURLE_GOT_NOTHING => true,
105
+ ];
106
+
107
+ // Retry when nothing is present or when curl failed to rewind.
108
+ if (!isset($response['err_message'])
109
+ && (empty($response['curl']['errno'])
110
+ || $response['curl']['errno'] == 65)
111
+ ) {
112
+ return self::retryFailedRewind($handler, $request, $response);
113
+ }
114
+
115
+ $message = isset($response['err_message'])
116
+ ? $response['err_message']
117
+ : sprintf('cURL error %s: %s',
118
+ $response['curl']['errno'],
119
+ isset($response['curl']['error'])
120
+ ? $response['curl']['error']
121
+ : 'See http://curl.haxx.se/libcurl/c/libcurl-errors.html');
122
+
123
+ $error = isset($response['curl']['errno'])
124
+ && isset($connectionErrors[$response['curl']['errno']])
125
+ ? new ConnectException($message)
126
+ : new RingException($message);
127
+
128
+ return $response + [
129
+ 'status' => null,
130
+ 'reason' => null,
131
+ 'body' => null,
132
+ 'headers' => [],
133
+ 'error' => $error,
134
+ ];
135
+ }
136
+
137
+ private function getOutputBody(array $request, array &$options)
138
+ {
139
+ // Determine where the body of the response (if any) will be streamed.
140
+ if (isset($options[CURLOPT_WRITEFUNCTION])) {
141
+ return $request['client']['save_to'];
142
+ }
143
+
144
+ if (isset($options[CURLOPT_FILE])) {
145
+ return $options[CURLOPT_FILE];
146
+ }
147
+
148
+ if ($request['http_method'] != 'HEAD') {
149
+ // Create a default body if one was not provided
150
+ return $options[CURLOPT_FILE] = fopen('php://temp', 'w+');
151
+ }
152
+
153
+ return null;
154
+ }
155
+
156
+ private function getDefaultOptions(array $request, array &$headers)
157
+ {
158
+ $url = Core::url($request);
159
+ $startingResponse = false;
160
+
161
+ $options = [
162
+ '_headers' => $request['headers'],
163
+ CURLOPT_CUSTOMREQUEST => $request['http_method'],
164
+ CURLOPT_URL => $url,
165
+ CURLOPT_RETURNTRANSFER => false,
166
+ CURLOPT_HEADER => false,
167
+ CURLOPT_CONNECTTIMEOUT => 150,
168
+ CURLOPT_HEADERFUNCTION => function ($ch, $h) use (&$headers, &$startingResponse) {
169
+ $value = trim($h);
170
+ if ($value === '') {
171
+ $startingResponse = true;
172
+ } elseif ($startingResponse) {
173
+ $startingResponse = false;
174
+ $headers = [$value];
175
+ } else {
176
+ $headers[] = $value;
177
+ }
178
+ return strlen($h);
179
+ },
180
+ ];
181
+
182
+ if (isset($request['version'])) {
183
+ $options[CURLOPT_HTTP_VERSION] = $request['version'] == 1.1 ? CURL_HTTP_VERSION_1_1 : CURL_HTTP_VERSION_1_0;
184
+ }
185
+
186
+ if (defined('CURLOPT_PROTOCOLS')) {
187
+ $options[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS;
188
+ }
189
+
190
+ return $options;
191
+ }
192
+
193
+ private function applyMethod(array $request, array &$options)
194
+ {
195
+ if (isset($request['body'])) {
196
+ $this->applyBody($request, $options);
197
+ return;
198
+ }
199
+
200
+ switch ($request['http_method']) {
201
+ case 'PUT':
202
+ case 'POST':
203
+ // See http://tools.ietf.org/html/rfc7230#section-3.3.2
204
+ if (!Core::hasHeader($request, 'Content-Length')) {
205
+ $options[CURLOPT_HTTPHEADER][] = 'Content-Length: 0';
206
+ }
207
+ break;
208
+ case 'HEAD':
209
+ $options[CURLOPT_NOBODY] = true;
210
+ unset(
211
+ $options[CURLOPT_WRITEFUNCTION],
212
+ $options[CURLOPT_READFUNCTION],
213
+ $options[CURLOPT_FILE],
214
+ $options[CURLOPT_INFILE]
215
+ );
216
+ }
217
+ }
218
+
219
+ private function applyBody(array $request, array &$options)
220
+ {
221
+ $contentLength = Core::firstHeader($request, 'Content-Length');
222
+ $size = $contentLength !== null ? (int) $contentLength : null;
223
+
224
+ // Send the body as a string if the size is less than 1MB OR if the
225
+ // [client][curl][body_as_string] request value is set.
226
+ if (($size !== null && $size < 1000000) ||
227
+ isset($request['client']['curl']['body_as_string']) ||
228
+ is_string($request['body'])
229
+ ) {
230
+ $options[CURLOPT_POSTFIELDS] = Core::body($request);
231
+ // Don't duplicate the Content-Length header
232
+ $this->removeHeader('Content-Length', $options);
233
+ $this->removeHeader('Transfer-Encoding', $options);
234
+ } else {
235
+ $options[CURLOPT_UPLOAD] = true;
236
+ if ($size !== null) {
237
+ // Let cURL handle setting the Content-Length header
238
+ $options[CURLOPT_INFILESIZE] = $size;
239
+ $this->removeHeader('Content-Length', $options);
240
+ }
241
+ $this->addStreamingBody($request, $options);
242
+ }
243
+
244
+ // If the Expect header is not present, prevent curl from adding it
245
+ if (!Core::hasHeader($request, 'Expect')) {
246
+ $options[CURLOPT_HTTPHEADER][] = 'Expect:';
247
+ }
248
+
249
+ // cURL sometimes adds a content-type by default. Prevent this.
250
+ if (!Core::hasHeader($request, 'Content-Type')) {
251
+ $options[CURLOPT_HTTPHEADER][] = 'Content-Type:';
252
+ }
253
+ }
254
+
255
+ private function addStreamingBody(array $request, array &$options)
256
+ {
257
+ $body = $request['body'];
258
+
259
+ if ($body instanceof StreamInterface) {
260
+ $options[CURLOPT_READFUNCTION] = function ($ch, $fd, $length) use ($body) {
261
+ return (string) $body->read($length);
262
+ };
263
+ if (!isset($options[CURLOPT_INFILESIZE])) {
264
+ if ($size = $body->getSize()) {
265
+ $options[CURLOPT_INFILESIZE] = $size;
266
+ }
267
+ }
268
+ } elseif (is_resource($body)) {
269
+ $options[CURLOPT_INFILE] = $body;
270
+ } elseif ($body instanceof \Iterator) {
271
+ $buf = '';
272
+ $options[CURLOPT_READFUNCTION] = function ($ch, $fd, $length) use ($body, &$buf) {
273
+ if ($body->valid()) {
274
+ $buf .= $body->current();
275
+ $body->next();
276
+ }
277
+ $result = (string) substr($buf, 0, $length);
278
+ $buf = substr($buf, $length);
279
+ return $result;
280
+ };
281
+ } else {
282
+ throw new \InvalidArgumentException('Invalid request body provided');
283
+ }
284
+ }
285
+
286
+ private function applyHeaders(array $request, array &$options)
287
+ {
288
+ foreach ($options['_headers'] as $name => $values) {
289
+ foreach ($values as $value) {
290
+ $options[CURLOPT_HTTPHEADER][] = "$name: $value";
291
+ }
292
+ }
293
+
294
+ // Remove the Accept header if one was not set
295
+ if (!Core::hasHeader($request, 'Accept')) {
296
+ $options[CURLOPT_HTTPHEADER][] = 'Accept:';
297
+ }
298
+ }
299
+
300
+ /**
301
+ * Takes an array of curl options specified in the 'curl' option of a
302
+ * request's configuration array and maps them to CURLOPT_* options.
303
+ *
304
+ * This method is only called when a request has a 'curl' config setting.
305
+ *
306
+ * @param array $config Configuration array of custom curl option
307
+ * @param array $options Array of existing curl options
308
+ *
309
+ * @return array Returns a new array of curl options
310
+ */
311
+ private function applyCustomCurlOptions(array $config, array $options)
312
+ {
313
+ $curlOptions = [];
314
+ foreach ($config as $key => $value) {
315
+ if (is_int($key)) {
316
+ $curlOptions[$key] = $value;
317
+ }
318
+ }
319
+
320
+ return $curlOptions + $options;
321
+ }
322
+
323
+ /**
324
+ * Remove a header from the options array.
325
+ *
326
+ * @param string $name Case-insensitive header to remove
327
+ * @param array $options Array of options to modify
328
+ */
329
+ private function removeHeader($name, array &$options)
330
+ {
331
+ foreach (array_keys($options['_headers']) as $key) {
332
+ if (!strcasecmp($key, $name)) {
333
+ unset($options['_headers'][$key]);
334
+ return;
335
+ }
336
+ }
337
+ }
338
+
339
+ /**
340
+ * Applies an array of request client options to a the options array.
341
+ *
342
+ * This method uses a large switch rather than double-dispatch to save on
343
+ * high overhead of calling functions in PHP.
344
+ */
345
+ private function applyHandlerOptions(array $request, array &$options)
346
+ {
347
+ foreach ($request['client'] as $key => $value) {
348
+ switch ($key) {
349
+ // Violating PSR-4 to provide more room.
350
+ case 'verify':
351
+
352
+ if ($value === false) {
353
+ unset($options[CURLOPT_CAINFO]);
354
+ $options[CURLOPT_SSL_VERIFYHOST] = 0;
355
+ $options[CURLOPT_SSL_VERIFYPEER] = false;
356
+ continue;
357
+ }
358
+
359
+ $options[CURLOPT_SSL_VERIFYHOST] = 2;
360
+ $options[CURLOPT_SSL_VERIFYPEER] = true;
361
+
362
+ if (is_string($value)) {
363
+ $options[CURLOPT_CAINFO] = $value;
364
+ if (!file_exists($value)) {
365
+ throw new \InvalidArgumentException(
366
+ "SSL CA bundle not found: $value"
367
+ );
368
+ }
369
+ }
370
+ break;
371
+
372
+ case 'decode_content':
373
+
374
+ if ($value === false) {
375
+ continue;
376
+ }
377
+
378
+ $accept = Core::firstHeader($request, 'Accept-Encoding');
379
+ if ($accept) {
380
+ $options[CURLOPT_ENCODING] = $accept;
381
+ } else {
382
+ $options[CURLOPT_ENCODING] = '';
383
+ // Don't let curl send the header over the wire
384
+ $options[CURLOPT_HTTPHEADER][] = 'Accept-Encoding:';
385
+ }
386
+ break;
387
+
388
+ case 'save_to':
389
+
390
+ if (is_string($value)) {
391
+ $value = new LazyOpenStream($value, 'w+');
392
+ }
393
+
394
+ if ($value instanceof StreamInterface) {
395
+ $options[CURLOPT_WRITEFUNCTION] =
396
+ function ($ch, $write) use ($value) {
397
+ return $value->write($write);
398
+ };
399
+ } elseif (is_resource($value)) {
400
+ $options[CURLOPT_FILE] = $value;
401
+ } else {
402
+ throw new \InvalidArgumentException('save_to must be a '
403
+ . 'GuzzleHttp\Stream\StreamInterface or resource');
404
+ }
405
+ break;
406
+
407
+ case 'timeout':
408
+
409
+ if (defined('CURLOPT_TIMEOUT_MS')) {
410
+ $options[CURLOPT_TIMEOUT_MS] = $value * 1000;
411
+ } else {
412
+ $options[CURLOPT_TIMEOUT] = $value;
413
+ }
414
+ break;
415
+
416
+ case 'connect_timeout':
417
+
418
+ if (defined('CURLOPT_CONNECTTIMEOUT_MS')) {
419
+ $options[CURLOPT_CONNECTTIMEOUT_MS] = $value * 1000;
420
+ } else {
421
+ $options[CURLOPT_CONNECTTIMEOUT] = $value;
422
+ }
423
+ break;
424
+
425
+ case 'proxy':
426
+
427
+ if (!is_array($value)) {
428
+ $options[CURLOPT_PROXY] = $value;
429
+ } elseif (isset($request['scheme'])) {
430
+ $scheme = $request['scheme'];
431
+ if (isset($value[$scheme])) {
432
+ $options[CURLOPT_PROXY] = $value[$scheme];
433
+ }
434
+ }
435
+ break;
436
+
437
+ case 'cert':
438
+
439
+ if (is_array($value)) {
440
+ $options[CURLOPT_SSLCERTPASSWD] = $value[1];
441
+ $value = $value[0];
442
+ }
443
+
444
+ if (!file_exists($value)) {
445
+ throw new \InvalidArgumentException(
446
+ "SSL certificate not found: {$value}"
447
+ );
448
+ }
449
+
450
+ $options[CURLOPT_SSLCERT] = $value;
451
+ break;
452
+
453
+ case 'ssl_key':
454
+
455
+ if (is_array($value)) {
456
+ $options[CURLOPT_SSLKEYPASSWD] = $value[1];
457
+ $value = $value[0];
458
+ }
459
+
460
+ if (!file_exists($value)) {
461
+ throw new \InvalidArgumentException(
462
+ "SSL private key not found: {$value}"
463
+ );
464
+ }
465
+
466
+ $options[CURLOPT_SSLKEY] = $value;
467
+ break;
468
+
469
+ case 'progress':
470
+
471
+ if (!is_callable($value)) {
472
+ throw new \InvalidArgumentException(
473
+ 'progress client option must be callable'
474
+ );
475
+ }
476
+
477
+ $options[CURLOPT_NOPROGRESS] = false;
478
+ $options[CURLOPT_PROGRESSFUNCTION] =
479
+ function () use ($value) {
480
+ $args = func_get_args();
481
+ // PHP 5.5 pushed the handle onto the start of the args
482
+ if (is_resource($args[0])) {
483
+ array_shift($args);
484
+ }
485
+ call_user_func_array($value, $args);
486
+ };
487
+ break;
488
+
489
+ case 'debug':
490
+
491
+ if ($value) {
492
+ $options[CURLOPT_STDERR] = Core::getDebugResource($value);
493
+ $options[CURLOPT_VERBOSE] = true;
494
+ }
495
+ break;
496
+ }
497
+ }
498
+ }
499
+
500
+ /**
501
+ * This function ensures that a response was set on a transaction. If one
502
+ * was not set, then the request is retried if possible. This error
503
+ * typically means you are sending a payload, curl encountered a
504
+ * "Connection died, retrying a fresh connect" error, tried to rewind the
505
+ * stream, and then encountered a "necessary data rewind wasn't possible"
506
+ * error, causing the request to be sent through curl_multi_info_read()
507
+ * without an error status.
508
+ */
509
+ private static function retryFailedRewind(
510
+ callable $handler,
511
+ array $request,
512
+ array $response
513
+ ) {
514
+ // If there is no body, then there is some other kind of issue. This
515
+ // is weird and should probably never happen.
516
+ if (!isset($request['body'])) {
517
+ $response['err_message'] = 'No response was received for a request '
518
+ . 'with no body. This could mean that you are saturating your '
519
+ . 'network.';
520
+ return self::createErrorResponse($handler, $request, $response);
521
+ }
522
+
523
+ if (!Core::rewindBody($request)) {
524
+ $response['err_message'] = 'The connection unexpectedly failed '
525
+ . 'without providing an error. The request would have been '
526
+ . 'retried, but attempting to rewind the request body failed.';
527
+ return self::createErrorResponse($handler, $request, $response);
528
+ }
529
+
530
+ // Retry no more than 3 times before giving up.
531
+ if (!isset($request['curl']['retries'])) {
532
+ $request['curl']['retries'] = 1;
533
+ } elseif ($request['curl']['retries'] == 2) {
534
+ $response['err_message'] = 'The cURL request was retried 3 times '
535
+ . 'and did no succeed. cURL was unable to rewind the body of '
536
+ . 'the request and subsequent retries resulted in the same '
537
+ . 'error. Turn on the debug option to see what went wrong. '
538
+ . 'See https://bugs.php.net/bug.php?id=47204 for more information.';
539
+ return self::createErrorResponse($handler, $request, $response);
540
+ } else {
541
+ $request['curl']['retries']++;
542
+ }
543
+
544
+ return $handler($request);
545
+ }
546
+ }
backend/vendor/guzzlehttp/ringphp/src/Client/CurlHandler.php ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Ring\Client;
3
+
4
+ use GuzzleHttp\Ring\Future\CompletedFutureArray;
5
+ use GuzzleHttp\Ring\Core;
6
+
7
+ /**
8
+ * HTTP handler that uses cURL easy handles as a transport layer.
9
+ *
10
+ * Requires PHP 5.5+
11
+ *
12
+ * When using the CurlHandler, custom curl options can be specified as an
13
+ * associative array of curl option constants mapping to values in the
14
+ * **curl** key of the "client" key of the request.
15
+ */
16
+ class CurlHandler
17
+ {
18
+ /** @var callable */
19
+ private $factory;
20
+
21
+ /** @var array Array of curl easy handles */
22
+ private $handles = [];
23
+
24
+ /** @var array Array of owned curl easy handles */
25
+ private $ownedHandles = [];
26
+
27
+ /** @var int Total number of idle handles to keep in cache */
28
+ private $maxHandles;
29
+
30
+ /**
31
+ * Accepts an associative array of options:
32
+ *
33
+ * - factory: Optional callable factory used to create cURL handles.
34
+ * The callable is passed a request hash when invoked, and returns an
35
+ * array of the curl handle, headers resource, and body resource.
36
+ * - max_handles: Maximum number of idle handles (defaults to 5).
37
+ *
38
+ * @param array $options Array of options to use with the handler
39
+ */
40
+ public function __construct(array $options = [])
41
+ {
42
+ $this->handles = $this->ownedHandles = [];
43
+ $this->factory = isset($options['handle_factory'])
44
+ ? $options['handle_factory']
45
+ : new CurlFactory();
46
+ $this->maxHandles = isset($options['max_handles'])
47
+ ? $options['max_handles']
48
+ : 5;
49
+ }
50
+
51
+ public function __destruct()
52
+ {
53
+ foreach ($this->handles as $handle) {
54
+ if (is_resource($handle)) {
55
+ curl_close($handle);
56
+ }
57
+ }
58
+ }
59
+
60
+ public function __invoke(array $request)
61
+ {
62
+ $factory = $this->factory;
63
+
64
+ // Ensure headers are by reference. They're updated elsewhere.
65
+ $result = $factory($request, $this->checkoutEasyHandle());
66
+ $h = $result[0];
67
+ $hd =& $result[1];
68
+ $bd = $result[2];
69
+ Core::doSleep($request);
70
+ curl_exec($h);
71
+ $response = ['transfer_stats' => curl_getinfo($h)];
72
+ $response['curl']['error'] = curl_error($h);
73
+ $response['curl']['errno'] = curl_errno($h);
74
+ $this->releaseEasyHandle($h);
75
+
76
+ return new CompletedFutureArray(
77
+ CurlFactory::createResponse($this, $request, $response, $hd, $bd)
78
+ );
79
+ }
80
+
81
+ private function checkoutEasyHandle()
82
+ {
83
+ // Find an unused handle in the cache
84
+ if (false !== ($key = array_search(false, $this->ownedHandles, true))) {
85
+ $this->ownedHandles[$key] = true;
86
+ return $this->handles[$key];
87
+ }
88
+
89
+ // Add a new handle
90
+ $handle = curl_init();
91
+ $id = (int) $handle;
92
+ $this->handles[$id] = $handle;
93
+ $this->ownedHandles[$id] = true;
94
+
95
+ return $handle;
96
+ }
97
+
98
+ private function releaseEasyHandle($handle)
99
+ {
100
+ $id = (int) $handle;
101
+ if (count($this->ownedHandles) > $this->maxHandles) {
102
+ curl_close($this->handles[$id]);
103
+ unset($this->handles[$id], $this->ownedHandles[$id]);
104
+ } else {
105
+ // curl_reset doesn't clear these out for some reason
106
+ static $unsetValues = [
107
+ CURLOPT_HEADERFUNCTION => null,
108
+ CURLOPT_WRITEFUNCTION => null,
109
+ CURLOPT_READFUNCTION => null,
110
+ CURLOPT_PROGRESSFUNCTION => null,
111
+ ];
112
+ curl_setopt_array($handle, $unsetValues);
113
+ curl_reset($handle);
114
+ $this->ownedHandles[$id] = false;
115
+ }
116
+ }
117
+ }
backend/vendor/guzzlehttp/ringphp/src/Client/CurlMultiHandler.php ADDED
@@ -0,0 +1,239 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Ring\Client;
3
+
4
+ use GuzzleHttp\Ring\Future\FutureArray;
5
+ use React\Promise\Deferred;
6
+
7
+ /**
8
+ * Returns an asynchronous response using curl_multi_* functions.
9
+ *
10
+ * This handler supports future responses and the "delay" request client
11
+ * option that can be used to delay before sending a request.
12
+ *
13
+ * When using the CurlMultiHandler, custom curl options can be specified as an
14
+ * associative array of curl option constants mapping to values in the
15
+ * **curl** key of the "client" key of the request.
16
+ */
17
+ class CurlMultiHandler
18
+ {
19
+ /** @var callable */
20
+ private $factory;
21
+ private $selectTimeout;
22
+ private $mh;
23
+ private $active;
24
+ private $handles = [];
25
+ private $delays = [];
26
+ private $maxHandles;
27
+
28
+ /**
29
+ * This handler accepts the following options:
30
+ *
31
+ * - mh: An optional curl_multi resource
32
+ * - handle_factory: An optional callable used to generate curl handle
33
+ * resources. the callable accepts a request hash and returns an array
34
+ * of the handle, headers file resource, and the body resource.
35
+ * - select_timeout: Optional timeout (in seconds) to block before timing
36
+ * out while selecting curl handles. Defaults to 1 second.
37
+ * - max_handles: Optional integer representing the maximum number of
38
+ * open requests. When this number is reached, the queued futures are
39
+ * flushed.
40
+ *
41
+ * @param array $options
42
+ */
43
+ public function __construct(array $options = [])
44
+ {
45
+ $this->mh = isset($options['mh'])
46
+ ? $options['mh'] : curl_multi_init();
47
+ $this->factory = isset($options['handle_factory'])
48
+ ? $options['handle_factory'] : new CurlFactory();
49
+ $this->selectTimeout = isset($options['select_timeout'])
50
+ ? $options['select_timeout'] : 1;
51
+ $this->maxHandles = isset($options['max_handles'])
52
+ ? $options['max_handles'] : 100;
53
+ }
54
+
55
+ public function __destruct()
56
+ {
57
+ // Finish any open connections before terminating the script.
58
+ if ($this->handles) {
59
+ $this->execute();
60
+ }
61
+
62
+ if ($this->mh) {
63
+ curl_multi_close($this->mh);
64
+ $this->mh = null;
65
+ }
66
+ }
67
+
68
+ public function __invoke(array $request)
69
+ {
70
+ $factory = $this->factory;
71
+ $result = $factory($request);
72
+ $entry = [
73
+ 'request' => $request,
74
+ 'response' => [],
75
+ 'handle' => $result[0],
76
+ 'headers' => &$result[1],
77
+ 'body' => $result[2],
78
+ 'deferred' => new Deferred(),
79
+ ];
80
+
81
+ $id = (int) $result[0];
82
+
83
+ $future = new FutureArray(
84
+ $entry['deferred']->promise(),
85
+ [$this, 'execute'],
86
+ function () use ($id) {
87
+ return $this->cancel($id);
88
+ }
89
+ );
90
+
91
+ $this->addRequest($entry);
92
+
93
+ // Transfer outstanding requests if there are too many open handles.
94
+ if (count($this->handles) >= $this->maxHandles) {
95
+ $this->execute();
96
+ }
97
+
98
+ return $future;
99
+ }
100
+
101
+ /**
102
+ * Runs until all outstanding connections have completed.
103
+ */
104
+ public function execute()
105
+ {
106
+ do {
107
+
108
+ if ($this->active &&
109
+ curl_multi_select($this->mh, $this->selectTimeout) === -1
110
+ ) {
111
+ // Perform a usleep if a select returns -1.
112
+ // See: https://bugs.php.net/bug.php?id=61141
113
+ usleep(250);
114
+ }
115
+
116
+ // Add any delayed futures if needed.
117
+ if ($this->delays) {
118
+ $this->addDelays();
119
+ }
120
+
121
+ do {
122
+ $mrc = curl_multi_exec($this->mh, $this->active);
123
+ } while ($mrc === CURLM_CALL_MULTI_PERFORM);
124
+
125
+ $this->processMessages();
126
+
127
+ // If there are delays but no transfers, then sleep for a bit.
128
+ if (!$this->active && $this->delays) {
129
+ usleep(500);
130
+ }
131
+
132
+ } while ($this->active || $this->handles);
133
+ }
134
+
135
+ private function addRequest(array &$entry)
136
+ {
137
+ $id = (int) $entry['handle'];
138
+ $this->handles[$id] = $entry;
139
+
140
+ // If the request is a delay, then add the reques to the curl multi
141
+ // pool only after the specified delay.
142
+ if (isset($entry['request']['client']['delay'])) {
143
+ $this->delays[$id] = microtime(true) + ($entry['request']['client']['delay'] / 1000);
144
+ } elseif (empty($entry['request']['future'])) {
145
+ curl_multi_add_handle($this->mh, $entry['handle']);
146
+ } else {
147
+ curl_multi_add_handle($this->mh, $entry['handle']);
148
+ // "lazy" futures are only sent once the pool has many requests.
149
+ if ($entry['request']['future'] !== 'lazy') {
150
+ do {
151
+ $mrc = curl_multi_exec($this->mh, $this->active);
152
+ } while ($mrc === CURLM_CALL_MULTI_PERFORM);
153
+ $this->processMessages();
154
+ }
155
+ }
156
+ }
157
+
158
+ private function removeProcessed($id)
159
+ {
160
+ if (isset($this->handles[$id])) {
161
+ curl_multi_remove_handle(
162
+ $this->mh,
163
+ $this->handles[$id]['handle']
164
+ );
165
+ curl_close($this->handles[$id]['handle']);
166
+ unset($this->handles[$id], $this->delays[$id]);
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Cancels a handle from sending and removes references to it.
172
+ *
173
+ * @param int $id Handle ID to cancel and remove.
174
+ *
175
+ * @return bool True on success, false on failure.
176
+ */
177
+ private function cancel($id)
178
+ {
179
+ // Cannot cancel if it has been processed.
180
+ if (!isset($this->handles[$id])) {
181
+ return false;
182
+ }
183
+
184
+ $handle = $this->handles[$id]['handle'];
185
+ unset($this->delays[$id], $this->handles[$id]);
186
+ curl_multi_remove_handle($this->mh, $handle);
187
+ curl_close($handle);
188
+
189
+ return true;
190
+ }
191
+
192
+ private function addDelays()
193
+ {
194
+ $currentTime = microtime(true);
195
+
196
+ foreach ($this->delays as $id => $delay) {
197
+ if ($currentTime >= $delay) {
198
+ unset($this->delays[$id]);
199
+ curl_multi_add_handle(
200
+ $this->mh,
201
+ $this->handles[$id]['handle']
202
+ );
203
+ }
204
+ }
205
+ }
206
+
207
+ private function processMessages()
208
+ {
209
+ while ($done = curl_multi_info_read($this->mh)) {
210
+ $id = (int) $done['handle'];
211
+
212
+ if (!isset($this->handles[$id])) {
213
+ // Probably was cancelled.
214
+ continue;
215
+ }
216
+
217
+ $entry = $this->handles[$id];
218
+ $entry['response']['transfer_stats'] = curl_getinfo($done['handle']);
219
+
220
+ if ($done['result'] !== CURLM_OK) {
221
+ $entry['response']['curl']['errno'] = $done['result'];
222
+ if (function_exists('curl_strerror')) {
223
+ $entry['response']['curl']['error'] = curl_strerror($done['result']);
224
+ }
225
+ }
226
+
227
+ $result = CurlFactory::createResponse(
228
+ $this,
229
+ $entry['request'],
230
+ $entry['response'],
231
+ $entry['headers'],
232
+ $entry['body']
233
+ );
234
+
235
+ $this->removeProcessed($id);
236
+ $entry['deferred']->resolve($result);
237
+ }
238
+ }
239
+ }
backend/vendor/guzzlehttp/ringphp/src/Client/Middleware.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Ring\Client;
3
+
4
+ /**
5
+ * Provides basic middleware wrappers.
6
+ *
7
+ * If a middleware is more complex than a few lines of code, then it should
8
+ * be implemented in a class rather than a static method.
9
+ */
10
+ class Middleware
11
+ {
12
+ /**
13
+ * Sends future requests to a future compatible handler while sending all
14
+ * other requests to a default handler.
15
+ *
16
+ * When the "future" option is not provided on a request, any future responses
17
+ * are automatically converted to synchronous responses and block.
18
+ *
19
+ * @param callable $default Handler used for non-streaming responses
20
+ * @param callable $future Handler used for future responses
21
+ *
22
+ * @return callable Returns the composed handler.
23
+ */
24
+ public static function wrapFuture(
25
+ callable $default,
26
+ callable $future
27
+ ) {
28
+ return function (array $request) use ($default, $future) {
29
+ return empty($request['client']['future'])
30
+ ? $default($request)
31
+ : $future($request);
32
+ };
33
+ }
34
+
35
+ /**
36
+ * Sends streaming requests to a streaming compatible handler while sendin
37
+ * all other requests to a default handler.
38
+ *
39
+ * This, for example, could be useful for taking advantage of the
40
+ * performance benefits of curl while still supporting true streaming
41
+ * through the StreamHandler.
42
+ *
43
+ * @param callable $default Handler used for non-streaming responses
44
+ * @param callable $streaming Handler used for streaming responses
45
+ *
46
+ * @return callable Returns the composed handler.
47
+ */
48
+ public static function wrapStreaming(
49
+ callable $default,
50
+ callable $streaming
51
+ ) {
52
+ return function (array $request) use ($default, $streaming) {
53
+ return empty($request['client']['stream'])
54
+ ? $default($request)
55
+ : $streaming($request);
56
+ };
57
+ }
58
+ }
backend/vendor/guzzlehttp/ringphp/src/Client/MockHandler.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Ring\Client;
3
+
4
+ use GuzzleHttp\Ring\Core;
5
+ use GuzzleHttp\Ring\Future\CompletedFutureArray;
6
+ use GuzzleHttp\Ring\Future\FutureArrayInterface;
7
+
8
+ /**
9
+ * Ring handler that returns a canned response or evaluated function result.
10
+ */
11
+ class MockHandler
12
+ {
13
+ /** @var callable|array|FutureArrayInterface */
14
+ private $result;
15
+
16
+ /**
17
+ * Provide an array or future to always return the same value. Provide a
18
+ * callable that accepts a request object and returns an array or future
19
+ * to dynamically create a response.
20
+ *
21
+ * @param array|FutureArrayInterface|callable $result Mock return value.
22
+ */
23
+ public function __construct($result)
24
+ {
25
+ $this->result = $result;
26
+ }
27
+
28
+ public function __invoke(array $request)
29
+ {
30
+ Core::doSleep($request);
31
+ $response = is_callable($this->result)
32
+ ? call_user_func($this->result, $request)
33
+ : $this->result;
34
+
35
+ if (is_array($response)) {
36
+ $response = new CompletedFutureArray($response + [
37
+ 'status' => null,
38
+ 'body' => null,
39
+ 'headers' => [],
40
+ 'reason' => null,
41
+ 'effective_url' => null,
42
+ ]);
43
+ } elseif (!$response instanceof FutureArrayInterface) {
44
+ throw new \InvalidArgumentException(
45
+ 'Response must be an array or FutureArrayInterface. Found '
46
+ . Core::describeType($request)
47
+ );
48
+ }
49
+
50
+ return $response;
51
+ }
52
+ }
backend/vendor/guzzlehttp/ringphp/src/Client/StreamHandler.php ADDED
@@ -0,0 +1,412 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Ring\Client;
3
+
4
+ use GuzzleHttp\Ring\Core;
5
+ use GuzzleHttp\Ring\Exception\ConnectException;
6
+ use GuzzleHttp\Ring\Exception\RingException;
7
+ use GuzzleHttp\Ring\Future\CompletedFutureArray;
8
+ use GuzzleHttp\Stream\InflateStream;
9
+ use GuzzleHttp\Stream\StreamInterface;
10
+ use GuzzleHttp\Stream\Stream;
11
+ use GuzzleHttp\Stream\Utils;
12
+
13
+ /**
14
+ * RingPHP client handler that uses PHP's HTTP stream wrapper.
15
+ */
16
+ class StreamHandler
17
+ {
18
+ private $options;
19
+
20
+ public function __construct(array $options = [])
21
+ {
22
+ $this->options = $options;
23
+ }
24
+
25
+ public function __invoke(array $request)
26
+ {
27
+ $url = Core::url($request);
28
+ Core::doSleep($request);
29
+
30
+ try {
31
+ // Does not support the expect header.
32
+ $request = Core::removeHeader($request, 'Expect');
33
+ $stream = $this->createStream($url, $request, $headers);
34
+ return $this->createResponse($request, $url, $headers, $stream);
35
+ } catch (RingException $e) {
36
+ return $this->createErrorResponse($url, $e);
37
+ }
38
+ }
39
+
40
+ private function createResponse(array $request, $url, array $hdrs, $stream)
41
+ {
42
+ $parts = explode(' ', array_shift($hdrs), 3);
43
+ $response = [
44
+ 'status' => $parts[1],
45
+ 'reason' => isset($parts[2]) ? $parts[2] : null,
46
+ 'headers' => Core::headersFromLines($hdrs),
47
+ 'effective_url' => $url,
48
+ ];
49
+
50
+ $stream = $this->checkDecode($request, $response, $stream);
51
+
52
+ // If not streaming, then drain the response into a stream.
53
+ if (empty($request['client']['stream'])) {
54
+ $dest = isset($request['client']['save_to'])
55
+ ? $request['client']['save_to']
56
+ : fopen('php://temp', 'r+');
57
+ $stream = $this->drain($stream, $dest);
58
+ }
59
+
60
+ $response['body'] = $stream;
61
+
62
+ return new CompletedFutureArray($response);
63
+ }
64
+
65
+ private function checkDecode(array $request, array $response, $stream)
66
+ {
67
+ // Automatically decode responses when instructed.
68
+ if (!empty($request['client']['decode_content'])) {
69
+ switch (Core::firstHeader($response, 'Content-Encoding', true)) {
70
+ case 'gzip':
71
+ case 'deflate':
72
+ $stream = new InflateStream(Stream::factory($stream));
73
+ break;
74
+ }
75
+ }
76
+
77
+ return $stream;
78
+ }
79
+
80
+ /**
81
+ * Drains the stream into the "save_to" client option.
82
+ *
83
+ * @param resource $stream
84
+ * @param string|resource|StreamInterface $dest
85
+ *
86
+ * @return Stream
87
+ * @throws \RuntimeException when the save_to option is invalid.
88
+ */
89
+ private function drain($stream, $dest)
90
+ {
91
+ if (is_resource($stream)) {
92
+ if (!is_resource($dest)) {
93
+ $stream = Stream::factory($stream);
94
+ } else {
95
+ stream_copy_to_stream($stream, $dest);
96
+ fclose($stream);
97
+ rewind($dest);
98
+ return $dest;
99
+ }
100
+ }
101
+
102
+ // Stream the response into the destination stream
103
+ $dest = is_string($dest)
104
+ ? new Stream(Utils::open($dest, 'r+'))
105
+ : Stream::factory($dest);
106
+
107
+ Utils::copyToStream($stream, $dest);
108
+ $dest->seek(0);
109
+ $stream->close();
110
+
111
+ return $dest;
112
+ }
113
+
114
+ /**
115
+ * Creates an error response for the given stream.
116
+ *
117
+ * @param string $url
118
+ * @param RingException $e
119
+ *
120
+ * @return array
121
+ */
122
+ private function createErrorResponse($url, RingException $e)
123
+ {
124
+ // Determine if the error was a networking error.
125
+ $message = $e->getMessage();
126
+
127
+ // This list can probably get more comprehensive.
128
+ if (strpos($message, 'getaddrinfo') // DNS lookup failed
129
+ || strpos($message, 'Connection refused')
130
+ ) {
131
+ $e = new ConnectException($e->getMessage(), 0, $e);
132
+ }
133
+
134
+ return new CompletedFutureArray([
135
+ 'status' => null,
136
+ 'body' => null,
137
+ 'headers' => [],
138
+ 'effective_url' => $url,
139
+ 'error' => $e
140
+ ]);
141
+ }
142
+
143
+ /**
144
+ * Create a resource and check to ensure it was created successfully
145
+ *
146
+ * @param callable $callback Callable that returns stream resource
147
+ *
148
+ * @return resource
149
+ * @throws \RuntimeException on error
150
+ */
151
+ private function createResource(callable $callback)
152
+ {
153
+ $errors = null;
154
+ set_error_handler(function ($_, $msg, $file, $line) use (&$errors) {
155
+ $errors[] = [
156
+ 'message' => $msg,
157
+ 'file' => $file,
158
+ 'line' => $line
159
+ ];
160
+ return true;
161
+ });
162
+
163
+ $resource = $callback();
164
+ restore_error_handler();
165
+
166
+ if (!$resource) {
167
+ $message = 'Error creating resource: ';
168
+ foreach ($errors as $err) {
169
+ foreach ($err as $key => $value) {
170
+ $message .= "[$key] $value" . PHP_EOL;
171
+ }
172
+ }
173
+ throw new RingException(trim($message));
174
+ }
175
+
176
+ return $resource;
177
+ }
178
+
179
+ private function createStream(
180
+ $url,
181
+ array $request,
182
+ &$http_response_header
183
+ ) {
184
+ static $methods;
185
+ if (!$methods) {
186
+ $methods = array_flip(get_class_methods(__CLASS__));
187
+ }
188
+
189
+ // HTTP/1.1 streams using the PHP stream wrapper require a
190
+ // Connection: close header
191
+ if ((!isset($request['version']) || $request['version'] == '1.1')
192
+ && !Core::hasHeader($request, 'Connection')
193
+ ) {
194
+ $request['headers']['Connection'] = ['close'];
195
+ }
196
+
197
+ // Ensure SSL is verified by default
198
+ if (!isset($request['client']['verify'])) {
199
+ $request['client']['verify'] = true;
200
+ }
201
+
202
+ $params = [];
203
+ $options = $this->getDefaultOptions($request);
204
+
205
+ if (isset($request['client'])) {
206
+ foreach ($request['client'] as $key => $value) {
207
+ $method = "add_{$key}";
208
+ if (isset($methods[$method])) {
209
+ $this->{$method}($request, $options, $value, $params);
210
+ }
211
+ }
212
+ }
213
+
214
+ return $this->createStreamResource(
215
+ $url,
216
+ $request,
217
+ $options,
218
+ $this->createContext($request, $options, $params),
219
+ $http_response_header
220
+ );
221
+ }
222
+
223
+ private function getDefaultOptions(array $request)
224
+ {
225
+ $headers = "";
226
+ foreach ($request['headers'] as $name => $value) {
227
+ foreach ((array) $value as $val) {
228
+ $headers .= "$name: $val\r\n";
229
+ }
230
+ }
231
+
232
+ $context = [
233
+ 'http' => [
234
+ 'method' => $request['http_method'],
235
+ 'header' => $headers,
236
+ 'protocol_version' => isset($request['version']) ? $request['version'] : 1.1,
237
+ 'ignore_errors' => true,
238
+ 'follow_location' => 0,
239
+ ],
240
+ ];
241
+
242
+ $body = Core::body($request);
243
+ if (isset($body)) {
244
+ $context['http']['content'] = $body;
245
+ // Prevent the HTTP handler from adding a Content-Type header.
246
+ if (!Core::hasHeader($request, 'Content-Type')) {
247
+ $context['http']['header'] .= "Content-Type:\r\n";
248
+ }
249
+ }
250
+
251
+ $context['http']['header'] = rtrim($context['http']['header']);
252
+
253
+ return $context;
254
+ }
255
+
256
+ private function add_proxy(array $request, &$options, $value, &$params)
257
+ {
258
+ if (!is_array($value)) {
259
+ $options['http']['proxy'] = $value;
260
+ } else {
261
+ $scheme = isset($request['scheme']) ? $request['scheme'] : 'http';
262
+ if (isset($value[$scheme])) {
263
+ $options['http']['proxy'] = $value[$scheme];
264
+ }
265
+ }
266
+ }
267
+
268
+ private function add_timeout(array $request, &$options, $value, &$params)
269
+ {
270
+ $options['http']['timeout'] = $value;
271
+ }
272
+
273
+ private function add_verify(array $request, &$options, $value, &$params)
274
+ {
275
+ if ($value === true) {
276
+ // PHP 5.6 or greater will find the system cert by default. When
277
+ // < 5.6, use the Guzzle bundled cacert.
278
+ if (PHP_VERSION_ID < 50600) {
279
+ $options['ssl']['cafile'] = ClientUtils::getDefaultCaBundle();
280
+ }
281
+ } elseif (is_string($value)) {
282
+ $options['ssl']['cafile'] = $value;
283
+ if (!file_exists($value)) {
284
+ throw new RingException("SSL CA bundle not found: $value");
285
+ }
286
+ } elseif ($value === false) {
287
+ $options['ssl']['verify_peer'] = false;
288
+ return;
289
+ } else {
290
+ throw new RingException('Invalid verify request option');
291
+ }
292
+
293
+ $options['ssl']['verify_peer'] = true;
294
+ $options['ssl']['allow_self_signed'] = true;
295
+ }
296
+
297
+ private function add_cert(array $request, &$options, $value, &$params)
298
+ {
299
+ if (is_array($value)) {
300
+ $options['ssl']['passphrase'] = $value[1];
301
+ $value = $value[0];
302
+ }
303
+
304
+ if (!file_exists($value)) {
305
+ throw new RingException("SSL certificate not found: {$value}");
306
+ }
307
+
308
+ $options['ssl']['local_cert'] = $value;
309
+ }
310
+
311
+ private function add_progress(array $request, &$options, $value, &$params)
312
+ {
313
+ $fn = function ($code, $_, $_, $_, $transferred, $total) use ($value) {
314
+ if ($code == STREAM_NOTIFY_PROGRESS) {
315
+ $value($total, $transferred, null, null);
316
+ }
317
+ };
318
+
319
+ // Wrap the existing function if needed.
320
+ $params['notification'] = isset($params['notification'])
321
+ ? Core::callArray([$params['notification'], $fn])
322
+ : $fn;
323
+ }
324
+
325
+ private function add_debug(array $request, &$options, $value, &$params)
326
+ {
327
+ if ($value === false) {
328
+ return;
329
+ }
330
+
331
+ static $map = [
332
+ STREAM_NOTIFY_CONNECT => 'CONNECT',
333
+ STREAM_NOTIFY_AUTH_REQUIRED => 'AUTH_REQUIRED',
334
+ STREAM_NOTIFY_AUTH_RESULT => 'AUTH_RESULT',
335
+ STREAM_NOTIFY_MIME_TYPE_IS => 'MIME_TYPE_IS',
336
+ STREAM_NOTIFY_FILE_SIZE_IS => 'FILE_SIZE_IS',
337
+ STREAM_NOTIFY_REDIRECTED => 'REDIRECTED',
338
+ STREAM_NOTIFY_PROGRESS => 'PROGRESS',
339
+ STREAM_NOTIFY_FAILURE => 'FAILURE',
340
+ STREAM_NOTIFY_COMPLETED => 'COMPLETED',
341
+ STREAM_NOTIFY_RESOLVE => 'RESOLVE',
342
+ ];
343
+
344
+ static $args = ['severity', 'message', 'message_code',
345
+ 'bytes_transferred', 'bytes_max'];
346
+
347
+ $value = Core::getDebugResource($value);
348
+ $ident = $request['http_method'] . ' ' . Core::url($request);
349
+ $fn = function () use ($ident, $value, $map, $args) {
350
+ $passed = func_get_args();
351
+ $code = array_shift($passed);
352
+ fprintf($value, '<%s> [%s] ', $ident, $map[$code]);
353
+ foreach (array_filter($passed) as $i => $v) {
354
+ fwrite($value, $args[$i] . ': "' . $v . '" ');
355
+ }
356
+ fwrite($value, "\n");
357
+ };
358
+
359
+ // Wrap the existing function if needed.
360
+ $params['notification'] = isset($params['notification'])
361
+ ? Core::callArray([$params['notification'], $fn])
362
+ : $fn;
363
+ }
364
+
365
+ private function applyCustomOptions(array $request, array &$options)
366
+ {
367
+ if (!isset($request['client']['stream_context'])) {
368
+ return;
369
+ }
370
+
371
+ if (!is_array($request['client']['stream_context'])) {
372
+ throw new RingException('stream_context must be an array');
373
+ }
374
+
375
+ $options = array_replace_recursive(
376
+ $options,
377
+ $request['client']['stream_context']
378
+ );
379
+ }
380
+
381
+ private function createContext(array $request, array $options, array $params)
382
+ {
383
+ $this->applyCustomOptions($request, $options);
384
+ return $this->createResource(
385
+ function () use ($request, $options, $params) {
386
+ return stream_context_create($options, $params);
387
+ },
388
+ $request,
389
+ $options
390
+ );
391
+ }
392
+
393
+ private function createStreamResource(
394
+ $url,
395
+ array $request,
396
+ array $options,
397
+ $context,
398
+ &$http_response_header
399
+ ) {
400
+ return $this->createResource(
401
+ function () use ($url, &$http_response_header, $context) {
402
+ if (false === strpos($url, 'http')) {
403
+ trigger_error("URL is invalid: {$url}", E_USER_WARNING);
404
+ return null;
405
+ }
406
+ return fopen($url, 'r', null, $context);
407
+ },
408
+ $request,
409
+ $options
410
+ );
411
+ }
412
+ }
backend/vendor/guzzlehttp/ringphp/src/Core.php ADDED
@@ -0,0 +1,364 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Ring;
3
+
4
+ use GuzzleHttp\Stream\StreamInterface;
5
+ use GuzzleHttp\Ring\Future\FutureArrayInterface;
6
+ use GuzzleHttp\Ring\Future\FutureArray;
7
+
8
+ /**
9
+ * Provides core functionality of Ring handlers and middleware.
10
+ */
11
+ class Core
12
+ {
13
+ /**
14
+ * Returns a function that calls all of the provided functions, in order,
15
+ * passing the arguments provided to the composed function to each function.
16
+ *
17
+ * @param callable[] $functions Array of functions to proxy to.
18
+ *
19
+ * @return callable
20
+ */
21
+ public static function callArray(array $functions)
22
+ {
23
+ return function () use ($functions) {
24
+ $args = func_get_args();
25
+ foreach ($functions as $fn) {
26
+ call_user_func_array($fn, $args);
27
+ }
28
+ };
29
+ }
30
+
31
+ /**
32
+ * Gets an array of header line values from a message for a specific header
33
+ *
34
+ * This method searches through the "headers" key of a message for a header
35
+ * using a case-insensitive search.
36
+ *
37
+ * @param array $message Request or response hash.
38
+ * @param string $header Header to retrieve
39
+ *
40
+ * @return array
41
+ */
42
+ public static function headerLines($message, $header)
43
+ {
44
+ $result = [];
45
+
46
+ if (!empty($message['headers'])) {
47
+ foreach ($message['headers'] as $name => $value) {
48
+ if (!strcasecmp($name, $header)) {
49
+ $result = array_merge($result, $value);
50
+ }
51
+ }
52
+ }
53
+
54
+ return $result;
55
+ }
56
+
57
+ /**
58
+ * Gets a header value from a message as a string or null
59
+ *
60
+ * This method searches through the "headers" key of a message for a header
61
+ * using a case-insensitive search. The lines of the header are imploded
62
+ * using commas into a single string return value.
63
+ *
64
+ * @param array $message Request or response hash.
65
+ * @param string $header Header to retrieve
66
+ *
67
+ * @return string|null Returns the header string if found, or null if not.
68
+ */
69
+ public static function header($message, $header)
70
+ {
71
+ $match = self::headerLines($message, $header);
72
+ return $match ? implode(', ', $match) : null;
73
+ }
74
+
75
+ /**
76
+ * Returns the first header value from a message as a string or null. If
77
+ * a header line contains multiple values separated by a comma, then this
78
+ * function will return the first value in the list.
79
+ *
80
+ * @param array $message Request or response hash.
81
+ * @param string $header Header to retrieve
82
+ *
83
+ * @return string|null Returns the value as a string if found.
84
+ */
85
+ public static function firstHeader($message, $header)
86
+ {
87
+ if (!empty($message['headers'])) {
88
+ foreach ($message['headers'] as $name => $value) {
89
+ if (!strcasecmp($name, $header)) {
90
+ // Return the match itself if it is a single value.
91
+ $pos = strpos($value[0], ',');
92
+ return $pos ? substr($value[0], 0, $pos) : $value[0];
93
+ }
94
+ }
95
+ }
96
+
97
+ return null;
98
+ }
99
+
100
+ /**
101
+ * Returns true if a message has the provided case-insensitive header.
102
+ *
103
+ * @param array $message Request or response hash.
104
+ * @param string $header Header to check
105
+ *
106
+ * @return bool
107
+ */
108
+ public static function hasHeader($message, $header)
109
+ {
110
+ if (!empty($message['headers'])) {
111
+ foreach ($message['headers'] as $name => $value) {
112
+ if (!strcasecmp($name, $header)) {
113
+ return true;
114
+ }
115
+ }
116
+ }
117
+
118
+ return false;
119
+ }
120
+
121
+ /**
122
+ * Parses an array of header lines into an associative array of headers.
123
+ *
124
+ * @param array $lines Header lines array of strings in the following
125
+ * format: "Name: Value"
126
+ * @return array
127
+ */
128
+ public static function headersFromLines($lines)
129
+ {
130
+ $headers = [];
131
+
132
+ foreach ($lines as $line) {
133
+ $parts = explode(':', $line, 2);
134
+ $headers[trim($parts[0])][] = isset($parts[1])
135
+ ? trim($parts[1])
136
+ : null;
137
+ }
138
+
139
+ return $headers;
140
+ }
141
+
142
+ /**
143
+ * Removes a header from a message using a case-insensitive comparison.
144
+ *
145
+ * @param array $message Message that contains 'headers'
146
+ * @param string $header Header to remove
147
+ *
148
+ * @return array
149
+ */
150
+ public static function removeHeader(array $message, $header)
151
+ {
152
+ if (isset($message['headers'])) {
153
+ foreach (array_keys($message['headers']) as $key) {
154
+ if (!strcasecmp($header, $key)) {
155
+ unset($message['headers'][$key]);
156
+ }
157
+ }
158
+ }
159
+
160
+ return $message;
161
+ }
162
+
163
+ /**
164
+ * Replaces any existing case insensitive headers with the given value.
165
+ *
166
+ * @param array $message Message that contains 'headers'
167
+ * @param string $header Header to set.
168
+ * @param array $value Value to set.
169
+ *
170
+ * @return array
171
+ */
172
+ public static function setHeader(array $message, $header, array $value)
173
+ {
174
+ $message = self::removeHeader($message, $header);
175
+ $message['headers'][$header] = $value;
176
+
177
+ return $message;
178
+ }
179
+
180
+ /**
181
+ * Creates a URL string from a request.
182
+ *
183
+ * If the "url" key is present on the request, it is returned, otherwise
184
+ * the url is built up based on the scheme, host, uri, and query_string
185
+ * request values.
186
+ *
187
+ * @param array $request Request to get the URL from
188
+ *
189
+ * @return string Returns the request URL as a string.
190
+ * @throws \InvalidArgumentException if no Host header is present.
191
+ */
192
+ public static function url(array $request)
193
+ {
194
+ if (isset($request['url'])) {
195
+ return $request['url'];
196
+ }
197
+
198
+ $uri = (isset($request['scheme'])
199
+ ? $request['scheme'] : 'http') . '://';
200
+
201
+ if ($host = self::header($request, 'host')) {
202
+ $uri .= $host;
203
+ } else {
204
+ throw new \InvalidArgumentException('No Host header was provided');
205
+ }
206
+
207
+ if (isset($request['uri'])) {
208
+ $uri .= $request['uri'];
209
+ }
210
+
211
+ if (isset($request['query_string'])) {
212
+ $uri .= '?' . $request['query_string'];
213
+ }
214
+
215
+ return $uri;
216
+ }
217
+
218
+ /**
219
+ * Reads the body of a message into a string.
220
+ *
221
+ * @param array|FutureArrayInterface $message Array containing a "body" key
222
+ *
223
+ * @return null|string Returns the body as a string or null if not set.
224
+ * @throws \InvalidArgumentException if a request body is invalid.
225
+ */
226
+ public static function body($message)
227
+ {
228
+ if (!isset($message['body'])) {
229
+ return null;
230
+ }
231
+
232
+ if ($message['body'] instanceof StreamInterface) {
233
+ return (string) $message['body'];
234
+ }
235
+
236
+ switch (gettype($message['body'])) {
237
+ case 'string':
238
+ return $message['body'];
239
+ case 'resource':
240
+ return stream_get_contents($message['body']);
241
+ case 'object':
242
+ if ($message['body'] instanceof \Iterator) {
243
+ return implode('', iterator_to_array($message['body']));
244
+ } elseif (method_exists($message['body'], '__toString')) {
245
+ return (string) $message['body'];
246
+ }
247
+ default:
248
+ throw new \InvalidArgumentException('Invalid request body: '
249
+ . self::describeType($message['body']));
250
+ }
251
+ }
252
+
253
+ /**
254
+ * Rewind the body of the provided message if possible.
255
+ *
256
+ * @param array $message Message that contains a 'body' field.
257
+ *
258
+ * @return bool Returns true on success, false on failure
259
+ */
260
+ public static function rewindBody($message)
261
+ {
262
+ if ($message['body'] instanceof StreamInterface) {
263
+ return $message['body']->seek(0);
264
+ }
265
+
266
+ if ($message['body'] instanceof \Generator) {
267
+ return false;
268
+ }
269
+
270
+ if ($message['body'] instanceof \Iterator) {
271
+ $message['body']->rewind();
272
+ return true;
273
+ }
274
+
275
+ if (is_resource($message['body'])) {
276
+ return rewind($message['body']);
277
+ }
278
+
279
+ return is_string($message['body'])
280
+ || (is_object($message['body'])
281
+ && method_exists($message['body'], '__toString'));
282
+ }
283
+
284
+ /**
285
+ * Debug function used to describe the provided value type and class.
286
+ *
287
+ * @param mixed $input
288
+ *
289
+ * @return string Returns a string containing the type of the variable and
290
+ * if a class is provided, the class name.
291
+ */
292
+ public static function describeType($input)
293
+ {
294
+ switch (gettype($input)) {
295
+ case 'object':
296
+ return 'object(' . get_class($input) . ')';
297
+ case 'array':
298
+ return 'array(' . count($input) . ')';
299
+ default:
300
+ ob_start();
301
+ var_dump($input);
302
+ // normalize float vs double
303
+ return str_replace('double(', 'float(', rtrim(ob_get_clean()));
304
+ }
305
+ }
306
+
307
+ /**
308
+ * Sleep for the specified amount of time specified in the request's
309
+ * ['client']['delay'] option if present.
310
+ *
311
+ * This function should only be used when a non-blocking sleep is not
312
+ * possible.
313
+ *
314
+ * @param array $request Request to sleep
315
+ */
316
+ public static function doSleep(array $request)
317
+ {
318
+ if (isset($request['client']['delay'])) {
319
+ usleep($request['client']['delay'] * 1000);
320
+ }
321
+ }
322
+
323
+ /**
324
+ * Returns a proxied future that modifies the dereferenced value of another
325
+ * future using a promise.
326
+ *
327
+ * @param FutureArrayInterface $future Future to wrap with a new future
328
+ * @param callable $onFulfilled Invoked when the future fulfilled
329
+ * @param callable $onRejected Invoked when the future rejected
330
+ * @param callable $onProgress Invoked when the future progresses
331
+ *
332
+ * @return FutureArray
333
+ */
334
+ public static function proxy(
335
+ FutureArrayInterface $future,
336
+ callable $onFulfilled = null,
337
+ callable $onRejected = null,
338
+ callable $onProgress = null
339
+ ) {
340
+ return new FutureArray(
341
+ $future->then($onFulfilled, $onRejected, $onProgress),
342
+ [$future, 'wait'],
343
+ [$future, 'cancel']
344
+ );
345
+ }
346
+
347
+ /**
348
+ * Returns a debug stream based on the provided variable.
349
+ *
350
+ * @param mixed $value Optional value
351
+ *
352
+ * @return resource
353
+ */
354
+ public static function getDebugResource($value = null)
355
+ {
356
+ if (is_resource($value)) {
357
+ return $value;
358
+ } elseif (defined('STDOUT')) {
359
+ return STDOUT;
360
+ } else {
361
+ return fopen('php://output', 'w');
362
+ }
363
+ }
364
+ }
backend/vendor/guzzlehttp/ringphp/src/Exception/CancelledException.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Ring\Exception;
3
+
4
+ /**
5
+ * Marker interface for cancelled exceptions.
6
+ */
7
+ interface CancelledException {}
backend/vendor/guzzlehttp/ringphp/src/Exception/CancelledFutureAccessException.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Ring\Exception;
3
+
4
+ class CancelledFutureAccessException extends RingException implements CancelledException {}
backend/vendor/guzzlehttp/ringphp/src/Exception/ConnectException.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Ring\Exception;
3
+
4
+ /**
5
+ * Occurs when the connection failed.
6
+ */
7
+ class ConnectException extends RingException {}
backend/vendor/guzzlehttp/ringphp/src/Exception/RingException.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Ring\Exception;
3
+
4
+ class RingException extends \RuntimeException {};
backend/vendor/guzzlehttp/ringphp/src/Future/BaseFutureTrait.php ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Ring\Future;
3
+
4
+ use GuzzleHttp\Ring\Exception\CancelledFutureAccessException;
5
+ use GuzzleHttp\Ring\Exception\RingException;
6
+ use React\Promise\PromiseInterface;
7
+
8
+ /**
9
+ * Implements common future functionality built on top of promises.
10
+ */
11
+ trait BaseFutureTrait
12
+ {
13
+ /** @var callable */
14
+ private $waitfn;
15
+
16
+ /** @var callable */
17
+ private $cancelfn;
18
+
19
+ /** @var PromiseInterface */
20
+ private $wrappedPromise;
21
+
22
+ /** @var \Exception Error encountered. */
23
+ private $error;
24
+
25
+ /** @var mixed Result of the future */
26
+ private $result;
27
+
28
+ private $isRealized = false;
29
+
30
+ /**
31
+ * @param PromiseInterface $promise Promise to shadow with the future.
32
+ * @param callable $wait Function that blocks until the deferred
33
+ * computation has been resolved. This
34
+ * function MUST resolve the deferred value
35
+ * associated with the supplied promise.
36
+ * @param callable $cancel If possible and reasonable, provide a
37
+ * function that can be used to cancel the
38
+ * future from completing.
39
+ */
40
+ public function __construct(
41
+ PromiseInterface $promise,
42
+ callable $wait = null,
43
+ callable $cancel = null
44
+ ) {
45
+ $this->wrappedPromise = $promise;
46
+ $this->waitfn = $wait;
47
+ $this->cancelfn = $cancel;
48
+ }
49
+
50
+ public function wait()
51
+ {
52
+ if (!$this->isRealized) {
53
+ $this->addShadow();
54
+ if (!$this->isRealized && $this->waitfn) {
55
+ $this->invokeWait();
56
+ }
57
+ if (!$this->isRealized) {
58
+ $this->error = new RingException('Waiting did not resolve future');
59
+ }
60
+ }
61
+
62
+ if ($this->error) {
63
+ throw $this->error;
64
+ }
65
+
66
+ return $this->result;
67
+ }
68
+
69
+ public function promise()
70
+ {
71
+ return $this->wrappedPromise;
72
+ }
73
+
74
+ public function then(
75
+ callable $onFulfilled = null,
76
+ callable $onRejected = null,
77
+ callable $onProgress = null
78
+ ) {
79
+ return $this->wrappedPromise->then($onFulfilled, $onRejected, $onProgress);
80
+ }
81
+
82
+ public function cancel()
83
+ {
84
+ if (!$this->isRealized) {
85
+ $cancelfn = $this->cancelfn;
86
+ $this->waitfn = $this->cancelfn = null;
87
+ $this->isRealized = true;
88
+ $this->error = new CancelledFutureAccessException();
89
+ if ($cancelfn) {
90
+ $cancelfn($this);
91
+ }
92
+ }
93
+ }
94
+
95
+ private function addShadow()
96
+ {
97
+ // Get the result and error when the promise is resolved. Note that
98
+ // calling this function might trigger the resolution immediately.
99
+ $this->wrappedPromise->then(
100
+ function ($value) {
101
+ $this->isRealized = true;
102
+ $this->result = $value;
103
+ $this->waitfn = $this->cancelfn = null;
104
+ },
105
+ function ($error) {
106
+ $this->isRealized = true;
107
+ $this->error = $error;
108
+ $this->waitfn = $this->cancelfn = null;
109
+ }
110
+ );
111
+ }
112
+
113
+ private function invokeWait()
114
+ {
115
+ try {
116
+ $wait = $this->waitfn;
117
+ $this->waitfn = null;
118
+ $wait();
119
+ } catch (\Exception $e) {
120
+ // Defer can throw to reject.
121
+ $this->error = $e;
122
+ $this->isRealized = true;
123
+ }
124
+ }
125
+ }
backend/vendor/guzzlehttp/ringphp/src/Future/CompletedFutureArray.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Ring\Future;
3
+
4
+ /**
5
+ * Represents a future array that has been completed successfully.
6
+ */
7
+ class CompletedFutureArray extends CompletedFutureValue implements FutureArrayInterface
8
+ {
9
+ public function __construct(array $result)
10
+ {
11
+ parent::__construct($result);
12
+ }
13
+
14
+ public function offsetExists($offset)
15
+ {
16
+ return isset($this->result[$offset]);
17
+ }
18
+
19
+ public function offsetGet($offset)
20
+ {
21
+ return $this->result[$offset];
22
+ }
23
+
24
+ public function offsetSet($offset, $value)
25
+ {
26
+ $this->result[$offset] = $value;
27
+ }
28
+
29
+ public function offsetUnset($offset)
30
+ {
31
+ unset($this->result[$offset]);
32
+ }
33
+
34
+ public function count()
35
+ {
36
+ return count($this->result);
37
+ }
38
+
39
+ public function getIterator()
40
+ {
41
+ return new \ArrayIterator($this->result);
42
+ }
43
+ }
backend/vendor/guzzlehttp/ringphp/src/Future/CompletedFutureValue.php ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Ring\Future;
3
+
4
+ use React\Promise\FulfilledPromise;
5
+ use React\Promise\RejectedPromise;
6
+
7
+ /**
8
+ * Represents a future value that has been resolved or rejected.
9
+ */
10
+ class CompletedFutureValue implements FutureInterface
11
+ {
12
+ protected $result;
13
+ protected $error;
14
+
15
+ private $cachedPromise;
16
+
17
+ /**
18
+ * @param mixed $result Resolved result
19
+ * @param \Exception $e Error. Pass a GuzzleHttp\Ring\Exception\CancelledFutureAccessException
20
+ * to mark the future as cancelled.
21
+ */
22
+ public function __construct($result, \Exception $e = null)
23
+ {
24
+ $this->result = $result;
25
+ $this->error = $e;
26
+ }
27
+
28
+ public function wait()
29
+ {
30
+ if ($this->error) {
31
+ throw $this->error;
32
+ }
33
+
34
+ return $this->result;
35
+ }
36
+
37
+ public function cancel() {}
38
+
39
+ public function promise()
40
+ {
41
+ if (!$this->cachedPromise) {
42
+ $this->cachedPromise = $this->error
43
+ ? new RejectedPromise($this->error)
44
+ : new FulfilledPromise($this->result);
45
+ }
46
+
47
+ return $this->cachedPromise;
48
+ }
49
+
50
+ public function then(
51
+ callable $onFulfilled = null,
52
+ callable $onRejected = null,
53
+ callable $onProgress = null
54
+ ) {
55
+ return $this->promise()->then($onFulfilled, $onRejected, $onProgress);
56
+ }
57
+ }
backend/vendor/guzzlehttp/ringphp/src/Future/FutureArray.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Ring\Future;
3
+
4
+ /**
5
+ * Represents a future array value that when dereferenced returns an array.
6
+ */
7
+ class FutureArray implements FutureArrayInterface
8
+ {
9
+ use MagicFutureTrait;
10
+
11
+ public function offsetExists($offset)
12
+ {
13
+ return isset($this->_value[$offset]);
14
+ }
15
+
16
+ public function offsetGet($offset)
17
+ {
18
+ return $this->_value[$offset];
19
+ }
20
+
21
+ public function offsetSet($offset, $value)
22
+ {
23
+ $this->_value[$offset] = $value;
24
+ }
25
+
26
+ public function offsetUnset($offset)
27
+ {
28
+ unset($this->_value[$offset]);
29
+ }
30
+
31
+ public function count()
32
+ {
33
+ return count($this->_value);
34
+ }
35
+
36
+ public function getIterator()
37
+ {
38
+ return new \ArrayIterator($this->_value);
39
+ }
40
+ }
backend/vendor/guzzlehttp/ringphp/src/Future/FutureArrayInterface.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Ring\Future;
3
+
4
+ /**
5
+ * Future that provides array-like access.
6
+ */
7
+ interface FutureArrayInterface extends
8
+ FutureInterface,
9
+ \ArrayAccess,
10
+ \Countable,
11
+ \IteratorAggregate {};
backend/vendor/guzzlehttp/ringphp/src/Future/FutureInterface.php ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Ring\Future;
3
+
4
+ use React\Promise\PromiseInterface;
5
+ use React\Promise\PromisorInterface;
6
+
7
+ /**
8
+ * Represents the result of a computation that may not have completed yet.
9
+ *
10
+ * You can use the future in a blocking manner using the wait() function, or
11
+ * you can use a promise from the future to receive the result when the future
12
+ * has been resolved.
13
+ *
14
+ * When the future is dereferenced using wait(), the result of the computation
15
+ * is cached and returned for subsequent calls to wait(). If the result of the
16
+ * computation has not yet completed when wait() is called, the call to wait()
17
+ * will block until the future has completed.
18
+ */
19
+ interface FutureInterface extends PromisorInterface
20
+ {
21
+ /**
22
+ * Returns the result of the future either from cache or by blocking until
23
+ * it is complete.
24
+ *
25
+ * This method must block until the future has a result or is cancelled.
26
+ * Throwing an exception in the wait() method will mark the future as
27
+ * realized and will throw the exception each time wait() is called.
28
+ * Throwing an instance of GuzzleHttp\Ring\CancelledException will mark
29
+ * the future as realized, will not throw immediately, but will throw the
30
+ * exception if the future's wait() method is called again.
31
+ *
32
+ * @return mixed
33
+ */
34
+ public function wait();
35
+
36
+ /**
37
+ * Cancels the future, if possible.
38
+ */
39
+ public function cancel();
40
+
41
+ /**
42
+ * Create and return a promise that invokes the given methods when the
43
+ * future has a value, exception, or progress events.
44
+ *
45
+ * @param callable $onFulfilled Called when the promise is resolved.
46
+ * @param callable $onRejected Called when the promise is rejected.
47
+ * @param callable $onProgress Called on progress events.
48
+ *
49
+ * @return PromiseInterface
50
+ */
51
+ public function then(
52
+ callable $onFulfilled = null,
53
+ callable $onRejected = null,
54
+ callable $onProgress = null
55
+ );
56
+ }
backend/vendor/guzzlehttp/ringphp/src/Future/FutureValue.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Ring\Future;
3
+
4
+ /**
5
+ * Represents a future value that responds to wait() to retrieve the promised
6
+ * value, but can also return promises that are delivered the value when it is
7
+ * available.
8
+ */
9
+ class FutureValue implements FutureInterface
10
+ {
11
+ use BaseFutureTrait;
12
+ }
backend/vendor/guzzlehttp/ringphp/src/Future/MagicFutureTrait.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Ring\Future;
3
+
4
+ /**
5
+ * Implements common future functionality that is triggered when the result
6
+ * property is accessed via a magic __get method.
7
+ *
8
+ * @property mixed $_value Actual data used by the future. Accessing this
9
+ * property will cause the future to block if needed.
10
+ */
11
+ trait MagicFutureTrait
12
+ {
13
+ use BaseFutureTrait;
14
+
15
+ /**
16
+ * This function handles retrieving the dereferenced result when requested.
17
+ *
18
+ * @param string $name Should always be "data" or an exception is thrown.
19
+ *
20
+ * @return mixed Returns the dereferenced data.
21
+ * @throws \RuntimeException
22
+ * @throws \GuzzleHttp\Ring\Exception\CancelledException
23
+ */
24
+ public function __get($name)
25
+ {
26
+ if ($name !== '_value') {
27
+ throw new \RuntimeException("Class has no {$name} property");
28
+ }
29
+
30
+ return $this->_value = $this->wait();
31
+ }
32
+ }
backend/vendor/guzzlehttp/ringphp/tests/Client/CurlFactoryTest.php ADDED
@@ -0,0 +1,792 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // Override curl_setopt_array() to get the last set curl options
3
+ namespace GuzzleHttp\Ring\Client {
4
+ function curl_setopt_array($handle, array $options) {
5
+ if (!empty($_SERVER['curl_test'])) {
6
+ $_SERVER['_curl'] = $options;
7
+ } else {
8
+ unset($_SERVER['_curl']);
9
+ }
10
+ \curl_setopt_array($handle, $options);
11
+ }
12
+ }
13
+
14
+ namespace GuzzleHttp\Tests\Ring\Client {
15
+
16
+ use GuzzleHttp\Ring\Client\CurlFactory;
17
+ use GuzzleHttp\Ring\Client\CurlMultiHandler;
18
+ use GuzzleHttp\Ring\Client\MockHandler;
19
+ use GuzzleHttp\Ring\Core;
20
+ use GuzzleHttp\Stream\FnStream;
21
+ use GuzzleHttp\Stream\NoSeekStream;
22
+ use GuzzleHttp\Stream\Stream;
23
+
24
+ class CurlFactoryTest extends \PHPUnit_Framework_TestCase
25
+ {
26
+ public static function setUpBeforeClass()
27
+ {
28
+ $_SERVER['curl_test'] = true;
29
+ unset($_SERVER['_curl']);
30
+ }
31
+
32
+ public static function tearDownAfterClass()
33
+ {
34
+ unset($_SERVER['_curl'], $_SERVER['curl_test']);
35
+ }
36
+
37
+ public function testCreatesCurlHandle()
38
+ {
39
+ Server::flush();
40
+ Server::enqueue([[
41
+ 'status' => 200,
42
+ 'headers' => [
43
+ 'Foo' => ['Bar'],
44
+ 'Baz' => ['bam'],
45
+ 'Content-Length' => [2],
46
+ ],
47
+ 'body' => 'hi',
48
+ ]]);
49
+
50
+ $stream = Stream::factory();
51
+
52
+ $request = [
53
+ 'http_method' => 'PUT',
54
+ 'headers' => [
55
+ 'host' => [Server::$url],
56
+ 'Hi' => [' 123'],
57
+ ],
58
+ 'body' => 'testing',
59
+ 'client' => ['save_to' => $stream],
60
+ ];
61
+
62
+ $f = new CurlFactory();
63
+ $result = $f($request);
64
+ $this->assertInternalType('array', $result);
65
+ $this->assertCount(3, $result);
66
+ $this->assertInternalType('resource', $result[0]);
67
+ $this->assertInternalType('array', $result[1]);
68
+ $this->assertSame($stream, $result[2]);
69
+ curl_close($result[0]);
70
+
71
+ $this->assertEquals('PUT', $_SERVER['_curl'][CURLOPT_CUSTOMREQUEST]);
72
+ $this->assertEquals(
73
+ 'http://http://127.0.0.1:8125/',
74
+ $_SERVER['_curl'][CURLOPT_URL]
75
+ );
76
+ // Sends via post fields when the request is small enough
77
+ $this->assertEquals('testing', $_SERVER['_curl'][CURLOPT_POSTFIELDS]);
78
+ $this->assertEquals(0, $_SERVER['_curl'][CURLOPT_RETURNTRANSFER]);
79
+ $this->assertEquals(0, $_SERVER['_curl'][CURLOPT_HEADER]);
80
+ $this->assertEquals(150, $_SERVER['_curl'][CURLOPT_CONNECTTIMEOUT]);
81
+ $this->assertInstanceOf('Closure', $_SERVER['_curl'][CURLOPT_HEADERFUNCTION]);
82
+
83
+ if (defined('CURLOPT_PROTOCOLS')) {
84
+ $this->assertEquals(
85
+ CURLPROTO_HTTP | CURLPROTO_HTTPS,
86
+ $_SERVER['_curl'][CURLOPT_PROTOCOLS]
87
+ );
88
+ }
89
+
90
+ $this->assertContains('Expect:', $_SERVER['_curl'][CURLOPT_HTTPHEADER]);
91
+ $this->assertContains('Accept:', $_SERVER['_curl'][CURLOPT_HTTPHEADER]);
92
+ $this->assertContains('Content-Type:', $_SERVER['_curl'][CURLOPT_HTTPHEADER]);
93
+ $this->assertContains('Hi: 123', $_SERVER['_curl'][CURLOPT_HTTPHEADER]);
94
+ $this->assertContains('host: http://127.0.0.1:8125/', $_SERVER['_curl'][CURLOPT_HTTPHEADER]);
95
+ }
96
+
97
+ public function testSendsHeadRequests()
98
+ {
99
+ Server::flush();
100
+ Server::enqueue([['status' => 200]]);
101
+ $a = new CurlMultiHandler();
102
+ $response = $a([
103
+ 'http_method' => 'HEAD',
104
+ 'headers' => ['host' => [Server::$host]],
105
+ ]);
106
+ $response->wait();
107
+ $this->assertEquals(true, $_SERVER['_curl'][CURLOPT_NOBODY]);
108
+ $checks = [CURLOPT_WRITEFUNCTION, CURLOPT_READFUNCTION, CURLOPT_FILE, CURLOPT_INFILE];
109
+ foreach ($checks as $check) {
110
+ $this->assertArrayNotHasKey($check, $_SERVER['_curl']);
111
+ }
112
+ $this->assertEquals('HEAD', Server::received()[0]['http_method']);
113
+ }
114
+
115
+ public function testCanAddCustomCurlOptions()
116
+ {
117
+ Server::flush();
118
+ Server::enqueue([['status' => 200]]);
119
+ $a = new CurlMultiHandler();
120
+ $a([
121
+ 'http_method' => 'GET',
122
+ 'headers' => ['host' => [Server::$host]],
123
+ 'client' => ['curl' => [CURLOPT_LOW_SPEED_LIMIT => 10]],
124
+ ]);
125
+ $this->assertEquals(10, $_SERVER['_curl'][CURLOPT_LOW_SPEED_LIMIT]);
126
+ }
127
+
128
+ /**
129
+ * @expectedException \InvalidArgumentException
130
+ * @expectedExceptionMessage SSL CA bundle not found: /does/not/exist
131
+ */
132
+ public function testValidatesVerify()
133
+ {
134
+ $f = new CurlFactory();
135
+ $f([
136
+ 'http_method' => 'GET',
137
+ 'headers' => ['host' => ['foo.com']],
138
+ 'client' => ['verify' => '/does/not/exist'],
139
+ ]);
140
+ }
141
+
142
+ public function testCanSetVerifyToFile()
143
+ {
144
+ $f = new CurlFactory();
145
+ $f([
146
+ 'http_method' => 'GET',
147
+ 'headers' => ['host' => ['foo.com']],
148
+ 'client' => ['verify' => __FILE__],
149
+ ]);
150
+ $this->assertEquals(__FILE__, $_SERVER['_curl'][CURLOPT_CAINFO]);
151
+ $this->assertEquals(2, $_SERVER['_curl'][CURLOPT_SSL_VERIFYHOST]);
152
+ $this->assertEquals(true, $_SERVER['_curl'][CURLOPT_SSL_VERIFYPEER]);
153
+ }
154
+
155
+ public function testAddsVerifyAsTrue()
156
+ {
157
+ $f = new CurlFactory();
158
+ $f([
159
+ 'http_method' => 'GET',
160
+ 'headers' => ['host' => ['foo.com']],
161
+ 'client' => ['verify' => true],
162
+ ]);
163
+ $this->assertEquals(2, $_SERVER['_curl'][CURLOPT_SSL_VERIFYHOST]);
164
+ $this->assertEquals(true, $_SERVER['_curl'][CURLOPT_SSL_VERIFYPEER]);
165
+ $this->assertArrayNotHasKey(CURLOPT_CAINFO, $_SERVER['_curl']);
166
+ }
167
+
168
+ public function testCanDisableVerify()
169
+ {
170
+ $f = new CurlFactory();
171
+ $f([
172
+ 'http_method' => 'GET',
173
+ 'headers' => ['host' => ['foo.com']],
174
+ 'client' => ['verify' => false],
175
+ ]);
176
+ $this->assertEquals(0, $_SERVER['_curl'][CURLOPT_SSL_VERIFYHOST]);
177
+ $this->assertEquals(false, $_SERVER['_curl'][CURLOPT_SSL_VERIFYPEER]);
178
+ }
179
+
180
+ public function testAddsProxy()
181
+ {
182
+ $f = new CurlFactory();
183
+ $f([
184
+ 'http_method' => 'GET',
185
+ 'headers' => ['host' => ['foo.com']],
186
+ 'client' => ['proxy' => 'http://bar.com'],
187
+ ]);
188
+ $this->assertEquals('http://bar.com', $_SERVER['_curl'][CURLOPT_PROXY]);
189
+ }
190
+
191
+ public function testAddsViaScheme()
192
+ {
193
+ $f = new CurlFactory();
194
+ $f([
195
+ 'http_method' => 'GET',
196
+ 'scheme' => 'http',
197
+ 'headers' => ['host' => ['foo.com']],
198
+ 'client' => [
199
+ 'proxy' => ['http' => 'http://bar.com', 'https' => 'https://t'],
200
+ ],
201
+ ]);
202
+ $this->assertEquals('http://bar.com', $_SERVER['_curl'][CURLOPT_PROXY]);
203
+ }
204
+
205
+ /**
206
+ * @expectedException \InvalidArgumentException
207
+ * @expectedExceptionMessage SSL private key not found: /does/not/exist
208
+ */
209
+ public function testValidatesSslKey()
210
+ {
211
+ $f = new CurlFactory();
212
+ $f([
213
+ 'http_method' => 'GET',
214
+ 'headers' => ['host' => ['foo.com']],
215
+ 'client' => ['ssl_key' => '/does/not/exist'],
216
+ ]);
217
+ }
218
+
219
+ public function testAddsSslKey()
220
+ {
221
+ $f = new CurlFactory();
222
+ $f([
223
+ 'http_method' => 'GET',
224
+ 'headers' => ['host' => ['foo.com']],
225
+ 'client' => ['ssl_key' => __FILE__],
226
+ ]);
227
+ $this->assertEquals(__FILE__, $_SERVER['_curl'][CURLOPT_SSLKEY]);
228
+ }
229
+
230
+ public function testAddsSslKeyWithPassword()
231
+ {
232
+ $f = new CurlFactory();
233
+ $f([
234
+ 'http_method' => 'GET',
235
+ 'headers' => ['host' => ['foo.com']],
236
+ 'client' => ['ssl_key' => [__FILE__, 'test']],
237
+ ]);
238
+ $this->assertEquals(__FILE__, $_SERVER['_curl'][CURLOPT_SSLKEY]);
239
+ $this->assertEquals('test', $_SERVER['_curl'][CURLOPT_SSLKEYPASSWD]);
240
+ }
241
+
242
+ /**
243
+ * @expectedException \InvalidArgumentException
244
+ * @expectedExceptionMessage SSL certificate not found: /does/not/exist
245
+ */
246
+ public function testValidatesCert()
247
+ {
248
+ $f = new CurlFactory();
249
+ $f([
250
+ 'http_method' => 'GET',
251
+ 'headers' => ['host' => ['foo.com']],
252
+ 'client' => ['cert' => '/does/not/exist'],
253
+ ]);
254
+ }
255
+
256
+ public function testAddsCert()
257
+ {
258
+ $f = new CurlFactory();
259
+ $f([
260
+ 'http_method' => 'GET',
261
+ 'headers' => ['host' => ['foo.com']],
262
+ 'client' => ['cert' => __FILE__],
263
+ ]);
264
+ $this->assertEquals(__FILE__, $_SERVER['_curl'][CURLOPT_SSLCERT]);
265
+ }
266
+
267
+ public function testAddsCertWithPassword()
268
+ {
269
+ $f = new CurlFactory();
270
+ $f([
271
+ 'http_method' => 'GET',
272
+ 'headers' => ['host' => ['foo.com']],
273
+ 'client' => ['cert' => [__FILE__, 'test']],
274
+ ]);
275
+ $this->assertEquals(__FILE__, $_SERVER['_curl'][CURLOPT_SSLCERT]);
276
+ $this->assertEquals('test', $_SERVER['_curl'][CURLOPT_SSLCERTPASSWD]);
277
+ }
278
+
279
+ /**
280
+ * @expectedException \InvalidArgumentException
281
+ * @expectedExceptionMessage progress client option must be callable
282
+ */
283
+ public function testValidatesProgress()
284
+ {
285
+ $f = new CurlFactory();
286
+ $f([
287
+ 'http_method' => 'GET',
288
+ 'headers' => ['host' => ['foo.com']],
289
+ 'client' => ['progress' => 'foo'],
290
+ ]);
291
+ }
292
+
293
+ public function testEmitsDebugInfoToStream()
294
+ {
295
+ $res = fopen('php://memory', 'r+');
296
+ Server::flush();
297
+ Server::enqueue([['status' => 200]]);
298
+ $a = new CurlMultiHandler();
299
+ $response = $a([
300
+ 'http_method' => 'HEAD',
301
+ 'headers' => ['host' => [Server::$host]],
302
+ 'client' => ['debug' => $res],
303
+ ]);
304
+ $response->wait();
305
+ rewind($res);
306
+ $output = str_replace("\r", '', stream_get_contents($res));
307
+ $this->assertContains(
308
+ "> HEAD / HTTP/1.1\nhost: 127.0.0.1:8125\n\n",
309
+ $output
310
+ );
311
+ $this->assertContains("< HTTP/1.1 200", $output);
312
+ fclose($res);
313
+ }
314
+
315
+ public function testEmitsProgressToFunction()
316
+ {
317
+ Server::flush();
318
+ Server::enqueue([['status' => 200]]);
319
+ $a = new CurlMultiHandler();
320
+ $called = [];
321
+ $response = $a([
322
+ 'http_method' => 'HEAD',
323
+ 'headers' => ['host' => [Server::$host]],
324
+ 'client' => [
325
+ 'progress' => function () use (&$called) {
326
+ $called[] = func_get_args();
327
+ },
328
+ ],
329
+ ]);
330
+ $response->wait();
331
+ $this->assertNotEmpty($called);
332
+ foreach ($called as $call) {
333
+ $this->assertCount(4, $call);
334
+ }
335
+ }
336
+
337
+ private function addDecodeResponse($withEncoding = true)
338
+ {
339
+ $content = gzencode('test');
340
+ $response = [
341
+ 'status' => 200,
342
+ 'reason' => 'OK',
343
+ 'headers' => ['Content-Length' => [strlen($content)]],
344
+ 'body' => $content,
345
+ ];
346
+
347
+ if ($withEncoding) {
348
+ $response['headers']['Content-Encoding'] = ['gzip'];
349
+ }
350
+
351
+ Server::flush();
352
+ Server::enqueue([$response]);
353
+
354
+ return $content;
355
+ }
356
+
357
+ public function testDecodesGzippedResponses()
358
+ {
359
+ $this->addDecodeResponse();
360
+ $handler = new CurlMultiHandler();
361
+ $response = $handler([
362
+ 'http_method' => 'GET',
363
+ 'headers' => ['host' => [Server::$host]],
364
+ 'client' => ['decode_content' => true],
365
+ ]);
366
+ $response->wait();
367
+ $this->assertEquals('test', Core::body($response));
368
+ $this->assertEquals('', $_SERVER['_curl'][CURLOPT_ENCODING]);
369
+ $sent = Server::received()[0];
370
+ $this->assertNull(Core::header($sent, 'Accept-Encoding'));
371
+ }
372
+
373
+ public function testDecodesGzippedResponsesWithHeader()
374
+ {
375
+ $this->addDecodeResponse();
376
+ $handler = new CurlMultiHandler();
377
+ $response = $handler([
378
+ 'http_method' => 'GET',
379
+ 'headers' => [
380
+ 'host' => [Server::$host],
381
+ 'Accept-Encoding' => ['gzip'],
382
+ ],
383
+ 'client' => ['decode_content' => true],
384
+ ]);
385
+ $response->wait();
386
+ $this->assertEquals('gzip', $_SERVER['_curl'][CURLOPT_ENCODING]);
387
+ $sent = Server::received()[0];
388
+ $this->assertEquals('gzip', Core::header($sent, 'Accept-Encoding'));
389
+ $this->assertEquals('test', Core::body($response));
390
+ }
391
+
392
+ public function testDoesNotForceDecode()
393
+ {
394
+ $content = $this->addDecodeResponse();
395
+ $handler = new CurlMultiHandler();
396
+ $response = $handler([
397
+ 'http_method' => 'GET',
398
+ 'headers' => ['host' => [Server::$host]],
399
+ 'client' => ['decode_content' => false],
400
+ ]);
401
+ $response->wait();
402
+ $sent = Server::received()[0];
403
+ $this->assertNull(Core::header($sent, 'Accept-Encoding'));
404
+ $this->assertEquals($content, Core::body($response));
405
+ }
406
+
407
+ public function testProtocolVersion()
408
+ {
409
+ Server::flush();
410
+ Server::enqueue([['status' => 200]]);
411
+ $a = new CurlMultiHandler();
412
+ $a([
413
+ 'http_method' => 'GET',
414
+ 'headers' => ['host' => [Server::$host]],
415
+ 'version' => 1.0,
416
+ ]);
417
+ $this->assertEquals(CURL_HTTP_VERSION_1_0, $_SERVER['_curl'][CURLOPT_HTTP_VERSION]);
418
+ }
419
+
420
+ /**
421
+ * @expectedException \InvalidArgumentException
422
+ */
423
+ public function testValidatesSaveTo()
424
+ {
425
+ $handler = new CurlMultiHandler();
426
+ $handler([
427
+ 'http_method' => 'GET',
428
+ 'headers' => ['host' => [Server::$host]],
429
+ 'client' => ['save_to' => true],
430
+ ]);
431
+ }
432
+
433
+ public function testSavesToStream()
434
+ {
435
+ $stream = fopen('php://memory', 'r+');
436
+ $this->addDecodeResponse();
437
+ $handler = new CurlMultiHandler();
438
+ $response = $handler([
439
+ 'http_method' => 'GET',
440
+ 'headers' => ['host' => [Server::$host]],
441
+ 'client' => [
442
+ 'decode_content' => true,
443
+ 'save_to' => $stream,
444
+ ],
445
+ ]);
446
+ $response->wait();
447
+ rewind($stream);
448
+ $this->assertEquals('test', stream_get_contents($stream));
449
+ }
450
+
451
+ public function testSavesToGuzzleStream()
452
+ {
453
+ $stream = Stream::factory();
454
+ $this->addDecodeResponse();
455
+ $handler = new CurlMultiHandler();
456
+ $response = $handler([
457
+ 'http_method' => 'GET',
458
+ 'headers' => ['host' => [Server::$host]],
459
+ 'client' => [
460
+ 'decode_content' => true,
461
+ 'save_to' => $stream,
462
+ ],
463
+ ]);
464
+ $response->wait();
465
+ $this->assertEquals('test', (string) $stream);
466
+ }
467
+
468
+ public function testSavesToFileOnDisk()
469
+ {
470
+ $tmpfile = tempnam(sys_get_temp_dir(), 'testfile');
471
+ $this->addDecodeResponse();
472
+ $handler = new CurlMultiHandler();
473
+ $response = $handler([
474
+ 'http_method' => 'GET',
475
+ 'headers' => ['host' => [Server::$host]],
476
+ 'client' => [
477
+ 'decode_content' => true,
478
+ 'save_to' => $tmpfile,
479
+ ],
480
+ ]);
481
+ $response->wait();
482
+ $this->assertEquals('test', file_get_contents($tmpfile));
483
+ unlink($tmpfile);
484
+ }
485
+
486
+ /**
487
+ * @expectedException \InvalidArgumentException
488
+ */
489
+ public function testValidatesBody()
490
+ {
491
+ $handler = new CurlMultiHandler();
492
+ $handler([
493
+ 'http_method' => 'GET',
494
+ 'headers' => ['host' => [Server::$host]],
495
+ 'body' => false,
496
+ ]);
497
+ }
498
+
499
+ public function testAddsLargePayloadFromStreamWithNoSizeUsingChunked()
500
+ {
501
+ $stream = Stream::factory('foo');
502
+ $stream = FnStream::decorate($stream, [
503
+ 'getSize' => function () {
504
+ return null;
505
+ }
506
+ ]);
507
+ $this->addDecodeResponse();
508
+ $handler = new CurlMultiHandler();
509
+ $response = $handler([
510
+ 'http_method' => 'GET',
511
+ 'headers' => ['host' => [Server::$host]],
512
+ 'body' => $stream,
513
+ ]);
514
+ $response->wait();
515
+ $sent = Server::received()[0];
516
+ $this->assertEquals('chunked', Core::header($sent, 'Transfer-Encoding'));
517
+ $this->assertNull(Core::header($sent, 'Content-Length'));
518
+ $this->assertEquals('foo', $sent['body']);
519
+ }
520
+
521
+ public function testAddsPayloadFromIterator()
522
+ {
523
+ $iter = new \ArrayIterator(['f', 'o', 'o']);
524
+ $this->addDecodeResponse();
525
+ $handler = new CurlMultiHandler();
526
+ $response = $handler([
527
+ 'http_method' => 'GET',
528
+ 'headers' => ['host' => [Server::$host]],
529
+ 'body' => $iter,
530
+ ]);
531
+ $response->wait();
532
+ $sent = Server::received()[0];
533
+ $this->assertEquals('chunked', Core::header($sent, 'Transfer-Encoding'));
534
+ $this->assertNull(Core::header($sent, 'Content-Length'));
535
+ $this->assertEquals('foo', $sent['body']);
536
+ }
537
+
538
+ public function testAddsPayloadFromResource()
539
+ {
540
+ $res = fopen('php://memory', 'r+');
541
+ $data = str_repeat('.', 1000000);
542
+ fwrite($res, $data);
543
+ rewind($res);
544
+ $this->addDecodeResponse();
545
+ $handler = new CurlMultiHandler();
546
+ $response = $handler([
547
+ 'http_method' => 'GET',
548
+ 'headers' => [
549
+ 'host' => [Server::$host],
550
+ 'content-length' => [1000000],
551
+ ],
552
+ 'body' => $res,
553
+ ]);
554
+ $response->wait();
555
+ $sent = Server::received()[0];
556
+ $this->assertNull(Core::header($sent, 'Transfer-Encoding'));
557
+ $this->assertEquals(1000000, Core::header($sent, 'Content-Length'));
558
+ $this->assertEquals($data, $sent['body']);
559
+ }
560
+
561
+ public function testAddsContentLengthFromStream()
562
+ {
563
+ $stream = Stream::factory('foo');
564
+ $this->addDecodeResponse();
565
+ $handler = new CurlMultiHandler();
566
+ $response = $handler([
567
+ 'http_method' => 'GET',
568
+ 'headers' => ['host' => [Server::$host]],
569
+ 'body' => $stream,
570
+ ]);
571
+ $response->wait();
572
+ $sent = Server::received()[0];
573
+ $this->assertEquals(3, Core::header($sent, 'Content-Length'));
574
+ $this->assertNull(Core::header($sent, 'Transfer-Encoding'));
575
+ $this->assertEquals('foo', $sent['body']);
576
+ }
577
+
578
+ public function testDoesNotAddMultipleContentLengthHeaders()
579
+ {
580
+ $this->addDecodeResponse();
581
+ $handler = new CurlMultiHandler();
582
+ $response = $handler([
583
+ 'http_method' => 'GET',
584
+ 'headers' => [
585
+ 'host' => [Server::$host],
586
+ 'content-length' => [3],
587
+ ],
588
+ 'body' => 'foo',
589
+ ]);
590
+ $response->wait();
591
+ $sent = Server::received()[0];
592
+ $this->assertEquals(3, Core::header($sent, 'Content-Length'));
593
+ $this->assertNull(Core::header($sent, 'Transfer-Encoding'));
594
+ $this->assertEquals('foo', $sent['body']);
595
+ }
596
+
597
+ public function testSendsPostWithNoBodyOrDefaultContentType()
598
+ {
599
+ Server::flush();
600
+ Server::enqueue([['status' => 200]]);
601
+ $handler = new CurlMultiHandler();
602
+ $response = $handler([
603
+ 'http_method' => 'POST',
604
+ 'uri' => '/',
605
+ 'headers' => ['host' => [Server::$host]],
606
+ ]);
607
+ $response->wait();
608
+ $received = Server::received()[0];
609
+ $this->assertEquals('POST', $received['http_method']);
610
+ $this->assertNull(Core::header($received, 'content-type'));
611
+ $this->assertSame('0', Core::firstHeader($received, 'content-length'));
612
+ }
613
+
614
+ public function testFailsWhenNoResponseAndNoBody()
615
+ {
616
+ $res = CurlFactory::createResponse(function () {}, [], [], [], null);
617
+ $this->assertInstanceOf('GuzzleHttp\Ring\Exception\RingException', $res['error']);
618
+ $this->assertContains(
619
+ 'No response was received for a request with no body',
620
+ $res['error']->getMessage()
621
+ );
622
+ }
623
+
624
+ public function testFailsWhenCannotRewindRetry()
625
+ {
626
+ $res = CurlFactory::createResponse(function () {}, [
627
+ 'body' => new NoSeekStream(Stream::factory('foo'))
628
+ ], [], [], null);
629
+ $this->assertInstanceOf('GuzzleHttp\Ring\Exception\RingException', $res['error']);
630
+ $this->assertContains(
631
+ 'rewind the request body failed',
632
+ $res['error']->getMessage()
633
+ );
634
+ }
635
+
636
+ public function testRetriesWhenBodyCanBeRewound()
637
+ {
638
+ $callHandler = $called = false;
639
+ $res = CurlFactory::createResponse(function () use (&$callHandler) {
640
+ $callHandler = true;
641
+ return ['status' => 200];
642
+ }, [
643
+ 'body' => FnStream::decorate(Stream::factory('test'), [
644
+ 'seek' => function () use (&$called) {
645
+ $called = true;
646
+ return true;
647
+ }
648
+ ])
649
+ ], [], [], null);
650
+
651
+ $this->assertTrue($callHandler);
652
+ $this->assertTrue($called);
653
+ $this->assertEquals('200', $res['status']);
654
+ }
655
+
656
+ public function testFailsWhenRetryMoreThanThreeTimes()
657
+ {
658
+ $call = 0;
659
+ $mock = new MockHandler(function (array $request) use (&$mock, &$call) {
660
+ $call++;
661
+ return CurlFactory::createResponse($mock, $request, [], [], null);
662
+ });
663
+ $response = $mock([
664
+ 'http_method' => 'GET',
665
+ 'body' => 'test',
666
+ ]);
667
+ $this->assertEquals(3, $call);
668
+ $this->assertArrayHasKey('error', $response);
669
+ $this->assertContains(
670
+ 'The cURL request was retried 3 times',
671
+ $response['error']->getMessage()
672
+ );
673
+ }
674
+
675
+ public function testHandles100Continue()
676
+ {
677
+ Server::flush();
678
+ Server::enqueue([
679
+ [
680
+ 'status' => '200',
681
+ 'reason' => 'OK',
682
+ 'headers' => [
683
+ 'Test' => ['Hello'],
684
+ 'Content-Length' => ['4'],
685
+ ],
686
+ 'body' => 'test',
687
+ ],
688
+ ]);
689
+
690
+ $request = [
691
+ 'http_method' => 'PUT',
692
+ 'headers' => [
693
+ 'Host' => [Server::$host],
694
+ 'Expect' => ['100-Continue'],
695
+ ],
696
+ 'body' => 'test',
697
+ ];
698
+
699
+ $handler = new CurlMultiHandler();
700
+ $response = $handler($request)->wait();
701
+ $this->assertEquals(200, $response['status']);
702
+ $this->assertEquals('OK', $response['reason']);
703
+ $this->assertEquals(['Hello'], $response['headers']['Test']);
704
+ $this->assertEquals(['4'], $response['headers']['Content-Length']);
705
+ $this->assertEquals('test', Core::body($response));
706
+ }
707
+
708
+ public function testCreatesConnectException()
709
+ {
710
+ $m = new \ReflectionMethod('GuzzleHttp\Ring\Client\CurlFactory', 'createErrorResponse');
711
+ $m->setAccessible(true);
712
+ $response = $m->invoke(
713
+ null,
714
+ function () {},
715
+ [],
716
+ [
717
+ 'err_message' => 'foo',
718
+ 'curl' => [
719
+ 'errno' => CURLE_COULDNT_CONNECT,
720
+ ]
721
+ ]
722
+ );
723
+ $this->assertInstanceOf('GuzzleHttp\Ring\Exception\ConnectException', $response['error']);
724
+ }
725
+
726
+ public function testParsesLastResponseOnly()
727
+ {
728
+ $response1 = [
729
+ 'status' => 301,
730
+ 'headers' => [
731
+ 'Content-Length' => ['0'],
732
+ 'Location' => ['/foo']
733
+ ]
734
+ ];
735
+
736
+ $response2 = [
737
+ 'status' => 200,
738
+ 'headers' => [
739
+ 'Content-Length' => ['0'],
740
+ 'Foo' => ['bar']
741
+ ]
742
+ ];
743
+
744
+ Server::flush();
745
+ Server::enqueue([$response1, $response2]);
746
+
747
+ $a = new CurlMultiHandler();
748
+ $response = $a([
749
+ 'http_method' => 'GET',
750
+ 'headers' => ['Host' => [Server::$host]],
751
+ 'client' => [
752
+ 'curl' => [
753
+ CURLOPT_FOLLOWLOCATION => true
754
+ ]
755
+ ]
756
+ ])->wait();
757
+
758
+ $this->assertEquals(1, $response['transfer_stats']['redirect_count']);
759
+ $this->assertEquals('http://127.0.0.1:8125/foo', $response['effective_url']);
760
+ $this->assertEquals(['bar'], $response['headers']['Foo']);
761
+ $this->assertEquals(200, $response['status']);
762
+ $this->assertFalse(Core::hasHeader($response, 'Location'));
763
+ }
764
+
765
+ public function testMaintainsMultiHeaderOrder()
766
+ {
767
+ Server::flush();
768
+ Server::enqueue([
769
+ [
770
+ 'status' => 200,
771
+ 'headers' => [
772
+ 'Content-Length' => ['0'],
773
+ 'Foo' => ['a', 'b'],
774
+ 'foo' => ['c', 'd'],
775
+ ]
776
+ ]
777
+ ]);
778
+
779
+ $a = new CurlMultiHandler();
780
+ $response = $a([
781
+ 'http_method' => 'GET',
782
+ 'headers' => ['Host' => [Server::$host]]
783
+ ])->wait();
784
+
785
+ $this->assertEquals(
786
+ ['a', 'b', 'c', 'd'],
787
+ Core::headerLines($response, 'Foo')
788
+ );
789
+ }
790
+ }
791
+
792
+ }
backend/vendor/guzzlehttp/ringphp/tests/Client/CurlHandlerTest.php ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests\Ring\Client;
3
+
4
+ use GuzzleHttp\Ring\Client\CurlHandler;
5
+
6
+ class CurlHandlerTest extends \PHPUnit_Framework_TestCase
7
+ {
8
+ protected function setUp()
9
+ {
10
+ if (!function_exists('curl_reset')) {
11
+ $this->markTestSkipped('curl_reset() is not available');
12
+ }
13
+ }
14
+
15
+ protected function getHandler($factory = null, $options = [])
16
+ {
17
+ return new CurlHandler($options);
18
+ }
19
+
20
+ public function testCanSetMaxHandles()
21
+ {
22
+ $a = new CurlHandler(['max_handles' => 10]);
23
+ $this->assertEquals(10, $this->readAttribute($a, 'maxHandles'));
24
+ }
25
+
26
+ public function testCreatesCurlErrors()
27
+ {
28
+ $handler = new CurlHandler();
29
+ $response = $handler([
30
+ 'http_method' => 'GET',
31
+ 'uri' => '/',
32
+ 'headers' => ['host' => ['localhost:123']],
33
+ 'client' => ['timeout' => 0.001, 'connect_timeout' => 0.001],
34
+ ]);
35
+ $this->assertNull($response['status']);
36
+ $this->assertNull($response['reason']);
37
+ $this->assertEquals([], $response['headers']);
38
+ $this->assertInstanceOf(
39
+ 'GuzzleHttp\Ring\Exception\RingException',
40
+ $response['error']
41
+ );
42
+
43
+ $this->assertEquals(
44
+ 1,
45
+ preg_match('/^cURL error \d+: .*$/', $response['error']->getMessage())
46
+ );
47
+ }
48
+
49
+ public function testReleasesAdditionalEasyHandles()
50
+ {
51
+ Server::flush();
52
+ $response = [
53
+ 'status' => 200,
54
+ 'headers' => ['Content-Length' => [4]],
55
+ 'body' => 'test',
56
+ ];
57
+
58
+ Server::enqueue([$response, $response, $response, $response]);
59
+ $a = new CurlHandler(['max_handles' => 2]);
60
+
61
+ $fn = function () use (&$calls, $a, &$fn) {
62
+ if (++$calls < 4) {
63
+ $a([
64
+ 'http_method' => 'GET',
65
+ 'headers' => ['host' => [Server::$host]],
66
+ 'client' => ['progress' => $fn],
67
+ ]);
68
+ }
69
+ };
70
+
71
+ $request = [
72
+ 'http_method' => 'GET',
73
+ 'headers' => ['host' => [Server::$host]],
74
+ 'client' => [
75
+ 'progress' => $fn,
76
+ ],
77
+ ];
78
+
79
+ $a($request);
80
+ $this->assertCount(2, $this->readAttribute($a, 'handles'));
81
+ }
82
+
83
+ public function testReusesHandles()
84
+ {
85
+ Server::flush();
86
+ $response = ['status' => 200];
87
+ Server::enqueue([$response, $response]);
88
+ $a = new CurlHandler();
89
+ $request = [
90
+ 'http_method' => 'GET',
91
+ 'headers' => ['host' => [Server::$host]],
92
+ ];
93
+ $a($request);
94
+ $a($request);
95
+ }
96
+ }
backend/vendor/guzzlehttp/ringphp/tests/Client/CurlMultiHandlerTest.php ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests\Ring\Client;
3
+
4
+ use GuzzleHttp\Ring\Client\CurlMultiHandler;
5
+
6
+ class CurlMultiHandlerTest extends \PHPUnit_Framework_TestCase
7
+ {
8
+ public function testSendsRequest()
9
+ {
10
+ Server::enqueue([['status' => 200]]);
11
+ $a = new CurlMultiHandler();
12
+ $response = $a([
13
+ 'http_method' => 'GET',
14
+ 'headers' => ['host' => [Server::$host]],
15
+ ]);
16
+ $this->assertInstanceOf('GuzzleHttp\Ring\Future\FutureArray', $response);
17
+ $this->assertEquals(200, $response['status']);
18
+ $this->assertArrayHasKey('transfer_stats', $response);
19
+ $realUrl = trim($response['transfer_stats']['url'], '/');
20
+ $this->assertEquals(trim(Server::$url, '/'), $realUrl);
21
+ $this->assertArrayHasKey('effective_url', $response);
22
+ $this->assertEquals(
23
+ trim(Server::$url, '/'),
24
+ trim($response['effective_url'], '/')
25
+ );
26
+ }
27
+
28
+ public function testCreatesErrorResponses()
29
+ {
30
+ $url = 'http://localhost:123/';
31
+ $a = new CurlMultiHandler();
32
+ $response = $a([
33
+ 'http_method' => 'GET',
34
+ 'headers' => ['host' => ['localhost:123']],
35
+ ]);
36
+ $this->assertInstanceOf('GuzzleHttp\Ring\Future\FutureArray', $response);
37
+ $this->assertNull($response['status']);
38
+ $this->assertNull($response['reason']);
39
+ $this->assertEquals([], $response['headers']);
40
+ $this->assertArrayHasKey('error', $response);
41
+ $this->assertContains('cURL error ', $response['error']->getMessage());
42
+ $this->assertArrayHasKey('transfer_stats', $response);
43
+ $this->assertEquals(
44
+ trim($url, '/'),
45
+ trim($response['transfer_stats']['url'], '/')
46
+ );
47
+ $this->assertArrayHasKey('effective_url', $response);
48
+ $this->assertEquals(
49
+ trim($url, '/'),
50
+ trim($response['effective_url'], '/')
51
+ );
52
+ }
53
+
54
+ public function testSendsFuturesWhenDestructed()
55
+ {
56
+ Server::enqueue([['status' => 200]]);
57
+ $a = new CurlMultiHandler();
58
+ $response = $a([
59
+ 'http_method' => 'GET',
60
+ 'headers' => ['host' => [Server::$host]],
61
+ ]);
62
+ $this->assertInstanceOf('GuzzleHttp\Ring\Future\FutureArray', $response);
63
+ $a->__destruct();
64
+ $this->assertEquals(200, $response['status']);
65
+ }
66
+
67
+ public function testCanSetMaxHandles()
68
+ {
69
+ $a = new CurlMultiHandler(['max_handles' => 2]);
70
+ $this->assertEquals(2, $this->readAttribute($a, 'maxHandles'));
71
+ }
72
+
73
+ public function testCanSetSelectTimeout()
74
+ {
75
+ $a = new CurlMultiHandler(['select_timeout' => 2]);
76
+ $this->assertEquals(2, $this->readAttribute($a, 'selectTimeout'));
77
+ }
78
+
79
+ public function testSendsFuturesWhenMaxHandlesIsReached()
80
+ {
81
+ $request = [
82
+ 'http_method' => 'PUT',
83
+ 'headers' => ['host' => [Server::$host]],
84
+ 'future' => 'lazy', // passing this to control the test
85
+ ];
86
+ $response = ['status' => 200];
87
+ Server::flush();
88
+ Server::enqueue([$response, $response, $response]);
89
+ $a = new CurlMultiHandler(['max_handles' => 3]);
90
+ for ($i = 0; $i < 5; $i++) {
91
+ $responses[] = $a($request);
92
+ }
93
+ $this->assertCount(3, Server::received());
94
+ $responses[3]->cancel();
95
+ $responses[4]->cancel();
96
+ }
97
+
98
+ public function testCanCancel()
99
+ {
100
+ Server::flush();
101
+ $response = ['status' => 200];
102
+ Server::enqueue(array_fill_keys(range(0, 10), $response));
103
+ $a = new CurlMultiHandler();
104
+ $responses = [];
105
+
106
+ for ($i = 0; $i < 10; $i++) {
107
+ $response = $a([
108
+ 'http_method' => 'GET',
109
+ 'headers' => ['host' => [Server::$host]],
110
+ 'future' => 'lazy',
111
+ ]);
112
+ $response->cancel();
113
+ $responses[] = $response;
114
+ }
115
+
116
+ $this->assertCount(0, Server::received());
117
+
118
+ foreach ($responses as $response) {
119
+ $this->assertTrue($this->readAttribute($response, 'isRealized'));
120
+ }
121
+ }
122
+
123
+ public function testCannotCancelFinished()
124
+ {
125
+ Server::flush();
126
+ Server::enqueue([['status' => 200]]);
127
+ $a = new CurlMultiHandler();
128
+ $response = $a([
129
+ 'http_method' => 'GET',
130
+ 'headers' => ['host' => [Server::$host]],
131
+ ]);
132
+ $response->wait();
133
+ $response->cancel();
134
+ }
135
+
136
+ public function testDelaysInParallel()
137
+ {
138
+ Server::flush();
139
+ Server::enqueue([['status' => 200]]);
140
+ $a = new CurlMultiHandler();
141
+ $expected = microtime(true) + (100 / 1000);
142
+ $response = $a([
143
+ 'http_method' => 'GET',
144
+ 'headers' => ['host' => [Server::$host]],
145
+ 'client' => ['delay' => 100],
146
+ ]);
147
+ $response->wait();
148
+ $this->assertGreaterThanOrEqual($expected, microtime(true));
149
+ }
150
+
151
+ public function testSendsNonLazyFutures()
152
+ {
153
+ $request = [
154
+ 'http_method' => 'GET',
155
+ 'headers' => ['host' => [Server::$host]],
156
+ 'future' => true,
157
+ ];
158
+ Server::flush();
159
+ Server::enqueue([['status' => 202]]);
160
+ $a = new CurlMultiHandler();
161
+ $response = $a($request);
162
+ $this->assertInstanceOf('GuzzleHttp\Ring\Future\FutureArray', $response);
163
+ $this->assertEquals(202, $response['status']);
164
+ }
165
+ }
backend/vendor/guzzlehttp/ringphp/tests/Client/MiddlewareTest.php ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests\Ring\Client;
3
+
4
+ use GuzzleHttp\Ring\Client\Middleware;
5
+ use GuzzleHttp\Ring\Future\CompletedFutureArray;
6
+
7
+ class MiddlewareTest extends \PHPUnit_Framework_TestCase
8
+ {
9
+ public function testFutureCallsDefaultHandler()
10
+ {
11
+ $future = new CompletedFutureArray(['status' => 200]);
12
+ $calledA = false;
13
+ $a = function (array $req) use (&$calledA, $future) {
14
+ $calledA = true;
15
+ return $future;
16
+ };
17
+ $calledB = false;
18
+ $b = function (array $req) use (&$calledB) { $calledB = true; };
19
+ $s = Middleware::wrapFuture($a, $b);
20
+ $s([]);
21
+ $this->assertTrue($calledA);
22
+ $this->assertFalse($calledB);
23
+ }
24
+
25
+ public function testFutureCallsStreamingHandler()
26
+ {
27
+ $future = new CompletedFutureArray(['status' => 200]);
28
+ $calledA = false;
29
+ $a = function (array $req) use (&$calledA) { $calledA = true; };
30
+ $calledB = false;
31
+ $b = function (array $req) use (&$calledB, $future) {
32
+ $calledB = true;
33
+ return $future;
34
+ };
35
+ $s = Middleware::wrapFuture($a, $b);
36
+ $result = $s(['client' => ['future' => true]]);
37
+ $this->assertFalse($calledA);
38
+ $this->assertTrue($calledB);
39
+ $this->assertSame($future, $result);
40
+ }
41
+
42
+ public function testStreamingCallsDefaultHandler()
43
+ {
44
+ $calledA = false;
45
+ $a = function (array $req) use (&$calledA) { $calledA = true; };
46
+ $calledB = false;
47
+ $b = function (array $req) use (&$calledB) { $calledB = true; };
48
+ $s = Middleware::wrapStreaming($a, $b);
49
+ $s([]);
50
+ $this->assertTrue($calledA);
51
+ $this->assertFalse($calledB);
52
+ }
53
+
54
+ public function testStreamingCallsStreamingHandler()
55
+ {
56
+ $calledA = false;
57
+ $a = function (array $req) use (&$calledA) { $calledA = true; };
58
+ $calledB = false;
59
+ $b = function (array $req) use (&$calledB) { $calledB = true; };
60
+ $s = Middleware::wrapStreaming($a, $b);
61
+ $s(['client' => ['stream' => true]]);
62
+ $this->assertFalse($calledA);
63
+ $this->assertTrue($calledB);
64
+ }
65
+ }
backend/vendor/guzzlehttp/ringphp/tests/Client/MockHandlerTest.php ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests\Ring\Client;
3
+
4
+ use GuzzleHttp\Ring\Client\MockHandler;
5
+ use GuzzleHttp\Ring\Future\FutureArray;
6
+ use React\Promise\Deferred;
7
+
8
+ class MockHandlerTest extends \PHPUnit_Framework_TestCase
9
+ {
10
+ public function testReturnsArray()
11
+ {
12
+ $mock = new MockHandler(['status' => 200]);
13
+ $response = $mock([]);
14
+ $this->assertEquals(200, $response['status']);
15
+ $this->assertEquals([], $response['headers']);
16
+ $this->assertNull($response['body']);
17
+ $this->assertNull($response['reason']);
18
+ $this->assertNull($response['effective_url']);
19
+ }
20
+
21
+ public function testReturnsFutures()
22
+ {
23
+ $deferred = new Deferred();
24
+ $future = new FutureArray(
25
+ $deferred->promise(),
26
+ function () use ($deferred) {
27
+ $deferred->resolve(['status' => 200]);
28
+ }
29
+ );
30
+ $mock = new MockHandler($future);
31
+ $response = $mock([]);
32
+ $this->assertInstanceOf('GuzzleHttp\Ring\Future\FutureArray', $response);
33
+ $this->assertEquals(200, $response['status']);
34
+ }
35
+
36
+ public function testReturnsFuturesWithThenCall()
37
+ {
38
+ $deferred = new Deferred();
39
+ $future = new FutureArray(
40
+ $deferred->promise(),
41
+ function () use ($deferred) {
42
+ $deferred->resolve(['status' => 200]);
43
+ }
44
+ );
45
+ $mock = new MockHandler($future);
46
+ $response = $mock([]);
47
+ $this->assertInstanceOf('GuzzleHttp\Ring\Future\FutureArray', $response);
48
+ $this->assertEquals(200, $response['status']);
49
+ $req = null;
50
+ $promise = $response->then(function ($value) use (&$req) {
51
+ $req = $value;
52
+ $this->assertEquals(200, $req['status']);
53
+ });
54
+ $this->assertInstanceOf('React\Promise\PromiseInterface', $promise);
55
+ $this->assertEquals(200, $req['status']);
56
+ }
57
+
58
+ public function testReturnsFuturesAndProxiesCancel()
59
+ {
60
+ $c = null;
61
+ $deferred = new Deferred();
62
+ $future = new FutureArray(
63
+ $deferred->promise(),
64
+ function () {},
65
+ function () use (&$c) {
66
+ $c = true;
67
+ return true;
68
+ }
69
+ );
70
+ $mock = new MockHandler($future);
71
+ $response = $mock([]);
72
+ $this->assertInstanceOf('GuzzleHttp\Ring\Future\FutureArray', $response);
73
+ $response->cancel();
74
+ $this->assertTrue($c);
75
+ }
76
+
77
+ /**
78
+ * @expectedException \InvalidArgumentException
79
+ * @expectedExceptionMessage Response must be an array or FutureArrayInterface. Found
80
+ */
81
+ public function testEnsuresMockIsValid()
82
+ {
83
+ $mock = new MockHandler('foo');
84
+ $mock([]);
85
+ }
86
+ }
backend/vendor/guzzlehttp/ringphp/tests/Client/Server.php ADDED
@@ -0,0 +1,183 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests\Ring\Client;
3
+
4
+ use GuzzleHttp\Ring\Client\StreamHandler;
5
+ use GuzzleHttp\Ring\Core;
6
+
7
+ /**
8
+ * Class uses to control the test webserver.
9
+ *
10
+ * Queued responses will be served to requests using a FIFO order. All requests
11
+ * received by the server are stored on the node.js server and can be retrieved
12
+ * by calling {@see Server::received()}.
13
+ *
14
+ * Mock responses that don't require data to be transmitted over HTTP a great
15
+ * for testing. Mock response, however, cannot test the actual sending of an
16
+ * HTTP request using cURL. This test server allows the simulation of any
17
+ * number of HTTP request response transactions to test the actual sending of
18
+ * requests over the wire without having to leave an internal network.
19
+ */
20
+ class Server
21
+ {
22
+ public static $started;
23
+ public static $url = 'http://127.0.0.1:8125/';
24
+ public static $host = '127.0.0.1:8125';
25
+ public static $port = 8125;
26
+
27
+ /**
28
+ * Flush the received requests from the server
29
+ * @throws \RuntimeException
30
+ */
31
+ public static function flush()
32
+ {
33
+ self::send('DELETE', '/guzzle-server/requests');
34
+ }
35
+
36
+ /**
37
+ * Queue an array of responses or a single response on the server.
38
+ *
39
+ * Any currently queued responses will be overwritten. Subsequent requests
40
+ * on the server will return queued responses in FIFO order.
41
+ *
42
+ * @param array $responses An array of responses. The shape of a response
43
+ * is the shape described in the RingPHP spec.
44
+ * @throws \Exception
45
+ */
46
+ public static function enqueue(array $responses)
47
+ {
48
+ $data = [];
49
+
50
+ foreach ($responses as $response) {
51
+ if (!is_array($response)) {
52
+ throw new \Exception('Each response must be an array');
53
+ }
54
+
55
+ if (isset($response['body'])) {
56
+ $response['body'] = base64_encode($response['body']);
57
+ }
58
+
59
+ $response += ['headers' => [], 'reason' => '', 'body' => ''];
60
+ $data[] = $response;
61
+ }
62
+
63
+ self::send('PUT', '/guzzle-server/responses', json_encode($data));
64
+ }
65
+
66
+ /**
67
+ * Get all of the received requests as a RingPHP request structure.
68
+ *
69
+ * @return array
70
+ * @throws \RuntimeException
71
+ */
72
+ public static function received()
73
+ {
74
+ if (!self::$started) {
75
+ return [];
76
+ }
77
+
78
+ $response = self::send('GET', '/guzzle-server/requests');
79
+ $body = Core::body($response);
80
+ $result = json_decode($body, true);
81
+ if ($result === false) {
82
+ throw new \RuntimeException('Error decoding response: '
83
+ . json_last_error());
84
+ }
85
+
86
+ foreach ($result as &$res) {
87
+ if (isset($res['uri'])) {
88
+ $res['resource'] = $res['uri'];
89
+ }
90
+ if (isset($res['query_string'])) {
91
+ $res['resource'] .= '?' . $res['query_string'];
92
+ }
93
+ if (!isset($res['resource'])) {
94
+ $res['resource'] = '';
95
+ }
96
+ // Ensure that headers are all arrays
97
+ if (isset($res['headers'])) {
98
+ foreach ($res['headers'] as &$h) {
99
+ $h = (array) $h;
100
+ }
101
+ unset($h);
102
+ }
103
+ }
104
+
105
+ unset($res);
106
+ return $result;
107
+ }
108
+
109
+ /**
110
+ * Stop running the node.js server
111
+ */
112
+ public static function stop()
113
+ {
114
+ if (self::$started) {
115
+ self::send('DELETE', '/guzzle-server');
116
+ }
117
+
118
+ self::$started = false;
119
+ }
120
+
121
+ public static function wait($maxTries = 20)
122
+ {
123
+ $tries = 0;
124
+ while (!self::isListening() && ++$tries < $maxTries) {
125
+ usleep(100000);
126
+ }
127
+
128
+ if (!self::isListening()) {
129
+ throw new \RuntimeException('Unable to contact node.js server');
130
+ }
131
+ }
132
+
133
+ public static function start()
134
+ {
135
+ if (self::$started) {
136
+ return;
137
+ }
138
+
139
+ try {
140
+ self::wait();
141
+ } catch (\Exception $e) {
142
+ exec('node ' . __DIR__ . \DIRECTORY_SEPARATOR . 'server.js '
143
+ . self::$port . ' >> /tmp/server.log 2>&1 &');
144
+ self::wait();
145
+ }
146
+
147
+ self::$started = true;
148
+ }
149
+
150
+ private static function isListening()
151
+ {
152
+ $response = self::send('GET', '/guzzle-server/perf', null, [
153
+ 'connect_timeout' => 1,
154
+ 'timeout' => 1
155
+ ]);
156
+
157
+ return !isset($response['error']);
158
+ }
159
+
160
+ private static function send(
161
+ $method,
162
+ $path,
163
+ $body = null,
164
+ array $client = []
165
+ ) {
166
+ $handler = new StreamHandler();
167
+
168
+ $request = [
169
+ 'http_method' => $method,
170
+ 'uri' => $path,
171
+ 'request_port' => 8125,
172
+ 'headers' => ['host' => ['127.0.0.1:8125']],
173
+ 'body' => $body,
174
+ 'client' => $client,
175
+ ];
176
+
177
+ if ($body) {
178
+ $request['headers']['content-length'] = [strlen($body)];
179
+ }
180
+
181
+ return $handler($request);
182
+ }
183
+ }
backend/vendor/guzzlehttp/ringphp/tests/Client/StreamHandlerTest.php ADDED
@@ -0,0 +1,479 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests\Ring\Client;
3
+
4
+ use GuzzleHttp\Ring\Client\ClientUtils;
5
+ use GuzzleHttp\Ring\Core;
6
+ use GuzzleHttp\Ring\Client\StreamHandler;
7
+
8
+ class StreamHandlerTest extends \PHPUnit_Framework_TestCase
9
+ {
10
+ public function testReturnsResponseForSuccessfulRequest()
11
+ {
12
+ $this->queueRes();
13
+ $handler = new StreamHandler();
14
+ $response = $handler([
15
+ 'http_method' => 'GET',
16
+ 'uri' => '/',
17
+ 'headers' => [
18
+ 'host' => [Server::$host],
19
+ 'Foo' => ['Bar'],
20
+ ],
21
+ ]);
22
+
23
+ $this->assertEquals(200, $response['status']);
24
+ $this->assertEquals('OK', $response['reason']);
25
+ $this->assertEquals(['Bar'], $response['headers']['Foo']);
26
+ $this->assertEquals(['8'], $response['headers']['Content-Length']);
27
+ $this->assertEquals('hi there', Core::body($response));
28
+
29
+ $sent = Server::received()[0];
30
+ $this->assertEquals('GET', $sent['http_method']);
31
+ $this->assertEquals('/', $sent['resource']);
32
+ $this->assertEquals(['127.0.0.1:8125'], $sent['headers']['host']);
33
+ $this->assertEquals('Bar', Core::header($sent, 'foo'));
34
+ }
35
+
36
+ public function testAddsErrorToResponse()
37
+ {
38
+ $handler = new StreamHandler();
39
+ $result = $handler([
40
+ 'http_method' => 'GET',
41
+ 'headers' => ['host' => ['localhost:123']],
42
+ 'client' => ['timeout' => 0.01],
43
+ ]);
44
+ $this->assertInstanceOf(
45
+ 'GuzzleHttp\Ring\Future\CompletedFutureArray',
46
+ $result
47
+ );
48
+ $this->assertNull($result['status']);
49
+ $this->assertNull($result['body']);
50
+ $this->assertEquals([], $result['headers']);
51
+ $this->assertInstanceOf(
52
+ 'GuzzleHttp\Ring\Exception\RingException',
53
+ $result['error']
54
+ );
55
+ }
56
+
57
+ public function testEnsuresTheHttpProtocol()
58
+ {
59
+ $handler = new StreamHandler();
60
+ $result = $handler([
61
+ 'http_method' => 'GET',
62
+ 'url' => 'ftp://localhost:123',
63
+ ]);
64
+ $this->assertArrayHasKey('error', $result);
65
+ $this->assertContains(
66
+ 'URL is invalid: ftp://localhost:123',
67
+ $result['error']->getMessage()
68
+ );
69
+ }
70
+
71
+ public function testStreamAttributeKeepsStreamOpen()
72
+ {
73
+ $this->queueRes();
74
+ $handler = new StreamHandler();
75
+ $response = $handler([
76
+ 'http_method' => 'PUT',
77
+ 'uri' => '/foo',
78
+ 'query_string' => 'baz=bar',
79
+ 'headers' => [
80
+ 'host' => [Server::$host],
81
+ 'Foo' => ['Bar'],
82
+ ],
83
+ 'body' => 'test',
84
+ 'client' => ['stream' => true],
85
+ ]);
86
+
87
+ $this->assertEquals(200, $response['status']);
88
+ $this->assertEquals('OK', $response['reason']);
89
+ $this->assertEquals('8', Core::header($response, 'Content-Length'));
90
+ $body = $response['body'];
91
+ $this->assertTrue(is_resource($body));
92
+ $this->assertEquals('http', stream_get_meta_data($body)['wrapper_type']);
93
+ $this->assertEquals('hi there', stream_get_contents($body));
94
+ fclose($body);
95
+ $sent = Server::received()[0];
96
+ $this->assertEquals('PUT', $sent['http_method']);
97
+ $this->assertEquals('/foo', $sent['uri']);
98
+ $this->assertEquals('baz=bar', $sent['query_string']);
99
+ $this->assertEquals('/foo?baz=bar', $sent['resource']);
100
+ $this->assertEquals('127.0.0.1:8125', Core::header($sent, 'host'));
101
+ $this->assertEquals('Bar', Core::header($sent, 'foo'));
102
+ }
103
+
104
+ public function testDrainsResponseIntoTempStream()
105
+ {
106
+ $this->queueRes();
107
+ $handler = new StreamHandler();
108
+ $response = $handler([
109
+ 'http_method' => 'GET',
110
+ 'uri' => '/',
111
+ 'headers' => ['host' => [Server::$host]],
112
+ ]);
113
+ $body = $response['body'];
114
+ $this->assertEquals('php://temp', stream_get_meta_data($body)['uri']);
115
+ $this->assertEquals('hi', fread($body, 2));
116
+ fclose($body);
117
+ }
118
+
119
+ public function testDrainsResponseIntoSaveToBody()
120
+ {
121
+ $r = fopen('php://temp', 'r+');
122
+ $this->queueRes();
123
+ $handler = new StreamHandler();
124
+ $response = $handler([
125
+ 'http_method' => 'GET',
126
+ 'uri' => '/',
127
+ 'headers' => ['host' => [Server::$host]],
128
+ 'client' => ['save_to' => $r],
129
+ ]);
130
+ $body = $response['body'];
131
+ $this->assertEquals('php://temp', stream_get_meta_data($body)['uri']);
132
+ $this->assertEquals('hi', fread($body, 2));
133
+ $this->assertEquals(' there', stream_get_contents($r));
134
+ fclose($r);
135
+ }
136
+
137
+ public function testDrainsResponseIntoSaveToBodyAtPath()
138
+ {
139
+ $tmpfname = tempnam('/tmp', 'save_to_path');
140
+ $this->queueRes();
141
+ $handler = new StreamHandler();
142
+ $response = $handler([
143
+ 'http_method' => 'GET',
144
+ 'uri' => '/',
145
+ 'headers' => ['host' => [Server::$host]],
146
+ 'client' => ['save_to' => $tmpfname],
147
+ ]);
148
+ $body = $response['body'];
149
+ $this->assertInstanceOf('GuzzleHttp\Stream\StreamInterface', $body);
150
+ $this->assertEquals($tmpfname, $body->getMetadata('uri'));
151
+ $this->assertEquals('hi', $body->read(2));
152
+ $body->close();
153
+ unlink($tmpfname);
154
+ }
155
+
156
+ public function testAutomaticallyDecompressGzip()
157
+ {
158
+ Server::flush();
159
+ $content = gzencode('test');
160
+ Server::enqueue([
161
+ [
162
+ 'status' => 200,
163
+ 'reason' => 'OK',
164
+ 'headers' => [
165
+ 'Content-Encoding' => ['gzip'],
166
+ 'Content-Length' => [strlen($content)],
167
+ ],
168
+ 'body' => $content,
169
+ ],
170
+ ]);
171
+
172
+ $handler = new StreamHandler();
173
+ $response = $handler([
174
+ 'http_method' => 'GET',
175
+ 'headers' => ['host' => [Server::$host]],
176
+ 'uri' => '/',
177
+ 'client' => ['decode_content' => true],
178
+ ]);
179
+ $this->assertEquals('test', Core::body($response));
180
+ }
181
+
182
+ public function testDoesNotForceGzipDecode()
183
+ {
184
+ Server::flush();
185
+ $content = gzencode('test');
186
+ Server::enqueue([
187
+ [
188
+ 'status' => 200,
189
+ 'reason' => 'OK',
190
+ 'headers' => [
191
+ 'Content-Encoding' => ['gzip'],
192
+ 'Content-Length' => [strlen($content)],
193
+ ],
194
+ 'body' => $content,
195
+ ],
196
+ ]);
197
+
198
+ $handler = new StreamHandler();
199
+ $response = $handler([
200
+ 'http_method' => 'GET',
201
+ 'headers' => ['host' => [Server::$host]],
202
+ 'uri' => '/',
203
+ 'client' => ['stream' => true, 'decode_content' => false],
204
+ ]);
205
+ $this->assertSame($content, Core::body($response));
206
+ }
207
+
208
+ public function testProtocolVersion()
209
+ {
210
+ $this->queueRes();
211
+ $handler = new StreamHandler();
212
+ $handler([
213
+ 'http_method' => 'GET',
214
+ 'uri' => '/',
215
+ 'headers' => ['host' => [Server::$host]],
216
+ 'version' => 1.0,
217
+ ]);
218
+
219
+ $this->assertEquals(1.0, Server::received()[0]['version']);
220
+ }
221
+
222
+ protected function getSendResult(array $opts)
223
+ {
224
+ $this->queueRes();
225
+ $handler = new StreamHandler();
226
+ $opts['stream'] = true;
227
+ return $handler([
228
+ 'http_method' => 'GET',
229
+ 'uri' => '/',
230
+ 'headers' => ['host' => [Server::$host]],
231
+ 'client' => $opts,
232
+ ]);
233
+ }
234
+
235
+ public function testAddsProxy()
236
+ {
237
+ $res = $this->getSendResult(['stream' => true, 'proxy' => '127.0.0.1:8125']);
238
+ $opts = stream_context_get_options($res['body']);
239
+ $this->assertEquals('127.0.0.1:8125', $opts['http']['proxy']);
240
+ }
241
+
242
+ public function testAddsTimeout()
243
+ {
244
+ $res = $this->getSendResult(['stream' => true, 'timeout' => 200]);
245
+ $opts = stream_context_get_options($res['body']);
246
+ $this->assertEquals(200, $opts['http']['timeout']);
247
+ }
248
+
249
+ public function testVerifiesVerifyIsValidIfPath()
250
+ {
251
+ $res = $this->getSendResult(['verify' => '/does/not/exist']);
252
+ $this->assertContains(
253
+ 'SSL CA bundle not found: /does/not/exist',
254
+ (string) $res['error']
255
+ );
256
+ }
257
+
258
+ public function testVerifyCanBeDisabled()
259
+ {
260
+ $res = $this->getSendResult(['verify' => false]);
261
+ $this->assertArrayNotHasKey('error', $res);
262
+ }
263
+
264
+ public function testVerifiesCertIfValidPath()
265
+ {
266
+ $res = $this->getSendResult(['cert' => '/does/not/exist']);
267
+ $this->assertContains(
268
+ 'SSL certificate not found: /does/not/exist',
269
+ (string) $res['error']
270
+ );
271
+ }
272
+
273
+ public function testVerifyCanBeSetToPath()
274
+ {
275
+ $path = $path = ClientUtils::getDefaultCaBundle();
276
+ $res = $this->getSendResult(['verify' => $path]);
277
+ $this->assertArrayNotHasKey('error', $res);
278
+ $opts = stream_context_get_options($res['body']);
279
+ $this->assertEquals(true, $opts['ssl']['verify_peer']);
280
+ $this->assertEquals($path, $opts['ssl']['cafile']);
281
+ $this->assertTrue(file_exists($opts['ssl']['cafile']));
282
+ }
283
+
284
+ public function testUsesSystemDefaultBundle()
285
+ {
286
+ $path = $path = ClientUtils::getDefaultCaBundle();
287
+ $res = $this->getSendResult(['verify' => true]);
288
+ $this->assertArrayNotHasKey('error', $res);
289
+ $opts = stream_context_get_options($res['body']);
290
+ if (PHP_VERSION_ID < 50600) {
291
+ $this->assertEquals($path, $opts['ssl']['cafile']);
292
+ }
293
+ }
294
+
295
+ public function testEnsuresVerifyOptionIsValid()
296
+ {
297
+ $res = $this->getSendResult(['verify' => 10]);
298
+ $this->assertContains(
299
+ 'Invalid verify request option',
300
+ (string) $res['error']
301
+ );
302
+ }
303
+
304
+ public function testCanSetPasswordWhenSettingCert()
305
+ {
306
+ $path = __FILE__;
307
+ $res = $this->getSendResult(['cert' => [$path, 'foo']]);
308
+ $opts = stream_context_get_options($res['body']);
309
+ $this->assertEquals($path, $opts['ssl']['local_cert']);
310
+ $this->assertEquals('foo', $opts['ssl']['passphrase']);
311
+ }
312
+
313
+ public function testDebugAttributeWritesToStream()
314
+ {
315
+ $this->queueRes();
316
+ $f = fopen('php://temp', 'w+');
317
+ $this->getSendResult(['debug' => $f]);
318
+ fseek($f, 0);
319
+ $contents = stream_get_contents($f);
320
+ $this->assertContains('<GET http://127.0.0.1:8125/> [CONNECT]', $contents);
321
+ $this->assertContains('<GET http://127.0.0.1:8125/> [FILE_SIZE_IS]', $contents);
322
+ $this->assertContains('<GET http://127.0.0.1:8125/> [PROGRESS]', $contents);
323
+ }
324
+
325
+ public function testDebugAttributeWritesStreamInfoToBuffer()
326
+ {
327
+ $called = false;
328
+ $this->queueRes();
329
+ $buffer = fopen('php://temp', 'r+');
330
+ $this->getSendResult([
331
+ 'progress' => function () use (&$called) { $called = true; },
332
+ 'debug' => $buffer,
333
+ ]);
334
+ fseek($buffer, 0);
335
+ $contents = stream_get_contents($buffer);
336
+ $this->assertContains('<GET http://127.0.0.1:8125/> [CONNECT]', $contents);
337
+ $this->assertContains('<GET http://127.0.0.1:8125/> [FILE_SIZE_IS] message: "Content-Length: 8"', $contents);
338
+ $this->assertContains('<GET http://127.0.0.1:8125/> [PROGRESS] bytes_max: "8"', $contents);
339
+ $this->assertTrue($called);
340
+ }
341
+
342
+ public function testEmitsProgressInformation()
343
+ {
344
+ $called = [];
345
+ $this->queueRes();
346
+ $this->getSendResult([
347
+ 'progress' => function () use (&$called) {
348
+ $called[] = func_get_args();
349
+ },
350
+ ]);
351
+ $this->assertNotEmpty($called);
352
+ $this->assertEquals(8, $called[0][0]);
353
+ $this->assertEquals(0, $called[0][1]);
354
+ }
355
+
356
+ public function testEmitsProgressInformationAndDebugInformation()
357
+ {
358
+ $called = [];
359
+ $this->queueRes();
360
+ $buffer = fopen('php://memory', 'w+');
361
+ $this->getSendResult([
362
+ 'debug' => $buffer,
363
+ 'progress' => function () use (&$called) {
364
+ $called[] = func_get_args();
365
+ },
366
+ ]);
367
+ $this->assertNotEmpty($called);
368
+ $this->assertEquals(8, $called[0][0]);
369
+ $this->assertEquals(0, $called[0][1]);
370
+ rewind($buffer);
371
+ $this->assertNotEmpty(stream_get_contents($buffer));
372
+ fclose($buffer);
373
+ }
374
+
375
+ public function testAddsProxyByProtocol()
376
+ {
377
+ $url = str_replace('http', 'tcp', Server::$url);
378
+ $res = $this->getSendResult(['proxy' => ['http' => $url]]);
379
+ $opts = stream_context_get_options($res['body']);
380
+ $this->assertEquals($url, $opts['http']['proxy']);
381
+ }
382
+
383
+ public function testPerformsShallowMergeOfCustomContextOptions()
384
+ {
385
+ $res = $this->getSendResult([
386
+ 'stream_context' => [
387
+ 'http' => [
388
+ 'request_fulluri' => true,
389
+ 'method' => 'HEAD',
390
+ ],
391
+ 'socket' => [
392
+ 'bindto' => '127.0.0.1:0',
393
+ ],
394
+ 'ssl' => [
395
+ 'verify_peer' => false,
396
+ ],
397
+ ],
398
+ ]);
399
+
400
+ $opts = stream_context_get_options($res['body']);
401
+ $this->assertEquals('HEAD', $opts['http']['method']);
402
+ $this->assertTrue($opts['http']['request_fulluri']);
403
+ $this->assertFalse($opts['ssl']['verify_peer']);
404
+ $this->assertEquals('127.0.0.1:0', $opts['socket']['bindto']);
405
+ }
406
+
407
+ public function testEnsuresThatStreamContextIsAnArray()
408
+ {
409
+ $res = $this->getSendResult(['stream_context' => 'foo']);
410
+ $this->assertContains(
411
+ 'stream_context must be an array',
412
+ (string) $res['error']
413
+ );
414
+ }
415
+
416
+ public function testDoesNotAddContentTypeByDefault()
417
+ {
418
+ $this->queueRes();
419
+ $handler = new StreamHandler();
420
+ $handler([
421
+ 'http_method' => 'PUT',
422
+ 'uri' => '/',
423
+ 'headers' => ['host' => [Server::$host], 'content-length' => [3]],
424
+ 'body' => 'foo',
425
+ ]);
426
+ $req = Server::received()[0];
427
+ $this->assertEquals('', Core::header($req, 'Content-Type'));
428
+ $this->assertEquals(3, Core::header($req, 'Content-Length'));
429
+ }
430
+
431
+ private function queueRes()
432
+ {
433
+ Server::flush();
434
+ Server::enqueue([
435
+ [
436
+ 'status' => 200,
437
+ 'reason' => 'OK',
438
+ 'headers' => [
439
+ 'Foo' => ['Bar'],
440
+ 'Content-Length' => [8],
441
+ ],
442
+ 'body' => 'hi there',
443
+ ],
444
+ ]);
445
+ }
446
+
447
+ public function testSupports100Continue()
448
+ {
449
+ Server::flush();
450
+ Server::enqueue([
451
+ [
452
+ 'status' => '200',
453
+ 'reason' => 'OK',
454
+ 'headers' => [
455
+ 'Test' => ['Hello'],
456
+ 'Content-Length' => ['4'],
457
+ ],
458
+ 'body' => 'test',
459
+ ],
460
+ ]);
461
+
462
+ $request = [
463
+ 'http_method' => 'PUT',
464
+ 'headers' => [
465
+ 'Host' => [Server::$host],
466
+ 'Expect' => ['100-Continue'],
467
+ ],
468
+ 'body' => 'test',
469
+ ];
470
+
471
+ $handler = new StreamHandler();
472
+ $response = $handler($request);
473
+ $this->assertEquals(200, $response['status']);
474
+ $this->assertEquals('OK', $response['reason']);
475
+ $this->assertEquals(['Hello'], $response['headers']['Test']);
476
+ $this->assertEquals(['4'], $response['headers']['Content-Length']);
477
+ $this->assertEquals('test', Core::body($response));
478
+ }
479
+ }
backend/vendor/guzzlehttp/ringphp/tests/Client/server.js ADDED
@@ -0,0 +1,230 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Guzzle node.js test server to return queued responses to HTTP requests and
3
+ * expose a RESTful API for enqueueing responses and retrieving the requests
4
+ * that have been received.
5
+ *
6
+ * - Delete all requests that have been received:
7
+ * > DELETE /guzzle-server/requests
8
+ * > Host: 127.0.0.1:8125
9
+ *
10
+ * - Enqueue responses
11
+ * > PUT /guzzle-server/responses
12
+ * > Host: 127.0.0.1:8125
13
+ * >
14
+ * > [{'status': 200, 'reason': 'OK', 'headers': {}, 'body': '' }]
15
+ *
16
+ * - Get the received requests
17
+ * > GET /guzzle-server/requests
18
+ * > Host: 127.0.0.1:8125
19
+ *
20
+ * < HTTP/1.1 200 OK
21
+ * <
22
+ * < [{'http_method': 'GET', 'uri': '/', 'headers': {}, 'body': 'string'}]
23
+ *
24
+ * - Attempt access to the secure area
25
+ * > GET /secure/by-digest/qop-auth/guzzle-server/requests
26
+ * > Host: 127.0.0.1:8125
27
+ *
28
+ * < HTTP/1.1 401 Unauthorized
29
+ * < WWW-Authenticate: Digest realm="Digest Test", qop="auth", nonce="0796e98e1aeef43141fab2a66bf4521a", algorithm="MD5", stale="false"
30
+ * <
31
+ * < 401 Unauthorized
32
+ *
33
+ * - Shutdown the server
34
+ * > DELETE /guzzle-server
35
+ * > Host: 127.0.0.1:8125
36
+ *
37
+ * @package Guzzle PHP <http://www.guzzlephp.org>
38
+ * @license See the LICENSE file that was distributed with this source code.
39
+ */
40
+
41
+ var http = require('http');
42
+ var url = require('url');
43
+
44
+ /**
45
+ * Guzzle node.js server
46
+ * @class
47
+ */
48
+ var GuzzleServer = function(port, log) {
49
+
50
+ this.port = port;
51
+ this.log = log;
52
+ this.responses = [];
53
+ this.requests = [];
54
+ var that = this;
55
+
56
+ var md5 = function(input) {
57
+ var crypto = require('crypto');
58
+ var hasher = crypto.createHash('md5');
59
+ hasher.update(input);
60
+ return hasher.digest('hex');
61
+ }
62
+
63
+ /**
64
+ * Node.js HTTP server authentication module.
65
+ *
66
+ * It is only initialized on demand (by loadAuthentifier). This avoids
67
+ * requiring the dependency to http-auth on standard operations, and the
68
+ * performance hit at startup.
69
+ */
70
+ var auth;
71
+
72
+ /**
73
+ * Provides authentication handlers (Basic, Digest).
74
+ */
75
+ var loadAuthentifier = function(type, options) {
76
+ var typeId = type;
77
+ if (type == 'digest') {
78
+ typeId += '.'+(options && options.qop ? options.qop : 'none');
79
+ }
80
+ if (!loadAuthentifier[typeId]) {
81
+ if (!auth) {
82
+ auth = require('http-auth');
83
+ }
84
+ switch (type) {
85
+ case 'digest':
86
+ var digestParams = {
87
+ realm: 'Digest Test',
88
+ login: 'me',
89
+ password: 'test'
90
+ };
91
+ if (options && options.qop) {
92
+ digestParams.qop = options.qop;
93
+ }
94
+ loadAuthentifier[typeId] = auth.digest(digestParams, function(username, callback) {
95
+ callback(md5(digestParams.login + ':' + digestParams.realm + ':' + digestParams.password));
96
+ });
97
+ break
98
+ }
99
+ }
100
+ return loadAuthentifier[typeId];
101
+ };
102
+
103
+ var firewallRequest = function(request, req, res, requestHandlerCallback) {
104
+ var securedAreaUriParts = request.uri.match(/^\/secure\/by-(digest)(\/qop-([^\/]*))?(\/.*)$/);
105
+ if (securedAreaUriParts) {
106
+ var authentifier = loadAuthentifier(securedAreaUriParts[1], { qop: securedAreaUriParts[2] });
107
+ authentifier.check(req, res, function(req, res) {
108
+ req.url = securedAreaUriParts[4];
109
+ requestHandlerCallback(request, req, res);
110
+ });
111
+ } else {
112
+ requestHandlerCallback(request, req, res);
113
+ }
114
+ };
115
+
116
+ var controlRequest = function(request, req, res) {
117
+ if (req.url == '/guzzle-server/perf') {
118
+ res.writeHead(200, 'OK', {'Content-Length': 16});
119
+ res.end('Body of response');
120
+ } else if (req.method == 'DELETE') {
121
+ if (req.url == '/guzzle-server/requests') {
122
+ // Clear the received requests
123
+ that.requests = [];
124
+ res.writeHead(200, 'OK', { 'Content-Length': 0 });
125
+ res.end();
126
+ if (that.log) {
127
+ console.log('Flushing requests');
128
+ }
129
+ } else if (req.url == '/guzzle-server') {
130
+ // Shutdown the server
131
+ res.writeHead(200, 'OK', { 'Content-Length': 0, 'Connection': 'close' });
132
+ res.end();
133
+ if (that.log) {
134
+ console.log('Shutting down');
135
+ }
136
+ that.server.close();
137
+ }
138
+ } else if (req.method == 'GET') {
139
+ if (req.url === '/guzzle-server/requests') {
140
+ if (that.log) {
141
+ console.log('Sending received requests');
142
+ }
143
+ // Get received requests
144
+ var body = JSON.stringify(that.requests);
145
+ res.writeHead(200, 'OK', { 'Content-Length': body.length });
146
+ res.end(body);
147
+ }
148
+ } else if (req.method == 'PUT' && req.url == '/guzzle-server/responses') {
149
+ if (that.log) {
150
+ console.log('Adding responses...');
151
+ }
152
+ if (!request.body) {
153
+ if (that.log) {
154
+ console.log('No response data was provided');
155
+ }
156
+ res.writeHead(400, 'NO RESPONSES IN REQUEST', { 'Content-Length': 0 });
157
+ } else {
158
+ that.responses = eval('(' + request.body + ')');
159
+ for (var i = 0; i < that.responses.length; i++) {
160
+ if (that.responses[i].body) {
161
+ that.responses[i].body = new Buffer(that.responses[i].body, 'base64');
162
+ }
163
+ }
164
+ if (that.log) {
165
+ console.log(that.responses);
166
+ }
167
+ res.writeHead(200, 'OK', { 'Content-Length': 0 });
168
+ }
169
+ res.end();
170
+ }
171
+ };
172
+
173
+ var receivedRequest = function(request, req, res) {
174
+ if (req.url.indexOf('/guzzle-server') === 0) {
175
+ controlRequest(request, req, res);
176
+ } else if (req.url.indexOf('/guzzle-server') == -1 && !that.responses.length) {
177
+ res.writeHead(500);
178
+ res.end('No responses in queue');
179
+ } else {
180
+ if (that.log) {
181
+ console.log('Returning response from queue and adding request');
182
+ }
183
+ that.requests.push(request);
184
+ var response = that.responses.shift();
185
+ res.writeHead(response.status, response.reason, response.headers);
186
+ res.end(response.body);
187
+ }
188
+ };
189
+
190
+ this.start = function() {
191
+
192
+ that.server = http.createServer(function(req, res) {
193
+
194
+ var parts = url.parse(req.url, false);
195
+ var request = {
196
+ http_method: req.method,
197
+ scheme: parts.scheme,
198
+ uri: parts.pathname,
199
+ query_string: parts.query,
200
+ headers: req.headers,
201
+ version: req.httpVersion,
202
+ body: ''
203
+ };
204
+
205
+ // Receive each chunk of the request body
206
+ req.addListener('data', function(chunk) {
207
+ request.body += chunk;
208
+ });
209
+
210
+ // Called when the request completes
211
+ req.addListener('end', function() {
212
+ firewallRequest(request, req, res, receivedRequest);
213
+ });
214
+ });
215
+
216
+ that.server.listen(this.port, '127.0.0.1');
217
+
218
+ if (this.log) {
219
+ console.log('Server running at http://127.0.0.1:8125/');
220
+ }
221
+ };
222
+ };
223
+
224
+ // Get the port from the arguments
225
+ port = process.argv.length >= 3 ? process.argv[2] : 8125;
226
+ log = process.argv.length >= 4 ? process.argv[3] : false;
227
+
228
+ // Start the server
229
+ server = new GuzzleServer(port, log);
230
+ server.start();
backend/vendor/guzzlehttp/ringphp/tests/CoreTest.php ADDED
@@ -0,0 +1,336 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests\Ring;
3
+
4
+ use GuzzleHttp\Ring\Core;
5
+ use GuzzleHttp\Ring\Future\CompletedFutureArray;
6
+ use GuzzleHttp\Ring\Future\FutureArray;
7
+ use GuzzleHttp\Stream\Stream;
8
+ use React\Promise\Deferred;
9
+
10
+ class CoreTest extends \PHPUnit_Framework_TestCase
11
+ {
12
+ public function testReturnsNullNoHeadersAreSet()
13
+ {
14
+ $this->assertNull(Core::header([], 'Foo'));
15
+ $this->assertNull(Core::firstHeader([], 'Foo'));
16
+ }
17
+
18
+ public function testChecksIfHasHeader()
19
+ {
20
+ $message = [
21
+ 'headers' => [
22
+ 'Foo' => ['Bar', 'Baz'],
23
+ 'foo' => ['hello'],
24
+ 'bar' => ['1']
25
+ ]
26
+ ];
27
+ $this->assertTrue(Core::hasHeader($message, 'Foo'));
28
+ $this->assertTrue(Core::hasHeader($message, 'foo'));
29
+ $this->assertTrue(Core::hasHeader($message, 'FoO'));
30
+ $this->assertTrue(Core::hasHeader($message, 'bar'));
31
+ $this->assertFalse(Core::hasHeader($message, 'barr'));
32
+ }
33
+
34
+ public function testReturnsFirstHeaderWhenSimple()
35
+ {
36
+ $this->assertEquals('Bar', Core::firstHeader([
37
+ 'headers' => ['Foo' => ['Bar', 'Baz']],
38
+ ], 'Foo'));
39
+ }
40
+
41
+ public function testReturnsFirstHeaderWhenMultiplePerLine()
42
+ {
43
+ $this->assertEquals('Bar', Core::firstHeader([
44
+ 'headers' => ['Foo' => ['Bar, Baz']],
45
+ ], 'Foo'));
46
+ }
47
+
48
+ public function testExtractsCaseInsensitiveHeader()
49
+ {
50
+ $this->assertEquals(
51
+ 'hello',
52
+ Core::header(['headers' => ['foo' => ['hello']]], 'FoO')
53
+ );
54
+ }
55
+
56
+ public function testExtractsCaseInsensitiveHeaderLines()
57
+ {
58
+ $this->assertEquals(
59
+ ['a', 'b', 'c', 'd'],
60
+ Core::headerLines([
61
+ 'headers' => [
62
+ 'foo' => ['a', 'b'],
63
+ 'Foo' => ['c', 'd']
64
+ ]
65
+ ], 'foo')
66
+ );
67
+ }
68
+
69
+ public function testExtractsHeaderLines()
70
+ {
71
+ $this->assertEquals(
72
+ ['bar', 'baz'],
73
+ Core::headerLines([
74
+ 'headers' => [
75
+ 'Foo' => ['bar', 'baz'],
76
+ ],
77
+ ], 'Foo')
78
+ );
79
+ }
80
+
81
+ public function testExtractsHeaderAsString()
82
+ {
83
+ $this->assertEquals(
84
+ 'bar, baz',
85
+ Core::header([
86
+ 'headers' => [
87
+ 'Foo' => ['bar', 'baz'],
88
+ ],
89
+ ], 'Foo', true)
90
+ );
91
+ }
92
+
93
+ public function testReturnsNullWhenHeaderNotFound()
94
+ {
95
+ $this->assertNull(Core::header(['headers' => []], 'Foo'));
96
+ }
97
+
98
+ public function testRemovesHeaders()
99
+ {
100
+ $message = [
101
+ 'headers' => [
102
+ 'foo' => ['bar'],
103
+ 'Foo' => ['bam'],
104
+ 'baz' => ['123'],
105
+ ],
106
+ ];
107
+
108
+ $this->assertSame($message, Core::removeHeader($message, 'bam'));
109
+ $this->assertEquals([
110
+ 'headers' => ['baz' => ['123']],
111
+ ], Core::removeHeader($message, 'foo'));
112
+ }
113
+
114
+ public function testCreatesUrl()
115
+ {
116
+ $req = [
117
+ 'scheme' => 'http',
118
+ 'headers' => ['host' => ['foo.com']],
119
+ 'uri' => '/',
120
+ ];
121
+
122
+ $this->assertEquals('http://foo.com/', Core::url($req));
123
+ }
124
+
125
+ /**
126
+ * @expectedException \InvalidArgumentException
127
+ * @expectedExceptionMessage No Host header was provided
128
+ */
129
+ public function testEnsuresHostIsAvailableWhenCreatingUrls()
130
+ {
131
+ Core::url([]);
132
+ }
133
+
134
+ public function testCreatesUrlWithQueryString()
135
+ {
136
+ $req = [
137
+ 'scheme' => 'http',
138
+ 'headers' => ['host' => ['foo.com']],
139
+ 'uri' => '/',
140
+ 'query_string' => 'foo=baz',
141
+ ];
142
+
143
+ $this->assertEquals('http://foo.com/?foo=baz', Core::url($req));
144
+ }
145
+
146
+ public function testUsesUrlIfSet()
147
+ {
148
+ $req = ['url' => 'http://foo.com'];
149
+ $this->assertEquals('http://foo.com', Core::url($req));
150
+ }
151
+
152
+ public function testReturnsNullWhenNoBody()
153
+ {
154
+ $this->assertNull(Core::body([]));
155
+ }
156
+
157
+ public function testReturnsStreamAsString()
158
+ {
159
+ $this->assertEquals(
160
+ 'foo',
161
+ Core::body(['body' => Stream::factory('foo')])
162
+ );
163
+ }
164
+
165
+ public function testReturnsString()
166
+ {
167
+ $this->assertEquals('foo', Core::body(['body' => 'foo']));
168
+ }
169
+
170
+ public function testReturnsResourceContent()
171
+ {
172
+ $r = fopen('php://memory', 'w+');
173
+ fwrite($r, 'foo');
174
+ rewind($r);
175
+ $this->assertEquals('foo', Core::body(['body' => $r]));
176
+ fclose($r);
177
+ }
178
+
179
+ public function testReturnsIteratorContent()
180
+ {
181
+ $a = new \ArrayIterator(['a', 'b', 'cd', '']);
182
+ $this->assertEquals('abcd', Core::body(['body' => $a]));
183
+ }
184
+
185
+ public function testReturnsObjectToString()
186
+ {
187
+ $this->assertEquals('foo', Core::body(['body' => new StrClass]));
188
+ }
189
+
190
+ /**
191
+ * @expectedException \InvalidArgumentException
192
+ */
193
+ public function testEnsuresBodyIsValid()
194
+ {
195
+ Core::body(['body' => false]);
196
+ }
197
+
198
+ public function testParsesHeadersFromLines()
199
+ {
200
+ $lines = ['Foo: bar', 'Foo: baz', 'Abc: 123', 'Def: a, b'];
201
+ $this->assertEquals([
202
+ 'Foo' => ['bar', 'baz'],
203
+ 'Abc' => ['123'],
204
+ 'Def' => ['a, b'],
205
+ ], Core::headersFromLines($lines));
206
+ }
207
+
208
+ public function testParsesHeadersFromLinesWithMultipleLines()
209
+ {
210
+ $lines = ['Foo: bar', 'Foo: baz', 'Foo: 123'];
211
+ $this->assertEquals([
212
+ 'Foo' => ['bar', 'baz', '123'],
213
+ ], Core::headersFromLines($lines));
214
+ }
215
+
216
+ public function testCreatesArrayCallFunctions()
217
+ {
218
+ $called = [];
219
+ $a = function ($a, $b) use (&$called) {
220
+ $called['a'] = func_get_args();
221
+ };
222
+ $b = function ($a, $b) use (&$called) {
223
+ $called['b'] = func_get_args();
224
+ };
225
+ $c = Core::callArray([$a, $b]);
226
+ $c(1, 2);
227
+ $this->assertEquals([1, 2], $called['a']);
228
+ $this->assertEquals([1, 2], $called['b']);
229
+ }
230
+
231
+ public function testRewindsGuzzleStreams()
232
+ {
233
+ $str = Stream::factory('foo');
234
+ $this->assertTrue(Core::rewindBody(['body' => $str]));
235
+ }
236
+
237
+ public function testRewindsStreams()
238
+ {
239
+ $str = Stream::factory('foo')->detach();
240
+ $this->assertTrue(Core::rewindBody(['body' => $str]));
241
+ }
242
+
243
+ public function testRewindsIterators()
244
+ {
245
+ $iter = new \ArrayIterator(['foo']);
246
+ $this->assertTrue(Core::rewindBody(['body' => $iter]));
247
+ }
248
+
249
+ public function testRewindsStrings()
250
+ {
251
+ $this->assertTrue(Core::rewindBody(['body' => 'hi']));
252
+ }
253
+
254
+ public function testRewindsToStrings()
255
+ {
256
+ $this->assertTrue(Core::rewindBody(['body' => new StrClass()]));
257
+ }
258
+
259
+ public function typeProvider()
260
+ {
261
+ return [
262
+ ['foo', 'string(3) "foo"'],
263
+ [true, 'bool(true)'],
264
+ [false, 'bool(false)'],
265
+ [10, 'int(10)'],
266
+ [1.0, 'float(1)'],
267
+ [new StrClass(), 'object(GuzzleHttp\Tests\Ring\StrClass)'],
268
+ [['foo'], 'array(1)']
269
+ ];
270
+ }
271
+
272
+ /**
273
+ * @dataProvider typeProvider
274
+ */
275
+ public function testDescribesType($input, $output)
276
+ {
277
+ $this->assertEquals($output, Core::describeType($input));
278
+ }
279
+
280
+ public function testDoesSleep()
281
+ {
282
+ $t = microtime(true);
283
+ $expected = $t + (100 / 1000);
284
+ Core::doSleep(['client' => ['delay' => 100]]);
285
+ $this->assertGreaterThanOrEqual($expected, microtime(true));
286
+ }
287
+
288
+ public function testProxiesFuture()
289
+ {
290
+ $f = new CompletedFutureArray(['status' => 200]);
291
+ $res = null;
292
+ $proxied = Core::proxy($f, function ($value) use (&$res) {
293
+ $value['foo'] = 'bar';
294
+ $res = $value;
295
+ return $value;
296
+ });
297
+ $this->assertNotSame($f, $proxied);
298
+ $this->assertEquals(200, $f->wait()['status']);
299
+ $this->assertArrayNotHasKey('foo', $f->wait());
300
+ $this->assertEquals('bar', $proxied->wait()['foo']);
301
+ $this->assertEquals(200, $proxied->wait()['status']);
302
+ }
303
+
304
+ public function testProxiesDeferredFuture()
305
+ {
306
+ $d = new Deferred();
307
+ $f = new FutureArray($d->promise());
308
+ $f2 = Core::proxy($f);
309
+ $d->resolve(['foo' => 'bar']);
310
+ $this->assertEquals('bar', $f['foo']);
311
+ $this->assertEquals('bar', $f2['foo']);
312
+ }
313
+
314
+ public function testProxiesDeferredFutureFailure()
315
+ {
316
+ $d = new Deferred();
317
+ $f = new FutureArray($d->promise());
318
+ $f2 = Core::proxy($f);
319
+ $d->reject(new \Exception('foo'));
320
+ try {
321
+ $f2['hello?'];
322
+ $this->fail('did not throw');
323
+ } catch (\Exception $e) {
324
+ $this->assertEquals('foo', $e->getMessage());
325
+ }
326
+
327
+ }
328
+ }
329
+
330
+ final class StrClass
331
+ {
332
+ public function __toString()
333
+ {
334
+ return 'foo';
335
+ }
336
+ }
backend/vendor/guzzlehttp/ringphp/tests/Future/CompletedFutureArrayTest.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests\Ring\Future;
3
+
4
+ use GuzzleHttp\Ring\Future\CompletedFutureArray;
5
+
6
+ class CompletedFutureArrayTest extends \PHPUnit_Framework_TestCase
7
+ {
8
+ public function testReturnsAsArray()
9
+ {
10
+ $f = new CompletedFutureArray(['foo' => 'bar']);
11
+ $this->assertEquals('bar', $f['foo']);
12
+ $this->assertFalse(isset($f['baz']));
13
+ $f['abc'] = '123';
14
+ $this->assertTrue(isset($f['abc']));
15
+ $this->assertEquals(['foo' => 'bar', 'abc' => '123'], iterator_to_array($f));
16
+ $this->assertEquals(2, count($f));
17
+ unset($f['abc']);
18
+ $this->assertEquals(1, count($f));
19
+ $this->assertEquals(['foo' => 'bar'], iterator_to_array($f));
20
+ }
21
+ }
backend/vendor/guzzlehttp/ringphp/tests/Future/CompletedFutureValueTest.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests\Ring\Future;
3
+
4
+ use GuzzleHttp\Ring\Exception\CancelledFutureAccessException;
5
+ use GuzzleHttp\Ring\Future\CompletedFutureValue;
6
+
7
+ class CompletedFutureValueTest extends \PHPUnit_Framework_TestCase
8
+ {
9
+ public function testReturnsValue()
10
+ {
11
+ $f = new CompletedFutureValue('hi');
12
+ $this->assertEquals('hi', $f->wait());
13
+ $f->cancel();
14
+
15
+ $a = null;
16
+ $f->then(function ($v) use (&$a) {
17
+ $a = $v;
18
+ });
19
+ $this->assertSame('hi', $a);
20
+ }
21
+
22
+ public function testThrows()
23
+ {
24
+ $ex = new \Exception('foo');
25
+ $f = new CompletedFutureValue(null, $ex);
26
+ $f->cancel();
27
+ try {
28
+ $f->wait();
29
+ $this->fail('did not throw');
30
+ } catch (\Exception $e) {
31
+ $this->assertSame($e, $ex);
32
+ }
33
+ }
34
+
35
+ public function testMarksAsCancelled()
36
+ {
37
+ $ex = new CancelledFutureAccessException();
38
+ $f = new CompletedFutureValue(null, $ex);
39
+ try {
40
+ $f->wait();
41
+ $this->fail('did not throw');
42
+ } catch (\Exception $e) {
43
+ $this->assertSame($e, $ex);
44
+ }
45
+ }
46
+ }
backend/vendor/guzzlehttp/ringphp/tests/Future/FutureArrayTest.php ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests\Ring\Future;
3
+
4
+ use GuzzleHttp\Ring\Future\FutureArray;
5
+ use React\Promise\Deferred;
6
+
7
+ class FutureArrayTest extends \PHPUnit_Framework_TestCase
8
+ {
9
+ public function testLazilyCallsDeref()
10
+ {
11
+ $c = false;
12
+ $deferred = new Deferred();
13
+ $f = new FutureArray(
14
+ $deferred->promise(),
15
+ function () use (&$c, $deferred) {
16
+ $c = true;
17
+ $deferred->resolve(['status' => 200]);
18
+ }
19
+ );
20
+ $this->assertFalse($c);
21
+ $this->assertFalse($this->readAttribute($f, 'isRealized'));
22
+ $this->assertEquals(200, $f['status']);
23
+ $this->assertTrue($c);
24
+ }
25
+
26
+ public function testActsLikeArray()
27
+ {
28
+ $deferred = new Deferred();
29
+ $f = new FutureArray(
30
+ $deferred->promise(),
31
+ function () use (&$c, $deferred) {
32
+ $deferred->resolve(['status' => 200]);
33
+ }
34
+ );
35
+
36
+ $this->assertTrue(isset($f['status']));
37
+ $this->assertEquals(200, $f['status']);
38
+ $this->assertEquals(['status' => 200], $f->wait());
39
+ $this->assertEquals(1, count($f));
40
+ $f['baz'] = 10;
41
+ $this->assertEquals(10, $f['baz']);
42
+ unset($f['baz']);
43
+ $this->assertFalse(isset($f['baz']));
44
+ $this->assertEquals(['status' => 200], iterator_to_array($f));
45
+ }
46
+
47
+ /**
48
+ * @expectedException \RuntimeException
49
+ */
50
+ public function testThrowsWhenAccessingInvalidProperty()
51
+ {
52
+ $deferred = new Deferred();
53
+ $f = new FutureArray($deferred->promise(), function () {});
54
+ $f->foo;
55
+ }
56
+ }
backend/vendor/guzzlehttp/ringphp/tests/Future/FutureValueTest.php ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests\Ring\Future;
3
+
4
+ use GuzzleHttp\Ring\Exception\CancelledFutureAccessException;
5
+ use GuzzleHttp\Ring\Future\FutureValue;
6
+ use React\Promise\Deferred;
7
+
8
+ class FutureValueTest extends \PHPUnit_Framework_TestCase
9
+ {
10
+ public function testDerefReturnsValue()
11
+ {
12
+ $called = 0;
13
+ $deferred = new Deferred();
14
+
15
+ $f = new FutureValue(
16
+ $deferred->promise(),
17
+ function () use ($deferred, &$called) {
18
+ $called++;
19
+ $deferred->resolve('foo');
20
+ }
21
+ );
22
+
23
+ $this->assertEquals('foo', $f->wait());
24
+ $this->assertEquals(1, $called);
25
+ $this->assertEquals('foo', $f->wait());
26
+ $this->assertEquals(1, $called);
27
+ $f->cancel();
28
+ $this->assertTrue($this->readAttribute($f, 'isRealized'));
29
+ }
30
+
31
+ /**
32
+ * @expectedException \GuzzleHttp\Ring\Exception\CancelledFutureAccessException
33
+ */
34
+ public function testThrowsWhenAccessingCancelled()
35
+ {
36
+ $f = new FutureValue(
37
+ (new Deferred())->promise(),
38
+ function () {},
39
+ function () { return true; }
40
+ );
41
+ $f->cancel();
42
+ $f->wait();
43
+ }
44
+
45
+ /**
46
+ * @expectedException \OutOfBoundsException
47
+ */
48
+ public function testThrowsWhenDerefFailure()
49
+ {
50
+ $called = false;
51
+ $deferred = new Deferred();
52
+ $f = new FutureValue(
53
+ $deferred->promise(),
54
+ function () use(&$called) {
55
+ $called = true;
56
+ }
57
+ );
58
+ $deferred->reject(new \OutOfBoundsException());
59
+ $f->wait();
60
+ $this->assertFalse($called);
61
+ }
62
+
63
+ /**
64
+ * @expectedException \GuzzleHttp\Ring\Exception\RingException
65
+ * @expectedExceptionMessage Waiting did not resolve future
66
+ */
67
+ public function testThrowsWhenDerefDoesNotResolve()
68
+ {
69
+ $deferred = new Deferred();
70
+ $f = new FutureValue(
71
+ $deferred->promise(),
72
+ function () use(&$called) {
73
+ $called = true;
74
+ }
75
+ );
76
+ $f->wait();
77
+ }
78
+
79
+ public function testThrowingCancelledFutureAccessExceptionCancels()
80
+ {
81
+ $deferred = new Deferred();
82
+ $f = new FutureValue(
83
+ $deferred->promise(),
84
+ function () use ($deferred) {
85
+ throw new CancelledFutureAccessException();
86
+ }
87
+ );
88
+ try {
89
+ $f->wait();
90
+ $this->fail('did not throw');
91
+ } catch (CancelledFutureAccessException $e) {}
92
+ }
93
+
94
+ /**
95
+ * @expectedException \Exception
96
+ * @expectedExceptionMessage foo
97
+ */
98
+ public function testThrowingExceptionInDerefMarksAsFailed()
99
+ {
100
+ $deferred = new Deferred();
101
+ $f = new FutureValue(
102
+ $deferred->promise(),
103
+ function () {
104
+ throw new \Exception('foo');
105
+ }
106
+ );
107
+ $f->wait();
108
+ }
109
+ }
backend/vendor/guzzlehttp/ringphp/tests/bootstrap.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require __DIR__ . '/../vendor/autoload.php';
3
+ require __DIR__ . '/Client/Server.php';
4
+
5
+ use GuzzleHttp\Tests\Ring\Client\Server;
6
+
7
+ Server::start();
8
+
9
+ register_shutdown_function(function () {
10
+ Server::stop();
11
+ });
backend/vendor/guzzlehttp/streams/.gitignore ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ .idea
2
+ .DS_STORE
3
+ coverage
4
+ phpunit.xml
5
+ composer.lock
6
+ vendor/
backend/vendor/guzzlehttp/streams/.travis.yml ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ language: php
2
+
3
+ php:
4
+ - 5.4
5
+ - 5.5
6
+ - 5.6
7
+ - hhvm
8
+
9
+ before_script:
10
+ - composer self-update
11
+ - composer install --no-interaction --prefer-source --dev
12
+
13
+ script: vendor/bin/phpunit
14
+
15
+ matrix:
16
+ allow_failures:
17
+ - php: hhvm
backend/vendor/guzzlehttp/streams/CHANGELOG.rst ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ =========
2
+ Changelog
3
+ =========
4
+
5
+ 3.0.0 (2014-10-12)
6
+ ------------------
7
+
8
+ * Now supports creating streams from functions and iterators.
9
+ * Supports creating buffered streams and asynchronous streams.
10
+ * Removed ``functions.php``. Use the corresponding functions provided by
11
+ ``GuzzleHttp\Streams\Utils`` instead.
12
+ * Moved ``GuzzleHttp\Stream\MetadataStreamInterface::getMetadata`` to
13
+ ``GuzzleHttp\Stream\StreamInterface``. MetadataStreamInterface is no longer
14
+ used and is marked as deprecated.
15
+ * Added ``attach()`` to ``GuzzleHttp\Stream\StreamInterface`` for PSR-7
16
+ compatibility.
17
+ * Removed ``flush()`` from StreamInterface.
18
+ * Removed the ``$maxLength`` parameter from
19
+ ``GuzzleHttp\Stream\StreamInterface::getContents()``. This function now
20
+ returns the entire remainder of the stream. If you want to limit the maximum
21
+ amount of data read from the stream, use the
22
+ ``GuzzleHttp\Stream\Utils::copyToString()`` function.
23
+ * Streams that return an empty string, ``''``, are no longer considered a
24
+ failure. You MUST return ``false`` to mark the read as a failure, and ensure
25
+ that any decorators you create properly return ``true`` in response to the
26
+ ``eof()`` method when the stream is consumed.
27
+ * ``GuzzleHttp\Stream\Stream::__construct``,
28
+ ``GuzzleHttp\Stream\Stream::factory``, and
29
+ ``GuzzleHttp\Stream\Utils::create`` no longer accept a size in the second
30
+ argument. They now accept an associative array of options, including the
31
+ "size" key and "metadata" key which can be used to provide custom metadata.
32
+ * Added ``GuzzleHttp\Stream\BufferStream`` to add support for buffering data,
33
+ and when read, shifting data off of the buffer.
34
+ * Added ``GuzzleHttp\Stream\NullBuffer`` which can be used as a buffer that
35
+ does not actually store any data.
36
+ * Added ``GuzzleHttp\Stream\AsyncStream`` to provide support for non-blocking
37
+ streams that can be filled by a remote source (e.g., an event-loop). If a
38
+ ``drain`` option is provided, the stream can also act as if it is a blocking
39
+ stream.
40
+
41
+ 2.1.0 (2014-08-17)
42
+ ------------------
43
+
44
+ * Added an InflateStream to inflate gzipped or deflated content.
45
+ * Added ``flush`` to stream wrapper.
46
+ * Added the ability to easily register the GuzzleStreamWrapper if needed.
47
+
48
+ 2.0.0 (2014-08-16)
49
+ ------------------
50
+
51
+ * Deprecated functions.php and moved all of those methods to
52
+ ``GuzzleHttp\Streams\Utils``. Use ``GuzzleHttp\Stream\Stream::factory()``
53
+ instead of ``GuzzleHttp\Stream\create()`` to create new streams.
54
+ * Added ``flush()`` to ``StreamInterface``. This method is used to flush any
55
+ underlying stream write buffers.
56
+ * Added ``FnStream`` to easily decorate stream behavior with callables.
57
+ * ``Utils::hash`` now throws an exception when the stream cannot seek to 0.
58
+
59
+ 1.5.1 (2014-09-10)
60
+ ------------------
61
+
62
+ * Stream metadata is grabbed from the underlying stream each time
63
+ ``getMetadata`` is called rather than returning a value from a cache.
64
+ * Properly closing all underlying streams when AppendStream is closed.
65
+ * Seek functions no longer throw exceptions.
66
+ * LazyOpenStream now correctly returns the underlying stream resource when
67
+ detached.
68
+
69
+ 1.5.0 (2014-08-07)
70
+ ------------------
71
+
72
+ * Added ``Stream\safe_open`` to open stream resources and throw exceptions
73
+ instead of raising errors.
74
+
75
+ 1.4.0 (2014-07-19)
76
+ ------------------
77
+
78
+ * Added a LazyOpenStream
79
+
80
+ 1.3.0 (2014-07-15)
81
+ ------------------
82
+
83
+ * Added an AppendStream to stream over multiple stream one after the other.
84
+
85
+ 1.2.0 (2014-07-15)
86
+ ------------------
87
+
88
+ * Updated the ``detach()`` method to return the underlying stream resource or
89
+ ``null`` if it does not wrap a resource.
90
+ * Multiple fixes for how streams behave when the underlying resource is
91
+ detached
92
+ * Do not clear statcache when a stream does not have a 'uri'
93
+ * Added a fix to LimitStream
94
+ * Added a condition to ensure that functions.php can be required multiple times
backend/vendor/guzzlehttp/streams/LICENSE ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright (c) 2014 Michael Dowling, https://github.com/mtdowling <mtdowling@gmail.com>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
backend/vendor/guzzlehttp/streams/Makefile ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ all: clean coverage
2
+
3
+ release: tag
4
+ git push origin --tags
5
+
6
+ tag:
7
+ chag tag --sign --debug CHANGELOG.rst
8
+
9
+ test:
10
+ vendor/bin/phpunit
11
+
12
+ coverage:
13
+ vendor/bin/phpunit --coverage-html=artifacts/coverage
14
+
15
+ view-coverage:
16
+ open artifacts/coverage/index.html
17
+
18
+ clean:
19
+ rm -rf artifacts/*
backend/vendor/guzzlehttp/streams/README.rst ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ==============
2
+ Guzzle Streams
3
+ ==============
4
+
5
+ Provides a simple abstraction over streams of data.
6
+
7
+ This library is used in `Guzzle 5 <https://github.com/guzzle/guzzle>`_, and is
8
+ (currently) compatible with the WIP PSR-7.
9
+
10
+ Installation
11
+ ============
12
+
13
+ This package can be installed easily using `Composer <http://getcomposer.org>`_.
14
+ Simply add the following to the composer.json file at the root of your project:
15
+
16
+ .. code-block:: javascript
17
+
18
+ {
19
+ "require": {
20
+ "guzzlehttp/streams": "~3.0"
21
+ }
22
+ }
23
+
24
+ Then install your dependencies using ``composer.phar install``.
25
+
26
+ Documentation
27
+ =============
28
+
29
+ The documentation for this package can be found on the main Guzzle website at
30
+ http://docs.guzzlephp.org/en/guzzle4/streams.html.
31
+
32
+ Testing
33
+ =======
34
+
35
+ This library is tested using PHPUnit. You'll need to install the dependencies
36
+ using `Composer <http://getcomposer.org>`_ then run ``make test``.
backend/vendor/guzzlehttp/streams/composer.json ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "guzzlehttp/streams",
3
+ "description": "Provides a simple abstraction over streams of data",
4
+ "homepage": "http://guzzlephp.org/",
5
+ "keywords": ["stream", "guzzle"],
6
+ "license": "MIT",
7
+ "authors": [
8
+ {
9
+ "name": "Michael Dowling",
10
+ "email": "mtdowling@gmail.com",
11
+ "homepage": "https://github.com/mtdowling"
12
+ }
13
+ ],
14
+ "require": {
15
+ "php": ">=5.4.0"
16
+ },
17
+ "require-dev": {
18
+ "phpunit/phpunit": "~4.0"
19
+ },
20
+ "autoload": {
21
+ "psr-4": { "GuzzleHttp\\Stream\\": "src/" }
22
+ },
23
+ "extra": {
24
+ "branch-alias": {
25
+ "dev-master": "3.0-dev"
26
+ }
27
+ }
28
+ }
backend/vendor/guzzlehttp/streams/phpunit.xml.dist ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <phpunit bootstrap="./vendor/autoload.php"
3
+ colors="true">
4
+ <testsuites>
5
+ <testsuite>
6
+ <directory>tests</directory>
7
+ </testsuite>
8
+ </testsuites>
9
+ <filter>
10
+ <whitelist>
11
+ <directory suffix=".php">src</directory>
12
+ <exclude>
13
+ <file>src/functions.php</file>
14
+ </exclude>
15
+ </whitelist>
16
+ </filter>
17
+ </phpunit>
backend/vendor/guzzlehttp/streams/src/AppendStream.php ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Stream;
3
+
4
+ use GuzzleHttp\Stream\Exception\CannotAttachException;
5
+
6
+ /**
7
+ * Reads from multiple streams, one after the other.
8
+ *
9
+ * This is a read-only stream decorator.
10
+ */
11
+ class AppendStream implements StreamInterface
12
+ {
13
+ /** @var StreamInterface[] Streams being decorated */
14
+ private $streams = [];
15
+
16
+ private $seekable = true;
17
+ private $current = 0;
18
+ private $pos = 0;
19
+ private $detached = false;
20
+
21
+ /**
22
+ * @param StreamInterface[] $streams Streams to decorate. Each stream must
23
+ * be readable.
24
+ */
25
+ public function __construct(array $streams = [])
26
+ {
27
+ foreach ($streams as $stream) {
28
+ $this->addStream($stream);
29
+ }
30
+ }
31
+
32
+ public function __toString()
33
+ {
34
+ try {
35
+ $this->seek(0);
36
+ return $this->getContents();
37
+ } catch (\Exception $e) {
38
+ return '';
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Add a stream to the AppendStream
44
+ *
45
+ * @param StreamInterface $stream Stream to append. Must be readable.
46
+ *
47
+ * @throws \InvalidArgumentException if the stream is not readable
48
+ */
49
+ public function addStream(StreamInterface $stream)
50
+ {
51
+ if (!$stream->isReadable()) {
52
+ throw new \InvalidArgumentException('Each stream must be readable');
53
+ }
54
+
55
+ // The stream is only seekable if all streams are seekable
56
+ if (!$stream->isSeekable()) {
57
+ $this->seekable = false;
58
+ }
59
+
60
+ $this->streams[] = $stream;
61
+ }
62
+
63
+ public function getContents()
64
+ {
65
+ return Utils::copyToString($this);
66
+ }
67
+
68
+ /**
69
+ * Closes each attached stream.
70
+ *
71
+ * {@inheritdoc}
72
+ */
73
+ public function close()
74
+ {
75
+ $this->pos = $this->current = 0;
76
+
77
+ foreach ($this->streams as $stream) {
78
+ $stream->close();
79
+ }
80
+
81
+ $this->streams = [];
82
+ }
83
+
84
+ /**
85
+ * Detaches each attached stream
86
+ *
87
+ * {@inheritdoc}
88
+ */
89
+ public function detach()
90
+ {
91
+ $this->close();
92
+ $this->detached = true;
93
+ }
94
+
95
+ public function attach($stream)
96
+ {
97
+ throw new CannotAttachException();
98
+ }
99
+
100
+ public function tell()
101
+ {
102
+ return $this->pos;
103
+ }
104
+
105
+ /**
106
+ * Tries to calculate the size by adding the size of each stream.
107
+ *
108
+ * If any of the streams do not return a valid number, then the size of the
109
+ * append stream cannot be determined and null is returned.
110
+ *
111
+ * {@inheritdoc}
112
+ */
113
+ public function getSize()
114
+ {
115
+ $size = 0;
116
+
117
+ foreach ($this->streams as $stream) {
118
+ $s = $stream->getSize();
119
+ if ($s === null) {
120
+ return null;
121
+ }
122
+ $size += $s;
123
+ }
124
+
125
+ return $size;
126
+ }
127
+
128
+ public function eof()
129
+ {
130
+ return !$this->streams ||
131
+ ($this->current >= count($this->streams) - 1 &&
132
+ $this->streams[$this->current]->eof());
133
+ }
134
+
135
+ /**
136
+ * Attempts to seek to the given position. Only supports SEEK_SET.
137
+ *
138
+ * {@inheritdoc}
139
+ */
140
+ public function seek($offset, $whence = SEEK_SET)
141
+ {
142
+ if (!$this->seekable || $whence !== SEEK_SET) {
143
+ return false;
144
+ }
145
+
146
+ $success = true;
147
+ $this->pos = $this->current = 0;
148
+
149
+ // Rewind each stream
150
+ foreach ($this->streams as $stream) {
151
+ if (!$stream->seek(0)) {
152
+ $success = false;
153
+ }
154
+ }
155
+
156
+ if (!$success) {
157
+ return false;
158
+ }
159
+
160
+ // Seek to the actual position by reading from each stream
161
+ while ($this->pos < $offset && !$this->eof()) {
162
+ $this->read(min(8096, $offset - $this->pos));
163
+ }
164
+
165
+ return $this->pos == $offset;
166
+ }
167
+
168
+ /**
169
+ * Reads from all of the appended streams until the length is met or EOF.
170
+ *
171
+ * {@inheritdoc}
172
+ */
173
+ public function read($length)
174
+ {
175
+ $buffer = '';
176
+ $total = count($this->streams) - 1;
177
+ $remaining = $length;
178
+
179
+ while ($remaining > 0) {
180
+ // Progress to the next stream if needed.
181
+ if ($this->streams[$this->current]->eof()) {
182
+ if ($this->current == $total) {
183
+ break;
184
+ }
185
+ $this->current++;
186
+ }
187
+ $buffer .= $this->streams[$this->current]->read($remaining);
188
+ $remaining = $length - strlen($buffer);
189
+ }
190
+
191
+ $this->pos += strlen($buffer);
192
+
193
+ return $buffer;
194
+ }
195
+
196
+ public function isReadable()
197
+ {
198
+ return true;
199
+ }
200
+
201
+ public function isWritable()
202
+ {
203
+ return false;
204
+ }
205
+
206
+ public function isSeekable()
207
+ {
208
+ return $this->seekable;
209
+ }
210
+
211
+ public function write($string)
212
+ {
213
+ return false;
214
+ }
215
+
216
+ public function getMetadata($key = null)
217
+ {
218
+ return $key ? null : [];
219
+ }
220
+ }
backend/vendor/guzzlehttp/streams/src/AsyncReadStream.php ADDED
@@ -0,0 +1,207 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Stream;
3
+
4
+ /**
5
+ * Represents an asynchronous read-only stream that supports a drain event and
6
+ * pumping data from a source stream.
7
+ *
8
+ * The AsyncReadStream can be used as a completely asynchronous stream, meaning
9
+ * the data you can read from the stream will immediately return only
10
+ * the data that is currently buffered.
11
+ *
12
+ * AsyncReadStream can also be used in a "blocking" manner if a "pump" function
13
+ * is provided. When a caller requests more bytes than are available in the
14
+ * buffer, then the pump function is used to block until the requested number
15
+ * of bytes are available or the remote source stream has errored, closed, or
16
+ * timed-out. This behavior isn't strictly "blocking" because the pump function
17
+ * can send other transfers while waiting on the desired buffer size to be
18
+ * ready for reading (e.g., continue to tick an event loop).
19
+ *
20
+ * @unstable This class is subject to change.
21
+ */
22
+ class AsyncReadStream implements StreamInterface
23
+ {
24
+ use StreamDecoratorTrait;
25
+
26
+ /** @var callable|null Fn used to notify writers the buffer has drained */
27
+ private $drain;
28
+
29
+ /** @var callable|null Fn used to block for more data */
30
+ private $pump;
31
+
32
+ /** @var int|null Highwater mark of the underlying buffer */
33
+ private $hwm;
34
+
35
+ /** @var bool Whether or not drain needs to be called at some point */
36
+ private $needsDrain;
37
+
38
+ /** @var int The expected size of the remote source */
39
+ private $size;
40
+
41
+ /**
42
+ * In order to utilize high water marks to tell writers to slow down, the
43
+ * provided stream must answer to the "hwm" stream metadata variable,
44
+ * providing the high water mark. If no "hwm" metadata value is available,
45
+ * then the "drain" functionality is not utilized.
46
+ *
47
+ * This class accepts an associative array of configuration options.
48
+ *
49
+ * - drain: (callable) Function to invoke when the stream has drained,
50
+ * meaning the buffer is now writable again because the size of the
51
+ * buffer is at an acceptable level (e.g., below the high water mark).
52
+ * The function accepts a single argument, the buffer stream object that
53
+ * has drained.
54
+ * - pump: (callable) A function that accepts the number of bytes to read
55
+ * from the source stream. This function will block until all of the data
56
+ * that was requested has been read, EOF of the source stream, or the
57
+ * source stream is closed.
58
+ * - size: (int) The expected size in bytes of the data that will be read
59
+ * (if known up-front).
60
+ *
61
+ * @param StreamInterface $buffer Buffer that contains the data that has
62
+ * been read by the event loop.
63
+ * @param array $config Associative array of options.
64
+ *
65
+ * @throws \InvalidArgumentException if the buffer is not readable and
66
+ * writable.
67
+ */
68
+ public function __construct(
69
+ StreamInterface $buffer,
70
+ array $config = []
71
+ ) {
72
+ if (!$buffer->isReadable() || !$buffer->isWritable()) {
73
+ throw new \InvalidArgumentException(
74
+ 'Buffer must be readable and writable'
75
+ );
76
+ }
77
+
78
+ if (isset($config['size'])) {
79
+ $this->size = $config['size'];
80
+ }
81
+
82
+ static $callables = ['pump', 'drain'];
83
+ foreach ($callables as $check) {
84
+ if (isset($config[$check])) {
85
+ if (!is_callable($config[$check])) {
86
+ throw new \InvalidArgumentException(
87
+ $check . ' must be callable'
88
+ );
89
+ }
90
+ $this->{$check} = $config[$check];
91
+ }
92
+ }
93
+
94
+ $this->hwm = $buffer->getMetadata('hwm');
95
+
96
+ // Cannot drain when there's no high water mark.
97
+ if ($this->hwm === null) {
98
+ $this->drain = null;
99
+ }
100
+
101
+ $this->stream = $buffer;
102
+ }
103
+
104
+ /**
105
+ * Factory method used to create new async stream and an underlying buffer
106
+ * if no buffer is provided.
107
+ *
108
+ * This function accepts the same options as AsyncReadStream::__construct,
109
+ * but added the following key value pairs:
110
+ *
111
+ * - buffer: (StreamInterface) Buffer used to buffer data. If none is
112
+ * provided, a default buffer is created.
113
+ * - hwm: (int) High water mark to use if a buffer is created on your
114
+ * behalf.
115
+ * - max_buffer: (int) If provided, wraps the utilized buffer in a
116
+ * DroppingStream decorator to ensure that buffer does not exceed a given
117
+ * length. When exceeded, the stream will begin dropping data. Set the
118
+ * max_buffer to 0, to use a NullStream which does not store data.
119
+ * - write: (callable) A function that is invoked when data is written
120
+ * to the underlying buffer. The function accepts the buffer as the first
121
+ * argument, and the data being written as the second. The function MUST
122
+ * return the number of bytes that were written or false to let writers
123
+ * know to slow down.
124
+ * - drain: (callable) See constructor documentation.
125
+ * - pump: (callable) See constructor documentation.
126
+ *
127
+ * @param array $options Associative array of options.
128
+ *
129
+ * @return array Returns an array containing the buffer used to buffer
130
+ * data, followed by the ready to use AsyncReadStream object.
131
+ */
132
+ public static function create(array $options = [])
133
+ {
134
+ $maxBuffer = isset($options['max_buffer'])
135
+ ? $options['max_buffer']
136
+ : null;
137
+
138
+ if ($maxBuffer === 0) {
139
+ $buffer = new NullStream();
140
+ } elseif (isset($options['buffer'])) {
141
+ $buffer = $options['buffer'];
142
+ } else {
143
+ $hwm = isset($options['hwm']) ? $options['hwm'] : 16384;
144
+ $buffer = new BufferStream($hwm);
145
+ }
146
+
147
+ if ($maxBuffer > 0) {
148
+ $buffer = new DroppingStream($buffer, $options['max_buffer']);
149
+ }
150
+
151
+ // Call the on_write callback if an on_write function was provided.
152
+ if (isset($options['write'])) {
153
+ $onWrite = $options['write'];
154
+ $buffer = FnStream::decorate($buffer, [
155
+ 'write' => function ($string) use ($buffer, $onWrite) {
156
+ $result = $buffer->write($string);
157
+ $onWrite($buffer, $string);
158
+ return $result;
159
+ }
160
+ ]);
161
+ }
162
+
163
+ return [$buffer, new self($buffer, $options)];
164
+ }
165
+
166
+ public function getSize()
167
+ {
168
+ return $this->size;
169
+ }
170
+
171
+ public function isWritable()
172
+ {
173
+ return false;
174
+ }
175
+
176
+ public function write($string)
177
+ {
178
+ return false;
179
+ }
180
+
181
+ public function read($length)
182
+ {
183
+ if (!$this->needsDrain && $this->drain) {
184
+ $this->needsDrain = $this->stream->getSize() >= $this->hwm;
185
+ }
186
+
187
+ $result = $this->stream->read($length);
188
+
189
+ // If we need to drain, then drain when the buffer is empty.
190
+ if ($this->needsDrain && $this->stream->getSize() === 0) {
191
+ $this->needsDrain = false;
192
+ $drainFn = $this->drain;
193
+ $drainFn($this->stream);
194
+ }
195
+
196
+ $resultLen = strlen($result);
197
+
198
+ // If a pump was provided, the buffer is still open, and not enough
199
+ // data was given, then block until the data is provided.
200
+ if ($this->pump && $resultLen < $length) {
201
+ $pumpFn = $this->pump;
202
+ $result .= $pumpFn($length - $resultLen);
203
+ }
204
+
205
+ return $result;
206
+ }
207
+ }
backend/vendor/guzzlehttp/streams/src/BufferStream.php ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Stream;
3
+
4
+ use GuzzleHttp\Stream\Exception\CannotAttachException;
5
+
6
+ /**
7
+ * Provides a buffer stream that can be written to to fill a buffer, and read
8
+ * from to remove bytes from the buffer.
9
+ *
10
+ * This stream returns a "hwm" metadata value that tells upstream consumers
11
+ * what the configured high water mark of the stream is, or the maximum
12
+ * preferred size of the buffer.
13
+ *
14
+ * @package GuzzleHttp\Stream
15
+ */
16
+ class BufferStream implements StreamInterface
17
+ {
18
+ private $hwm;
19
+ private $buffer = '';
20
+
21
+ /**
22
+ * @param int $hwm High water mark, representing the preferred maximum
23
+ * buffer size. If the size of the buffer exceeds the high
24
+ * water mark, then calls to write will continue to succeed
25
+ * but will return false to inform writers to slow down
26
+ * until the buffer has been drained by reading from it.
27
+ */
28
+ public function __construct($hwm = 16384)
29
+ {
30
+ $this->hwm = $hwm;
31
+ }
32
+
33
+ public function __toString()
34
+ {
35
+ return $this->getContents();
36
+ }
37
+
38
+ public function getContents()
39
+ {
40
+ $buffer = $this->buffer;
41
+ $this->buffer = '';
42
+
43
+ return $buffer;
44
+ }
45
+
46
+ public function close()
47
+ {
48
+ $this->buffer = '';
49
+ }
50
+
51
+ public function detach()
52
+ {
53
+ $this->close();
54
+ }
55
+
56
+ public function attach($stream)
57
+ {
58
+ throw new CannotAttachException();
59
+ }
60
+
61
+ public function getSize()
62
+ {
63
+ return strlen($this->buffer);
64
+ }
65
+
66
+ public function isReadable()
67
+ {
68
+ return true;
69
+ }
70
+
71
+ public function isWritable()
72
+ {
73
+ return true;
74
+ }
75
+
76
+ public function isSeekable()
77
+ {
78
+ return false;
79
+ }
80
+
81
+ public function seek($offset, $whence = SEEK_SET)
82
+ {
83
+ return false;
84
+ }
85
+
86
+ public function eof()
87
+ {
88
+ return strlen($this->buffer) === 0;
89
+ }
90
+
91
+ public function tell()
92
+ {
93
+ return false;
94
+ }
95
+
96
+ /**
97
+ * Reads data from the buffer.
98
+ */
99
+ public function read($length)
100
+ {
101
+ $currentLength = strlen($this->buffer);
102
+
103
+ if ($length >= $currentLength) {
104
+ // No need to slice the buffer because we don't have enough data.
105
+ $result = $this->buffer;
106
+ $this->buffer = '';
107
+ } else {
108
+ // Slice up the result to provide a subset of the buffer.
109
+ $result = substr($this->buffer, 0, $length);
110
+ $this->buffer = substr($this->buffer, $length);
111
+ }
112
+
113
+ return $result;
114
+ }
115
+
116
+ /**
117
+ * Writes data to the buffer.
118
+ */
119
+ public function write($string)
120
+ {
121
+ $this->buffer .= $string;
122
+
123
+ if (strlen($this->buffer) >= $this->hwm) {
124
+ return false;
125
+ }
126
+
127
+ return strlen($string);
128
+ }
129
+
130
+ public function getMetadata($key = null)
131
+ {
132
+ if ($key == 'hwm') {
133
+ return $this->hwm;
134
+ }
135
+
136
+ return $key ? null : [];
137
+ }
138
+ }
backend/vendor/guzzlehttp/streams/src/CachingStream.php ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Stream;
3
+
4
+ use GuzzleHttp\Stream\Exception\SeekException;
5
+
6
+ /**
7
+ * Stream decorator that can cache previously read bytes from a sequentially
8
+ * read stream.
9
+ */
10
+ class CachingStream implements StreamInterface
11
+ {
12
+ use StreamDecoratorTrait;
13
+
14
+ /** @var StreamInterface Stream being wrapped */
15
+ private $remoteStream;
16
+
17
+ /** @var int Number of bytes to skip reading due to a write on the buffer */
18
+ private $skipReadBytes = 0;
19
+
20
+ /**
21
+ * We will treat the buffer object as the body of the stream
22
+ *
23
+ * @param StreamInterface $stream Stream to cache
24
+ * @param StreamInterface $target Optionally specify where data is cached
25
+ */
26
+ public function __construct(
27
+ StreamInterface $stream,
28
+ StreamInterface $target = null
29
+ ) {
30
+ $this->remoteStream = $stream;
31
+ $this->stream = $target ?: new Stream(fopen('php://temp', 'r+'));
32
+ }
33
+
34
+ public function getSize()
35
+ {
36
+ return max($this->stream->getSize(), $this->remoteStream->getSize());
37
+ }
38
+
39
+ /**
40
+ * {@inheritdoc}
41
+ * @throws SeekException When seeking with SEEK_END or when seeking
42
+ * past the total size of the buffer stream
43
+ */
44
+ public function seek($offset, $whence = SEEK_SET)
45
+ {
46
+ if ($whence == SEEK_SET) {
47
+ $byte = $offset;
48
+ } elseif ($whence == SEEK_CUR) {
49
+ $byte = $offset + $this->tell();
50
+ } else {
51
+ return false;
52
+ }
53
+
54
+ // You cannot skip ahead past where you've read from the remote stream
55
+ if ($byte > $this->stream->getSize()) {
56
+ throw new SeekException(
57
+ $this,
58
+ $byte,
59
+ sprintf('Cannot seek to byte %d when the buffered stream only'
60
+ . ' contains %d bytes', $byte, $this->stream->getSize())
61
+ );
62
+ }
63
+
64
+ return $this->stream->seek($byte);
65
+ }
66
+
67
+ public function read($length)
68
+ {
69
+ // Perform a regular read on any previously read data from the buffer
70
+ $data = $this->stream->read($length);
71
+ $remaining = $length - strlen($data);
72
+
73
+ // More data was requested so read from the remote stream
74
+ if ($remaining) {
75
+ // If data was written to the buffer in a position that would have
76
+ // been filled from the remote stream, then we must skip bytes on
77
+ // the remote stream to emulate overwriting bytes from that
78
+ // position. This mimics the behavior of other PHP stream wrappers.
79
+ $remoteData = $this->remoteStream->read(
80
+ $remaining + $this->skipReadBytes
81
+ );
82
+
83
+ if ($this->skipReadBytes) {
84
+ $len = strlen($remoteData);
85
+ $remoteData = substr($remoteData, $this->skipReadBytes);
86
+ $this->skipReadBytes = max(0, $this->skipReadBytes - $len);
87
+ }
88
+
89
+ $data .= $remoteData;
90
+ $this->stream->write($remoteData);
91
+ }
92
+
93
+ return $data;
94
+ }
95
+
96
+ public function write($string)
97
+ {
98
+ // When appending to the end of the currently read stream, you'll want
99
+ // to skip bytes from being read from the remote stream to emulate
100
+ // other stream wrappers. Basically replacing bytes of data of a fixed
101
+ // length.
102
+ $overflow = (strlen($string) + $this->tell()) - $this->remoteStream->tell();
103
+ if ($overflow > 0) {
104
+ $this->skipReadBytes += $overflow;
105
+ }
106
+
107
+ return $this->stream->write($string);
108
+ }
109
+
110
+ public function eof()
111
+ {
112
+ return $this->stream->eof() && $this->remoteStream->eof();
113
+ }
114
+
115
+ /**
116
+ * Close both the remote stream and buffer stream
117
+ */
118
+ public function close()
119
+ {
120
+ $this->remoteStream->close() && $this->stream->close();
121
+ }
122
+ }
backend/vendor/guzzlehttp/streams/src/DroppingStream.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Stream;
3
+
4
+ /**
5
+ * Stream decorator that begins dropping data once the size of the underlying
6
+ * stream becomes too full.
7
+ */
8
+ class DroppingStream implements StreamInterface
9
+ {
10
+ use StreamDecoratorTrait;
11
+
12
+ private $maxLength;
13
+
14
+ /**
15
+ * @param StreamInterface $stream Underlying stream to decorate.
16
+ * @param int $maxLength Maximum size before dropping data.
17
+ */
18
+ public function __construct(StreamInterface $stream, $maxLength)
19
+ {
20
+ $this->stream = $stream;
21
+ $this->maxLength = $maxLength;
22
+ }
23
+
24
+ public function write($string)
25
+ {
26
+ $diff = $this->maxLength - $this->stream->getSize();
27
+
28
+ // Begin returning false when the underlying stream is too large.
29
+ if ($diff <= 0) {
30
+ return false;
31
+ }
32
+
33
+ // Write the stream or a subset of the stream if needed.
34
+ if (strlen($string) < $diff) {
35
+ return $this->stream->write($string);
36
+ }
37
+
38
+ $this->stream->write(substr($string, 0, $diff));
39
+
40
+ return false;
41
+ }
42
+ }
backend/vendor/guzzlehttp/streams/src/Exception/CannotAttachException.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Stream\Exception;
3
+
4
+ class CannotAttachException extends \RuntimeException {}
backend/vendor/guzzlehttp/streams/src/Exception/SeekException.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Stream\Exception;
3
+
4
+ use GuzzleHttp\Stream\StreamInterface;
5
+
6
+ /**
7
+ * Exception thrown when a seek fails on a stream.
8
+ */
9
+ class SeekException extends \RuntimeException
10
+ {
11
+ private $stream;
12
+
13
+ public function __construct(StreamInterface $stream, $pos = 0, $msg = '')
14
+ {
15
+ $this->stream = $stream;
16
+ $msg = $msg ?: 'Could not seek the stream to position ' . $pos;
17
+ parent::__construct($msg);
18
+ }
19
+
20
+ /**
21
+ * @return StreamInterface
22
+ */
23
+ public function getStream()
24
+ {
25
+ return $this->stream;
26
+ }
27
+ }
backend/vendor/guzzlehttp/streams/src/FnStream.php ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Stream;
3
+
4
+ /**
5
+ * Compose stream implementations based on a hash of functions.
6
+ *
7
+ * Allows for easy testing and extension of a provided stream without needing
8
+ * to create a concrete class for a simple extension point.
9
+ */
10
+ class FnStream implements StreamInterface
11
+ {
12
+ /** @var array */
13
+ private $methods;
14
+
15
+ /** @var array Methods that must be implemented in the given array */
16
+ private static $slots = ['__toString', 'close', 'detach', 'attach',
17
+ 'getSize', 'tell', 'eof', 'isSeekable', 'seek', 'isWritable', 'write',
18
+ 'isReadable', 'read', 'getContents', 'getMetadata'];
19
+
20
+ /**
21
+ * @param array $methods Hash of method name to a callable.
22
+ */
23
+ public function __construct(array $methods)
24
+ {
25
+ $this->methods = $methods;
26
+
27
+ // Create the functions on the class
28
+ foreach ($methods as $name => $fn) {
29
+ $this->{'_fn_' . $name} = $fn;
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Lazily determine which methods are not implemented.
35
+ * @throws \BadMethodCallException
36
+ */
37
+ public function __get($name)
38
+ {
39
+ throw new \BadMethodCallException(str_replace('_fn_', '', $name)
40
+ . '() is not implemented in the FnStream');
41
+ }
42
+
43
+ /**
44
+ * The close method is called on the underlying stream only if possible.
45
+ */
46
+ public function __destruct()
47
+ {
48
+ if (isset($this->_fn_close)) {
49
+ call_user_func($this->_fn_close);
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Adds custom functionality to an underlying stream by intercepting
55
+ * specific method calls.
56
+ *
57
+ * @param StreamInterface $stream Stream to decorate
58
+ * @param array $methods Hash of method name to a closure
59
+ *
60
+ * @return FnStream
61
+ */
62
+ public static function decorate(StreamInterface $stream, array $methods)
63
+ {
64
+ // If any of the required methods were not provided, then simply
65
+ // proxy to the decorated stream.
66
+ foreach (array_diff(self::$slots, array_keys($methods)) as $diff) {
67
+ $methods[$diff] = [$stream, $diff];
68
+ }
69
+
70
+ return new self($methods);
71
+ }
72
+
73
+ public function __toString()
74
+ {
75
+ return call_user_func($this->_fn___toString);
76
+ }
77
+
78
+ public function close()
79
+ {
80
+ return call_user_func($this->_fn_close);
81
+ }
82
+
83
+ public function detach()
84
+ {
85
+ return call_user_func($this->_fn_detach);
86
+ }
87
+
88
+ public function attach($stream)
89
+ {
90
+ return call_user_func($this->_fn_attach, $stream);
91
+ }
92
+
93
+ public function getSize()
94
+ {
95
+ return call_user_func($this->_fn_getSize);
96
+ }
97
+
98
+ public function tell()
99
+ {
100
+ return call_user_func($this->_fn_tell);
101
+ }
102
+
103
+ public function eof()
104
+ {
105
+ return call_user_func($this->_fn_eof);
106
+ }
107
+
108
+ public function isSeekable()
109
+ {
110
+ return call_user_func($this->_fn_isSeekable);
111
+ }
112
+
113
+ public function seek($offset, $whence = SEEK_SET)
114
+ {
115
+ return call_user_func($this->_fn_seek, $offset, $whence);
116
+ }
117
+
118
+ public function isWritable()
119
+ {
120
+ return call_user_func($this->_fn_isWritable);
121
+ }
122
+
123
+ public function write($string)
124
+ {
125
+ return call_user_func($this->_fn_write, $string);
126
+ }
127
+
128
+ public function isReadable()
129
+ {
130
+ return call_user_func($this->_fn_isReadable);
131
+ }
132
+
133
+ public function read($length)
134
+ {
135
+ return call_user_func($this->_fn_read, $length);
136
+ }
137
+
138
+ public function getContents()
139
+ {
140
+ return call_user_func($this->_fn_getContents);
141
+ }
142
+
143
+ public function getMetadata($key = null)
144
+ {
145
+ return call_user_func($this->_fn_getMetadata, $key);
146
+ }
147
+ }
backend/vendor/guzzlehttp/streams/src/GuzzleStreamWrapper.php ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Stream;
3
+
4
+ /**
5
+ * Converts Guzzle streams into PHP stream resources.
6
+ */
7
+ class GuzzleStreamWrapper
8
+ {
9
+ /** @var resource */
10
+ public $context;
11
+
12
+ /** @var StreamInterface */
13
+ private $stream;
14
+
15
+ /** @var string r, r+, or w */
16
+ private $mode;
17
+
18
+ /**
19
+ * Returns a resource representing the stream.
20
+ *
21
+ * @param StreamInterface $stream The stream to get a resource for
22
+ *
23
+ * @return resource
24
+ * @throws \InvalidArgumentException if stream is not readable or writable
25
+ */
26
+ public static function getResource(StreamInterface $stream)
27
+ {
28
+ self::register();
29
+
30
+ if ($stream->isReadable()) {
31
+ $mode = $stream->isWritable() ? 'r+' : 'r';
32
+ } elseif ($stream->isWritable()) {
33
+ $mode = 'w';
34
+ } else {
35
+ throw new \InvalidArgumentException('The stream must be readable, '
36
+ . 'writable, or both.');
37
+ }
38
+
39
+ return fopen('guzzle://stream', $mode, null, stream_context_create([
40
+ 'guzzle' => ['stream' => $stream]
41
+ ]));
42
+ }
43
+
44
+ /**
45
+ * Registers the stream wrapper if needed
46
+ */
47
+ public static function register()
48
+ {
49
+ if (!in_array('guzzle', stream_get_wrappers())) {
50
+ stream_wrapper_register('guzzle', __CLASS__);
51
+ }
52
+ }
53
+
54
+ public function stream_open($path, $mode, $options, &$opened_path)
55
+ {
56
+ $options = stream_context_get_options($this->context);
57
+
58
+ if (!isset($options['guzzle']['stream'])) {
59
+ return false;
60
+ }
61
+
62
+ $this->mode = $mode;
63
+ $this->stream = $options['guzzle']['stream'];
64
+
65
+ return true;
66
+ }
67
+
68
+ public function stream_read($count)
69
+ {
70
+ return $this->stream->read($count);
71
+ }
72
+
73
+ public function stream_write($data)
74
+ {
75
+ return (int) $this->stream->write($data);
76
+ }
77
+
78
+ public function stream_tell()
79
+ {
80
+ return $this->stream->tell();
81
+ }
82
+
83
+ public function stream_eof()
84
+ {
85
+ return $this->stream->eof();
86
+ }
87
+
88
+ public function stream_seek($offset, $whence)
89
+ {
90
+ return $this->stream->seek($offset, $whence);
91
+ }
92
+
93
+ public function stream_stat()
94
+ {
95
+ static $modeMap = [
96
+ 'r' => 33060,
97
+ 'r+' => 33206,
98
+ 'w' => 33188
99
+ ];
100
+
101
+ return [
102
+ 'dev' => 0,
103
+ 'ino' => 0,
104
+ 'mode' => $modeMap[$this->mode],
105
+ 'nlink' => 0,
106
+ 'uid' => 0,
107
+ 'gid' => 0,
108
+ 'rdev' => 0,
109
+ 'size' => $this->stream->getSize() ?: 0,
110
+ 'atime' => 0,
111
+ 'mtime' => 0,
112
+ 'ctime' => 0,
113
+ 'blksize' => 0,
114
+ 'blocks' => 0
115
+ ];
116
+ }
117
+ }
backend/vendor/guzzlehttp/streams/src/InflateStream.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Stream;
3
+
4
+ /**
5
+ * Uses PHP's zlib.inflate filter to inflate deflate or gzipped content.
6
+ *
7
+ * This stream decorator skips the first 10 bytes of the given stream to remove
8
+ * the gzip header, converts the provided stream to a PHP stream resource,
9
+ * then appends the zlib.inflate filter. The stream is then converted back
10
+ * to a Guzzle stream resource to be used as a Guzzle stream.
11
+ *
12
+ * @link http://tools.ietf.org/html/rfc1952
13
+ * @link http://php.net/manual/en/filters.compression.php
14
+ */
15
+ class InflateStream implements StreamInterface
16
+ {
17
+ use StreamDecoratorTrait;
18
+
19
+ public function __construct(StreamInterface $stream)
20
+ {
21
+ // Skip the first 10 bytes
22
+ $stream = new LimitStream($stream, -1, 10);
23
+ $resource = GuzzleStreamWrapper::getResource($stream);
24
+ stream_filter_append($resource, 'zlib.inflate', STREAM_FILTER_READ);
25
+ $this->stream = new Stream($resource);
26
+ }
27
+ }
backend/vendor/guzzlehttp/streams/src/LazyOpenStream.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Stream;
3
+
4
+ /**
5
+ * Lazily reads or writes to a file that is opened only after an IO operation
6
+ * take place on the stream.
7
+ */
8
+ class LazyOpenStream implements StreamInterface
9
+ {
10
+ use StreamDecoratorTrait;
11
+
12
+ /** @var string File to open */
13
+ private $filename;
14
+
15
+ /** @var string $mode */
16
+ private $mode;
17
+
18
+ /**
19
+ * @param string $filename File to lazily open
20
+ * @param string $mode fopen mode to use when opening the stream
21
+ */
22
+ public function __construct($filename, $mode)
23
+ {
24
+ $this->filename = $filename;
25
+ $this->mode = $mode;
26
+ }
27
+
28
+ /**
29
+ * Creates the underlying stream lazily when required.
30
+ *
31
+ * @return StreamInterface
32
+ */
33
+ protected function createStream()
34
+ {
35
+ return Stream::factory(Utils::open($this->filename, $this->mode));
36
+ }
37
+ }
backend/vendor/guzzlehttp/streams/src/LimitStream.php ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Stream;
3
+
4
+ use GuzzleHttp\Stream\Exception\SeekException;
5
+
6
+ /**
7
+ * Decorator used to return only a subset of a stream
8
+ */
9
+ class LimitStream implements StreamInterface
10
+ {
11
+ use StreamDecoratorTrait;
12
+
13
+ /** @var int Offset to start reading from */
14
+ private $offset;
15
+
16
+ /** @var int Limit the number of bytes that can be read */
17
+ private $limit;
18
+
19
+ /**
20
+ * @param StreamInterface $stream Stream to wrap
21
+ * @param int $limit Total number of bytes to allow to be read
22
+ * from the stream. Pass -1 for no limit.
23
+ * @param int|null $offset Position to seek to before reading (only
24
+ * works on seekable streams).
25
+ */
26
+ public function __construct(
27
+ StreamInterface $stream,
28
+ $limit = -1,
29
+ $offset = 0
30
+ ) {
31
+ $this->stream = $stream;
32
+ $this->setLimit($limit);
33
+ $this->setOffset($offset);
34
+ }
35
+
36
+ public function eof()
37
+ {
38
+ // Always return true if the underlying stream is EOF
39
+ if ($this->stream->eof()) {
40
+ return true;
41
+ }
42
+
43
+ // No limit and the underlying stream is not at EOF
44
+ if ($this->limit == -1) {
45
+ return false;
46
+ }
47
+
48
+ $tell = $this->stream->tell();
49
+ if ($tell === false) {
50
+ return false;
51
+ }
52
+
53
+ return $tell >= $this->offset + $this->limit;
54
+ }
55
+
56
+ /**
57
+ * Returns the size of the limited subset of data
58
+ * {@inheritdoc}
59
+ */
60
+ public function getSize()
61
+ {
62
+ if (null === ($length = $this->stream->getSize())) {
63
+ return null;
64
+ } elseif ($this->limit == -1) {
65
+ return $length - $this->offset;
66
+ } else {
67
+ return min($this->limit, $length - $this->offset);
68
+ }
69
+ }
70
+
71
+ /**
72
+ * Allow for a bounded seek on the read limited stream
73
+ * {@inheritdoc}
74
+ */
75
+ public function seek($offset, $whence = SEEK_SET)
76
+ {
77
+ if ($whence !== SEEK_SET || $offset < 0) {
78
+ return false;
79
+ }
80
+
81
+ $offset += $this->offset;
82
+
83
+ if ($this->limit !== -1) {
84
+ if ($offset > $this->offset + $this->limit) {
85
+ $offset = $this->offset + $this->limit;
86
+ }
87
+ }
88
+
89
+ return $this->stream->seek($offset);
90
+ }
91
+
92
+ /**
93
+ * Give a relative tell()
94
+ * {@inheritdoc}
95
+ */
96
+ public function tell()
97
+ {
98
+ return $this->stream->tell() - $this->offset;
99
+ }
100
+
101
+ /**
102
+ * Set the offset to start limiting from
103
+ *
104
+ * @param int $offset Offset to seek to and begin byte limiting from
105
+ *
106
+ * @return self
107
+ * @throws SeekException
108
+ */
109
+ public function setOffset($offset)
110
+ {
111
+ $current = $this->stream->tell();
112
+
113
+ if ($current !== $offset) {
114
+ // If the stream cannot seek to the offset position, then read to it
115
+ if (!$this->stream->seek($offset)) {
116
+ if ($current > $offset) {
117
+ throw new SeekException($this, $offset);
118
+ } else {
119
+ $this->stream->read($offset - $current);
120
+ }
121
+ }
122
+ }
123
+
124
+ $this->offset = $offset;
125
+
126
+ return $this;
127
+ }
128
+
129
+ /**
130
+ * Set the limit of bytes that the decorator allows to be read from the
131
+ * stream.
132
+ *
133
+ * @param int $limit Number of bytes to allow to be read from the stream.
134
+ * Use -1 for no limit.
135
+ * @return self
136
+ */
137
+ public function setLimit($limit)
138
+ {
139
+ $this->limit = $limit;
140
+
141
+ return $this;
142
+ }
143
+
144
+ public function read($length)
145
+ {
146
+ if ($this->limit == -1) {
147
+ return $this->stream->read($length);
148
+ }
149
+
150
+ // Check if the current position is less than the total allowed
151
+ // bytes + original offset
152
+ $remaining = ($this->offset + $this->limit) - $this->stream->tell();
153
+ if ($remaining > 0) {
154
+ // Only return the amount of requested data, ensuring that the byte
155
+ // limit is not exceeded
156
+ return $this->stream->read(min($remaining, $length));
157
+ } else {
158
+ return false;
159
+ }
160
+ }
161
+ }
backend/vendor/guzzlehttp/streams/src/MetadataStreamInterface.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Stream;
3
+
4
+ /**
5
+ * This interface is deprecated and should no longer be used. Just use
6
+ * StreamInterface now that the getMetadata method has been added to
7
+ * StreamInterface.
8
+ *
9
+ * @deprecated
10
+ */
11
+ interface MetadataStreamInterface extends StreamInterface {}
backend/vendor/guzzlehttp/streams/src/NoSeekStream.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Stream;
3
+
4
+ /**
5
+ * Stream decorator that prevents a stream from being seeked
6
+ */
7
+ class NoSeekStream implements StreamInterface
8
+ {
9
+ use StreamDecoratorTrait;
10
+
11
+ public function seek($offset, $whence = SEEK_SET)
12
+ {
13
+ return false;
14
+ }
15
+
16
+ public function isSeekable()
17
+ {
18
+ return false;
19
+ }
20
+
21
+ public function attach($stream)
22
+ {
23
+ $this->stream->attach($stream);
24
+ }
25
+ }
backend/vendor/guzzlehttp/streams/src/NullStream.php ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Stream;
3
+ use GuzzleHttp\Stream\Exception\CannotAttachException;
4
+
5
+ /**
6
+ * Does not store any data written to it.
7
+ */
8
+ class NullStream implements StreamInterface
9
+ {
10
+ public function __toString()
11
+ {
12
+ return '';
13
+ }
14
+
15
+ public function getContents()
16
+ {
17
+ return '';
18
+ }
19
+
20
+ public function close() {}
21
+
22
+ public function detach() {}
23
+
24
+ public function attach($stream)
25
+ {
26
+ throw new CannotAttachException();
27
+ }
28
+
29
+ public function getSize()
30
+ {
31
+ return 0;
32
+ }
33
+
34
+ public function isReadable()
35
+ {
36
+ return true;
37
+ }
38
+
39
+ public function isWritable()
40
+ {
41
+ return true;
42
+ }
43
+
44
+ public function isSeekable()
45
+ {
46
+ return true;
47
+ }
48
+
49
+ public function eof()
50
+ {
51
+ return true;
52
+ }
53
+
54
+ public function tell()
55
+ {
56
+ return 0;
57
+ }
58
+
59
+ public function seek($offset, $whence = SEEK_SET)
60
+ {
61
+ return false;
62
+ }
63
+
64
+ public function read($length)
65
+ {
66
+ return false;
67
+ }
68
+
69
+ public function write($string)
70
+ {
71
+ return strlen($string);
72
+ }
73
+
74
+ public function getMetadata($key = null)
75
+ {
76
+ return $key ? null : [];
77
+ }
78
+ }
backend/vendor/guzzlehttp/streams/src/PumpStream.php ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Stream;
3
+
4
+ use GuzzleHttp\Stream\Exception\CannotAttachException;
5
+
6
+ /**
7
+ * Provides a read only stream that pumps data from a PHP callable.
8
+ *
9
+ * When invoking the provided callable, the PumpStream will pass the amount of
10
+ * data requested to read to the callable. The callable can choose to ignore
11
+ * this value and return fewer or more bytes than requested. Any extra data
12
+ * returned by the provided callable is buffered internally until drained using
13
+ * the read() function of the PumpStream. The provided callable MUST return
14
+ * false when there is no more data to read.
15
+ */
16
+ class PumpStream implements StreamInterface
17
+ {
18
+ /** @var callable */
19
+ private $source;
20
+
21
+ /** @var int */
22
+ private $size;
23
+
24
+ /** @var int */
25
+ private $tellPos = 0;
26
+
27
+ /** @var array */
28
+ private $metadata;
29
+
30
+ /** @var BufferStream */
31
+ private $buffer;
32
+
33
+ /**
34
+ * @param callable $source Source of the stream data. The callable MAY
35
+ * accept an integer argument used to control the
36
+ * amount of data to return. The callable MUST
37
+ * return a string when called, or false on error
38
+ * or EOF.
39
+ * @param array $options Stream options:
40
+ * - metadata: Hash of metadata to use with stream.
41
+ * - size: Size of the stream, if known.
42
+ */
43
+ public function __construct(callable $source, array $options = [])
44
+ {
45
+ $this->source = $source;
46
+ $this->size = isset($options['size']) ? $options['size'] : null;
47
+ $this->metadata = isset($options['metadata']) ? $options['metadata'] : [];
48
+ $this->buffer = new BufferStream();
49
+ }
50
+
51
+ public function __toString()
52
+ {
53
+ return Utils::copyToString($this);
54
+ }
55
+
56
+ public function close()
57
+ {
58
+ $this->detach();
59
+ }
60
+
61
+ public function detach()
62
+ {
63
+ $this->tellPos = false;
64
+ $this->source = null;
65
+ }
66
+
67
+ public function attach($stream)
68
+ {
69
+ throw new CannotAttachException();
70
+ }
71
+
72
+ public function getSize()
73
+ {
74
+ return $this->size;
75
+ }
76
+
77
+ public function tell()
78
+ {
79
+ return $this->tellPos;
80
+ }
81
+
82
+ public function eof()
83
+ {
84
+ return !$this->source;
85
+ }
86
+
87
+ public function isSeekable()
88
+ {
89
+ return false;
90
+ }
91
+
92
+ public function seek($offset, $whence = SEEK_SET)
93
+ {
94
+ return false;
95
+ }
96
+
97
+ public function isWritable()
98
+ {
99
+ return false;
100
+ }
101
+
102
+ public function write($string)
103
+ {
104
+ return false;
105
+ }
106
+
107
+ public function isReadable()
108
+ {
109
+ return true;
110
+ }
111
+
112
+ public function read($length)
113
+ {
114
+ $data = $this->buffer->read($length);
115
+ $readLen = strlen($data);
116
+ $this->tellPos += $readLen;
117
+ $remaining = $length - $readLen;
118
+
119
+ if ($remaining) {
120
+ $this->pump($remaining);
121
+ $data .= $this->buffer->read($remaining);
122
+ $this->tellPos += strlen($data) - $readLen;
123
+ }
124
+
125
+ return $data;
126
+ }
127
+
128
+ public function getContents()
129
+ {
130
+ $result = '';
131
+ while (!$this->eof()) {
132
+ $result .= $this->read(1000000);
133
+ }
134
+
135
+ return $result;
136
+ }
137
+
138
+ public function getMetadata($key = null)
139
+ {
140
+ if (!$key) {
141
+ return $this->metadata;
142
+ }
143
+
144
+ return isset($this->metadata[$key]) ? $this->metadata[$key] : null;
145
+ }
146
+
147
+ private function pump($length)
148
+ {
149
+ if ($this->source) {
150
+ do {
151
+ $data = call_user_func($this->source, $length);
152
+ if ($data === false || $data === null) {
153
+ $this->source = null;
154
+ return;
155
+ }
156
+ $this->buffer->write($data);
157
+ $length -= strlen($data);
158
+ } while ($length > 0);
159
+ }
160
+ }
161
+ }
backend/vendor/guzzlehttp/streams/src/Stream.php ADDED
@@ -0,0 +1,261 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Stream;
3
+
4
+ /**
5
+ * PHP stream implementation
6
+ */
7
+ class Stream implements StreamInterface
8
+ {
9
+ private $stream;
10
+ private $size;
11
+ private $seekable;
12
+ private $readable;
13
+ private $writable;
14
+ private $uri;
15
+ private $customMetadata;
16
+
17
+ /** @var array Hash of readable and writable stream types */
18
+ private static $readWriteHash = [
19
+ 'read' => [
20
+ 'r' => true, 'w+' => true, 'r+' => true, 'x+' => true, 'c+' => true,
21
+ 'rb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true,
22
+ 'c+b' => true, 'rt' => true, 'w+t' => true, 'r+t' => true,
23
+ 'x+t' => true, 'c+t' => true, 'a+' => true
24
+ ],
25
+ 'write' => [
26
+ 'w' => true, 'w+' => true, 'rw' => true, 'r+' => true, 'x+' => true,
27
+ 'c+' => true, 'wb' => true, 'w+b' => true, 'r+b' => true,
28
+ 'x+b' => true, 'c+b' => true, 'w+t' => true, 'r+t' => true,
29
+ 'x+t' => true, 'c+t' => true, 'a' => true, 'a+' => true
30
+ ]
31
+ ];
32
+
33
+ /**
34
+ * Create a new stream based on the input type.
35
+ *
36
+ * This factory accepts the same associative array of options as described
37
+ * in the constructor.
38
+ *
39
+ * @param resource|string|StreamInterface $resource Entity body data
40
+ * @param array $options Additional options
41
+ *
42
+ * @return Stream
43
+ * @throws \InvalidArgumentException if the $resource arg is not valid.
44
+ */
45
+ public static function factory($resource = '', array $options = [])
46
+ {
47
+ $type = gettype($resource);
48
+
49
+ if ($type == 'string') {
50
+ $stream = fopen('php://temp', 'r+');
51
+ if ($resource !== '') {
52
+ fwrite($stream, $resource);
53
+ fseek($stream, 0);
54
+ }
55
+ return new self($stream, $options);
56
+ }
57
+
58
+ if ($type == 'resource') {
59
+ return new self($resource, $options);
60
+ }
61
+
62
+ if ($resource instanceof StreamInterface) {
63
+ return $resource;
64
+ }
65
+
66
+ if ($type == 'object' && method_exists($resource, '__toString')) {
67
+ return self::factory((string) $resource, $options);
68
+ }
69
+
70
+ if (is_callable($resource)) {
71
+ return new PumpStream($resource, $options);
72
+ }
73
+
74
+ if ($resource instanceof \Iterator) {
75
+ return new PumpStream(function () use ($resource) {
76
+ if (!$resource->valid()) {
77
+ return false;
78
+ }
79
+ $result = $resource->current();
80
+ $resource->next();
81
+ return $result;
82
+ }, $options);
83
+ }
84
+
85
+ throw new \InvalidArgumentException('Invalid resource type: ' . $type);
86
+ }
87
+
88
+ /**
89
+ * This constructor accepts an associative array of options.
90
+ *
91
+ * - size: (int) If a read stream would otherwise have an indeterminate
92
+ * size, but the size is known due to foreknownledge, then you can
93
+ * provide that size, in bytes.
94
+ * - metadata: (array) Any additional metadata to return when the metadata
95
+ * of the stream is accessed.
96
+ *
97
+ * @param resource $stream Stream resource to wrap.
98
+ * @param array $options Associative array of options.
99
+ *
100
+ * @throws \InvalidArgumentException if the stream is not a stream resource
101
+ */
102
+ public function __construct($stream, $options = [])
103
+ {
104
+ if (!is_resource($stream)) {
105
+ throw new \InvalidArgumentException('Stream must be a resource');
106
+ }
107
+
108
+ if (isset($options['size'])) {
109
+ $this->size = $options['size'];
110
+ }
111
+
112
+ $this->customMetadata = isset($options['metadata'])
113
+ ? $options['metadata']
114
+ : [];
115
+
116
+ $this->attach($stream);
117
+ }
118
+
119
+ /**
120
+ * Closes the stream when the destructed
121
+ */
122
+ public function __destruct()
123
+ {
124
+ $this->close();
125
+ }
126
+
127
+ public function __toString()
128
+ {
129
+ if (!$this->stream) {
130
+ return '';
131
+ }
132
+
133
+ $this->seek(0);
134
+
135
+ return (string) stream_get_contents($this->stream);
136
+ }
137
+
138
+ public function getContents()
139
+ {
140
+ return $this->stream ? stream_get_contents($this->stream) : '';
141
+ }
142
+
143
+ public function close()
144
+ {
145
+ if (is_resource($this->stream)) {
146
+ fclose($this->stream);
147
+ }
148
+
149
+ $this->detach();
150
+ }
151
+
152
+ public function detach()
153
+ {
154
+ $result = $this->stream;
155
+ $this->stream = $this->size = $this->uri = null;
156
+ $this->readable = $this->writable = $this->seekable = false;
157
+
158
+ return $result;
159
+ }
160
+
161
+ public function attach($stream)
162
+ {
163
+ $this->stream = $stream;
164
+ $meta = stream_get_meta_data($this->stream);
165
+ $this->seekable = $meta['seekable'];
166
+ $this->readable = isset(self::$readWriteHash['read'][$meta['mode']]);
167
+ $this->writable = isset(self::$readWriteHash['write'][$meta['mode']]);
168
+ $this->uri = $this->getMetadata('uri');
169
+ }
170
+
171
+ public function getSize()
172
+ {
173
+ if ($this->size !== null) {
174
+ return $this->size;
175
+ }
176
+
177
+ if (!$this->stream) {
178
+ return null;
179
+ }
180
+
181
+ // Clear the stat cache if the stream has a URI
182
+ if ($this->uri) {
183
+ clearstatcache(true, $this->uri);
184
+ }
185
+
186
+ $stats = fstat($this->stream);
187
+ if (isset($stats['size'])) {
188
+ $this->size = $stats['size'];
189
+ return $this->size;
190
+ }
191
+
192
+ return null;
193
+ }
194
+
195
+ public function isReadable()
196
+ {
197
+ return $this->readable;
198
+ }
199
+
200
+ public function isWritable()
201
+ {
202
+ return $this->writable;
203
+ }
204
+
205
+ public function isSeekable()
206
+ {
207
+ return $this->seekable;
208
+ }
209
+
210
+ public function eof()
211
+ {
212
+ return !$this->stream || feof($this->stream);
213
+ }
214
+
215
+ public function tell()
216
+ {
217
+ return $this->stream ? ftell($this->stream) : false;
218
+ }
219
+
220
+ public function setSize($size)
221
+ {
222
+ $this->size = $size;
223
+
224
+ return $this;
225
+ }
226
+
227
+ public function seek($offset, $whence = SEEK_SET)
228
+ {
229
+ return $this->seekable
230
+ ? fseek($this->stream, $offset, $whence) === 0
231
+ : false;
232
+ }
233
+
234
+ public function read($length)
235
+ {
236
+ return $this->readable ? fread($this->stream, $length) : false;
237
+ }
238
+
239
+ public function write($string)
240
+ {
241
+ // We can't know the size after writing anything
242
+ $this->size = null;
243
+
244
+ return $this->writable ? fwrite($this->stream, $string) : false;
245
+ }
246
+
247
+ public function getMetadata($key = null)
248
+ {
249
+ if (!$this->stream) {
250
+ return $key ? null : [];
251
+ } elseif (!$key) {
252
+ return $this->customMetadata + stream_get_meta_data($this->stream);
253
+ } elseif (isset($this->customMetadata[$key])) {
254
+ return $this->customMetadata[$key];
255
+ }
256
+
257
+ $meta = stream_get_meta_data($this->stream);
258
+
259
+ return isset($meta[$key]) ? $meta[$key] : null;
260
+ }
261
+ }
backend/vendor/guzzlehttp/streams/src/StreamDecoratorTrait.php ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Stream;
3
+ use GuzzleHttp\Stream\Exception\CannotAttachException;
4
+
5
+ /**
6
+ * Stream decorator trait
7
+ * @property StreamInterface stream
8
+ */
9
+ trait StreamDecoratorTrait
10
+ {
11
+ /**
12
+ * @param StreamInterface $stream Stream to decorate
13
+ */
14
+ public function __construct(StreamInterface $stream)
15
+ {
16
+ $this->stream = $stream;
17
+ }
18
+
19
+ /**
20
+ * Magic method used to create a new stream if streams are not added in
21
+ * the constructor of a decorator (e.g., LazyOpenStream).
22
+ */
23
+ public function __get($name)
24
+ {
25
+ if ($name == 'stream') {
26
+ $this->stream = $this->createStream();
27
+ return $this->stream;
28
+ }
29
+
30
+ throw new \UnexpectedValueException("$name not found on class");
31
+ }
32
+
33
+ public function __toString()
34
+ {
35
+ try {
36
+ $this->seek(0);
37
+ return $this->getContents();
38
+ } catch (\Exception $e) {
39
+ // Really, PHP? https://bugs.php.net/bug.php?id=53648
40
+ trigger_error('StreamDecorator::__toString exception: '
41
+ . (string) $e, E_USER_ERROR);
42
+ return '';
43
+ }
44
+ }
45
+
46
+ public function getContents()
47
+ {
48
+ return Utils::copyToString($this);
49
+ }
50
+
51
+ /**
52
+ * Allow decorators to implement custom methods
53
+ *
54
+ * @param string $method Missing method name
55
+ * @param array $args Method arguments
56
+ *
57
+ * @return mixed
58
+ */
59
+ public function __call($method, array $args)
60
+ {
61
+ $result = call_user_func_array(array($this->stream, $method), $args);
62
+
63
+ // Always return the wrapped object if the result is a return $this
64
+ return $result === $this->stream ? $this : $result;
65
+ }
66
+
67
+ public function close()
68
+ {
69
+ $this->stream->close();
70
+ }
71
+
72
+ public function getMetadata($key = null)
73
+ {
74
+ return $this->stream->getMetadata($key);
75
+ }
76
+
77
+ public function detach()
78
+ {
79
+ return $this->stream->detach();
80
+ }
81
+
82
+ public function attach($stream)
83
+ {
84
+ throw new CannotAttachException();
85
+ }
86
+
87
+ public function getSize()
88
+ {
89
+ return $this->stream->getSize();
90
+ }
91
+
92
+ public function eof()
93
+ {
94
+ return $this->stream->eof();
95
+ }
96
+
97
+ public function tell()
98
+ {
99
+ return $this->stream->tell();
100
+ }
101
+
102
+ public function isReadable()
103
+ {
104
+ return $this->stream->isReadable();
105
+ }
106
+
107
+ public function isWritable()
108
+ {
109
+ return $this->stream->isWritable();
110
+ }
111
+
112
+ public function isSeekable()
113
+ {
114
+ return $this->stream->isSeekable();
115
+ }
116
+
117
+ public function seek($offset, $whence = SEEK_SET)
118
+ {
119
+ return $this->stream->seek($offset, $whence);
120
+ }
121
+
122
+ public function read($length)
123
+ {
124
+ return $this->stream->read($length);
125
+ }
126
+
127
+ public function write($string)
128
+ {
129
+ return $this->stream->write($string);
130
+ }
131
+
132
+ /**
133
+ * Implement in subclasses to dynamically create streams when requested.
134
+ *
135
+ * @return StreamInterface
136
+ * @throws \BadMethodCallException
137
+ */
138
+ protected function createStream()
139
+ {
140
+ throw new \BadMethodCallException('createStream() not implemented in '
141
+ . get_class($this));
142
+ }
143
+ }
backend/vendor/guzzlehttp/streams/src/StreamInterface.php ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Stream;
3
+
4
+ /**
5
+ * Describes a stream instance.
6
+ */
7
+ interface StreamInterface
8
+ {
9
+ /**
10
+ * Attempts to seek to the beginning of the stream and reads all data into
11
+ * a string until the end of the stream is reached.
12
+ *
13
+ * Warning: This could attempt to load a large amount of data into memory.
14
+ *
15
+ * @return string
16
+ */
17
+ public function __toString();
18
+
19
+ /**
20
+ * Closes the stream and any underlying resources.
21
+ */
22
+ public function close();
23
+
24
+ /**
25
+ * Separates any underlying resources from the stream.
26
+ *
27
+ * After the underlying resource has been detached, the stream object is in
28
+ * an unusable state. If you wish to use a Stream object as a PHP stream
29
+ * but keep the Stream object in a consistent state, use
30
+ * {@see GuzzleHttp\Stream\GuzzleStreamWrapper::getResource}.
31
+ *
32
+ * @return resource|null Returns the underlying PHP stream resource or null
33
+ * if the Stream object did not utilize an underlying
34
+ * stream resource.
35
+ */
36
+ public function detach();
37
+
38
+ /**
39
+ * Replaces the underlying stream resource with the provided stream.
40
+ *
41
+ * Use this method to replace the underlying stream with another; as an
42
+ * example, in server-side code, if you decide to return a file, you
43
+ * would replace the original content-oriented stream with the file
44
+ * stream.
45
+ *
46
+ * Any internal state such as caching of cursor position should be reset
47
+ * when attach() is called, as the stream has changed.
48
+ *
49
+ * @param resource $stream
50
+ *
51
+ * @return void
52
+ */
53
+ public function attach($stream);
54
+
55
+ /**
56
+ * Get the size of the stream if known
57
+ *
58
+ * @return int|null Returns the size in bytes if known, or null if unknown
59
+ */
60
+ public function getSize();
61
+
62
+ /**
63
+ * Returns the current position of the file read/write pointer
64
+ *
65
+ * @return int|bool Returns the position of the file pointer or false on error
66
+ */
67
+ public function tell();
68
+
69
+ /**
70
+ * Returns true if the stream is at the end of the stream.
71
+ *
72
+ * @return bool
73
+ */
74
+ public function eof();
75
+
76
+ /**
77
+ * Returns whether or not the stream is seekable
78
+ *
79
+ * @return bool
80
+ */
81
+ public function isSeekable();
82
+
83
+ /**
84
+ * Seek to a position in the stream
85
+ *
86
+ * @param int $offset Stream offset
87
+ * @param int $whence Specifies how the cursor position will be calculated
88
+ * based on the seek offset. Valid values are identical
89
+ * to the built-in PHP $whence values for `fseek()`.
90
+ * SEEK_SET: Set position equal to offset bytes
91
+ * SEEK_CUR: Set position to current location plus offset
92
+ * SEEK_END: Set position to end-of-stream plus offset
93
+ *
94
+ * @return bool Returns true on success or false on failure
95
+ * @link http://www.php.net/manual/en/function.fseek.php
96
+ */
97
+ public function seek($offset, $whence = SEEK_SET);
98
+
99
+ /**
100
+ * Returns whether or not the stream is writable
101
+ *
102
+ * @return bool
103
+ */
104
+ public function isWritable();
105
+
106
+ /**
107
+ * Write data to the stream
108
+ *
109
+ * @param string $string The string that is to be written.
110
+ *
111
+ * @return int|bool Returns the number of bytes written to the stream on
112
+ * success returns false on failure (e.g., broken pipe,
113
+ * writer needs to slow down, buffer is full, etc.)
114
+ */
115
+ public function write($string);
116
+
117
+ /**
118
+ * Returns whether or not the stream is readable
119
+ *
120
+ * @return bool
121
+ */
122
+ public function isReadable();
123
+
124
+ /**
125
+ * Read data from the stream
126
+ *
127
+ * @param int $length Read up to $length bytes from the object and return
128
+ * them. Fewer than $length bytes may be returned if
129
+ * underlying stream call returns fewer bytes.
130
+ *
131
+ * @return string Returns the data read from the stream.
132
+ */
133
+ public function read($length);
134
+
135
+ /**
136
+ * Returns the remaining contents of the stream as a string.
137
+ *
138
+ * Note: this could potentially load a large amount of data into memory.
139
+ *
140
+ * @return string
141
+ */
142
+ public function getContents();
143
+
144
+ /**
145
+ * Get stream metadata as an associative array or retrieve a specific key.
146
+ *
147
+ * The keys returned are identical to the keys returned from PHP's
148
+ * stream_get_meta_data() function.
149
+ *
150
+ * @param string $key Specific metadata to retrieve.
151
+ *
152
+ * @return array|mixed|null Returns an associative array if no key is
153
+ * no key is provided. Returns a specific key
154
+ * value if a key is provided and the value is
155
+ * found, or null if the key is not found.
156
+ * @see http://php.net/manual/en/function.stream-get-meta-data.php
157
+ */
158
+ public function getMetadata($key = null);
159
+ }
backend/vendor/guzzlehttp/streams/src/Utils.php ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Stream;
3
+
4
+ use GuzzleHttp\Stream\Exception\SeekException;
5
+
6
+ /**
7
+ * Static utility class because PHP's autoloaders don't support the concept
8
+ * of namespaced function autoloading.
9
+ */
10
+ class Utils
11
+ {
12
+ /**
13
+ * Safely opens a PHP stream resource using a filename.
14
+ *
15
+ * When fopen fails, PHP normally raises a warning. This function adds an
16
+ * error handler that checks for errors and throws an exception instead.
17
+ *
18
+ * @param string $filename File to open
19
+ * @param string $mode Mode used to open the file
20
+ *
21
+ * @return resource
22
+ * @throws \RuntimeException if the file cannot be opened
23
+ */
24
+ public static function open($filename, $mode)
25
+ {
26
+ $ex = null;
27
+ set_error_handler(function () use ($filename, $mode, &$ex) {
28
+ $ex = new \RuntimeException(sprintf(
29
+ 'Unable to open %s using mode %s: %s',
30
+ $filename,
31
+ $mode,
32
+ func_get_args()[1]
33
+ ));
34
+ });
35
+
36
+ $handle = fopen($filename, $mode);
37
+ restore_error_handler();
38
+
39
+ if ($ex) {
40
+ /** @var $ex \RuntimeException */
41
+ throw $ex;
42
+ }
43
+
44
+ return $handle;
45
+ }
46
+
47
+ /**
48
+ * Copy the contents of a stream into a string until the given number of
49
+ * bytes have been read.
50
+ *
51
+ * @param StreamInterface $stream Stream to read
52
+ * @param int $maxLen Maximum number of bytes to read. Pass -1
53
+ * to read the entire stream.
54
+ * @return string
55
+ */
56
+ public static function copyToString(StreamInterface $stream, $maxLen = -1)
57
+ {
58
+ $buffer = '';
59
+
60
+ if ($maxLen === -1) {
61
+ while (!$stream->eof()) {
62
+ $buf = $stream->read(1048576);
63
+ if ($buf === false) {
64
+ break;
65
+ }
66
+ $buffer .= $buf;
67
+ }
68
+ return $buffer;
69
+ }
70
+
71
+ $len = 0;
72
+ while (!$stream->eof() && $len < $maxLen) {
73
+ $buf = $stream->read($maxLen - $len);
74
+ if ($buf === false) {
75
+ break;
76
+ }
77
+ $buffer .= $buf;
78
+ $len = strlen($buffer);
79
+ }
80
+
81
+ return $buffer;
82
+ }
83
+
84
+ /**
85
+ * Copy the contents of a stream into another stream until the given number
86
+ * of bytes have been read.
87
+ *
88
+ * @param StreamInterface $source Stream to read from
89
+ * @param StreamInterface $dest Stream to write to
90
+ * @param int $maxLen Maximum number of bytes to read. Pass -1
91
+ * to read the entire stream.
92
+ */
93
+ public static function copyToStream(
94
+ StreamInterface $source,
95
+ StreamInterface $dest,
96
+ $maxLen = -1
97
+ ) {
98
+ if ($maxLen === -1) {
99
+ while (!$source->eof()) {
100
+ if (!$dest->write($source->read(1048576))) {
101
+ break;
102
+ }
103
+ }
104
+ return;
105
+ }
106
+
107
+ $bytes = 0;
108
+ while (!$source->eof()) {
109
+ $buf = $source->read($maxLen - $bytes);
110
+ if (!($len = strlen($buf))) {
111
+ break;
112
+ }
113
+ $bytes += $len;
114
+ $dest->write($buf);
115
+ if ($bytes == $maxLen) {
116
+ break;
117
+ }
118
+ }
119
+ }
120
+
121
+ /**
122
+ * Calculate a hash of a Stream
123
+ *
124
+ * @param StreamInterface $stream Stream to calculate the hash for
125
+ * @param string $algo Hash algorithm (e.g. md5, crc32, etc)
126
+ * @param bool $rawOutput Whether or not to use raw output
127
+ *
128
+ * @return string Returns the hash of the stream
129
+ * @throws SeekException
130
+ */
131
+ public static function hash(
132
+ StreamInterface $stream,
133
+ $algo,
134
+ $rawOutput = false
135
+ ) {
136
+ $pos = $stream->tell();
137
+
138
+ if ($pos > 0 && !$stream->seek(0)) {
139
+ throw new SeekException($stream);
140
+ }
141
+
142
+ $ctx = hash_init($algo);
143
+ while (!$stream->eof()) {
144
+ hash_update($ctx, $stream->read(1048576));
145
+ }
146
+
147
+ $out = hash_final($ctx, (bool) $rawOutput);
148
+ $stream->seek($pos);
149
+
150
+ return $out;
151
+ }
152
+
153
+ /**
154
+ * Read a line from the stream up to the maximum allowed buffer length
155
+ *
156
+ * @param StreamInterface $stream Stream to read from
157
+ * @param int $maxLength Maximum buffer length
158
+ *
159
+ * @return string|bool
160
+ */
161
+ public static function readline(StreamInterface $stream, $maxLength = null)
162
+ {
163
+ $buffer = '';
164
+ $size = 0;
165
+
166
+ while (!$stream->eof()) {
167
+ if (false === ($byte = $stream->read(1))) {
168
+ return $buffer;
169
+ }
170
+ $buffer .= $byte;
171
+ // Break when a new line is found or the max length - 1 is reached
172
+ if ($byte == PHP_EOL || ++$size == $maxLength - 1) {
173
+ break;
174
+ }
175
+ }
176
+
177
+ return $buffer;
178
+ }
179
+
180
+ /**
181
+ * Alias of GuzzleHttp\Stream\Stream::factory.
182
+ *
183
+ * @param mixed $resource Resource to create
184
+ * @param array $options Associative array of stream options defined in
185
+ * {@see \GuzzleHttp\Stream\Stream::__construct}
186
+ *
187
+ * @return StreamInterface
188
+ *
189
+ * @see GuzzleHttp\Stream\Stream::factory
190
+ * @see GuzzleHttp\Stream\Stream::__construct
191
+ */
192
+ public static function create($resource, array $options = [])
193
+ {
194
+ return Stream::factory($resource, $options);
195
+ }
196
+ }
backend/vendor/guzzlehttp/streams/tests/AppendStreamTest.php ADDED
@@ -0,0 +1,178 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests\Stream;
3
+
4
+ use GuzzleHttp\Stream\AppendStream;
5
+ use GuzzleHttp\Stream\Stream;
6
+
7
+ class AppendStreamTest extends \PHPUnit_Framework_TestCase
8
+ {
9
+ /**
10
+ * @expectedException \InvalidArgumentException
11
+ * @expectedExceptionMessage Each stream must be readable
12
+ */
13
+ public function testValidatesStreamsAreReadable()
14
+ {
15
+ $a = new AppendStream();
16
+ $s = $this->getMockBuilder('GuzzleHttp\Stream\StreamInterface')
17
+ ->setMethods(['isReadable'])
18
+ ->getMockForAbstractClass();
19
+ $s->expects($this->once())
20
+ ->method('isReadable')
21
+ ->will($this->returnValue(false));
22
+ $a->addStream($s);
23
+ }
24
+
25
+ public function testValidatesSeekType()
26
+ {
27
+ $a = new AppendStream();
28
+ $this->assertFalse($a->seek(100, SEEK_CUR));
29
+ }
30
+
31
+ public function testTriesToRewindOnSeek()
32
+ {
33
+ $a = new AppendStream();
34
+ $s = $this->getMockBuilder('GuzzleHttp\Stream\StreamInterface')
35
+ ->setMethods(['isReadable', 'seek', 'isSeekable'])
36
+ ->getMockForAbstractClass();
37
+ $s->expects($this->once())
38
+ ->method('isReadable')
39
+ ->will($this->returnValue(true));
40
+ $s->expects($this->once())
41
+ ->method('isSeekable')
42
+ ->will($this->returnValue(true));
43
+ $s->expects($this->once())
44
+ ->method('seek')
45
+ ->will($this->returnValue(false));
46
+ $a->addStream($s);
47
+ $this->assertFalse($a->seek(10));
48
+ }
49
+
50
+ public function testSeeksToPositionByReading()
51
+ {
52
+ $a = new AppendStream([
53
+ Stream::factory('foo'),
54
+ Stream::factory('bar'),
55
+ Stream::factory('baz'),
56
+ ]);
57
+
58
+ $this->assertTrue($a->seek(3));
59
+ $this->assertEquals(3, $a->tell());
60
+ $this->assertEquals('bar', $a->read(3));
61
+ $a->seek(6);
62
+ $this->assertEquals(6, $a->tell());
63
+ $this->assertEquals('baz', $a->read(3));
64
+ }
65
+
66
+ public function testDetachesEachStream()
67
+ {
68
+ $s1 = Stream::factory('foo');
69
+ $s2 = Stream::factory('foo');
70
+ $a = new AppendStream([$s1, $s2]);
71
+ $this->assertSame('foofoo', (string) $a);
72
+ $a->detach();
73
+ $this->assertSame('', (string) $a);
74
+ $this->assertSame(0, $a->getSize());
75
+ }
76
+
77
+ public function testClosesEachStream()
78
+ {
79
+ $s1 = Stream::factory('foo');
80
+ $a = new AppendStream([$s1]);
81
+ $a->close();
82
+ $this->assertSame('', (string) $a);
83
+ }
84
+
85
+ public function testIsNotWritable()
86
+ {
87
+ $a = new AppendStream([Stream::factory('foo')]);
88
+ $this->assertFalse($a->isWritable());
89
+ $this->assertTrue($a->isSeekable());
90
+ $this->assertTrue($a->isReadable());
91
+ $this->assertFalse($a->write('foo'));
92
+ }
93
+
94
+ public function testDoesNotNeedStreams()
95
+ {
96
+ $a = new AppendStream();
97
+ $this->assertEquals('', (string) $a);
98
+ }
99
+
100
+ public function testCanReadFromMultipleStreams()
101
+ {
102
+ $a = new AppendStream([
103
+ Stream::factory('foo'),
104
+ Stream::factory('bar'),
105
+ Stream::factory('baz'),
106
+ ]);
107
+ $this->assertFalse($a->eof());
108
+ $this->assertSame(0, $a->tell());
109
+ $this->assertEquals('foo', $a->read(3));
110
+ $this->assertEquals('bar', $a->read(3));
111
+ $this->assertEquals('baz', $a->read(3));
112
+ $this->assertTrue($a->eof());
113
+ $this->assertSame(9, $a->tell());
114
+ $this->assertEquals('foobarbaz', (string) $a);
115
+ }
116
+
117
+ public function testCanDetermineSizeFromMultipleStreams()
118
+ {
119
+ $a = new AppendStream([
120
+ Stream::factory('foo'),
121
+ Stream::factory('bar')
122
+ ]);
123
+ $this->assertEquals(6, $a->getSize());
124
+
125
+ $s = $this->getMockBuilder('GuzzleHttp\Stream\StreamInterface')
126
+ ->setMethods(['isSeekable', 'isReadable'])
127
+ ->getMockForAbstractClass();
128
+ $s->expects($this->once())
129
+ ->method('isSeekable')
130
+ ->will($this->returnValue(null));
131
+ $s->expects($this->once())
132
+ ->method('isReadable')
133
+ ->will($this->returnValue(true));
134
+ $a->addStream($s);
135
+ $this->assertNull($a->getSize());
136
+ }
137
+
138
+ public function testCatchesExceptionsWhenCastingToString()
139
+ {
140
+ $s = $this->getMockBuilder('GuzzleHttp\Stream\StreamInterface')
141
+ ->setMethods(['read', 'isReadable', 'eof'])
142
+ ->getMockForAbstractClass();
143
+ $s->expects($this->once())
144
+ ->method('read')
145
+ ->will($this->throwException(new \RuntimeException('foo')));
146
+ $s->expects($this->once())
147
+ ->method('isReadable')
148
+ ->will($this->returnValue(true));
149
+ $s->expects($this->any())
150
+ ->method('eof')
151
+ ->will($this->returnValue(false));
152
+ $a = new AppendStream([$s]);
153
+ $this->assertFalse($a->eof());
154
+ $this->assertSame('', (string) $a);
155
+ }
156
+
157
+ public function testCanDetach()
158
+ {
159
+ $s = new AppendStream();
160
+ $s->detach();
161
+ }
162
+
163
+ public function testReturnsEmptyMetadata()
164
+ {
165
+ $s = new AppendStream();
166
+ $this->assertEquals([], $s->getMetadata());
167
+ $this->assertNull($s->getMetadata('foo'));
168
+ }
169
+
170
+ /**
171
+ * @expectedException \GuzzleHttp\Stream\Exception\CannotAttachException
172
+ */
173
+ public function testCannotAttach()
174
+ {
175
+ $p = new AppendStream();
176
+ $p->attach('a');
177
+ }
178
+ }
backend/vendor/guzzlehttp/streams/tests/AsyncReadStreamTest.php ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests\Stream;
3
+
4
+ use GuzzleHttp\Stream\AsyncReadStream;
5
+ use GuzzleHttp\Stream\BufferStream;
6
+ use GuzzleHttp\Stream\FnStream;
7
+ use GuzzleHttp\Stream\Stream;
8
+
9
+ class AsyncReadStreamTest extends \PHPUnit_Framework_TestCase
10
+ {
11
+ /**
12
+ * @expectedException \InvalidArgumentException
13
+ * @expectedExceptionMessage Buffer must be readable and writable
14
+ */
15
+ public function testValidatesReadableBuffer()
16
+ {
17
+ new AsyncReadStream(FnStream::decorate(
18
+ Stream::factory(),
19
+ ['isReadable' => function () { return false; }]
20
+ ));
21
+ }
22
+
23
+ /**
24
+ * @expectedException \InvalidArgumentException
25
+ * @expectedExceptionMessage Buffer must be readable and writable
26
+ */
27
+ public function testValidatesWritableBuffer()
28
+ {
29
+ new AsyncReadStream(FnStream::decorate(
30
+ Stream::factory(),
31
+ ['isWritable' => function () { return false; }]
32
+ ));
33
+ }
34
+
35
+ public function testValidatesHwmMetadata()
36
+ {
37
+ $a = new AsyncReadStream(Stream::factory(), [
38
+ 'drain' => function() {}
39
+ ]);
40
+ $this->assertNull($this->readAttribute($a, 'drain'));
41
+ }
42
+
43
+ /**
44
+ * @expectedException \InvalidArgumentException
45
+ * @expectedExceptionMessage pump must be callable
46
+ */
47
+ public function testValidatesPumpIsCallable()
48
+ {
49
+ new AsyncReadStream(new BufferStream(), ['pump' => true]);
50
+ }
51
+
52
+ /**
53
+ * @expectedException \InvalidArgumentException
54
+ * @expectedExceptionMessage drain must be callable
55
+ */
56
+ public function testValidatesDrainIsCallable()
57
+ {
58
+ new AsyncReadStream(new BufferStream(), ['drain' => true]);
59
+ }
60
+
61
+ public function testCanInitialize()
62
+ {
63
+ $buffer = new BufferStream();
64
+ $a = new AsyncReadStream($buffer, [
65
+ 'size' => 10,
66
+ 'drain' => function () {},
67
+ 'pump' => function () {},
68
+ ]);
69
+ $this->assertSame($buffer, $this->readAttribute($a, 'stream'));
70
+ $this->assertTrue(is_callable($this->readAttribute($a, 'drain')));
71
+ $this->assertTrue(is_callable($this->readAttribute($a, 'pump')));
72
+ $this->assertTrue($a->isReadable());
73
+ $this->assertFalse($a->isSeekable());
74
+ $this->assertFalse($a->isWritable());
75
+ $this->assertFalse($a->write('foo'));
76
+ $this->assertEquals(10, $a->getSize());
77
+ }
78
+
79
+ public function testReadsFromBufferWithNoDrainOrPump()
80
+ {
81
+ $buffer = new BufferStream();
82
+ $a = new AsyncReadStream($buffer);
83
+ $buffer->write('foo');
84
+ $this->assertNull($a->getSize());
85
+ $this->assertEquals('foo', $a->read(10));
86
+ $this->assertEquals('', $a->read(10));
87
+ }
88
+
89
+ public function testCallsPumpForMoreDataWhenRequested()
90
+ {
91
+ $called = 0;
92
+ $buffer = new BufferStream();
93
+ $a = new AsyncReadStream($buffer, [
94
+ 'pump' => function ($size) use (&$called) {
95
+ $called++;
96
+ return str_repeat('.', $size);
97
+ }
98
+ ]);
99
+ $buffer->write('foobar');
100
+ $this->assertEquals('foo', $a->read(3));
101
+ $this->assertEquals(0, $called);
102
+ $this->assertEquals('bar.....', $a->read(8));
103
+ $this->assertEquals(1, $called);
104
+ $this->assertEquals('..', $a->read(2));
105
+ $this->assertEquals(2, $called);
106
+ }
107
+
108
+ public function testCallsDrainWhenNeeded()
109
+ {
110
+ $called = 0;
111
+ $buffer = new BufferStream(5);
112
+ $a = new AsyncReadStream($buffer, [
113
+ 'drain' => function (BufferStream $b) use (&$called, $buffer) {
114
+ $this->assertSame($b, $buffer);
115
+ $called++;
116
+ }
117
+ ]);
118
+
119
+ $buffer->write('foobar');
120
+ $this->assertEquals(6, $buffer->getSize());
121
+ $this->assertEquals(0, $called);
122
+
123
+ $a->read(3);
124
+ $this->assertTrue($this->readAttribute($a, 'needsDrain'));
125
+ $this->assertEquals(3, $buffer->getSize());
126
+ $this->assertEquals(0, $called);
127
+
128
+ $a->read(3);
129
+ $this->assertEquals(0, $buffer->getSize());
130
+ $this->assertFalse($this->readAttribute($a, 'needsDrain'));
131
+ $this->assertEquals(1, $called);
132
+ }
133
+
134
+ public function testCreatesBufferWithNoConfig()
135
+ {
136
+ list($buffer, $async) = AsyncReadStream::create();
137
+ $this->assertInstanceOf('GuzzleHttp\Stream\BufferStream', $buffer);
138
+ $this->assertInstanceOf('GuzzleHttp\Stream\AsyncReadStream', $async);
139
+ }
140
+
141
+ public function testCreatesBufferWithSpecifiedBuffer()
142
+ {
143
+ $buf = new BufferStream();
144
+ list($buffer, $async) = AsyncReadStream::create(['buffer' => $buf]);
145
+ $this->assertSame($buf, $buffer);
146
+ $this->assertInstanceOf('GuzzleHttp\Stream\AsyncReadStream', $async);
147
+ }
148
+
149
+ public function testCreatesNullStream()
150
+ {
151
+ list($buffer, $async) = AsyncReadStream::create(['max_buffer' => 0]);
152
+ $this->assertInstanceOf('GuzzleHttp\Stream\NullStream', $buffer);
153
+ $this->assertInstanceOf('GuzzleHttp\Stream\AsyncReadStream', $async);
154
+ }
155
+
156
+ public function testCreatesDroppingStream()
157
+ {
158
+ list($buffer, $async) = AsyncReadStream::create(['max_buffer' => 5]);
159
+ $this->assertInstanceOf('GuzzleHttp\Stream\DroppingStream', $buffer);
160
+ $this->assertInstanceOf('GuzzleHttp\Stream\AsyncReadStream', $async);
161
+ $buffer->write('12345678910');
162
+ $this->assertEquals(5, $buffer->getSize());
163
+ }
164
+
165
+ public function testCreatesOnWriteStream()
166
+ {
167
+ $c = 0;
168
+ $b = new BufferStream();
169
+ list($buffer, $async) = AsyncReadStream::create([
170
+ 'buffer' => $b,
171
+ 'write' => function (BufferStream $buf, $data) use (&$c, $b) {
172
+ $this->assertSame($buf, $b);
173
+ $this->assertEquals('foo', $data);
174
+ $c++;
175
+ }
176
+ ]);
177
+ $this->assertInstanceOf('GuzzleHttp\Stream\FnStream', $buffer);
178
+ $this->assertInstanceOf('GuzzleHttp\Stream\AsyncReadStream', $async);
179
+ $this->assertEquals(0, $c);
180
+ $this->assertEquals(3, $buffer->write('foo'));
181
+ $this->assertEquals(1, $c);
182
+ $this->assertEquals(3, $buffer->write('foo'));
183
+ $this->assertEquals(2, $c);
184
+ $this->assertEquals('foofoo', (string) $buffer);
185
+ }
186
+ }
backend/vendor/guzzlehttp/streams/tests/BufferStreamTest.php ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests\Stream;
3
+
4
+ use GuzzleHttp\Stream\BufferStream;
5
+
6
+ class BufferStreamTest extends \PHPUnit_Framework_TestCase
7
+ {
8
+ public function testHasMetadata()
9
+ {
10
+ $b = new BufferStream(10);
11
+ $this->assertTrue($b->isReadable());
12
+ $this->assertTrue($b->isWritable());
13
+ $this->assertFalse($b->isSeekable());
14
+ $this->assertEquals(null, $b->getMetadata('foo'));
15
+ $this->assertEquals(10, $b->getMetadata('hwm'));
16
+ $this->assertEquals([], $b->getMetadata());
17
+ }
18
+
19
+ public function testRemovesReadDataFromBuffer()
20
+ {
21
+ $b = new BufferStream();
22
+ $this->assertEquals(3, $b->write('foo'));
23
+ $this->assertEquals(3, $b->getSize());
24
+ $this->assertFalse($b->eof());
25
+ $this->assertEquals('foo', $b->read(10));
26
+ $this->assertTrue($b->eof());
27
+ $this->assertEquals('', $b->read(10));
28
+ }
29
+
30
+ public function testCanCastToStringOrGetContents()
31
+ {
32
+ $b = new BufferStream();
33
+ $b->write('foo');
34
+ $b->write('baz');
35
+ $this->assertEquals('foo', $b->read(3));
36
+ $b->write('bar');
37
+ $this->assertEquals('bazbar', (string) $b);
38
+ $this->assertFalse($b->tell());
39
+ }
40
+
41
+ public function testDetachClearsBuffer()
42
+ {
43
+ $b = new BufferStream();
44
+ $b->write('foo');
45
+ $b->detach();
46
+ $this->assertEquals(0, $b->tell());
47
+ $this->assertTrue($b->eof());
48
+ $this->assertEquals(3, $b->write('abc'));
49
+ $this->assertEquals('abc', $b->read(10));
50
+ }
51
+
52
+ public function testExceedingHighwaterMarkReturnsFalseButStillBuffers()
53
+ {
54
+ $b = new BufferStream(5);
55
+ $this->assertEquals(3, $b->write('hi '));
56
+ $this->assertFalse($b->write('hello'));
57
+ $this->assertEquals('hi hello', (string) $b);
58
+ $this->assertEquals(4, $b->write('test'));
59
+ }
60
+
61
+ /**
62
+ * @expectedException \GuzzleHttp\Stream\Exception\CannotAttachException
63
+ */
64
+ public function testCannotAttach()
65
+ {
66
+ $p = new BufferStream();
67
+ $p->attach('a');
68
+ }
69
+ }
backend/vendor/guzzlehttp/streams/tests/CachingStreamTest.php ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests\Stream;
3
+
4
+ use GuzzleHttp\Stream\Stream;
5
+ use GuzzleHttp\Stream\CachingStream;
6
+ use GuzzleHttp\Stream\Utils;
7
+
8
+ /**
9
+ * @covers GuzzleHttp\Stream\CachingStream
10
+ */
11
+ class CachingStreamTest extends \PHPUnit_Framework_TestCase
12
+ {
13
+ /** @var CachingStream */
14
+ protected $body;
15
+
16
+ /** @var Stream */
17
+ protected $decorated;
18
+
19
+ public function setUp()
20
+ {
21
+ $this->decorated = Stream::factory('testing');
22
+ $this->body = new CachingStream($this->decorated);
23
+ }
24
+
25
+ public function tearDown()
26
+ {
27
+ $this->decorated->close();
28
+ $this->body->close();
29
+ }
30
+
31
+ public function testUsesRemoteSizeIfPossible()
32
+ {
33
+ $body = Stream::factory('test');
34
+ $caching = new CachingStream($body);
35
+ $this->assertEquals(4, $caching->getSize());
36
+ }
37
+
38
+ /**
39
+ * @expectedException \RuntimeException
40
+ * @expectedExceptionMessage Cannot seek to byte 10
41
+ */
42
+ public function testCannotSeekPastWhatHasBeenRead()
43
+ {
44
+ $this->body->seek(10);
45
+ }
46
+
47
+ public function testCannotUseSeekEnd()
48
+ {
49
+ $this->assertFalse($this->body->seek(2, SEEK_END));
50
+ }
51
+
52
+ public function testRewindUsesSeek()
53
+ {
54
+ $a = Stream::factory('foo');
55
+ $d = $this->getMockBuilder('GuzzleHttp\Stream\CachingStream')
56
+ ->setMethods(array('seek'))
57
+ ->setConstructorArgs(array($a))
58
+ ->getMock();
59
+ $d->expects($this->once())
60
+ ->method('seek')
61
+ ->with(0)
62
+ ->will($this->returnValue(true));
63
+ $d->seek(0);
64
+ }
65
+
66
+ public function testCanSeekToReadBytes()
67
+ {
68
+ $this->assertEquals('te', $this->body->read(2));
69
+ $this->body->seek(0);
70
+ $this->assertEquals('test', $this->body->read(4));
71
+ $this->assertEquals(4, $this->body->tell());
72
+ $this->body->seek(2);
73
+ $this->assertEquals(2, $this->body->tell());
74
+ $this->body->seek(2, SEEK_CUR);
75
+ $this->assertEquals(4, $this->body->tell());
76
+ $this->assertEquals('ing', $this->body->read(3));
77
+ }
78
+
79
+ public function testWritesToBufferStream()
80
+ {
81
+ $this->body->read(2);
82
+ $this->body->write('hi');
83
+ $this->body->seek(0);
84
+ $this->assertEquals('tehiing', (string) $this->body);
85
+ }
86
+
87
+ public function testSkipsOverwrittenBytes()
88
+ {
89
+ $decorated = Stream::factory(
90
+ implode("\n", array_map(function ($n) {
91
+ return str_pad($n, 4, '0', STR_PAD_LEFT);
92
+ }, range(0, 25)))
93
+ );
94
+
95
+ $body = new CachingStream($decorated);
96
+
97
+ $this->assertEquals("0000\n", Utils::readline($body));
98
+ $this->assertEquals("0001\n", Utils::readline($body));
99
+ // Write over part of the body yet to be read, so skip some bytes
100
+ $this->assertEquals(5, $body->write("TEST\n"));
101
+ $this->assertEquals(5, $this->readAttribute($body, 'skipReadBytes'));
102
+ // Read, which skips bytes, then reads
103
+ $this->assertEquals("0003\n", Utils::readline($body));
104
+ $this->assertEquals(0, $this->readAttribute($body, 'skipReadBytes'));
105
+ $this->assertEquals("0004\n", Utils::readline($body));
106
+ $this->assertEquals("0005\n", Utils::readline($body));
107
+
108
+ // Overwrite part of the cached body (so don't skip any bytes)
109
+ $body->seek(5);
110
+ $this->assertEquals(5, $body->write("ABCD\n"));
111
+ $this->assertEquals(0, $this->readAttribute($body, 'skipReadBytes'));
112
+ $this->assertEquals("TEST\n", Utils::readline($body));
113
+ $this->assertEquals("0003\n", Utils::readline($body));
114
+ $this->assertEquals("0004\n", Utils::readline($body));
115
+ $this->assertEquals("0005\n", Utils::readline($body));
116
+ $this->assertEquals("0006\n", Utils::readline($body));
117
+ $this->assertEquals(5, $body->write("1234\n"));
118
+ $this->assertEquals(5, $this->readAttribute($body, 'skipReadBytes'));
119
+
120
+ // Seek to 0 and ensure the overwritten bit is replaced
121
+ $body->seek(0);
122
+ $this->assertEquals("0000\nABCD\nTEST\n0003\n0004\n0005\n0006\n1234\n0008\n0009\n", $body->read(50));
123
+
124
+ // Ensure that casting it to a string does not include the bit that was overwritten
125
+ $this->assertContains("0000\nABCD\nTEST\n0003\n0004\n0005\n0006\n1234\n0008\n0009\n", (string) $body);
126
+ }
127
+
128
+ public function testClosesBothStreams()
129
+ {
130
+ $s = fopen('php://temp', 'r');
131
+ $a = Stream::factory($s);
132
+ $d = new CachingStream($a);
133
+ $d->close();
134
+ $this->assertFalse(is_resource($s));
135
+ }
136
+ }
backend/vendor/guzzlehttp/streams/tests/DroppingStreamTest.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests\Stream;
3
+
4
+ use GuzzleHttp\Stream\BufferStream;
5
+ use GuzzleHttp\Stream\DroppingStream;
6
+
7
+ class DroppingStreamTest extends \PHPUnit_Framework_TestCase
8
+ {
9
+ public function testBeginsDroppingWhenSizeExceeded()
10
+ {
11
+ $stream = new BufferStream();
12
+ $drop = new DroppingStream($stream, 5);
13
+ $this->assertEquals(3, $drop->write('hel'));
14
+ $this->assertFalse($drop->write('lo'));
15
+ $this->assertEquals(5, $drop->getSize());
16
+ $this->assertEquals('hello', $drop->read(5));
17
+ $this->assertEquals(0, $drop->getSize());
18
+ $drop->write('12345678910');
19
+ $this->assertEquals(5, $stream->getSize());
20
+ $this->assertEquals(5, $drop->getSize());
21
+ $this->assertEquals('12345', (string) $drop);
22
+ $this->assertEquals(0, $drop->getSize());
23
+ $drop->write('hello');
24
+ $this->assertFalse($drop->write('test'));
25
+ }
26
+ }
backend/vendor/guzzlehttp/streams/tests/Exception/SeekExceptionTest.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests\Stream\Exception;
3
+
4
+ use GuzzleHttp\Stream\Exception\SeekException;
5
+ use GuzzleHttp\Stream\Stream;
6
+
7
+ class SeekExceptionTest extends \PHPUnit_Framework_TestCase
8
+ {
9
+ public function testHasStream()
10
+ {
11
+ $s = Stream::factory('foo');
12
+ $e = new SeekException($s, 10);
13
+ $this->assertSame($s, $e->getStream());
14
+ $this->assertContains('10', $e->getMessage());
15
+ }
16
+ }
backend/vendor/guzzlehttp/streams/tests/FnStreamTest.php ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests\Stream;
3
+
4
+ use GuzzleHttp\Stream\Stream;
5
+ use GuzzleHttp\Stream\FnStream;
6
+
7
+ /**
8
+ * @covers GuzzleHttp\Stream\FnStream
9
+ */
10
+ class FnStreamTest extends \PHPUnit_Framework_TestCase
11
+ {
12
+ /**
13
+ * @expectedException \BadMethodCallException
14
+ * @expectedExceptionMessage seek() is not implemented in the FnStream
15
+ */
16
+ public function testThrowsWhenNotImplemented()
17
+ {
18
+ (new FnStream([]))->seek(1);
19
+ }
20
+
21
+ public function testProxiesToFunction()
22
+ {
23
+ $s = new FnStream([
24
+ 'read' => function ($len) {
25
+ $this->assertEquals(3, $len);
26
+ return 'foo';
27
+ }
28
+ ]);
29
+
30
+ $this->assertEquals('foo', $s->read(3));
31
+ }
32
+
33
+ public function testCanCloseOnDestruct()
34
+ {
35
+ $called = false;
36
+ $s = new FnStream([
37
+ 'close' => function () use (&$called) {
38
+ $called = true;
39
+ }
40
+ ]);
41
+ unset($s);
42
+ $this->assertTrue($called);
43
+ }
44
+
45
+ public function testDoesNotRequireClose()
46
+ {
47
+ $s = new FnStream([]);
48
+ unset($s);
49
+ }
50
+
51
+ public function testDecoratesStream()
52
+ {
53
+ $a = Stream::factory('foo');
54
+ $b = FnStream::decorate($a, []);
55
+ $this->assertEquals(3, $b->getSize());
56
+ $this->assertEquals($b->isWritable(), true);
57
+ $this->assertEquals($b->isReadable(), true);
58
+ $this->assertEquals($b->isSeekable(), true);
59
+ $this->assertEquals($b->read(3), 'foo');
60
+ $this->assertEquals($b->tell(), 3);
61
+ $this->assertEquals($a->tell(), 3);
62
+ $this->assertEquals($b->eof(), true);
63
+ $this->assertEquals($a->eof(), true);
64
+ $b->seek(0);
65
+ $this->assertEquals('foo', (string) $b);
66
+ $b->seek(0);
67
+ $this->assertEquals('foo', $b->getContents());
68
+ $this->assertEquals($a->getMetadata(), $b->getMetadata());
69
+ $b->seek(0, SEEK_END);
70
+ $b->write('bar');
71
+ $this->assertEquals('foobar', (string) $b);
72
+ $this->assertInternalType('resource', $b->detach());
73
+ $b->close();
74
+ }
75
+
76
+ public function testDecoratesWithCustomizations()
77
+ {
78
+ $called = false;
79
+ $a = Stream::factory('foo');
80
+ $b = FnStream::decorate($a, [
81
+ 'read' => function ($len) use (&$called, $a) {
82
+ $called = true;
83
+ return $a->read($len);
84
+ }
85
+ ]);
86
+ $this->assertEquals('foo', $b->read(3));
87
+ $this->assertTrue($called);
88
+ }
89
+ }
backend/vendor/guzzlehttp/streams/tests/GuzzleStreamWrapperTest.php ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests\Stream;
3
+
4
+ use GuzzleHttp\Stream\GuzzleStreamWrapper;
5
+ use GuzzleHttp\Stream\Stream;
6
+
7
+ /**
8
+ * @covers GuzzleHttp\Stream\GuzzleStreamWrapper
9
+ */
10
+ class GuzzleStreamWrapperTest extends \PHPUnit_Framework_TestCase
11
+ {
12
+ public function testResource()
13
+ {
14
+ $stream = Stream::factory('foo');
15
+ $handle = GuzzleStreamWrapper::getResource($stream);
16
+ $this->assertSame('foo', fread($handle, 3));
17
+ $this->assertSame(3, ftell($handle));
18
+ $this->assertSame(3, fwrite($handle, 'bar'));
19
+ $this->assertSame(0, fseek($handle, 0));
20
+ $this->assertSame('foobar', fread($handle, 6));
21
+ $this->assertTrue(feof($handle));
22
+
23
+ // This fails on HHVM for some reason
24
+ if (!defined('HHVM_VERSION')) {
25
+ $this->assertEquals([
26
+ 'dev' => 0,
27
+ 'ino' => 0,
28
+ 'mode' => 33206,
29
+ 'nlink' => 0,
30
+ 'uid' => 0,
31
+ 'gid' => 0,
32
+ 'rdev' => 0,
33
+ 'size' => 6,
34
+ 'atime' => 0,
35
+ 'mtime' => 0,
36
+ 'ctime' => 0,
37
+ 'blksize' => 0,
38
+ 'blocks' => 0,
39
+ 0 => 0,
40
+ 1 => 0,
41
+ 2 => 33206,
42
+ 3 => 0,
43
+ 4 => 0,
44
+ 5 => 0,
45
+ 6 => 0,
46
+ 7 => 6,
47
+ 8 => 0,
48
+ 9 => 0,
49
+ 10 => 0,
50
+ 11 => 0,
51
+ 12 => 0,
52
+ ], fstat($handle));
53
+ }
54
+
55
+ $this->assertTrue(fclose($handle));
56
+ $this->assertSame('foobar', (string) $stream);
57
+ }
58
+
59
+ /**
60
+ * @expectedException \InvalidArgumentException
61
+ */
62
+ public function testValidatesStream()
63
+ {
64
+ $stream = $this->getMockBuilder('GuzzleHttp\Stream\StreamInterface')
65
+ ->setMethods(['isReadable', 'isWritable'])
66
+ ->getMockForAbstractClass();
67
+ $stream->expects($this->once())
68
+ ->method('isReadable')
69
+ ->will($this->returnValue(false));
70
+ $stream->expects($this->once())
71
+ ->method('isWritable')
72
+ ->will($this->returnValue(false));
73
+ GuzzleStreamWrapper::getResource($stream);
74
+ }
75
+
76
+ /**
77
+ * @expectedException \PHPUnit_Framework_Error_Warning
78
+ */
79
+ public function testReturnsFalseWhenStreamDoesNotExist()
80
+ {
81
+ fopen('guzzle://foo', 'r');
82
+ }
83
+
84
+ public function testCanOpenReadonlyStream()
85
+ {
86
+ $stream = $this->getMockBuilder('GuzzleHttp\Stream\StreamInterface')
87
+ ->setMethods(['isReadable', 'isWritable'])
88
+ ->getMockForAbstractClass();
89
+ $stream->expects($this->once())
90
+ ->method('isReadable')
91
+ ->will($this->returnValue(false));
92
+ $stream->expects($this->once())
93
+ ->method('isWritable')
94
+ ->will($this->returnValue(true));
95
+ $r = GuzzleStreamWrapper::getResource($stream);
96
+ $this->assertInternalType('resource', $r);
97
+ fclose($r);
98
+ }
99
+ }
backend/vendor/guzzlehttp/streams/tests/InflateStreamTest.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests\Stream;
3
+
4
+ use GuzzleHttp\Stream\InflateStream;
5
+ use GuzzleHttp\Stream\Stream;
6
+
7
+ class InflateStreamtest extends \PHPUnit_Framework_TestCase
8
+ {
9
+ public function testInflatesStreams()
10
+ {
11
+ $content = gzencode('test');
12
+ $a = Stream::factory($content);
13
+ $b = new InflateStream($a);
14
+ $this->assertEquals('test', (string) $b);
15
+ }
16
+ }
backend/vendor/guzzlehttp/streams/tests/LazyOpenStreamTest.php ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests\Stream;
3
+
4
+ use GuzzleHttp\Stream\LazyOpenStream;
5
+
6
+ class LazyOpenStreamTest extends \PHPUnit_Framework_TestCase
7
+ {
8
+ private $fname;
9
+
10
+ public function setup()
11
+ {
12
+ $this->fname = tempnam('/tmp', 'tfile');
13
+
14
+ if (file_exists($this->fname)) {
15
+ unlink($this->fname);
16
+ }
17
+ }
18
+
19
+ public function tearDown()
20
+ {
21
+ if (file_exists($this->fname)) {
22
+ unlink($this->fname);
23
+ }
24
+ }
25
+
26
+ public function testOpensLazily()
27
+ {
28
+ $l = new LazyOpenStream($this->fname, 'w+');
29
+ $l->write('foo');
30
+ $this->assertInternalType('array', $l->getMetadata());
31
+ $this->assertFileExists($this->fname);
32
+ $this->assertEquals('foo', file_get_contents($this->fname));
33
+ $this->assertEquals('foo', (string) $l);
34
+ }
35
+
36
+ public function testProxiesToFile()
37
+ {
38
+ file_put_contents($this->fname, 'foo');
39
+ $l = new LazyOpenStream($this->fname, 'r');
40
+ $this->assertEquals('foo', $l->read(4));
41
+ $this->assertTrue($l->eof());
42
+ $this->assertEquals(3, $l->tell());
43
+ $this->assertTrue($l->isReadable());
44
+ $this->assertTrue($l->isSeekable());
45
+ $this->assertFalse($l->isWritable());
46
+ $l->seek(1);
47
+ $this->assertEquals('oo', $l->getContents());
48
+ $this->assertEquals('foo', (string) $l);
49
+ $this->assertEquals(3, $l->getSize());
50
+ $this->assertInternalType('array', $l->getMetadata());
51
+ $l->close();
52
+ }
53
+
54
+ public function testDetachesUnderlyingStream()
55
+ {
56
+ file_put_contents($this->fname, 'foo');
57
+ $l = new LazyOpenStream($this->fname, 'r');
58
+ $r = $l->detach();
59
+ $this->assertInternalType('resource', $r);
60
+ fseek($r, 0);
61
+ $this->assertEquals('foo', stream_get_contents($r));
62
+ fclose($r);
63
+ }
64
+ }
backend/vendor/guzzlehttp/streams/tests/LimitStreamTest.php ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests\Http;
3
+
4
+ use GuzzleHttp\Stream\FnStream;
5
+ use GuzzleHttp\Stream\Stream;
6
+ use GuzzleHttp\Stream\LimitStream;
7
+ use GuzzleHttp\Stream\NoSeekStream;
8
+
9
+ /**
10
+ * @covers GuzzleHttp\Stream\LimitStream
11
+ */
12
+ class LimitStreamTest extends \PHPUnit_Framework_TestCase
13
+ {
14
+ /** @var LimitStream */
15
+ protected $body;
16
+
17
+ /** @var Stream */
18
+ protected $decorated;
19
+
20
+ public function setUp()
21
+ {
22
+ $this->decorated = Stream::factory(fopen(__FILE__, 'r'));
23
+ $this->body = new LimitStream($this->decorated, 10, 3);
24
+ }
25
+
26
+ public function testReturnsSubset()
27
+ {
28
+ $body = new LimitStream(Stream::factory('foo'), -1, 1);
29
+ $this->assertEquals('oo', (string) $body);
30
+ $this->assertTrue($body->eof());
31
+ $body->seek(0);
32
+ $this->assertFalse($body->eof());
33
+ $this->assertEquals('oo', $body->read(100));
34
+ $this->assertTrue($body->eof());
35
+ }
36
+
37
+ public function testReturnsSubsetWhenCastToString()
38
+ {
39
+ $body = Stream::factory('foo_baz_bar');
40
+ $limited = new LimitStream($body, 3, 4);
41
+ $this->assertEquals('baz', (string) $limited);
42
+ }
43
+
44
+ public function testReturnsSubsetOfEmptyBodyWhenCastToString()
45
+ {
46
+ $body = Stream::factory('');
47
+ $limited = new LimitStream($body, 0, 10);
48
+ $this->assertEquals('', (string) $limited);
49
+ }
50
+
51
+ public function testSeeksWhenConstructed()
52
+ {
53
+ $this->assertEquals(0, $this->body->tell());
54
+ $this->assertEquals(3, $this->decorated->tell());
55
+ }
56
+
57
+ public function testAllowsBoundedSeek()
58
+ {
59
+ $this->assertEquals(true, $this->body->seek(100));
60
+ $this->assertEquals(10, $this->body->tell());
61
+ $this->assertEquals(13, $this->decorated->tell());
62
+ $this->assertEquals(true, $this->body->seek(0));
63
+ $this->assertEquals(0, $this->body->tell());
64
+ $this->assertEquals(3, $this->decorated->tell());
65
+ $this->assertEquals(false, $this->body->seek(-10));
66
+ $this->assertEquals(0, $this->body->tell());
67
+ $this->assertEquals(3, $this->decorated->tell());
68
+ $this->assertEquals(true, $this->body->seek(5));
69
+ $this->assertEquals(5, $this->body->tell());
70
+ $this->assertEquals(8, $this->decorated->tell());
71
+ $this->assertEquals(false, $this->body->seek(1000, SEEK_END));
72
+ }
73
+
74
+ public function testReadsOnlySubsetOfData()
75
+ {
76
+ $data = $this->body->read(100);
77
+ $this->assertEquals(10, strlen($data));
78
+ $this->assertFalse($this->body->read(1000));
79
+
80
+ $this->body->setOffset(10);
81
+ $newData = $this->body->read(100);
82
+ $this->assertEquals(10, strlen($newData));
83
+ $this->assertNotSame($data, $newData);
84
+ }
85
+
86
+ /**
87
+ * @expectedException \GuzzleHttp\Stream\Exception\SeekException
88
+ * @expectedExceptionMessage Could not seek the stream to position 2
89
+ */
90
+ public function testThrowsWhenCurrentGreaterThanOffsetSeek()
91
+ {
92
+ $a = Stream::factory('foo_bar');
93
+ $b = new NoSeekStream($a);
94
+ $c = new LimitStream($b);
95
+ $a->getContents();
96
+ $c->setOffset(2);
97
+ }
98
+
99
+ public function testClaimsConsumedWhenReadLimitIsReached()
100
+ {
101
+ $this->assertFalse($this->body->eof());
102
+ $this->body->read(1000);
103
+ $this->assertTrue($this->body->eof());
104
+ }
105
+
106
+ public function testContentLengthIsBounded()
107
+ {
108
+ $this->assertEquals(10, $this->body->getSize());
109
+ }
110
+
111
+ public function testGetContentsIsBasedOnSubset()
112
+ {
113
+ $body = new LimitStream(Stream::factory('foobazbar'), 3, 3);
114
+ $this->assertEquals('baz', $body->getContents());
115
+ }
116
+
117
+ public function testReturnsNullIfSizeCannotBeDetermined()
118
+ {
119
+ $a = new FnStream([
120
+ 'getSize' => function () { return null; },
121
+ 'tell' => function () { return 0; },
122
+ ]);
123
+ $b = new LimitStream($a);
124
+ $this->assertNull($b->getSize());
125
+ }
126
+
127
+ public function testLengthLessOffsetWhenNoLimitSize()
128
+ {
129
+ $a = Stream::factory('foo_bar');
130
+ $b = new LimitStream($a, -1, 4);
131
+ $this->assertEquals(3, $b->getSize());
132
+ }
133
+ }
backend/vendor/guzzlehttp/streams/tests/NoSeekStreamTest.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests\Stream;
3
+
4
+ use GuzzleHttp\Stream\Stream;
5
+ use GuzzleHttp\Stream\NoSeekStream;
6
+
7
+ /**
8
+ * @covers GuzzleHttp\Stream\NoSeekStream
9
+ * @covers GuzzleHttp\Stream\StreamDecoratorTrait
10
+ */
11
+ class NoSeekStreamTest extends \PHPUnit_Framework_TestCase
12
+ {
13
+ public function testCannotSeek()
14
+ {
15
+ $s = $this->getMockBuilder('GuzzleHttp\Stream\StreamInterface')
16
+ ->setMethods(['isSeekable', 'seek'])
17
+ ->getMockForAbstractClass();
18
+ $s->expects($this->never())->method('seek');
19
+ $s->expects($this->never())->method('isSeekable');
20
+ $wrapped = new NoSeekStream($s);
21
+ $this->assertFalse($wrapped->isSeekable());
22
+ $this->assertFalse($wrapped->seek(2));
23
+ }
24
+
25
+ public function testHandlesClose()
26
+ {
27
+ $s = Stream::factory('foo');
28
+ $wrapped = new NoSeekStream($s);
29
+ $wrapped->close();
30
+ $this->assertFalse($wrapped->write('foo'));
31
+ }
32
+
33
+ public function testCanAttach()
34
+ {
35
+ $s1 = Stream::factory('foo');
36
+ $s2 = Stream::factory('bar');
37
+ $wrapped = new NoSeekStream($s1);
38
+ $wrapped->attach($s2->detach());
39
+ $this->assertEquals('bar', (string) $wrapped);
40
+ }
41
+ }
backend/vendor/guzzlehttp/streams/tests/NullStreamTest.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests\Stream;
3
+
4
+ use GuzzleHttp\Stream\NullStream;
5
+
6
+ class NullStreamTest extends \PHPUnit_Framework_TestCase
7
+ {
8
+ public function testDoesNothing()
9
+ {
10
+ $b = new NullStream();
11
+ $this->assertEquals('', $b->read(10));
12
+ $this->assertEquals(4, $b->write('test'));
13
+ $this->assertEquals('', (string) $b);
14
+ $this->assertNull($b->getMetadata('a'));
15
+ $this->assertEquals([], $b->getMetadata());
16
+ $this->assertEquals(0, $b->getSize());
17
+ $this->assertEquals('', $b->getContents());
18
+ $this->assertEquals(0, $b->tell());
19
+
20
+ $this->assertTrue($b->isReadable());
21
+ $this->assertTrue($b->isWritable());
22
+ $this->assertTrue($b->isSeekable());
23
+ $this->assertFalse($b->seek(10));
24
+
25
+ $this->assertTrue($b->eof());
26
+ $b->detach();
27
+ $this->assertTrue($b->eof());
28
+ $b->close();
29
+ }
30
+
31
+ /**
32
+ * @expectedException \GuzzleHttp\Stream\Exception\CannotAttachException
33
+ */
34
+ public function testCannotAttach()
35
+ {
36
+ $p = new NullStream();
37
+ $p->attach('a');
38
+ }
39
+ }
backend/vendor/guzzlehttp/streams/tests/PumpStreamTest.php ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests\Stream;
3
+
4
+ use GuzzleHttp\Stream\LimitStream;
5
+ use GuzzleHttp\Stream\PumpStream;
6
+ use GuzzleHttp\Stream\Stream;
7
+
8
+ class PumpStreamTest extends \PHPUnit_Framework_TestCase
9
+ {
10
+ public function testHasMetadataAndSize()
11
+ {
12
+ $p = new PumpStream(function () {}, [
13
+ 'metadata' => ['foo' => 'bar'],
14
+ 'size' => 100
15
+ ]);
16
+
17
+ $this->assertEquals('bar', $p->getMetadata('foo'));
18
+ $this->assertEquals(['foo' => 'bar'], $p->getMetadata());
19
+ $this->assertEquals(100, $p->getSize());
20
+ }
21
+
22
+ public function testCanReadFromCallable()
23
+ {
24
+ $p = Stream::factory(function ($size) {
25
+ return 'a';
26
+ });
27
+ $this->assertEquals('a', $p->read(1));
28
+ $this->assertEquals(1, $p->tell());
29
+ $this->assertEquals('aaaaa', $p->read(5));
30
+ $this->assertEquals(6, $p->tell());
31
+ }
32
+
33
+ public function testStoresExcessDataInBuffer()
34
+ {
35
+ $called = [];
36
+ $p = Stream::factory(function ($size) use (&$called) {
37
+ $called[] = $size;
38
+ return 'abcdef';
39
+ });
40
+ $this->assertEquals('a', $p->read(1));
41
+ $this->assertEquals('b', $p->read(1));
42
+ $this->assertEquals('cdef', $p->read(4));
43
+ $this->assertEquals('abcdefabc', $p->read(9));
44
+ $this->assertEquals([1, 9, 3], $called);
45
+ }
46
+
47
+ public function testInifiniteStreamWrappedInLimitStream()
48
+ {
49
+ $p = Stream::factory(function () { return 'a'; });
50
+ $s = new LimitStream($p, 5);
51
+ $this->assertEquals('aaaaa', (string) $s);
52
+ }
53
+
54
+ public function testDescribesCapabilities()
55
+ {
56
+ $p = Stream::factory(function () {});
57
+ $this->assertTrue($p->isReadable());
58
+ $this->assertFalse($p->isSeekable());
59
+ $this->assertFalse($p->isWritable());
60
+ $this->assertNull($p->getSize());
61
+ $this->assertFalse($p->write('aa'));
62
+ $this->assertEquals('', $p->getContents());
63
+ $this->assertEquals('', (string) $p);
64
+ $p->close();
65
+ $this->assertEquals('', $p->read(10));
66
+ $this->assertTrue($p->eof());
67
+ }
68
+
69
+ /**
70
+ * @expectedException \GuzzleHttp\Stream\Exception\CannotAttachException
71
+ */
72
+ public function testCannotAttach()
73
+ {
74
+ $p = Stream::factory(function () {});
75
+ $p->attach('a');
76
+ }
77
+ }
backend/vendor/guzzlehttp/streams/tests/StreamDecoratorTraitTest.php ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests\Stream;
3
+
4
+ use GuzzleHttp\Stream\StreamInterface;
5
+ use GuzzleHttp\Stream\Stream;
6
+ use GuzzleHttp\Stream\StreamDecoratorTrait;
7
+
8
+ class Str implements StreamInterface
9
+ {
10
+ use StreamDecoratorTrait;
11
+ }
12
+
13
+ /**
14
+ * @covers GuzzleHttp\Stream\StreamDecoratorTrait
15
+ */
16
+ class StreamDecoratorTraitTest extends \PHPUnit_Framework_TestCase
17
+ {
18
+ private $a;
19
+ private $b;
20
+ private $c;
21
+
22
+ public function setUp()
23
+ {
24
+ $this->c = fopen('php://temp', 'r+');
25
+ fwrite($this->c, 'foo');
26
+ fseek($this->c, 0);
27
+ $this->a = Stream::factory($this->c);
28
+ $this->b = new Str($this->a);
29
+ }
30
+
31
+ public function testCatchesExceptionsWhenCastingToString()
32
+ {
33
+ $s = $this->getMockBuilder('GuzzleHttp\Stream\StreamInterface')
34
+ ->setMethods(['read'])
35
+ ->getMockForAbstractClass();
36
+ $s->expects($this->once())
37
+ ->method('read')
38
+ ->will($this->throwException(new \Exception('foo')));
39
+ $msg = '';
40
+ set_error_handler(function ($errNo, $str) use (&$msg) { $msg = $str; });
41
+ echo new Str($s);
42
+ restore_error_handler();
43
+ $this->assertContains('foo', $msg);
44
+ }
45
+
46
+ public function testToString()
47
+ {
48
+ $this->assertEquals('foo', (string) $this->b);
49
+ }
50
+
51
+ public function testHasSize()
52
+ {
53
+ $this->assertEquals(3, $this->b->getSize());
54
+ $this->assertSame($this->b, $this->b->setSize(2));
55
+ $this->assertEquals(2, $this->b->getSize());
56
+ }
57
+
58
+ public function testReads()
59
+ {
60
+ $this->assertEquals('foo', $this->b->read(10));
61
+ }
62
+
63
+ public function testCheckMethods()
64
+ {
65
+ $this->assertEquals($this->a->isReadable(), $this->b->isReadable());
66
+ $this->assertEquals($this->a->isWritable(), $this->b->isWritable());
67
+ $this->assertEquals($this->a->isSeekable(), $this->b->isSeekable());
68
+ }
69
+
70
+ public function testSeeksAndTells()
71
+ {
72
+ $this->assertTrue($this->b->seek(1));
73
+ $this->assertEquals(1, $this->a->tell());
74
+ $this->assertEquals(1, $this->b->tell());
75
+ $this->assertTrue($this->b->seek(0));
76
+ $this->assertEquals(0, $this->a->tell());
77
+ $this->assertEquals(0, $this->b->tell());
78
+ $this->assertTrue($this->b->seek(0, SEEK_END));
79
+ $this->assertEquals(3, $this->a->tell());
80
+ $this->assertEquals(3, $this->b->tell());
81
+ }
82
+
83
+ public function testGetsContents()
84
+ {
85
+ $this->assertEquals('foo', $this->b->getContents());
86
+ $this->assertEquals('', $this->b->getContents());
87
+ $this->b->seek(1);
88
+ $this->assertEquals('oo', $this->b->getContents(1));
89
+ }
90
+
91
+ public function testCloses()
92
+ {
93
+ $this->b->close();
94
+ $this->assertFalse(is_resource($this->c));
95
+ }
96
+
97
+ public function testDetaches()
98
+ {
99
+ $this->b->detach();
100
+ $this->assertFalse($this->b->isReadable());
101
+ }
102
+
103
+ /**
104
+ * @expectedException \GuzzleHttp\Stream\Exception\CannotAttachException
105
+ */
106
+ public function testCannotAttachByDefault()
107
+ {
108
+ $this->b->attach('a');
109
+ }
110
+
111
+ public function testWrapsMetadata()
112
+ {
113
+ $this->assertSame($this->b->getMetadata(), $this->a->getMetadata());
114
+ $this->assertSame($this->b->getMetadata('uri'), $this->a->getMetadata('uri'));
115
+ }
116
+
117
+ public function testWrapsWrites()
118
+ {
119
+ $this->b->seek(0, SEEK_END);
120
+ $this->b->write('foo');
121
+ $this->assertEquals('foofoo', (string) $this->a);
122
+ }
123
+
124
+ /**
125
+ * @expectedException \UnexpectedValueException
126
+ */
127
+ public function testThrowsWithInvalidGetter()
128
+ {
129
+ $this->b->foo;
130
+ }
131
+
132
+ /**
133
+ * @expectedException \BadMethodCallException
134
+ */
135
+ public function testThrowsWhenGetterNotImplemented()
136
+ {
137
+ $s = new BadStream();
138
+ $s->stream;
139
+ }
140
+ }
141
+
142
+ class BadStream
143
+ {
144
+ use StreamDecoratorTrait;
145
+
146
+ public function __construct() {}
147
+ }
backend/vendor/guzzlehttp/streams/tests/StreamTest.php ADDED
@@ -0,0 +1,252 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests\Stream;
3
+
4
+ use GuzzleHttp\Stream\Stream;
5
+
6
+ /**
7
+ * @covers GuzzleHttp\Stream\Stream
8
+ */
9
+ class StreamTest extends \PHPUnit_Framework_TestCase
10
+ {
11
+ /**
12
+ * @expectedException \InvalidArgumentException
13
+ */
14
+ public function testConstructorThrowsExceptionOnInvalidArgument()
15
+ {
16
+ new Stream(true);
17
+ }
18
+
19
+ public function testConstructorInitializesProperties()
20
+ {
21
+ $handle = fopen('php://temp', 'r+');
22
+ fwrite($handle, 'data');
23
+ $stream = new Stream($handle);
24
+ $this->assertTrue($stream->isReadable());
25
+ $this->assertTrue($stream->isWritable());
26
+ $this->assertTrue($stream->isSeekable());
27
+ $this->assertEquals('php://temp', $stream->getMetadata('uri'));
28
+ $this->assertInternalType('array', $stream->getMetadata());
29
+ $this->assertEquals(4, $stream->getSize());
30
+ $this->assertFalse($stream->eof());
31
+ $stream->close();
32
+ }
33
+
34
+ public function testStreamClosesHandleOnDestruct()
35
+ {
36
+ $handle = fopen('php://temp', 'r');
37
+ $stream = new Stream($handle);
38
+ unset($stream);
39
+ $this->assertFalse(is_resource($handle));
40
+ }
41
+
42
+ public function testConvertsToString()
43
+ {
44
+ $handle = fopen('php://temp', 'w+');
45
+ fwrite($handle, 'data');
46
+ $stream = new Stream($handle);
47
+ $this->assertEquals('data', (string) $stream);
48
+ $this->assertEquals('data', (string) $stream);
49
+ $stream->close();
50
+ }
51
+
52
+ public function testGetsContents()
53
+ {
54
+ $handle = fopen('php://temp', 'w+');
55
+ fwrite($handle, 'data');
56
+ $stream = new Stream($handle);
57
+ $this->assertEquals('', $stream->getContents());
58
+ $stream->seek(0);
59
+ $this->assertEquals('data', $stream->getContents());
60
+ $this->assertEquals('', $stream->getContents());
61
+ }
62
+
63
+ public function testChecksEof()
64
+ {
65
+ $handle = fopen('php://temp', 'w+');
66
+ fwrite($handle, 'data');
67
+ $stream = new Stream($handle);
68
+ $this->assertFalse($stream->eof());
69
+ $stream->read(4);
70
+ $this->assertTrue($stream->eof());
71
+ $stream->close();
72
+ }
73
+
74
+ public function testAllowsSettingManualSize()
75
+ {
76
+ $handle = fopen('php://temp', 'w+');
77
+ fwrite($handle, 'data');
78
+ $stream = new Stream($handle);
79
+ $stream->setSize(10);
80
+ $this->assertEquals(10, $stream->getSize());
81
+ $stream->close();
82
+ }
83
+
84
+ public function testGetSize()
85
+ {
86
+ $size = filesize(__FILE__);
87
+ $handle = fopen(__FILE__, 'r');
88
+ $stream = new Stream($handle);
89
+ $this->assertEquals($size, $stream->getSize());
90
+ // Load from cache
91
+ $this->assertEquals($size, $stream->getSize());
92
+ $stream->close();
93
+ }
94
+
95
+ public function testEnsuresSizeIsConsistent()
96
+ {
97
+ $h = fopen('php://temp', 'w+');
98
+ $this->assertEquals(3, fwrite($h, 'foo'));
99
+ $stream = new Stream($h);
100
+ $this->assertEquals(3, $stream->getSize());
101
+ $this->assertEquals(4, $stream->write('test'));
102
+ $this->assertEquals(7, $stream->getSize());
103
+ $this->assertEquals(7, $stream->getSize());
104
+ $stream->close();
105
+ }
106
+
107
+ public function testProvidesStreamPosition()
108
+ {
109
+ $handle = fopen('php://temp', 'w+');
110
+ $stream = new Stream($handle);
111
+ $this->assertEquals(0, $stream->tell());
112
+ $stream->write('foo');
113
+ $this->assertEquals(3, $stream->tell());
114
+ $stream->seek(1);
115
+ $this->assertEquals(1, $stream->tell());
116
+ $this->assertSame(ftell($handle), $stream->tell());
117
+ $stream->close();
118
+ }
119
+
120
+ public function testKeepsPositionOfResource()
121
+ {
122
+ $h = fopen(__FILE__, 'r');
123
+ fseek($h, 10);
124
+ $stream = Stream::factory($h);
125
+ $this->assertEquals(10, $stream->tell());
126
+ $stream->close();
127
+ }
128
+
129
+ public function testCanDetachAndAttachStream()
130
+ {
131
+ $r = fopen('php://temp', 'w+');
132
+ $stream = new Stream($r);
133
+ $stream->write('foo');
134
+ $this->assertTrue($stream->isReadable());
135
+ $this->assertSame($r, $stream->detach());
136
+ $this->assertNull($stream->detach());
137
+
138
+ $this->assertFalse($stream->isReadable());
139
+ $this->assertFalse($stream->read(10));
140
+ $this->assertFalse($stream->isWritable());
141
+ $this->assertFalse($stream->write('bar'));
142
+ $this->assertFalse($stream->isSeekable());
143
+ $this->assertFalse($stream->seek(10));
144
+ $this->assertFalse($stream->tell());
145
+ $this->assertTrue($stream->eof());
146
+ $this->assertNull($stream->getSize());
147
+ $this->assertSame('', (string) $stream);
148
+ $this->assertSame('', $stream->getContents());
149
+
150
+ $stream->attach($r);
151
+ $stream->seek(0);
152
+ $this->assertEquals('foo', $stream->getContents());
153
+ $this->assertTrue($stream->isReadable());
154
+ $this->assertTrue($stream->isWritable());
155
+ $this->assertTrue($stream->isSeekable());
156
+
157
+ $stream->close();
158
+ }
159
+
160
+ public function testCloseClearProperties()
161
+ {
162
+ $handle = fopen('php://temp', 'r+');
163
+ $stream = new Stream($handle);
164
+ $stream->close();
165
+
166
+ $this->assertEmpty($stream->getMetadata());
167
+ $this->assertFalse($stream->isSeekable());
168
+ $this->assertFalse($stream->isReadable());
169
+ $this->assertFalse($stream->isWritable());
170
+ $this->assertNull($stream->getSize());
171
+ }
172
+
173
+ public function testCreatesWithFactory()
174
+ {
175
+ $stream = Stream::factory('foo');
176
+ $this->assertInstanceOf('GuzzleHttp\Stream\Stream', $stream);
177
+ $this->assertEquals('foo', $stream->getContents());
178
+ $stream->close();
179
+ }
180
+
181
+ public function testFactoryCreatesFromEmptyString()
182
+ {
183
+ $s = Stream::factory();
184
+ $this->assertInstanceOf('GuzzleHttp\Stream\Stream', $s);
185
+ }
186
+
187
+ public function testFactoryCreatesFromResource()
188
+ {
189
+ $r = fopen(__FILE__, 'r');
190
+ $s = Stream::factory($r);
191
+ $this->assertInstanceOf('GuzzleHttp\Stream\Stream', $s);
192
+ $this->assertSame(file_get_contents(__FILE__), (string) $s);
193
+ }
194
+
195
+ public function testFactoryCreatesFromObjectWithToString()
196
+ {
197
+ $r = new HasToString();
198
+ $s = Stream::factory($r);
199
+ $this->assertInstanceOf('GuzzleHttp\Stream\Stream', $s);
200
+ $this->assertEquals('foo', (string) $s);
201
+ }
202
+
203
+ public function testCreatePassesThrough()
204
+ {
205
+ $s = Stream::factory('foo');
206
+ $this->assertSame($s, Stream::factory($s));
207
+ }
208
+
209
+ /**
210
+ * @expectedException \InvalidArgumentException
211
+ */
212
+ public function testThrowsExceptionForUnknown()
213
+ {
214
+ Stream::factory(new \stdClass());
215
+ }
216
+
217
+ public function testReturnsCustomMetadata()
218
+ {
219
+ $s = Stream::factory('foo', ['metadata' => ['hwm' => 3]]);
220
+ $this->assertEquals(3, $s->getMetadata('hwm'));
221
+ $this->assertArrayHasKey('hwm', $s->getMetadata());
222
+ }
223
+
224
+ public function testCanSetSize()
225
+ {
226
+ $s = Stream::factory('', ['size' => 10]);
227
+ $this->assertEquals(10, $s->getSize());
228
+ }
229
+
230
+ public function testCanCreateIteratorBasedStream()
231
+ {
232
+ $a = new \ArrayIterator(['foo', 'bar', '123']);
233
+ $p = Stream::factory($a);
234
+ $this->assertInstanceOf('GuzzleHttp\Stream\PumpStream', $p);
235
+ $this->assertEquals('foo', $p->read(3));
236
+ $this->assertFalse($p->eof());
237
+ $this->assertEquals('b', $p->read(1));
238
+ $this->assertEquals('a', $p->read(1));
239
+ $this->assertEquals('r12', $p->read(3));
240
+ $this->assertFalse($p->eof());
241
+ $this->assertEquals('3', $p->getContents());
242
+ $this->assertTrue($p->eof());
243
+ $this->assertEquals(9, $p->tell());
244
+ }
245
+ }
246
+
247
+ class HasToString
248
+ {
249
+ public function __toString() {
250
+ return 'foo';
251
+ }
252
+ }
backend/vendor/guzzlehttp/streams/tests/UtilsTest.php ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests\Stream;
3
+
4
+ use GuzzleHttp\Stream\FnStream;
5
+ use GuzzleHttp\Stream\NoSeekStream;
6
+ use GuzzleHttp\Stream\Stream;
7
+ use GuzzleHttp\Stream\Utils;
8
+
9
+ class UtilsTest extends \PHPUnit_Framework_TestCase
10
+ {
11
+ public function testCopiesToString()
12
+ {
13
+ $s = Stream::factory('foobaz');
14
+ $this->assertEquals('foobaz', Utils::copyToString($s));
15
+ $s->seek(0);
16
+ $this->assertEquals('foo', Utils::copyToString($s, 3));
17
+ $this->assertEquals('baz', Utils::copyToString($s, 3));
18
+ $this->assertEquals('', Utils::copyToString($s));
19
+ }
20
+
21
+ public function testCopiesToStringStopsWhenReadFails()
22
+ {
23
+ $s1 = Stream::factory('foobaz');
24
+ $s1 = FnStream::decorate($s1, [
25
+ 'read' => function () {
26
+ return false;
27
+ }
28
+ ]);
29
+ $result = Utils::copyToString($s1);
30
+ $this->assertEquals('', $result);
31
+ }
32
+
33
+ public function testCopiesToStream()
34
+ {
35
+ $s1 = Stream::factory('foobaz');
36
+ $s2 = Stream::factory('');
37
+ Utils::copyToStream($s1, $s2);
38
+ $this->assertEquals('foobaz', (string) $s2);
39
+ $s2 = Stream::factory('');
40
+ $s1->seek(0);
41
+ Utils::copyToStream($s1, $s2, 3);
42
+ $this->assertEquals('foo', (string) $s2);
43
+ Utils::copyToStream($s1, $s2, 3);
44
+ $this->assertEquals('foobaz', (string) $s2);
45
+ }
46
+
47
+ public function testStopsCopyToStreamWhenWriteFails()
48
+ {
49
+ $s1 = Stream::factory('foobaz');
50
+ $s2 = Stream::factory('');
51
+ $s2 = FnStream::decorate($s2, ['write' => function () { return 0; }]);
52
+ Utils::copyToStream($s1, $s2);
53
+ $this->assertEquals('', (string) $s2);
54
+ }
55
+
56
+ public function testStopsCopyToSteamWhenWriteFailsWithMaxLen()
57
+ {
58
+ $s1 = Stream::factory('foobaz');
59
+ $s2 = Stream::factory('');
60
+ $s2 = FnStream::decorate($s2, ['write' => function () { return 0; }]);
61
+ Utils::copyToStream($s1, $s2, 10);
62
+ $this->assertEquals('', (string) $s2);
63
+ }
64
+
65
+ public function testStopsCopyToSteamWhenReadFailsWithMaxLen()
66
+ {
67
+ $s1 = Stream::factory('foobaz');
68
+ $s1 = FnStream::decorate($s1, ['read' => function () { return ''; }]);
69
+ $s2 = Stream::factory('');
70
+ Utils::copyToStream($s1, $s2, 10);
71
+ $this->assertEquals('', (string) $s2);
72
+ }
73
+
74
+ public function testReadsLines()
75
+ {
76
+ $s = Stream::factory("foo\nbaz\nbar");
77
+ $this->assertEquals("foo\n", Utils::readline($s));
78
+ $this->assertEquals("baz\n", Utils::readline($s));
79
+ $this->assertEquals("bar", Utils::readline($s));
80
+ }
81
+
82
+ public function testReadsLinesUpToMaxLength()
83
+ {
84
+ $s = Stream::factory("12345\n");
85
+ $this->assertEquals("123", Utils::readline($s, 4));
86
+ $this->assertEquals("45\n", Utils::readline($s));
87
+ }
88
+
89
+ public function testReadsLineUntilFalseReturnedFromRead()
90
+ {
91
+ $s = $this->getMockBuilder('GuzzleHttp\Stream\Stream')
92
+ ->setMethods(['read', 'eof'])
93
+ ->disableOriginalConstructor()
94
+ ->getMock();
95
+ $s->expects($this->exactly(2))
96
+ ->method('read')
97
+ ->will($this->returnCallback(function () {
98
+ static $c = false;
99
+ if ($c) {
100
+ return false;
101
+ }
102
+ $c = true;
103
+ return 'h';
104
+ }));
105
+ $s->expects($this->exactly(2))
106
+ ->method('eof')
107
+ ->will($this->returnValue(false));
108
+ $this->assertEquals("h", Utils::readline($s));
109
+ }
110
+
111
+ public function testCalculatesHash()
112
+ {
113
+ $s = Stream::factory('foobazbar');
114
+ $this->assertEquals(md5('foobazbar'), Utils::hash($s, 'md5'));
115
+ }
116
+
117
+ /**
118
+ * @expectedException \GuzzleHttp\Stream\Exception\SeekException
119
+ */
120
+ public function testCalculatesHashThrowsWhenSeekFails()
121
+ {
122
+ $s = new NoSeekStream(Stream::factory('foobazbar'));
123
+ $s->read(2);
124
+ Utils::hash($s, 'md5');
125
+ }
126
+
127
+ public function testCalculatesHashSeeksToOriginalPosition()
128
+ {
129
+ $s = Stream::factory('foobazbar');
130
+ $s->seek(4);
131
+ $this->assertEquals(md5('foobazbar'), Utils::hash($s, 'md5'));
132
+ $this->assertEquals(4, $s->tell());
133
+ }
134
+
135
+ public function testOpensFilesSuccessfully()
136
+ {
137
+ $r = Utils::open(__FILE__, 'r');
138
+ $this->assertInternalType('resource', $r);
139
+ fclose($r);
140
+ }
141
+
142
+ /**
143
+ * @expectedException \RuntimeException
144
+ * @expectedExceptionMessage Unable to open /path/to/does/not/exist using mode r
145
+ */
146
+ public function testThrowsExceptionNotWarning()
147
+ {
148
+ Utils::open('/path/to/does/not/exist', 'r');
149
+ }
150
+
151
+ public function testProxiesToFactory()
152
+ {
153
+ $this->assertEquals('foo', (string) Utils::create('foo'));
154
+ }
155
+ }
backend/vendor/react/promise/.gitignore ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ composer.lock
2
+ composer.phar
3
+ phpunit.xml
4
+ vendor/
backend/vendor/react/promise/.travis.yml ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ language: php
2
+
3
+ php:
4
+ - 5.4
5
+ - 5.5
6
+ - 5.6
7
+ - hhvm
8
+
9
+ before_script:
10
+ - composer self-update
11
+ - composer install --dev --prefer-source
12
+
13
+ script: phpunit --coverage-text
backend/vendor/react/promise/CHANGELOG.md ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ CHANGELOG
2
+ =========
3
+
4
+ * 2.2.0 (2014-12-30)
5
+
6
+ * Introduce new ExtendedPromiseInterface implemented by all promises
7
+ * Add new .done() method (part of the ExtendedPromiseInterface)
8
+ * Add new .otherwise() method (part of the ExtendedPromiseInterface)
9
+ * Add new .always() method (part of the ExtendedPromiseInterface)
10
+ * Add new .progress() method (part of the ExtendedPromiseInterface)
11
+ * Rename Deferred::progress to Deferred::notify to avoid confusion with
12
+ ExtendedPromiseInterface::progress (a Deferred::progress alias is still
13
+ available for backward compatibility)
14
+ * resolve() now always returns a ExtendedPromiseInterface
15
+
16
+ * 2.1.0 (2014-10-15)
17
+
18
+ * Introduce new CancellablePromiseInterface implemented by all promises
19
+ * Add new .cancel() method (part of the CancellablePromiseInterface)
20
+
21
+ * 2.0.0 (2013-12-10)
22
+
23
+ New major release. The goal was to streamline the API and to make it more
24
+ compliant with other promise libraries and especially with the new upcoming
25
+ [ES6 promises specification](https://github.com/domenic/promises-unwrapping/).
26
+
27
+ * Add standalone Promise class.
28
+ * Add new React\Promise\race() function.
29
+ * BC break: Bump minimum PHP version to PHP 5.4.
30
+ * BC break: Remove ResolverInterface and PromiseInterface from Deferred.
31
+ * BC break: Change signature of PromiseInterface.
32
+ * BC break: Remove When and Util classes and move static methods to functions.
33
+ * BC break: FulfilledPromise and RejectedPromise now throw an exception when
34
+ initialized with a promise instead of a value/reason.
35
+ * BC break: React\Promise\Deferred::resolve() and React\Promise\Deferred::reject()
36
+ no longer return a promise.
37
+
38
+ * 1.0.4 (2013-04-03)
39
+
40
+ * Trigger PHP errors when invalid callback is passed.
41
+ * Fully resolve rejection value before calling rejection handler.
42
+ * Add When::lazy() to create lazy promises which will be initialized once a
43
+ consumer calls the then() method.
44
+
45
+ * 1.0.3 (2012-11-17)
46
+
47
+ * Add `PromisorInterface` for objects that have a `promise()` method.
48
+
49
+ * 1.0.2 (2012-11-14)
50
+
51
+ * Fix bug in When::any() not correctly unwrapping to a single result value
52
+ * $promiseOrValue argument of When::resolve() and When::reject() is now optional
53
+
54
+ * 1.0.1 (2012-11-13)
55
+
56
+ * Prevent deep recursion which was reaching `xdebug.max_nesting_level` default of 100
57
+
58
+ * 1.0.0 (2012-11-07)
59
+
60
+ * First tagged release
backend/vendor/react/promise/LICENSE ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright (c) 2012 Jan Sorgalla
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
backend/vendor/react/promise/README.md ADDED
@@ -0,0 +1,824 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ React/Promise
2
+ =============
3
+
4
+ A lightweight implementation of
5
+ [CommonJS Promises/A](http://wiki.commonjs.org/wiki/Promises/A) for PHP.
6
+
7
+ [![Build Status](https://secure.travis-ci.org/reactphp/promise.png?branch=master)](http://travis-ci.org/reactphp/promise)
8
+
9
+ Table of Contents
10
+ -----------------
11
+
12
+ 1. [Introduction](#introduction)
13
+ 2. [Concepts](#concepts)
14
+ * [Deferred](#deferred)
15
+ * [Promise](#promise)
16
+ 3. [API](#api)
17
+ * [Deferred](#deferred-1)
18
+ * [Deferred::promise()](#deferredpromise)
19
+ * [Deferred::resolve()](#deferredresolve)
20
+ * [Deferred::reject()](#deferredreject)
21
+ * [Deferred::notify()](#deferrednotify)
22
+ * [PromiseInterface](#promiseinterface)
23
+ * [PromiseInterface::then()](#promiseinterfacethen)
24
+ * [ExtendedPromiseInterface](#extendedpromiseinterface)
25
+ * [ExtendedPromiseInterface::done()](#extendedpromiseinterfacedone)
26
+ * [ExtendedPromiseInterface::otherwise()](#extendedpromiseinterfaceotherwise)
27
+ * [ExtendedPromiseInterface::always()](#extendedpromiseinterfacealways)
28
+ * [ExtendedPromiseInterface::progress()](#extendedpromiseinterfaceprogress)
29
+ * [CancellablePromiseInterface](#cancellablepromiseinterface)
30
+ * [CancellablePromiseInterface::cancel()](#cancellablepromiseinterfacecancel)
31
+ * [Promise](#promise-1)
32
+ * [FulfilledPromise](#fulfilledpromise)
33
+ * [RejectedPromise](#rejectedpromise)
34
+ * [LazyPromise](#lazypromise)
35
+ * [Functions](#functions)
36
+ * [resolve()](#resolve)
37
+ * [reject()](#reject)
38
+ * [all()](#all)
39
+ * [race()](#race)
40
+ * [any()](#any)
41
+ * [some()](#some)
42
+ * [map()](#map)
43
+ * [reduce()](#reduce)
44
+ * [PromisorInterface](#promisorinterface)
45
+ 4. [Examples](#examples)
46
+ * [How to use Deferred](#how-to-use-deferred)
47
+ * [How promise forwarding works](#how-promise-forwarding-works)
48
+ * [Resolution forwarding](#resolution-forwarding)
49
+ * [Rejection forwarding](#rejection-forwarding)
50
+ * [Mixed resolution and rejection forwarding](#mixed-resolution-and-rejection-forwarding)
51
+ * [Progress event forwarding](#progress-event-forwarding)
52
+ * [done() vs. then()](#done-vs-then)
53
+ 5. [Credits](#credits)
54
+ 6. [License](#license)
55
+
56
+ Introduction
57
+ ------------
58
+
59
+ React/Promise is a library implementing
60
+ [CommonJS Promises/A](http://wiki.commonjs.org/wiki/Promises/A) for PHP.
61
+
62
+ It also provides several other useful promise-related concepts, such as joining
63
+ multiple promises and mapping and reducing collections of promises.
64
+
65
+ If you've never heard about promises before,
66
+ [read this first](https://gist.github.com/3889970).
67
+
68
+ Concepts
69
+ --------
70
+
71
+ ### Deferred
72
+
73
+ A **Deferred** represents a computation or unit of work that may not have
74
+ completed yet. Typically (but not always), that computation will be something
75
+ that executes asynchronously and completes at some point in the future.
76
+
77
+ ### Promise
78
+
79
+ While a deferred represents the computation itself, a **Promise** represents
80
+ the result of that computation. Thus, each deferred has a promise that acts as
81
+ a placeholder for its actual result.
82
+
83
+ API
84
+ ---
85
+
86
+ ### Deferred
87
+
88
+ A deferred represents an operation whose resolution is pending. It has separate
89
+ promise and resolver parts.
90
+
91
+ ```php
92
+ $deferred = new React\Promise\Deferred();
93
+
94
+ $promise = $deferred->promise();
95
+
96
+ $deferred->resolve(mixed $value = null);
97
+ $deferred->reject(mixed $reason = null);
98
+ $deferred->notify(mixed $update = null);
99
+ ```
100
+
101
+ The `promise` method returns the promise of the deferred.
102
+
103
+ The `resolve` and `reject` methods control the state of the deferred.
104
+
105
+ The `notify` method is for progress notification.
106
+
107
+ The constructor of the `Deferred` accepts an optional `$canceller` argument.
108
+ See [Promise](#promise-1) for more information.
109
+
110
+ #### Deferred::promise()
111
+
112
+ ```php
113
+ $promise = $deferred->promise();
114
+ ```
115
+
116
+ Returns the promise of the deferred, which you can hand out to others while
117
+ keeping the authority to modify its state to yourself.
118
+
119
+ #### Deferred::resolve()
120
+
121
+ ```php
122
+ $deferred->resolve(mixed $value = null);
123
+ ```
124
+
125
+ Resolves the promise returned by `promise()`. All consumers are notified by
126
+ having `$onFulfilled` (which they registered via `$promise->then()`) called with
127
+ `$value`.
128
+
129
+ If `$value` itself is a promise, the promise will transition to the state of
130
+ this promise once it is resolved.
131
+
132
+ #### Deferred::reject()
133
+
134
+ ```php
135
+ $deferred->reject(mixed $reason = null);
136
+ ```
137
+
138
+ Rejects the promise returned by `promise()`, signalling that the deferred's
139
+ computation failed.
140
+ All consumers are notified by having `$onRejected` (which they registered via
141
+ `$promise->then()`) called with `$reason`.
142
+
143
+ If `$reason` itself is a promise, the promise will be rejected with the outcome
144
+ of this promise regardless whether it fulfills or rejects.
145
+
146
+ #### Deferred::notify()
147
+
148
+ ```php
149
+ $deferred->notify(mixed $update = null);
150
+ ```
151
+
152
+ Triggers progress notifications, to indicate to consumers that the computation
153
+ is making progress toward its result.
154
+
155
+ All consumers are notified by having `$onProgress` (which they registered via
156
+ `$promise->then()`) called with `$update`.
157
+
158
+ ### PromiseInterface
159
+
160
+ The promise interface provides the common interface for all promise
161
+ implementations.
162
+
163
+ A promise represents an eventual outcome, which is either fulfillment (success)
164
+ and an associated value, or rejection (failure) and an associated reason.
165
+
166
+ Once in the fulfilled or rejected state, a promise becomes immutable.
167
+ Neither its state nor its result (or error) can be modified.
168
+
169
+ #### Implementations
170
+
171
+ * [Promise](#promise-1)
172
+ * [FulfilledPromise](#fulfilledpromise)
173
+ * [RejectedPromise](#rejectedpromise)
174
+ * [LazyPromise](#lazypromise)
175
+
176
+ #### PromiseInterface::then()
177
+
178
+ ```php
179
+ $transformedPromise = $promise->then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null);
180
+ ```
181
+
182
+ Transforms a promise's value by applying a function to the promise's fulfillment
183
+ or rejection value. Returns a new promise for the transformed result.
184
+
185
+ The `then()` method registers new fulfilled, rejection and progress handlers
186
+ with a promise (all parameters are optional):
187
+
188
+ * `$onFulfilled` will be invoked once the promise is fulfilled and passed
189
+ the result as the first argument.
190
+ * `$onRejected` will be invoked once the promise is rejected and passed the
191
+ reason as the first argument.
192
+ * `$onProgress` will be invoked whenever the producer of the promise
193
+ triggers progress notifications and passed a single argument (whatever it
194
+ wants) to indicate progress.
195
+
196
+ It returns a new promise that will fulfill with the return value of either
197
+ `$onFulfilled` or `$onRejected`, whichever is called, or will reject with
198
+ the thrown exception if either throws.
199
+
200
+ A promise makes the following guarantees about handlers registered in
201
+ the same call to `then()`:
202
+
203
+ 1. Only one of `$onFulfilled` or `$onRejected` will be called,
204
+ never both.
205
+ 2. `$onFulfilled` and `$onRejected` will never be called more
206
+ than once.
207
+ 3. `$onProgress` may be called multiple times.
208
+
209
+ #### See also
210
+
211
+ * [resolve()](#resolve) - Creating a resolved promise
212
+ * [reject()](#reject) - Creating a rejected promise
213
+ * [ExtendedPromiseInterface::done()](#extendedpromiseinterfacedone)
214
+ * [done() vs. then()](#done-vs-then)
215
+
216
+ ### ExtendedPromiseInterface
217
+
218
+ The ExtendedPromiseInterface extends the PromiseInterface with useful shortcut
219
+ and utility methods which are not part of the Promises/A specification.
220
+
221
+ #### Implementations
222
+
223
+ * [Promise](#promise-1)
224
+ * [FulfilledPromise](#fulfilledpromise)
225
+ * [RejectedPromise](#rejectedpromise)
226
+ * [LazyPromise](#lazypromise)
227
+
228
+ #### ExtendedPromiseInterface::done()
229
+
230
+ ```php
231
+ $promise->done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null);
232
+ ```
233
+
234
+ Consumes the promise's ultimate value if the promise fulfills, or handles the
235
+ ultimate error.
236
+
237
+ It will cause a fatal error if either `$onFulfilled` or `$onRejected` throw or
238
+ return a rejected promise.
239
+
240
+ Since the purpose of `done()` is consumption rather than transformation,
241
+ `done()` always returns `null`.
242
+
243
+ #### See also
244
+
245
+ * [PromiseInterface::then()](#promiseinterfacethen)
246
+ * [done() vs. then()](#done-vs-then)
247
+
248
+ #### ExtendedPromiseInterface::otherwise()
249
+
250
+ ```php
251
+ $promise->otherwise(callable $onRejected);
252
+ ```
253
+
254
+ Registers a rejection handler for promise. It is a shortcut for:
255
+
256
+ ```php
257
+ $promise->then(null, $onRejected);
258
+ ```
259
+
260
+ Additionally, you can type hint the `$reason` argument of `$onRejected` to catch
261
+ only specific errors.
262
+
263
+ ```php
264
+ $promise
265
+ ->otherwise(function (\RuntimeException $reason) {
266
+ // Only catch \RuntimeException instances
267
+ // All other types of errors will propagate automatically
268
+ })
269
+ ->otherwise(function ($reason) {
270
+ // Catch other errors
271
+ )};
272
+ ```
273
+
274
+ #### ExtendedPromiseInterface::always()
275
+
276
+ ```php
277
+ $newPromise = $promise->always(callable $onFulfilledOrRejected);
278
+ ```
279
+
280
+ Allows you to execute "cleanup" type tasks in a promise chain.
281
+
282
+ It arranges for `$onFulfilledOrRejected` to be called, with no arguments,
283
+ when the promise is either fulfilled or rejected.
284
+
285
+ * If `$promise` fulfills, and `$onFulfilledOrRejected` returns successfully,
286
+ `$newPromise` will fulfill with the same value as `$promise`.
287
+ * If `$promise` fulfills, and `$onFulfilledOrRejected` throws or returns a
288
+ rejected promise, `$newPromise` will reject with the thrown exception or
289
+ rejected promise's reason.
290
+ * If `$promise` rejects, and `$onFulfilledOrRejected` returns successfully,
291
+ `$newPromise` will reject with the same reason as `$promise`.
292
+ * If `$promise` rejects, and `$onFulfilledOrRejected` throws or returns a
293
+ rejected promise, `$newPromise` will reject with the thrown exception or
294
+ rejected promise's reason.
295
+
296
+ `always()` behaves similarly to the synchronous finally statement. When combined
297
+ with `otherwise()`, `always()` allows you to write code that is similar to the familiar
298
+ synchronous catch/finally pair.
299
+
300
+ Consider the following synchronous code:
301
+
302
+ ```php
303
+ try {
304
+ return doSomething();
305
+ } catch(\Exception $e) {
306
+ return handleError($e);
307
+ } finally {
308
+ cleanup();
309
+ }
310
+ ```
311
+
312
+ Similar asynchronous code (with `doSomething()` that returns a promise) can be
313
+ written:
314
+
315
+ ```php
316
+ return doSomething()
317
+ ->otherwise('handleError')
318
+ ->always('cleanup');
319
+ ```
320
+
321
+ #### ExtendedPromiseInterface::progress()
322
+
323
+ ```php
324
+ $promise->progress(callable $onProgress);
325
+ ```
326
+
327
+ Registers a handler for progress updates from promise. It is a shortcut for:
328
+
329
+ ```php
330
+ $promise->then(null, null, $onProgress);
331
+ ```
332
+
333
+ ### CancellablePromiseInterface
334
+
335
+ A cancellable promise provides a mechanism for consumers to notify the creator
336
+ of the promise that they are not longer interested in the result of an
337
+ operation.
338
+
339
+ #### CancellablePromiseInterface::cancel()
340
+
341
+ ``` php
342
+ $promise->cancel();
343
+ ```
344
+
345
+ The `cancel()` method notifies the creator of the promise that there is no
346
+ further interest in the results of the operation.
347
+
348
+ Once a promise is settled (either fulfilled or rejected), calling `cancel()` on
349
+ a promise has no effect.
350
+
351
+ #### Implementations
352
+
353
+ * [Promise](#promise-1)
354
+ * [FulfilledPromise](#fulfilledpromise)
355
+ * [RejectedPromise](#rejectedpromise)
356
+ * [LazyPromise](#lazypromise)
357
+
358
+ ### Promise
359
+
360
+ Creates a promise whose state is controlled by the functions passed to
361
+ `$resolver`.
362
+
363
+ ```php
364
+ $resolver = function (callable $resolve, callable $reject, callable $notify) {
365
+ // Do some work, possibly asynchronously, and then
366
+ // resolve or reject. You can notify of progress events
367
+ // along the way if you want/need.
368
+
369
+ $resolve($awesomeResult);
370
+ // or $resolve($anotherPromise);
371
+ // or $reject($nastyError);
372
+ // or $notify($progressNotification);
373
+ };
374
+
375
+ $canceller = function (callable $resolve, callable $reject, callable $progress) {
376
+ // Cancel/abort any running operations like network connections, streams etc.
377
+
378
+ $reject(new \Exception('Promise cancelled'));
379
+ };
380
+
381
+ $promise = new React\Promise\Promise($resolver, $canceller);
382
+ ```
383
+
384
+ The promise constructor receives a resolver function and an optional canceller
385
+ function which both will be called with 3 arguments:
386
+
387
+ * `$resolve($value)` - Primary function that seals the fate of the
388
+ returned promise. Accepts either a non-promise value, or another promise.
389
+ When called with a non-promise value, fulfills promise with that value.
390
+ When called with another promise, e.g. `$resolve($otherPromise)`, promise's
391
+ fate will be equivalent to that of `$otherPromise`.
392
+ * `$reject($reason)` - Function that rejects the promise.
393
+ * `$notify($update)` - Function that issues progress events for the promise.
394
+
395
+ If the resolver or canceller throw an exception, the promise will be rejected
396
+ with that thrown exception as the rejection reason.
397
+
398
+ The resolver function will be called immediately, the canceller function only
399
+ once all consumers called the `cancel()` method of the promise.
400
+
401
+ ### FulfilledPromise
402
+
403
+ Creates a already fulfilled promise.
404
+
405
+ ```php
406
+ $promise = React\Promise\FulfilledPromise($value);
407
+ ```
408
+
409
+ Note, that `$value` **cannot** be a promise. It's recommended to use
410
+ [resolve()](#resolve) for creating resolved promises.
411
+
412
+ ### RejectedPromise
413
+
414
+ Creates a already rejected promise.
415
+
416
+ ```php
417
+ $promise = React\Promise\RejectedPromise($reason);
418
+ ```
419
+
420
+ Note, that `$reason` **cannot** be a promise. It's recommended to use
421
+ [reject()](#reject) for creating rejected promises.
422
+
423
+ ### LazyPromise
424
+
425
+ Creates a promise which will be lazily initialized by `$factory` once a consumer
426
+ calls the `then()` method.
427
+
428
+ ```php
429
+ $factory = function () {
430
+ $deferred = new React\Promise\Deferred();
431
+
432
+ // Do some heavy stuff here and resolve the deferred once completed
433
+
434
+ return $deferred->promise();
435
+ };
436
+
437
+ $promise = React\Promise\LazyPromise($factory);
438
+
439
+ // $factory will only be executed once we call then()
440
+ $promise->then(function ($value) {
441
+ });
442
+ ```
443
+
444
+ ### Functions
445
+
446
+ Useful functions for creating, joining, mapping and reducing collections of
447
+ promises.
448
+
449
+ #### resolve()
450
+
451
+ ```php
452
+ $promise = React\Promise\resolve(mixed $promiseOrValue);
453
+ ```
454
+
455
+ Creates a promise for the supplied `$promiseOrValue`.
456
+
457
+ If `$promiseOrValue` is a value, it will be the resolution value of the
458
+ returned promise.
459
+
460
+ If `$promiseOrValue` is a promise, it will simply be returned.
461
+
462
+ Note: The promise returned is always a promise implementing
463
+ [ExtendedPromiseInterface](#extendedpromiseinterface). If you pass in a custom
464
+ promise which only implements [PromiseInterface](#promiseinterface), this
465
+ promise will be assimilated to a extended promise following `$promiseOrValue`.
466
+
467
+ #### reject()
468
+
469
+ ```php
470
+ $promise = React\Promise\reject(mixed $promiseOrValue);
471
+ ```
472
+
473
+ Creates a rejected promise for the supplied `$promiseOrValue`.
474
+
475
+ If `$promiseOrValue` is a value, it will be the rejection value of the
476
+ returned promise.
477
+
478
+ If `$promiseOrValue` is a promise, its completion value will be the rejected
479
+ value of the returned promise.
480
+
481
+ This can be useful in situations where you need to reject a promise without
482
+ throwing an exception. For example, it allows you to propagate a rejection with
483
+ the value of another promise.
484
+
485
+ #### all()
486
+
487
+ ```php
488
+ $promise = React\Promise\all(array|React\Promise\PromiseInterface $promisesOrValues);
489
+ ```
490
+
491
+ Returns a promise that will resolve only once all the items in
492
+ `$promisesOrValues` have resolved. The resolution value of the returned promise
493
+ will be an array containing the resolution values of each of the items in
494
+ `$promisesOrValues`.
495
+
496
+ #### race()
497
+
498
+ ```php
499
+ $promise = React\Promise\race(array|React\Promise\PromiseInterface $promisesOrValues);
500
+ ```
501
+
502
+ Initiates a competitive race that allows one winner. Returns a promise which is
503
+ resolved in the same way the first settled promise resolves.
504
+
505
+ #### any()
506
+
507
+ ```php
508
+ $promise = React\Promise\any(array|React\Promise\PromiseInterface $promisesOrValues);
509
+ ```
510
+
511
+ Returns a promise that will resolve when any one of the items in
512
+ `$promisesOrValues` resolves. The resolution value of the returned promise
513
+ will be the resolution value of the triggering item.
514
+
515
+ The returned promise will only reject if *all* items in `$promisesOrValues` are
516
+ rejected. The rejection value will be an array of all rejection reasons.
517
+
518
+ #### some()
519
+
520
+ ```php
521
+ $promise = React\Promise\some(array|React\Promise\PromiseInterface $promisesOrValues, integer $howMany);
522
+ ```
523
+
524
+ Returns a promise that will resolve when `$howMany` of the supplied items in
525
+ `$promisesOrValues` resolve. The resolution value of the returned promise
526
+ will be an array of length `$howMany` containing the resolution values of the
527
+ triggering items.
528
+
529
+ The returned promise will reject if it becomes impossible for `$howMany` items
530
+ to resolve (that is, when `(count($promisesOrValues) - $howMany) + 1` items
531
+ reject). The rejection value will be an array of
532
+ `(count($promisesOrValues) - $howMany) + 1` rejection reasons.
533
+
534
+ #### map()
535
+
536
+ ```php
537
+ $promise = React\Promise\map(array|React\Promise\PromiseInterface $promisesOrValues, callable $mapFunc);
538
+ ```
539
+
540
+ Traditional map function, similar to `array_map()`, but allows input to contain
541
+ promises and/or values, and `$mapFunc` may return either a value or a promise.
542
+
543
+ The map function receives each item as argument, where item is a fully resolved
544
+ value of a promise or value in `$promisesOrValues`.
545
+
546
+ #### reduce()
547
+
548
+ ```php
549
+ $promise = React\Promise\reduce(array|React\Promise\PromiseInterface $promisesOrValues, callable $reduceFunc , $initialValue = null);
550
+ ```
551
+
552
+ Traditional reduce function, similar to `array_reduce()`, but input may contain
553
+ promises and/or values, and `$reduceFunc` may return either a value or a
554
+ promise, *and* `$initialValue` may be a promise or a value for the starting
555
+ value.
556
+
557
+ ### PromisorInterface
558
+
559
+ The `React\Promise\PromisorInterface` provides a common interface for objects
560
+ that provide a promise. `React\Promise\Deferred` implements it, but since it
561
+ is part of the public API anyone can implement it.
562
+
563
+ Examples
564
+ --------
565
+
566
+ ### How to use Deferred
567
+
568
+ ```php
569
+ function getAwesomeResultPromise()
570
+ {
571
+ $deferred = new React\Promise\Deferred();
572
+
573
+ // Execute a Node.js-style function using the callback pattern
574
+ computeAwesomeResultAsynchronously(function ($error, $result) use ($deferred) {
575
+ if ($error) {
576
+ $deferred->reject($error);
577
+ } else {
578
+ $deferred->resolve($result);
579
+ }
580
+ });
581
+
582
+ // Return the promise
583
+ return $deferred->promise();
584
+ }
585
+
586
+ getAwesomeResultPromise()
587
+ ->then(
588
+ function ($value) {
589
+ // Deferred resolved, do something with $value
590
+ },
591
+ function ($reason) {
592
+ // Deferred rejected, do something with $reason
593
+ },
594
+ function ($update) {
595
+ // Progress notification triggered, do something with $update
596
+ }
597
+ );
598
+ ```
599
+
600
+ ### How promise forwarding works
601
+
602
+ A few simple examples to show how the mechanics of Promises/A forwarding works.
603
+ These examples are contrived, of course, and in real usage, promise chains will
604
+ typically be spread across several function calls, or even several levels of
605
+ your application architecture.
606
+
607
+ #### Resolution forwarding
608
+
609
+ Resolved promises forward resolution values to the next promise.
610
+ The first promise, `$deferred->promise()`, will resolve with the value passed
611
+ to `$deferred->resolve()` below.
612
+
613
+ Each call to `then()` returns a new promise that will resolve with the return
614
+ value of the previous handler. This creates a promise "pipeline".
615
+
616
+ ```php
617
+ $deferred = new React\Promise\Deferred();
618
+
619
+ $deferred->promise()
620
+ ->then(function ($x) {
621
+ // $x will be the value passed to $deferred->resolve() below
622
+ // and returns a *new promise* for $x + 1
623
+ return $x + 1;
624
+ })
625
+ ->then(function ($x) {
626
+ // $x === 2
627
+ // This handler receives the return value of the
628
+ // previous handler.
629
+ return $x + 1;
630
+ })
631
+ ->then(function ($x) {
632
+ // $x === 3
633
+ // This handler receives the return value of the
634
+ // previous handler.
635
+ return $x + 1;
636
+ })
637
+ ->then(function ($x) {
638
+ // $x === 4
639
+ // This handler receives the return value of the
640
+ // previous handler.
641
+ echo 'Resolve ' . $x;
642
+ });
643
+
644
+ $deferred->resolve(1); // Prints "Resolve 4"
645
+ ```
646
+
647
+ #### Rejection forwarding
648
+
649
+ Rejected promises behave similarly, and also work similarly to try/catch:
650
+ When you catch an exception, you must rethrow for it to propagate.
651
+
652
+ Similarly, when you handle a rejected promise, to propagate the rejection,
653
+ "rethrow" it by either returning a rejected promise, or actually throwing
654
+ (since promise translates thrown exceptions into rejections)
655
+
656
+ ```php
657
+ $deferred = new React\Promise\Deferred();
658
+
659
+ $deferred->promise()
660
+ ->then(function ($x) {
661
+ throw new \Exception($x + 1);
662
+ })
663
+ ->then(null, function (\Exception $x) {
664
+ // Propagate the rejection
665
+ throw $x;
666
+ })
667
+ ->then(null, function (\Exception $x) {
668
+ // Can also propagate by returning another rejection
669
+ return React\Promise\reject((integer) $x->getMessage() + 1);
670
+ })
671
+ ->then(null, function ($x) {
672
+ echo 'Reject ' . $x; // 3
673
+ });
674
+
675
+ $deferred->resolve(1); // Prints "Reject 3"
676
+ ```
677
+
678
+ #### Mixed resolution and rejection forwarding
679
+
680
+ Just like try/catch, you can choose to propagate or not. Mixing resolutions and
681
+ rejections will still forward handler results in a predictable way.
682
+
683
+ ```php
684
+ $deferred = new React\Promise\Deferred();
685
+
686
+ $deferred->promise()
687
+ ->then(function ($x) {
688
+ return $x + 1;
689
+ })
690
+ ->then(function ($x) {
691
+ throw \Exception($x + 1);
692
+ })
693
+ ->then(null, function (\Exception $x) {
694
+ // Handle the rejection, and don't propagate.
695
+ // This is like catch without a rethrow
696
+ return (integer) $x->getMessage() + 1;
697
+ })
698
+ ->then(function ($x) {
699
+ echo 'Mixed ' . $x; // 4
700
+ });
701
+
702
+ $deferred->resolve(1); // Prints "Mixed 4"
703
+ ```
704
+
705
+ #### Progress event forwarding
706
+
707
+ In the same way as resolution and rejection handlers, your progress handler
708
+ **MUST** return a progress event to be propagated to the next link in the chain.
709
+ If you return nothing, `null` will be propagated.
710
+
711
+ Also in the same way as resolutions and rejections, if you don't register a
712
+ progress handler, the update will be propagated through.
713
+
714
+ If your progress handler throws an exception, the exception will be propagated
715
+ to the next link in the chain. The best thing to do is to ensure your progress
716
+ handlers do not throw exceptions.
717
+
718
+ This gives you the opportunity to transform progress events at each step in the
719
+ chain so that they are meaningful to the next step. It also allows you to choose
720
+ not to transform them, and simply let them propagate untransformed, by not
721
+ registering a progress handler.
722
+
723
+ ```php
724
+ $deferred = new React\Promise\Deferred();
725
+
726
+ $deferred->promise()
727
+ ->progress(function ($update) {
728
+ return $update + 1;
729
+ })
730
+ ->progress(function ($update) {
731
+ echo 'Progress ' . $update; // 2
732
+ });
733
+
734
+ $deferred->notify(1); // Prints "Progress 2"
735
+ ```
736
+
737
+ ### done() vs. then()
738
+
739
+ The golden rule is:
740
+
741
+ Either return your promise, or call done() on it.
742
+
743
+ At a first glance, `then()` and `done()` seem very similar. However, there are
744
+ important distinctions.
745
+
746
+ The intent of `then()` is to transform a promise's value and to pass or return
747
+ a new promise for the transformed value along to other parts of your code.
748
+
749
+ The intent of `done()` is to consume a promise's value, transferring
750
+ responsibility for the value to your code.
751
+
752
+ In addition to transforming a value, `then()` allows you to recover from, or
753
+ propagate intermediate errors. Any errors that are not handled will be caught
754
+ by the promise machinery and used to reject the promise returned by `then()`.
755
+
756
+ Calling `done()` transfers all responsibility for errors to your code. If an
757
+ error (either a thrown exception or returned rejection) escapes the
758
+ `$onFulfilled` or `$onRejected` callbacks you provide to done, it will be
759
+ rethrown in an uncatchable way causing a fatal error.
760
+
761
+ ```php
762
+ function getJsonResult()
763
+ {
764
+ return queryApi()
765
+ ->then(
766
+ // Transform API results to an object
767
+ function ($jsonResultString) {
768
+ return json_decode($jsonResultString);
769
+ },
770
+ // Transform API errors to an exception
771
+ function ($jsonErrorString) {
772
+ $object = json_decode($jsonErrorString);
773
+ throw new ApiErrorException($object->errorMessage);
774
+ }
775
+ );
776
+ }
777
+
778
+ // Here we provide no rejection handler.
779
+ // If the promise returned has been rejected,
780
+ // a React\Promise\UnhandledRejectionException will be thrown
781
+ getJsonResult()
782
+ ->done(
783
+ // Consume transformed object
784
+ function ($jsonResultObject) {
785
+ // Do something with $jsonObject
786
+ }
787
+ );
788
+
789
+ // Here we provide a rejection handler which will either throw while debugging
790
+ // or log the exception.
791
+ getJsonResult()
792
+ ->done(
793
+ function ($jsonObject) {
794
+ // Do something with $jsonObject
795
+ },
796
+ function (ApiErrorException $exception) {
797
+ if (isDebug()) {
798
+ throw $e;
799
+ } else {
800
+ logException($exception);
801
+ }
802
+ }
803
+ );
804
+ ```
805
+
806
+ Note that if a rejection value is not an instance of `\Exception`, it will be
807
+ wrapped in an exception of the type `React\Promise\UnhandledRejectionException`.
808
+
809
+ You can get the original rejection reason by calling `$exception->getReason()`.
810
+
811
+ Credits
812
+ -------
813
+
814
+ React/Promise is a port of [when.js](https://github.com/cujojs/when)
815
+ by [Brian Cavalier](https://github.com/briancavalier).
816
+
817
+ Also, large parts of the documentation have been ported from the when.js
818
+ [Wiki](https://github.com/cujojs/when/wiki) and the
819
+ [API docs](https://github.com/cujojs/when/blob/master/docs/api.md).
820
+
821
+ License
822
+ -------
823
+
824
+ React/Promise is released under the [MIT](https://github.com/reactphp/promise/blob/master/LICENSE) license.
backend/vendor/react/promise/composer.json ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "react/promise",
3
+ "description": "A lightweight implementation of CommonJS Promises/A for PHP",
4
+ "license": "MIT",
5
+ "authors": [
6
+ {"name": "Jan Sorgalla", "email": "jsorgalla@googlemail.com"}
7
+ ],
8
+ "require": {
9
+ "php": ">=5.4.0"
10
+ },
11
+ "autoload": {
12
+ "psr-4": {
13
+ "React\\Promise\\": "src/"
14
+ },
15
+ "files": ["src/functions_include.php"]
16
+ },
17
+ "extra": {
18
+ "branch-alias": {
19
+ "dev-master": "2.0-dev"
20
+ }
21
+ }
22
+ }
backend/vendor/react/promise/phpunit.xml.dist ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+
3
+ <phpunit backupGlobals="false"
4
+ backupStaticAttributes="false"
5
+ colors="true"
6
+ convertErrorsToExceptions="true"
7
+ convertNoticesToExceptions="true"
8
+ convertWarningsToExceptions="true"
9
+ processIsolation="false"
10
+ stopOnFailure="false"
11
+ syntaxCheck="false"
12
+ bootstrap="tests/bootstrap.php"
13
+ >
14
+ <testsuites>
15
+ <testsuite name="Promise Test Suite">
16
+ <directory>./tests/</directory>
17
+ </testsuite>
18
+ </testsuites>
19
+
20
+ <filter>
21
+ <whitelist>
22
+ <directory>./src/</directory>
23
+ </whitelist>
24
+ </filter>
25
+ </phpunit>
backend/vendor/react/promise/src/CancellablePromiseInterface.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace React\Promise;
4
+
5
+ interface CancellablePromiseInterface extends PromiseInterface
6
+ {
7
+ /**
8
+ * @return void
9
+ */
10
+ public function cancel();
11
+ }
backend/vendor/react/promise/src/Deferred.php ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace React\Promise;
4
+
5
+ class Deferred implements PromisorInterface
6
+ {
7
+ private $promise;
8
+ private $resolveCallback;
9
+ private $rejectCallback;
10
+ private $notifyCallback;
11
+ private $canceller;
12
+
13
+ public function __construct(callable $canceller = null)
14
+ {
15
+ $this->canceller = $canceller;
16
+ }
17
+
18
+ public function promise()
19
+ {
20
+ if (null === $this->promise) {
21
+ $this->promise = new Promise(function ($resolve, $reject, $notify) {
22
+ $this->resolveCallback = $resolve;
23
+ $this->rejectCallback = $reject;
24
+ $this->notifyCallback = $notify;
25
+ }, $this->canceller);
26
+ }
27
+
28
+ return $this->promise;
29
+ }
30
+
31
+ public function resolve($value = null)
32
+ {
33
+ $this->promise();
34
+
35
+ call_user_func($this->resolveCallback, $value);
36
+ }
37
+
38
+ public function reject($reason = null)
39
+ {
40
+ $this->promise();
41
+
42
+ call_user_func($this->rejectCallback, $reason);
43
+ }
44
+
45
+ public function notify($update = null)
46
+ {
47
+ $this->promise();
48
+
49
+ call_user_func($this->notifyCallback, $update);
50
+ }
51
+
52
+ /**
53
+ * @deprecated 2.2.0
54
+ * @see Deferred::notify()
55
+ */
56
+ public function progress($update = null)
57
+ {
58
+ $this->notify($update);
59
+ }
60
+ }
backend/vendor/react/promise/src/ExtendedPromiseInterface.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace React\Promise;
4
+
5
+ interface ExtendedPromiseInterface extends PromiseInterface
6
+ {
7
+ /**
8
+ * @return void
9
+ */
10
+ public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null);
11
+
12
+ /**
13
+ * @return ExtendedPromiseInterface
14
+ */
15
+ public function otherwise(callable $onRejected);
16
+
17
+ /**
18
+ * @return ExtendedPromiseInterface
19
+ */
20
+ public function always(callable $onFulfilledOrRejected);
21
+
22
+ /**
23
+ * @return ExtendedPromiseInterface
24
+ */
25
+ public function progress(callable $onProgress);
26
+ }
backend/vendor/react/promise/src/FulfilledPromise.php ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace React\Promise;
4
+
5
+ class FulfilledPromise implements ExtendedPromiseInterface, CancellablePromiseInterface
6
+ {
7
+ private $value;
8
+
9
+ public function __construct($value = null)
10
+ {
11
+ if ($value instanceof PromiseInterface) {
12
+ throw new \InvalidArgumentException('You cannot create React\Promise\FulfilledPromise with a promise. Use React\Promise\resolve($promiseOrValue) instead.');
13
+ }
14
+
15
+ $this->value = $value;
16
+ }
17
+
18
+ public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
19
+ {
20
+ try {
21
+ $value = $this->value;
22
+
23
+ if (null !== $onFulfilled) {
24
+ $value = $onFulfilled($value);
25
+ }
26
+
27
+ return resolve($value);
28
+ } catch (\Exception $exception) {
29
+ return new RejectedPromise($exception);
30
+ }
31
+ }
32
+
33
+ public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
34
+ {
35
+ if (null === $onFulfilled) {
36
+ return;
37
+ }
38
+
39
+ $result = $onFulfilled($this->value);
40
+
41
+ if ($result instanceof ExtendedPromiseInterface) {
42
+ $result->done();
43
+ }
44
+ }
45
+
46
+ public function otherwise(callable $onRejected)
47
+ {
48
+ return new FulfilledPromise($this->value);
49
+ }
50
+
51
+ public function always(callable $onFulfilledOrRejected)
52
+ {
53
+ return $this->then(function ($value) use ($onFulfilledOrRejected) {
54
+ return resolve($onFulfilledOrRejected())->then(function () use ($value) {
55
+ return $value;
56
+ });
57
+ });
58
+ }
59
+
60
+ public function progress(callable $onProgress)
61
+ {
62
+ return new FulfilledPromise($this->value);
63
+ }
64
+
65
+ public function cancel()
66
+ {
67
+ }
68
+ }
backend/vendor/react/promise/src/LazyPromise.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace React\Promise;
4
+
5
+ class LazyPromise implements ExtendedPromiseInterface, CancellablePromiseInterface
6
+ {
7
+ private $factory;
8
+ private $promise;
9
+
10
+ public function __construct(callable $factory)
11
+ {
12
+ $this->factory = $factory;
13
+ }
14
+
15
+ public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
16
+ {
17
+ return $this->promise()->then($onFulfilled, $onRejected, $onProgress);
18
+ }
19
+
20
+
21
+ public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
22
+ {
23
+ return $this->promise()->done($onFulfilled, $onRejected, $onProgress);
24
+ }
25
+
26
+ public function otherwise(callable $onRejected)
27
+ {
28
+ return $this->promise()->otherwise($onRejected);
29
+ }
30
+
31
+ public function always(callable $onFulfilledOrRejected)
32
+ {
33
+ return $this->promise()->always($onFulfilledOrRejected);
34
+ }
35
+
36
+ public function progress(callable $onProgress)
37
+ {
38
+ return $this->promise()->progress($onProgress);
39
+ }
40
+
41
+ public function cancel()
42
+ {
43
+ return $this->promise()->cancel();
44
+ }
45
+
46
+ private function promise()
47
+ {
48
+ if (null === $this->promise) {
49
+ try {
50
+ $this->promise = resolve(call_user_func($this->factory));
51
+ } catch (\Exception $exception) {
52
+ $this->promise = new RejectedPromise($exception);
53
+ }
54
+ }
55
+
56
+ return $this->promise;
57
+ }
58
+ }
backend/vendor/react/promise/src/Promise.php ADDED
@@ -0,0 +1,182 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace React\Promise;
4
+
5
+ class Promise implements ExtendedPromiseInterface, CancellablePromiseInterface
6
+ {
7
+ private $canceller;
8
+ private $result;
9
+
10
+ private $handlers = [];
11
+ private $progressHandlers = [];
12
+
13
+ private $requiredCancelRequests = 0;
14
+ private $cancelRequests = 0;
15
+
16
+ public function __construct(callable $resolver, callable $canceller = null)
17
+ {
18
+ $this->canceller = $canceller;
19
+ $this->call($resolver);
20
+ }
21
+
22
+ public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
23
+ {
24
+ if (null !== $this->result) {
25
+ return $this->result->then($onFulfilled, $onRejected, $onProgress);
26
+ }
27
+
28
+ if (null === $this->canceller) {
29
+ return new static($this->resolver($onFulfilled, $onRejected, $onProgress));
30
+ }
31
+
32
+ $this->requiredCancelRequests++;
33
+
34
+ return new static($this->resolver($onFulfilled, $onRejected, $onProgress), function ($resolve, $reject, $progress) {
35
+ if (++$this->cancelRequests < $this->requiredCancelRequests) {
36
+ return;
37
+ }
38
+
39
+ $this->cancel();
40
+ });
41
+ }
42
+
43
+ public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
44
+ {
45
+ if (null !== $this->result) {
46
+ return $this->result->done($onFulfilled, $onRejected, $onProgress);
47
+ }
48
+
49
+ $this->handlers[] = function (PromiseInterface $promise) use ($onFulfilled, $onRejected) {
50
+ $promise
51
+ ->done($onFulfilled, $onRejected);
52
+ };
53
+
54
+ if ($onProgress) {
55
+ $this->progressHandlers[] = $onProgress;
56
+ }
57
+ }
58
+
59
+ public function otherwise(callable $onRejected)
60
+ {
61
+ return $this->then(null, function ($reason) use ($onRejected) {
62
+ if (!_checkTypehint($onRejected, $reason)) {
63
+ return new RejectedPromise($reason);
64
+ }
65
+
66
+ return $onRejected($reason);
67
+ });
68
+ }
69
+
70
+ public function always(callable $onFulfilledOrRejected)
71
+ {
72
+ return $this->then(function ($value) use ($onFulfilledOrRejected) {
73
+ return resolve($onFulfilledOrRejected())->then(function () use ($value) {
74
+ return $value;
75
+ });
76
+ }, function ($reason) use ($onFulfilledOrRejected) {
77
+ return resolve($onFulfilledOrRejected())->then(function () use ($reason) {
78
+ return new RejectedPromise($reason);
79
+ });
80
+ });
81
+ }
82
+
83
+ public function progress(callable $onProgress)
84
+ {
85
+ return $this->then(null, null, $onProgress);
86
+ }
87
+
88
+ public function cancel()
89
+ {
90
+ if (null === $this->canceller || null !== $this->result) {
91
+ return;
92
+ }
93
+
94
+ $this->call($this->canceller);
95
+ }
96
+
97
+ private function resolver(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
98
+ {
99
+ return function ($resolve, $reject, $notify) use ($onFulfilled, $onRejected, $onProgress) {
100
+ if ($onProgress) {
101
+ $progressHandler = function ($update) use ($notify, $onProgress) {
102
+ try {
103
+ $notify($onProgress($update));
104
+ } catch (\Exception $e) {
105
+ $notify($e);
106
+ }
107
+ };
108
+ } else {
109
+ $progressHandler = $notify;
110
+ }
111
+
112
+ $this->handlers[] = function (PromiseInterface $promise) use ($onFulfilled, $onRejected, $resolve, $reject, $progressHandler) {
113
+ $promise
114
+ ->then($onFulfilled, $onRejected)
115
+ ->done($resolve, $reject, $progressHandler);
116
+ };
117
+
118
+ $this->progressHandlers[] = $progressHandler;
119
+ };
120
+ }
121
+
122
+ private function resolve($value = null)
123
+ {
124
+ if (null !== $this->result) {
125
+ return;
126
+ }
127
+
128
+ $this->settle(resolve($value));
129
+ }
130
+
131
+ private function reject($reason = null)
132
+ {
133
+ if (null !== $this->result) {
134
+ return;
135
+ }
136
+
137
+ $this->settle(reject($reason));
138
+ }
139
+
140
+ private function notify($update = null)
141
+ {
142
+ if (null !== $this->result) {
143
+ return;
144
+ }
145
+
146
+ foreach ($this->progressHandlers as $handler) {
147
+ $handler($update);
148
+ }
149
+ }
150
+
151
+ private function settle(ExtendedPromiseInterface $promise)
152
+ {
153
+ $result = $promise;
154
+
155
+ foreach ($this->handlers as $handler) {
156
+ $handler($result);
157
+ }
158
+
159
+ $this->progressHandlers = $this->handlers = [];
160
+
161
+ $this->result = $result;
162
+ }
163
+
164
+ private function call(callable $callback)
165
+ {
166
+ try {
167
+ $callback(
168
+ function ($value = null) {
169
+ $this->resolve($value);
170
+ },
171
+ function ($reason = null) {
172
+ $this->reject($reason);
173
+ },
174
+ function ($update = null) {
175
+ $this->notify($update);
176
+ }
177
+ );
178
+ } catch (\Exception $e) {
179
+ $this->reject($e);
180
+ }
181
+ }
182
+ }
backend/vendor/react/promise/src/PromiseInterface.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace React\Promise;
4
+
5
+ interface PromiseInterface
6
+ {
7
+ /**
8
+ * @return PromiseInterface
9
+ */
10
+ public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null);
11
+ }
backend/vendor/react/promise/src/PromisorInterface.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace React\Promise;
4
+
5
+ interface PromisorInterface
6
+ {
7
+ /**
8
+ * @return PromiseInterface
9
+ */
10
+ public function promise();
11
+ }
backend/vendor/react/promise/src/RejectedPromise.php ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace React\Promise;
4
+
5
+ class RejectedPromise implements ExtendedPromiseInterface, CancellablePromiseInterface
6
+ {
7
+ private $reason;
8
+
9
+ public function __construct($reason = null)
10
+ {
11
+ if ($reason instanceof PromiseInterface) {
12
+ throw new \InvalidArgumentException('You cannot create React\Promise\RejectedPromise with a promise. Use React\Promise\reject($promiseOrValue) instead.');
13
+ }
14
+
15
+ $this->reason = $reason;
16
+ }
17
+
18
+ public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
19
+ {
20
+ try {
21
+ if (null === $onRejected) {
22
+ return new RejectedPromise($this->reason);
23
+ }
24
+
25
+ return resolve($onRejected($this->reason));
26
+ } catch (\Exception $exception) {
27
+ return new RejectedPromise($exception);
28
+ }
29
+ }
30
+
31
+ public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
32
+ {
33
+ if (null === $onRejected) {
34
+ throw UnhandledRejectionException::resolve($this->reason);
35
+ }
36
+
37
+ $result = $onRejected($this->reason);
38
+
39
+ if ($result instanceof self) {
40
+ throw UnhandledRejectionException::resolve($result->reason);
41
+ }
42
+
43
+ if ($result instanceof ExtendedPromiseInterface) {
44
+ $result->done();
45
+ }
46
+ }
47
+
48
+ public function otherwise(callable $onRejected)
49
+ {
50
+ if (!_checkTypehint($onRejected, $this->reason)) {
51
+ return new RejectedPromise($this->reason);
52
+ }
53
+
54
+ return $this->then(null, $onRejected);
55
+ }
56
+
57
+ public function always(callable $onFulfilledOrRejected)
58
+ {
59
+ return $this->then(null, function ($reason) use ($onFulfilledOrRejected) {
60
+ return resolve($onFulfilledOrRejected())->then(function () use ($reason) {
61
+ return new RejectedPromise($reason);
62
+ });
63
+ });
64
+ }
65
+
66
+ public function progress(callable $onProgress)
67
+ {
68
+ return new RejectedPromise($this->reason);
69
+ }
70
+
71
+ public function cancel()
72
+ {
73
+ }
74
+ }
backend/vendor/react/promise/src/UnhandledRejectionException.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace React\Promise;
4
+
5
+ class UnhandledRejectionException extends \RuntimeException
6
+ {
7
+ private $reason;
8
+
9
+ public static function resolve($reason)
10
+ {
11
+ if ($reason instanceof \Exception) {
12
+ return $reason;
13
+ }
14
+
15
+ return new static($reason);
16
+ }
17
+
18
+ public function __construct($reason)
19
+ {
20
+ $this->reason = $reason;
21
+
22
+ $message = sprintf('Unhandled Rejection: %s', json_encode($reason));
23
+
24
+ parent::__construct($message, 0);
25
+ }
26
+
27
+ public function getReason()
28
+ {
29
+ return $this->reason;
30
+ }
31
+ }
backend/vendor/react/promise/src/functions.php ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace React\Promise;
4
+
5
+ function resolve($promiseOrValue = null)
6
+ {
7
+ if (!$promiseOrValue instanceof PromiseInterface) {
8
+ return new FulfilledPromise($promiseOrValue);
9
+ }
10
+
11
+ if ($promiseOrValue instanceof ExtendedPromiseInterface) {
12
+ return $promiseOrValue;
13
+ }
14
+
15
+ return new Promise(function ($resolve, $reject, $notify) use ($promiseOrValue) {
16
+ $promiseOrValue->then($resolve, $reject, $notify);
17
+ });
18
+ }
19
+
20
+ function reject($promiseOrValue = null)
21
+ {
22
+ if ($promiseOrValue instanceof PromiseInterface) {
23
+ return resolve($promiseOrValue)->then(function ($value) {
24
+ return new RejectedPromise($value);
25
+ });
26
+ }
27
+
28
+ return new RejectedPromise($promiseOrValue);
29
+ }
30
+
31
+ function all($promisesOrValues)
32
+ {
33
+ return map($promisesOrValues, function ($val) {
34
+ return $val;
35
+ });
36
+ }
37
+
38
+ function race($promisesOrValues)
39
+ {
40
+ return resolve($promisesOrValues)
41
+ ->then(function ($array) {
42
+ if (!is_array($array) || !$array) {
43
+ return resolve();
44
+ }
45
+
46
+ return new Promise(function ($resolve, $reject, $notify) use ($array) {
47
+ foreach ($array as $promiseOrValue) {
48
+ resolve($promiseOrValue)
49
+ ->done($resolve, $reject, $notify);
50
+ }
51
+ });
52
+ });
53
+ }
54
+
55
+ function any($promisesOrValues)
56
+ {
57
+ return some($promisesOrValues, 1)
58
+ ->then(function ($val) {
59
+ return array_shift($val);
60
+ });
61
+ }
62
+
63
+ function some($promisesOrValues, $howMany)
64
+ {
65
+ return resolve($promisesOrValues)
66
+ ->then(function ($array) use ($howMany) {
67
+ if (!is_array($array) || !$array || $howMany < 1) {
68
+ return resolve([]);
69
+ }
70
+
71
+ return new Promise(function ($resolve, $reject, $notify) use ($array, $howMany) {
72
+ $len = count($array);
73
+ $toResolve = min($howMany, $len);
74
+ $toReject = ($len - $toResolve) + 1;
75
+ $values = [];
76
+ $reasons = [];
77
+
78
+ foreach ($array as $i => $promiseOrValue) {
79
+ $fulfiller = function ($val) use ($i, &$values, &$toResolve, $toReject, $resolve) {
80
+ if ($toResolve < 1 || $toReject < 1) {
81
+ return;
82
+ }
83
+
84
+ $values[$i] = $val;
85
+
86
+ if (0 === --$toResolve) {
87
+ $resolve($values);
88
+ }
89
+ };
90
+
91
+ $rejecter = function ($reason) use ($i, &$reasons, &$toReject, $toResolve, $reject) {
92
+ if ($toResolve < 1 || $toReject < 1) {
93
+ return;
94
+ }
95
+
96
+ $reasons[$i] = $reason;
97
+
98
+ if (0 === --$toReject) {
99
+ $reject($reasons);
100
+ }
101
+ };
102
+
103
+ resolve($promiseOrValue)
104
+ ->done($fulfiller, $rejecter, $notify);
105
+ }
106
+ });
107
+ });
108
+ }
109
+
110
+ function map($promisesOrValues, callable $mapFunc)
111
+ {
112
+ return resolve($promisesOrValues)
113
+ ->then(function ($array) use ($mapFunc) {
114
+ if (!is_array($array) || !$array) {
115
+ return resolve([]);
116
+ }
117
+
118
+ return new Promise(function ($resolve, $reject, $notify) use ($array, $mapFunc) {
119
+ $toResolve = count($array);
120
+ $values = [];
121
+
122
+ foreach ($array as $i => $promiseOrValue) {
123
+ resolve($promiseOrValue)
124
+ ->then($mapFunc)
125
+ ->done(
126
+ function ($mapped) use ($i, &$values, &$toResolve, $resolve) {
127
+ $values[$i] = $mapped;
128
+
129
+ if (0 === --$toResolve) {
130
+ $resolve($values);
131
+ }
132
+ },
133
+ $reject,
134
+ $notify
135
+ );
136
+ }
137
+ });
138
+ });
139
+ }
140
+
141
+ function reduce($promisesOrValues, callable $reduceFunc , $initialValue = null)
142
+ {
143
+ return resolve($promisesOrValues)
144
+ ->then(function ($array) use ($reduceFunc, $initialValue) {
145
+ if (!is_array($array)) {
146
+ $array = [];
147
+ }
148
+
149
+ $total = count($array);
150
+ $i = 0;
151
+
152
+ // Wrap the supplied $reduceFunc with one that handles promises and then
153
+ // delegates to the supplied.
154
+ $wrappedReduceFunc = function ($current, $val) use ($reduceFunc, $total, &$i) {
155
+ return resolve($current)
156
+ ->then(function ($c) use ($reduceFunc, $total, &$i, $val) {
157
+ return resolve($val)
158
+ ->then(function ($value) use ($reduceFunc, $total, &$i, $c) {
159
+ return $reduceFunc($c, $value, $i++, $total);
160
+ });
161
+ });
162
+ };
163
+
164
+ return array_reduce($array, $wrappedReduceFunc, $initialValue);
165
+ });
166
+ }
167
+
168
+ // Internal functions
169
+ function _checkTypehint(callable $callback, $object)
170
+ {
171
+ if (!is_object($object)) {
172
+ return true;
173
+ }
174
+
175
+ if (is_array($callback)) {
176
+ $callbackReflection = new \ReflectionMethod($callback[0], $callback[1]);
177
+ } elseif (is_object($callback) && !$callback instanceof \Closure) {
178
+ $callbackReflection = new \ReflectionMethod($callback, '__invoke');
179
+ } else {
180
+ $callbackReflection = new \ReflectionFunction($callback);
181
+ }
182
+
183
+ $parameters = $callbackReflection->getParameters();
184
+
185
+ if (!isset($parameters[0])) {
186
+ return true;
187
+ }
188
+
189
+ $expectedException = $parameters[0];
190
+
191
+ if (!$expectedException->getClass()) {
192
+ return true;
193
+ }
194
+
195
+ return $expectedException->getClass()->isInstance($object);
196
+ }
backend/vendor/react/promise/src/functions_include.php ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ <?php
2
+
3
+ if (!function_exists('React\Promise\resolve')) {
4
+ require __DIR__.'/functions.php';
5
+ }
backend/vendor/react/promise/tests/DeferredTest.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace React\Promise;
4
+
5
+ use React\Promise\PromiseAdapter\CallbackPromiseAdapter;
6
+
7
+ class DeferredTest extends TestCase
8
+ {
9
+ use PromiseTest\FullTestTrait;
10
+
11
+ public function getPromiseTestAdapter(callable $canceller = null)
12
+ {
13
+ $d = new Deferred($canceller);
14
+
15
+ return new CallbackPromiseAdapter([
16
+ 'promise' => [$d, 'promise'],
17
+ 'resolve' => [$d, 'resolve'],
18
+ 'reject' => [$d, 'reject'],
19
+ 'notify' => [$d, 'progress'],
20
+ 'settle' => [$d, 'resolve'],
21
+ ]);
22
+ }
23
+
24
+ /** @test */
25
+ public function progressIsAnAliasForNotify()
26
+ {
27
+ $deferred = new Deferred();
28
+
29
+ $sentinel = new \stdClass();
30
+
31
+ $mock = $this->createCallableMock();
32
+ $mock
33
+ ->expects($this->once())
34
+ ->method('__invoke')
35
+ ->with($sentinel);
36
+
37
+ $deferred->promise()
38
+ ->then($this->expectCallableNever(), $this->expectCallableNever(), $mock);
39
+
40
+ $deferred->progress($sentinel);
41
+ }
42
+ }
backend/vendor/react/promise/tests/FulfilledPromiseTest.php ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace React\Promise;
4
+
5
+ use React\Promise\PromiseAdapter\CallbackPromiseAdapter;
6
+
7
+ class FulfilledPromiseTest extends TestCase
8
+ {
9
+ use PromiseTest\PromiseSettledTestTrait,
10
+ PromiseTest\PromiseFulfilledTestTrait;
11
+
12
+ public function getPromiseTestAdapter(callable $canceller = null)
13
+ {
14
+ $promise = null;
15
+
16
+ return new CallbackPromiseAdapter([
17
+ 'promise' => function () use (&$promise) {
18
+ if (!$promise) {
19
+ throw new \LogicException('FulfilledPromise must be resolved before obtaining the promise');
20
+ }
21
+
22
+ return $promise;
23
+ },
24
+ 'resolve' => function ($value = null) use (&$promise) {
25
+ if (!$promise) {
26
+ $promise = new FulfilledPromise($value);
27
+ }
28
+ },
29
+ 'reject' => function () {
30
+ throw new \LogicException('You cannot call reject() for React\Promise\FulfilledPromise');
31
+ },
32
+ 'notify' => function () {
33
+ // no-op
34
+ },
35
+ 'settle' => function ($value = null) use (&$promise) {
36
+ if (!$promise) {
37
+ $promise = new FulfilledPromise($value);
38
+ }
39
+ },
40
+ ]);
41
+ }
42
+
43
+ /** @test */
44
+ public function shouldThrowExceptionIfConstructedWithAPromise()
45
+ {
46
+ $this->setExpectedException('\InvalidArgumentException');
47
+
48
+ return new FulfilledPromise(new FulfilledPromise());
49
+ }
50
+ }
backend/vendor/react/promise/tests/FunctionAllTest.php ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace React\Promise;
4
+
5
+ class FunctionAllTest extends TestCase
6
+ {
7
+ /** @test */
8
+ public function shouldResolveEmptyInput()
9
+ {
10
+ $mock = $this->createCallableMock();
11
+ $mock
12
+ ->expects($this->once())
13
+ ->method('__invoke')
14
+ ->with($this->identicalTo([]));
15
+
16
+ all([])
17
+ ->then($mock);
18
+ }
19
+
20
+ /** @test */
21
+ public function shouldResolveValuesArray()
22
+ {
23
+ $mock = $this->createCallableMock();
24
+ $mock
25
+ ->expects($this->once())
26
+ ->method('__invoke')
27
+ ->with($this->identicalTo([1, 2, 3]));
28
+
29
+ all([1, 2, 3])
30
+ ->then($mock);
31
+ }
32
+
33
+ /** @test */
34
+ public function shouldResolvePromisesArray()
35
+ {
36
+ $mock = $this->createCallableMock();
37
+ $mock
38
+ ->expects($this->once())
39
+ ->method('__invoke')
40
+ ->with($this->identicalTo([1, 2, 3]));
41
+
42
+ all([resolve(1), resolve(2), resolve(3)])
43
+ ->then($mock);
44
+ }
45
+
46
+ /** @test */
47
+ public function shouldResolveSparseArrayInput()
48
+ {
49
+ $mock = $this->createCallableMock();
50
+ $mock
51
+ ->expects($this->once())
52
+ ->method('__invoke')
53
+ ->with($this->identicalTo([null, 1, null, 1, 1]));
54
+
55
+ all([null, 1, null, 1, 1])
56
+ ->then($mock);
57
+ }
58
+
59
+ /** @test */
60
+ public function shouldRejectIfAnyInputPromiseRejects()
61
+ {
62
+ $mock = $this->createCallableMock();
63
+ $mock
64
+ ->expects($this->once())
65
+ ->method('__invoke')
66
+ ->with($this->identicalTo(2));
67
+
68
+ all([resolve(1), reject(2), resolve(3)])
69
+ ->then($this->expectCallableNever(), $mock);
70
+ }
71
+
72
+ /** @test */
73
+ public function shouldAcceptAPromiseForAnArray()
74
+ {
75
+ $mock = $this->createCallableMock();
76
+ $mock
77
+ ->expects($this->once())
78
+ ->method('__invoke')
79
+ ->with($this->identicalTo([1, 2, 3]));
80
+
81
+ all(resolve([1, 2, 3]))
82
+ ->then($mock);
83
+ }
84
+
85
+ /** @test */
86
+ public function shouldResolveToEmptyArrayWhenInputPromiseDoesNotResolveToArray()
87
+ {
88
+ $mock = $this->createCallableMock();
89
+ $mock
90
+ ->expects($this->once())
91
+ ->method('__invoke')
92
+ ->with($this->identicalTo([]));
93
+
94
+ all(resolve(1))
95
+ ->then($mock);
96
+ }
97
+ }
backend/vendor/react/promise/tests/FunctionAnyTest.php ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace React\Promise;
4
+
5
+ class FunctionAnyTest extends TestCase
6
+ {
7
+ /** @test */
8
+ public function shouldResolveToNullWithEmptyInputArray()
9
+ {
10
+ $mock = $this->createCallableMock();
11
+ $mock
12
+ ->expects($this->once())
13
+ ->method('__invoke')
14
+ ->with($this->identicalTo(null));
15
+
16
+ any([])
17
+ ->then($mock);
18
+ }
19
+
20
+ /** @test */
21
+ public function shouldResolveWithAnInputValue()
22
+ {
23
+ $mock = $this->createCallableMock();
24
+ $mock
25
+ ->expects($this->once())
26
+ ->method('__invoke')
27
+ ->with($this->identicalTo(1));
28
+
29
+ any([1, 2, 3])
30
+ ->then($mock);
31
+ }
32
+
33
+ /** @test */
34
+ public function shouldResolveWithAPromisedInputValue()
35
+ {
36
+ $mock = $this->createCallableMock();
37
+ $mock
38
+ ->expects($this->once())
39
+ ->method('__invoke')
40
+ ->with($this->identicalTo(1));
41
+
42
+ any([resolve(1), resolve(2), resolve(3)])
43
+ ->then($mock);
44
+ }
45
+
46
+ /** @test */
47
+ public function shouldRejectWithAllRejectedInputValuesIfAllInputsAreRejected()
48
+ {
49
+ $mock = $this->createCallableMock();
50
+ $mock
51
+ ->expects($this->once())
52
+ ->method('__invoke')
53
+ ->with($this->identicalTo([0 => 1, 1 => 2, 2 => 3]));
54
+
55
+ any([reject(1), reject(2), reject(3)])
56
+ ->then($this->expectCallableNever(), $mock);
57
+ }
58
+
59
+ /** @test */
60
+ public function shouldResolveWhenFirstInputPromiseResolves()
61
+ {
62
+ $mock = $this->createCallableMock();
63
+ $mock
64
+ ->expects($this->once())
65
+ ->method('__invoke')
66
+ ->with($this->identicalTo(1));
67
+
68
+ any([resolve(1), reject(2), reject(3)])
69
+ ->then($mock);
70
+ }
71
+
72
+ /** @test */
73
+ public function shouldAcceptAPromiseForAnArray()
74
+ {
75
+ $mock = $this->createCallableMock();
76
+ $mock
77
+ ->expects($this->once())
78
+ ->method('__invoke')
79
+ ->with($this->identicalTo(1));
80
+
81
+ any(resolve([1, 2, 3]))
82
+ ->then($mock);
83
+ }
84
+
85
+ /** @test */
86
+ public function shouldResolveToNullArrayWhenInputPromiseDoesNotResolveToArray()
87
+ {
88
+ $mock = $this->createCallableMock();
89
+ $mock
90
+ ->expects($this->once())
91
+ ->method('__invoke')
92
+ ->with($this->identicalTo(null));
93
+
94
+ any(resolve(1))
95
+ ->then($mock);
96
+ }
97
+
98
+ /** @test */
99
+ public function shouldNotRelyOnArryIndexesWhenUnwrappingToASingleResolutionValue()
100
+ {
101
+ $mock = $this->createCallableMock();
102
+ $mock
103
+ ->expects($this->once())
104
+ ->method('__invoke')
105
+ ->with($this->identicalTo(2));
106
+
107
+ $d1 = new Deferred();
108
+ $d2 = new Deferred();
109
+
110
+ any(['abc' => $d1->promise(), 1 => $d2->promise()])
111
+ ->then($mock);
112
+
113
+ $d2->resolve(2);
114
+ $d1->resolve(1);
115
+ }
116
+ }
backend/vendor/react/promise/tests/FunctionCheckTypehintTest.php ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace React\Promise;
4
+
5
+ class FunctionCheckTypehintTest extends TestCase
6
+ {
7
+ /** @test */
8
+ public function shouldAcceptClosureCallbackWithTypehint()
9
+ {
10
+ $this->assertTrue(_checkTypehint(function (\InvalidArgumentException $e) {
11
+ }, new \InvalidArgumentException()));
12
+ $this->assertfalse(_checkTypehint(function (\InvalidArgumentException $e) {
13
+ }, new \Exception()));
14
+ }
15
+
16
+ /** @test */
17
+ public function shouldAcceptFunctionStringCallbackWithTypehint()
18
+ {
19
+ $this->assertTrue(_checkTypehint('React\Promise\testCallbackWithTypehint', new \InvalidArgumentException()));
20
+ $this->assertfalse(_checkTypehint('React\Promise\testCallbackWithTypehint', new \Exception()));
21
+ }
22
+
23
+ /** @test */
24
+ public function shouldAcceptInvokableObjectCallbackWithTypehint()
25
+ {
26
+ $this->assertTrue(_checkTypehint(new TestCallbackWithTypehintClass(), new \InvalidArgumentException()));
27
+ $this->assertfalse(_checkTypehint(new TestCallbackWithTypehintClass(), new \Exception()));
28
+ }
29
+
30
+ /** @test */
31
+ public function shouldAcceptObjectMethodCallbackWithTypehint()
32
+ {
33
+ $this->assertTrue(_checkTypehint([new TestCallbackWithTypehintClass(), 'testCallback'], new \InvalidArgumentException()));
34
+ $this->assertfalse(_checkTypehint([new TestCallbackWithTypehintClass(), 'testCallback'], new \Exception()));
35
+ }
36
+
37
+ /** @test */
38
+ public function shouldAcceptStaticClassCallbackWithTypehint()
39
+ {
40
+ $this->assertTrue(_checkTypehint(['React\Promise\TestCallbackWithTypehintClass', 'testCallbackStatic'], new \InvalidArgumentException()));
41
+ $this->assertfalse(_checkTypehint(['React\Promise\TestCallbackWithTypehintClass', 'testCallbackStatic'], new \Exception()));
42
+ }
43
+
44
+ /** @test */
45
+ public function shouldAcceptClosureCallbackWithoutTypehint()
46
+ {
47
+ $this->assertTrue(_checkTypehint(function (\InvalidArgumentException $e) {
48
+ }, new \InvalidArgumentException()));
49
+ }
50
+
51
+ /** @test */
52
+ public function shouldAcceptFunctionStringCallbackWithoutTypehint()
53
+ {
54
+ $this->assertTrue(_checkTypehint('React\Promise\testCallbackWithoutTypehint', new \InvalidArgumentException()));
55
+ }
56
+
57
+ /** @test */
58
+ public function shouldAcceptInvokableObjectCallbackWithoutTypehint()
59
+ {
60
+ $this->assertTrue(_checkTypehint(new TestCallbackWithoutTypehintClass(), new \InvalidArgumentException()));
61
+ }
62
+
63
+ /** @test */
64
+ public function shouldAcceptObjectMethodCallbackWithoutTypehint()
65
+ {
66
+ $this->assertTrue(_checkTypehint([new TestCallbackWithoutTypehintClass(), 'testCallback'], new \InvalidArgumentException()));
67
+ }
68
+
69
+ /** @test */
70
+ public function shouldAcceptStaticClassCallbackWithoutTypehint()
71
+ {
72
+ $this->assertTrue(_checkTypehint(['React\Promise\TestCallbackWithoutTypehintClass', 'testCallbackStatic'], new \InvalidArgumentException()));
73
+ }
74
+ }
75
+
76
+ function testCallbackWithTypehint(\InvalidArgumentException $e)
77
+ {
78
+ }
79
+
80
+ function testCallbackWithoutTypehint()
81
+ {
82
+ }
83
+
84
+ class TestCallbackWithTypehintClass
85
+ {
86
+ public function __invoke(\InvalidArgumentException $e)
87
+ {
88
+
89
+ }
90
+
91
+ public function testCallback(\InvalidArgumentException $e)
92
+ {
93
+
94
+ }
95
+
96
+ public static function testCallbackStatic(\InvalidArgumentException $e)
97
+ {
98
+
99
+ }
100
+ }
101
+
102
+ class TestCallbackWithoutTypehintClass
103
+ {
104
+ public function __invoke()
105
+ {
106
+
107
+ }
108
+
109
+ public function testCallback()
110
+ {
111
+
112
+ }
113
+
114
+ public static function testCallbackStatic()
115
+ {
116
+
117
+ }
118
+ }
backend/vendor/react/promise/tests/FunctionMapTest.php ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace React\Promise;
4
+
5
+ class FunctionMapTest extends TestCase
6
+ {
7
+ protected function mapper()
8
+ {
9
+ return function ($val) {
10
+ return $val * 2;
11
+ };
12
+ }
13
+
14
+ protected function promiseMapper()
15
+ {
16
+ return function ($val) {
17
+ return resolve($val * 2);
18
+ };
19
+ }
20
+
21
+ /** @test */
22
+ public function shouldMapInputValuesArray()
23
+ {
24
+ $mock = $this->createCallableMock();
25
+ $mock
26
+ ->expects($this->once())
27
+ ->method('__invoke')
28
+ ->with($this->identicalTo([2, 4, 6]));
29
+
30
+ map(
31
+ [1, 2, 3],
32
+ $this->mapper()
33
+ )->then($mock);
34
+ }
35
+
36
+ /** @test */
37
+ public function shouldMapInputPromisesArray()
38
+ {
39
+ $mock = $this->createCallableMock();
40
+ $mock
41
+ ->expects($this->once())
42
+ ->method('__invoke')
43
+ ->with($this->identicalTo([2, 4, 6]));
44
+
45
+ map(
46
+ [resolve(1), resolve(2), resolve(3)],
47
+ $this->mapper()
48
+ )->then($mock);
49
+ }
50
+
51
+ /** @test */
52
+ public function shouldMapMixedInputArray()
53
+ {
54
+ $mock = $this->createCallableMock();
55
+ $mock
56
+ ->expects($this->once())
57
+ ->method('__invoke')
58
+ ->with($this->identicalTo([2, 4, 6]));
59
+
60
+ map(
61
+ [1, resolve(2), 3],
62
+ $this->mapper()
63
+ )->then($mock);
64
+ }
65
+
66
+ /** @test */
67
+ public function shouldMapInputWhenMapperReturnsAPromise()
68
+ {
69
+ $mock = $this->createCallableMock();
70
+ $mock
71
+ ->expects($this->once())
72
+ ->method('__invoke')
73
+ ->with($this->identicalTo([2, 4, 6]));
74
+
75
+ map(
76
+ [1, 2, 3],
77
+ $this->promiseMapper()
78
+ )->then($mock);
79
+ }
80
+
81
+ /** @test */
82
+ public function shouldAcceptAPromiseForAnArray()
83
+ {
84
+ $mock = $this->createCallableMock();
85
+ $mock
86
+ ->expects($this->once())
87
+ ->method('__invoke')
88
+ ->with($this->identicalTo([2, 4, 6]));
89
+
90
+ map(
91
+ resolve([1, resolve(2), 3]),
92
+ $this->mapper()
93
+ )->then($mock);
94
+ }
95
+
96
+ /** @test */
97
+ public function shouldResolveToEmptyArrayWhenInputPromiseDoesNotResolveToArray()
98
+ {
99
+ $mock = $this->createCallableMock();
100
+ $mock
101
+ ->expects($this->once())
102
+ ->method('__invoke')
103
+ ->with($this->identicalTo([]));
104
+
105
+ map(
106
+ resolve(1),
107
+ $this->mapper()
108
+ )->then($mock);
109
+ }
110
+
111
+ /** @test */
112
+ public function shouldRejectWhenInputContainsRejection()
113
+ {
114
+ $mock = $this->createCallableMock();
115
+ $mock
116
+ ->expects($this->once())
117
+ ->method('__invoke')
118
+ ->with($this->identicalTo(2));
119
+
120
+ map(
121
+ [resolve(1), reject(2), resolve(3)],
122
+ $this->mapper()
123
+ )->then($this->expectCallableNever(), $mock);
124
+ }
125
+ }
backend/vendor/react/promise/tests/FunctionRaceTest.php ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace React\Promise;
4
+
5
+ class FunctionRaceTest extends TestCase
6
+ {
7
+ /** @test */
8
+ public function shouldResolveEmptyInput()
9
+ {
10
+ $mock = $this->createCallableMock();
11
+ $mock
12
+ ->expects($this->once())
13
+ ->method('__invoke')
14
+ ->with($this->identicalTo(null));
15
+
16
+ race(
17
+ []
18
+ )->then($mock);
19
+ }
20
+
21
+ /** @test */
22
+ public function shouldResolveValuesArray()
23
+ {
24
+ $mock = $this->createCallableMock();
25
+ $mock
26
+ ->expects($this->once())
27
+ ->method('__invoke')
28
+ ->with($this->identicalTo(1));
29
+
30
+ race(
31
+ [1, 2, 3]
32
+ )->then($mock);
33
+ }
34
+
35
+ /** @test */
36
+ public function shouldResolvePromisesArray()
37
+ {
38
+ $mock = $this->createCallableMock();
39
+ $mock
40
+ ->expects($this->once())
41
+ ->method('__invoke')
42
+ ->with($this->identicalTo(2));
43
+
44
+ $d1 = new Deferred();
45
+ $d2 = new Deferred();
46
+ $d3 = new Deferred();
47
+
48
+ race(
49
+ [$d1->promise(), $d2->promise(), $d3->promise()]
50
+ )->then($mock);
51
+
52
+ $d2->resolve(2);
53
+
54
+ $d1->resolve(1);
55
+ $d3->resolve(3);
56
+ }
57
+
58
+ /** @test */
59
+ public function shouldResolveSparseArrayInput()
60
+ {
61
+ $mock = $this->createCallableMock();
62
+ $mock
63
+ ->expects($this->once())
64
+ ->method('__invoke')
65
+ ->with($this->identicalTo(null));
66
+
67
+ race(
68
+ [null, 1, null, 2, 3]
69
+ )->then($mock);
70
+ }
71
+
72
+ /** @test */
73
+ public function shouldRejectIfFirstSettledPromiseRejects()
74
+ {
75
+ $mock = $this->createCallableMock();
76
+ $mock
77
+ ->expects($this->once())
78
+ ->method('__invoke')
79
+ ->with($this->identicalTo(2));
80
+
81
+ $d1 = new Deferred();
82
+ $d2 = new Deferred();
83
+ $d3 = new Deferred();
84
+
85
+ race(
86
+ [$d1->promise(), $d2->promise(), $d3->promise()]
87
+ )->then($this->expectCallableNever(), $mock);
88
+
89
+ $d2->reject(2);
90
+
91
+ $d1->resolve(1);
92
+ $d3->resolve(3);
93
+ }
94
+
95
+ /** @test */
96
+ public function shouldAcceptAPromiseForAnArray()
97
+ {
98
+ $mock = $this->createCallableMock();
99
+ $mock
100
+ ->expects($this->once())
101
+ ->method('__invoke')
102
+ ->with($this->identicalTo(1));
103
+
104
+ race(
105
+ resolve([1, 2, 3])
106
+ )->then($mock);
107
+ }
108
+
109
+ /** @test */
110
+ public function shouldResolveToNullWhenInputPromiseDoesNotResolveToArray()
111
+ {
112
+ $mock = $this->createCallableMock();
113
+ $mock
114
+ ->expects($this->once())
115
+ ->method('__invoke')
116
+ ->with($this->identicalTo(null));
117
+
118
+ race(
119
+ resolve(1)
120
+ )->then($mock);
121
+ }
122
+ }
backend/vendor/react/promise/tests/FunctionReduceTest.php ADDED
File without changes