Revive Old Posts – Auto Post to Social Media - Version 8.2.5

Version Description

  • 2019-05-17
Download this release

Release Info

Developer codeinwp
Plugin Icon 128x128 Revive Old Posts – Auto Post to Social Media
Version 8.2.5
Comparing to
See all releases

Code changes from version 8.2.4 to 8.2.5

Files changed (118) hide show
  1. CHANGELOG.md +11 -0
  2. includes/admin/abstract/class-rop-services-abstract.php +90 -0
  3. includes/admin/class-rop-admin.php +46 -0
  4. includes/admin/class-rop-global-settings.php +1 -1
  5. includes/admin/helpers/class-rop-post-format-helper.php +11 -0
  6. includes/admin/models/class-rop-posts-selector-model.php +0 -24
  7. includes/admin/services/class-rop-linkedin-service.php +16 -8
  8. includes/admin/services/class-rop-pinterest-service.php +4 -1
  9. includes/admin/services/class-rop-twitter-service.php +0 -90
  10. includes/class-rop.php +3 -1
  11. readme.md +9 -1
  12. readme.txt +9 -1
  13. themeisle-hash.json +1 -1
  14. tweet-old-post.php +3 -3
  15. vendor/autoload.php +1 -1
  16. vendor/composer/autoload_files.php +4 -0
  17. vendor/composer/autoload_psr4.php +4 -0
  18. vendor/composer/autoload_real.php +5 -5
  19. vendor/composer/installed.json +283 -0
  20. vendor/guzzlehttp/guzzle/CHANGELOG.md +1287 -0
  21. vendor/guzzlehttp/guzzle/LICENSE +19 -0
  22. vendor/guzzlehttp/guzzle/README.md +91 -0
  23. vendor/guzzlehttp/guzzle/UPGRADING.md +1203 -0
  24. vendor/guzzlehttp/guzzle/src/Client.php +422 -0
  25. vendor/guzzlehttp/guzzle/src/ClientInterface.php +84 -0
  26. vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php +314 -0
  27. vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php +84 -0
  28. vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php +90 -0
  29. vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php +71 -0
  30. vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php +403 -0
  31. vendor/guzzlehttp/guzzle/src/Exception/BadResponseException.php +27 -0
  32. vendor/guzzlehttp/guzzle/src/Exception/ClientException.php +7 -0
  33. vendor/guzzlehttp/guzzle/src/Exception/ConnectException.php +37 -0
  34. vendor/guzzlehttp/guzzle/src/Exception/GuzzleException.php +13 -0
  35. vendor/guzzlehttp/guzzle/src/Exception/RequestException.php +217 -0
  36. vendor/guzzlehttp/guzzle/src/Exception/SeekException.php +27 -0
  37. vendor/guzzlehttp/guzzle/src/Exception/ServerException.php +7 -0
  38. vendor/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php +4 -0
  39. vendor/guzzlehttp/guzzle/src/Exception/TransferException.php +4 -0
  40. vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php +565 -0
  41. vendor/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php +27 -0
  42. vendor/guzzlehttp/guzzle/src/Handler/CurlHandler.php +45 -0
  43. vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php +199 -0
  44. vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.php +92 -0
  45. vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php +189 -0
  46. vendor/guzzlehttp/guzzle/src/Handler/Proxy.php +55 -0
  47. vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php +532 -0
  48. vendor/guzzlehttp/guzzle/src/HandlerStack.php +273 -0
  49. vendor/guzzlehttp/guzzle/src/MessageFormatter.php +180 -0
  50. vendor/guzzlehttp/guzzle/src/Middleware.php +255 -0
  51. vendor/guzzlehttp/guzzle/src/Pool.php +123 -0
  52. vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php +106 -0
  53. vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php +237 -0
  54. vendor/guzzlehttp/guzzle/src/RequestOptions.php +255 -0
  55. vendor/guzzlehttp/guzzle/src/RetryMiddleware.php +112 -0
  56. vendor/guzzlehttp/guzzle/src/TransferStats.php +126 -0
  57. vendor/guzzlehttp/guzzle/src/UriTemplate.php +237 -0
  58. vendor/guzzlehttp/guzzle/src/functions.php +333 -0
  59. vendor/guzzlehttp/guzzle/src/functions_include.php +6 -0
  60. vendor/guzzlehttp/promises/CHANGELOG.md +65 -0
  61. vendor/guzzlehttp/promises/LICENSE +19 -0
  62. vendor/guzzlehttp/promises/Makefile +13 -0
  63. vendor/guzzlehttp/promises/README.md +504 -0
  64. vendor/guzzlehttp/promises/src/AggregateException.php +16 -0
  65. vendor/guzzlehttp/promises/src/CancellationException.php +9 -0
  66. vendor/guzzlehttp/promises/src/Coroutine.php +151 -0
  67. vendor/guzzlehttp/promises/src/EachPromise.php +229 -0
  68. vendor/guzzlehttp/promises/src/FulfilledPromise.php +82 -0
  69. vendor/guzzlehttp/promises/src/Promise.php +280 -0
  70. vendor/guzzlehttp/promises/src/PromiseInterface.php +93 -0
  71. vendor/guzzlehttp/promises/src/PromisorInterface.php +15 -0
  72. vendor/guzzlehttp/promises/src/RejectedPromise.php +87 -0
  73. vendor/guzzlehttp/promises/src/RejectionException.php +47 -0
  74. vendor/guzzlehttp/promises/src/TaskQueue.php +66 -0
  75. vendor/guzzlehttp/promises/src/TaskQueueInterface.php +25 -0
  76. vendor/guzzlehttp/promises/src/functions.php +457 -0
  77. vendor/guzzlehttp/promises/src/functions_include.php +6 -0
  78. vendor/guzzlehttp/psr7/CHANGELOG.md +225 -0
  79. vendor/guzzlehttp/psr7/LICENSE +19 -0
  80. vendor/guzzlehttp/psr7/README.md +745 -0
  81. vendor/guzzlehttp/psr7/src/AppendStream.php +241 -0
  82. vendor/guzzlehttp/psr7/src/BufferStream.php +137 -0
  83. vendor/guzzlehttp/psr7/src/CachingStream.php +138 -0
  84. vendor/guzzlehttp/psr7/src/DroppingStream.php +42 -0
  85. vendor/guzzlehttp/psr7/src/FnStream.php +158 -0
  86. vendor/guzzlehttp/psr7/src/InflateStream.php +52 -0
  87. vendor/guzzlehttp/psr7/src/LazyOpenStream.php +39 -0
  88. vendor/guzzlehttp/psr7/src/LimitStream.php +155 -0
  89. vendor/guzzlehttp/psr7/src/MessageTrait.php +183 -0
  90. vendor/guzzlehttp/psr7/src/MultipartStream.php +153 -0
  91. vendor/guzzlehttp/psr7/src/NoSeekStream.php +22 -0
  92. vendor/guzzlehttp/psr7/src/PumpStream.php +165 -0
  93. vendor/guzzlehttp/psr7/src/Request.php +142 -0
  94. vendor/guzzlehttp/psr7/src/Response.php +136 -0
  95. vendor/guzzlehttp/psr7/src/Rfc7230.php +18 -0
  96. vendor/guzzlehttp/psr7/src/ServerRequest.php +376 -0
  97. vendor/guzzlehttp/psr7/src/Stream.php +270 -0
  98. vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php +149 -0
  99. vendor/guzzlehttp/psr7/src/StreamWrapper.php +161 -0
  100. vendor/guzzlehttp/psr7/src/UploadedFile.php +316 -0
  101. vendor/guzzlehttp/psr7/src/Uri.php +738 -0
  102. vendor/guzzlehttp/psr7/src/UriNormalizer.php +216 -0
  103. vendor/guzzlehttp/psr7/src/UriResolver.php +219 -0
  104. vendor/guzzlehttp/psr7/src/functions.php +898 -0
  105. vendor/guzzlehttp/psr7/src/functions_include.php +6 -0
  106. vendor/psr/http-message/CHANGELOG.md +36 -0
  107. vendor/psr/http-message/LICENSE +19 -0
  108. vendor/psr/http-message/README.md +13 -0
  109. vendor/psr/http-message/src/MessageInterface.php +187 -0
  110. vendor/psr/http-message/src/RequestInterface.php +129 -0
  111. vendor/psr/http-message/src/ResponseInterface.php +68 -0
  112. vendor/psr/http-message/src/ServerRequestInterface.php +261 -0
  113. vendor/psr/http-message/src/StreamInterface.php +158 -0
  114. vendor/psr/http-message/src/UploadedFileInterface.php +123 -0
  115. vendor/psr/http-message/src/UriInterface.php +323 -0
  116. vendor/ralouphie/getallheaders/LICENSE +21 -0
  117. vendor/ralouphie/getallheaders/README.md +19 -0
  118. vendor/ralouphie/getallheaders/src/getallheaders.php +46 -0
CHANGELOG.md CHANGED
@@ -1,4 +1,15 @@
1
 
 
 
 
 
 
 
 
 
 
 
 
2
  ### v8.2.4 - 2019-04-15
3
  **Changes:**
4
  * Fix: Minor bugs
1
 
2
+ ### v8.2.5 - 2019-05-17
3
+ **Changes:**
4
+ * update tested up to
5
+
6
+ ### v8.2.5 - 2019-05-17
7
+ **Changes:**
8
+ * New: Show admin notice when WP Cron is turned off, which can cause posting issues with ROP
9
+ * Fix: LinkedIn Image posts were not going through
10
+ * Fix: Posting to some Pinterest boards with special characters was not working
11
+ * Info: Tested on WP 5.2
12
+
13
  ### v8.2.4 - 2019-04-15
14
  **Changes:**
15
  * Fix: Minor bugs
includes/admin/abstract/class-rop-services-abstract.php CHANGED
@@ -510,5 +510,95 @@ abstract class Rop_Services_Abstract {
510
 
511
  }
512
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
513
 
514
  }
510
 
511
  }
512
 
513
+ /**
514
+ * Get Image file path if exists, return default image_url if not.
515
+ *
516
+ * Used where file_get_contents might not work with urls, we provide the file path.
517
+ *
518
+ * @param string $image_url Image url.
519
+ *
520
+ * @return string Image path.
521
+ */
522
+ protected function get_path_by_url( $image_url, $mimetype ) {
523
+
524
+ $dir = wp_upload_dir();
525
+
526
+ $parsed = parse_url( $dir['baseurl'] );
527
+
528
+ $dir = $parsed['host'] . $parsed['path'];
529
+
530
+ if ( false === strpos( $image_url, $dir ) ) {
531
+ return $image_url;
532
+ }
533
+
534
+ $file = basename( $image_url );
535
+ $query = array(
536
+ 'post_type' => 'attachment',
537
+ 'fields' => 'ids',
538
+ 'posts_per_page' => '20',
539
+ 'no_found_rows' => true,
540
+ 'meta_query' => array(
541
+ array(
542
+ 'key' => '_wp_attached_file',
543
+ 'value' => $file,
544
+ 'compare' => 'LIKE',
545
+ ),
546
+ ),
547
+ );
548
+ $ids = get_posts( $query );
549
+ $id_found = false;
550
+ if ( strpos( $mimetype['type'], 'video' ) !== false ) {
551
+ if ( empty( $ids ) ) {
552
+ return $image_url;
553
+ }
554
+
555
+ return get_attached_file( reset( $ids ) );
556
+ }
557
+ if ( ! empty( $ids ) ) {
558
+
559
+ foreach ( $ids as $id ) {
560
+ if ( $image_url === array_shift( wp_get_attachment_image_src( $id, 'full' ) ) ) {
561
+ $id_found = $id;
562
+ break;
563
+ }
564
+ }
565
+ }
566
+ if ( $id_found === false ) {
567
+ $query['meta_query'][0]['key'] = '_wp_attachment_metadata';
568
+
569
+ // query attachments again
570
+ $ids = get_posts( $query );
571
+
572
+ if ( empty( $ids ) ) {
573
+ return $image_url;
574
+ }
575
+
576
+ foreach ( $ids as $id ) {
577
+
578
+ $meta = wp_get_attachment_metadata( $id );
579
+
580
+ foreach ( $meta['sizes'] as $size => $values ) {
581
+
582
+ if ( $values['file'] === $file && $image_url === array_shift( wp_get_attachment_image_src( $id, $size ) ) ) {
583
+ $id_found = $id;
584
+ break;
585
+ }
586
+ }
587
+ if ( $id_found === false ) {
588
+ break;
589
+ }
590
+ }
591
+ }
592
+ if ( $id_found === false ) {
593
+ return $image_url;
594
+ }
595
+ $path = get_attached_file( $id_found );
596
+ if ( empty( $path ) ) {
597
+ return $image_url;
598
+ }
599
+
600
+ return $path;
601
+ }
602
+
603
 
604
  }
includes/admin/class-rop-admin.php CHANGED
@@ -729,4 +729,50 @@ class Rop_Admin {
729
 
730
  }
731
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
732
  }
729
 
730
  }
731
 
732
+ /**
733
+ * WordPress Cron disabled notice.
734
+ *
735
+ * @since 8.2.5
736
+ * @access public
737
+ */
738
+ public function rop_wp_cron_notice() {
739
+
740
+ if ( ! defined( 'DISABLE_WP_CRON' ) ) {
741
+ return;
742
+ }
743
+
744
+ $user_id = get_current_user_id();
745
+
746
+ if ( get_user_meta( $user_id, 'rop-wp-cron-notice-dismissed' ) ) {
747
+ return;
748
+ }
749
+
750
+ if ( DISABLE_WP_CRON == true ) {
751
+
752
+ ?>
753
+ <div class="notice notice-error">
754
+ <?php echo sprintf( __( '%1$s%2$sRevive Old Posts:%3$s The WordPress Cron seems is disabled on your website. This can cause sharing issues with Revive Old Posts. If sharing is not working, then see %4$shere for solutions.%5$s%6$s%7$s', 'tweet-old-post' ), '<p>', '<b>', '</b>', '<a href="https://docs.revive.social/article/686-fix-revive-old-post-not-posting" target="_blank">', '</a>', '<a style="float: right;" href="?rop-wp-cron-notice-dismissed">Dismiss</a>', '</p>' ); ?>
755
+
756
+ </div>
757
+ <?php
758
+
759
+ }
760
+
761
+ }
762
+
763
+ /**
764
+ * Show WordPress Cron disabled notice.
765
+ *
766
+ * @since 8.2.5
767
+ * @access public
768
+ */
769
+ public function rop_show_cron_disabled_notice() {
770
+
771
+ $user_id = get_current_user_id();
772
+ if ( isset( $_GET['rop-wp-cron-notice-dismissed'] ) ) {
773
+ add_user_meta( $user_id, 'rop-wp-cron-notice-dismissed', 'true', true );
774
+ }
775
+
776
+ }
777
+
778
  }
includes/admin/class-rop-global-settings.php CHANGED
@@ -191,7 +191,7 @@ class Rop_Global_Settings {
191
  'short_url' => true,
192
  'short_url_service' => 'is.gd',
193
  'hashtags' => 'no-hashtags',
194
- 'hashtags_length' => '10',
195
  'hashtags_common' => '',
196
  'shortner_credentials' => array(),
197
  'hashtags_custom' => '',
191
  'short_url' => true,
192
  'short_url_service' => 'is.gd',
193
  'hashtags' => 'no-hashtags',
194
+ 'hashtags_length' => '20',
195
  'hashtags_common' => '',
196
  'shortner_credentials' => array(),
197
  'hashtags_custom' => '',
includes/admin/helpers/class-rop-post-format-helper.php CHANGED
@@ -725,6 +725,17 @@ class Rop_Post_Format_Helper {
725
  }
726
  }
727
 
 
 
 
 
 
 
 
 
 
 
 
728
  $post_url = apply_filters( 'rop_raw_post_url', $post_url, $post_id );
729
  $global_settings = new Rop_Global_Settings();
730
  $settings_model = new Rop_Settings_Model();
725
  }
726
  }
727
 
728
+ if ( get_post_type( $post_id ) === 'attachment' ) {
729
+
730
+ $parent_id = wp_get_post_parent_id( $post_id );
731
+ // If attachment was not uploaded to a post set the URL as site homepage
732
+ if ( empty( $parent_id ) ) {
733
+ $post_url = apply_filters( 'rop_attachment_no_parent', get_site_url(), $post_id );
734
+ } else {
735
+ $post_url = get_permalink( $parent_id );
736
+ }
737
+ }
738
+
739
  $post_url = apply_filters( 'rop_raw_post_url', $post_url, $post_id );
740
  $global_settings = new Rop_Global_Settings();
741
  $settings_model = new Rop_Settings_Model();
includes/admin/models/class-rop-posts-selector-model.php CHANGED
@@ -61,30 +61,6 @@ class Rop_Posts_Selector_Model extends Rop_Model_Abstract {
61
  $this->settings = new Rop_Settings_Model();
62
  $this->buffer = wp_parse_args( $this->get( 'posts_buffer' ), $this->buffer );
63
  $this->blocked = wp_parse_args( $this->get( 'posts_blocked' ), $this->blocked );
64
- add_filter( 'rop_raw_post_url', [ $this, 'alter_attachment_url' ], 10, 2 );
65
- }
66
-
67
- /**
68
- * Alter attachment post url and send attached post urls.
69
- *
70
- * @param string $post_url Original post url.
71
- * @param int $post_id Post id.
72
- *
73
- * @return string New post url.
74
- */
75
- public function alter_attachment_url( $post_url, $post_id ) {
76
- $post_types = $this->settings->get_selected_post_types();
77
- $post_types = wp_list_pluck( $post_types, 'value' );
78
- if ( ! in_array( 'attachment', $post_types ) ) {
79
- return $post_url;
80
- }
81
- if ( get_post_type( $post_id ) !== 'attachment' ) {
82
- return $post_url;
83
- }
84
-
85
- $post_parent_id = wp_get_post_parent_id( $post_id );
86
-
87
- return get_permalink( $post_parent_id );
88
  }
89
 
90
  /**
61
  $this->settings = new Rop_Settings_Model();
62
  $this->buffer = wp_parse_args( $this->get( 'posts_buffer' ), $this->buffer );
63
  $this->blocked = wp_parse_args( $this->get( 'posts_blocked' ), $this->blocked );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  }
65
 
66
  /**
includes/admin/services/class-rop-linkedin-service.php CHANGED
@@ -437,12 +437,13 @@ class Rop_Linkedin_Service extends Rop_Services_Abstract {
437
  } else {
438
  $new_post = $this->linkedin_image_post( $post_details, $args, $token, $api );
439
  }
440
- } elseif ( get_post_type( $post_details['post_id'] ) == 'attachment' ) {
441
  // Linkedin Api v2 doesn't support video upload. Share as article post
442
- if ( strpos( $post_details['mimetype']['type'], 'video' ) !== false ) {
443
  $new_post = $this->linkedin_article_post( $post_details, $args );
 
 
444
  }
445
- $new_post = $this->linkedin_image_post( $post_details, $args, $token, $api );
446
  }
447
 
448
  try {
@@ -483,6 +484,8 @@ class Rop_Linkedin_Service extends Rop_Services_Abstract {
483
  */
484
  private function linkedin_article_post( $post_details, $args ) {
485
 
 
 
486
  $new_post = array (
487
  'author' => 'urn:li:person:' . $args['id'],
488
  'lifecycleState' => 'PUBLISHED',
@@ -492,7 +495,7 @@ class Rop_Linkedin_Service extends Rop_Services_Abstract {
492
  array (
493
  'shareCommentary' =>
494
  array (
495
- 'text' => $this->strip_excess_blank_lines( $post_details['content'] ) . $post_details['hashtags'],
496
  ),
497
  'shareMediaCategory' => 'ARTICLE',
498
  'media' =>
@@ -504,7 +507,7 @@ class Rop_Linkedin_Service extends Rop_Services_Abstract {
504
  array (
505
  'text' => $this->strip_excess_blank_lines( $post_details['content'] ),
506
  ),
507
- 'originalUrl' => trim( $this->get_url( $post_details ) ),
508
  'title' =>
509
  array (
510
  'text' => html_entity_decode( get_the_title( $post_details['post_id'] ) ),
@@ -560,13 +563,18 @@ class Rop_Linkedin_Service extends Rop_Services_Abstract {
560
  $upload_url = $response['value']['uploadMechanism']['com.linkedin.digitalmedia.uploading.MediaUploadHttpRequest']['uploadUrl'];
561
  $asset = $response['value']['asset'];
562
 
563
- $img = wp_get_attachment_url( $post_details['post_id'] );
 
 
 
 
 
564
 
565
- if ( ! class_exists( '\GuzzleHttp\Client' ) ) {
566
  $this->logger->alert_error( 'Error: Cannot find Guzzle' );
567
  return;
568
  }
569
- $guzzle = new \GuzzleHttp\Client();
570
  $guzzle->request(
571
  'PUT',
572
  $upload_url,
437
  } else {
438
  $new_post = $this->linkedin_image_post( $post_details, $args, $token, $api );
439
  }
440
+ } elseif ( get_post_type( $post_details['post_id'] ) === 'attachment' ) {
441
  // Linkedin Api v2 doesn't support video upload. Share as article post
442
+ if ( strpos( get_post_mime_type( $post_details['post_id'] ), 'video' ) !== false ) {
443
  $new_post = $this->linkedin_article_post( $post_details, $args );
444
+ } else {
445
+ $new_post = $this->linkedin_image_post( $post_details, $args, $token, $api );
446
  }
 
447
  }
448
 
449
  try {
484
  */
485
  private function linkedin_article_post( $post_details, $args ) {
486
 
487
+ $video_post = strpos( get_post_mime_type( $post_details['post_id'] ), 'video' );
488
+
489
  $new_post = array (
490
  'author' => 'urn:li:person:' . $args['id'],
491
  'lifecycleState' => 'PUBLISHED',
495
  array (
496
  'shareCommentary' =>
497
  array (
498
+ 'text' => $this->strip_excess_blank_lines( $post_details['content'] ) . $this->get_url( $post_details ) . $post_details['hashtags'],
499
  ),
500
  'shareMediaCategory' => 'ARTICLE',
501
  'media' =>
507
  array (
508
  'text' => $this->strip_excess_blank_lines( $post_details['content'] ),
509
  ),
510
+ 'originalUrl' => ( $video_post === false ) ? trim( $this->get_url( $post_details ) ) : get_permalink( $post_details['post_id'] ),
511
  'title' =>
512
  array (
513
  'text' => html_entity_decode( get_the_title( $post_details['post_id'] ) ),
563
  $upload_url = $response['value']['uploadMechanism']['com.linkedin.digitalmedia.uploading.MediaUploadHttpRequest']['uploadUrl'];
564
  $asset = $response['value']['asset'];
565
 
566
+ // If this is an attachment post we need to make sure we pass the URL to get_path_by_url() correctly
567
+ if ( get_post_type( $post_details['post_id'] ) === 'attachment' ) {
568
+ $img = $this->get_path_by_url( wp_get_attachment_url( $post_details['post_id'] ), $post_details['mimetype'] );
569
+ } else {
570
+ $img = $this->get_path_by_url( $post_details['post_image'], $post_details['mimetype'] );
571
+ }
572
 
573
+ if ( ! class_exists( 'GuzzleHttp\Client' ) ) {
574
  $this->logger->alert_error( 'Error: Cannot find Guzzle' );
575
  return;
576
  }
577
+ $guzzle = new GuzzleHttp\Client();
578
  $guzzle->request(
579
  'PUT',
580
  $upload_url,
includes/admin/services/class-rop-pinterest-service.php CHANGED
@@ -285,9 +285,12 @@ class Rop_Pinterest_Service extends Rop_Services_Abstract {
285
  )
286
  );
287
 
 
 
 
288
  foreach ( $boards as $board ) {
289
  $board_details = array();
290
- $board_details['id'] = $user->username . '/' . str_replace( ' ', '-', $board->name );
291
  $board_details['account'] = $this->normalize_string( sprintf( '%s %s', $user->first_name, $user->last_name ) );
292
  $board_details['user'] = $this->normalize_string( $board->name );
293
  $board_details['active'] = false;
285
  )
286
  );
287
 
288
+ $search = array( ' ', '.', '/', '!', '@', '&', '#', '%', '*', '(', ')', '{', '}', '[', ']', '|', '\\', '$' );
289
+ $replace = array( '-', '' );
290
+
291
  foreach ( $boards as $board ) {
292
  $board_details = array();
293
+ $board_details['id'] = $user->username . '/' . str_replace( $search, $replace, $board->name );
294
  $board_details['account'] = $this->normalize_string( sprintf( '%s %s', $user->first_name, $user->last_name ) );
295
  $board_details['user'] = $this->normalize_string( $board->name );
296
  $board_details['active'] = false;
includes/admin/services/class-rop-twitter-service.php CHANGED
@@ -503,94 +503,4 @@ class Rop_Twitter_Service extends Rop_Services_Abstract {
503
  return false;
504
  }
505
 
506
- /**
507
- * Get Image file path if exists, return default image_url if not.
508
- *
509
- * Used where file_get_contents might not work with urls, we provide the file path.
510
- *
511
- * @param string $image_url Image url.
512
- *
513
- * @return string Image path.
514
- */
515
- private function get_path_by_url( $image_url, $mimetype ) {
516
-
517
- $dir = wp_upload_dir();
518
-
519
- $parsed = parse_url( $dir['baseurl'] );
520
-
521
- $dir = $parsed['host'] . $parsed['path'];
522
-
523
- if ( false === strpos( $image_url, $dir ) ) {
524
- return $image_url;
525
- }
526
-
527
- $file = basename( $image_url );
528
- $query = array(
529
- 'post_type' => 'attachment',
530
- 'fields' => 'ids',
531
- 'posts_per_page' => '20',
532
- 'no_found_rows' => true,
533
- 'meta_query' => array(
534
- array(
535
- 'key' => '_wp_attached_file',
536
- 'value' => $file,
537
- 'compare' => 'LIKE',
538
- ),
539
- ),
540
- );
541
- $ids = get_posts( $query );
542
- $id_found = false;
543
- if ( strpos( $mimetype['type'], 'video' ) !== false ) {
544
- if ( empty( $ids ) ) {
545
- return $image_url;
546
- }
547
-
548
- return get_attached_file( reset( $ids ) );
549
- }
550
- if ( ! empty( $ids ) ) {
551
-
552
- foreach ( $ids as $id ) {
553
- if ( $image_url === array_shift( wp_get_attachment_image_src( $id, 'full' ) ) ) {
554
- $id_found = $id;
555
- break;
556
- }
557
- }
558
- }
559
- if ( $id_found === false ) {
560
- $query['meta_query'][0]['key'] = '_wp_attachment_metadata';
561
-
562
- // query attachments again
563
- $ids = get_posts( $query );
564
-
565
- if ( empty( $ids ) ) {
566
- return $image_url;
567
- }
568
-
569
- foreach ( $ids as $id ) {
570
-
571
- $meta = wp_get_attachment_metadata( $id );
572
-
573
- foreach ( $meta['sizes'] as $size => $values ) {
574
-
575
- if ( $values['file'] === $file && $image_url === array_shift( wp_get_attachment_image_src( $id, $size ) ) ) {
576
- $id_found = $id;
577
- break;
578
- }
579
- }
580
- if ( $id_found === false ) {
581
- break;
582
- }
583
- }
584
- }
585
- if ( $id_found === false ) {
586
- return $image_url;
587
- }
588
- $path = get_attached_file( $id_found );
589
- if ( empty( $path ) ) {
590
- return $image_url;
591
- }
592
-
593
- return $path;
594
- }
595
-
596
  }
503
  return false;
504
  }
505
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
506
  }
includes/class-rop.php CHANGED
@@ -68,7 +68,7 @@ class Rop {
68
  public function __construct() {
69
 
70
  $this->plugin_name = 'rop';
71
- $this->version = '8.2.4';
72
 
73
  $this->load_dependencies();
74
  $this->set_locale();
@@ -131,6 +131,8 @@ class Rop {
131
  $this->loader->add_action( 'admin_init', $plugin_admin, 'rop_show_linkedin_api_v2_notice' );
132
  $this->loader->add_action( 'admin_notices', $plugin_admin, 'rop_linkedin_api_v2_notice' );
133
  $this->loader->add_action( 'admin_notices', $plugin_admin, 'bitly_shortener_upgrade_notice' );
 
 
134
  $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_styles' );
135
  $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts' );
136
  $this->loader->add_action( 'admin_head', $tutorial_pointers, 'rop_pointer_button_css' );
68
  public function __construct() {
69
 
70
  $this->plugin_name = 'rop';
71
+ $this->version = '8.2.5';
72
 
73
  $this->load_dependencies();
74
  $this->set_locale();
131
  $this->loader->add_action( 'admin_init', $plugin_admin, 'rop_show_linkedin_api_v2_notice' );
132
  $this->loader->add_action( 'admin_notices', $plugin_admin, 'rop_linkedin_api_v2_notice' );
133
  $this->loader->add_action( 'admin_notices', $plugin_admin, 'bitly_shortener_upgrade_notice' );
134
+ $this->loader->add_action( 'admin_init', $plugin_admin, 'rop_show_cron_disabled_notice' );
135
+ $this->loader->add_action( 'admin_notices', $plugin_admin, 'rop_wp_cron_notice' );
136
  $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_styles' );
137
  $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts' );
138
  $this->loader->add_action( 'admin_head', $tutorial_pointers, 'rop_pointer_button_css' );
readme.md CHANGED
@@ -2,7 +2,7 @@
2
  **Contributors:** [codeinwp](https://profiles.wordpress.org/codeinwp), [marius2012](https://profiles.wordpress.org/marius2012), [marius_codeinwp](https://profiles.wordpress.org/marius_codeinwp), [hardeepasrani](https://profiles.wordpress.org/hardeepasrani), [Madalin_Themeisle](https://profiles.wordpress.org/Madalin_Themeisle), [rsocial](https://profiles.wordpress.org/rsocial), [uriahs-victor](https://profiles.wordpress.org/uriahs-victor)
3
  **Tags:** auto publish, auto post, social media automation, social media scheduling, automatic, facebook, twitter, linkedin, pinterest, autopilot, analytics, sharing
4
  **Requires at least:** 4.7
5
- **Tested up to:** 5.1
6
  **Requires PHP:** 5.6
7
  **Stable tag:** trunk
8
 
@@ -134,6 +134,14 @@ http://revive.social/plugins/revive-old-post
134
 
135
 
136
  ## Changelog ##
 
 
 
 
 
 
 
 
137
  ### 8.2.4 - 2019-04-15 ###
138
 
139
  * Fix: Minor bugs
2
  **Contributors:** [codeinwp](https://profiles.wordpress.org/codeinwp), [marius2012](https://profiles.wordpress.org/marius2012), [marius_codeinwp](https://profiles.wordpress.org/marius_codeinwp), [hardeepasrani](https://profiles.wordpress.org/hardeepasrani), [Madalin_Themeisle](https://profiles.wordpress.org/Madalin_Themeisle), [rsocial](https://profiles.wordpress.org/rsocial), [uriahs-victor](https://profiles.wordpress.org/uriahs-victor)
3
  **Tags:** auto publish, auto post, social media automation, social media scheduling, automatic, facebook, twitter, linkedin, pinterest, autopilot, analytics, sharing
4
  **Requires at least:** 4.7
5
+ **Tested up to:** 5.2
6
  **Requires PHP:** 5.6
7
  **Stable tag:** trunk
8
 
134
 
135
 
136
  ## Changelog ##
137
+ ### 8.2.5 - 2019-05-17 ###
138
+
139
+ * New: Show admin notice when WP Cron is turned off, which can cause posting issues with ROP
140
+ * Fix: LinkedIn Image posts were not going through
141
+ * Fix: Posting to some Pinterest boards with special characters was not working
142
+ * Info: Tested on WP 5.2
143
+
144
+
145
  ### 8.2.4 - 2019-04-15 ###
146
 
147
  * Fix: Minor bugs
readme.txt CHANGED
@@ -2,7 +2,7 @@
2
  Contributors: codeinwp,marius2012,marius_codeinwp,hardeepasrani,Madalin_Themeisle, rsocial, uriahs-victor
3
  Tags: auto publish, auto post, social media automation, social media scheduling, automatic, facebook, twitter, linkedin, pinterest, autopilot, analytics, sharing
4
  Requires at least: 4.7
5
- Tested up to: 5.1
6
  Requires PHP: 5.6
7
  Stable tag: trunk
8
 
@@ -134,6 +134,14 @@ http://revive.social/plugins/revive-old-post
134
 
135
 
136
  == Changelog ==
 
 
 
 
 
 
 
 
137
  = 8.2.4 - 2019-04-15 =
138
 
139
  * Fix: Minor bugs
2
  Contributors: codeinwp,marius2012,marius_codeinwp,hardeepasrani,Madalin_Themeisle, rsocial, uriahs-victor
3
  Tags: auto publish, auto post, social media automation, social media scheduling, automatic, facebook, twitter, linkedin, pinterest, autopilot, analytics, sharing
4
  Requires at least: 4.7
5
+ Tested up to: 5.2
6
  Requires PHP: 5.6
7
  Stable tag: trunk
8
 
134
 
135
 
136
  == Changelog ==
137
+ = 8.2.5 - 2019-05-17 =
138
+
139
+ * New: Show admin notice when WP Cron is turned off, which can cause posting issues with ROP
140
+ * Fix: LinkedIn Image posts were not going through
141
+ * Fix: Posting to some Pinterest boards with special characters was not working
142
+ * Info: Tested on WP 5.2
143
+
144
+
145
  = 8.2.4 - 2019-04-15 =
146
 
147
  * Fix: Minor bugs
themeisle-hash.json CHANGED
@@ -1 +1 @@
1
- {"class-rop-autoloader.php":"7bfbb1554230d0ace777adb2e42bebeb","index.php":"39ab8276fb0e4bd3fcab3270822c5977","tweet-old-post.php":"65d39a7cba7eded4172f2f89e42b9ad6","uninstall.php":"5c68258039522cc06b0cf2108e735c4f"}
1
+ {"class-rop-autoloader.php":"7bfbb1554230d0ace777adb2e42bebeb","index.php":"39ab8276fb0e4bd3fcab3270822c5977","tweet-old-post.php":"33f22986201dabed124615d95f6f782d","uninstall.php":"5c68258039522cc06b0cf2108e735c4f"}
tweet-old-post.php CHANGED
@@ -16,11 +16,11 @@
16
  * Plugin Name: Revive Old Posts
17
  * Plugin URI: https://revive.social/
18
  * Description: WordPress plugin that helps you to keeps your old posts alive by sharing them and driving more traffic to them from twitter/facebook or linkedin. It also helps you to promote your content. You can set time and no of posts to share to drive more traffic.For questions, comments, or feature requests, <a href="http://revive.social/support/?utm_source=plugindesc&utm_medium=announce&utm_campaign=top">contact </a> us!
19
- * Version: 8.2.4
20
  * Author: revive.social
21
  * Author URI: https://revive.social/
22
  * Requires at least: 3.5
23
- * Tested up to: 5.1
24
  * Stable tag: trunk
25
  * WordPress Available: yes
26
  * Pro Slug: tweet-old-post-pro
@@ -98,7 +98,7 @@ function run_rop() {
98
  }
99
 
100
  define( 'ROP_PRO_URL', 'http://revive.social/plugins/revive-old-post/' );
101
- define( 'ROP_LITE_VERSION', '8.2.4' );
102
  define( 'ROP_LITE_BASE_FILE', __FILE__ );
103
  define( 'ROP_DEBUG', false );
104
  define( 'ROP_LITE_PATH', plugin_dir_path( __FILE__ ) );
16
  * Plugin Name: Revive Old Posts
17
  * Plugin URI: https://revive.social/
18
  * Description: WordPress plugin that helps you to keeps your old posts alive by sharing them and driving more traffic to them from twitter/facebook or linkedin. It also helps you to promote your content. You can set time and no of posts to share to drive more traffic.For questions, comments, or feature requests, <a href="http://revive.social/support/?utm_source=plugindesc&utm_medium=announce&utm_campaign=top">contact </a> us!
19
+ * Version: 8.2.5
20
  * Author: revive.social
21
  * Author URI: https://revive.social/
22
  * Requires at least: 3.5
23
+ * Tested up to: 5.2
24
  * Stable tag: trunk
25
  * WordPress Available: yes
26
  * Pro Slug: tweet-old-post-pro
98
  }
99
 
100
  define( 'ROP_PRO_URL', 'http://revive.social/plugins/revive-old-post/' );
101
+ define( 'ROP_LITE_VERSION', '8.2.5' );
102
  define( 'ROP_LITE_BASE_FILE', __FILE__ );
103
  define( 'ROP_DEBUG', false );
104
  define( 'ROP_LITE_PATH', plugin_dir_path( __FILE__ ) );
vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer' . '/autoload_real.php';
6
 
7
- return ComposerAutoloaderInit471fee80aedc6ff1f09ed501be9d4e6b::getLoader();
4
 
5
  require_once __DIR__ . '/composer' . '/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInit3947ef487f258ad86b6d6e19cb23535f::getLoader();
vendor/composer/autoload_files.php CHANGED
@@ -6,6 +6,10 @@ $vendorDir = dirname(dirname(__FILE__));
6
  $baseDir = dirname($vendorDir);
7
 
8
  return array(
 
 
 
 
9
  'c65d09b6820da036953a371c8c73a9b1' => $vendorDir . '/facebook/graph-sdk/src/Facebook/polyfills.php',
10
  '36c24edf14e0462467180307deb4c41f' => $vendorDir . '/codeinwp/themeisle-sdk/load.php',
11
  );
6
  $baseDir = dirname($vendorDir);
7
 
8
  return array(
9
+ '7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
10
+ 'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php',
11
+ 'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php',
12
+ '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
13
  'c65d09b6820da036953a371c8c73a9b1' => $vendorDir . '/facebook/graph-sdk/src/Facebook/polyfills.php',
14
  '36c24edf14e0462467180307deb4c41f' => $vendorDir . '/codeinwp/themeisle-sdk/load.php',
15
  );
vendor/composer/autoload_psr4.php CHANGED
@@ -7,7 +7,11 @@ $baseDir = dirname($vendorDir);
7
 
8
  return array(
9
  'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
 
10
  'Monolog\\' => array($vendorDir . '/monolog/monolog/src/Monolog'),
 
 
 
11
  'Facebook\\' => array($vendorDir . '/facebook/graph-sdk/src/Facebook'),
12
  'Abraham\\TwitterOAuth\\' => array($vendorDir . '/abraham/twitteroauth/src'),
13
  );
7
 
8
  return array(
9
  'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
10
+ 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'),
11
  'Monolog\\' => array($vendorDir . '/monolog/monolog/src/Monolog'),
12
+ 'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'),
13
+ 'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'),
14
+ 'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),
15
  'Facebook\\' => array($vendorDir . '/facebook/graph-sdk/src/Facebook'),
16
  'Abraham\\TwitterOAuth\\' => array($vendorDir . '/abraham/twitteroauth/src'),
17
  );
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInit471fee80aedc6ff1f09ed501be9d4e6b
6
  {
7
  private static $loader;
8
 
@@ -19,9 +19,9 @@ class ComposerAutoloaderInit471fee80aedc6ff1f09ed501be9d4e6b
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInit471fee80aedc6ff1f09ed501be9d4e6b', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInit471fee80aedc6ff1f09ed501be9d4e6b', 'loadClassLoader'));
25
 
26
  $map = require __DIR__ . '/autoload_namespaces.php';
27
  foreach ($map as $namespace => $path) {
@@ -42,14 +42,14 @@ class ComposerAutoloaderInit471fee80aedc6ff1f09ed501be9d4e6b
42
 
43
  $includeFiles = require __DIR__ . '/autoload_files.php';
44
  foreach ($includeFiles as $fileIdentifier => $file) {
45
- composerRequire471fee80aedc6ff1f09ed501be9d4e6b($fileIdentifier, $file);
46
  }
47
 
48
  return $loader;
49
  }
50
  }
51
 
52
- function composerRequire471fee80aedc6ff1f09ed501be9d4e6b($fileIdentifier, $file)
53
  {
54
  if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
55
  require $file;
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInit3947ef487f258ad86b6d6e19cb23535f
6
  {
7
  private static $loader;
8
 
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInit3947ef487f258ad86b6d6e19cb23535f', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInit3947ef487f258ad86b6d6e19cb23535f', 'loadClassLoader'));
25
 
26
  $map = require __DIR__ . '/autoload_namespaces.php';
27
  foreach ($map as $namespace => $path) {
42
 
43
  $includeFiles = require __DIR__ . '/autoload_files.php';
44
  foreach ($includeFiles as $fileIdentifier => $file) {
45
+ composerRequire3947ef487f258ad86b6d6e19cb23535f($fileIdentifier, $file);
46
  }
47
 
48
  return $loader;
49
  }
50
  }
51
 
52
+ function composerRequire3947ef487f258ad86b6d6e19cb23535f($fileIdentifier, $file)
53
  {
54
  if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
55
  require $file;
vendor/composer/installed.json CHANGED
@@ -115,6 +115,289 @@
115
  "sdk"
116
  ]
117
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  {
119
  "name": "psr/log",
120
  "version": "1.1.0",
115
  "sdk"
116
  ]
117
  },
118
+ {
119
+ "name": "guzzlehttp/promises",
120
+ "version": "v1.3.1",
121
+ "version_normalized": "1.3.1.0",
122
+ "source": {
123
+ "type": "git",
124
+ "url": "https://github.com/guzzle/promises.git",
125
+ "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646"
126
+ },
127
+ "dist": {
128
+ "type": "zip",
129
+ "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646",
130
+ "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646",
131
+ "shasum": ""
132
+ },
133
+ "require": {
134
+ "php": ">=5.5.0"
135
+ },
136
+ "require-dev": {
137
+ "phpunit/phpunit": "^4.0"
138
+ },
139
+ "time": "2016-12-20 10:07:11",
140
+ "type": "library",
141
+ "extra": {
142
+ "branch-alias": {
143
+ "dev-master": "1.4-dev"
144
+ }
145
+ },
146
+ "installation-source": "dist",
147
+ "autoload": {
148
+ "psr-4": {
149
+ "GuzzleHttp\\Promise\\": "src/"
150
+ },
151
+ "files": [
152
+ "src/functions_include.php"
153
+ ]
154
+ },
155
+ "notification-url": "https://packagist.org/downloads/",
156
+ "license": [
157
+ "MIT"
158
+ ],
159
+ "authors": [
160
+ {
161
+ "name": "Michael Dowling",
162
+ "email": "mtdowling@gmail.com",
163
+ "homepage": "https://github.com/mtdowling"
164
+ }
165
+ ],
166
+ "description": "Guzzle promises library",
167
+ "keywords": [
168
+ "promise"
169
+ ]
170
+ },
171
+ {
172
+ "name": "ralouphie/getallheaders",
173
+ "version": "2.0.5",
174
+ "version_normalized": "2.0.5.0",
175
+ "source": {
176
+ "type": "git",
177
+ "url": "https://github.com/ralouphie/getallheaders.git",
178
+ "reference": "5601c8a83fbba7ef674a7369456d12f1e0d0eafa"
179
+ },
180
+ "dist": {
181
+ "type": "zip",
182
+ "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/5601c8a83fbba7ef674a7369456d12f1e0d0eafa",
183
+ "reference": "5601c8a83fbba7ef674a7369456d12f1e0d0eafa",
184
+ "shasum": ""
185
+ },
186
+ "require": {
187
+ "php": ">=5.3"
188
+ },
189
+ "require-dev": {
190
+ "phpunit/phpunit": "~3.7.0",
191
+ "satooshi/php-coveralls": ">=1.0"
192
+ },
193
+ "time": "2016-02-11 07:05:27",
194
+ "type": "library",
195
+ "installation-source": "dist",
196
+ "autoload": {
197
+ "files": [
198
+ "src/getallheaders.php"
199
+ ]
200
+ },
201
+ "notification-url": "https://packagist.org/downloads/",
202
+ "license": [
203
+ "MIT"
204
+ ],
205
+ "authors": [
206
+ {
207
+ "name": "Ralph Khattar",
208
+ "email": "ralph.khattar@gmail.com"
209
+ }
210
+ ],
211
+ "description": "A polyfill for getallheaders."
212
+ },
213
+ {
214
+ "name": "psr/http-message",
215
+ "version": "1.0.1",
216
+ "version_normalized": "1.0.1.0",
217
+ "source": {
218
+ "type": "git",
219
+ "url": "https://github.com/php-fig/http-message.git",
220
+ "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
221
+ },
222
+ "dist": {
223
+ "type": "zip",
224
+ "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
225
+ "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
226
+ "shasum": ""
227
+ },
228
+ "require": {
229
+ "php": ">=5.3.0"
230
+ },
231
+ "time": "2016-08-06 14:39:51",
232
+ "type": "library",
233
+ "extra": {
234
+ "branch-alias": {
235
+ "dev-master": "1.0.x-dev"
236
+ }
237
+ },
238
+ "installation-source": "dist",
239
+ "autoload": {
240
+ "psr-4": {
241
+ "Psr\\Http\\Message\\": "src/"
242
+ }
243
+ },
244
+ "notification-url": "https://packagist.org/downloads/",
245
+ "license": [
246
+ "MIT"
247
+ ],
248
+ "authors": [
249
+ {
250
+ "name": "PHP-FIG",
251
+ "homepage": "http://www.php-fig.org/"
252
+ }
253
+ ],
254
+ "description": "Common interface for HTTP messages",
255
+ "homepage": "https://github.com/php-fig/http-message",
256
+ "keywords": [
257
+ "http",
258
+ "http-message",
259
+ "psr",
260
+ "psr-7",
261
+ "request",
262
+ "response"
263
+ ]
264
+ },
265
+ {
266
+ "name": "guzzlehttp/psr7",
267
+ "version": "1.5.2",
268
+ "version_normalized": "1.5.2.0",
269
+ "source": {
270
+ "type": "git",
271
+ "url": "https://github.com/guzzle/psr7.git",
272
+ "reference": "9f83dded91781a01c63574e387eaa769be769115"
273
+ },
274
+ "dist": {
275
+ "type": "zip",
276
+ "url": "https://api.github.com/repos/guzzle/psr7/zipball/9f83dded91781a01c63574e387eaa769be769115",
277
+ "reference": "9f83dded91781a01c63574e387eaa769be769115",
278
+ "shasum": ""
279
+ },
280
+ "require": {
281
+ "php": ">=5.4.0",
282
+ "psr/http-message": "~1.0",
283
+ "ralouphie/getallheaders": "^2.0.5"
284
+ },
285
+ "provide": {
286
+ "psr/http-message-implementation": "1.0"
287
+ },
288
+ "require-dev": {
289
+ "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8"
290
+ },
291
+ "time": "2018-12-04 20:46:45",
292
+ "type": "library",
293
+ "extra": {
294
+ "branch-alias": {
295
+ "dev-master": "1.5-dev"
296
+ }
297
+ },
298
+ "installation-source": "dist",
299
+ "autoload": {
300
+ "psr-4": {
301
+ "GuzzleHttp\\Psr7\\": "src/"
302
+ },
303
+ "files": [
304
+ "src/functions_include.php"
305
+ ]
306
+ },
307
+ "notification-url": "https://packagist.org/downloads/",
308
+ "license": [
309
+ "MIT"
310
+ ],
311
+ "authors": [
312
+ {
313
+ "name": "Michael Dowling",
314
+ "email": "mtdowling@gmail.com",
315
+ "homepage": "https://github.com/mtdowling"
316
+ },
317
+ {
318
+ "name": "Tobias Schultze",
319
+ "homepage": "https://github.com/Tobion"
320
+ }
321
+ ],
322
+ "description": "PSR-7 message implementation that also provides common utility methods",
323
+ "keywords": [
324
+ "http",
325
+ "message",
326
+ "psr-7",
327
+ "request",
328
+ "response",
329
+ "stream",
330
+ "uri",
331
+ "url"
332
+ ]
333
+ },
334
+ {
335
+ "name": "guzzlehttp/guzzle",
336
+ "version": "6.3.3",
337
+ "version_normalized": "6.3.3.0",
338
+ "source": {
339
+ "type": "git",
340
+ "url": "https://github.com/guzzle/guzzle.git",
341
+ "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba"
342
+ },
343
+ "dist": {
344
+ "type": "zip",
345
+ "url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba",
346
+ "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba",
347
+ "shasum": ""
348
+ },
349
+ "require": {
350
+ "guzzlehttp/promises": "^1.0",
351
+ "guzzlehttp/psr7": "^1.4",
352
+ "php": ">=5.5"
353
+ },
354
+ "require-dev": {
355
+ "ext-curl": "*",
356
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0",
357
+ "psr/log": "^1.0"
358
+ },
359
+ "suggest": {
360
+ "psr/log": "Required for using the Log middleware"
361
+ },
362
+ "time": "2018-04-22 15:46:56",
363
+ "type": "library",
364
+ "extra": {
365
+ "branch-alias": {
366
+ "dev-master": "6.3-dev"
367
+ }
368
+ },
369
+ "installation-source": "dist",
370
+ "autoload": {
371
+ "files": [
372
+ "src/functions_include.php"
373
+ ],
374
+ "psr-4": {
375
+ "GuzzleHttp\\": "src/"
376
+ }
377
+ },
378
+ "notification-url": "https://packagist.org/downloads/",
379
+ "license": [
380
+ "MIT"
381
+ ],
382
+ "authors": [
383
+ {
384
+ "name": "Michael Dowling",
385
+ "email": "mtdowling@gmail.com",
386
+ "homepage": "https://github.com/mtdowling"
387
+ }
388
+ ],
389
+ "description": "Guzzle is a PHP HTTP client library",
390
+ "homepage": "http://guzzlephp.org/",
391
+ "keywords": [
392
+ "client",
393
+ "curl",
394
+ "framework",
395
+ "http",
396
+ "http client",
397
+ "rest",
398
+ "web service"
399
+ ]
400
+ },
401
  {
402
  "name": "psr/log",
403
  "version": "1.1.0",
vendor/guzzlehttp/guzzle/CHANGELOG.md ADDED
@@ -0,0 +1,1287 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Change Log
2
+
3
+ ## 6.3.3 - 2018-04-22
4
+
5
+ * Fix: Default headers when decode_content is specified
6
+
7
+
8
+ ## 6.3.2 - 2018-03-26
9
+
10
+ * Fix: Release process
11
+
12
+
13
+ ## 6.3.1 - 2018-03-26
14
+
15
+ * Bug fix: Parsing 0 epoch expiry times in cookies [#2014](https://github.com/guzzle/guzzle/pull/2014)
16
+ * Improvement: Better ConnectException detection [#2012](https://github.com/guzzle/guzzle/pull/2012)
17
+ * Bug fix: Malformed domain that contains a "/" [#1999](https://github.com/guzzle/guzzle/pull/1999)
18
+ * Bug fix: Undefined offset when a cookie has no first key-value pair [#1998](https://github.com/guzzle/guzzle/pull/1998)
19
+ * Improvement: Support PHPUnit 6 [#1953](https://github.com/guzzle/guzzle/pull/1953)
20
+ * Bug fix: Support empty headers [#1915](https://github.com/guzzle/guzzle/pull/1915)
21
+ * Bug fix: Ignore case during header modifications [#1916](https://github.com/guzzle/guzzle/pull/1916)
22
+
23
+ + Minor code cleanups, documentation fixes and clarifications.
24
+
25
+
26
+ ## 6.3.0 - 2017-06-22
27
+
28
+ * Feature: force IP resolution (ipv4 or ipv6) [#1608](https://github.com/guzzle/guzzle/pull/1608), [#1659](https://github.com/guzzle/guzzle/pull/1659)
29
+ * Improvement: Don't include summary in exception message when body is empty [#1621](https://github.com/guzzle/guzzle/pull/1621)
30
+ * Improvement: Handle `on_headers` option in MockHandler [#1580](https://github.com/guzzle/guzzle/pull/1580)
31
+ * Improvement: Added SUSE Linux CA path [#1609](https://github.com/guzzle/guzzle/issues/1609)
32
+ * Improvement: Use class reference for getting the name of the class instead of using hardcoded strings [#1641](https://github.com/guzzle/guzzle/pull/1641)
33
+ * Feature: Added `read_timeout` option [#1611](https://github.com/guzzle/guzzle/pull/1611)
34
+ * Bug fix: PHP 7.x fixes [#1685](https://github.com/guzzle/guzzle/pull/1685), [#1686](https://github.com/guzzle/guzzle/pull/1686), [#1811](https://github.com/guzzle/guzzle/pull/1811)
35
+ * Deprecation: BadResponseException instantiation without a response [#1642](https://github.com/guzzle/guzzle/pull/1642)
36
+ * Feature: Added NTLM auth [#1569](https://github.com/guzzle/guzzle/pull/1569)
37
+ * Feature: Track redirect HTTP status codes [#1711](https://github.com/guzzle/guzzle/pull/1711)
38
+ * Improvement: Check handler type during construction [#1745](https://github.com/guzzle/guzzle/pull/1745)
39
+ * Improvement: Always include the Content-Length if there's a body [#1721](https://github.com/guzzle/guzzle/pull/1721)
40
+ * Feature: Added convenience method to access a cookie by name [#1318](https://github.com/guzzle/guzzle/pull/1318)
41
+ * Bug fix: Fill `CURLOPT_CAPATH` and `CURLOPT_CAINFO` properly [#1684](https://github.com/guzzle/guzzle/pull/1684)
42
+ * Improvement: Use `\GuzzleHttp\Promise\rejection_for` function instead of object init [#1827](https://github.com/guzzle/guzzle/pull/1827)
43
+
44
+
45
+ + Minor code cleanups, documentation fixes and clarifications.
46
+
47
+ ## 6.2.3 - 2017-02-28
48
+
49
+ * Fix deprecations with guzzle/psr7 version 1.4
50
+
51
+ ## 6.2.2 - 2016-10-08
52
+
53
+ * Allow to pass nullable Response to delay callable
54
+ * Only add scheme when host is present
55
+ * Fix drain case where content-length is the literal string zero
56
+ * Obfuscate in-URL credentials in exceptions
57
+
58
+ ## 6.2.1 - 2016-07-18
59
+
60
+ * Address HTTP_PROXY security vulnerability, CVE-2016-5385:
61
+ https://httpoxy.org/
62
+ * Fixing timeout bug with StreamHandler:
63
+ https://github.com/guzzle/guzzle/pull/1488
64
+ * Only read up to `Content-Length` in PHP StreamHandler to avoid timeouts when
65
+ a server does not honor `Connection: close`.
66
+ * Ignore URI fragment when sending requests.
67
+
68
+ ## 6.2.0 - 2016-03-21
69
+
70
+ * Feature: added `GuzzleHttp\json_encode` and `GuzzleHttp\json_decode`.
71
+ https://github.com/guzzle/guzzle/pull/1389
72
+ * Bug fix: Fix sleep calculation when waiting for delayed requests.
73
+ https://github.com/guzzle/guzzle/pull/1324
74
+ * Feature: More flexible history containers.
75
+ https://github.com/guzzle/guzzle/pull/1373
76
+ * Bug fix: defer sink stream opening in StreamHandler.
77
+ https://github.com/guzzle/guzzle/pull/1377
78
+ * Bug fix: do not attempt to escape cookie values.
79
+ https://github.com/guzzle/guzzle/pull/1406
80
+ * Feature: report original content encoding and length on decoded responses.
81
+ https://github.com/guzzle/guzzle/pull/1409
82
+ * Bug fix: rewind seekable request bodies before dispatching to cURL.
83
+ https://github.com/guzzle/guzzle/pull/1422
84
+ * Bug fix: provide an empty string to `http_build_query` for HHVM workaround.
85
+ https://github.com/guzzle/guzzle/pull/1367
86
+
87
+ ## 6.1.1 - 2015-11-22
88
+
89
+ * Bug fix: Proxy::wrapSync() now correctly proxies to the appropriate handler
90
+ https://github.com/guzzle/guzzle/commit/911bcbc8b434adce64e223a6d1d14e9a8f63e4e4
91
+ * Feature: HandlerStack is now more generic.
92
+ https://github.com/guzzle/guzzle/commit/f2102941331cda544745eedd97fc8fd46e1ee33e
93
+ * Bug fix: setting verify to false in the StreamHandler now disables peer
94
+ verification. https://github.com/guzzle/guzzle/issues/1256
95
+ * Feature: Middleware now uses an exception factory, including more error
96
+ context. https://github.com/guzzle/guzzle/pull/1282
97
+ * Feature: better support for disabled functions.
98
+ https://github.com/guzzle/guzzle/pull/1287
99
+ * Bug fix: fixed regression where MockHandler was not using `sink`.
100
+ https://github.com/guzzle/guzzle/pull/1292
101
+
102
+ ## 6.1.0 - 2015-09-08
103
+
104
+ * Feature: Added the `on_stats` request option to provide access to transfer
105
+ statistics for requests. https://github.com/guzzle/guzzle/pull/1202
106
+ * Feature: Added the ability to persist session cookies in CookieJars.
107
+ https://github.com/guzzle/guzzle/pull/1195
108
+ * Feature: Some compatibility updates for Google APP Engine
109
+ https://github.com/guzzle/guzzle/pull/1216
110
+ * Feature: Added support for NO_PROXY to prevent the use of a proxy based on
111
+ a simple set of rules. https://github.com/guzzle/guzzle/pull/1197
112
+ * Feature: Cookies can now contain square brackets.
113
+ https://github.com/guzzle/guzzle/pull/1237
114
+ * Bug fix: Now correctly parsing `=` inside of quotes in Cookies.
115
+ https://github.com/guzzle/guzzle/pull/1232
116
+ * Bug fix: Cusotm cURL options now correctly override curl options of the
117
+ same name. https://github.com/guzzle/guzzle/pull/1221
118
+ * Bug fix: Content-Type header is now added when using an explicitly provided
119
+ multipart body. https://github.com/guzzle/guzzle/pull/1218
120
+ * Bug fix: Now ignoring Set-Cookie headers that have no name.
121
+ * Bug fix: Reason phrase is no longer cast to an int in some cases in the
122
+ cURL handler. https://github.com/guzzle/guzzle/pull/1187
123
+ * Bug fix: Remove the Authorization header when redirecting if the Host
124
+ header changes. https://github.com/guzzle/guzzle/pull/1207
125
+ * Bug fix: Cookie path matching fixes
126
+ https://github.com/guzzle/guzzle/issues/1129
127
+ * Bug fix: Fixing the cURL `body_as_string` setting
128
+ https://github.com/guzzle/guzzle/pull/1201
129
+ * Bug fix: quotes are no longer stripped when parsing cookies.
130
+ https://github.com/guzzle/guzzle/issues/1172
131
+ * Bug fix: `form_params` and `query` now always uses the `&` separator.
132
+ https://github.com/guzzle/guzzle/pull/1163
133
+ * Bug fix: Adding a Content-Length to PHP stream wrapper requests if not set.
134
+ https://github.com/guzzle/guzzle/pull/1189
135
+
136
+ ## 6.0.2 - 2015-07-04
137
+
138
+ * Fixed a memory leak in the curl handlers in which references to callbacks
139
+ were not being removed by `curl_reset`.
140
+ * Cookies are now extracted properly before redirects.
141
+ * Cookies now allow more character ranges.
142
+ * Decoded Content-Encoding responses are now modified to correctly reflect
143
+ their state if the encoding was automatically removed by a handler. This
144
+ means that the `Content-Encoding` header may be removed an the
145
+ `Content-Length` modified to reflect the message size after removing the
146
+ encoding.
147
+ * Added a more explicit error message when trying to use `form_params` and
148
+ `multipart` in the same request.
149
+ * Several fixes for HHVM support.
150
+ * Functions are now conditionally required using an additional level of
151
+ indirection to help with global Composer installations.
152
+
153
+ ## 6.0.1 - 2015-05-27
154
+
155
+ * Fixed a bug with serializing the `query` request option where the `&`
156
+ separator was missing.
157
+ * Added a better error message for when `body` is provided as an array. Please
158
+ use `form_params` or `multipart` instead.
159
+ * Various doc fixes.
160
+
161
+ ## 6.0.0 - 2015-05-26
162
+
163
+ * See the UPGRADING.md document for more information.
164
+ * Added `multipart` and `form_params` request options.
165
+ * Added `synchronous` request option.
166
+ * Added the `on_headers` request option.
167
+ * Fixed `expect` handling.
168
+ * No longer adding default middlewares in the client ctor. These need to be
169
+ present on the provided handler in order to work.
170
+ * Requests are no longer initiated when sending async requests with the
171
+ CurlMultiHandler. This prevents unexpected recursion from requests completing
172
+ while ticking the cURL loop.
173
+ * Removed the semantics of setting `default` to `true`. This is no longer
174
+ required now that the cURL loop is not ticked for async requests.
175
+ * Added request and response logging middleware.
176
+ * No longer allowing self signed certificates when using the StreamHandler.
177
+ * Ensuring that `sink` is valid if saving to a file.
178
+ * Request exceptions now include a "handler context" which provides handler
179
+ specific contextual information.
180
+ * Added `GuzzleHttp\RequestOptions` to allow request options to be applied
181
+ using constants.
182
+ * `$maxHandles` has been removed from CurlMultiHandler.
183
+ * `MultipartPostBody` is now part of the `guzzlehttp/psr7` package.
184
+
185
+ ## 5.3.0 - 2015-05-19
186
+
187
+ * Mock now supports `save_to`
188
+ * Marked `AbstractRequestEvent::getTransaction()` as public.
189
+ * Fixed a bug in which multiple headers using different casing would overwrite
190
+ previous headers in the associative array.
191
+ * Added `Utils::getDefaultHandler()`
192
+ * Marked `GuzzleHttp\Client::getDefaultUserAgent` as deprecated.
193
+ * URL scheme is now always lowercased.
194
+
195
+ ## 6.0.0-beta.1
196
+
197
+ * Requires PHP >= 5.5
198
+ * Updated to use PSR-7
199
+ * Requires immutable messages, which basically means an event based system
200
+ owned by a request instance is no longer possible.
201
+ * Utilizing the [Guzzle PSR-7 package](https://github.com/guzzle/psr7).
202
+ * Removed the dependency on `guzzlehttp/streams`. These stream abstractions
203
+ are available in the `guzzlehttp/psr7` package under the `GuzzleHttp\Psr7`
204
+ namespace.
205
+ * Added middleware and handler system
206
+ * Replaced the Guzzle event and subscriber system with a middleware system.
207
+ * No longer depends on RingPHP, but rather places the HTTP handlers directly
208
+ in Guzzle, operating on PSR-7 messages.
209
+ * Retry logic is now encapsulated in `GuzzleHttp\Middleware::retry`, which
210
+ means the `guzzlehttp/retry-subscriber` is now obsolete.
211
+ * Mocking responses is now handled using `GuzzleHttp\Handler\MockHandler`.
212
+ * Asynchronous responses
213
+ * No longer supports the `future` request option to send an async request.
214
+ Instead, use one of the `*Async` methods of a client (e.g., `requestAsync`,
215
+ `getAsync`, etc.).
216
+ * Utilizing `GuzzleHttp\Promise` instead of React's promise library to avoid
217
+ recursion required by chaining and forwarding react promises. See
218
+ https://github.com/guzzle/promises
219
+ * Added `requestAsync` and `sendAsync` to send request asynchronously.
220
+ * Added magic methods for `getAsync()`, `postAsync()`, etc. to send requests
221
+ asynchronously.
222
+ * Request options
223
+ * POST and form updates
224
+ * Added the `form_fields` and `form_files` request options.
225
+ * Removed the `GuzzleHttp\Post` namespace.
226
+ * The `body` request option no longer accepts an array for POST requests.
227
+ * The `exceptions` request option has been deprecated in favor of the
228
+ `http_errors` request options.
229
+ * The `save_to` request option has been deprecated in favor of `sink` request
230
+ option.
231
+ * Clients no longer accept an array of URI template string and variables for
232
+ URI variables. You will need to expand URI templates before passing them
233
+ into a client constructor or request method.
234
+ * Client methods `get()`, `post()`, `put()`, `patch()`, `options()`, etc. are
235
+ now magic methods that will send synchronous requests.
236
+ * Replaced `Utils.php` with plain functions in `functions.php`.
237
+ * Removed `GuzzleHttp\Collection`.
238
+ * Removed `GuzzleHttp\BatchResults`. Batched pool results are now returned as
239
+ an array.
240
+ * Removed `GuzzleHttp\Query`. Query string handling is now handled using an
241
+ associative array passed into the `query` request option. The query string
242
+ is serialized using PHP's `http_build_query`. If you need more control, you
243
+ can pass the query string in as a string.
244
+ * `GuzzleHttp\QueryParser` has been replaced with the
245
+ `GuzzleHttp\Psr7\parse_query`.
246
+
247
+ ## 5.2.0 - 2015-01-27
248
+
249
+ * Added `AppliesHeadersInterface` to make applying headers to a request based
250
+ on the body more generic and not specific to `PostBodyInterface`.
251
+ * Reduced the number of stack frames needed to send requests.
252
+ * Nested futures are now resolved in the client rather than the RequestFsm
253
+ * Finishing state transitions is now handled in the RequestFsm rather than the
254
+ RingBridge.
255
+ * Added a guard in the Pool class to not use recursion for request retries.
256
+
257
+ ## 5.1.0 - 2014-12-19
258
+
259
+ * Pool class no longer uses recursion when a request is intercepted.
260
+ * The size of a Pool can now be dynamically adjusted using a callback.
261
+ See https://github.com/guzzle/guzzle/pull/943.
262
+ * Setting a request option to `null` when creating a request with a client will
263
+ ensure that the option is not set. This allows you to overwrite default
264
+ request options on a per-request basis.
265
+ See https://github.com/guzzle/guzzle/pull/937.
266
+ * Added the ability to limit which protocols are allowed for redirects by
267
+ specifying a `protocols` array in the `allow_redirects` request option.
268
+ * Nested futures due to retries are now resolved when waiting for synchronous
269
+ responses. See https://github.com/guzzle/guzzle/pull/947.
270
+ * `"0"` is now an allowed URI path. See
271
+ https://github.com/guzzle/guzzle/pull/935.
272
+ * `Query` no longer typehints on the `$query` argument in the constructor,
273
+ allowing for strings and arrays.
274
+ * Exceptions thrown in the `end` event are now correctly wrapped with Guzzle
275
+ specific exceptions if necessary.
276
+
277
+ ## 5.0.3 - 2014-11-03
278
+
279
+ This change updates query strings so that they are treated as un-encoded values
280
+ by default where the value represents an un-encoded value to send over the
281
+ wire. A Query object then encodes the value before sending over the wire. This
282
+ means that even value query string values (e.g., ":") are url encoded. This
283
+ makes the Query class match PHP's http_build_query function. However, if you
284
+ want to send requests over the wire using valid query string characters that do
285
+ not need to be encoded, then you can provide a string to Url::setQuery() and
286
+ pass true as the second argument to specify that the query string is a raw
287
+ string that should not be parsed or encoded (unless a call to getQuery() is
288
+ subsequently made, forcing the query-string to be converted into a Query
289
+ object).
290
+
291
+ ## 5.0.2 - 2014-10-30
292
+
293
+ * Added a trailing `\r\n` to multipart/form-data payloads. See
294
+ https://github.com/guzzle/guzzle/pull/871
295
+ * Added a `GuzzleHttp\Pool::send()` convenience method to match the docs.
296
+ * Status codes are now returned as integers. See
297
+ https://github.com/guzzle/guzzle/issues/881
298
+ * No longer overwriting an existing `application/x-www-form-urlencoded` header
299
+ when sending POST requests, allowing for customized headers. See
300
+ https://github.com/guzzle/guzzle/issues/877
301
+ * Improved path URL serialization.
302
+
303
+ * No longer double percent-encoding characters in the path or query string if
304
+ they are already encoded.
305
+ * Now properly encoding the supplied path to a URL object, instead of only
306
+ encoding ' ' and '?'.
307
+ * Note: This has been changed in 5.0.3 to now encode query string values by
308
+ default unless the `rawString` argument is provided when setting the query
309
+ string on a URL: Now allowing many more characters to be present in the
310
+ query string without being percent encoded. See http://tools.ietf.org/html/rfc3986#appendix-A
311
+
312
+ ## 5.0.1 - 2014-10-16
313
+
314
+ Bugfix release.
315
+
316
+ * Fixed an issue where connection errors still returned response object in
317
+ error and end events event though the response is unusable. This has been
318
+ corrected so that a response is not returned in the `getResponse` method of
319
+ these events if the response did not complete. https://github.com/guzzle/guzzle/issues/867
320
+ * Fixed an issue where transfer statistics were not being populated in the
321
+ RingBridge. https://github.com/guzzle/guzzle/issues/866
322
+
323
+ ## 5.0.0 - 2014-10-12
324
+
325
+ Adding support for non-blocking responses and some minor API cleanup.
326
+
327
+ ### New Features
328
+
329
+ * Added support for non-blocking responses based on `guzzlehttp/guzzle-ring`.
330
+ * Added a public API for creating a default HTTP adapter.
331
+ * Updated the redirect plugin to be non-blocking so that redirects are sent
332
+ concurrently. Other plugins like this can now be updated to be non-blocking.
333
+ * Added a "progress" event so that you can get upload and download progress
334
+ events.
335
+ * Added `GuzzleHttp\Pool` which implements FutureInterface and transfers
336
+ requests concurrently using a capped pool size as efficiently as possible.
337
+ * Added `hasListeners()` to EmitterInterface.
338
+ * Removed `GuzzleHttp\ClientInterface::sendAll` and marked
339
+ `GuzzleHttp\Client::sendAll` as deprecated (it's still there, just not the
340
+ recommended way).
341
+
342
+ ### Breaking changes
343
+
344
+ The breaking changes in this release are relatively minor. The biggest thing to
345
+ look out for is that request and response objects no longer implement fluent
346
+ interfaces.
347
+
348
+ * Removed the fluent interfaces (i.e., `return $this`) from requests,
349
+ responses, `GuzzleHttp\Collection`, `GuzzleHttp\Url`,
350
+ `GuzzleHttp\Query`, `GuzzleHttp\Post\PostBody`, and
351
+ `GuzzleHttp\Cookie\SetCookie`. This blog post provides a good outline of
352
+ why I did this: http://ocramius.github.io/blog/fluent-interfaces-are-evil/.
353
+ This also makes the Guzzle message interfaces compatible with the current
354
+ PSR-7 message proposal.
355
+ * Removed "functions.php", so that Guzzle is truly PSR-4 compliant. Except
356
+ for the HTTP request functions from function.php, these functions are now
357
+ implemented in `GuzzleHttp\Utils` using camelCase. `GuzzleHttp\json_decode`
358
+ moved to `GuzzleHttp\Utils::jsonDecode`. `GuzzleHttp\get_path` moved to
359
+ `GuzzleHttp\Utils::getPath`. `GuzzleHttp\set_path` moved to
360
+ `GuzzleHttp\Utils::setPath`. `GuzzleHttp\batch` should now be
361
+ `GuzzleHttp\Pool::batch`, which returns an `objectStorage`. Using functions.php
362
+ caused problems for many users: they aren't PSR-4 compliant, require an
363
+ explicit include, and needed an if-guard to ensure that the functions are not
364
+ declared multiple times.
365
+ * Rewrote adapter layer.
366
+ * Removing all classes from `GuzzleHttp\Adapter`, these are now
367
+ implemented as callables that are stored in `GuzzleHttp\Ring\Client`.
368
+ * Removed the concept of "parallel adapters". Sending requests serially or
369
+ concurrently is now handled using a single adapter.
370
+ * Moved `GuzzleHttp\Adapter\Transaction` to `GuzzleHttp\Transaction`. The
371
+ Transaction object now exposes the request, response, and client as public
372
+ properties. The getters and setters have been removed.
373
+ * Removed the "headers" event. This event was only useful for changing the
374
+ body a response once the headers of the response were known. You can implement
375
+ a similar behavior in a number of ways. One example might be to use a
376
+ FnStream that has access to the transaction being sent. For example, when the
377
+ first byte is written, you could check if the response headers match your
378
+ expectations, and if so, change the actual stream body that is being
379
+ written to.
380
+ * Removed the `asArray` parameter from
381
+ `GuzzleHttp\Message\MessageInterface::getHeader`. If you want to get a header
382
+ value as an array, then use the newly added `getHeaderAsArray()` method of
383
+ `MessageInterface`. This change makes the Guzzle interfaces compatible with
384
+ the PSR-7 interfaces.
385
+ * `GuzzleHttp\Message\MessageFactory` no longer allows subclasses to add
386
+ custom request options using double-dispatch (this was an implementation
387
+ detail). Instead, you should now provide an associative array to the
388
+ constructor which is a mapping of the request option name mapping to a
389
+ function that applies the option value to a request.
390
+ * Removed the concept of "throwImmediately" from exceptions and error events.
391
+ This control mechanism was used to stop a transfer of concurrent requests
392
+ from completing. This can now be handled by throwing the exception or by
393
+ cancelling a pool of requests or each outstanding future request individually.
394
+ * Updated to "GuzzleHttp\Streams" 3.0.
395
+ * `GuzzleHttp\Stream\StreamInterface::getContents()` no longer accepts a
396
+ `maxLen` parameter. This update makes the Guzzle streams project
397
+ compatible with the current PSR-7 proposal.
398
+ * `GuzzleHttp\Stream\Stream::__construct`,
399
+ `GuzzleHttp\Stream\Stream::factory`, and
400
+ `GuzzleHttp\Stream\Utils::create` no longer accept a size in the second
401
+ argument. They now accept an associative array of options, including the
402
+ "size" key and "metadata" key which can be used to provide custom metadata.
403
+
404
+ ## 4.2.2 - 2014-09-08
405
+
406
+ * Fixed a memory leak in the CurlAdapter when reusing cURL handles.
407
+ * No longer using `request_fulluri` in stream adapter proxies.
408
+ * Relative redirects are now based on the last response, not the first response.
409
+
410
+ ## 4.2.1 - 2014-08-19
411
+
412
+ * Ensuring that the StreamAdapter does not always add a Content-Type header
413
+ * Adding automated github releases with a phar and zip
414
+
415
+ ## 4.2.0 - 2014-08-17
416
+
417
+ * Now merging in default options using a case-insensitive comparison.
418
+ Closes https://github.com/guzzle/guzzle/issues/767
419
+ * Added the ability to automatically decode `Content-Encoding` response bodies
420
+ using the `decode_content` request option. This is set to `true` by default
421
+ to decode the response body if it comes over the wire with a
422
+ `Content-Encoding`. Set this value to `false` to disable decoding the
423
+ response content, and pass a string to provide a request `Accept-Encoding`
424
+ header and turn on automatic response decoding. This feature now allows you
425
+ to pass an `Accept-Encoding` header in the headers of a request but still
426
+ disable automatic response decoding.
427
+ Closes https://github.com/guzzle/guzzle/issues/764
428
+ * Added the ability to throw an exception immediately when transferring
429
+ requests in parallel. Closes https://github.com/guzzle/guzzle/issues/760
430
+ * Updating guzzlehttp/streams dependency to ~2.1
431
+ * No longer utilizing the now deprecated namespaced methods from the stream
432
+ package.
433
+
434
+ ## 4.1.8 - 2014-08-14
435
+
436
+ * Fixed an issue in the CurlFactory that caused setting the `stream=false`
437
+ request option to throw an exception.
438
+ See: https://github.com/guzzle/guzzle/issues/769
439
+ * TransactionIterator now calls rewind on the inner iterator.
440
+ See: https://github.com/guzzle/guzzle/pull/765
441
+ * You can now set the `Content-Type` header to `multipart/form-data`
442
+ when creating POST requests to force multipart bodies.
443
+ See https://github.com/guzzle/guzzle/issues/768
444
+
445
+ ## 4.1.7 - 2014-08-07
446
+
447
+ * Fixed an error in the HistoryPlugin that caused the same request and response
448
+ to be logged multiple times when an HTTP protocol error occurs.
449
+ * Ensuring that cURL does not add a default Content-Type when no Content-Type
450
+ has been supplied by the user. This prevents the adapter layer from modifying
451
+ the request that is sent over the wire after any listeners may have already
452
+ put the request in a desired state (e.g., signed the request).
453
+ * Throwing an exception when you attempt to send requests that have the
454
+ "stream" set to true in parallel using the MultiAdapter.
455
+ * Only calling curl_multi_select when there are active cURL handles. This was
456
+ previously changed and caused performance problems on some systems due to PHP
457
+ always selecting until the maximum select timeout.
458
+ * Fixed a bug where multipart/form-data POST fields were not correctly
459
+ aggregated (e.g., values with "&").
460
+
461
+ ## 4.1.6 - 2014-08-03
462
+
463
+ * Added helper methods to make it easier to represent messages as strings,
464
+ including getting the start line and getting headers as a string.
465
+
466
+ ## 4.1.5 - 2014-08-02
467
+
468
+ * Automatically retrying cURL "Connection died, retrying a fresh connect"
469
+ errors when possible.
470
+ * cURL implementation cleanup
471
+ * Allowing multiple event subscriber listeners to be registered per event by
472
+ passing an array of arrays of listener configuration.
473
+
474
+ ## 4.1.4 - 2014-07-22
475
+
476
+ * Fixed a bug that caused multi-part POST requests with more than one field to
477
+ serialize incorrectly.
478
+ * Paths can now be set to "0"
479
+ * `ResponseInterface::xml` now accepts a `libxml_options` option and added a
480
+ missing default argument that was required when parsing XML response bodies.
481
+ * A `save_to` stream is now created lazily, which means that files are not
482
+ created on disk unless a request succeeds.
483
+
484
+ ## 4.1.3 - 2014-07-15
485
+
486
+ * Various fixes to multipart/form-data POST uploads
487
+ * Wrapping function.php in an if-statement to ensure Guzzle can be used
488
+ globally and in a Composer install
489
+ * Fixed an issue with generating and merging in events to an event array
490
+ * POST headers are only applied before sending a request to allow you to change
491
+ the query aggregator used before uploading
492
+ * Added much more robust query string parsing
493
+ * Fixed various parsing and normalization issues with URLs
494
+ * Fixing an issue where multi-valued headers were not being utilized correctly
495
+ in the StreamAdapter
496
+
497
+ ## 4.1.2 - 2014-06-18
498
+
499
+ * Added support for sending payloads with GET requests
500
+
501
+ ## 4.1.1 - 2014-06-08
502
+
503
+ * Fixed an issue related to using custom message factory options in subclasses
504
+ * Fixed an issue with nested form fields in a multi-part POST
505
+ * Fixed an issue with using the `json` request option for POST requests
506
+ * Added `ToArrayInterface` to `GuzzleHttp\Cookie\CookieJar`
507
+
508
+ ## 4.1.0 - 2014-05-27
509
+
510
+ * Added a `json` request option to easily serialize JSON payloads.
511
+ * Added a `GuzzleHttp\json_decode()` wrapper to safely parse JSON.
512
+ * Added `setPort()` and `getPort()` to `GuzzleHttp\Message\RequestInterface`.
513
+ * Added the ability to provide an emitter to a client in the client constructor.
514
+ * Added the ability to persist a cookie session using $_SESSION.
515
+ * Added a trait that can be used to add event listeners to an iterator.
516
+ * Removed request method constants from RequestInterface.
517
+ * Fixed warning when invalid request start-lines are received.
518
+ * Updated MessageFactory to work with custom request option methods.
519
+ * Updated cacert bundle to latest build.
520
+
521
+ 4.0.2 (2014-04-16)
522
+ ------------------
523
+
524
+ * Proxy requests using the StreamAdapter now properly use request_fulluri (#632)
525
+ * Added the ability to set scalars as POST fields (#628)
526
+
527
+ ## 4.0.1 - 2014-04-04
528
+
529
+ * The HTTP status code of a response is now set as the exception code of
530
+ RequestException objects.
531
+ * 303 redirects will now correctly switch from POST to GET requests.
532
+ * The default parallel adapter of a client now correctly uses the MultiAdapter.
533
+ * HasDataTrait now initializes the internal data array as an empty array so
534
+ that the toArray() method always returns an array.
535
+
536
+ ## 4.0.0 - 2014-03-29
537
+
538
+ * For more information on the 4.0 transition, see:
539
+ http://mtdowling.com/blog/2014/03/15/guzzle-4-rc/
540
+ * For information on changes and upgrading, see:
541
+ https://github.com/guzzle/guzzle/blob/master/UPGRADING.md#3x-to-40
542
+ * Added `GuzzleHttp\batch()` as a convenience function for sending requests in
543
+ parallel without needing to write asynchronous code.
544
+ * Restructured how events are added to `GuzzleHttp\ClientInterface::sendAll()`.
545
+ You can now pass a callable or an array of associative arrays where each
546
+ associative array contains the "fn", "priority", and "once" keys.
547
+
548
+ ## 4.0.0.rc-2 - 2014-03-25
549
+
550
+ * Removed `getConfig()` and `setConfig()` from clients to avoid confusion
551
+ around whether things like base_url, message_factory, etc. should be able to
552
+ be retrieved or modified.
553
+ * Added `getDefaultOption()` and `setDefaultOption()` to ClientInterface
554
+ * functions.php functions were renamed using snake_case to match PHP idioms
555
+ * Added support for `HTTP_PROXY`, `HTTPS_PROXY`, and
556
+ `GUZZLE_CURL_SELECT_TIMEOUT` environment variables
557
+ * Added the ability to specify custom `sendAll()` event priorities
558
+ * Added the ability to specify custom stream context options to the stream
559
+ adapter.
560
+ * Added a functions.php function for `get_path()` and `set_path()`
561
+ * CurlAdapter and MultiAdapter now use a callable to generate curl resources
562
+ * MockAdapter now properly reads a body and emits a `headers` event
563
+ * Updated Url class to check if a scheme and host are set before adding ":"
564
+ and "//". This allows empty Url (e.g., "") to be serialized as "".
565
+ * Parsing invalid XML no longer emits warnings
566
+ * Curl classes now properly throw AdapterExceptions
567
+ * Various performance optimizations
568
+ * Streams are created with the faster `Stream\create()` function
569
+ * Marked deprecation_proxy() as internal
570
+ * Test server is now a collection of static methods on a class
571
+
572
+ ## 4.0.0-rc.1 - 2014-03-15
573
+
574
+ * See https://github.com/guzzle/guzzle/blob/master/UPGRADING.md#3x-to-40
575
+
576
+ ## 3.8.1 - 2014-01-28
577
+
578
+ * Bug: Always using GET requests when redirecting from a 303 response
579
+ * Bug: CURLOPT_SSL_VERIFYHOST is now correctly set to false when setting `$certificateAuthority` to false in
580
+ `Guzzle\Http\ClientInterface::setSslVerification()`
581
+ * Bug: RedirectPlugin now uses strict RFC 3986 compliance when combining a base URL with a relative URL
582
+ * Bug: The body of a request can now be set to `"0"`
583
+ * Sending PHP stream requests no longer forces `HTTP/1.0`
584
+ * Adding more information to ExceptionCollection exceptions so that users have more context, including a stack trace of
585
+ each sub-exception
586
+ * Updated the `$ref` attribute in service descriptions to merge over any existing parameters of a schema (rather than
587
+ clobbering everything).
588
+ * Merging URLs will now use the query string object from the relative URL (thus allowing custom query aggregators)
589
+ * Query strings are now parsed in a way that they do no convert empty keys with no value to have a dangling `=`.
590
+ For example `foo&bar=baz` is now correctly parsed and recognized as `foo&bar=baz` rather than `foo=&bar=baz`.
591
+ * Now properly escaping the regular expression delimiter when matching Cookie domains.
592
+ * Network access is now disabled when loading XML documents
593
+
594
+ ## 3.8.0 - 2013-12-05
595
+
596
+ * Added the ability to define a POST name for a file
597
+ * JSON response parsing now properly walks additionalProperties
598
+ * cURL error code 18 is now retried automatically in the BackoffPlugin
599
+ * Fixed a cURL error when URLs contain fragments
600
+ * Fixed an issue in the BackoffPlugin retry event where it was trying to access all exceptions as if they were
601
+ CurlExceptions
602
+ * CURLOPT_PROGRESS function fix for PHP 5.5 (69fcc1e)
603
+ * Added the ability for Guzzle to work with older versions of cURL that do not support `CURLOPT_TIMEOUT_MS`
604
+ * Fixed a bug that was encountered when parsing empty header parameters
605
+ * UriTemplate now has a `setRegex()` method to match the docs
606
+ * The `debug` request parameter now checks if it is truthy rather than if it exists
607
+ * Setting the `debug` request parameter to true shows verbose cURL output instead of using the LogPlugin
608
+ * Added the ability to combine URLs using strict RFC 3986 compliance
609
+ * Command objects can now return the validation errors encountered by the command
610
+ * Various fixes to cache revalidation (#437 and 29797e5)
611
+ * Various fixes to the AsyncPlugin
612
+ * Cleaned up build scripts
613
+
614
+ ## 3.7.4 - 2013-10-02
615
+
616
+ * Bug fix: 0 is now an allowed value in a description parameter that has a default value (#430)
617
+ * Bug fix: SchemaFormatter now returns an integer when formatting to a Unix timestamp
618
+ (see https://github.com/aws/aws-sdk-php/issues/147)
619
+ * Bug fix: Cleaned up and fixed URL dot segment removal to properly resolve internal dots
620
+ * Minimum PHP version is now properly specified as 5.3.3 (up from 5.3.2) (#420)
621
+ * Updated the bundled cacert.pem (#419)
622
+ * OauthPlugin now supports adding authentication to headers or query string (#425)
623
+
624
+ ## 3.7.3 - 2013-09-08
625
+
626
+ * Added the ability to get the exception associated with a request/command when using `MultiTransferException` and
627
+ `CommandTransferException`.
628
+ * Setting `additionalParameters` of a response to false is now honored when parsing responses with a service description
629
+ * Schemas are only injected into response models when explicitly configured.
630
+ * No longer guessing Content-Type based on the path of a request. Content-Type is now only guessed based on the path of
631
+ an EntityBody.
632
+ * Bug fix: ChunkedIterator can now properly chunk a \Traversable as well as an \Iterator.
633
+ * Bug fix: FilterIterator now relies on `\Iterator` instead of `\Traversable`.
634
+ * Bug fix: Gracefully handling malformed responses in RequestMediator::writeResponseBody()
635
+ * Bug fix: Replaced call to canCache with canCacheRequest in the CallbackCanCacheStrategy of the CachePlugin
636
+ * Bug fix: Visiting XML attributes first before visiting XML children when serializing requests
637
+ * Bug fix: Properly parsing headers that contain commas contained in quotes
638
+ * Bug fix: mimetype guessing based on a filename is now case-insensitive
639
+
640
+ ## 3.7.2 - 2013-08-02
641
+
642
+ * Bug fix: Properly URL encoding paths when using the PHP-only version of the UriTemplate expander
643
+ See https://github.com/guzzle/guzzle/issues/371
644
+ * Bug fix: Cookie domains are now matched correctly according to RFC 6265
645
+ See https://github.com/guzzle/guzzle/issues/377
646
+ * Bug fix: GET parameters are now used when calculating an OAuth signature
647
+ * Bug fix: Fixed an issue with cache revalidation where the If-None-Match header was being double quoted
648
+ * `Guzzle\Common\AbstractHasDispatcher::dispatch()` now returns the event that was dispatched
649
+ * `Guzzle\Http\QueryString::factory()` now guesses the most appropriate query aggregator to used based on the input.
650
+ See https://github.com/guzzle/guzzle/issues/379
651
+ * Added a way to add custom domain objects to service description parsing using the `operation.parse_class` event. See
652
+ https://github.com/guzzle/guzzle/pull/380
653
+ * cURL multi cleanup and optimizations
654
+
655
+ ## 3.7.1 - 2013-07-05
656
+
657
+ * Bug fix: Setting default options on a client now works
658
+ * Bug fix: Setting options on HEAD requests now works. See #352
659
+ * Bug fix: Moving stream factory before send event to before building the stream. See #353
660
+ * Bug fix: Cookies no longer match on IP addresses per RFC 6265
661
+ * Bug fix: Correctly parsing header parameters that are in `<>` and quotes
662
+ * Added `cert` and `ssl_key` as request options
663
+ * `Host` header can now diverge from the host part of a URL if the header is set manually
664
+ * `Guzzle\Service\Command\LocationVisitor\Request\XmlVisitor` was rewritten to change from using SimpleXML to XMLWriter
665
+ * OAuth parameters are only added via the plugin if they aren't already set
666
+ * Exceptions are now thrown when a URL cannot be parsed
667
+ * Returning `false` if `Guzzle\Http\EntityBody::getContentMd5()` fails
668
+ * Not setting a `Content-MD5` on a command if calculating the Content-MD5 fails via the CommandContentMd5Plugin
669
+
670
+ ## 3.7.0 - 2013-06-10
671
+
672
+ * See UPGRADING.md for more information on how to upgrade.
673
+ * Requests now support the ability to specify an array of $options when creating a request to more easily modify a
674
+ request. You can pass a 'request.options' configuration setting to a client to apply default request options to
675
+ every request created by a client (e.g. default query string variables, headers, curl options, etc.).
676
+ * Added a static facade class that allows you to use Guzzle with static methods and mount the class to `\Guzzle`.
677
+ See `Guzzle\Http\StaticClient::mount`.
678
+ * Added `command.request_options` to `Guzzle\Service\Command\AbstractCommand` to pass request options to requests
679
+ created by a command (e.g. custom headers, query string variables, timeout settings, etc.).
680
+ * Stream size in `Guzzle\Stream\PhpStreamRequestFactory` will now be set if Content-Length is returned in the
681
+ headers of a response
682
+ * Added `Guzzle\Common\Collection::setPath($path, $value)` to set a value into an array using a nested key
683
+ (e.g. `$collection->setPath('foo/baz/bar', 'test'); echo $collection['foo']['bar']['bar'];`)
684
+ * ServiceBuilders now support storing and retrieving arbitrary data
685
+ * CachePlugin can now purge all resources for a given URI
686
+ * CachePlugin can automatically purge matching cached items when a non-idempotent request is sent to a resource
687
+ * CachePlugin now uses the Vary header to determine if a resource is a cache hit
688
+ * `Guzzle\Http\Message\Response` now implements `\Serializable`
689
+ * Added `Guzzle\Cache\CacheAdapterFactory::fromCache()` to more easily create cache adapters
690
+ * `Guzzle\Service\ClientInterface::execute()` now accepts an array, single command, or Traversable
691
+ * Fixed a bug in `Guzzle\Http\Message\Header\Link::addLink()`
692
+ * Better handling of calculating the size of a stream in `Guzzle\Stream\Stream` using fstat() and caching the size
693
+ * `Guzzle\Common\Exception\ExceptionCollection` now creates a more readable exception message
694
+ * Fixing BC break: Added back the MonologLogAdapter implementation rather than extending from PsrLog so that older
695
+ Symfony users can still use the old version of Monolog.
696
+ * Fixing BC break: Added the implementation back in for `Guzzle\Http\Message\AbstractMessage::getTokenizedHeader()`.
697
+ Now triggering an E_USER_DEPRECATED warning when used. Use `$message->getHeader()->parseParams()`.
698
+ * Several performance improvements to `Guzzle\Common\Collection`
699
+ * Added an `$options` argument to the end of the following methods of `Guzzle\Http\ClientInterface`:
700
+ createRequest, head, delete, put, patch, post, options, prepareRequest
701
+ * Added an `$options` argument to the end of `Guzzle\Http\Message\Request\RequestFactoryInterface::createRequest()`
702
+ * Added an `applyOptions()` method to `Guzzle\Http\Message\Request\RequestFactoryInterface`
703
+ * Changed `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $body = null)` to
704
+ `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $options = array())`. You can still pass in a
705
+ resource, string, or EntityBody into the $options parameter to specify the download location of the response.
706
+ * Changed `Guzzle\Common\Collection::__construct($data)` to no longer accepts a null value for `$data` but a
707
+ default `array()`
708
+ * Added `Guzzle\Stream\StreamInterface::isRepeatable`
709
+ * Removed `Guzzle\Http\ClientInterface::setDefaultHeaders(). Use
710
+ $client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`. or
711
+ $client->getConfig()->setPath('request.options/headers', array('header_name' => 'value'))`.
712
+ * Removed `Guzzle\Http\ClientInterface::getDefaultHeaders(). Use $client->getConfig()->getPath('request.options/headers')`.
713
+ * Removed `Guzzle\Http\ClientInterface::expandTemplate()`
714
+ * Removed `Guzzle\Http\ClientInterface::setRequestFactory()`
715
+ * Removed `Guzzle\Http\ClientInterface::getCurlMulti()`
716
+ * Removed `Guzzle\Http\Message\RequestInterface::canCache`
717
+ * Removed `Guzzle\Http\Message\RequestInterface::setIsRedirect`
718
+ * Removed `Guzzle\Http\Message\RequestInterface::isRedirect`
719
+ * Made `Guzzle\Http\Client::expandTemplate` and `getUriTemplate` protected methods.
720
+ * You can now enable E_USER_DEPRECATED warnings to see if you are using a deprecated method by setting
721
+ `Guzzle\Common\Version::$emitWarnings` to true.
722
+ * Marked `Guzzle\Http\Message\Request::isResponseBodyRepeatable()` as deprecated. Use
723
+ `$request->getResponseBody()->isRepeatable()` instead.
724
+ * Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use
725
+ `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead.
726
+ * Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use
727
+ `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead.
728
+ * Marked `Guzzle\Http\Message\Request::setIsRedirect()` as deprecated. Use the HistoryPlugin instead.
729
+ * Marked `Guzzle\Http\Message\Request::isRedirect()` as deprecated. Use the HistoryPlugin instead.
730
+ * Marked `Guzzle\Cache\CacheAdapterFactory::factory()` as deprecated
731
+ * Marked 'command.headers', 'command.response_body' and 'command.on_complete' as deprecated for AbstractCommand.
732
+ These will work through Guzzle 4.0
733
+ * Marked 'request.params' for `Guzzle\Http\Client` as deprecated. Use [request.options][params].
734
+ * Marked `Guzzle\Service\Client::enableMagicMethods()` as deprecated. Magic methods can no longer be disabled on a Guzzle\Service\Client.
735
+ * Marked `Guzzle\Service\Client::getDefaultHeaders()` as deprecated. Use $client->getConfig()->getPath('request.options/headers')`.
736
+ * Marked `Guzzle\Service\Client::setDefaultHeaders()` as deprecated. Use $client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`.
737
+ * Marked `Guzzle\Parser\Url\UrlParser` as deprecated. Just use PHP's `parse_url()` and percent encode your UTF-8.
738
+ * Marked `Guzzle\Common\Collection::inject()` as deprecated.
739
+ * Marked `Guzzle\Plugin\CurlAuth\CurlAuthPlugin` as deprecated. Use `$client->getConfig()->setPath('request.options/auth', array('user', 'pass', 'Basic|Digest');`
740
+ * CacheKeyProviderInterface and DefaultCacheKeyProvider are no longer used. All of this logic is handled in a
741
+ CacheStorageInterface. These two objects and interface will be removed in a future version.
742
+ * Always setting X-cache headers on cached responses
743
+ * Default cache TTLs are now handled by the CacheStorageInterface of a CachePlugin
744
+ * `CacheStorageInterface::cache($key, Response $response, $ttl = null)` has changed to `cache(RequestInterface
745
+ $request, Response $response);`
746
+ * `CacheStorageInterface::fetch($key)` has changed to `fetch(RequestInterface $request);`
747
+ * `CacheStorageInterface::delete($key)` has changed to `delete(RequestInterface $request);`
748
+ * Added `CacheStorageInterface::purge($url)`
749
+ * `DefaultRevalidation::__construct(CacheKeyProviderInterface $cacheKey, CacheStorageInterface $cache, CachePlugin
750
+ $plugin)` has changed to `DefaultRevalidation::__construct(CacheStorageInterface $cache,
751
+ CanCacheStrategyInterface $canCache = null)`
752
+ * Added `RevalidationInterface::shouldRevalidate(RequestInterface $request, Response $response)`
753
+
754
+ ## 3.6.0 - 2013-05-29
755
+
756
+ * ServiceDescription now implements ToArrayInterface
757
+ * Added command.hidden_params to blacklist certain headers from being treated as additionalParameters
758
+ * Guzzle can now correctly parse incomplete URLs
759
+ * Mixed casing of headers are now forced to be a single consistent casing across all values for that header.
760
+ * Messages internally use a HeaderCollection object to delegate handling case-insensitive header resolution
761
+ * Removed the whole changedHeader() function system of messages because all header changes now go through addHeader().
762
+ * Specific header implementations can be created for complex headers. When a message creates a header, it uses a
763
+ HeaderFactory which can map specific headers to specific header classes. There is now a Link header and
764
+ CacheControl header implementation.
765
+ * Removed from interface: Guzzle\Http\ClientInterface::setUriTemplate
766
+ * Removed from interface: Guzzle\Http\ClientInterface::setCurlMulti()
767
+ * Removed Guzzle\Http\Message\Request::receivedRequestHeader() and implemented this functionality in
768
+ Guzzle\Http\Curl\RequestMediator
769
+ * Removed the optional $asString parameter from MessageInterface::getHeader(). Just cast the header to a string.
770
+ * Removed the optional $tryChunkedTransfer option from Guzzle\Http\Message\EntityEnclosingRequestInterface
771
+ * Removed the $asObjects argument from Guzzle\Http\Message\MessageInterface::getHeaders()
772
+ * Removed Guzzle\Parser\ParserRegister::get(). Use getParser()
773
+ * Removed Guzzle\Parser\ParserRegister::set(). Use registerParser().
774
+ * All response header helper functions return a string rather than mixing Header objects and strings inconsistently
775
+ * Removed cURL blacklist support. This is no longer necessary now that Expect, Accept, etc. are managed by Guzzle
776
+ directly via interfaces
777
+ * Removed the injecting of a request object onto a response object. The methods to get and set a request still exist
778
+ but are a no-op until removed.
779
+ * Most classes that used to require a `Guzzle\Service\Command\CommandInterface` typehint now request a
780
+ `Guzzle\Service\Command\ArrayCommandInterface`.
781
+ * Added `Guzzle\Http\Message\RequestInterface::startResponse()` to the RequestInterface to handle injecting a response
782
+ on a request while the request is still being transferred
783
+ * The ability to case-insensitively search for header values
784
+ * Guzzle\Http\Message\Header::hasExactHeader
785
+ * Guzzle\Http\Message\Header::raw. Use getAll()
786
+ * Deprecated cache control specific methods on Guzzle\Http\Message\AbstractMessage. Use the CacheControl header object
787
+ instead.
788
+ * `Guzzle\Service\Command\CommandInterface` now extends from ToArrayInterface and ArrayAccess
789
+ * Added the ability to cast Model objects to a string to view debug information.
790
+
791
+ ## 3.5.0 - 2013-05-13
792
+
793
+ * Bug: Fixed a regression so that request responses are parsed only once per oncomplete event rather than multiple times
794
+ * Bug: Better cleanup of one-time events across the board (when an event is meant to fire once, it will now remove
795
+ itself from the EventDispatcher)
796
+ * Bug: `Guzzle\Log\MessageFormatter` now properly writes "total_time" and "connect_time" values
797
+ * Bug: Cloning an EntityEnclosingRequest now clones the EntityBody too
798
+ * Bug: Fixed an undefined index error when parsing nested JSON responses with a sentAs parameter that reference a
799
+ non-existent key
800
+ * Bug: All __call() method arguments are now required (helps with mocking frameworks)
801
+ * Deprecating Response::getRequest() and now using a shallow clone of a request object to remove a circular reference
802
+ to help with refcount based garbage collection of resources created by sending a request
803
+ * Deprecating ZF1 cache and log adapters. These will be removed in the next major version.
804
+ * Deprecating `Response::getPreviousResponse()` (method signature still exists, but it's deprecated). Use the
805
+ HistoryPlugin for a history.
806
+ * Added a `responseBody` alias for the `response_body` location
807
+ * Refactored internals to no longer rely on Response::getRequest()
808
+ * HistoryPlugin can now be cast to a string
809
+ * HistoryPlugin now logs transactions rather than requests and responses to more accurately keep track of the requests
810
+ and responses that are sent over the wire
811
+ * Added `getEffectiveUrl()` and `getRedirectCount()` to Response objects
812
+
813
+ ## 3.4.3 - 2013-04-30
814
+
815
+ * Bug fix: Fixing bug introduced in 3.4.2 where redirect responses are duplicated on the final redirected response
816
+ * Added a check to re-extract the temp cacert bundle from the phar before sending each request
817
+
818
+ ## 3.4.2 - 2013-04-29
819
+
820
+ * Bug fix: Stream objects now work correctly with "a" and "a+" modes
821
+ * Bug fix: Removing `Transfer-Encoding: chunked` header when a Content-Length is present
822
+ * Bug fix: AsyncPlugin no longer forces HEAD requests
823
+ * Bug fix: DateTime timezones are now properly handled when using the service description schema formatter
824
+ * Bug fix: CachePlugin now properly handles stale-if-error directives when a request to the origin server fails
825
+ * Setting a response on a request will write to the custom request body from the response body if one is specified
826
+ * LogPlugin now writes to php://output when STDERR is undefined
827
+ * Added the ability to set multiple POST files for the same key in a single call
828
+ * application/x-www-form-urlencoded POSTs now use the utf-8 charset by default
829
+ * Added the ability to queue CurlExceptions to the MockPlugin
830
+ * Cleaned up how manual responses are queued on requests (removed "queued_response" and now using request.before_send)
831
+ * Configuration loading now allows remote files
832
+
833
+ ## 3.4.1 - 2013-04-16
834
+
835
+ * Large refactoring to how CurlMulti handles work. There is now a proxy that sits in front of a pool of CurlMulti
836
+ handles. This greatly simplifies the implementation, fixes a couple bugs, and provides a small performance boost.
837
+ * Exceptions are now properly grouped when sending requests in parallel
838
+ * Redirects are now properly aggregated when a multi transaction fails
839
+ * Redirects now set the response on the original object even in the event of a failure
840
+ * Bug fix: Model names are now properly set even when using $refs
841
+ * Added support for PHP 5.5's CurlFile to prevent warnings with the deprecated @ syntax
842
+ * Added support for oauth_callback in OAuth signatures
843
+ * Added support for oauth_verifier in OAuth signatures
844
+ * Added support to attempt to retrieve a command first literally, then ucfirst, the with inflection
845
+
846
+ ## 3.4.0 - 2013-04-11
847
+
848
+ * Bug fix: URLs are now resolved correctly based on http://tools.ietf.org/html/rfc3986#section-5.2. #289
849
+ * Bug fix: Absolute URLs with a path in a service description will now properly override the base URL. #289
850
+ * Bug fix: Parsing a query string with a single PHP array value will now result in an array. #263
851
+ * Bug fix: Better normalization of the User-Agent header to prevent duplicate headers. #264.
852
+ * Bug fix: Added `number` type to service descriptions.
853
+ * Bug fix: empty parameters are removed from an OAuth signature
854
+ * Bug fix: Revalidating a cache entry prefers the Last-Modified over the Date header
855
+ * Bug fix: Fixed "array to string" error when validating a union of types in a service description
856
+ * Bug fix: Removed code that attempted to determine the size of a stream when data is written to the stream
857
+ * Bug fix: Not including an `oauth_token` if the value is null in the OauthPlugin.
858
+ * Bug fix: Now correctly aggregating successful requests and failed requests in CurlMulti when a redirect occurs.
859
+ * The new default CURLOPT_TIMEOUT setting has been increased to 150 seconds so that Guzzle works on poor connections.
860
+ * Added a feature to EntityEnclosingRequest::setBody() that will automatically set the Content-Type of the request if
861
+ the Content-Type can be determined based on the entity body or the path of the request.
862
+ * Added the ability to overwrite configuration settings in a client when grabbing a throwaway client from a builder.
863
+ * Added support for a PSR-3 LogAdapter.
864
+ * Added a `command.after_prepare` event
865
+ * Added `oauth_callback` parameter to the OauthPlugin
866
+ * Added the ability to create a custom stream class when using a stream factory
867
+ * Added a CachingEntityBody decorator
868
+ * Added support for `additionalParameters` in service descriptions to define how custom parameters are serialized.
869
+ * The bundled SSL certificate is now provided in the phar file and extracted when running Guzzle from a phar.
870
+ * You can now send any EntityEnclosingRequest with POST fields or POST files and cURL will handle creating bodies
871
+ * POST requests using a custom entity body are now treated exactly like PUT requests but with a custom cURL method. This
872
+ means that the redirect behavior of POST requests with custom bodies will not be the same as POST requests that use
873
+ POST fields or files (the latter is only used when emulating a form POST in the browser).
874
+ * Lots of cleanup to CurlHandle::factory and RequestFactory::createRequest
875
+
876
+ ## 3.3.1 - 2013-03-10
877
+
878
+ * Added the ability to create PHP streaming responses from HTTP requests
879
+ * Bug fix: Running any filters when parsing response headers with service descriptions
880
+ * Bug fix: OauthPlugin fixes to allow for multi-dimensional array signing, and sorting parameters before signing
881
+ * Bug fix: Removed the adding of default empty arrays and false Booleans to responses in order to be consistent across
882
+ response location visitors.
883
+ * Bug fix: Removed the possibility of creating configuration files with circular dependencies
884
+ * RequestFactory::create() now uses the key of a POST file when setting the POST file name
885
+ * Added xmlAllowEmpty to serialize an XML body even if no XML specific parameters are set
886
+
887
+ ## 3.3.0 - 2013-03-03
888
+
889
+ * A large number of performance optimizations have been made
890
+ * Bug fix: Added 'wb' as a valid write mode for streams
891
+ * Bug fix: `Guzzle\Http\Message\Response::json()` now allows scalar values to be returned
892
+ * Bug fix: Fixed bug in `Guzzle\Http\Message\Response` where wrapping quotes were stripped from `getEtag()`
893
+ * BC: Removed `Guzzle\Http\Utils` class
894
+ * BC: Setting a service description on a client will no longer modify the client's command factories.
895
+ * BC: Emitting IO events from a RequestMediator is now a parameter that must be set in a request's curl options using
896
+ the 'emit_io' key. This was previously set under a request's parameters using 'curl.emit_io'
897
+ * BC: `Guzzle\Stream\Stream::getWrapper()` and `Guzzle\Stream\Stream::getSteamType()` are no longer converted to
898
+ lowercase
899
+ * Operation parameter objects are now lazy loaded internally
900
+ * Added ErrorResponsePlugin that can throw errors for responses defined in service description operations' errorResponses
901
+ * Added support for instantiating responseType=class responseClass classes. Classes must implement
902
+ `Guzzle\Service\Command\ResponseClassInterface`
903
+ * Added support for additionalProperties for top-level parameters in responseType=model responseClasses. These
904
+ additional properties also support locations and can be used to parse JSON responses where the outermost part of the
905
+ JSON is an array
906
+ * Added support for nested renaming of JSON models (rename sentAs to name)
907
+ * CachePlugin
908
+ * Added support for stale-if-error so that the CachePlugin can now serve stale content from the cache on error
909
+ * Debug headers can now added to cached response in the CachePlugin
910
+
911
+ ## 3.2.0 - 2013-02-14
912
+
913
+ * CurlMulti is no longer reused globally. A new multi object is created per-client. This helps to isolate clients.
914
+ * URLs with no path no longer contain a "/" by default
915
+ * Guzzle\Http\QueryString does no longer manages the leading "?". This is now handled in Guzzle\Http\Url.
916
+ * BadResponseException no longer includes the full request and response message
917
+ * Adding setData() to Guzzle\Service\Description\ServiceDescriptionInterface
918
+ * Adding getResponseBody() to Guzzle\Http\Message\RequestInterface
919
+ * Various updates to classes to use ServiceDescriptionInterface type hints rather than ServiceDescription
920
+ * Header values can now be normalized into distinct values when multiple headers are combined with a comma separated list
921
+ * xmlEncoding can now be customized for the XML declaration of a XML service description operation
922
+ * Guzzle\Http\QueryString now uses Guzzle\Http\QueryAggregator\QueryAggregatorInterface objects to add custom value
923
+ aggregation and no longer uses callbacks
924
+ * The URL encoding implementation of Guzzle\Http\QueryString can now be customized
925
+ * Bug fix: Filters were not always invoked for array service description parameters
926
+ * Bug fix: Redirects now use a target response body rather than a temporary response body
927
+ * Bug fix: The default exponential backoff BackoffPlugin was not giving when the request threshold was exceeded
928
+ * Bug fix: Guzzle now takes the first found value when grabbing Cache-Control directives
929
+
930
+ ## 3.1.2 - 2013-01-27
931
+
932
+ * Refactored how operation responses are parsed. Visitors now include a before() method responsible for parsing the
933
+ response body. For example, the XmlVisitor now parses the XML response into an array in the before() method.
934
+ * Fixed an issue where cURL would not automatically decompress responses when the Accept-Encoding header was sent
935
+ * CURLOPT_SSL_VERIFYHOST is never set to 1 because it is deprecated (see 5e0ff2ef20f839e19d1eeb298f90ba3598784444)
936
+ * Fixed a bug where redirect responses were not chained correctly using getPreviousResponse()
937
+ * Setting default headers on a client after setting the user-agent will not erase the user-agent setting
938
+
939
+ ## 3.1.1 - 2013-01-20
940
+
941
+ * Adding wildcard support to Guzzle\Common\Collection::getPath()
942
+ * Adding alias support to ServiceBuilder configs
943
+ * Adding Guzzle\Service\Resource\CompositeResourceIteratorFactory and cleaning up factory interface
944
+
945
+ ## 3.1.0 - 2013-01-12
946
+
947
+ * BC: CurlException now extends from RequestException rather than BadResponseException
948
+ * BC: Renamed Guzzle\Plugin\Cache\CanCacheStrategyInterface::canCache() to canCacheRequest() and added CanCacheResponse()
949
+ * Added getData to ServiceDescriptionInterface
950
+ * Added context array to RequestInterface::setState()
951
+ * Bug: Removing hard dependency on the BackoffPlugin from Guzzle\Http
952
+ * Bug: Adding required content-type when JSON request visitor adds JSON to a command
953
+ * Bug: Fixing the serialization of a service description with custom data
954
+ * Made it easier to deal with exceptions thrown when transferring commands or requests in parallel by providing
955
+ an array of successful and failed responses
956
+ * Moved getPath from Guzzle\Service\Resource\Model to Guzzle\Common\Collection
957
+ * Added Guzzle\Http\IoEmittingEntityBody
958
+ * Moved command filtration from validators to location visitors
959
+ * Added `extends` attributes to service description parameters
960
+ * Added getModels to ServiceDescriptionInterface
961
+
962
+ ## 3.0.7 - 2012-12-19
963
+
964
+ * Fixing phar detection when forcing a cacert to system if null or true
965
+ * Allowing filename to be passed to `Guzzle\Http\Message\Request::setResponseBody()`
966
+ * Cleaning up `Guzzle\Common\Collection::inject` method
967
+ * Adding a response_body location to service descriptions
968
+
969
+ ## 3.0.6 - 2012-12-09
970
+
971
+ * CurlMulti performance improvements
972
+ * Adding setErrorResponses() to Operation
973
+ * composer.json tweaks
974
+
975
+ ## 3.0.5 - 2012-11-18
976
+
977
+ * Bug: Fixing an infinite recursion bug caused from revalidating with the CachePlugin
978
+ * Bug: Response body can now be a string containing "0"
979
+ * Bug: Using Guzzle inside of a phar uses system by default but now allows for a custom cacert
980
+ * Bug: QueryString::fromString now properly parses query string parameters that contain equal signs
981
+ * Added support for XML attributes in service description responses
982
+ * DefaultRequestSerializer now supports array URI parameter values for URI template expansion
983
+ * Added better mimetype guessing to requests and post files
984
+
985
+ ## 3.0.4 - 2012-11-11
986
+
987
+ * Bug: Fixed a bug when adding multiple cookies to a request to use the correct glue value
988
+ * Bug: Cookies can now be added that have a name, domain, or value set to "0"
989
+ * Bug: Using the system cacert bundle when using the Phar
990
+ * Added json and xml methods to Response to make it easier to parse JSON and XML response data into data structures
991
+ * Enhanced cookie jar de-duplication
992
+ * Added the ability to enable strict cookie jars that throw exceptions when invalid cookies are added
993
+ * Added setStream to StreamInterface to actually make it possible to implement custom rewind behavior for entity bodies
994
+ * Added the ability to create any sort of hash for a stream rather than just an MD5 hash
995
+
996
+ ## 3.0.3 - 2012-11-04
997
+
998
+ * Implementing redirects in PHP rather than cURL
999
+ * Added PECL URI template extension and using as default parser if available
1000
+ * Bug: Fixed Content-Length parsing of Response factory
1001
+ * Adding rewind() method to entity bodies and streams. Allows for custom rewinding of non-repeatable streams.
1002
+ * Adding ToArrayInterface throughout library
1003
+ * Fixing OauthPlugin to create unique nonce values per request
1004
+
1005
+ ## 3.0.2 - 2012-10-25
1006
+
1007
+ * Magic methods are enabled by default on clients
1008
+ * Magic methods return the result of a command
1009
+ * Service clients no longer require a base_url option in the factory
1010
+ * Bug: Fixed an issue with URI templates where null template variables were being expanded
1011
+
1012
+ ## 3.0.1 - 2012-10-22
1013
+
1014
+ * Models can now be used like regular collection objects by calling filter, map, etc.
1015
+ * Models no longer require a Parameter structure or initial data in the constructor
1016
+ * Added a custom AppendIterator to get around a PHP bug with the `\AppendIterator`
1017
+
1018
+ ## 3.0.0 - 2012-10-15
1019
+
1020
+ * Rewrote service description format to be based on Swagger
1021
+ * Now based on JSON schema
1022
+ * Added nested input structures and nested response models
1023
+ * Support for JSON and XML input and output models
1024
+ * Renamed `commands` to `operations`
1025
+ * Removed dot class notation
1026
+ * Removed custom types
1027
+ * Broke the project into smaller top-level namespaces to be more component friendly
1028
+ * Removed support for XML configs and descriptions. Use arrays or JSON files.
1029
+ * Removed the Validation component and Inspector
1030
+ * Moved all cookie code to Guzzle\Plugin\Cookie
1031
+ * Magic methods on a Guzzle\Service\Client now return the command un-executed.
1032
+ * Calling getResult() or getResponse() on a command will lazily execute the command if needed.
1033
+ * Now shipping with cURL's CA certs and using it by default
1034
+ * Added previousResponse() method to response objects
1035
+ * No longer sending Accept and Accept-Encoding headers on every request
1036
+ * Only sending an Expect header by default when a payload is greater than 1MB
1037
+ * Added/moved client options:
1038
+ * curl.blacklist to curl.option.blacklist
1039
+ * Added ssl.certificate_authority
1040
+ * Added a Guzzle\Iterator component
1041
+ * Moved plugins from Guzzle\Http\Plugin to Guzzle\Plugin
1042
+ * Added a more robust backoff retry strategy (replaced the ExponentialBackoffPlugin)
1043
+ * Added a more robust caching plugin
1044
+ * Added setBody to response objects
1045
+ * Updating LogPlugin to use a more flexible MessageFormatter
1046
+ * Added a completely revamped build process
1047
+ * Cleaning up Collection class and removing default values from the get method
1048
+ * Fixed ZF2 cache adapters
1049
+
1050
+ ## 2.8.8 - 2012-10-15
1051
+
1052
+ * Bug: Fixed a cookie issue that caused dot prefixed domains to not match where popular browsers did
1053
+
1054
+ ## 2.8.7 - 2012-09-30
1055
+
1056
+ * Bug: Fixed config file aliases for JSON includes
1057
+ * Bug: Fixed cookie bug on a request object by using CookieParser to parse cookies on requests
1058
+ * Bug: Removing the path to a file when sending a Content-Disposition header on a POST upload
1059
+ * Bug: Hardening request and response parsing to account for missing parts
1060
+ * Bug: Fixed PEAR packaging
1061
+ * Bug: Fixed Request::getInfo
1062
+ * Bug: Fixed cases where CURLM_CALL_MULTI_PERFORM return codes were causing curl transactions to fail
1063
+ * Adding the ability for the namespace Iterator factory to look in multiple directories
1064
+ * Added more getters/setters/removers from service descriptions
1065
+ * Added the ability to remove POST fields from OAuth signatures
1066
+ * OAuth plugin now supports 2-legged OAuth
1067
+
1068
+ ## 2.8.6 - 2012-09-05
1069
+
1070
+ * Added the ability to modify and build service descriptions
1071
+ * Added the use of visitors to apply parameters to locations in service descriptions using the dynamic command
1072
+ * Added a `json` parameter location
1073
+ * Now allowing dot notation for classes in the CacheAdapterFactory
1074
+ * Using the union of two arrays rather than an array_merge when extending service builder services and service params
1075
+ * Ensuring that a service is a string before doing strpos() checks on it when substituting services for references
1076
+ in service builder config files.
1077
+ * Services defined in two different config files that include one another will by default replace the previously
1078
+ defined service, but you can now create services that extend themselves and merge their settings over the previous
1079
+ * The JsonLoader now supports aliasing filenames with different filenames. This allows you to alias something like
1080
+ '_default' with a default JSON configuration file.
1081
+
1082
+ ## 2.8.5 - 2012-08-29
1083
+
1084
+ * Bug: Suppressed empty arrays from URI templates
1085
+ * Bug: Added the missing $options argument from ServiceDescription::factory to enable caching
1086
+ * Added support for HTTP responses that do not contain a reason phrase in the start-line
1087
+ * AbstractCommand commands are now invokable
1088
+ * Added a way to get the data used when signing an Oauth request before a request is sent
1089
+
1090
+ ## 2.8.4 - 2012-08-15
1091
+
1092
+ * Bug: Custom delay time calculations are no longer ignored in the ExponentialBackoffPlugin
1093
+ * 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.
1094
+ * Added a StreamInterface, EntityBodyInterface, and added ftell() to Guzzle\Common\Stream
1095
+ * Added an AbstractEntityBodyDecorator and a ReadLimitEntityBody decorator to transfer only a subset of a decorated stream
1096
+ * Stream and EntityBody objects will now return the file position to the previous position after a read required operation (e.g. getContentMd5())
1097
+ * Added additional response status codes
1098
+ * Removed SSL information from the default User-Agent header
1099
+ * DELETE requests can now send an entity body
1100
+ * Added an EventDispatcher to the ExponentialBackoffPlugin and added an ExponentialBackoffLogger to log backoff retries
1101
+ * Added the ability of the MockPlugin to consume mocked request bodies
1102
+ * LogPlugin now exposes request and response objects in the extras array
1103
+
1104
+ ## 2.8.3 - 2012-07-30
1105
+
1106
+ * Bug: Fixed a case where empty POST requests were sent as GET requests
1107
+ * Bug: Fixed a bug in ExponentialBackoffPlugin that caused fatal errors when retrying an EntityEnclosingRequest that does not have a body
1108
+ * Bug: Setting the response body of a request to null after completing a request, not when setting the state of a request to new
1109
+ * Added multiple inheritance to service description commands
1110
+ * Added an ApiCommandInterface and added `getParamNames()` and `hasParam()`
1111
+ * Removed the default 2mb size cutoff from the Md5ValidatorPlugin so that it now defaults to validating everything
1112
+ * Changed CurlMulti::perform to pass a smaller timeout to CurlMulti::executeHandles
1113
+
1114
+ ## 2.8.2 - 2012-07-24
1115
+
1116
+ * Bug: Query string values set to 0 are no longer dropped from the query string
1117
+ * Bug: A Collection object is no longer created each time a call is made to `Guzzle\Service\Command\AbstractCommand::getRequestHeaders()`
1118
+ * Bug: `+` is now treated as an encoded space when parsing query strings
1119
+ * QueryString and Collection performance improvements
1120
+ * Allowing dot notation for class paths in filters attribute of a service descriptions
1121
+
1122
+ ## 2.8.1 - 2012-07-16
1123
+
1124
+ * Loosening Event Dispatcher dependency
1125
+ * POST redirects can now be customized using CURLOPT_POSTREDIR
1126
+
1127
+ ## 2.8.0 - 2012-07-15
1128
+
1129
+ * BC: Guzzle\Http\Query
1130
+ * Query strings with empty variables will always show an equal sign unless the variable is set to QueryString::BLANK (e.g. ?acl= vs ?acl)
1131
+ * Changed isEncodingValues() and isEncodingFields() to isUrlEncoding()
1132
+ * Changed setEncodeValues(bool) and setEncodeFields(bool) to useUrlEncoding(bool)
1133
+ * Changed the aggregation functions of QueryString to be static methods
1134
+ * Can now use fromString() with querystrings that have a leading ?
1135
+ * cURL configuration values can be specified in service descriptions using `curl.` prefixed parameters
1136
+ * Content-Length is set to 0 before emitting the request.before_send event when sending an empty request body
1137
+ * Cookies are no longer URL decoded by default
1138
+ * Bug: URI template variables set to null are no longer expanded
1139
+
1140
+ ## 2.7.2 - 2012-07-02
1141
+
1142
+ * BC: Moving things to get ready for subtree splits. Moving Inflection into Common. Moving Guzzle\Http\Parser to Guzzle\Parser.
1143
+ * BC: Removing Guzzle\Common\Batch\Batch::count() and replacing it with isEmpty()
1144
+ * CachePlugin now allows for a custom request parameter function to check if a request can be cached
1145
+ * Bug fix: CachePlugin now only caches GET and HEAD requests by default
1146
+ * Bug fix: Using header glue when transferring headers over the wire
1147
+ * Allowing deeply nested arrays for composite variables in URI templates
1148
+ * Batch divisors can now return iterators or arrays
1149
+
1150
+ ## 2.7.1 - 2012-06-26
1151
+
1152
+ * Minor patch to update version number in UA string
1153
+ * Updating build process
1154
+
1155
+ ## 2.7.0 - 2012-06-25
1156
+
1157
+ * BC: Inflection classes moved to Guzzle\Inflection. No longer static methods. Can now inject custom inflectors into classes.
1158
+ * BC: Removed magic setX methods from commands
1159
+ * BC: Magic methods mapped to service description commands are now inflected in the command factory rather than the client __call() method
1160
+ * Verbose cURL options are no longer enabled by default. Set curl.debug to true on a client to enable.
1161
+ * Bug: Now allowing colons in a response start-line (e.g. HTTP/1.1 503 Service Unavailable: Back-end server is at capacity)
1162
+ * Guzzle\Service\Resource\ResourceIteratorApplyBatched now internally uses the Guzzle\Common\Batch namespace
1163
+ * Added Guzzle\Service\Plugin namespace and a PluginCollectionPlugin
1164
+ * Added the ability to set POST fields and files in a service description
1165
+ * Guzzle\Http\EntityBody::factory() now accepts objects with a __toString() method
1166
+ * Adding a command.before_prepare event to clients
1167
+ * Added BatchClosureTransfer and BatchClosureDivisor
1168
+ * BatchTransferException now includes references to the batch divisor and transfer strategies
1169
+ * Fixed some tests so that they pass more reliably
1170
+ * Added Guzzle\Common\Log\ArrayLogAdapter
1171
+
1172
+ ## 2.6.6 - 2012-06-10
1173
+
1174
+ * BC: Removing Guzzle\Http\Plugin\BatchQueuePlugin
1175
+ * BC: Removing Guzzle\Service\Command\CommandSet
1176
+ * Adding generic batching system (replaces the batch queue plugin and command set)
1177
+ * Updating ZF cache and log adapters and now using ZF's composer repository
1178
+ * Bug: Setting the name of each ApiParam when creating through an ApiCommand
1179
+ * Adding result_type, result_doc, deprecated, and doc_url to service descriptions
1180
+ * Bug: Changed the default cookie header casing back to 'Cookie'
1181
+
1182
+ ## 2.6.5 - 2012-06-03
1183
+
1184
+ * BC: Renaming Guzzle\Http\Message\RequestInterface::getResourceUri() to getResource()
1185
+ * BC: Removing unused AUTH_BASIC and AUTH_DIGEST constants from
1186
+ * BC: Guzzle\Http\Cookie is now used to manage Set-Cookie data, not Cookie data
1187
+ * BC: Renaming methods in the CookieJarInterface
1188
+ * Moving almost all cookie logic out of the CookiePlugin and into the Cookie or CookieJar implementations
1189
+ * Making the default glue for HTTP headers ';' instead of ','
1190
+ * Adding a removeValue to Guzzle\Http\Message\Header
1191
+ * Adding getCookies() to request interface.
1192
+ * Making it easier to add event subscribers to HasDispatcherInterface classes. Can now directly call addSubscriber()
1193
+
1194
+ ## 2.6.4 - 2012-05-30
1195
+
1196
+ * BC: Cleaning up how POST files are stored in EntityEnclosingRequest objects. Adding PostFile class.
1197
+ * BC: Moving ApiCommand specific functionality from the Inspector and on to the ApiCommand
1198
+ * Bug: Fixing magic method command calls on clients
1199
+ * Bug: Email constraint only validates strings
1200
+ * Bug: Aggregate POST fields when POST files are present in curl handle
1201
+ * Bug: Fixing default User-Agent header
1202
+ * Bug: Only appending or prepending parameters in commands if they are specified
1203
+ * Bug: Not requiring response reason phrases or status codes to match a predefined list of codes
1204
+ * Allowing the use of dot notation for class namespaces when using instance_of constraint
1205
+ * Added any_match validation constraint
1206
+ * Added an AsyncPlugin
1207
+ * Passing request object to the calculateWait method of the ExponentialBackoffPlugin
1208
+ * Allowing the result of a command object to be changed
1209
+ * Parsing location and type sub values when instantiating a service description rather than over and over at runtime
1210
+
1211
+ ## 2.6.3 - 2012-05-23
1212
+
1213
+ * [BC] Guzzle\Common\FromConfigInterface no longer requires any config options.
1214
+ * [BC] Refactoring how POST files are stored on an EntityEnclosingRequest. They are now separate from POST fields.
1215
+ * You can now use an array of data when creating PUT request bodies in the request factory.
1216
+ * Removing the requirement that HTTPS requests needed a Cache-Control: public directive to be cacheable.
1217
+ * [Http] Adding support for Content-Type in multipart POST uploads per upload
1218
+ * [Http] Added support for uploading multiple files using the same name (foo[0], foo[1])
1219
+ * Adding more POST data operations for easier manipulation of POST data.
1220
+ * You can now set empty POST fields.
1221
+ * The body of a request is only shown on EntityEnclosingRequest objects that do not use POST files.
1222
+ * Split the Guzzle\Service\Inspector::validateConfig method into two methods. One to initialize when a command is created, and one to validate.
1223
+ * CS updates
1224
+
1225
+ ## 2.6.2 - 2012-05-19
1226
+
1227
+ * [Http] Better handling of nested scope requests in CurlMulti. Requests are now always prepares in the send() method rather than the addRequest() method.
1228
+
1229
+ ## 2.6.1 - 2012-05-19
1230
+
1231
+ * [BC] Removing 'path' support in service descriptions. Use 'uri'.
1232
+ * [BC] Guzzle\Service\Inspector::parseDocBlock is now protected. Adding getApiParamsForClass() with cache.
1233
+ * [BC] Removing Guzzle\Common\NullObject. Use https://github.com/mtdowling/NullObject if you need it.
1234
+ * [BC] Removing Guzzle\Common\XmlElement.
1235
+ * All commands, both dynamic and concrete, have ApiCommand objects.
1236
+ * Adding a fix for CurlMulti so that if all of the connections encounter some sort of curl error, then the loop exits.
1237
+ * Adding checks to EntityEnclosingRequest so that empty POST files and fields are ignored.
1238
+ * Making the method signature of Guzzle\Service\Builder\ServiceBuilder::factory more flexible.
1239
+
1240
+ ## 2.6.0 - 2012-05-15
1241
+
1242
+ * [BC] Moving Guzzle\Service\Builder to Guzzle\Service\Builder\ServiceBuilder
1243
+ * [BC] Executing a Command returns the result of the command rather than the command
1244
+ * [BC] Moving all HTTP parsing logic to Guzzle\Http\Parsers. Allows for faster C implementations if needed.
1245
+ * [BC] Changing the Guzzle\Http\Message\Response::setProtocol() method to accept a protocol and version in separate args.
1246
+ * [BC] Moving ResourceIterator* to Guzzle\Service\Resource
1247
+ * [BC] Completely refactored ResourceIterators to iterate over a cloned command object
1248
+ * [BC] Moved Guzzle\Http\UriTemplate to Guzzle\Http\Parser\UriTemplate\UriTemplate
1249
+ * [BC] Guzzle\Guzzle is now deprecated
1250
+ * Moving Guzzle\Common\Guzzle::inject to Guzzle\Common\Collection::inject
1251
+ * Adding Guzzle\Version class to give version information about Guzzle
1252
+ * Adding Guzzle\Http\Utils class to provide getDefaultUserAgent() and getHttpDate()
1253
+ * Adding Guzzle\Curl\CurlVersion to manage caching curl_version() data
1254
+ * ServiceDescription and ServiceBuilder are now cacheable using similar configs
1255
+ * Changing the format of XML and JSON service builder configs. Backwards compatible.
1256
+ * Cleaned up Cookie parsing
1257
+ * Trimming the default Guzzle User-Agent header
1258
+ * Adding a setOnComplete() method to Commands that is called when a command completes
1259
+ * Keeping track of requests that were mocked in the MockPlugin
1260
+ * Fixed a caching bug in the CacheAdapterFactory
1261
+ * Inspector objects can be injected into a Command object
1262
+ * Refactoring a lot of code and tests to be case insensitive when dealing with headers
1263
+ * Adding Guzzle\Http\Message\HeaderComparison for easy comparison of HTTP headers using a DSL
1264
+ * Adding the ability to set global option overrides to service builder configs
1265
+ * Adding the ability to include other service builder config files from within XML and JSON files
1266
+ * Moving the parseQuery method out of Url and on to QueryString::fromString() as a static factory method.
1267
+
1268
+ ## 2.5.0 - 2012-05-08
1269
+
1270
+ * Major performance improvements
1271
+ * [BC] Simplifying Guzzle\Common\Collection. Please check to see if you are using features that are now deprecated.
1272
+ * [BC] Using a custom validation system that allows a flyweight implementation for much faster validation. No longer using Symfony2 Validation component.
1273
+ * [BC] No longer supporting "{{ }}" for injecting into command or UriTemplates. Use "{}"
1274
+ * Added the ability to passed parameters to all requests created by a client
1275
+ * Added callback functionality to the ExponentialBackoffPlugin
1276
+ * Using microtime in ExponentialBackoffPlugin to allow more granular backoff strategies.
1277
+ * Rewinding request stream bodies when retrying requests
1278
+ * Exception is thrown when JSON response body cannot be decoded
1279
+ * Added configurable magic method calls to clients and commands. This is off by default.
1280
+ * Fixed a defect that added a hash to every parsed URL part
1281
+ * Fixed duplicate none generation for OauthPlugin.
1282
+ * Emitting an event each time a client is generated by a ServiceBuilder
1283
+ * Using an ApiParams object instead of a Collection for parameters of an ApiCommand
1284
+ * cache.* request parameters should be renamed to params.cache.*
1285
+ * Added the ability to set arbitrary curl options on requests (disable_wire, progress, etc.). See CurlHandle.
1286
+ * Added the ability to disable type validation of service descriptions
1287
+ * ServiceDescriptions and ServiceBuilders are now Serializable
vendor/guzzlehttp/guzzle/LICENSE ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright (c) 2011-2018 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.
vendor/guzzlehttp/guzzle/README.md ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Guzzle, PHP HTTP client
2
+ =======================
3
+
4
+ [![Latest Version](https://img.shields.io/github/release/guzzle/guzzle.svg?style=flat-square)](https://github.com/guzzle/guzzle/releases)
5
+ [![Build Status](https://img.shields.io/travis/guzzle/guzzle.svg?style=flat-square)](https://travis-ci.org/guzzle/guzzle)
6
+ [![Total Downloads](https://img.shields.io/packagist/dt/guzzlehttp/guzzle.svg?style=flat-square)](https://packagist.org/packages/guzzlehttp/guzzle)
7
+
8
+ Guzzle is a PHP HTTP client that makes it easy to send HTTP requests and
9
+ trivial to integrate with web services.
10
+
11
+ - Simple interface for building query strings, POST requests, streaming large
12
+ uploads, streaming large downloads, using HTTP cookies, uploading JSON data,
13
+ etc...
14
+ - Can send both synchronous and asynchronous requests using the same interface.
15
+ - Uses PSR-7 interfaces for requests, responses, and streams. This allows you
16
+ to utilize other PSR-7 compatible libraries with Guzzle.
17
+ - Abstracts away the underlying HTTP transport, allowing you to write
18
+ environment and transport agnostic code; i.e., no hard dependency on cURL,
19
+ PHP streams, sockets, or non-blocking event loops.
20
+ - Middleware system allows you to augment and compose client behavior.
21
+
22
+ ```php
23
+ $client = new \GuzzleHttp\Client();
24
+ $res = $client->request('GET', 'https://api.github.com/repos/guzzle/guzzle');
25
+ echo $res->getStatusCode();
26
+ // 200
27
+ echo $res->getHeaderLine('content-type');
28
+ // 'application/json; charset=utf8'
29
+ echo $res->getBody();
30
+ // '{"id": 1420053, "name": "guzzle", ...}'
31
+
32
+ // Send an asynchronous request.
33
+ $request = new \GuzzleHttp\Psr7\Request('GET', 'http://httpbin.org');
34
+ $promise = $client->sendAsync($request)->then(function ($response) {
35
+ echo 'I completed! ' . $response->getBody();
36
+ });
37
+ $promise->wait();
38
+ ```
39
+
40
+ ## Help and docs
41
+
42
+ - [Documentation](http://guzzlephp.org/)
43
+ - [Stack Overflow](http://stackoverflow.com/questions/tagged/guzzle)
44
+ - [Gitter](https://gitter.im/guzzle/guzzle)
45
+
46
+
47
+ ## Installing Guzzle
48
+
49
+ The recommended way to install Guzzle is through
50
+ [Composer](http://getcomposer.org).
51
+
52
+ ```bash
53
+ # Install Composer
54
+ curl -sS https://getcomposer.org/installer | php
55
+ ```
56
+
57
+ Next, run the Composer command to install the latest stable version of Guzzle:
58
+
59
+ ```bash
60
+ php composer.phar require guzzlehttp/guzzle
61
+ ```
62
+
63
+ After installing, you need to require Composer's autoloader:
64
+
65
+ ```php
66
+ require 'vendor/autoload.php';
67
+ ```
68
+
69
+ You can then later update Guzzle using composer:
70
+
71
+ ```bash
72
+ composer.phar update
73
+ ```
74
+
75
+
76
+ ## Version Guidance
77
+
78
+ | Version | Status | Packagist | Namespace | Repo | Docs | PSR-7 | PHP Version |
79
+ |---------|------------|---------------------|--------------|---------------------|---------------------|-------|-------------|
80
+ | 3.x | EOL | `guzzle/guzzle` | `Guzzle` | [v3][guzzle-3-repo] | [v3][guzzle-3-docs] | No | >= 5.3.3 |
81
+ | 4.x | EOL | `guzzlehttp/guzzle` | `GuzzleHttp` | [v4][guzzle-4-repo] | N/A | No | >= 5.4 |
82
+ | 5.x | Maintained | `guzzlehttp/guzzle` | `GuzzleHttp` | [v5][guzzle-5-repo] | [v5][guzzle-5-docs] | No | >= 5.4 |
83
+ | 6.x | Latest | `guzzlehttp/guzzle` | `GuzzleHttp` | [v6][guzzle-6-repo] | [v6][guzzle-6-docs] | Yes | >= 5.5 |
84
+
85
+ [guzzle-3-repo]: https://github.com/guzzle/guzzle3
86
+ [guzzle-4-repo]: https://github.com/guzzle/guzzle/tree/4.x
87
+ [guzzle-5-repo]: https://github.com/guzzle/guzzle/tree/5.3
88
+ [guzzle-6-repo]: https://github.com/guzzle/guzzle
89
+ [guzzle-3-docs]: http://guzzle3.readthedocs.org/en/latest/
90
+ [guzzle-5-docs]: http://guzzle.readthedocs.org/en/5.3/
91
+ [guzzle-6-docs]: http://guzzle.readthedocs.org/en/latest/
vendor/guzzlehttp/guzzle/UPGRADING.md ADDED
@@ -0,0 +1,1203 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Guzzle Upgrade Guide
2
+ ====================
3
+
4
+ 5.0 to 6.0
5
+ ----------
6
+
7
+ Guzzle now uses [PSR-7](http://www.php-fig.org/psr/psr-7/) for HTTP messages.
8
+ Due to the fact that these messages are immutable, this prompted a refactoring
9
+ of Guzzle to use a middleware based system rather than an event system. Any
10
+ HTTP message interaction (e.g., `GuzzleHttp\Message\Request`) need to be
11
+ updated to work with the new immutable PSR-7 request and response objects. Any
12
+ event listeners or subscribers need to be updated to become middleware
13
+ functions that wrap handlers (or are injected into a
14
+ `GuzzleHttp\HandlerStack`).
15
+
16
+ - Removed `GuzzleHttp\BatchResults`
17
+ - Removed `GuzzleHttp\Collection`
18
+ - Removed `GuzzleHttp\HasDataTrait`
19
+ - Removed `GuzzleHttp\ToArrayInterface`
20
+ - The `guzzlehttp/streams` dependency has been removed. Stream functionality
21
+ is now present in the `GuzzleHttp\Psr7` namespace provided by the
22
+ `guzzlehttp/psr7` package.
23
+ - Guzzle no longer uses ReactPHP promises and now uses the
24
+ `guzzlehttp/promises` library. We use a custom promise library for three
25
+ significant reasons:
26
+ 1. React promises (at the time of writing this) are recursive. Promise
27
+ chaining and promise resolution will eventually blow the stack. Guzzle
28
+ promises are not recursive as they use a sort of trampolining technique.
29
+ Note: there has been movement in the React project to modify promises to
30
+ no longer utilize recursion.
31
+ 2. Guzzle needs to have the ability to synchronously block on a promise to
32
+ wait for a result. Guzzle promises allows this functionality (and does
33
+ not require the use of recursion).
34
+ 3. Because we need to be able to wait on a result, doing so using React
35
+ promises requires wrapping react promises with RingPHP futures. This
36
+ overhead is no longer needed, reducing stack sizes, reducing complexity,
37
+ and improving performance.
38
+ - `GuzzleHttp\Mimetypes` has been moved to a function in
39
+ `GuzzleHttp\Psr7\mimetype_from_extension` and
40
+ `GuzzleHttp\Psr7\mimetype_from_filename`.
41
+ - `GuzzleHttp\Query` and `GuzzleHttp\QueryParser` have been removed. Query
42
+ strings must now be passed into request objects as strings, or provided to
43
+ the `query` request option when creating requests with clients. The `query`
44
+ option uses PHP's `http_build_query` to convert an array to a string. If you
45
+ need a different serialization technique, you will need to pass the query
46
+ string in as a string. There are a couple helper functions that will make
47
+ working with query strings easier: `GuzzleHttp\Psr7\parse_query` and
48
+ `GuzzleHttp\Psr7\build_query`.
49
+ - Guzzle no longer has a dependency on RingPHP. Due to the use of a middleware
50
+ system based on PSR-7, using RingPHP and it's middleware system as well adds
51
+ more complexity than the benefits it provides. All HTTP handlers that were
52
+ present in RingPHP have been modified to work directly with PSR-7 messages
53
+ and placed in the `GuzzleHttp\Handler` namespace. This significantly reduces
54
+ complexity in Guzzle, removes a dependency, and improves performance. RingPHP
55
+ will be maintained for Guzzle 5 support, but will no longer be a part of
56
+ Guzzle 6.
57
+ - As Guzzle now uses a middleware based systems the event system and RingPHP
58
+ integration has been removed. Note: while the event system has been removed,
59
+ it is possible to add your own type of event system that is powered by the
60
+ middleware system.
61
+ - Removed the `Event` namespace.
62
+ - Removed the `Subscriber` namespace.
63
+ - Removed `Transaction` class
64
+ - Removed `RequestFsm`
65
+ - Removed `RingBridge`
66
+ - `GuzzleHttp\Subscriber\Cookie` is now provided by
67
+ `GuzzleHttp\Middleware::cookies`
68
+ - `GuzzleHttp\Subscriber\HttpError` is now provided by
69
+ `GuzzleHttp\Middleware::httpError`
70
+ - `GuzzleHttp\Subscriber\History` is now provided by
71
+ `GuzzleHttp\Middleware::history`
72
+ - `GuzzleHttp\Subscriber\Mock` is now provided by
73
+ `GuzzleHttp\Handler\MockHandler`
74
+ - `GuzzleHttp\Subscriber\Prepare` is now provided by
75
+ `GuzzleHttp\PrepareBodyMiddleware`
76
+ - `GuzzleHttp\Subscriber\Redirect` is now provided by
77
+ `GuzzleHttp\RedirectMiddleware`
78
+ - Guzzle now uses `Psr\Http\Message\UriInterface` (implements in
79
+ `GuzzleHttp\Psr7\Uri`) for URI support. `GuzzleHttp\Url` is now gone.
80
+ - Static functions in `GuzzleHttp\Utils` have been moved to namespaced
81
+ functions under the `GuzzleHttp` namespace. This requires either a Composer
82
+ based autoloader or you to include functions.php.
83
+ - `GuzzleHttp\ClientInterface::getDefaultOption` has been renamed to
84
+ `GuzzleHttp\ClientInterface::getConfig`.
85
+ - `GuzzleHttp\ClientInterface::setDefaultOption` has been removed.
86
+ - The `json` and `xml` methods of response objects has been removed. With the
87
+ migration to strictly adhering to PSR-7 as the interface for Guzzle messages,
88
+ adding methods to message interfaces would actually require Guzzle messages
89
+ to extend from PSR-7 messages rather then work with them directly.
90
+
91
+ ## Migrating to middleware
92
+
93
+ The change to PSR-7 unfortunately required significant refactoring to Guzzle
94
+ due to the fact that PSR-7 messages are immutable. Guzzle 5 relied on an event
95
+ system from plugins. The event system relied on mutability of HTTP messages and
96
+ side effects in order to work. With immutable messages, you have to change your
97
+ workflow to become more about either returning a value (e.g., functional
98
+ middlewares) or setting a value on an object. Guzzle v6 has chosen the
99
+ functional middleware approach.
100
+
101
+ Instead of using the event system to listen for things like the `before` event,
102
+ you now create a stack based middleware function that intercepts a request on
103
+ the way in and the promise of the response on the way out. This is a much
104
+ simpler and more predictable approach than the event system and works nicely
105
+ with PSR-7 middleware. Due to the use of promises, the middleware system is
106
+ also asynchronous.
107
+
108
+ v5:
109
+
110
+ ```php
111
+ use GuzzleHttp\Event\BeforeEvent;
112
+ $client = new GuzzleHttp\Client();
113
+ // Get the emitter and listen to the before event.
114
+ $client->getEmitter()->on('before', function (BeforeEvent $e) {
115
+ // Guzzle v5 events relied on mutation
116
+ $e->getRequest()->setHeader('X-Foo', 'Bar');
117
+ });
118
+ ```
119
+
120
+ v6:
121
+
122
+ In v6, you can modify the request before it is sent using the `mapRequest`
123
+ middleware. The idiomatic way in v6 to modify the request/response lifecycle is
124
+ to setup a handler middleware stack up front and inject the handler into a
125
+ client.
126
+
127
+ ```php
128
+ use GuzzleHttp\Middleware;
129
+ // Create a handler stack that has all of the default middlewares attached
130
+ $handler = GuzzleHttp\HandlerStack::create();
131
+ // Push the handler onto the handler stack
132
+ $handler->push(Middleware::mapRequest(function (RequestInterface $request) {
133
+ // Notice that we have to return a request object
134
+ return $request->withHeader('X-Foo', 'Bar');
135
+ }));
136
+ // Inject the handler into the client
137
+ $client = new GuzzleHttp\Client(['handler' => $handler]);
138
+ ```
139
+
140
+ ## POST Requests
141
+
142
+ This version added the [`form_params`](http://guzzle.readthedocs.org/en/latest/request-options.html#form_params)
143
+ and `multipart` request options. `form_params` is an associative array of
144
+ strings or array of strings and is used to serialize an
145
+ `application/x-www-form-urlencoded` POST request. The
146
+ [`multipart`](http://guzzle.readthedocs.org/en/latest/request-options.html#multipart)
147
+ option is now used to send a multipart/form-data POST request.
148
+
149
+ `GuzzleHttp\Post\PostFile` has been removed. Use the `multipart` option to add
150
+ POST files to a multipart/form-data request.
151
+
152
+ The `body` option no longer accepts an array to send POST requests. Please use
153
+ `multipart` or `form_params` instead.
154
+
155
+ The `base_url` option has been renamed to `base_uri`.
156
+
157
+ 4.x to 5.0
158
+ ----------
159
+
160
+ ## Rewritten Adapter Layer
161
+
162
+ Guzzle now uses [RingPHP](http://ringphp.readthedocs.org/en/latest) to send
163
+ HTTP requests. The `adapter` option in a `GuzzleHttp\Client` constructor
164
+ is still supported, but it has now been renamed to `handler`. Instead of
165
+ passing a `GuzzleHttp\Adapter\AdapterInterface`, you must now pass a PHP
166
+ `callable` that follows the RingPHP specification.
167
+
168
+ ## Removed Fluent Interfaces
169
+
170
+ [Fluent interfaces were removed](http://ocramius.github.io/blog/fluent-interfaces-are-evil)
171
+ from the following classes:
172
+
173
+ - `GuzzleHttp\Collection`
174
+ - `GuzzleHttp\Url`
175
+ - `GuzzleHttp\Query`
176
+ - `GuzzleHttp\Post\PostBody`
177
+ - `GuzzleHttp\Cookie\SetCookie`
178
+
179
+ ## Removed functions.php
180
+
181
+ Removed "functions.php", so that Guzzle is truly PSR-4 compliant. The following
182
+ functions can be used as replacements.
183
+
184
+ - `GuzzleHttp\json_decode` -> `GuzzleHttp\Utils::jsonDecode`
185
+ - `GuzzleHttp\get_path` -> `GuzzleHttp\Utils::getPath`
186
+ - `GuzzleHttp\Utils::setPath` -> `GuzzleHttp\set_path`
187
+ - `GuzzleHttp\Pool::batch` -> `GuzzleHttp\batch`. This function is, however,
188
+ deprecated in favor of using `GuzzleHttp\Pool::batch()`.
189
+
190
+ The "procedural" global client has been removed with no replacement (e.g.,
191
+ `GuzzleHttp\get()`, `GuzzleHttp\post()`, etc.). Use a `GuzzleHttp\Client`
192
+ object as a replacement.
193
+
194
+ ## `throwImmediately` has been removed
195
+
196
+ The concept of "throwImmediately" has been removed from exceptions and error
197
+ events. This control mechanism was used to stop a transfer of concurrent
198
+ requests from completing. This can now be handled by throwing the exception or
199
+ by cancelling a pool of requests or each outstanding future request
200
+ individually.
201
+
202
+ ## headers event has been removed
203
+
204
+ Removed the "headers" event. This event was only useful for changing the
205
+ body a response once the headers of the response were known. You can implement
206
+ a similar behavior in a number of ways. One example might be to use a
207
+ FnStream that has access to the transaction being sent. For example, when the
208
+ first byte is written, you could check if the response headers match your
209
+ expectations, and if so, change the actual stream body that is being
210
+ written to.
211
+
212
+ ## Updates to HTTP Messages
213
+
214
+ Removed the `asArray` parameter from
215
+ `GuzzleHttp\Message\MessageInterface::getHeader`. If you want to get a header
216
+ value as an array, then use the newly added `getHeaderAsArray()` method of
217
+ `MessageInterface`. This change makes the Guzzle interfaces compatible with
218
+ the PSR-7 interfaces.
219
+
220
+ 3.x to 4.0
221
+ ----------
222
+
223
+ ## Overarching changes:
224
+
225
+ - Now requires PHP 5.4 or greater.
226
+ - No longer requires cURL to send requests.
227
+ - Guzzle no longer wraps every exception it throws. Only exceptions that are
228
+ recoverable are now wrapped by Guzzle.
229
+ - Various namespaces have been removed or renamed.
230
+ - No longer requiring the Symfony EventDispatcher. A custom event dispatcher
231
+ based on the Symfony EventDispatcher is
232
+ now utilized in `GuzzleHttp\Event\EmitterInterface` (resulting in significant
233
+ speed and functionality improvements).
234
+
235
+ Changes per Guzzle 3.x namespace are described below.
236
+
237
+ ## Batch
238
+
239
+ The `Guzzle\Batch` namespace has been removed. This is best left to
240
+ third-parties to implement on top of Guzzle's core HTTP library.
241
+
242
+ ## Cache
243
+
244
+ The `Guzzle\Cache` namespace has been removed. (Todo: No suitable replacement
245
+ has been implemented yet, but hoping to utilize a PSR cache interface).
246
+
247
+ ## Common
248
+
249
+ - Removed all of the wrapped exceptions. It's better to use the standard PHP
250
+ library for unrecoverable exceptions.
251
+ - `FromConfigInterface` has been removed.
252
+ - `Guzzle\Common\Version` has been removed. The VERSION constant can be found
253
+ at `GuzzleHttp\ClientInterface::VERSION`.
254
+
255
+ ### Collection
256
+
257
+ - `getAll` has been removed. Use `toArray` to convert a collection to an array.
258
+ - `inject` has been removed.
259
+ - `keySearch` has been removed.
260
+ - `getPath` no longer supports wildcard expressions. Use something better like
261
+ JMESPath for this.
262
+ - `setPath` now supports appending to an existing array via the `[]` notation.
263
+
264
+ ### Events
265
+
266
+ Guzzle no longer requires Symfony's EventDispatcher component. Guzzle now uses
267
+ `GuzzleHttp\Event\Emitter`.
268
+
269
+ - `Symfony\Component\EventDispatcher\EventDispatcherInterface` is replaced by
270
+ `GuzzleHttp\Event\EmitterInterface`.
271
+ - `Symfony\Component\EventDispatcher\EventDispatcher` is replaced by
272
+ `GuzzleHttp\Event\Emitter`.
273
+ - `Symfony\Component\EventDispatcher\Event` is replaced by
274
+ `GuzzleHttp\Event\Event`, and Guzzle now has an EventInterface in
275
+ `GuzzleHttp\Event\EventInterface`.
276
+ - `AbstractHasDispatcher` has moved to a trait, `HasEmitterTrait`, and
277
+ `HasDispatcherInterface` has moved to `HasEmitterInterface`. Retrieving the
278
+ event emitter of a request, client, etc. now uses the `getEmitter` method
279
+ rather than the `getDispatcher` method.
280
+
281
+ #### Emitter
282
+
283
+ - Use the `once()` method to add a listener that automatically removes itself
284
+ the first time it is invoked.
285
+ - Use the `listeners()` method to retrieve a list of event listeners rather than
286
+ the `getListeners()` method.
287
+ - Use `emit()` instead of `dispatch()` to emit an event from an emitter.
288
+ - Use `attach()` instead of `addSubscriber()` and `detach()` instead of
289
+ `removeSubscriber()`.
290
+
291
+ ```php
292
+ $mock = new Mock();
293
+ // 3.x
294
+ $request->getEventDispatcher()->addSubscriber($mock);
295
+ $request->getEventDispatcher()->removeSubscriber($mock);
296
+ // 4.x
297
+ $request->getEmitter()->attach($mock);
298
+ $request->getEmitter()->detach($mock);
299
+ ```
300
+
301
+ Use the `on()` method to add a listener rather than the `addListener()` method.
302
+
303
+ ```php
304
+ // 3.x
305
+ $request->getEventDispatcher()->addListener('foo', function (Event $event) { /* ... */ } );
306
+ // 4.x
307
+ $request->getEmitter()->on('foo', function (Event $event, $name) { /* ... */ } );
308
+ ```
309
+
310
+ ## Http
311
+
312
+ ### General changes
313
+
314
+ - The cacert.pem certificate has been moved to `src/cacert.pem`.
315
+ - Added the concept of adapters that are used to transfer requests over the
316
+ wire.
317
+ - Simplified the event system.
318
+ - Sending requests in parallel is still possible, but batching is no longer a
319
+ concept of the HTTP layer. Instead, you must use the `complete` and `error`
320
+ events to asynchronously manage parallel request transfers.
321
+ - `Guzzle\Http\Url` has moved to `GuzzleHttp\Url`.
322
+ - `Guzzle\Http\QueryString` has moved to `GuzzleHttp\Query`.
323
+ - QueryAggregators have been rewritten so that they are simply callable
324
+ functions.
325
+ - `GuzzleHttp\StaticClient` has been removed. Use the functions provided in
326
+ `functions.php` for an easy to use static client instance.
327
+ - Exceptions in `GuzzleHttp\Exception` have been updated to all extend from
328
+ `GuzzleHttp\Exception\TransferException`.
329
+
330
+ ### Client
331
+
332
+ Calling methods like `get()`, `post()`, `head()`, etc. no longer create and
333
+ return a request, but rather creates a request, sends the request, and returns
334
+ the response.
335
+
336
+ ```php
337
+ // 3.0
338
+ $request = $client->get('/');
339
+ $response = $request->send();
340
+
341
+ // 4.0
342
+ $response = $client->get('/');
343
+
344
+ // or, to mirror the previous behavior
345
+ $request = $client->createRequest('GET', '/');
346
+ $response = $client->send($request);
347
+ ```
348
+
349
+ `GuzzleHttp\ClientInterface` has changed.
350
+
351
+ - The `send` method no longer accepts more than one request. Use `sendAll` to
352
+ send multiple requests in parallel.
353
+ - `setUserAgent()` has been removed. Use a default request option instead. You
354
+ could, for example, do something like:
355
+ `$client->setConfig('defaults/headers/User-Agent', 'Foo/Bar ' . $client::getDefaultUserAgent())`.
356
+ - `setSslVerification()` has been removed. Use default request options instead,
357
+ like `$client->setConfig('defaults/verify', true)`.
358
+
359
+ `GuzzleHttp\Client` has changed.
360
+
361
+ - The constructor now accepts only an associative array. You can include a
362
+ `base_url` string or array to use a URI template as the base URL of a client.
363
+ You can also specify a `defaults` key that is an associative array of default
364
+ request options. You can pass an `adapter` to use a custom adapter,
365
+ `batch_adapter` to use a custom adapter for sending requests in parallel, or
366
+ a `message_factory` to change the factory used to create HTTP requests and
367
+ responses.
368
+ - The client no longer emits a `client.create_request` event.
369
+ - Creating requests with a client no longer automatically utilize a URI
370
+ template. You must pass an array into a creational method (e.g.,
371
+ `createRequest`, `get`, `put`, etc.) in order to expand a URI template.
372
+
373
+ ### Messages
374
+
375
+ Messages no longer have references to their counterparts (i.e., a request no
376
+ longer has a reference to it's response, and a response no loger has a
377
+ reference to its request). This association is now managed through a
378
+ `GuzzleHttp\Adapter\TransactionInterface` object. You can get references to
379
+ these transaction objects using request events that are emitted over the
380
+ lifecycle of a request.
381
+
382
+ #### Requests with a body
383
+
384
+ - `GuzzleHttp\Message\EntityEnclosingRequest` and
385
+ `GuzzleHttp\Message\EntityEnclosingRequestInterface` have been removed. The
386
+ separation between requests that contain a body and requests that do not
387
+ contain a body has been removed, and now `GuzzleHttp\Message\RequestInterface`
388
+ handles both use cases.
389
+ - Any method that previously accepts a `GuzzleHttp\Response` object now accept a
390
+ `GuzzleHttp\Message\ResponseInterface`.
391
+ - `GuzzleHttp\Message\RequestFactoryInterface` has been renamed to
392
+ `GuzzleHttp\Message\MessageFactoryInterface`. This interface is used to create
393
+ both requests and responses and is implemented in
394
+ `GuzzleHttp\Message\MessageFactory`.
395
+ - POST field and file methods have been removed from the request object. You
396
+ must now use the methods made available to `GuzzleHttp\Post\PostBodyInterface`
397
+ to control the format of a POST body. Requests that are created using a
398
+ standard `GuzzleHttp\Message\MessageFactoryInterface` will automatically use
399
+ a `GuzzleHttp\Post\PostBody` body if the body was passed as an array or if
400
+ the method is POST and no body is provided.
401
+
402
+ ```php
403
+ $request = $client->createRequest('POST', '/');
404
+ $request->getBody()->setField('foo', 'bar');
405
+ $request->getBody()->addFile(new PostFile('file_key', fopen('/path/to/content', 'r')));
406
+ ```
407
+
408
+ #### Headers
409
+
410
+ - `GuzzleHttp\Message\Header` has been removed. Header values are now simply
411
+ represented by an array of values or as a string. Header values are returned
412
+ as a string by default when retrieving a header value from a message. You can
413
+ pass an optional argument of `true` to retrieve a header value as an array
414
+ of strings instead of a single concatenated string.
415
+ - `GuzzleHttp\PostFile` and `GuzzleHttp\PostFileInterface` have been moved to
416
+ `GuzzleHttp\Post`. This interface has been simplified and now allows the
417
+ addition of arbitrary headers.
418
+ - Custom headers like `GuzzleHttp\Message\Header\Link` have been removed. Most
419
+ of the custom headers are now handled separately in specific
420
+ subscribers/plugins, and `GuzzleHttp\Message\HeaderValues::parseParams()` has
421
+ been updated to properly handle headers that contain parameters (like the
422
+ `Link` header).
423
+
424
+ #### Responses
425
+
426
+ - `GuzzleHttp\Message\Response::getInfo()` and
427
+ `GuzzleHttp\Message\Response::setInfo()` have been removed. Use the event
428
+ system to retrieve this type of information.
429
+ - `GuzzleHttp\Message\Response::getRawHeaders()` has been removed.
430
+ - `GuzzleHttp\Message\Response::getMessage()` has been removed.
431
+ - `GuzzleHttp\Message\Response::calculateAge()` and other cache specific
432
+ methods have moved to the CacheSubscriber.
433
+ - Header specific helper functions like `getContentMd5()` have been removed.
434
+ Just use `getHeader('Content-MD5')` instead.
435
+ - `GuzzleHttp\Message\Response::setRequest()` and
436
+ `GuzzleHttp\Message\Response::getRequest()` have been removed. Use the event
437
+ system to work with request and response objects as a transaction.
438
+ - `GuzzleHttp\Message\Response::getRedirectCount()` has been removed. Use the
439
+ Redirect subscriber instead.
440
+ - `GuzzleHttp\Message\Response::isSuccessful()` and other related methods have
441
+ been removed. Use `getStatusCode()` instead.
442
+
443
+ #### Streaming responses
444
+
445
+ Streaming requests can now be created by a client directly, returning a
446
+ `GuzzleHttp\Message\ResponseInterface` object that contains a body stream
447
+ referencing an open PHP HTTP stream.
448
+
449
+ ```php
450
+ // 3.0
451
+ use Guzzle\Stream\PhpStreamRequestFactory;
452
+ $request = $client->get('/');
453
+ $factory = new PhpStreamRequestFactory();
454
+ $stream = $factory->fromRequest($request);
455
+ $data = $stream->read(1024);
456
+
457
+ // 4.0
458
+ $response = $client->get('/', ['stream' => true]);
459
+ // Read some data off of the stream in the response body
460
+ $data = $response->getBody()->read(1024);
461
+ ```
462
+
463
+ #### Redirects
464
+
465
+ The `configureRedirects()` method has been removed in favor of a
466
+ `allow_redirects` request option.
467
+
468
+ ```php
469
+ // Standard redirects with a default of a max of 5 redirects
470
+ $request = $client->createRequest('GET', '/', ['allow_redirects' => true]);
471
+
472
+ // Strict redirects with a custom number of redirects
473
+ $request = $client->createRequest('GET', '/', [
474
+ 'allow_redirects' => ['max' => 5, 'strict' => true]
475
+ ]);
476
+ ```
477
+
478
+ #### EntityBody
479
+
480
+ EntityBody interfaces and classes have been removed or moved to
481
+ `GuzzleHttp\Stream`. All classes and interfaces that once required
482
+ `GuzzleHttp\EntityBodyInterface` now require
483
+ `GuzzleHttp\Stream\StreamInterface`. Creating a new body for a request no
484
+ longer uses `GuzzleHttp\EntityBody::factory` but now uses
485
+ `GuzzleHttp\Stream\Stream::factory` or even better:
486
+ `GuzzleHttp\Stream\create()`.
487
+
488
+ - `Guzzle\Http\EntityBodyInterface` is now `GuzzleHttp\Stream\StreamInterface`
489
+ - `Guzzle\Http\EntityBody` is now `GuzzleHttp\Stream\Stream`
490
+ - `Guzzle\Http\CachingEntityBody` is now `GuzzleHttp\Stream\CachingStream`
491
+ - `Guzzle\Http\ReadLimitEntityBody` is now `GuzzleHttp\Stream\LimitStream`
492
+ - `Guzzle\Http\IoEmittyinEntityBody` has been removed.
493
+
494
+ #### Request lifecycle events
495
+
496
+ Requests previously submitted a large number of requests. The number of events
497
+ emitted over the lifecycle of a request has been significantly reduced to make
498
+ it easier to understand how to extend the behavior of a request. All events
499
+ emitted during the lifecycle of a request now emit a custom
500
+ `GuzzleHttp\Event\EventInterface` object that contains context providing
501
+ methods and a way in which to modify the transaction at that specific point in
502
+ time (e.g., intercept the request and set a response on the transaction).
503
+
504
+ - `request.before_send` has been renamed to `before` and now emits a
505
+ `GuzzleHttp\Event\BeforeEvent`
506
+ - `request.complete` has been renamed to `complete` and now emits a
507
+ `GuzzleHttp\Event\CompleteEvent`.
508
+ - `request.sent` has been removed. Use `complete`.
509
+ - `request.success` has been removed. Use `complete`.
510
+ - `error` is now an event that emits a `GuzzleHttp\Event\ErrorEvent`.
511
+ - `request.exception` has been removed. Use `error`.
512
+ - `request.receive.status_line` has been removed.
513
+ - `curl.callback.progress` has been removed. Use a custom `StreamInterface` to
514
+ maintain a status update.
515
+ - `curl.callback.write` has been removed. Use a custom `StreamInterface` to
516
+ intercept writes.
517
+ - `curl.callback.read` has been removed. Use a custom `StreamInterface` to
518
+ intercept reads.
519
+
520
+ `headers` is a new event that is emitted after the response headers of a
521
+ request have been received before the body of the response is downloaded. This
522
+ event emits a `GuzzleHttp\Event\HeadersEvent`.
523
+
524
+ You can intercept a request and inject a response using the `intercept()` event
525
+ of a `GuzzleHttp\Event\BeforeEvent`, `GuzzleHttp\Event\CompleteEvent`, and
526
+ `GuzzleHttp\Event\ErrorEvent` event.
527
+
528
+ See: http://docs.guzzlephp.org/en/latest/events.html
529
+
530
+ ## Inflection
531
+
532
+ The `Guzzle\Inflection` namespace has been removed. This is not a core concern
533
+ of Guzzle.
534
+
535
+ ## Iterator
536
+
537
+ The `Guzzle\Iterator` namespace has been removed.
538
+
539
+ - `Guzzle\Iterator\AppendIterator`, `Guzzle\Iterator\ChunkedIterator`, and
540
+ `Guzzle\Iterator\MethodProxyIterator` are nice, but not a core requirement of
541
+ Guzzle itself.
542
+ - `Guzzle\Iterator\FilterIterator` is no longer needed because an equivalent
543
+ class is shipped with PHP 5.4.
544
+ - `Guzzle\Iterator\MapIterator` is not really needed when using PHP 5.5 because
545
+ it's easier to just wrap an iterator in a generator that maps values.
546
+
547
+ For a replacement of these iterators, see https://github.com/nikic/iter
548
+
549
+ ## Log
550
+
551
+ The LogPlugin has moved to https://github.com/guzzle/log-subscriber. The
552
+ `Guzzle\Log` namespace has been removed. Guzzle now relies on
553
+ `Psr\Log\LoggerInterface` for all logging. The MessageFormatter class has been
554
+ moved to `GuzzleHttp\Subscriber\Log\Formatter`.
555
+
556
+ ## Parser
557
+
558
+ The `Guzzle\Parser` namespace has been removed. This was previously used to
559
+ make it possible to plug in custom parsers for cookies, messages, URI
560
+ templates, and URLs; however, this level of complexity is not needed in Guzzle
561
+ so it has been removed.
562
+
563
+ - Cookie: Cookie parsing logic has been moved to
564
+ `GuzzleHttp\Cookie\SetCookie::fromString`.
565
+ - Message: Message parsing logic for both requests and responses has been moved
566
+ to `GuzzleHttp\Message\MessageFactory::fromMessage`. Message parsing is only
567
+ used in debugging or deserializing messages, so it doesn't make sense for
568
+ Guzzle as a library to add this level of complexity to parsing messages.
569
+ - UriTemplate: URI template parsing has been moved to
570
+ `GuzzleHttp\UriTemplate`. The Guzzle library will automatically use the PECL
571
+ URI template library if it is installed.
572
+ - Url: URL parsing is now performed in `GuzzleHttp\Url::fromString` (previously
573
+ it was `Guzzle\Http\Url::factory()`). If custom URL parsing is necessary,
574
+ then developers are free to subclass `GuzzleHttp\Url`.
575
+
576
+ ## Plugin
577
+
578
+ The `Guzzle\Plugin` namespace has been renamed to `GuzzleHttp\Subscriber`.
579
+ Several plugins are shipping with the core Guzzle library under this namespace.
580
+
581
+ - `GuzzleHttp\Subscriber\Cookie`: Replaces the old CookiePlugin. Cookie jar
582
+ code has moved to `GuzzleHttp\Cookie`.
583
+ - `GuzzleHttp\Subscriber\History`: Replaces the old HistoryPlugin.
584
+ - `GuzzleHttp\Subscriber\HttpError`: Throws errors when a bad HTTP response is
585
+ received.
586
+ - `GuzzleHttp\Subscriber\Mock`: Replaces the old MockPlugin.
587
+ - `GuzzleHttp\Subscriber\Prepare`: Prepares the body of a request just before
588
+ sending. This subscriber is attached to all requests by default.
589
+ - `GuzzleHttp\Subscriber\Redirect`: Replaces the RedirectPlugin.
590
+
591
+ The following plugins have been removed (third-parties are free to re-implement
592
+ these if needed):
593
+
594
+ - `GuzzleHttp\Plugin\Async` has been removed.
595
+ - `GuzzleHttp\Plugin\CurlAuth` has been removed.
596
+ - `GuzzleHttp\Plugin\ErrorResponse\ErrorResponsePlugin` has been removed. This
597
+ functionality should instead be implemented with event listeners that occur
598
+ after normal response parsing occurs in the guzzle/command package.
599
+
600
+ The following plugins are not part of the core Guzzle package, but are provided
601
+ in separate repositories:
602
+
603
+ - `Guzzle\Http\Plugin\BackoffPlugin` has been rewritten to be much simpler
604
+ to build custom retry policies using simple functions rather than various
605
+ chained classes. See: https://github.com/guzzle/retry-subscriber
606
+ - `Guzzle\Http\Plugin\Cache\CachePlugin` has moved to
607
+ https://github.com/guzzle/cache-subscriber
608
+ - `Guzzle\Http\Plugin\Log\LogPlugin` has moved to
609
+ https://github.com/guzzle/log-subscriber
610
+ - `Guzzle\Http\Plugin\Md5\Md5Plugin` has moved to
611
+ https://github.com/guzzle/message-integrity-subscriber
612
+ - `Guzzle\Http\Plugin\Mock\MockPlugin` has moved to
613
+ `GuzzleHttp\Subscriber\MockSubscriber`.
614
+ - `Guzzle\Http\Plugin\Oauth\OauthPlugin` has moved to
615
+ https://github.com/guzzle/oauth-subscriber
616
+
617
+ ## Service
618
+
619
+ The service description layer of Guzzle has moved into two separate packages:
620
+
621
+ - http://github.com/guzzle/command Provides a high level abstraction over web
622
+ services by representing web service operations using commands.
623
+ - http://github.com/guzzle/guzzle-services Provides an implementation of
624
+ guzzle/command that provides request serialization and response parsing using
625
+ Guzzle service descriptions.
626
+
627
+ ## Stream
628
+
629
+ Stream have moved to a separate package available at
630
+ https://github.com/guzzle/streams.
631
+
632
+ `Guzzle\Stream\StreamInterface` has been given a large update to cleanly take
633
+ on the responsibilities of `Guzzle\Http\EntityBody` and
634
+ `Guzzle\Http\EntityBodyInterface` now that they have been removed. The number
635
+ of methods implemented by the `StreamInterface` has been drastically reduced to
636
+ allow developers to more easily extend and decorate stream behavior.
637
+
638
+ ## Removed methods from StreamInterface
639
+
640
+ - `getStream` and `setStream` have been removed to better encapsulate streams.
641
+ - `getMetadata` and `setMetadata` have been removed in favor of
642
+ `GuzzleHttp\Stream\MetadataStreamInterface`.
643
+ - `getWrapper`, `getWrapperData`, `getStreamType`, and `getUri` have all been
644
+ removed. This data is accessible when
645
+ using streams that implement `GuzzleHttp\Stream\MetadataStreamInterface`.
646
+ - `rewind` has been removed. Use `seek(0)` for a similar behavior.
647
+
648
+ ## Renamed methods
649
+
650
+ - `detachStream` has been renamed to `detach`.
651
+ - `feof` has been renamed to `eof`.
652
+ - `ftell` has been renamed to `tell`.
653
+ - `readLine` has moved from an instance method to a static class method of
654
+ `GuzzleHttp\Stream\Stream`.
655
+
656
+ ## Metadata streams
657
+
658
+ `GuzzleHttp\Stream\MetadataStreamInterface` has been added to denote streams
659
+ that contain additional metadata accessible via `getMetadata()`.
660
+ `GuzzleHttp\Stream\StreamInterface::getMetadata` and
661
+ `GuzzleHttp\Stream\StreamInterface::setMetadata` have been removed.
662
+
663
+ ## StreamRequestFactory
664
+
665
+ The entire concept of the StreamRequestFactory has been removed. The way this
666
+ was used in Guzzle 3 broke the actual interface of sending streaming requests
667
+ (instead of getting back a Response, you got a StreamInterface). Streaming
668
+ PHP requests are now implemented through the `GuzzleHttp\Adapter\StreamAdapter`.
669
+
670
+ 3.6 to 3.7
671
+ ----------
672
+
673
+ ### Deprecations
674
+
675
+ - You can now enable E_USER_DEPRECATED warnings to see if you are using any deprecated methods.:
676
+
677
+ ```php
678
+ \Guzzle\Common\Version::$emitWarnings = true;
679
+ ```
680
+
681
+ The following APIs and options have been marked as deprecated:
682
+
683
+ - Marked `Guzzle\Http\Message\Request::isResponseBodyRepeatable()` as deprecated. Use `$request->getResponseBody()->isRepeatable()` instead.
684
+ - Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead.
685
+ - Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead.
686
+ - Marked `Guzzle\Http\Message\Request::setIsRedirect()` as deprecated. Use the HistoryPlugin instead.
687
+ - Marked `Guzzle\Http\Message\Request::isRedirect()` as deprecated. Use the HistoryPlugin instead.
688
+ - Marked `Guzzle\Cache\CacheAdapterFactory::factory()` as deprecated
689
+ - Marked `Guzzle\Service\Client::enableMagicMethods()` as deprecated. Magic methods can no longer be disabled on a Guzzle\Service\Client.
690
+ - Marked `Guzzle\Parser\Url\UrlParser` as deprecated. Just use PHP's `parse_url()` and percent encode your UTF-8.
691
+ - Marked `Guzzle\Common\Collection::inject()` as deprecated.
692
+ - Marked `Guzzle\Plugin\CurlAuth\CurlAuthPlugin` as deprecated. Use
693
+ `$client->getConfig()->setPath('request.options/auth', array('user', 'pass', 'Basic|Digest|NTLM|Any'));` or
694
+ `$client->setDefaultOption('auth', array('user', 'pass', 'Basic|Digest|NTLM|Any'));`
695
+
696
+ 3.7 introduces `request.options` as a parameter for a client configuration and as an optional argument to all creational
697
+ request methods. When paired with a client's configuration settings, these options allow you to specify default settings
698
+ for various aspects of a request. Because these options make other previous configuration options redundant, several
699
+ configuration options and methods of a client and AbstractCommand have been deprecated.
700
+
701
+ - Marked `Guzzle\Service\Client::getDefaultHeaders()` as deprecated. Use `$client->getDefaultOption('headers')`.
702
+ - Marked `Guzzle\Service\Client::setDefaultHeaders()` as deprecated. Use `$client->setDefaultOption('headers/{header_name}', 'value')`.
703
+ - Marked 'request.params' for `Guzzle\Http\Client` as deprecated. Use `$client->setDefaultOption('params/{param_name}', 'value')`
704
+ - Marked 'command.headers', 'command.response_body' and 'command.on_complete' as deprecated for AbstractCommand. These will work through Guzzle 4.0
705
+
706
+ $command = $client->getCommand('foo', array(
707
+ 'command.headers' => array('Test' => '123'),
708
+ 'command.response_body' => '/path/to/file'
709
+ ));
710
+
711
+ // Should be changed to:
712
+
713
+ $command = $client->getCommand('foo', array(
714
+ 'command.request_options' => array(
715
+ 'headers' => array('Test' => '123'),
716
+ 'save_as' => '/path/to/file'
717
+ )
718
+ ));
719
+
720
+ ### Interface changes
721
+
722
+ Additions and changes (you will need to update any implementations or subclasses you may have created):
723
+
724
+ - Added an `$options` argument to the end of the following methods of `Guzzle\Http\ClientInterface`:
725
+ createRequest, head, delete, put, patch, post, options, prepareRequest
726
+ - Added an `$options` argument to the end of `Guzzle\Http\Message\Request\RequestFactoryInterface::createRequest()`
727
+ - Added an `applyOptions()` method to `Guzzle\Http\Message\Request\RequestFactoryInterface`
728
+ - Changed `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $body = null)` to
729
+ `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $options = array())`. You can still pass in a
730
+ resource, string, or EntityBody into the $options parameter to specify the download location of the response.
731
+ - Changed `Guzzle\Common\Collection::__construct($data)` to no longer accepts a null value for `$data` but a
732
+ default `array()`
733
+ - Added `Guzzle\Stream\StreamInterface::isRepeatable`
734
+ - Made `Guzzle\Http\Client::expandTemplate` and `getUriTemplate` protected methods.
735
+
736
+ The following methods were removed from interfaces. All of these methods are still available in the concrete classes
737
+ that implement them, but you should update your code to use alternative methods:
738
+
739
+ - Removed `Guzzle\Http\ClientInterface::setDefaultHeaders(). Use
740
+ `$client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`. or
741
+ `$client->getConfig()->setPath('request.options/headers', array('header_name' => 'value'))` or
742
+ `$client->setDefaultOption('headers/{header_name}', 'value')`. or
743
+ `$client->setDefaultOption('headers', array('header_name' => 'value'))`.
744
+ - Removed `Guzzle\Http\ClientInterface::getDefaultHeaders(). Use `$client->getConfig()->getPath('request.options/headers')`.
745
+ - Removed `Guzzle\Http\ClientInterface::expandTemplate()`. This is an implementation detail.
746
+ - Removed `Guzzle\Http\ClientInterface::setRequestFactory()`. This is an implementation detail.
747
+ - Removed `Guzzle\Http\ClientInterface::getCurlMulti()`. This is a very specific implementation detail.
748
+ - Removed `Guzzle\Http\Message\RequestInterface::canCache`. Use the CachePlugin.
749
+ - Removed `Guzzle\Http\Message\RequestInterface::setIsRedirect`. Use the HistoryPlugin.
750
+ - Removed `Guzzle\Http\Message\RequestInterface::isRedirect`. Use the HistoryPlugin.
751
+
752
+ ### Cache plugin breaking changes
753
+
754
+ - CacheKeyProviderInterface and DefaultCacheKeyProvider are no longer used. All of this logic is handled in a
755
+ CacheStorageInterface. These two objects and interface will be removed in a future version.
756
+ - Always setting X-cache headers on cached responses
757
+ - Default cache TTLs are now handled by the CacheStorageInterface of a CachePlugin
758
+ - `CacheStorageInterface::cache($key, Response $response, $ttl = null)` has changed to `cache(RequestInterface
759
+ $request, Response $response);`
760
+ - `CacheStorageInterface::fetch($key)` has changed to `fetch(RequestInterface $request);`
761
+ - `CacheStorageInterface::delete($key)` has changed to `delete(RequestInterface $request);`
762
+ - Added `CacheStorageInterface::purge($url)`
763
+ - `DefaultRevalidation::__construct(CacheKeyProviderInterface $cacheKey, CacheStorageInterface $cache, CachePlugin
764
+ $plugin)` has changed to `DefaultRevalidation::__construct(CacheStorageInterface $cache,
765
+ CanCacheStrategyInterface $canCache = null)`
766
+ - Added `RevalidationInterface::shouldRevalidate(RequestInterface $request, Response $response)`
767
+
768
+ 3.5 to 3.6
769
+ ----------
770
+
771
+ * Mixed casing of headers are now forced to be a single consistent casing across all values for that header.
772
+ * Messages internally use a HeaderCollection object to delegate handling case-insensitive header resolution
773
+ * Removed the whole changedHeader() function system of messages because all header changes now go through addHeader().
774
+ For example, setHeader() first removes the header using unset on a HeaderCollection and then calls addHeader().
775
+ Keeping the Host header and URL host in sync is now handled by overriding the addHeader method in Request.
776
+ * Specific header implementations can be created for complex headers. When a message creates a header, it uses a
777
+ HeaderFactory which can map specific headers to specific header classes. There is now a Link header and
778
+ CacheControl header implementation.
779
+ * Moved getLinks() from Response to just be used on a Link header object.
780
+
781
+ If you previously relied on Guzzle\Http\Message\Header::raw(), then you will need to update your code to use the
782
+ HeaderInterface (e.g. toArray(), getAll(), etc.).
783
+
784
+ ### Interface changes
785
+
786
+ * Removed from interface: Guzzle\Http\ClientInterface::setUriTemplate
787
+ * Removed from interface: Guzzle\Http\ClientInterface::setCurlMulti()
788
+ * Removed Guzzle\Http\Message\Request::receivedRequestHeader() and implemented this functionality in
789
+ Guzzle\Http\Curl\RequestMediator
790
+ * Removed the optional $asString parameter from MessageInterface::getHeader(). Just cast the header to a string.
791
+ * Removed the optional $tryChunkedTransfer option from Guzzle\Http\Message\EntityEnclosingRequestInterface
792
+ * Removed the $asObjects argument from Guzzle\Http\Message\MessageInterface::getHeaders()
793
+
794
+ ### Removed deprecated functions
795
+
796
+ * Removed Guzzle\Parser\ParserRegister::get(). Use getParser()
797
+ * Removed Guzzle\Parser\ParserRegister::set(). Use registerParser().
798
+
799
+ ### Deprecations
800
+
801
+ * The ability to case-insensitively search for header values
802
+ * Guzzle\Http\Message\Header::hasExactHeader
803
+ * Guzzle\Http\Message\Header::raw. Use getAll()
804
+ * Deprecated cache control specific methods on Guzzle\Http\Message\AbstractMessage. Use the CacheControl header object
805
+ instead.
806
+
807
+ ### Other changes
808
+
809
+ * All response header helper functions return a string rather than mixing Header objects and strings inconsistently
810
+ * Removed cURL blacklist support. This is no longer necessary now that Expect, Accept, etc. are managed by Guzzle
811
+ directly via interfaces
812
+ * Removed the injecting of a request object onto a response object. The methods to get and set a request still exist
813
+ but are a no-op until removed.
814
+ * Most classes that used to require a `Guzzle\Service\Command\CommandInterface` typehint now request a
815
+ `Guzzle\Service\Command\ArrayCommandInterface`.
816
+ * Added `Guzzle\Http\Message\RequestInterface::startResponse()` to the RequestInterface to handle injecting a response
817
+ on a request while the request is still being transferred
818
+ * `Guzzle\Service\Command\CommandInterface` now extends from ToArrayInterface and ArrayAccess
819
+
820
+ 3.3 to 3.4
821
+ ----------
822
+
823
+ Base URLs of a client now follow the rules of http://tools.ietf.org/html/rfc3986#section-5.2.2 when merging URLs.
824
+
825
+ 3.2 to 3.3
826
+ ----------
827
+
828
+ ### Response::getEtag() quote stripping removed
829
+
830
+ `Guzzle\Http\Message\Response::getEtag()` no longer strips quotes around the ETag response header
831
+
832
+ ### Removed `Guzzle\Http\Utils`
833
+
834
+ The `Guzzle\Http\Utils` class was removed. This class was only used for testing.
835
+
836
+ ### Stream wrapper and type
837
+
838
+ `Guzzle\Stream\Stream::getWrapper()` and `Guzzle\Stream\Stream::getStreamType()` are no longer converted to lowercase.
839
+
840
+ ### curl.emit_io became emit_io
841
+
842
+ Emitting IO events from a RequestMediator is now a parameter that must be set in a request's curl options using the
843
+ 'emit_io' key. This was previously set under a request's parameters using 'curl.emit_io'
844
+
845
+ 3.1 to 3.2
846
+ ----------
847
+
848
+ ### CurlMulti is no longer reused globally
849
+
850
+ Before 3.2, the same CurlMulti object was reused globally for each client. This can cause issue where plugins added
851
+ to a single client can pollute requests dispatched from other clients.
852
+
853
+ If you still wish to reuse the same CurlMulti object with each client, then you can add a listener to the
854
+ ServiceBuilder's `service_builder.create_client` event to inject a custom CurlMulti object into each client as it is
855
+ created.
856
+
857
+ ```php
858
+ $multi = new Guzzle\Http\Curl\CurlMulti();
859
+ $builder = Guzzle\Service\Builder\ServiceBuilder::factory('/path/to/config.json');
860
+ $builder->addListener('service_builder.create_client', function ($event) use ($multi) {
861
+ $event['client']->setCurlMulti($multi);
862
+ }
863
+ });
864
+ ```
865
+
866
+ ### No default path
867
+
868
+ URLs no longer have a default path value of '/' if no path was specified.
869
+
870
+ Before:
871
+
872
+ ```php
873
+ $request = $client->get('http://www.foo.com');
874
+ echo $request->getUrl();
875
+ // >> http://www.foo.com/
876
+ ```
877
+
878
+ After:
879
+
880
+ ```php
881
+ $request = $client->get('http://www.foo.com');
882
+ echo $request->getUrl();
883
+ // >> http://www.foo.com
884
+ ```
885
+
886
+ ### Less verbose BadResponseException
887
+
888
+ The exception message for `Guzzle\Http\Exception\BadResponseException` no longer contains the full HTTP request and
889
+ response information. You can, however, get access to the request and response object by calling `getRequest()` or
890
+ `getResponse()` on the exception object.
891
+
892
+ ### Query parameter aggregation
893
+
894
+ Multi-valued query parameters are no longer aggregated using a callback function. `Guzzle\Http\Query` now has a
895
+ setAggregator() method that accepts a `Guzzle\Http\QueryAggregator\QueryAggregatorInterface` object. This object is
896
+ responsible for handling the aggregation of multi-valued query string variables into a flattened hash.
897
+
898
+ 2.8 to 3.x
899
+ ----------
900
+
901
+ ### Guzzle\Service\Inspector
902
+
903
+ Change `\Guzzle\Service\Inspector::fromConfig` to `\Guzzle\Common\Collection::fromConfig`
904
+
905
+ **Before**
906
+
907
+ ```php
908
+ use Guzzle\Service\Inspector;
909
+
910
+ class YourClient extends \Guzzle\Service\Client
911
+ {
912
+ public static function factory($config = array())
913
+ {
914
+ $default = array();
915
+ $required = array('base_url', 'username', 'api_key');
916
+ $config = Inspector::fromConfig($config, $default, $required);
917
+
918
+ $client = new self(
919
+ $config->get('base_url'),
920
+ $config->get('username'),
921
+ $config->get('api_key')
922
+ );
923
+ $client->setConfig($config);
924
+
925
+ $client->setDescription(ServiceDescription::factory(__DIR__ . DIRECTORY_SEPARATOR . 'client.json'));
926
+
927
+ return $client;
928
+ }
929
+ ```
930
+
931
+ **After**
932
+
933
+ ```php
934
+ use Guzzle\Common\Collection;
935
+
936
+ class YourClient extends \Guzzle\Service\Client
937
+ {
938
+ public static function factory($config = array())
939
+ {
940
+ $default = array();
941
+ $required = array('base_url', 'username', 'api_key');
942
+ $config = Collection::fromConfig($config, $default, $required);
943
+
944
+ $client = new self(
945
+ $config->get('base_url'),
946
+ $config->get('username'),
947
+ $config->get('api_key')
948
+ );
949
+ $client->setConfig($config);
950
+
951
+ $client->setDescription(ServiceDescription::factory(__DIR__ . DIRECTORY_SEPARATOR . 'client.json'));
952
+
953
+ return $client;
954
+ }
955
+ ```
956
+
957
+ ### Convert XML Service Descriptions to JSON
958
+
959
+ **Before**
960
+
961
+ ```xml
962
+ <?xml version="1.0" encoding="UTF-8"?>
963
+ <client>
964
+ <commands>
965
+ <!-- Groups -->
966
+ <command name="list_groups" method="GET" uri="groups.json">
967
+ <doc>Get a list of groups</doc>
968
+ </command>
969
+ <command name="search_groups" method="GET" uri='search.json?query="{{query}} type:group"'>
970
+ <doc>Uses a search query to get a list of groups</doc>
971
+ <param name="query" type="string" required="true" />
972
+ </command>
973
+ <command name="create_group" method="POST" uri="groups.json">
974
+ <doc>Create a group</doc>
975
+ <param name="data" type="array" location="body" filters="json_encode" doc="Group JSON"/>
976
+ <param name="Content-Type" location="header" static="application/json"/>
977
+ </command>
978
+ <command name="delete_group" method="DELETE" uri="groups/{{id}}.json">
979
+ <doc>Delete a group by ID</doc>
980
+ <param name="id" type="integer" required="true"/>
981
+ </command>
982
+ <command name="get_group" method="GET" uri="groups/{{id}}.json">
983
+ <param name="id" type="integer" required="true"/>
984
+ </command>
985
+ <command name="update_group" method="PUT" uri="groups/{{id}}.json">
986
+ <doc>Update a group</doc>
987
+ <param name="id" type="integer" required="true"/>
988
+ <param name="data" type="array" location="body" filters="json_encode" doc="Group JSON"/>
989
+ <param name="Content-Type" location="header" static="application/json"/>
990
+ </command>
991
+ </commands>
992
+ </client>
993
+ ```
994
+
995
+ **After**
996
+
997
+ ```json
998
+ {
999
+ "name": "Zendesk REST API v2",
1000
+ "apiVersion": "2012-12-31",
1001
+ "description":"Provides access to Zendesk views, groups, tickets, ticket fields, and users",
1002
+ "operations": {
1003
+ "list_groups": {
1004
+ "httpMethod":"GET",
1005
+ "uri": "groups.json",
1006
+ "summary": "Get a list of groups"
1007
+ },
1008
+ "search_groups":{
1009
+ "httpMethod":"GET",
1010
+ "uri": "search.json?query=\"{query} type:group\"",
1011
+ "summary": "Uses a search query to get a list of groups",
1012
+ "parameters":{
1013
+ "query":{
1014
+ "location": "uri",
1015
+ "description":"Zendesk Search Query",
1016
+ "type": "string",
1017
+ "required": true
1018
+ }
1019
+ }
1020
+ },
1021
+ "create_group": {
1022
+ "httpMethod":"POST",
1023
+ "uri": "groups.json",
1024
+ "summary": "Create a group",
1025
+ "parameters":{
1026
+ "data": {
1027
+ "type": "array",
1028
+ "location": "body",
1029
+ "description":"Group JSON",
1030
+ "filters": "json_encode",
1031
+ "required": true
1032
+ },
1033
+ "Content-Type":{
1034
+ "type": "string",
1035
+ "location":"header",
1036
+ "static": "application/json"
1037
+ }
1038
+ }
1039
+ },
1040
+ "delete_group": {
1041
+ "httpMethod":"DELETE",
1042
+ "uri": "groups/{id}.json",
1043
+ "summary": "Delete a group",
1044
+ "parameters":{
1045
+ "id":{
1046
+ "location": "uri",
1047
+ "description":"Group to delete by ID",
1048
+ "type": "integer",
1049
+ "required": true
1050
+ }
1051
+ }
1052
+ },
1053
+ "get_group": {
1054
+ "httpMethod":"GET",
1055
+ "uri": "groups/{id}.json",
1056
+ "summary": "Get a ticket",
1057
+ "parameters":{
1058
+ "id":{
1059
+ "location": "uri",
1060
+ "description":"Group to get by ID",
1061
+ "type": "integer",
1062
+ "required": true
1063
+ }
1064
+ }
1065
+ },
1066
+ "update_group": {
1067
+ "httpMethod":"PUT",
1068
+ "uri": "groups/{id}.json",
1069
+ "summary": "Update a group",
1070
+ "parameters":{
1071
+ "id": {
1072
+ "location": "uri",
1073
+ "description":"Group to update by ID",
1074
+ "type": "integer",
1075
+ "required": true
1076
+ },
1077
+ "data": {
1078
+ "type": "array",
1079
+ "location": "body",
1080
+ "description":"Group JSON",
1081
+ "filters": "json_encode",
1082
+ "required": true
1083
+ },
1084
+ "Content-Type":{
1085
+ "type": "string",
1086
+ "location":"header",
1087
+ "static": "application/json"
1088
+ }
1089
+ }
1090
+ }
1091
+ }
1092
+ ```
1093
+
1094
+ ### Guzzle\Service\Description\ServiceDescription
1095
+
1096
+ Commands are now called Operations
1097
+
1098
+ **Before**
1099
+
1100
+ ```php
1101
+ use Guzzle\Service\Description\ServiceDescription;
1102
+
1103
+ $sd = new ServiceDescription();
1104
+ $sd->getCommands(); // @returns ApiCommandInterface[]
1105
+ $sd->hasCommand($name);
1106
+ $sd->getCommand($name); // @returns ApiCommandInterface|null
1107
+ $sd->addCommand($command); // @param ApiCommandInterface $command
1108
+ ```
1109
+
1110
+ **After**
1111
+
1112
+ ```php
1113
+ use Guzzle\Service\Description\ServiceDescription;
1114
+
1115
+ $sd = new ServiceDescription();
1116
+ $sd->getOperations(); // @returns OperationInterface[]
1117
+ $sd->hasOperation($name);
1118
+ $sd->getOperation($name); // @returns OperationInterface|null
1119
+ $sd->addOperation($operation); // @param OperationInterface $operation
1120
+ ```
1121
+
1122
+ ### Guzzle\Common\Inflection\Inflector
1123
+
1124
+ Namespace is now `Guzzle\Inflection\Inflector`
1125
+
1126
+ ### Guzzle\Http\Plugin
1127
+
1128
+ Namespace is now `Guzzle\Plugin`. Many other changes occur within this namespace and are detailed in their own sections below.
1129
+
1130
+ ### Guzzle\Http\Plugin\LogPlugin and Guzzle\Common\Log
1131
+
1132
+ Now `Guzzle\Plugin\Log\LogPlugin` and `Guzzle\Log` respectively.
1133
+
1134
+ **Before**
1135
+
1136
+ ```php
1137
+ use Guzzle\Common\Log\ClosureLogAdapter;
1138
+ use Guzzle\Http\Plugin\LogPlugin;
1139
+
1140
+ /** @var \Guzzle\Http\Client */
1141
+ $client;
1142
+
1143
+ // $verbosity is an integer indicating desired message verbosity level
1144
+ $client->addSubscriber(new LogPlugin(new ClosureLogAdapter(function($m) { echo $m; }, $verbosity = LogPlugin::LOG_VERBOSE);
1145
+ ```
1146
+
1147
+ **After**
1148
+
1149
+ ```php
1150
+ use Guzzle\Log\ClosureLogAdapter;
1151
+ use Guzzle\Log\MessageFormatter;
1152
+ use Guzzle\Plugin\Log\LogPlugin;
1153
+
1154
+ /** @var \Guzzle\Http\Client */
1155
+ $client;
1156
+
1157
+ // $format is a string indicating desired message format -- @see MessageFormatter
1158
+ $client->addSubscriber(new LogPlugin(new ClosureLogAdapter(function($m) { echo $m; }, $format = MessageFormatter::DEBUG_FORMAT);
1159
+ ```
1160
+
1161
+ ### Guzzle\Http\Plugin\CurlAuthPlugin
1162
+
1163
+ Now `Guzzle\Plugin\CurlAuth\CurlAuthPlugin`.
1164
+
1165
+ ### Guzzle\Http\Plugin\ExponentialBackoffPlugin
1166
+
1167
+ Now `Guzzle\Plugin\Backoff\BackoffPlugin`, and other changes.
1168
+
1169
+ **Before**
1170
+
1171
+ ```php
1172
+ use Guzzle\Http\Plugin\ExponentialBackoffPlugin;
1173
+
1174
+ $backoffPlugin = new ExponentialBackoffPlugin($maxRetries, array_merge(
1175
+ ExponentialBackoffPlugin::getDefaultFailureCodes(), array(429)
1176
+ ));
1177
+
1178
+ $client->addSubscriber($backoffPlugin);
1179
+ ```
1180
+
1181
+ **After**
1182
+
1183
+ ```php
1184
+ use Guzzle\Plugin\Backoff\BackoffPlugin;
1185
+ use Guzzle\Plugin\Backoff\HttpBackoffStrategy;
1186
+
1187
+ // Use convenient factory method instead -- see implementation for ideas of what
1188
+ // you can do with chaining backoff strategies
1189
+ $backoffPlugin = BackoffPlugin::getExponentialBackoff($maxRetries, array_merge(
1190
+ HttpBackoffStrategy::getDefaultFailureCodes(), array(429)
1191
+ ));
1192
+ $client->addSubscriber($backoffPlugin);
1193
+ ```
1194
+
1195
+ ### Known Issues
1196
+
1197
+ #### [BUG] Accept-Encoding header behavior changed unintentionally.
1198
+
1199
+ (See #217) (Fixed in 09daeb8c666fb44499a0646d655a8ae36456575e)
1200
+
1201
+ In version 2.8 setting the `Accept-Encoding` header would set the CURLOPT_ENCODING option, which permitted cURL to
1202
+ properly handle gzip/deflate compressed responses from the server. In versions affected by this bug this does not happen.
1203
+ See issue #217 for a workaround, or use a version containing the fix.
vendor/guzzlehttp/guzzle/src/Client.php ADDED
@@ -0,0 +1,422 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Cookie\CookieJar;
5
+ use GuzzleHttp\Promise;
6
+ use GuzzleHttp\Psr7;
7
+ use Psr\Http\Message\UriInterface;
8
+ use Psr\Http\Message\RequestInterface;
9
+ use Psr\Http\Message\ResponseInterface;
10
+
11
+ /**
12
+ * @method ResponseInterface get(string|UriInterface $uri, array $options = [])
13
+ * @method ResponseInterface head(string|UriInterface $uri, array $options = [])
14
+ * @method ResponseInterface put(string|UriInterface $uri, array $options = [])
15
+ * @method ResponseInterface post(string|UriInterface $uri, array $options = [])
16
+ * @method ResponseInterface patch(string|UriInterface $uri, array $options = [])
17
+ * @method ResponseInterface delete(string|UriInterface $uri, array $options = [])
18
+ * @method Promise\PromiseInterface getAsync(string|UriInterface $uri, array $options = [])
19
+ * @method Promise\PromiseInterface headAsync(string|UriInterface $uri, array $options = [])
20
+ * @method Promise\PromiseInterface putAsync(string|UriInterface $uri, array $options = [])
21
+ * @method Promise\PromiseInterface postAsync(string|UriInterface $uri, array $options = [])
22
+ * @method Promise\PromiseInterface patchAsync(string|UriInterface $uri, array $options = [])
23
+ * @method Promise\PromiseInterface deleteAsync(string|UriInterface $uri, array $options = [])
24
+ */
25
+ class Client implements ClientInterface
26
+ {
27
+ /** @var array Default request options */
28
+ private $config;
29
+
30
+ /**
31
+ * Clients accept an array of constructor parameters.
32
+ *
33
+ * Here's an example of creating a client using a base_uri and an array of
34
+ * default request options to apply to each request:
35
+ *
36
+ * $client = new Client([
37
+ * 'base_uri' => 'http://www.foo.com/1.0/',
38
+ * 'timeout' => 0,
39
+ * 'allow_redirects' => false,
40
+ * 'proxy' => '192.168.16.1:10'
41
+ * ]);
42
+ *
43
+ * Client configuration settings include the following options:
44
+ *
45
+ * - handler: (callable) Function that transfers HTTP requests over the
46
+ * wire. The function is called with a Psr7\Http\Message\RequestInterface
47
+ * and array of transfer options, and must return a
48
+ * GuzzleHttp\Promise\PromiseInterface that is fulfilled with a
49
+ * Psr7\Http\Message\ResponseInterface on success. "handler" is a
50
+ * constructor only option that cannot be overridden in per/request
51
+ * options. If no handler is provided, a default handler will be created
52
+ * that enables all of the request options below by attaching all of the
53
+ * default middleware to the handler.
54
+ * - base_uri: (string|UriInterface) Base URI of the client that is merged
55
+ * into relative URIs. Can be a string or instance of UriInterface.
56
+ * - **: any request option
57
+ *
58
+ * @param array $config Client configuration settings.
59
+ *
60
+ * @see \GuzzleHttp\RequestOptions for a list of available request options.
61
+ */
62
+ public function __construct(array $config = [])
63
+ {
64
+ if (!isset($config['handler'])) {
65
+ $config['handler'] = HandlerStack::create();
66
+ } elseif (!is_callable($config['handler'])) {
67
+ throw new \InvalidArgumentException('handler must be a callable');
68
+ }
69
+
70
+ // Convert the base_uri to a UriInterface
71
+ if (isset($config['base_uri'])) {
72
+ $config['base_uri'] = Psr7\uri_for($config['base_uri']);
73
+ }
74
+
75
+ $this->configureDefaults($config);
76
+ }
77
+
78
+ public function __call($method, $args)
79
+ {
80
+ if (count($args) < 1) {
81
+ throw new \InvalidArgumentException('Magic request methods require a URI and optional options array');
82
+ }
83
+
84
+ $uri = $args[0];
85
+ $opts = isset($args[1]) ? $args[1] : [];
86
+
87
+ return substr($method, -5) === 'Async'
88
+ ? $this->requestAsync(substr($method, 0, -5), $uri, $opts)
89
+ : $this->request($method, $uri, $opts);
90
+ }
91
+
92
+ public function sendAsync(RequestInterface $request, array $options = [])
93
+ {
94
+ // Merge the base URI into the request URI if needed.
95
+ $options = $this->prepareDefaults($options);
96
+
97
+ return $this->transfer(
98
+ $request->withUri($this->buildUri($request->getUri(), $options), $request->hasHeader('Host')),
99
+ $options
100
+ );
101
+ }
102
+
103
+ public function send(RequestInterface $request, array $options = [])
104
+ {
105
+ $options[RequestOptions::SYNCHRONOUS] = true;
106
+ return $this->sendAsync($request, $options)->wait();
107
+ }
108
+
109
+ public function requestAsync($method, $uri = '', array $options = [])
110
+ {
111
+ $options = $this->prepareDefaults($options);
112
+ // Remove request modifying parameter because it can be done up-front.
113
+ $headers = isset($options['headers']) ? $options['headers'] : [];
114
+ $body = isset($options['body']) ? $options['body'] : null;
115
+ $version = isset($options['version']) ? $options['version'] : '1.1';
116
+ // Merge the URI into the base URI.
117
+ $uri = $this->buildUri($uri, $options);
118
+ if (is_array($body)) {
119
+ $this->invalidBody();
120
+ }
121
+ $request = new Psr7\Request($method, $uri, $headers, $body, $version);
122
+ // Remove the option so that they are not doubly-applied.
123
+ unset($options['headers'], $options['body'], $options['version']);
124
+
125
+ return $this->transfer($request, $options);
126
+ }
127
+
128
+ public function request($method, $uri = '', array $options = [])
129
+ {
130
+ $options[RequestOptions::SYNCHRONOUS] = true;
131
+ return $this->requestAsync($method, $uri, $options)->wait();
132
+ }
133
+
134
+ public function getConfig($option = null)
135
+ {
136
+ return $option === null
137
+ ? $this->config
138
+ : (isset($this->config[$option]) ? $this->config[$option] : null);
139
+ }
140
+
141
+ private function buildUri($uri, array $config)
142
+ {
143
+ // for BC we accept null which would otherwise fail in uri_for
144
+ $uri = Psr7\uri_for($uri === null ? '' : $uri);
145
+
146
+ if (isset($config['base_uri'])) {
147
+ $uri = Psr7\UriResolver::resolve(Psr7\uri_for($config['base_uri']), $uri);
148
+ }
149
+
150
+ return $uri->getScheme() === '' && $uri->getHost() !== '' ? $uri->withScheme('http') : $uri;
151
+ }
152
+
153
+ /**
154
+ * Configures the default options for a client.
155
+ *
156
+ * @param array $config
157
+ */
158
+ private function configureDefaults(array $config)
159
+ {
160
+ $defaults = [
161
+ 'allow_redirects' => RedirectMiddleware::$defaultSettings,
162
+ 'http_errors' => true,
163
+ 'decode_content' => true,
164
+ 'verify' => true,
165
+ 'cookies' => false
166
+ ];
167
+
168
+ // Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set.
169
+
170
+ // We can only trust the HTTP_PROXY environment variable in a CLI
171
+ // process due to the fact that PHP has no reliable mechanism to
172
+ // get environment variables that start with "HTTP_".
173
+ if (php_sapi_name() == 'cli' && getenv('HTTP_PROXY')) {
174
+ $defaults['proxy']['http'] = getenv('HTTP_PROXY');
175
+ }
176
+
177
+ if ($proxy = getenv('HTTPS_PROXY')) {
178
+ $defaults['proxy']['https'] = $proxy;
179
+ }
180
+
181
+ if ($noProxy = getenv('NO_PROXY')) {
182
+ $cleanedNoProxy = str_replace(' ', '', $noProxy);
183
+ $defaults['proxy']['no'] = explode(',', $cleanedNoProxy);
184
+ }
185
+
186
+ $this->config = $config + $defaults;
187
+
188
+ if (!empty($config['cookies']) && $config['cookies'] === true) {
189
+ $this->config['cookies'] = new CookieJar();
190
+ }
191
+
192
+ // Add the default user-agent header.
193
+ if (!isset($this->config['headers'])) {
194
+ $this->config['headers'] = ['User-Agent' => default_user_agent()];
195
+ } else {
196
+ // Add the User-Agent header if one was not already set.
197
+ foreach (array_keys($this->config['headers']) as $name) {
198
+ if (strtolower($name) === 'user-agent') {
199
+ return;
200
+ }
201
+ }
202
+ $this->config['headers']['User-Agent'] = default_user_agent();
203
+ }
204
+ }
205
+
206
+ /**
207
+ * Merges default options into the array.
208
+ *
209
+ * @param array $options Options to modify by reference
210
+ *
211
+ * @return array
212
+ */
213
+ private function prepareDefaults($options)
214
+ {
215
+ $defaults = $this->config;
216
+
217
+ if (!empty($defaults['headers'])) {
218
+ // Default headers are only added if they are not present.
219
+ $defaults['_conditional'] = $defaults['headers'];
220
+ unset($defaults['headers']);
221
+ }
222
+
223
+ // Special handling for headers is required as they are added as
224
+ // conditional headers and as headers passed to a request ctor.
225
+ if (array_key_exists('headers', $options)) {
226
+ // Allows default headers to be unset.
227
+ if ($options['headers'] === null) {
228
+ $defaults['_conditional'] = null;
229
+ unset($options['headers']);
230
+ } elseif (!is_array($options['headers'])) {
231
+ throw new \InvalidArgumentException('headers must be an array');
232
+ }
233
+ }
234
+
235
+ // Shallow merge defaults underneath options.
236
+ $result = $options + $defaults;
237
+
238
+ // Remove null values.
239
+ foreach ($result as $k => $v) {
240
+ if ($v === null) {
241
+ unset($result[$k]);
242
+ }
243
+ }
244
+
245
+ return $result;
246
+ }
247
+
248
+ /**
249
+ * Transfers the given request and applies request options.
250
+ *
251
+ * The URI of the request is not modified and the request options are used
252
+ * as-is without merging in default options.
253
+ *
254
+ * @param RequestInterface $request
255
+ * @param array $options
256
+ *
257
+ * @return Promise\PromiseInterface
258
+ */
259
+ private function transfer(RequestInterface $request, array $options)
260
+ {
261
+ // save_to -> sink
262
+ if (isset($options['save_to'])) {
263
+ $options['sink'] = $options['save_to'];
264
+ unset($options['save_to']);
265
+ }
266
+
267
+ // exceptions -> http_errors
268
+ if (isset($options['exceptions'])) {
269
+ $options['http_errors'] = $options['exceptions'];
270
+ unset($options['exceptions']);
271
+ }
272
+
273
+ $request = $this->applyOptions($request, $options);
274
+ $handler = $options['handler'];
275
+
276
+ try {
277
+ return Promise\promise_for($handler($request, $options));
278
+ } catch (\Exception $e) {
279
+ return Promise\rejection_for($e);
280
+ }
281
+ }
282
+
283
+ /**
284
+ * Applies the array of request options to a request.
285
+ *
286
+ * @param RequestInterface $request
287
+ * @param array $options
288
+ *
289
+ * @return RequestInterface
290
+ */
291
+ private function applyOptions(RequestInterface $request, array &$options)
292
+ {
293
+ $modify = [
294
+ 'set_headers' => [],
295
+ ];
296
+
297
+ if (isset($options['headers'])) {
298
+ $modify['set_headers'] = $options['headers'];
299
+ unset($options['headers']);
300
+ }
301
+
302
+ if (isset($options['form_params'])) {
303
+ if (isset($options['multipart'])) {
304
+ throw new \InvalidArgumentException('You cannot use '
305
+ . 'form_params and multipart at the same time. Use the '
306
+ . 'form_params option if you want to send application/'
307
+ . 'x-www-form-urlencoded requests, and the multipart '
308
+ . 'option to send multipart/form-data requests.');
309
+ }
310
+ $options['body'] = http_build_query($options['form_params'], '', '&');
311
+ unset($options['form_params']);
312
+ // Ensure that we don't have the header in different case and set the new value.
313
+ $options['_conditional'] = Psr7\_caseless_remove(['Content-Type'], $options['_conditional']);
314
+ $options['_conditional']['Content-Type'] = 'application/x-www-form-urlencoded';
315
+ }
316
+
317
+ if (isset($options['multipart'])) {
318
+ $options['body'] = new Psr7\MultipartStream($options['multipart']);
319
+ unset($options['multipart']);
320
+ }
321
+
322
+ if (isset($options['json'])) {
323
+ $options['body'] = \GuzzleHttp\json_encode($options['json']);
324
+ unset($options['json']);
325
+ // Ensure that we don't have the header in different case and set the new value.
326
+ $options['_conditional'] = Psr7\_caseless_remove(['Content-Type'], $options['_conditional']);
327
+ $options['_conditional']['Content-Type'] = 'application/json';
328
+ }
329
+
330
+ if (!empty($options['decode_content'])
331
+ && $options['decode_content'] !== true
332
+ ) {
333
+ // Ensure that we don't have the header in different case and set the new value.
334
+ $options['_conditional'] = Psr7\_caseless_remove(['Accept-Encoding'], $options['_conditional']);
335
+ $modify['set_headers']['Accept-Encoding'] = $options['decode_content'];
336
+ }
337
+
338
+ if (isset($options['body'])) {
339
+ if (is_array($options['body'])) {
340
+ $this->invalidBody();
341
+ }
342
+ $modify['body'] = Psr7\stream_for($options['body']);
343
+ unset($options['body']);
344
+ }
345
+
346
+ if (!empty($options['auth']) && is_array($options['auth'])) {
347
+ $value = $options['auth'];
348
+ $type = isset($value[2]) ? strtolower($value[2]) : 'basic';
349
+ switch ($type) {
350
+ case 'basic':
351
+ // Ensure that we don't have the header in different case and set the new value.
352
+ $modify['set_headers'] = Psr7\_caseless_remove(['Authorization'], $modify['set_headers']);
353
+ $modify['set_headers']['Authorization'] = 'Basic '
354
+ . base64_encode("$value[0]:$value[1]");
355
+ break;
356
+ case 'digest':
357
+ // @todo: Do not rely on curl
358
+ $options['curl'][CURLOPT_HTTPAUTH] = CURLAUTH_DIGEST;
359
+ $options['curl'][CURLOPT_USERPWD] = "$value[0]:$value[1]";
360
+ break;
361
+ case 'ntlm':
362
+ $options['curl'][CURLOPT_HTTPAUTH] = CURLAUTH_NTLM;
363
+ $options['curl'][CURLOPT_USERPWD] = "$value[0]:$value[1]";
364
+ break;
365
+ }
366
+ }
367
+
368
+ if (isset($options['query'])) {
369
+ $value = $options['query'];
370
+ if (is_array($value)) {
371
+ $value = http_build_query($value, null, '&', PHP_QUERY_RFC3986);
372
+ }
373
+ if (!is_string($value)) {
374
+ throw new \InvalidArgumentException('query must be a string or array');
375
+ }
376
+ $modify['query'] = $value;
377
+ unset($options['query']);
378
+ }
379
+
380
+ // Ensure that sink is not an invalid value.
381
+ if (isset($options['sink'])) {
382
+ // TODO: Add more sink validation?
383
+ if (is_bool($options['sink'])) {
384
+ throw new \InvalidArgumentException('sink must not be a boolean');
385
+ }
386
+ }
387
+
388
+ $request = Psr7\modify_request($request, $modify);
389
+ if ($request->getBody() instanceof Psr7\MultipartStream) {
390
+ // Use a multipart/form-data POST if a Content-Type is not set.
391
+ // Ensure that we don't have the header in different case and set the new value.
392
+ $options['_conditional'] = Psr7\_caseless_remove(['Content-Type'], $options['_conditional']);
393
+ $options['_conditional']['Content-Type'] = 'multipart/form-data; boundary='
394
+ . $request->getBody()->getBoundary();
395
+ }
396
+
397
+ // Merge in conditional headers if they are not present.
398
+ if (isset($options['_conditional'])) {
399
+ // Build up the changes so it's in a single clone of the message.
400
+ $modify = [];
401
+ foreach ($options['_conditional'] as $k => $v) {
402
+ if (!$request->hasHeader($k)) {
403
+ $modify['set_headers'][$k] = $v;
404
+ }
405
+ }
406
+ $request = Psr7\modify_request($request, $modify);
407
+ // Don't pass this internal value along to middleware/handlers.
408
+ unset($options['_conditional']);
409
+ }
410
+
411
+ return $request;
412
+ }
413
+
414
+ private function invalidBody()
415
+ {
416
+ throw new \InvalidArgumentException('Passing in the "body" request '
417
+ . 'option as an array to send a POST request has been deprecated. '
418
+ . 'Please use the "form_params" request option to send a '
419
+ . 'application/x-www-form-urlencoded request, or the "multipart" '
420
+ . 'request option to send a multipart/form-data request.');
421
+ }
422
+ }
vendor/guzzlehttp/guzzle/src/ClientInterface.php ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Promise\PromiseInterface;
5
+ use GuzzleHttp\Exception\GuzzleException;
6
+ use Psr\Http\Message\RequestInterface;
7
+ use Psr\Http\Message\ResponseInterface;
8
+ use Psr\Http\Message\UriInterface;
9
+
10
+ /**
11
+ * Client interface for sending HTTP requests.
12
+ */
13
+ interface ClientInterface
14
+ {
15
+ const VERSION = '6.3.3';
16
+
17
+ /**
18
+ * Send an HTTP request.
19
+ *
20
+ * @param RequestInterface $request Request to send
21
+ * @param array $options Request options to apply to the given
22
+ * request and to the transfer.
23
+ *
24
+ * @return ResponseInterface
25
+ * @throws GuzzleException
26
+ */
27
+ public function send(RequestInterface $request, array $options = []);
28
+
29
+ /**
30
+ * Asynchronously send an HTTP request.
31
+ *
32
+ * @param RequestInterface $request Request to send
33
+ * @param array $options Request options to apply to the given
34
+ * request and to the transfer.
35
+ *
36
+ * @return PromiseInterface
37
+ */
38
+ public function sendAsync(RequestInterface $request, array $options = []);
39
+
40
+ /**
41
+ * Create and send an HTTP request.
42
+ *
43
+ * Use an absolute path to override the base path of the client, or a
44
+ * relative path to append to the base path of the client. The URL can
45
+ * contain the query string as well.
46
+ *
47
+ * @param string $method HTTP method.
48
+ * @param string|UriInterface $uri URI object or string.
49
+ * @param array $options Request options to apply.
50
+ *
51
+ * @return ResponseInterface
52
+ * @throws GuzzleException
53
+ */
54
+ public function request($method, $uri, array $options = []);
55
+
56
+ /**
57
+ * Create and send an asynchronous HTTP request.
58
+ *
59
+ * Use an absolute path to override the base path of the client, or a
60
+ * relative path to append to the base path of the client. The URL can
61
+ * contain the query string as well. Use an array to provide a URL
62
+ * template and additional variables to use in the URL template expansion.
63
+ *
64
+ * @param string $method HTTP method
65
+ * @param string|UriInterface $uri URI object or string.
66
+ * @param array $options Request options to apply.
67
+ *
68
+ * @return PromiseInterface
69
+ */
70
+ public function requestAsync($method, $uri, array $options = []);
71
+
72
+ /**
73
+ * Get a client configuration option.
74
+ *
75
+ * These options include default request options of the client, a "handler"
76
+ * (if utilized by the concrete client), and a "base_uri" if utilized by
77
+ * the concrete client.
78
+ *
79
+ * @param string|null $option The config option to retrieve.
80
+ *
81
+ * @return mixed
82
+ */
83
+ public function getConfig($option = null);
84
+ }
vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php ADDED
@@ -0,0 +1,314 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Cookie;
3
+
4
+ use Psr\Http\Message\RequestInterface;
5
+ use Psr\Http\Message\ResponseInterface;
6
+
7
+ /**
8
+ * Cookie jar that stores cookies as an array
9
+ */
10
+ class CookieJar implements CookieJarInterface
11
+ {
12
+ /** @var SetCookie[] Loaded cookie data */
13
+ private $cookies = [];
14
+
15
+ /** @var bool */
16
+ private $strictMode;
17
+
18
+ /**
19
+ * @param bool $strictMode Set to true to throw exceptions when invalid
20
+ * cookies are added to the cookie jar.
21
+ * @param array $cookieArray Array of SetCookie objects or a hash of
22
+ * arrays that can be used with the SetCookie
23
+ * 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
+ * @deprecated
62
+ */
63
+ public static function getCookieValue($value)
64
+ {
65
+ return $value;
66
+ }
67
+
68
+ /**
69
+ * Evaluate if this cookie should be persisted to storage
70
+ * that survives between requests.
71
+ *
72
+ * @param SetCookie $cookie Being evaluated.
73
+ * @param bool $allowSessionCookies If we should persist session cookies
74
+ * @return bool
75
+ */
76
+ public static function shouldPersist(
77
+ SetCookie $cookie,
78
+ $allowSessionCookies = false
79
+ ) {
80
+ if ($cookie->getExpires() || $allowSessionCookies) {
81
+ if (!$cookie->getDiscard()) {
82
+ return true;
83
+ }
84
+ }
85
+
86
+ return false;
87
+ }
88
+
89
+ /**
90
+ * Finds and returns the cookie based on the name
91
+ *
92
+ * @param string $name cookie name to search for
93
+ * @return SetCookie|null cookie that was found or null if not found
94
+ */
95
+ public function getCookieByName($name)
96
+ {
97
+ // don't allow a null name
98
+ if ($name === null) {
99
+ return null;
100
+ }
101
+ foreach ($this->cookies as $cookie) {
102
+ if ($cookie->getName() !== null && strcasecmp($cookie->getName(), $name) === 0) {
103
+ return $cookie;
104
+ }
105
+ }
106
+ }
107
+
108
+ public function toArray()
109
+ {
110
+ return array_map(function (SetCookie $cookie) {
111
+ return $cookie->toArray();
112
+ }, $this->getIterator()->getArrayCopy());
113
+ }
114
+
115
+ public function clear($domain = null, $path = null, $name = null)
116
+ {
117
+ if (!$domain) {
118
+ $this->cookies = [];
119
+ return;
120
+ } elseif (!$path) {
121
+ $this->cookies = array_filter(
122
+ $this->cookies,
123
+ function (SetCookie $cookie) use ($path, $domain) {
124
+ return !$cookie->matchesDomain($domain);
125
+ }
126
+ );
127
+ } elseif (!$name) {
128
+ $this->cookies = array_filter(
129
+ $this->cookies,
130
+ function (SetCookie $cookie) use ($path, $domain) {
131
+ return !($cookie->matchesPath($path) &&
132
+ $cookie->matchesDomain($domain));
133
+ }
134
+ );
135
+ } else {
136
+ $this->cookies = array_filter(
137
+ $this->cookies,
138
+ function (SetCookie $cookie) use ($path, $domain, $name) {
139
+ return !($cookie->getName() == $name &&
140
+ $cookie->matchesPath($path) &&
141
+ $cookie->matchesDomain($domain));
142
+ }
143
+ );
144
+ }
145
+ }
146
+
147
+ public function clearSessionCookies()
148
+ {
149
+ $this->cookies = array_filter(
150
+ $this->cookies,
151
+ function (SetCookie $cookie) {
152
+ return !$cookie->getDiscard() && $cookie->getExpires();
153
+ }
154
+ );
155
+ }
156
+
157
+ public function setCookie(SetCookie $cookie)
158
+ {
159
+ // If the name string is empty (but not 0), ignore the set-cookie
160
+ // string entirely.
161
+ $name = $cookie->getName();
162
+ if (!$name && $name !== '0') {
163
+ return false;
164
+ }
165
+
166
+ // Only allow cookies with set and valid domain, name, value
167
+ $result = $cookie->validate();
168
+ if ($result !== true) {
169
+ if ($this->strictMode) {
170
+ throw new \RuntimeException('Invalid cookie: ' . $result);
171
+ } else {
172
+ $this->removeCookieIfEmpty($cookie);
173
+ return false;
174
+ }
175
+ }
176
+
177
+ // Resolve conflicts with previously set cookies
178
+ foreach ($this->cookies as $i => $c) {
179
+
180
+ // Two cookies are identical, when their path, and domain are
181
+ // identical.
182
+ if ($c->getPath() != $cookie->getPath() ||
183
+ $c->getDomain() != $cookie->getDomain() ||
184
+ $c->getName() != $cookie->getName()
185
+ ) {
186
+ continue;
187
+ }
188
+
189
+ // The previously set cookie is a discard cookie and this one is
190
+ // not so allow the new cookie to be set
191
+ if (!$cookie->getDiscard() && $c->getDiscard()) {
192
+ unset($this->cookies[$i]);
193
+ continue;
194
+ }
195
+
196
+ // If the new cookie's expiration is further into the future, then
197
+ // replace the old cookie
198
+ if ($cookie->getExpires() > $c->getExpires()) {
199
+ unset($this->cookies[$i]);
200
+ continue;
201
+ }
202
+
203
+ // If the value has changed, we better change it
204
+ if ($cookie->getValue() !== $c->getValue()) {
205
+ unset($this->cookies[$i]);
206
+ continue;
207
+ }
208
+
209
+ // The cookie exists, so no need to continue
210
+ return false;
211
+ }
212
+
213
+ $this->cookies[] = $cookie;
214
+
215
+ return true;
216
+ }
217
+
218
+ public function count()
219
+ {
220
+ return count($this->cookies);
221
+ }
222
+
223
+ public function getIterator()
224
+ {
225
+ return new \ArrayIterator(array_values($this->cookies));
226
+ }
227
+
228
+ public function extractCookies(
229
+ RequestInterface $request,
230
+ ResponseInterface $response
231
+ ) {
232
+ if ($cookieHeader = $response->getHeader('Set-Cookie')) {
233
+ foreach ($cookieHeader as $cookie) {
234
+ $sc = SetCookie::fromString($cookie);
235
+ if (!$sc->getDomain()) {
236
+ $sc->setDomain($request->getUri()->getHost());
237
+ }
238
+ if (0 !== strpos($sc->getPath(), '/')) {
239
+ $sc->setPath($this->getCookiePathFromRequest($request));
240
+ }
241
+ $this->setCookie($sc);
242
+ }
243
+ }
244
+ }
245
+
246
+ /**
247
+ * Computes cookie path following RFC 6265 section 5.1.4
248
+ *
249
+ * @link https://tools.ietf.org/html/rfc6265#section-5.1.4
250
+ *
251
+ * @param RequestInterface $request
252
+ * @return string
253
+ */
254
+ private function getCookiePathFromRequest(RequestInterface $request)
255
+ {
256
+ $uriPath = $request->getUri()->getPath();
257
+ if ('' === $uriPath) {
258
+ return '/';
259
+ }
260
+ if (0 !== strpos($uriPath, '/')) {
261
+ return '/';
262
+ }
263
+ if ('/' === $uriPath) {
264
+ return '/';
265
+ }
266
+ if (0 === $lastSlashPos = strrpos($uriPath, '/')) {
267
+ return '/';
268
+ }
269
+
270
+ return substr($uriPath, 0, $lastSlashPos);
271
+ }
272
+
273
+ public function withCookieHeader(RequestInterface $request)
274
+ {
275
+ $values = [];
276
+ $uri = $request->getUri();
277
+ $scheme = $uri->getScheme();
278
+ $host = $uri->getHost();
279
+ $path = $uri->getPath() ?: '/';
280
+
281
+ foreach ($this->cookies as $cookie) {
282
+ if ($cookie->matchesPath($path) &&
283
+ $cookie->matchesDomain($host) &&
284
+ !$cookie->isExpired() &&
285
+ (!$cookie->getSecure() || $scheme === 'https')
286
+ ) {
287
+ $values[] = $cookie->getName() . '='
288
+ . $cookie->getValue();
289
+ }
290
+ }
291
+
292
+ return $values
293
+ ? $request->withHeader('Cookie', implode('; ', $values))
294
+ : $request;
295
+ }
296
+
297
+ /**
298
+ * If a cookie already exists and the server asks to set it again with a
299
+ * null value, the cookie must be deleted.
300
+ *
301
+ * @param SetCookie $cookie
302
+ */
303
+ private function removeCookieIfEmpty(SetCookie $cookie)
304
+ {
305
+ $cookieValue = $cookie->getValue();
306
+ if ($cookieValue === null || $cookieValue === '') {
307
+ $this->clear(
308
+ $cookie->getDomain(),
309
+ $cookie->getPath(),
310
+ $cookie->getName()
311
+ );
312
+ }
313
+ }
314
+ }
vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Cookie;
3
+
4
+ use Psr\Http\Message\RequestInterface;
5
+ use Psr\Http\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
+ * Create a request with added cookie headers.
21
+ *
22
+ * If no matching cookies are found in the cookie jar, then no Cookie
23
+ * header is added to the request and the same request is returned.
24
+ *
25
+ * @param RequestInterface $request Request object to modify.
26
+ *
27
+ * @return RequestInterface returns the modified request.
28
+ */
29
+ public function withCookieHeader(RequestInterface $request);
30
+
31
+ /**
32
+ * Extract cookies from an HTTP response and store them in the CookieJar.
33
+ *
34
+ * @param RequestInterface $request Request that was sent
35
+ * @param ResponseInterface $response Response that was received
36
+ */
37
+ public function extractCookies(
38
+ RequestInterface $request,
39
+ ResponseInterface $response
40
+ );
41
+
42
+ /**
43
+ * Sets a cookie in the cookie jar.
44
+ *
45
+ * @param SetCookie $cookie Cookie to set.
46
+ *
47
+ * @return bool Returns true on success or false on failure
48
+ */
49
+ public function setCookie(SetCookie $cookie);
50
+
51
+ /**
52
+ * Remove cookies currently held in the cookie jar.
53
+ *
54
+ * Invoking this method without arguments will empty the whole cookie jar.
55
+ * If given a $domain argument only cookies belonging to that domain will
56
+ * be removed. If given a $domain and $path argument, cookies belonging to
57
+ * the specified path within that domain are removed. If given all three
58
+ * arguments, then the cookie with the specified name, path and domain is
59
+ * removed.
60
+ *
61
+ * @param string $domain Clears cookies matching a domain
62
+ * @param string $path Clears cookies matching a domain and path
63
+ * @param string $name Clears cookies matching a domain, path, and name
64
+ *
65
+ * @return CookieJarInterface
66
+ */
67
+ public function clear($domain = null, $path = null, $name = null);
68
+
69
+ /**
70
+ * Discard all sessions cookies.
71
+ *
72
+ * Removes cookies that don't have an expire field or a have a discard
73
+ * field set to true. To be called when the user agent shuts down according
74
+ * to RFC 2965.
75
+ */
76
+ public function clearSessionCookies();
77
+
78
+ /**
79
+ * Converts the cookie jar to an array.
80
+ *
81
+ * @return array
82
+ */
83
+ public function toArray();
84
+ }
vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Cookie;
3
+
4
+ /**
5
+ * Persists non-session cookies using a JSON formatted file
6
+ */
7
+ class FileCookieJar extends CookieJar
8
+ {
9
+ /** @var string filename */
10
+ private $filename;
11
+
12
+ /** @var bool Control whether to persist session cookies or not. */
13
+ private $storeSessionCookies;
14
+
15
+ /**
16
+ * Create a new FileCookieJar object
17
+ *
18
+ * @param string $cookieFile File to store the cookie data
19
+ * @param bool $storeSessionCookies Set to true to store session cookies
20
+ * in the cookie jar.
21
+ *
22
+ * @throws \RuntimeException if the file cannot be found or created
23
+ */
24
+ public function __construct($cookieFile, $storeSessionCookies = false)
25
+ {
26
+ $this->filename = $cookieFile;
27
+ $this->storeSessionCookies = $storeSessionCookies;
28
+
29
+ if (file_exists($cookieFile)) {
30
+ $this->load($cookieFile);
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Saves the file when shutting down
36
+ */
37
+ public function __destruct()
38
+ {
39
+ $this->save($this->filename);
40
+ }
41
+
42
+ /**
43
+ * Saves the cookies to a file.
44
+ *
45
+ * @param string $filename File to save
46
+ * @throws \RuntimeException if the file cannot be found or created
47
+ */
48
+ public function save($filename)
49
+ {
50
+ $json = [];
51
+ foreach ($this as $cookie) {
52
+ /** @var SetCookie $cookie */
53
+ if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
54
+ $json[] = $cookie->toArray();
55
+ }
56
+ }
57
+
58
+ $jsonStr = \GuzzleHttp\json_encode($json);
59
+ if (false === file_put_contents($filename, $jsonStr)) {
60
+ throw new \RuntimeException("Unable to save file {$filename}");
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Load cookies from a JSON formatted file.
66
+ *
67
+ * Old cookies are kept unless overwritten by newly loaded ones.
68
+ *
69
+ * @param string $filename Cookie file to load.
70
+ * @throws \RuntimeException if the file cannot be loaded.
71
+ */
72
+ public function load($filename)
73
+ {
74
+ $json = file_get_contents($filename);
75
+ if (false === $json) {
76
+ throw new \RuntimeException("Unable to load file {$filename}");
77
+ } elseif ($json === '') {
78
+ return;
79
+ }
80
+
81
+ $data = \GuzzleHttp\json_decode($json, true);
82
+ if (is_array($data)) {
83
+ foreach (json_decode($json, true) as $cookie) {
84
+ $this->setCookie(new SetCookie($cookie));
85
+ }
86
+ } elseif (strlen($data)) {
87
+ throw new \RuntimeException("Invalid cookie file: {$filename}");
88
+ }
89
+ }
90
+ }
vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Cookie;
3
+
4
+ /**
5
+ * Persists cookies in the client session
6
+ */
7
+ class SessionCookieJar extends CookieJar
8
+ {
9
+ /** @var string session key */
10
+ private $sessionKey;
11
+
12
+ /** @var bool Control whether to persist session cookies or not. */
13
+ private $storeSessionCookies;
14
+
15
+ /**
16
+ * Create a new SessionCookieJar object
17
+ *
18
+ * @param string $sessionKey Session key name to store the cookie
19
+ * data in session
20
+ * @param bool $storeSessionCookies Set to true to store session cookies
21
+ * in the cookie jar.
22
+ */
23
+ public function __construct($sessionKey, $storeSessionCookies = false)
24
+ {
25
+ $this->sessionKey = $sessionKey;
26
+ $this->storeSessionCookies = $storeSessionCookies;
27
+ $this->load();
28
+ }
29
+
30
+ /**
31
+ * Saves cookies to session when shutting down
32
+ */
33
+ public function __destruct()
34
+ {
35
+ $this->save();
36
+ }
37
+
38
+ /**
39
+ * Save cookies to the client session
40
+ */
41
+ public function save()
42
+ {
43
+ $json = [];
44
+ foreach ($this as $cookie) {
45
+ /** @var SetCookie $cookie */
46
+ if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
47
+ $json[] = $cookie->toArray();
48
+ }
49
+ }
50
+
51
+ $_SESSION[$this->sessionKey] = json_encode($json);
52
+ }
53
+
54
+ /**
55
+ * Load the contents of the client session into the data array
56
+ */
57
+ protected function load()
58
+ {
59
+ if (!isset($_SESSION[$this->sessionKey])) {
60
+ return;
61
+ }
62
+ $data = json_decode($_SESSION[$this->sessionKey], true);
63
+ if (is_array($data)) {
64
+ foreach ($data as $cookie) {
65
+ $this->setCookie(new SetCookie($cookie));
66
+ }
67
+ } elseif (strlen($data)) {
68
+ throw new \RuntimeException("Invalid cookie data");
69
+ }
70
+ }
71
+ }
vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php ADDED
@@ -0,0 +1,403 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Cookie;
3
+
4
+ /**
5
+ * Set-Cookie object
6
+ */
7
+ class SetCookie
8
+ {
9
+ /** @var array */
10
+ private static $defaults = [
11
+ 'Name' => null,
12
+ 'Value' => null,
13
+ 'Domain' => null,
14
+ 'Path' => '/',
15
+ 'Max-Age' => null,
16
+ 'Expires' => null,
17
+ 'Secure' => false,
18
+ 'Discard' => false,
19
+ 'HttpOnly' => false
20
+ ];
21
+
22
+ /** @var array Cookie data */
23
+ private $data;
24
+
25
+ /**
26
+ * Create a new SetCookie object from a string
27
+ *
28
+ * @param string $cookie Set-Cookie header string
29
+ *
30
+ * @return self
31
+ */
32
+ public static function fromString($cookie)
33
+ {
34
+ // Create the default return array
35
+ $data = self::$defaults;
36
+ // Explode the cookie string using a series of semicolons
37
+ $pieces = array_filter(array_map('trim', explode(';', $cookie)));
38
+ // The name of the cookie (first kvp) must exist and include an equal sign.
39
+ if (empty($pieces[0]) || !strpos($pieces[0], '=')) {
40
+ return new self($data);
41
+ }
42
+
43
+ // Add the cookie pieces into the parsed data array
44
+ foreach ($pieces as $part) {
45
+ $cookieParts = explode('=', $part, 2);
46
+ $key = trim($cookieParts[0]);
47
+ $value = isset($cookieParts[1])
48
+ ? trim($cookieParts[1], " \n\r\t\0\x0B")
49
+ : true;
50
+
51
+ // Only check for non-cookies when cookies have been found
52
+ if (empty($data['Name'])) {
53
+ $data['Name'] = $key;
54
+ $data['Value'] = $value;
55
+ } else {
56
+ foreach (array_keys(self::$defaults) as $search) {
57
+ if (!strcasecmp($search, $key)) {
58
+ $data[$search] = $value;
59
+ continue 2;
60
+ }
61
+ }
62
+ $data[$key] = $value;
63
+ }
64
+ }
65
+
66
+ return new self($data);
67
+ }
68
+
69
+ /**
70
+ * @param array $data Array of cookie data provided by a Cookie parser
71
+ */
72
+ public function __construct(array $data = [])
73
+ {
74
+ $this->data = array_replace(self::$defaults, $data);
75
+ // Extract the Expires value and turn it into a UNIX timestamp if needed
76
+ if (!$this->getExpires() && $this->getMaxAge()) {
77
+ // Calculate the Expires date
78
+ $this->setExpires(time() + $this->getMaxAge());
79
+ } elseif ($this->getExpires() && !is_numeric($this->getExpires())) {
80
+ $this->setExpires($this->getExpires());
81
+ }
82
+ }
83
+
84
+ public function __toString()
85
+ {
86
+ $str = $this->data['Name'] . '=' . $this->data['Value'] . '; ';
87
+ foreach ($this->data as $k => $v) {
88
+ if ($k !== 'Name' && $k !== 'Value' && $v !== null && $v !== false) {
89
+ if ($k === 'Expires') {
90
+ $str .= 'Expires=' . gmdate('D, d M Y H:i:s \G\M\T', $v) . '; ';
91
+ } else {
92
+ $str .= ($v === true ? $k : "{$k}={$v}") . '; ';
93
+ }
94
+ }
95
+ }
96
+
97
+ return rtrim($str, '; ');
98
+ }
99
+
100
+ public function toArray()
101
+ {
102
+ return $this->data;
103
+ }
104
+
105
+ /**
106
+ * Get the cookie name
107
+ *
108
+ * @return string
109
+ */
110
+ public function getName()
111
+ {
112
+ return $this->data['Name'];
113
+ }
114
+
115
+ /**
116
+ * Set the cookie name
117
+ *
118
+ * @param string $name Cookie name
119
+ */
120
+ public function setName($name)
121
+ {
122
+ $this->data['Name'] = $name;
123
+ }
124
+
125
+ /**
126
+ * Get the cookie value
127
+ *
128
+ * @return string
129
+ */
130
+ public function getValue()
131
+ {
132
+ return $this->data['Value'];
133
+ }
134
+
135
+ /**
136
+ * Set the cookie value
137
+ *
138
+ * @param string $value Cookie value
139
+ */
140
+ public function setValue($value)
141
+ {
142
+ $this->data['Value'] = $value;
143
+ }
144
+
145
+ /**
146
+ * Get the domain
147
+ *
148
+ * @return string|null
149
+ */
150
+ public function getDomain()
151
+ {
152
+ return $this->data['Domain'];
153
+ }
154
+
155
+ /**
156
+ * Set the domain of the cookie
157
+ *
158
+ * @param string $domain
159
+ */
160
+ public function setDomain($domain)
161
+ {
162
+ $this->data['Domain'] = $domain;
163
+ }
164
+
165
+ /**
166
+ * Get the path
167
+ *
168
+ * @return string
169
+ */
170
+ public function getPath()
171
+ {
172
+ return $this->data['Path'];
173
+ }
174
+
175
+ /**
176
+ * Set the path of the cookie
177
+ *
178
+ * @param string $path Path of the cookie
179
+ */
180
+ public function setPath($path)
181
+ {
182
+ $this->data['Path'] = $path;
183
+ }
184
+
185
+ /**
186
+ * Maximum lifetime of the cookie in seconds
187
+ *
188
+ * @return int|null
189
+ */
190
+ public function getMaxAge()
191
+ {
192
+ return $this->data['Max-Age'];
193
+ }
194
+
195
+ /**
196
+ * Set the max-age of the cookie
197
+ *
198
+ * @param int $maxAge Max age of the cookie in seconds
199
+ */
200
+ public function setMaxAge($maxAge)
201
+ {
202
+ $this->data['Max-Age'] = $maxAge;
203
+ }
204
+
205
+ /**
206
+ * The UNIX timestamp when the cookie Expires
207
+ *
208
+ * @return mixed
209
+ */
210
+ public function getExpires()
211
+ {
212
+ return $this->data['Expires'];
213
+ }
214
+
215
+ /**
216
+ * Set the unix timestamp for which the cookie will expire
217
+ *
218
+ * @param int $timestamp Unix timestamp
219
+ */
220
+ public function setExpires($timestamp)
221
+ {
222
+ $this->data['Expires'] = is_numeric($timestamp)
223
+ ? (int) $timestamp
224
+ : strtotime($timestamp);
225
+ }
226
+
227
+ /**
228
+ * Get whether or not this is a secure cookie
229
+ *
230
+ * @return null|bool
231
+ */
232
+ public function getSecure()
233
+ {
234
+ return $this->data['Secure'];
235
+ }
236
+
237
+ /**
238
+ * Set whether or not the cookie is secure
239
+ *
240
+ * @param bool $secure Set to true or false if secure
241
+ */
242
+ public function setSecure($secure)
243
+ {
244
+ $this->data['Secure'] = $secure;
245
+ }
246
+
247
+ /**
248
+ * Get whether or not this is a session cookie
249
+ *
250
+ * @return null|bool
251
+ */
252
+ public function getDiscard()
253
+ {
254
+ return $this->data['Discard'];
255
+ }
256
+
257
+ /**
258
+ * Set whether or not this is a session cookie
259
+ *
260
+ * @param bool $discard Set to true or false if this is a session cookie
261
+ */
262
+ public function setDiscard($discard)
263
+ {
264
+ $this->data['Discard'] = $discard;
265
+ }
266
+
267
+ /**
268
+ * Get whether or not this is an HTTP only cookie
269
+ *
270
+ * @return bool
271
+ */
272
+ public function getHttpOnly()
273
+ {
274
+ return $this->data['HttpOnly'];
275
+ }
276
+
277
+ /**
278
+ * Set whether or not this is an HTTP only cookie
279
+ *
280
+ * @param bool $httpOnly Set to true or false if this is HTTP only
281
+ */
282
+ public function setHttpOnly($httpOnly)
283
+ {
284
+ $this->data['HttpOnly'] = $httpOnly;
285
+ }
286
+
287
+ /**
288
+ * Check if the cookie matches a path value.
289
+ *
290
+ * A request-path path-matches a given cookie-path if at least one of
291
+ * the following conditions holds:
292
+ *
293
+ * - The cookie-path and the request-path are identical.
294
+ * - The cookie-path is a prefix of the request-path, and the last
295
+ * character of the cookie-path is %x2F ("/").
296
+ * - The cookie-path is a prefix of the request-path, and the first
297
+ * character of the request-path that is not included in the cookie-
298
+ * path is a %x2F ("/") character.
299
+ *
300
+ * @param string $requestPath Path to check against
301
+ *
302
+ * @return bool
303
+ */
304
+ public function matchesPath($requestPath)
305
+ {
306
+ $cookiePath = $this->getPath();
307
+
308
+ // Match on exact matches or when path is the default empty "/"
309
+ if ($cookiePath === '/' || $cookiePath == $requestPath) {
310
+ return true;
311
+ }
312
+
313
+ // Ensure that the cookie-path is a prefix of the request path.
314
+ if (0 !== strpos($requestPath, $cookiePath)) {
315
+ return false;
316
+ }
317
+
318
+ // Match if the last character of the cookie-path is "/"
319
+ if (substr($cookiePath, -1, 1) === '/') {
320
+ return true;
321
+ }
322
+
323
+ // Match if the first character not included in cookie path is "/"
324
+ return substr($requestPath, strlen($cookiePath), 1) === '/';
325
+ }
326
+
327
+ /**
328
+ * Check if the cookie matches a domain value
329
+ *
330
+ * @param string $domain Domain to check against
331
+ *
332
+ * @return bool
333
+ */
334
+ public function matchesDomain($domain)
335
+ {
336
+ // Remove the leading '.' as per spec in RFC 6265.
337
+ // http://tools.ietf.org/html/rfc6265#section-5.2.3
338
+ $cookieDomain = ltrim($this->getDomain(), '.');
339
+
340
+ // Domain not set or exact match.
341
+ if (!$cookieDomain || !strcasecmp($domain, $cookieDomain)) {
342
+ return true;
343
+ }
344
+
345
+ // Matching the subdomain according to RFC 6265.
346
+ // http://tools.ietf.org/html/rfc6265#section-5.1.3
347
+ if (filter_var($domain, FILTER_VALIDATE_IP)) {
348
+ return false;
349
+ }
350
+
351
+ return (bool) preg_match('/\.' . preg_quote($cookieDomain, '/') . '$/', $domain);
352
+ }
353
+
354
+ /**
355
+ * Check if the cookie is expired
356
+ *
357
+ * @return bool
358
+ */
359
+ public function isExpired()
360
+ {
361
+ return $this->getExpires() !== null && time() > $this->getExpires();
362
+ }
363
+
364
+ /**
365
+ * Check if the cookie is valid according to RFC 6265
366
+ *
367
+ * @return bool|string Returns true if valid or an error message if invalid
368
+ */
369
+ public function validate()
370
+ {
371
+ // Names must not be empty, but can be 0
372
+ $name = $this->getName();
373
+ if (empty($name) && !is_numeric($name)) {
374
+ return 'The cookie name must not be empty';
375
+ }
376
+
377
+ // Check if any of the invalid characters are present in the cookie name
378
+ if (preg_match(
379
+ '/[\x00-\x20\x22\x28-\x29\x2c\x2f\x3a-\x40\x5c\x7b\x7d\x7f]/',
380
+ $name
381
+ )) {
382
+ return 'Cookie name must not contain invalid characters: ASCII '
383
+ . 'Control characters (0-31;127), space, tab and the '
384
+ . 'following characters: ()<>@,;:\"/?={}';
385
+ }
386
+
387
+ // Value must not be empty, but can be 0
388
+ $value = $this->getValue();
389
+ if (empty($value) && !is_numeric($value)) {
390
+ return 'The cookie value must not be empty';
391
+ }
392
+
393
+ // Domains must not be empty, but can be 0
394
+ // A "0" is not a valid internet domain, but may be used as server name
395
+ // in a private network.
396
+ $domain = $this->getDomain();
397
+ if (empty($domain) && !is_numeric($domain)) {
398
+ return 'The cookie domain must not be empty';
399
+ }
400
+
401
+ return true;
402
+ }
403
+ }
vendor/guzzlehttp/guzzle/src/Exception/BadResponseException.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ use Psr\Http\Message\RequestInterface;
5
+ use Psr\Http\Message\ResponseInterface;
6
+
7
+ /**
8
+ * Exception when an HTTP error occurs (4xx or 5xx error)
9
+ */
10
+ class BadResponseException extends RequestException
11
+ {
12
+ public function __construct(
13
+ $message,
14
+ RequestInterface $request,
15
+ ResponseInterface $response = null,
16
+ \Exception $previous = null,
17
+ array $handlerContext = []
18
+ ) {
19
+ if (null === $response) {
20
+ @trigger_error(
21
+ 'Instantiating the ' . __CLASS__ . ' class without a Response is deprecated since version 6.3 and will be removed in 7.0.',
22
+ E_USER_DEPRECATED
23
+ );
24
+ }
25
+ parent::__construct($message, $request, $response, $previous, $handlerContext);
26
+ }
27
+ }
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 {}
vendor/guzzlehttp/guzzle/src/Exception/ConnectException.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ use Psr\Http\Message\RequestInterface;
5
+
6
+ /**
7
+ * Exception thrown when a connection cannot be established.
8
+ *
9
+ * Note that no response is present for a ConnectException
10
+ */
11
+ class ConnectException extends RequestException
12
+ {
13
+ public function __construct(
14
+ $message,
15
+ RequestInterface $request,
16
+ \Exception $previous = null,
17
+ array $handlerContext = []
18
+ ) {
19
+ parent::__construct($message, $request, null, $previous, $handlerContext);
20
+ }
21
+
22
+ /**
23
+ * @return null
24
+ */
25
+ public function getResponse()
26
+ {
27
+ return null;
28
+ }
29
+
30
+ /**
31
+ * @return bool
32
+ */
33
+ public function hasResponse()
34
+ {
35
+ return false;
36
+ }
37
+ }
vendor/guzzlehttp/guzzle/src/Exception/GuzzleException.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ /**
5
+ * @method string getMessage()
6
+ * @method \Throwable|null getPrevious()
7
+ * @method mixed getCode()
8
+ * @method string getFile()
9
+ * @method int getLine()
10
+ * @method array getTrace()
11
+ * @method string getTraceAsString()
12
+ */
13
+ interface GuzzleException {}
vendor/guzzlehttp/guzzle/src/Exception/RequestException.php ADDED
@@ -0,0 +1,217 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ use Psr\Http\Message\RequestInterface;
5
+ use Psr\Http\Message\ResponseInterface;
6
+ use GuzzleHttp\Promise\PromiseInterface;
7
+ use Psr\Http\Message\UriInterface;
8
+
9
+ /**
10
+ * HTTP Request exception
11
+ */
12
+ class RequestException extends TransferException
13
+ {
14
+ /** @var RequestInterface */
15
+ private $request;
16
+
17
+ /** @var ResponseInterface */
18
+ private $response;
19
+
20
+ /** @var array */
21
+ private $handlerContext;
22
+
23
+ public function __construct(
24
+ $message,
25
+ RequestInterface $request,
26
+ ResponseInterface $response = null,
27
+ \Exception $previous = null,
28
+ array $handlerContext = []
29
+ ) {
30
+ // Set the code of the exception if the response is set and not future.
31
+ $code = $response && !($response instanceof PromiseInterface)
32
+ ? $response->getStatusCode()
33
+ : 0;
34
+ parent::__construct($message, $code, $previous);
35
+ $this->request = $request;
36
+ $this->response = $response;
37
+ $this->handlerContext = $handlerContext;
38
+ }
39
+
40
+ /**
41
+ * Wrap non-RequestExceptions with a RequestException
42
+ *
43
+ * @param RequestInterface $request
44
+ * @param \Exception $e
45
+ *
46
+ * @return RequestException
47
+ */
48
+ public static function wrapException(RequestInterface $request, \Exception $e)
49
+ {
50
+ return $e instanceof RequestException
51
+ ? $e
52
+ : new RequestException($e->getMessage(), $request, null, $e);
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
+ * @param array $ctx Optional handler context.
62
+ *
63
+ * @return self
64
+ */
65
+ public static function create(
66
+ RequestInterface $request,
67
+ ResponseInterface $response = null,
68
+ \Exception $previous = null,
69
+ array $ctx = []
70
+ ) {
71
+ if (!$response) {
72
+ return new self(
73
+ 'Error completing request',
74
+ $request,
75
+ null,
76
+ $previous,
77
+ $ctx
78
+ );
79
+ }
80
+
81
+ $level = (int) floor($response->getStatusCode() / 100);
82
+ if ($level === 4) {
83
+ $label = 'Client error';
84
+ $className = ClientException::class;
85
+ } elseif ($level === 5) {
86
+ $label = 'Server error';
87
+ $className = ServerException::class;
88
+ } else {
89
+ $label = 'Unsuccessful request';
90
+ $className = __CLASS__;
91
+ }
92
+
93
+ $uri = $request->getUri();
94
+ $uri = static::obfuscateUri($uri);
95
+
96
+ // Client Error: `GET /` resulted in a `404 Not Found` response:
97
+ // <html> ... (truncated)
98
+ $message = sprintf(
99
+ '%s: `%s %s` resulted in a `%s %s` response',
100
+ $label,
101
+ $request->getMethod(),
102
+ $uri,
103
+ $response->getStatusCode(),
104
+ $response->getReasonPhrase()
105
+ );
106
+
107
+ $summary = static::getResponseBodySummary($response);
108
+
109
+ if ($summary !== null) {
110
+ $message .= ":\n{$summary}\n";
111
+ }
112
+
113
+ return new $className($message, $request, $response, $previous, $ctx);
114
+ }
115
+
116
+ /**
117
+ * Get a short summary of the response
118
+ *
119
+ * Will return `null` if the response is not printable.
120
+ *
121
+ * @param ResponseInterface $response
122
+ *
123
+ * @return string|null
124
+ */
125
+ public static function getResponseBodySummary(ResponseInterface $response)
126
+ {
127
+ $body = $response->getBody();
128
+
129
+ if (!$body->isSeekable()) {
130
+ return null;
131
+ }
132
+
133
+ $size = $body->getSize();
134
+
135
+ if ($size === 0) {
136
+ return null;
137
+ }
138
+
139
+ $summary = $body->read(120);
140
+ $body->rewind();
141
+
142
+ if ($size > 120) {
143
+ $summary .= ' (truncated...)';
144
+ }
145
+
146
+ // Matches any printable character, including unicode characters:
147
+ // letters, marks, numbers, punctuation, spacing, and separators.
148
+ if (preg_match('/[^\pL\pM\pN\pP\pS\pZ\n\r\t]/', $summary)) {
149
+ return null;
150
+ }
151
+
152
+ return $summary;
153
+ }
154
+
155
+ /**
156
+ * Obfuscates URI if there is an username and a password present
157
+ *
158
+ * @param UriInterface $uri
159
+ *
160
+ * @return UriInterface
161
+ */
162
+ private static function obfuscateUri($uri)
163
+ {
164
+ $userInfo = $uri->getUserInfo();
165
+
166
+ if (false !== ($pos = strpos($userInfo, ':'))) {
167
+ return $uri->withUserInfo(substr($userInfo, 0, $pos), '***');
168
+ }
169
+
170
+ return $uri;
171
+ }
172
+
173
+ /**
174
+ * Get the request that caused the exception
175
+ *
176
+ * @return RequestInterface
177
+ */
178
+ public function getRequest()
179
+ {
180
+ return $this->request;
181
+ }
182
+
183
+ /**
184
+ * Get the associated response
185
+ *
186
+ * @return ResponseInterface|null
187
+ */
188
+ public function getResponse()
189
+ {
190
+ return $this->response;
191
+ }
192
+
193
+ /**
194
+ * Check if a response was received
195
+ *
196
+ * @return bool
197
+ */
198
+ public function hasResponse()
199
+ {
200
+ return $this->response !== null;
201
+ }
202
+
203
+ /**
204
+ * Get contextual information about the error from the underlying handler.
205
+ *
206
+ * The contents of this array will vary depending on which handler you are
207
+ * using. It may also be just an empty array. Relying on this data will
208
+ * couple you to a specific handler, but can give more debug information
209
+ * when needed.
210
+ *
211
+ * @return array
212
+ */
213
+ public function getHandlerContext()
214
+ {
215
+ return $this->handlerContext;
216
+ }
217
+ }
vendor/guzzlehttp/guzzle/src/Exception/SeekException.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ use Psr\Http\Message\StreamInterface;
5
+
6
+ /**
7
+ * Exception thrown when a seek fails on a stream.
8
+ */
9
+ class SeekException extends \RuntimeException implements GuzzleException
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
+ }
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 {}
vendor/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ class TooManyRedirectsException extends RequestException {}
vendor/guzzlehttp/guzzle/src/Exception/TransferException.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ class TransferException extends \RuntimeException implements GuzzleException {}
vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php ADDED
@@ -0,0 +1,565 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Handler;
3
+
4
+ use GuzzleHttp\Exception\RequestException;
5
+ use GuzzleHttp\Exception\ConnectException;
6
+ use GuzzleHttp\Promise\FulfilledPromise;
7
+ use GuzzleHttp\Psr7;
8
+ use GuzzleHttp\Psr7\LazyOpenStream;
9
+ use GuzzleHttp\TransferStats;
10
+ use Psr\Http\Message\RequestInterface;
11
+
12
+ /**
13
+ * Creates curl resources from a request
14
+ */
15
+ class CurlFactory implements CurlFactoryInterface
16
+ {
17
+ /** @var array */
18
+ private $handles = [];
19
+
20
+ /** @var int Total number of idle handles to keep in cache */
21
+ private $maxHandles;
22
+
23
+ /**
24
+ * @param int $maxHandles Maximum number of idle handles.
25
+ */
26
+ public function __construct($maxHandles)
27
+ {
28
+ $this->maxHandles = $maxHandles;
29
+ }
30
+
31
+ public function create(RequestInterface $request, array $options)
32
+ {
33
+ if (isset($options['curl']['body_as_string'])) {
34
+ $options['_body_as_string'] = $options['curl']['body_as_string'];
35
+ unset($options['curl']['body_as_string']);
36
+ }
37
+
38
+ $easy = new EasyHandle;
39
+ $easy->request = $request;
40
+ $easy->options = $options;
41
+ $conf = $this->getDefaultConf($easy);
42
+ $this->applyMethod($easy, $conf);
43
+ $this->applyHandlerOptions($easy, $conf);
44
+ $this->applyHeaders($easy, $conf);
45
+ unset($conf['_headers']);
46
+
47
+ // Add handler options from the request configuration options
48
+ if (isset($options['curl'])) {
49
+ $conf = array_replace($conf, $options['curl']);
50
+ }
51
+
52
+ $conf[CURLOPT_HEADERFUNCTION] = $this->createHeaderFn($easy);
53
+ $easy->handle = $this->handles
54
+ ? array_pop($this->handles)
55
+ : curl_init();
56
+ curl_setopt_array($easy->handle, $conf);
57
+
58
+ return $easy;
59
+ }
60
+
61
+ public function release(EasyHandle $easy)
62
+ {
63
+ $resource = $easy->handle;
64
+ unset($easy->handle);
65
+
66
+ if (count($this->handles) >= $this->maxHandles) {
67
+ curl_close($resource);
68
+ } else {
69
+ // Remove all callback functions as they can hold onto references
70
+ // and are not cleaned up by curl_reset. Using curl_setopt_array
71
+ // does not work for some reason, so removing each one
72
+ // individually.
73
+ curl_setopt($resource, CURLOPT_HEADERFUNCTION, null);
74
+ curl_setopt($resource, CURLOPT_READFUNCTION, null);
75
+ curl_setopt($resource, CURLOPT_WRITEFUNCTION, null);
76
+ curl_setopt($resource, CURLOPT_PROGRESSFUNCTION, null);
77
+ curl_reset($resource);
78
+ $this->handles[] = $resource;
79
+ }
80
+ }
81
+
82
+ /**
83
+ * Completes a cURL transaction, either returning a response promise or a
84
+ * rejected promise.
85
+ *
86
+ * @param callable $handler
87
+ * @param EasyHandle $easy
88
+ * @param CurlFactoryInterface $factory Dictates how the handle is released
89
+ *
90
+ * @return \GuzzleHttp\Promise\PromiseInterface
91
+ */
92
+ public static function finish(
93
+ callable $handler,
94
+ EasyHandle $easy,
95
+ CurlFactoryInterface $factory
96
+ ) {
97
+ if (isset($easy->options['on_stats'])) {
98
+ self::invokeStats($easy);
99
+ }
100
+
101
+ if (!$easy->response || $easy->errno) {
102
+ return self::finishError($handler, $easy, $factory);
103
+ }
104
+
105
+ // Return the response if it is present and there is no error.
106
+ $factory->release($easy);
107
+
108
+ // Rewind the body of the response if possible.
109
+ $body = $easy->response->getBody();
110
+ if ($body->isSeekable()) {
111
+ $body->rewind();
112
+ }
113
+
114
+ return new FulfilledPromise($easy->response);
115
+ }
116
+
117
+ private static function invokeStats(EasyHandle $easy)
118
+ {
119
+ $curlStats = curl_getinfo($easy->handle);
120
+ $stats = new TransferStats(
121
+ $easy->request,
122
+ $easy->response,
123
+ $curlStats['total_time'],
124
+ $easy->errno,
125
+ $curlStats
126
+ );
127
+ call_user_func($easy->options['on_stats'], $stats);
128
+ }
129
+
130
+ private static function finishError(
131
+ callable $handler,
132
+ EasyHandle $easy,
133
+ CurlFactoryInterface $factory
134
+ ) {
135
+ // Get error information and release the handle to the factory.
136
+ $ctx = [
137
+ 'errno' => $easy->errno,
138
+ 'error' => curl_error($easy->handle),
139
+ ] + curl_getinfo($easy->handle);
140
+ $factory->release($easy);
141
+
142
+ // Retry when nothing is present or when curl failed to rewind.
143
+ if (empty($easy->options['_err_message'])
144
+ && (!$easy->errno || $easy->errno == 65)
145
+ ) {
146
+ return self::retryFailedRewind($handler, $easy, $ctx);
147
+ }
148
+
149
+ return self::createRejection($easy, $ctx);
150
+ }
151
+
152
+ private static function createRejection(EasyHandle $easy, array $ctx)
153
+ {
154
+ static $connectionErrors = [
155
+ CURLE_OPERATION_TIMEOUTED => true,
156
+ CURLE_COULDNT_RESOLVE_HOST => true,
157
+ CURLE_COULDNT_CONNECT => true,
158
+ CURLE_SSL_CONNECT_ERROR => true,
159
+ CURLE_GOT_NOTHING => true,
160
+ ];
161
+
162
+ // If an exception was encountered during the onHeaders event, then
163
+ // return a rejected promise that wraps that exception.
164
+ if ($easy->onHeadersException) {
165
+ return \GuzzleHttp\Promise\rejection_for(
166
+ new RequestException(
167
+ 'An error was encountered during the on_headers event',
168
+ $easy->request,
169
+ $easy->response,
170
+ $easy->onHeadersException,
171
+ $ctx
172
+ )
173
+ );
174
+ }
175
+
176
+ $message = sprintf(
177
+ 'cURL error %s: %s (%s)',
178
+ $ctx['errno'],
179
+ $ctx['error'],
180
+ 'see http://curl.haxx.se/libcurl/c/libcurl-errors.html'
181
+ );
182
+
183
+ // Create a connection exception if it was a specific error code.
184
+ $error = isset($connectionErrors[$easy->errno])
185
+ ? new ConnectException($message, $easy->request, null, $ctx)
186
+ : new RequestException($message, $easy->request, $easy->response, null, $ctx);
187
+
188
+ return \GuzzleHttp\Promise\rejection_for($error);
189
+ }
190
+
191
+ private function getDefaultConf(EasyHandle $easy)
192
+ {
193
+ $conf = [
194
+ '_headers' => $easy->request->getHeaders(),
195
+ CURLOPT_CUSTOMREQUEST => $easy->request->getMethod(),
196
+ CURLOPT_URL => (string) $easy->request->getUri()->withFragment(''),
197
+ CURLOPT_RETURNTRANSFER => false,
198
+ CURLOPT_HEADER => false,
199
+ CURLOPT_CONNECTTIMEOUT => 150,
200
+ ];
201
+
202
+ if (defined('CURLOPT_PROTOCOLS')) {
203
+ $conf[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS;
204
+ }
205
+
206
+ $version = $easy->request->getProtocolVersion();
207
+ if ($version == 1.1) {
208
+ $conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1;
209
+ } elseif ($version == 2.0) {
210
+ $conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_2_0;
211
+ } else {
212
+ $conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_0;
213
+ }
214
+
215
+ return $conf;
216
+ }
217
+
218
+ private function applyMethod(EasyHandle $easy, array &$conf)
219
+ {
220
+ $body = $easy->request->getBody();
221
+ $size = $body->getSize();
222
+
223
+ if ($size === null || $size > 0) {
224
+ $this->applyBody($easy->request, $easy->options, $conf);
225
+ return;
226
+ }
227
+
228
+ $method = $easy->request->getMethod();
229
+ if ($method === 'PUT' || $method === 'POST') {
230
+ // See http://tools.ietf.org/html/rfc7230#section-3.3.2
231
+ if (!$easy->request->hasHeader('Content-Length')) {
232
+ $conf[CURLOPT_HTTPHEADER][] = 'Content-Length: 0';
233
+ }
234
+ } elseif ($method === 'HEAD') {
235
+ $conf[CURLOPT_NOBODY] = true;
236
+ unset(
237
+ $conf[CURLOPT_WRITEFUNCTION],
238
+ $conf[CURLOPT_READFUNCTION],
239
+ $conf[CURLOPT_FILE],
240
+ $conf[CURLOPT_INFILE]
241
+ );
242
+ }
243
+ }
244
+
245
+ private function applyBody(RequestInterface $request, array $options, array &$conf)
246
+ {
247
+ $size = $request->hasHeader('Content-Length')
248
+ ? (int) $request->getHeaderLine('Content-Length')
249
+ : null;
250
+
251
+ // Send the body as a string if the size is less than 1MB OR if the
252
+ // [curl][body_as_string] request value is set.
253
+ if (($size !== null && $size < 1000000) ||
254
+ !empty($options['_body_as_string'])
255
+ ) {
256
+ $conf[CURLOPT_POSTFIELDS] = (string) $request->getBody();
257
+ // Don't duplicate the Content-Length header
258
+ $this->removeHeader('Content-Length', $conf);
259
+ $this->removeHeader('Transfer-Encoding', $conf);
260
+ } else {
261
+ $conf[CURLOPT_UPLOAD] = true;
262
+ if ($size !== null) {
263
+ $conf[CURLOPT_INFILESIZE] = $size;
264
+ $this->removeHeader('Content-Length', $conf);
265
+ }
266
+ $body = $request->getBody();
267
+ if ($body->isSeekable()) {
268
+ $body->rewind();
269
+ }
270
+ $conf[CURLOPT_READFUNCTION] = function ($ch, $fd, $length) use ($body) {
271
+ return $body->read($length);
272
+ };
273
+ }
274
+
275
+ // If the Expect header is not present, prevent curl from adding it
276
+ if (!$request->hasHeader('Expect')) {
277
+ $conf[CURLOPT_HTTPHEADER][] = 'Expect:';
278
+ }
279
+
280
+ // cURL sometimes adds a content-type by default. Prevent this.
281
+ if (!$request->hasHeader('Content-Type')) {
282
+ $conf[CURLOPT_HTTPHEADER][] = 'Content-Type:';
283
+ }
284
+ }
285
+
286
+ private function applyHeaders(EasyHandle $easy, array &$conf)
287
+ {
288
+ foreach ($conf['_headers'] as $name => $values) {
289
+ foreach ($values as $value) {
290
+ $value = (string) $value;
291
+ if ($value === '') {
292
+ // cURL requires a special format for empty headers.
293
+ // See https://github.com/guzzle/guzzle/issues/1882 for more details.
294
+ $conf[CURLOPT_HTTPHEADER][] = "$name;";
295
+ } else {
296
+ $conf[CURLOPT_HTTPHEADER][] = "$name: $value";
297
+ }
298
+ }
299
+ }
300
+
301
+ // Remove the Accept header if one was not set
302
+ if (!$easy->request->hasHeader('Accept')) {
303
+ $conf[CURLOPT_HTTPHEADER][] = 'Accept:';
304
+ }
305
+ }
306
+
307
+ /**
308
+ * Remove a header from the options array.
309
+ *
310
+ * @param string $name Case-insensitive header to remove
311
+ * @param array $options Array of options to modify
312
+ */
313
+ private function removeHeader($name, array &$options)
314
+ {
315
+ foreach (array_keys($options['_headers']) as $key) {
316
+ if (!strcasecmp($key, $name)) {
317
+ unset($options['_headers'][$key]);
318
+ return;
319
+ }
320
+ }
321
+ }
322
+
323
+ private function applyHandlerOptions(EasyHandle $easy, array &$conf)
324
+ {
325
+ $options = $easy->options;
326
+ if (isset($options['verify'])) {
327
+ if ($options['verify'] === false) {
328
+ unset($conf[CURLOPT_CAINFO]);
329
+ $conf[CURLOPT_SSL_VERIFYHOST] = 0;
330
+ $conf[CURLOPT_SSL_VERIFYPEER] = false;
331
+ } else {
332
+ $conf[CURLOPT_SSL_VERIFYHOST] = 2;
333
+ $conf[CURLOPT_SSL_VERIFYPEER] = true;
334
+ if (is_string($options['verify'])) {
335
+ // Throw an error if the file/folder/link path is not valid or doesn't exist.
336
+ if (!file_exists($options['verify'])) {
337
+ throw new \InvalidArgumentException(
338
+ "SSL CA bundle not found: {$options['verify']}"
339
+ );
340
+ }
341
+ // If it's a directory or a link to a directory use CURLOPT_CAPATH.
342
+ // If not, it's probably a file, or a link to a file, so use CURLOPT_CAINFO.
343
+ if (is_dir($options['verify']) ||
344
+ (is_link($options['verify']) && is_dir(readlink($options['verify'])))) {
345
+ $conf[CURLOPT_CAPATH] = $options['verify'];
346
+ } else {
347
+ $conf[CURLOPT_CAINFO] = $options['verify'];
348
+ }
349
+ }
350
+ }
351
+ }
352
+
353
+ if (!empty($options['decode_content'])) {
354
+ $accept = $easy->request->getHeaderLine('Accept-Encoding');
355
+ if ($accept) {
356
+ $conf[CURLOPT_ENCODING] = $accept;
357
+ } else {
358
+ $conf[CURLOPT_ENCODING] = '';
359
+ // Don't let curl send the header over the wire
360
+ $conf[CURLOPT_HTTPHEADER][] = 'Accept-Encoding:';
361
+ }
362
+ }
363
+
364
+ if (isset($options['sink'])) {
365
+ $sink = $options['sink'];
366
+ if (!is_string($sink)) {
367
+ $sink = \GuzzleHttp\Psr7\stream_for($sink);
368
+ } elseif (!is_dir(dirname($sink))) {
369
+ // Ensure that the directory exists before failing in curl.
370
+ throw new \RuntimeException(sprintf(
371
+ 'Directory %s does not exist for sink value of %s',
372
+ dirname($sink),
373
+ $sink
374
+ ));
375
+ } else {
376
+ $sink = new LazyOpenStream($sink, 'w+');
377
+ }
378
+ $easy->sink = $sink;
379
+ $conf[CURLOPT_WRITEFUNCTION] = function ($ch, $write) use ($sink) {
380
+ return $sink->write($write);
381
+ };
382
+ } else {
383
+ // Use a default temp stream if no sink was set.
384
+ $conf[CURLOPT_FILE] = fopen('php://temp', 'w+');
385
+ $easy->sink = Psr7\stream_for($conf[CURLOPT_FILE]);
386
+ }
387
+ $timeoutRequiresNoSignal = false;
388
+ if (isset($options['timeout'])) {
389
+ $timeoutRequiresNoSignal |= $options['timeout'] < 1;
390
+ $conf[CURLOPT_TIMEOUT_MS] = $options['timeout'] * 1000;
391
+ }
392
+
393
+ // CURL default value is CURL_IPRESOLVE_WHATEVER
394
+ if (isset($options['force_ip_resolve'])) {
395
+ if ('v4' === $options['force_ip_resolve']) {
396
+ $conf[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V4;
397
+ } elseif ('v6' === $options['force_ip_resolve']) {
398
+ $conf[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V6;
399
+ }
400
+ }
401
+
402
+ if (isset($options['connect_timeout'])) {
403
+ $timeoutRequiresNoSignal |= $options['connect_timeout'] < 1;
404
+ $conf[CURLOPT_CONNECTTIMEOUT_MS] = $options['connect_timeout'] * 1000;
405
+ }
406
+
407
+ if ($timeoutRequiresNoSignal && strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
408
+ $conf[CURLOPT_NOSIGNAL] = true;
409
+ }
410
+
411
+ if (isset($options['proxy'])) {
412
+ if (!is_array($options['proxy'])) {
413
+ $conf[CURLOPT_PROXY] = $options['proxy'];
414
+ } else {
415
+ $scheme = $easy->request->getUri()->getScheme();
416
+ if (isset($options['proxy'][$scheme])) {
417
+ $host = $easy->request->getUri()->getHost();
418
+ if (!isset($options['proxy']['no']) ||
419
+ !\GuzzleHttp\is_host_in_noproxy($host, $options['proxy']['no'])
420
+ ) {
421
+ $conf[CURLOPT_PROXY] = $options['proxy'][$scheme];
422
+ }
423
+ }
424
+ }
425
+ }
426
+
427
+ if (isset($options['cert'])) {
428
+ $cert = $options['cert'];
429
+ if (is_array($cert)) {
430
+ $conf[CURLOPT_SSLCERTPASSWD] = $cert[1];
431
+ $cert = $cert[0];
432
+ }
433
+ if (!file_exists($cert)) {
434
+ throw new \InvalidArgumentException(
435
+ "SSL certificate not found: {$cert}"
436
+ );
437
+ }
438
+ $conf[CURLOPT_SSLCERT] = $cert;
439
+ }
440
+
441
+ if (isset($options['ssl_key'])) {
442
+ $sslKey = $options['ssl_key'];
443
+ if (is_array($sslKey)) {
444
+ $conf[CURLOPT_SSLKEYPASSWD] = $sslKey[1];
445
+ $sslKey = $sslKey[0];
446
+ }
447
+ if (!file_exists($sslKey)) {
448
+ throw new \InvalidArgumentException(
449
+ "SSL private key not found: {$sslKey}"
450
+ );
451
+ }
452
+ $conf[CURLOPT_SSLKEY] = $sslKey;
453
+ }
454
+
455
+ if (isset($options['progress'])) {
456
+ $progress = $options['progress'];
457
+ if (!is_callable($progress)) {
458
+ throw new \InvalidArgumentException(
459
+ 'progress client option must be callable'
460
+ );
461
+ }
462
+ $conf[CURLOPT_NOPROGRESS] = false;
463
+ $conf[CURLOPT_PROGRESSFUNCTION] = function () use ($progress) {
464
+ $args = func_get_args();
465
+ // PHP 5.5 pushed the handle onto the start of the args
466
+ if (is_resource($args[0])) {
467
+ array_shift($args);
468
+ }
469
+ call_user_func_array($progress, $args);
470
+ };
471
+ }
472
+
473
+ if (!empty($options['debug'])) {
474
+ $conf[CURLOPT_STDERR] = \GuzzleHttp\debug_resource($options['debug']);
475
+ $conf[CURLOPT_VERBOSE] = true;
476
+ }
477
+ }
478
+
479
+ /**
480
+ * This function ensures that a response was set on a transaction. If one
481
+ * was not set, then the request is retried if possible. This error
482
+ * typically means you are sending a payload, curl encountered a
483
+ * "Connection died, retrying a fresh connect" error, tried to rewind the
484
+ * stream, and then encountered a "necessary data rewind wasn't possible"
485
+ * error, causing the request to be sent through curl_multi_info_read()
486
+ * without an error status.
487
+ */
488
+ private static function retryFailedRewind(
489
+ callable $handler,
490
+ EasyHandle $easy,
491
+ array $ctx
492
+ ) {
493
+ try {
494
+ // Only rewind if the body has been read from.
495
+ $body = $easy->request->getBody();
496
+ if ($body->tell() > 0) {
497
+ $body->rewind();
498
+ }
499
+ } catch (\RuntimeException $e) {
500
+ $ctx['error'] = 'The connection unexpectedly failed without '
501
+ . 'providing an error. The request would have been retried, '
502
+ . 'but attempting to rewind the request body failed. '
503
+ . 'Exception: ' . $e;
504
+ return self::createRejection($easy, $ctx);
505
+ }
506
+
507
+ // Retry no more than 3 times before giving up.
508
+ if (!isset($easy->options['_curl_retries'])) {
509
+ $easy->options['_curl_retries'] = 1;
510
+ } elseif ($easy->options['_curl_retries'] == 2) {
511
+ $ctx['error'] = 'The cURL request was retried 3 times '
512
+ . 'and did not succeed. The most likely reason for the failure '
513
+ . 'is that cURL was unable to rewind the body of the request '
514
+ . 'and subsequent retries resulted in the same error. Turn on '
515
+ . 'the debug option to see what went wrong. See '
516
+ . 'https://bugs.php.net/bug.php?id=47204 for more information.';
517
+ return self::createRejection($easy, $ctx);
518
+ } else {
519
+ $easy->options['_curl_retries']++;
520
+ }
521
+
522
+ return $handler($easy->request, $easy->options);
523
+ }
524
+
525
+ private function createHeaderFn(EasyHandle $easy)
526
+ {
527
+ if (isset($easy->options['on_headers'])) {
528
+ $onHeaders = $easy->options['on_headers'];
529
+
530
+ if (!is_callable($onHeaders)) {
531
+ throw new \InvalidArgumentException('on_headers must be callable');
532
+ }
533
+ } else {
534
+ $onHeaders = null;
535
+ }
536
+
537
+ return function ($ch, $h) use (
538
+ $onHeaders,
539
+ $easy,
540
+ &$startingResponse
541
+ ) {
542
+ $value = trim($h);
543
+ if ($value === '') {
544
+ $startingResponse = true;
545
+ $easy->createResponse();
546
+ if ($onHeaders !== null) {
547
+ try {
548
+ $onHeaders($easy->response);
549
+ } catch (\Exception $e) {
550
+ // Associate the exception with the handle and trigger
551
+ // a curl header write error by returning 0.
552
+ $easy->onHeadersException = $e;
553
+ return -1;
554
+ }
555
+ }
556
+ } elseif ($startingResponse) {
557
+ $startingResponse = false;
558
+ $easy->headers = [$value];
559
+ } else {
560
+ $easy->headers[] = $value;
561
+ }
562
+ return strlen($h);
563
+ };
564
+ }
565
+ }
vendor/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Handler;
3
+
4
+ use Psr\Http\Message\RequestInterface;
5
+
6
+ interface CurlFactoryInterface
7
+ {
8
+ /**
9
+ * Creates a cURL handle resource.
10
+ *
11
+ * @param RequestInterface $request Request
12
+ * @param array $options Transfer options
13
+ *
14
+ * @return EasyHandle
15
+ * @throws \RuntimeException when an option cannot be applied
16
+ */
17
+ public function create(RequestInterface $request, array $options);
18
+
19
+ /**
20
+ * Release an easy handle, allowing it to be reused or closed.
21
+ *
22
+ * This function must call unset on the easy handle's "handle" property.
23
+ *
24
+ * @param EasyHandle $easy
25
+ */
26
+ public function release(EasyHandle $easy);
27
+ }
vendor/guzzlehttp/guzzle/src/Handler/CurlHandler.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Handler;
3
+
4
+ use GuzzleHttp\Psr7;
5
+ use Psr\Http\Message\RequestInterface;
6
+
7
+ /**
8
+ * HTTP handler that uses cURL easy handles as a transport layer.
9
+ *
10
+ * When using the CurlHandler, custom curl options can be specified as an
11
+ * associative array of curl option constants mapping to values in the
12
+ * **curl** key of the "client" key of the request.
13
+ */
14
+ class CurlHandler
15
+ {
16
+ /** @var CurlFactoryInterface */
17
+ private $factory;
18
+
19
+ /**
20
+ * Accepts an associative array of options:
21
+ *
22
+ * - factory: Optional curl factory used to create cURL handles.
23
+ *
24
+ * @param array $options Array of options to use with the handler
25
+ */
26
+ public function __construct(array $options = [])
27
+ {
28
+ $this->factory = isset($options['handle_factory'])
29
+ ? $options['handle_factory']
30
+ : new CurlFactory(3);
31
+ }
32
+
33
+ public function __invoke(RequestInterface $request, array $options)
34
+ {
35
+ if (isset($options['delay'])) {
36
+ usleep($options['delay'] * 1000);
37
+ }
38
+
39
+ $easy = $this->factory->create($request, $options);
40
+ curl_exec($easy->handle);
41
+ $easy->errno = curl_errno($easy->handle);
42
+
43
+ return CurlFactory::finish($this, $easy, $this->factory);
44
+ }
45
+ }
vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php ADDED
@@ -0,0 +1,199 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Handler;
3
+
4
+ use GuzzleHttp\Promise as P;
5
+ use GuzzleHttp\Promise\Promise;
6
+ use GuzzleHttp\Psr7;
7
+ use Psr\Http\Message\RequestInterface;
8
+
9
+ /**
10
+ * Returns an asynchronous response using curl_multi_* functions.
11
+ *
12
+ * When using the CurlMultiHandler, 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 provided request options.
15
+ *
16
+ * @property resource $_mh Internal use only. Lazy loaded multi-handle.
17
+ */
18
+ class CurlMultiHandler
19
+ {
20
+ /** @var CurlFactoryInterface */
21
+ private $factory;
22
+ private $selectTimeout;
23
+ private $active;
24
+ private $handles = [];
25
+ private $delays = [];
26
+
27
+ /**
28
+ * This handler accepts the following options:
29
+ *
30
+ * - handle_factory: An optional factory used to create curl handles
31
+ * - select_timeout: Optional timeout (in seconds) to block before timing
32
+ * out while selecting curl handles. Defaults to 1 second.
33
+ *
34
+ * @param array $options
35
+ */
36
+ public function __construct(array $options = [])
37
+ {
38
+ $this->factory = isset($options['handle_factory'])
39
+ ? $options['handle_factory'] : new CurlFactory(50);
40
+ $this->selectTimeout = isset($options['select_timeout'])
41
+ ? $options['select_timeout'] : 1;
42
+ }
43
+
44
+ public function __get($name)
45
+ {
46
+ if ($name === '_mh') {
47
+ return $this->_mh = curl_multi_init();
48
+ }
49
+
50
+ throw new \BadMethodCallException();
51
+ }
52
+
53
+ public function __destruct()
54
+ {
55
+ if (isset($this->_mh)) {
56
+ curl_multi_close($this->_mh);
57
+ unset($this->_mh);
58
+ }
59
+ }
60
+
61
+ public function __invoke(RequestInterface $request, array $options)
62
+ {
63
+ $easy = $this->factory->create($request, $options);
64
+ $id = (int) $easy->handle;
65
+
66
+ $promise = new Promise(
67
+ [$this, 'execute'],
68
+ function () use ($id) {
69
+ return $this->cancel($id);
70
+ }
71
+ );
72
+
73
+ $this->addRequest(['easy' => $easy, 'deferred' => $promise]);
74
+
75
+ return $promise;
76
+ }
77
+
78
+ /**
79
+ * Ticks the curl event loop.
80
+ */
81
+ public function tick()
82
+ {
83
+ // Add any delayed handles if needed.
84
+ if ($this->delays) {
85
+ $currentTime = microtime(true);
86
+ foreach ($this->delays as $id => $delay) {
87
+ if ($currentTime >= $delay) {
88
+ unset($this->delays[$id]);
89
+ curl_multi_add_handle(
90
+ $this->_mh,
91
+ $this->handles[$id]['easy']->handle
92
+ );
93
+ }
94
+ }
95
+ }
96
+
97
+ // Step through the task queue which may add additional requests.
98
+ P\queue()->run();
99
+
100
+ if ($this->active &&
101
+ curl_multi_select($this->_mh, $this->selectTimeout) === -1
102
+ ) {
103
+ // Perform a usleep if a select returns -1.
104
+ // See: https://bugs.php.net/bug.php?id=61141
105
+ usleep(250);
106
+ }
107
+
108
+ while (curl_multi_exec($this->_mh, $this->active) === CURLM_CALL_MULTI_PERFORM);
109
+
110
+ $this->processMessages();
111
+ }
112
+
113
+ /**
114
+ * Runs until all outstanding connections have completed.
115
+ */
116
+ public function execute()
117
+ {
118
+ $queue = P\queue();
119
+
120
+ while ($this->handles || !$queue->isEmpty()) {
121
+ // If there are no transfers, then sleep for the next delay
122
+ if (!$this->active && $this->delays) {
123
+ usleep($this->timeToNext());
124
+ }
125
+ $this->tick();
126
+ }
127
+ }
128
+
129
+ private function addRequest(array $entry)
130
+ {
131
+ $easy = $entry['easy'];
132
+ $id = (int) $easy->handle;
133
+ $this->handles[$id] = $entry;
134
+ if (empty($easy->options['delay'])) {
135
+ curl_multi_add_handle($this->_mh, $easy->handle);
136
+ } else {
137
+ $this->delays[$id] = microtime(true) + ($easy->options['delay'] / 1000);
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Cancels a handle from sending and removes references to it.
143
+ *
144
+ * @param int $id Handle ID to cancel and remove.
145
+ *
146
+ * @return bool True on success, false on failure.
147
+ */
148
+ private function cancel($id)
149
+ {
150
+ // Cannot cancel if it has been processed.
151
+ if (!isset($this->handles[$id])) {
152
+ return false;
153
+ }
154
+
155
+ $handle = $this->handles[$id]['easy']->handle;
156
+ unset($this->delays[$id], $this->handles[$id]);
157
+ curl_multi_remove_handle($this->_mh, $handle);
158
+ curl_close($handle);
159
+
160
+ return true;
161
+ }
162
+
163
+ private function processMessages()
164
+ {
165
+ while ($done = curl_multi_info_read($this->_mh)) {
166
+ $id = (int) $done['handle'];
167
+ curl_multi_remove_handle($this->_mh, $done['handle']);
168
+
169
+ if (!isset($this->handles[$id])) {
170
+ // Probably was cancelled.
171
+ continue;
172
+ }
173
+
174
+ $entry = $this->handles[$id];
175
+ unset($this->handles[$id], $this->delays[$id]);
176
+ $entry['easy']->errno = $done['result'];
177
+ $entry['deferred']->resolve(
178
+ CurlFactory::finish(
179
+ $this,
180
+ $entry['easy'],
181
+ $this->factory
182
+ )
183
+ );
184
+ }
185
+ }
186
+
187
+ private function timeToNext()
188
+ {
189
+ $currentTime = microtime(true);
190
+ $nextTime = PHP_INT_MAX;
191
+ foreach ($this->delays as $time) {
192
+ if ($time < $nextTime) {
193
+ $nextTime = $time;
194
+ }
195
+ }
196
+
197
+ return max(0, $nextTime - $currentTime) * 1000000;
198
+ }
199
+ }
vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.php ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Handler;
3
+
4
+ use GuzzleHttp\Psr7\Response;
5
+ use Psr\Http\Message\RequestInterface;
6
+ use Psr\Http\Message\ResponseInterface;
7
+ use Psr\Http\Message\StreamInterface;
8
+
9
+ /**
10
+ * Represents a cURL easy handle and the data it populates.
11
+ *
12
+ * @internal
13
+ */
14
+ final class EasyHandle
15
+ {
16
+ /** @var resource cURL resource */
17
+ public $handle;
18
+
19
+ /** @var StreamInterface Where data is being written */
20
+ public $sink;
21
+
22
+ /** @var array Received HTTP headers so far */
23
+ public $headers = [];
24
+
25
+ /** @var ResponseInterface Received response (if any) */
26
+ public $response;
27
+
28
+ /** @var RequestInterface Request being sent */
29
+ public $request;
30
+
31
+ /** @var array Request options */
32
+ public $options = [];
33
+
34
+ /** @var int cURL error number (if any) */
35
+ public $errno = 0;
36
+
37
+ /** @var \Exception Exception during on_headers (if any) */
38
+ public $onHeadersException;
39
+
40
+ /**
41
+ * Attach a response to the easy handle based on the received headers.
42
+ *
43
+ * @throws \RuntimeException if no headers have been received.
44
+ */
45
+ public function createResponse()
46
+ {
47
+ if (empty($this->headers)) {
48
+ throw new \RuntimeException('No headers have been received');
49
+ }
50
+
51
+ // HTTP-version SP status-code SP reason-phrase
52
+ $startLine = explode(' ', array_shift($this->headers), 3);
53
+ $headers = \GuzzleHttp\headers_from_lines($this->headers);
54
+ $normalizedKeys = \GuzzleHttp\normalize_header_keys($headers);
55
+
56
+ if (!empty($this->options['decode_content'])
57
+ && isset($normalizedKeys['content-encoding'])
58
+ ) {
59
+ $headers['x-encoded-content-encoding']
60
+ = $headers[$normalizedKeys['content-encoding']];
61
+ unset($headers[$normalizedKeys['content-encoding']]);
62
+ if (isset($normalizedKeys['content-length'])) {
63
+ $headers['x-encoded-content-length']
64
+ = $headers[$normalizedKeys['content-length']];
65
+
66
+ $bodyLength = (int) $this->sink->getSize();
67
+ if ($bodyLength) {
68
+ $headers[$normalizedKeys['content-length']] = $bodyLength;
69
+ } else {
70
+ unset($headers[$normalizedKeys['content-length']]);
71
+ }
72
+ }
73
+ }
74
+
75
+ // Attach a response to the easy handle with the parsed headers.
76
+ $this->response = new Response(
77
+ $startLine[1],
78
+ $headers,
79
+ $this->sink,
80
+ substr($startLine[0], 5),
81
+ isset($startLine[2]) ? (string) $startLine[2] : null
82
+ );
83
+ }
84
+
85
+ public function __get($name)
86
+ {
87
+ $msg = $name === 'handle'
88
+ ? 'The EasyHandle has been released'
89
+ : 'Invalid property: ' . $name;
90
+ throw new \BadMethodCallException($msg);
91
+ }
92
+ }
vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php ADDED
@@ -0,0 +1,189 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Handler;
3
+
4
+ use GuzzleHttp\Exception\RequestException;
5
+ use GuzzleHttp\HandlerStack;
6
+ use GuzzleHttp\Promise\PromiseInterface;
7
+ use GuzzleHttp\Promise\RejectedPromise;
8
+ use GuzzleHttp\TransferStats;
9
+ use Psr\Http\Message\RequestInterface;
10
+ use Psr\Http\Message\ResponseInterface;
11
+
12
+ /**
13
+ * Handler that returns responses or throw exceptions from a queue.
14
+ */
15
+ class MockHandler implements \Countable
16
+ {
17
+ private $queue = [];
18
+ private $lastRequest;
19
+ private $lastOptions;
20
+ private $onFulfilled;
21
+ private $onRejected;
22
+
23
+ /**
24
+ * Creates a new MockHandler that uses the default handler stack list of
25
+ * middlewares.
26
+ *
27
+ * @param array $queue Array of responses, callables, or exceptions.
28
+ * @param callable $onFulfilled Callback to invoke when the return value is fulfilled.
29
+ * @param callable $onRejected Callback to invoke when the return value is rejected.
30
+ *
31
+ * @return HandlerStack
32
+ */
33
+ public static function createWithMiddleware(
34
+ array $queue = null,
35
+ callable $onFulfilled = null,
36
+ callable $onRejected = null
37
+ ) {
38
+ return HandlerStack::create(new self($queue, $onFulfilled, $onRejected));
39
+ }
40
+
41
+ /**
42
+ * The passed in value must be an array of
43
+ * {@see Psr7\Http\Message\ResponseInterface} objects, Exceptions,
44
+ * callables, or Promises.
45
+ *
46
+ * @param array $queue
47
+ * @param callable $onFulfilled Callback to invoke when the return value is fulfilled.
48
+ * @param callable $onRejected Callback to invoke when the return value is rejected.
49
+ */
50
+ public function __construct(
51
+ array $queue = null,
52
+ callable $onFulfilled = null,
53
+ callable $onRejected = null
54
+ ) {
55
+ $this->onFulfilled = $onFulfilled;
56
+ $this->onRejected = $onRejected;
57
+
58
+ if ($queue) {
59
+ call_user_func_array([$this, 'append'], $queue);
60
+ }
61
+ }
62
+
63
+ public function __invoke(RequestInterface $request, array $options)
64
+ {
65
+ if (!$this->queue) {
66
+ throw new \OutOfBoundsException('Mock queue is empty');
67
+ }
68
+
69
+ if (isset($options['delay'])) {
70
+ usleep($options['delay'] * 1000);
71
+ }
72
+
73
+ $this->lastRequest = $request;
74
+ $this->lastOptions = $options;
75
+ $response = array_shift($this->queue);
76
+
77
+ if (isset($options['on_headers'])) {
78
+ if (!is_callable($options['on_headers'])) {
79
+ throw new \InvalidArgumentException('on_headers must be callable');
80
+ }
81
+ try {
82
+ $options['on_headers']($response);
83
+ } catch (\Exception $e) {
84
+ $msg = 'An error was encountered during the on_headers event';
85
+ $response = new RequestException($msg, $request, $response, $e);
86
+ }
87
+ }
88
+
89
+ if (is_callable($response)) {
90
+ $response = call_user_func($response, $request, $options);
91
+ }
92
+
93
+ $response = $response instanceof \Exception
94
+ ? \GuzzleHttp\Promise\rejection_for($response)
95
+ : \GuzzleHttp\Promise\promise_for($response);
96
+
97
+ return $response->then(
98
+ function ($value) use ($request, $options) {
99
+ $this->invokeStats($request, $options, $value);
100
+ if ($this->onFulfilled) {
101
+ call_user_func($this->onFulfilled, $value);
102
+ }
103
+ if (isset($options['sink'])) {
104
+ $contents = (string) $value->getBody();
105
+ $sink = $options['sink'];
106
+
107
+ if (is_resource($sink)) {
108
+ fwrite($sink, $contents);
109
+ } elseif (is_string($sink)) {
110
+ file_put_contents($sink, $contents);
111
+ } elseif ($sink instanceof \Psr\Http\Message\StreamInterface) {
112
+ $sink->write($contents);
113
+ }
114
+ }
115
+
116
+ return $value;
117
+ },
118
+ function ($reason) use ($request, $options) {
119
+ $this->invokeStats($request, $options, null, $reason);
120
+ if ($this->onRejected) {
121
+ call_user_func($this->onRejected, $reason);
122
+ }
123
+ return \GuzzleHttp\Promise\rejection_for($reason);
124
+ }
125
+ );
126
+ }
127
+
128
+ /**
129
+ * Adds one or more variadic requests, exceptions, callables, or promises
130
+ * to the queue.
131
+ */
132
+ public function append()
133
+ {
134
+ foreach (func_get_args() as $value) {
135
+ if ($value instanceof ResponseInterface
136
+ || $value instanceof \Exception
137
+ || $value instanceof PromiseInterface
138
+ || is_callable($value)
139
+ ) {
140
+ $this->queue[] = $value;
141
+ } else {
142
+ throw new \InvalidArgumentException('Expected a response or '
143
+ . 'exception. Found ' . \GuzzleHttp\describe_type($value));
144
+ }
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Get the last received request.
150
+ *
151
+ * @return RequestInterface
152
+ */
153
+ public function getLastRequest()
154
+ {
155
+ return $this->lastRequest;
156
+ }
157
+
158
+ /**
159
+ * Get the last received request options.
160
+ *
161
+ * @return array
162
+ */
163
+ public function getLastOptions()
164
+ {
165
+ return $this->lastOptions;
166
+ }
167
+
168
+ /**
169
+ * Returns the number of remaining items in the queue.
170
+ *
171
+ * @return int
172
+ */
173
+ public function count()
174
+ {
175
+ return count($this->queue);
176
+ }
177
+
178
+ private function invokeStats(
179
+ RequestInterface $request,
180
+ array $options,
181
+ ResponseInterface $response = null,
182
+ $reason = null
183
+ ) {
184
+ if (isset($options['on_stats'])) {
185
+ $stats = new TransferStats($request, $response, 0, $reason);
186
+ call_user_func($options['on_stats'], $stats);
187
+ }
188
+ }
189
+ }
vendor/guzzlehttp/guzzle/src/Handler/Proxy.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Handler;
3
+
4
+ use GuzzleHttp\RequestOptions;
5
+ use Psr\Http\Message\RequestInterface;
6
+
7
+ /**
8
+ * Provides basic proxies for handlers.
9
+ */
10
+ class Proxy
11
+ {
12
+ /**
13
+ * Sends synchronous requests to a specific handler while sending all other
14
+ * requests to another handler.
15
+ *
16
+ * @param callable $default Handler used for normal responses
17
+ * @param callable $sync Handler used for synchronous responses.
18
+ *
19
+ * @return callable Returns the composed handler.
20
+ */
21
+ public static function wrapSync(
22
+ callable $default,
23
+ callable $sync
24
+ ) {
25
+ return function (RequestInterface $request, array $options) use ($default, $sync) {
26
+ return empty($options[RequestOptions::SYNCHRONOUS])
27
+ ? $default($request, $options)
28
+ : $sync($request, $options);
29
+ };
30
+ }
31
+
32
+ /**
33
+ * Sends streaming requests to a streaming compatible handler while sending
34
+ * all other requests to a default handler.
35
+ *
36
+ * This, for example, could be useful for taking advantage of the
37
+ * performance benefits of curl while still supporting true streaming
38
+ * through the StreamHandler.
39
+ *
40
+ * @param callable $default Handler used for non-streaming responses
41
+ * @param callable $streaming Handler used for streaming responses
42
+ *
43
+ * @return callable Returns the composed handler.
44
+ */
45
+ public static function wrapStreaming(
46
+ callable $default,
47
+ callable $streaming
48
+ ) {
49
+ return function (RequestInterface $request, array $options) use ($default, $streaming) {
50
+ return empty($options['stream'])
51
+ ? $default($request, $options)
52
+ : $streaming($request, $options);
53
+ };
54
+ }
55
+ }
vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php ADDED
@@ -0,0 +1,532 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Handler;
3
+
4
+ use GuzzleHttp\Exception\RequestException;
5
+ use GuzzleHttp\Exception\ConnectException;
6
+ use GuzzleHttp\Promise\FulfilledPromise;
7
+ use GuzzleHttp\Promise\PromiseInterface;
8
+ use GuzzleHttp\Psr7;
9
+ use GuzzleHttp\TransferStats;
10
+ use Psr\Http\Message\RequestInterface;
11
+ use Psr\Http\Message\ResponseInterface;
12
+ use Psr\Http\Message\StreamInterface;
13
+
14
+ /**
15
+ * HTTP handler that uses PHP's HTTP stream wrapper.
16
+ */
17
+ class StreamHandler
18
+ {
19
+ private $lastHeaders = [];
20
+
21
+ /**
22
+ * Sends an HTTP request.
23
+ *
24
+ * @param RequestInterface $request Request to send.
25
+ * @param array $options Request transfer options.
26
+ *
27
+ * @return PromiseInterface
28
+ */
29
+ public function __invoke(RequestInterface $request, array $options)
30
+ {
31
+ // Sleep if there is a delay specified.
32
+ if (isset($options['delay'])) {
33
+ usleep($options['delay'] * 1000);
34
+ }
35
+
36
+ $startTime = isset($options['on_stats']) ? microtime(true) : null;
37
+
38
+ try {
39
+ // Does not support the expect header.
40
+ $request = $request->withoutHeader('Expect');
41
+
42
+ // Append a content-length header if body size is zero to match
43
+ // cURL's behavior.
44
+ if (0 === $request->getBody()->getSize()) {
45
+ $request = $request->withHeader('Content-Length', 0);
46
+ }
47
+
48
+ return $this->createResponse(
49
+ $request,
50
+ $options,
51
+ $this->createStream($request, $options),
52
+ $startTime
53
+ );
54
+ } catch (\InvalidArgumentException $e) {
55
+ throw $e;
56
+ } catch (\Exception $e) {
57
+ // Determine if the error was a networking error.
58
+ $message = $e->getMessage();
59
+ // This list can probably get more comprehensive.
60
+ if (strpos($message, 'getaddrinfo') // DNS lookup failed
61
+ || strpos($message, 'Connection refused')
62
+ || strpos($message, "couldn't connect to host") // error on HHVM
63
+ || strpos($message, "connection attempt failed")
64
+ ) {
65
+ $e = new ConnectException($e->getMessage(), $request, $e);
66
+ }
67
+ $e = RequestException::wrapException($request, $e);
68
+ $this->invokeStats($options, $request, $startTime, null, $e);
69
+
70
+ return \GuzzleHttp\Promise\rejection_for($e);
71
+ }
72
+ }
73
+
74
+ private function invokeStats(
75
+ array $options,
76
+ RequestInterface $request,
77
+ $startTime,
78
+ ResponseInterface $response = null,
79
+ $error = null
80
+ ) {
81
+ if (isset($options['on_stats'])) {
82
+ $stats = new TransferStats(
83
+ $request,
84
+ $response,
85
+ microtime(true) - $startTime,
86
+ $error,
87
+ []
88
+ );
89
+ call_user_func($options['on_stats'], $stats);
90
+ }
91
+ }
92
+
93
+ private function createResponse(
94
+ RequestInterface $request,
95
+ array $options,
96
+ $stream,
97
+ $startTime
98
+ ) {
99
+ $hdrs = $this->lastHeaders;
100
+ $this->lastHeaders = [];
101
+ $parts = explode(' ', array_shift($hdrs), 3);
102
+ $ver = explode('/', $parts[0])[1];
103
+ $status = $parts[1];
104
+ $reason = isset($parts[2]) ? $parts[2] : null;
105
+ $headers = \GuzzleHttp\headers_from_lines($hdrs);
106
+ list($stream, $headers) = $this->checkDecode($options, $headers, $stream);
107
+ $stream = Psr7\stream_for($stream);
108
+ $sink = $stream;
109
+
110
+ if (strcasecmp('HEAD', $request->getMethod())) {
111
+ $sink = $this->createSink($stream, $options);
112
+ }
113
+
114
+ $response = new Psr7\Response($status, $headers, $sink, $ver, $reason);
115
+
116
+ if (isset($options['on_headers'])) {
117
+ try {
118
+ $options['on_headers']($response);
119
+ } catch (\Exception $e) {
120
+ $msg = 'An error was encountered during the on_headers event';
121
+ $ex = new RequestException($msg, $request, $response, $e);
122
+ return \GuzzleHttp\Promise\rejection_for($ex);
123
+ }
124
+ }
125
+
126
+ // Do not drain when the request is a HEAD request because they have
127
+ // no body.
128
+ if ($sink !== $stream) {
129
+ $this->drain(
130
+ $stream,
131
+ $sink,
132
+ $response->getHeaderLine('Content-Length')
133
+ );
134
+ }
135
+
136
+ $this->invokeStats($options, $request, $startTime, $response, null);
137
+
138
+ return new FulfilledPromise($response);
139
+ }
140
+
141
+ private function createSink(StreamInterface $stream, array $options)
142
+ {
143
+ if (!empty($options['stream'])) {
144
+ return $stream;
145
+ }
146
+
147
+ $sink = isset($options['sink'])
148
+ ? $options['sink']
149
+ : fopen('php://temp', 'r+');
150
+
151
+ return is_string($sink)
152
+ ? new Psr7\LazyOpenStream($sink, 'w+')
153
+ : Psr7\stream_for($sink);
154
+ }
155
+
156
+ private function checkDecode(array $options, array $headers, $stream)
157
+ {
158
+ // Automatically decode responses when instructed.
159
+ if (!empty($options['decode_content'])) {
160
+ $normalizedKeys = \GuzzleHttp\normalize_header_keys($headers);
161
+ if (isset($normalizedKeys['content-encoding'])) {
162
+ $encoding = $headers[$normalizedKeys['content-encoding']];
163
+ if ($encoding[0] === 'gzip' || $encoding[0] === 'deflate') {
164
+ $stream = new Psr7\InflateStream(
165
+ Psr7\stream_for($stream)
166
+ );
167
+ $headers['x-encoded-content-encoding']
168
+ = $headers[$normalizedKeys['content-encoding']];
169
+ // Remove content-encoding header
170
+ unset($headers[$normalizedKeys['content-encoding']]);
171
+ // Fix content-length header
172
+ if (isset($normalizedKeys['content-length'])) {
173
+ $headers['x-encoded-content-length']
174
+ = $headers[$normalizedKeys['content-length']];
175
+
176
+ $length = (int) $stream->getSize();
177
+ if ($length === 0) {
178
+ unset($headers[$normalizedKeys['content-length']]);
179
+ } else {
180
+ $headers[$normalizedKeys['content-length']] = [$length];
181
+ }
182
+ }
183
+ }
184
+ }
185
+ }
186
+
187
+ return [$stream, $headers];
188
+ }
189
+
190
+ /**
191
+ * Drains the source stream into the "sink" client option.
192
+ *
193
+ * @param StreamInterface $source
194
+ * @param StreamInterface $sink
195
+ * @param string $contentLength Header specifying the amount of
196
+ * data to read.
197
+ *
198
+ * @return StreamInterface
199
+ * @throws \RuntimeException when the sink option is invalid.
200
+ */
201
+ private function drain(
202
+ StreamInterface $source,
203
+ StreamInterface $sink,
204
+ $contentLength
205
+ ) {
206
+ // If a content-length header is provided, then stop reading once
207
+ // that number of bytes has been read. This can prevent infinitely
208
+ // reading from a stream when dealing with servers that do not honor
209
+ // Connection: Close headers.
210
+ Psr7\copy_to_stream(
211
+ $source,
212
+ $sink,
213
+ (strlen($contentLength) > 0 && (int) $contentLength > 0) ? (int) $contentLength : -1
214
+ );
215
+
216
+ $sink->seek(0);
217
+ $source->close();
218
+
219
+ return $sink;
220
+ }
221
+
222
+ /**
223
+ * Create a resource and check to ensure it was created successfully
224
+ *
225
+ * @param callable $callback Callable that returns stream resource
226
+ *
227
+ * @return resource
228
+ * @throws \RuntimeException on error
229
+ */
230
+ private function createResource(callable $callback)
231
+ {
232
+ $errors = null;
233
+ set_error_handler(function ($_, $msg, $file, $line) use (&$errors) {
234
+ $errors[] = [
235
+ 'message' => $msg,
236
+ 'file' => $file,
237
+ 'line' => $line
238
+ ];
239
+ return true;
240
+ });
241
+
242
+ $resource = $callback();
243
+ restore_error_handler();
244
+
245
+ if (!$resource) {
246
+ $message = 'Error creating resource: ';
247
+ foreach ($errors as $err) {
248
+ foreach ($err as $key => $value) {
249
+ $message .= "[$key] $value" . PHP_EOL;
250
+ }
251
+ }
252
+ throw new \RuntimeException(trim($message));
253
+ }
254
+
255
+ return $resource;
256
+ }
257
+
258
+ private function createStream(RequestInterface $request, array $options)
259
+ {
260
+ static $methods;
261
+ if (!$methods) {
262
+ $methods = array_flip(get_class_methods(__CLASS__));
263
+ }
264
+
265
+ // HTTP/1.1 streams using the PHP stream wrapper require a
266
+ // Connection: close header
267
+ if ($request->getProtocolVersion() == '1.1'
268
+ && !$request->hasHeader('Connection')
269
+ ) {
270
+ $request = $request->withHeader('Connection', 'close');
271
+ }
272
+
273
+ // Ensure SSL is verified by default
274
+ if (!isset($options['verify'])) {
275
+ $options['verify'] = true;
276
+ }
277
+
278
+ $params = [];
279
+ $context = $this->getDefaultContext($request);
280
+
281
+ if (isset($options['on_headers']) && !is_callable($options['on_headers'])) {
282
+ throw new \InvalidArgumentException('on_headers must be callable');
283
+ }
284
+
285
+ if (!empty($options)) {
286
+ foreach ($options as $key => $value) {
287
+ $method = "add_{$key}";
288
+ if (isset($methods[$method])) {
289
+ $this->{$method}($request, $context, $value, $params);
290
+ }
291
+ }
292
+ }
293
+
294
+ if (isset($options['stream_context'])) {
295
+ if (!is_array($options['stream_context'])) {
296
+ throw new \InvalidArgumentException('stream_context must be an array');
297
+ }
298
+ $context = array_replace_recursive(
299
+ $context,
300
+ $options['stream_context']
301
+ );
302
+ }
303
+
304
+ // Microsoft NTLM authentication only supported with curl handler
305
+ if (isset($options['auth'])
306
+ && is_array($options['auth'])
307
+ && isset($options['auth'][2])
308
+ && 'ntlm' == $options['auth'][2]
309
+ ) {
310
+ throw new \InvalidArgumentException('Microsoft NTLM authentication only supported with curl handler');
311
+ }
312
+
313
+ $uri = $this->resolveHost($request, $options);
314
+
315
+ $context = $this->createResource(
316
+ function () use ($context, $params) {
317
+ return stream_context_create($context, $params);
318
+ }
319
+ );
320
+
321
+ return $this->createResource(
322
+ function () use ($uri, &$http_response_header, $context, $options) {
323
+ $resource = fopen((string) $uri, 'r', null, $context);
324
+ $this->lastHeaders = $http_response_header;
325
+
326
+ if (isset($options['read_timeout'])) {
327
+ $readTimeout = $options['read_timeout'];
328
+ $sec = (int) $readTimeout;
329
+ $usec = ($readTimeout - $sec) * 100000;
330
+ stream_set_timeout($resource, $sec, $usec);
331
+ }
332
+
333
+ return $resource;
334
+ }
335
+ );
336
+ }
337
+
338
+ private function resolveHost(RequestInterface $request, array $options)
339
+ {
340
+ $uri = $request->getUri();
341
+
342
+ if (isset($options['force_ip_resolve']) && !filter_var($uri->getHost(), FILTER_VALIDATE_IP)) {
343
+ if ('v4' === $options['force_ip_resolve']) {
344
+ $records = dns_get_record($uri->getHost(), DNS_A);
345
+ if (!isset($records[0]['ip'])) {
346
+ throw new ConnectException(sprintf("Could not resolve IPv4 address for host '%s'", $uri->getHost()), $request);
347
+ }
348
+ $uri = $uri->withHost($records[0]['ip']);
349
+ } elseif ('v6' === $options['force_ip_resolve']) {
350
+ $records = dns_get_record($uri->getHost(), DNS_AAAA);
351
+ if (!isset($records[0]['ipv6'])) {
352
+ throw new ConnectException(sprintf("Could not resolve IPv6 address for host '%s'", $uri->getHost()), $request);
353
+ }
354
+ $uri = $uri->withHost('[' . $records[0]['ipv6'] . ']');
355
+ }
356
+ }
357
+
358
+ return $uri;
359
+ }
360
+
361
+ private function getDefaultContext(RequestInterface $request)
362
+ {
363
+ $headers = '';
364
+ foreach ($request->getHeaders() as $name => $value) {
365
+ foreach ($value as $val) {
366
+ $headers .= "$name: $val\r\n";
367
+ }
368
+ }
369
+
370
+ $context = [
371
+ 'http' => [
372
+ 'method' => $request->getMethod(),
373
+ 'header' => $headers,
374
+ 'protocol_version' => $request->getProtocolVersion(),
375
+ 'ignore_errors' => true,
376
+ 'follow_location' => 0,
377
+ ],
378
+ ];
379
+
380
+ $body = (string) $request->getBody();
381
+
382
+ if (!empty($body)) {
383
+ $context['http']['content'] = $body;
384
+ // Prevent the HTTP handler from adding a Content-Type header.
385
+ if (!$request->hasHeader('Content-Type')) {
386
+ $context['http']['header'] .= "Content-Type:\r\n";
387
+ }
388
+ }
389
+
390
+ $context['http']['header'] = rtrim($context['http']['header']);
391
+
392
+ return $context;
393
+ }
394
+
395
+ private function add_proxy(RequestInterface $request, &$options, $value, &$params)
396
+ {
397
+ if (!is_array($value)) {
398
+ $options['http']['proxy'] = $value;
399
+ } else {
400
+ $scheme = $request->getUri()->getScheme();
401
+ if (isset($value[$scheme])) {
402
+ if (!isset($value['no'])
403
+ || !\GuzzleHttp\is_host_in_noproxy(
404
+ $request->getUri()->getHost(),
405
+ $value['no']
406
+ )
407
+ ) {
408
+ $options['http']['proxy'] = $value[$scheme];
409
+ }
410
+ }
411
+ }
412
+ }
413
+
414
+ private function add_timeout(RequestInterface $request, &$options, $value, &$params)
415
+ {
416
+ if ($value > 0) {
417
+ $options['http']['timeout'] = $value;
418
+ }
419
+ }
420
+
421
+ private function add_verify(RequestInterface $request, &$options, $value, &$params)
422
+ {
423
+ if ($value === true) {
424
+ // PHP 5.6 or greater will find the system cert by default. When
425
+ // < 5.6, use the Guzzle bundled cacert.
426
+ if (PHP_VERSION_ID < 50600) {
427
+ $options['ssl']['cafile'] = \GuzzleHttp\default_ca_bundle();
428
+ }
429
+ } elseif (is_string($value)) {
430
+ $options['ssl']['cafile'] = $value;
431
+ if (!file_exists($value)) {
432
+ throw new \RuntimeException("SSL CA bundle not found: $value");
433
+ }
434
+ } elseif ($value === false) {
435
+ $options['ssl']['verify_peer'] = false;
436
+ $options['ssl']['verify_peer_name'] = false;
437
+ return;
438
+ } else {
439
+ throw new \InvalidArgumentException('Invalid verify request option');
440
+ }
441
+
442
+ $options['ssl']['verify_peer'] = true;
443
+ $options['ssl']['verify_peer_name'] = true;
444
+ $options['ssl']['allow_self_signed'] = false;
445
+ }
446
+
447
+ private function add_cert(RequestInterface $request, &$options, $value, &$params)
448
+ {
449
+ if (is_array($value)) {
450
+ $options['ssl']['passphrase'] = $value[1];
451
+ $value = $value[0];
452
+ }
453
+
454
+ if (!file_exists($value)) {
455
+ throw new \RuntimeException("SSL certificate not found: {$value}");
456
+ }
457
+
458
+ $options['ssl']['local_cert'] = $value;
459
+ }
460
+
461
+ private function add_progress(RequestInterface $request, &$options, $value, &$params)
462
+ {
463
+ $this->addNotification(
464
+ $params,
465
+ function ($code, $a, $b, $c, $transferred, $total) use ($value) {
466
+ if ($code == STREAM_NOTIFY_PROGRESS) {
467
+ $value($total, $transferred, null, null);
468
+ }
469
+ }
470
+ );
471
+ }
472
+
473
+ private function add_debug(RequestInterface $request, &$options, $value, &$params)
474
+ {
475
+ if ($value === false) {
476
+ return;
477
+ }
478
+
479
+ static $map = [
480
+ STREAM_NOTIFY_CONNECT => 'CONNECT',
481
+ STREAM_NOTIFY_AUTH_REQUIRED => 'AUTH_REQUIRED',
482
+ STREAM_NOTIFY_AUTH_RESULT => 'AUTH_RESULT',
483
+ STREAM_NOTIFY_MIME_TYPE_IS => 'MIME_TYPE_IS',
484
+ STREAM_NOTIFY_FILE_SIZE_IS => 'FILE_SIZE_IS',
485
+ STREAM_NOTIFY_REDIRECTED => 'REDIRECTED',
486
+ STREAM_NOTIFY_PROGRESS => 'PROGRESS',
487
+ STREAM_NOTIFY_FAILURE => 'FAILURE',
488
+ STREAM_NOTIFY_COMPLETED => 'COMPLETED',
489
+ STREAM_NOTIFY_RESOLVE => 'RESOLVE',
490
+ ];
491
+ static $args = ['severity', 'message', 'message_code',
492
+ 'bytes_transferred', 'bytes_max'];
493
+
494
+ $value = \GuzzleHttp\debug_resource($value);
495
+ $ident = $request->getMethod() . ' ' . $request->getUri()->withFragment('');
496
+ $this->addNotification(
497
+ $params,
498
+ function () use ($ident, $value, $map, $args) {
499
+ $passed = func_get_args();
500
+ $code = array_shift($passed);
501
+ fprintf($value, '<%s> [%s] ', $ident, $map[$code]);
502
+ foreach (array_filter($passed) as $i => $v) {
503
+ fwrite($value, $args[$i] . ': "' . $v . '" ');
504
+ }
505
+ fwrite($value, "\n");
506
+ }
507
+ );
508
+ }
509
+
510
+ private function addNotification(array &$params, callable $notify)
511
+ {
512
+ // Wrap the existing function if needed.
513
+ if (!isset($params['notification'])) {
514
+ $params['notification'] = $notify;
515
+ } else {
516
+ $params['notification'] = $this->callArray([
517
+ $params['notification'],
518
+ $notify
519
+ ]);
520
+ }
521
+ }
522
+
523
+ private function callArray(array $functions)
524
+ {
525
+ return function () use ($functions) {
526
+ $args = func_get_args();
527
+ foreach ($functions as $fn) {
528
+ call_user_func_array($fn, $args);
529
+ }
530
+ };
531
+ }
532
+ }
vendor/guzzlehttp/guzzle/src/HandlerStack.php ADDED
@@ -0,0 +1,273 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use Psr\Http\Message\RequestInterface;
5
+
6
+ /**
7
+ * Creates a composed Guzzle handler function by stacking middlewares on top of
8
+ * an HTTP handler function.
9
+ */
10
+ class HandlerStack
11
+ {
12
+ /** @var callable */
13
+ private $handler;
14
+
15
+ /** @var array */
16
+ private $stack = [];
17
+
18
+ /** @var callable|null */
19
+ private $cached;
20
+
21
+ /**
22
+ * Creates a default handler stack that can be used by clients.
23
+ *
24
+ * The returned handler will wrap the provided handler or use the most
25
+ * appropriate default handler for your system. The returned HandlerStack has
26
+ * support for cookies, redirects, HTTP error exceptions, and preparing a body
27
+ * before sending.
28
+ *
29
+ * The returned handler stack can be passed to a client in the "handler"
30
+ * option.
31
+ *
32
+ * @param callable $handler HTTP handler function to use with the stack. If no
33
+ * handler is provided, the best handler for your
34
+ * system will be utilized.
35
+ *
36
+ * @return HandlerStack
37
+ */
38
+ public static function create(callable $handler = null)
39
+ {
40
+ $stack = new self($handler ?: choose_handler());
41
+ $stack->push(Middleware::httpErrors(), 'http_errors');
42
+ $stack->push(Middleware::redirect(), 'allow_redirects');
43
+ $stack->push(Middleware::cookies(), 'cookies');
44
+ $stack->push(Middleware::prepareBody(), 'prepare_body');
45
+
46
+ return $stack;
47
+ }
48
+
49
+ /**
50
+ * @param callable $handler Underlying HTTP handler.
51
+ */
52
+ public function __construct(callable $handler = null)
53
+ {
54
+ $this->handler = $handler;
55
+ }
56
+
57
+ /**
58
+ * Invokes the handler stack as a composed handler
59
+ *
60
+ * @param RequestInterface $request
61
+ * @param array $options
62
+ */
63
+ public function __invoke(RequestInterface $request, array $options)
64
+ {
65
+ $handler = $this->resolve();
66
+
67
+ return $handler($request, $options);
68
+ }
69
+
70
+ /**
71
+ * Dumps a string representation of the stack.
72
+ *
73
+ * @return string
74
+ */
75
+ public function __toString()
76
+ {
77
+ $depth = 0;
78
+ $stack = [];
79
+ if ($this->handler) {
80
+ $stack[] = "0) Handler: " . $this->debugCallable($this->handler);
81
+ }
82
+
83
+ $result = '';
84
+ foreach (array_reverse($this->stack) as $tuple) {
85
+ $depth++;
86
+ $str = "{$depth}) Name: '{$tuple[1]}', ";
87
+ $str .= "Function: " . $this->debugCallable($tuple[0]);
88
+ $result = "> {$str}\n{$result}";
89
+ $stack[] = $str;
90
+ }
91
+
92
+ foreach (array_keys($stack) as $k) {
93
+ $result .= "< {$stack[$k]}\n";
94
+ }
95
+
96
+ return $result;
97
+ }
98
+
99
+ /**
100
+ * Set the HTTP handler that actually returns a promise.
101
+ *
102
+ * @param callable $handler Accepts a request and array of options and
103
+ * returns a Promise.
104
+ */
105
+ public function setHandler(callable $handler)
106
+ {
107
+ $this->handler = $handler;
108
+ $this->cached = null;
109
+ }
110
+
111
+ /**
112
+ * Returns true if the builder has a handler.
113
+ *
114
+ * @return bool
115
+ */
116
+ public function hasHandler()
117
+ {
118
+ return (bool) $this->handler;
119
+ }
120
+
121
+ /**
122
+ * Unshift a middleware to the bottom of the stack.
123
+ *
124
+ * @param callable $middleware Middleware function
125
+ * @param string $name Name to register for this middleware.
126
+ */
127
+ public function unshift(callable $middleware, $name = null)
128
+ {
129
+ array_unshift($this->stack, [$middleware, $name]);
130
+ $this->cached = null;
131
+ }
132
+
133
+ /**
134
+ * Push a middleware to the top of the stack.
135
+ *
136
+ * @param callable $middleware Middleware function
137
+ * @param string $name Name to register for this middleware.
138
+ */
139
+ public function push(callable $middleware, $name = '')
140
+ {
141
+ $this->stack[] = [$middleware, $name];
142
+ $this->cached = null;
143
+ }
144
+
145
+ /**
146
+ * Add a middleware before another middleware by name.
147
+ *
148
+ * @param string $findName Middleware to find
149
+ * @param callable $middleware Middleware function
150
+ * @param string $withName Name to register for this middleware.
151
+ */
152
+ public function before($findName, callable $middleware, $withName = '')
153
+ {
154
+ $this->splice($findName, $withName, $middleware, true);
155
+ }
156
+
157
+ /**
158
+ * Add a middleware after another middleware by name.
159
+ *
160
+ * @param string $findName Middleware to find
161
+ * @param callable $middleware Middleware function
162
+ * @param string $withName Name to register for this middleware.
163
+ */
164
+ public function after($findName, callable $middleware, $withName = '')
165
+ {
166
+ $this->splice($findName, $withName, $middleware, false);
167
+ }
168
+
169
+ /**
170
+ * Remove a middleware by instance or name from the stack.
171
+ *
172
+ * @param callable|string $remove Middleware to remove by instance or name.
173
+ */
174
+ public function remove($remove)
175
+ {
176
+ $this->cached = null;
177
+ $idx = is_callable($remove) ? 0 : 1;
178
+ $this->stack = array_values(array_filter(
179
+ $this->stack,
180
+ function ($tuple) use ($idx, $remove) {
181
+ return $tuple[$idx] !== $remove;
182
+ }
183
+ ));
184
+ }
185
+
186
+ /**
187
+ * Compose the middleware and handler into a single callable function.
188
+ *
189
+ * @return callable
190
+ */
191
+ public function resolve()
192
+ {
193
+ if (!$this->cached) {
194
+ if (!($prev = $this->handler)) {
195
+ throw new \LogicException('No handler has been specified');
196
+ }
197
+
198
+ foreach (array_reverse($this->stack) as $fn) {
199
+ $prev = $fn[0]($prev);
200
+ }
201
+
202
+ $this->cached = $prev;
203
+ }
204
+
205
+ return $this->cached;
206
+ }
207
+
208
+ /**
209
+ * @param $name
210
+ * @return int
211
+ */
212
+ private function findByName($name)
213
+ {
214
+ foreach ($this->stack as $k => $v) {
215
+ if ($v[1] === $name) {
216
+ return $k;
217
+ }
218
+ }
219
+
220
+ throw new \InvalidArgumentException("Middleware not found: $name");
221
+ }
222
+
223
+ /**
224
+ * Splices a function into the middleware list at a specific position.
225
+ *
226
+ * @param $findName
227
+ * @param $withName
228
+ * @param callable $middleware
229
+ * @param $before
230
+ */
231
+ private function splice($findName, $withName, callable $middleware, $before)
232
+ {
233
+ $this->cached = null;
234
+ $idx = $this->findByName($findName);
235
+ $tuple = [$middleware, $withName];
236
+
237
+ if ($before) {
238
+ if ($idx === 0) {
239
+ array_unshift($this->stack, $tuple);
240
+ } else {
241
+ $replacement = [$tuple, $this->stack[$idx]];
242
+ array_splice($this->stack, $idx, 1, $replacement);
243
+ }
244
+ } elseif ($idx === count($this->stack) - 1) {
245
+ $this->stack[] = $tuple;
246
+ } else {
247
+ $replacement = [$this->stack[$idx], $tuple];
248
+ array_splice($this->stack, $idx, 1, $replacement);
249
+ }
250
+ }
251
+
252
+ /**
253
+ * Provides a debug string for a given callable.
254
+ *
255
+ * @param array|callable $fn Function to write as a string.
256
+ *
257
+ * @return string
258
+ */
259
+ private function debugCallable($fn)
260
+ {
261
+ if (is_string($fn)) {
262
+ return "callable({$fn})";
263
+ }
264
+
265
+ if (is_array($fn)) {
266
+ return is_string($fn[0])
267
+ ? "callable({$fn[0]}::{$fn[1]})"
268
+ : "callable(['" . get_class($fn[0]) . "', '{$fn[1]}'])";
269
+ }
270
+
271
+ return 'callable(' . spl_object_hash($fn) . ')';
272
+ }
273
+ }
vendor/guzzlehttp/guzzle/src/MessageFormatter.php ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use Psr\Http\Message\MessageInterface;
5
+ use Psr\Http\Message\RequestInterface;
6
+ use Psr\Http\Message\ResponseInterface;
7
+
8
+ /**
9
+ * Formats log messages using variable substitutions for requests, responses,
10
+ * and other transactional data.
11
+ *
12
+ * The following variable substitutions are supported:
13
+ *
14
+ * - {request}: Full HTTP request message
15
+ * - {response}: Full HTTP response message
16
+ * - {ts}: ISO 8601 date in GMT
17
+ * - {date_iso_8601} ISO 8601 date in GMT
18
+ * - {date_common_log} Apache common log date using the configured timezone.
19
+ * - {host}: Host of the request
20
+ * - {method}: Method of the request
21
+ * - {uri}: URI of the request
22
+ * - {version}: Protocol version
23
+ * - {target}: Request target of the request (path + query + fragment)
24
+ * - {hostname}: Hostname of the machine that sent the request
25
+ * - {code}: Status code of the response (if available)
26
+ * - {phrase}: Reason phrase of the response (if available)
27
+ * - {error}: Any error messages (if available)
28
+ * - {req_header_*}: Replace `*` with the lowercased name of a request header to add to the message
29
+ * - {res_header_*}: Replace `*` with the lowercased name of a response header to add to the message
30
+ * - {req_headers}: Request headers
31
+ * - {res_headers}: Response headers
32
+ * - {req_body}: Request body
33
+ * - {res_body}: Response body
34
+ */
35
+ class MessageFormatter
36
+ {
37
+ /**
38
+ * Apache Common Log Format.
39
+ * @link http://httpd.apache.org/docs/2.4/logs.html#common
40
+ * @var string
41
+ */
42
+ const CLF = "{hostname} {req_header_User-Agent} - [{date_common_log}] \"{method} {target} HTTP/{version}\" {code} {res_header_Content-Length}";
43
+ const DEBUG = ">>>>>>>>\n{request}\n<<<<<<<<\n{response}\n--------\n{error}";
44
+ const SHORT = '[{ts}] "{method} {target} HTTP/{version}" {code}';
45
+
46
+ /** @var string Template used to format log messages */
47
+ private $template;
48
+
49
+ /**
50
+ * @param string $template Log message template
51
+ */
52
+ public function __construct($template = self::CLF)
53
+ {
54
+ $this->template = $template ?: self::CLF;
55
+ }
56
+
57
+ /**
58
+ * Returns a formatted message string.
59
+ *
60
+ * @param RequestInterface $request Request that was sent
61
+ * @param ResponseInterface $response Response that was received
62
+ * @param \Exception $error Exception that was received
63
+ *
64
+ * @return string
65
+ */
66
+ public function format(
67
+ RequestInterface $request,
68
+ ResponseInterface $response = null,
69
+ \Exception $error = null
70
+ ) {
71
+ $cache = [];
72
+
73
+ return preg_replace_callback(
74
+ '/{\s*([A-Za-z_\-\.0-9]+)\s*}/',
75
+ function (array $matches) use ($request, $response, $error, &$cache) {
76
+ if (isset($cache[$matches[1]])) {
77
+ return $cache[$matches[1]];
78
+ }
79
+
80
+ $result = '';
81
+ switch ($matches[1]) {
82
+ case 'request':
83
+ $result = Psr7\str($request);
84
+ break;
85
+ case 'response':
86
+ $result = $response ? Psr7\str($response) : '';
87
+ break;
88
+ case 'req_headers':
89
+ $result = trim($request->getMethod()
90
+ . ' ' . $request->getRequestTarget())
91
+ . ' HTTP/' . $request->getProtocolVersion() . "\r\n"
92
+ . $this->headers($request);
93
+ break;
94
+ case 'res_headers':
95
+ $result = $response ?
96
+ sprintf(
97
+ 'HTTP/%s %d %s',
98
+ $response->getProtocolVersion(),
99
+ $response->getStatusCode(),
100
+ $response->getReasonPhrase()
101
+ ) . "\r\n" . $this->headers($response)
102
+ : 'NULL';
103
+ break;
104
+ case 'req_body':
105
+ $result = $request->getBody();
106
+ break;
107
+ case 'res_body':
108
+ $result = $response ? $response->getBody() : 'NULL';
109
+ break;
110
+ case 'ts':
111
+ case 'date_iso_8601':
112
+ $result = gmdate('c');
113
+ break;
114
+ case 'date_common_log':
115
+ $result = date('d/M/Y:H:i:s O');
116
+ break;
117
+ case 'method':
118
+ $result = $request->getMethod();
119
+ break;
120
+ case 'version':
121
+ $result = $request->getProtocolVersion();
122
+ break;
123
+ case 'uri':
124
+ case 'url':
125
+ $result = $request->getUri();
126
+ break;
127
+ case 'target':
128
+ $result = $request->getRequestTarget();
129
+ break;
130
+ case 'req_version':
131
+ $result = $request->getProtocolVersion();
132
+ break;
133
+ case 'res_version':
134
+ $result = $response
135
+ ? $response->getProtocolVersion()
136
+ : 'NULL';
137
+ break;
138
+ case 'host':
139
+ $result = $request->getHeaderLine('Host');
140
+ break;
141
+ case 'hostname':
142
+ $result = gethostname();
143
+ break;
144
+ case 'code':
145
+ $result = $response ? $response->getStatusCode() : 'NULL';
146
+ break;
147
+ case 'phrase':
148
+ $result = $response ? $response->getReasonPhrase() : 'NULL';
149
+ break;
150
+ case 'error':
151
+ $result = $error ? $error->getMessage() : 'NULL';
152
+ break;
153
+ default:
154
+ // handle prefixed dynamic headers
155
+ if (strpos($matches[1], 'req_header_') === 0) {
156
+ $result = $request->getHeaderLine(substr($matches[1], 11));
157
+ } elseif (strpos($matches[1], 'res_header_') === 0) {
158
+ $result = $response
159
+ ? $response->getHeaderLine(substr($matches[1], 11))
160
+ : 'NULL';
161
+ }
162
+ }
163
+
164
+ $cache[$matches[1]] = $result;
165
+ return $result;
166
+ },
167
+ $this->template
168
+ );
169
+ }
170
+
171
+ private function headers(MessageInterface $message)
172
+ {
173
+ $result = '';
174
+ foreach ($message->getHeaders() as $name => $values) {
175
+ $result .= $name . ': ' . implode(', ', $values) . "\r\n";
176
+ }
177
+
178
+ return trim($result);
179
+ }
180
+ }
vendor/guzzlehttp/guzzle/src/Middleware.php ADDED
@@ -0,0 +1,255 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Cookie\CookieJarInterface;
5
+ use GuzzleHttp\Exception\RequestException;
6
+ use GuzzleHttp\Promise\RejectedPromise;
7
+ use GuzzleHttp\Psr7;
8
+ use Psr\Http\Message\ResponseInterface;
9
+ use Psr\Log\LoggerInterface;
10
+ use Psr\Log\LogLevel;
11
+
12
+ /**
13
+ * Functions used to create and wrap handlers with handler middleware.
14
+ */
15
+ final class Middleware
16
+ {
17
+ /**
18
+ * Middleware that adds cookies to requests.
19
+ *
20
+ * The options array must be set to a CookieJarInterface in order to use
21
+ * cookies. This is typically handled for you by a client.
22
+ *
23
+ * @return callable Returns a function that accepts the next handler.
24
+ */
25
+ public static function cookies()
26
+ {
27
+ return function (callable $handler) {
28
+ return function ($request, array $options) use ($handler) {
29
+ if (empty($options['cookies'])) {
30
+ return $handler($request, $options);
31
+ } elseif (!($options['cookies'] instanceof CookieJarInterface)) {
32
+ throw new \InvalidArgumentException('cookies must be an instance of GuzzleHttp\Cookie\CookieJarInterface');
33
+ }
34
+ $cookieJar = $options['cookies'];
35
+ $request = $cookieJar->withCookieHeader($request);
36
+ return $handler($request, $options)
37
+ ->then(
38
+ function ($response) use ($cookieJar, $request) {
39
+ $cookieJar->extractCookies($request, $response);
40
+ return $response;
41
+ }
42
+ );
43
+ };
44
+ };
45
+ }
46
+
47
+ /**
48
+ * Middleware that throws exceptions for 4xx or 5xx responses when the
49
+ * "http_error" request option is set to true.
50
+ *
51
+ * @return callable Returns a function that accepts the next handler.
52
+ */
53
+ public static function httpErrors()
54
+ {
55
+ return function (callable $handler) {
56
+ return function ($request, array $options) use ($handler) {
57
+ if (empty($options['http_errors'])) {
58
+ return $handler($request, $options);
59
+ }
60
+ return $handler($request, $options)->then(
61
+ function (ResponseInterface $response) use ($request, $handler) {
62
+ $code = $response->getStatusCode();
63
+ if ($code < 400) {
64
+ return $response;
65
+ }
66
+ throw RequestException::create($request, $response);
67
+ }
68
+ );
69
+ };
70
+ };
71
+ }
72
+
73
+ /**
74
+ * Middleware that pushes history data to an ArrayAccess container.
75
+ *
76
+ * @param array|\ArrayAccess $container Container to hold the history (by reference).
77
+ *
78
+ * @return callable Returns a function that accepts the next handler.
79
+ * @throws \InvalidArgumentException if container is not an array or ArrayAccess.
80
+ */
81
+ public static function history(&$container)
82
+ {
83
+ if (!is_array($container) && !$container instanceof \ArrayAccess) {
84
+ throw new \InvalidArgumentException('history container must be an array or object implementing ArrayAccess');
85
+ }
86
+
87
+ return function (callable $handler) use (&$container) {
88
+ return function ($request, array $options) use ($handler, &$container) {
89
+ return $handler($request, $options)->then(
90
+ function ($value) use ($request, &$container, $options) {
91
+ $container[] = [
92
+ 'request' => $request,
93
+ 'response' => $value,
94
+ 'error' => null,
95
+ 'options' => $options
96
+ ];
97
+ return $value;
98
+ },
99
+ function ($reason) use ($request, &$container, $options) {
100
+ $container[] = [
101
+ 'request' => $request,
102
+ 'response' => null,
103
+ 'error' => $reason,
104
+ 'options' => $options
105
+ ];
106
+ return \GuzzleHttp\Promise\rejection_for($reason);
107
+ }
108
+ );
109
+ };
110
+ };
111
+ }
112
+
113
+ /**
114
+ * Middleware that invokes a callback before and after sending a request.
115
+ *
116
+ * The provided listener cannot modify or alter the response. It simply
117
+ * "taps" into the chain to be notified before returning the promise. The
118
+ * before listener accepts a request and options array, and the after
119
+ * listener accepts a request, options array, and response promise.
120
+ *
121
+ * @param callable $before Function to invoke before forwarding the request.
122
+ * @param callable $after Function invoked after forwarding.
123
+ *
124
+ * @return callable Returns a function that accepts the next handler.
125
+ */
126
+ public static function tap(callable $before = null, callable $after = null)
127
+ {
128
+ return function (callable $handler) use ($before, $after) {
129
+ return function ($request, array $options) use ($handler, $before, $after) {
130
+ if ($before) {
131
+ $before($request, $options);
132
+ }
133
+ $response = $handler($request, $options);
134
+ if ($after) {
135
+ $after($request, $options, $response);
136
+ }
137
+ return $response;
138
+ };
139
+ };
140
+ }
141
+
142
+ /**
143
+ * Middleware that handles request redirects.
144
+ *
145
+ * @return callable Returns a function that accepts the next handler.
146
+ */
147
+ public static function redirect()
148
+ {
149
+ return function (callable $handler) {
150
+ return new RedirectMiddleware($handler);
151
+ };
152
+ }
153
+
154
+ /**
155
+ * Middleware that retries requests based on the boolean result of
156
+ * invoking the provided "decider" function.
157
+ *
158
+ * If no delay function is provided, a simple implementation of exponential
159
+ * backoff will be utilized.
160
+ *
161
+ * @param callable $decider Function that accepts the number of retries,
162
+ * a request, [response], and [exception] and
163
+ * returns true if the request is to be retried.
164
+ * @param callable $delay Function that accepts the number of retries and
165
+ * returns the number of milliseconds to delay.
166
+ *
167
+ * @return callable Returns a function that accepts the next handler.
168
+ */
169
+ public static function retry(callable $decider, callable $delay = null)
170
+ {
171
+ return function (callable $handler) use ($decider, $delay) {
172
+ return new RetryMiddleware($decider, $handler, $delay);
173
+ };
174
+ }
175
+
176
+ /**
177
+ * Middleware that logs requests, responses, and errors using a message
178
+ * formatter.
179
+ *
180
+ * @param LoggerInterface $logger Logs messages.
181
+ * @param MessageFormatter $formatter Formatter used to create message strings.
182
+ * @param string $logLevel Level at which to log requests.
183
+ *
184
+ * @return callable Returns a function that accepts the next handler.
185
+ */
186
+ public static function log(LoggerInterface $logger, MessageFormatter $formatter, $logLevel = LogLevel::INFO)
187
+ {
188
+ return function (callable $handler) use ($logger, $formatter, $logLevel) {
189
+ return function ($request, array $options) use ($handler, $logger, $formatter, $logLevel) {
190
+ return $handler($request, $options)->then(
191
+ function ($response) use ($logger, $request, $formatter, $logLevel) {
192
+ $message = $formatter->format($request, $response);
193
+ $logger->log($logLevel, $message);
194
+ return $response;
195
+ },
196
+ function ($reason) use ($logger, $request, $formatter) {
197
+ $response = $reason instanceof RequestException
198
+ ? $reason->getResponse()
199
+ : null;
200
+ $message = $formatter->format($request, $response, $reason);
201
+ $logger->notice($message);
202
+ return \GuzzleHttp\Promise\rejection_for($reason);
203
+ }
204
+ );
205
+ };
206
+ };
207
+ }
208
+
209
+ /**
210
+ * This middleware adds a default content-type if possible, a default
211
+ * content-length or transfer-encoding header, and the expect header.
212
+ *
213
+ * @return callable
214
+ */
215
+ public static function prepareBody()
216
+ {
217
+ return function (callable $handler) {
218
+ return new PrepareBodyMiddleware($handler);
219
+ };
220
+ }
221
+
222
+ /**
223
+ * Middleware that applies a map function to the request before passing to
224
+ * the next handler.
225
+ *
226
+ * @param callable $fn Function that accepts a RequestInterface and returns
227
+ * a RequestInterface.
228
+ * @return callable
229
+ */
230
+ public static function mapRequest(callable $fn)
231
+ {
232
+ return function (callable $handler) use ($fn) {
233
+ return function ($request, array $options) use ($handler, $fn) {
234
+ return $handler($fn($request), $options);
235
+ };
236
+ };
237
+ }
238
+
239
+ /**
240
+ * Middleware that applies a map function to the resolved promise's
241
+ * response.
242
+ *
243
+ * @param callable $fn Function that accepts a ResponseInterface and
244
+ * returns a ResponseInterface.
245
+ * @return callable
246
+ */
247
+ public static function mapResponse(callable $fn)
248
+ {
249
+ return function (callable $handler) use ($fn) {
250
+ return function ($request, array $options) use ($handler, $fn) {
251
+ return $handler($request, $options)->then($fn);
252
+ };
253
+ };
254
+ }
255
+ }
vendor/guzzlehttp/guzzle/src/Pool.php ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Promise\PromisorInterface;
5
+ use Psr\Http\Message\RequestInterface;
6
+ use GuzzleHttp\Promise\EachPromise;
7
+
8
+ /**
9
+ * Sends and iterator of requests concurrently using a capped pool size.
10
+ *
11
+ * The pool will read from an iterator until it is cancelled or until the
12
+ * iterator is consumed. When a request is yielded, the request is sent after
13
+ * applying the "request_options" request options (if provided in the ctor).
14
+ *
15
+ * When a function is yielded by the iterator, the function is provided the
16
+ * "request_options" array that should be merged on top of any existing
17
+ * options, and the function MUST then return a wait-able promise.
18
+ */
19
+ class Pool implements PromisorInterface
20
+ {
21
+ /** @var EachPromise */
22
+ private $each;
23
+
24
+ /**
25
+ * @param ClientInterface $client Client used to send the requests.
26
+ * @param array|\Iterator $requests Requests or functions that return
27
+ * requests to send concurrently.
28
+ * @param array $config Associative array of options
29
+ * - concurrency: (int) Maximum number of requests to send concurrently
30
+ * - options: Array of request options to apply to each request.
31
+ * - fulfilled: (callable) Function to invoke when a request completes.
32
+ * - rejected: (callable) Function to invoke when a request is rejected.
33
+ */
34
+ public function __construct(
35
+ ClientInterface $client,
36
+ $requests,
37
+ array $config = []
38
+ ) {
39
+ // Backwards compatibility.
40
+ if (isset($config['pool_size'])) {
41
+ $config['concurrency'] = $config['pool_size'];
42
+ } elseif (!isset($config['concurrency'])) {
43
+ $config['concurrency'] = 25;
44
+ }
45
+
46
+ if (isset($config['options'])) {
47
+ $opts = $config['options'];
48
+ unset($config['options']);
49
+ } else {
50
+ $opts = [];
51
+ }
52
+
53
+ $iterable = \GuzzleHttp\Promise\iter_for($requests);
54
+ $requests = function () use ($iterable, $client, $opts) {
55
+ foreach ($iterable as $key => $rfn) {
56
+ if ($rfn instanceof RequestInterface) {
57
+ yield $key => $client->sendAsync($rfn, $opts);
58
+ } elseif (is_callable($rfn)) {
59
+ yield $key => $rfn($opts);
60
+ } else {
61
+ throw new \InvalidArgumentException('Each value yielded by '
62
+ . 'the iterator must be a Psr7\Http\Message\RequestInterface '
63
+ . 'or a callable that returns a promise that fulfills '
64
+ . 'with a Psr7\Message\Http\ResponseInterface object.');
65
+ }
66
+ }
67
+ };
68
+
69
+ $this->each = new EachPromise($requests(), $config);
70
+ }
71
+
72
+ public function promise()
73
+ {
74
+ return $this->each->promise();
75
+ }
76
+
77
+ /**
78
+ * Sends multiple requests concurrently and returns an array of responses
79
+ * and exceptions that uses the same ordering as the provided requests.
80
+ *
81
+ * IMPORTANT: This method keeps every request and response in memory, and
82
+ * as such, is NOT recommended when sending a large number or an
83
+ * indeterminate number of requests concurrently.
84
+ *
85
+ * @param ClientInterface $client Client used to send the requests
86
+ * @param array|\Iterator $requests Requests to send concurrently.
87
+ * @param array $options Passes through the options available in
88
+ * {@see GuzzleHttp\Pool::__construct}
89
+ *
90
+ * @return array Returns an array containing the response or an exception
91
+ * in the same order that the requests were sent.
92
+ * @throws \InvalidArgumentException if the event format is incorrect.
93
+ */
94
+ public static function batch(
95
+ ClientInterface $client,
96
+ $requests,
97
+ array $options = []
98
+ ) {
99
+ $res = [];
100
+ self::cmpCallback($options, 'fulfilled', $res);
101
+ self::cmpCallback($options, 'rejected', $res);
102
+ $pool = new static($client, $requests, $options);
103
+ $pool->promise()->wait();
104
+ ksort($res);
105
+
106
+ return $res;
107
+ }
108
+
109
+ private static function cmpCallback(array &$options, $name, array &$results)
110
+ {
111
+ if (!isset($options[$name])) {
112
+ $options[$name] = function ($v, $k) use (&$results) {
113
+ $results[$k] = $v;
114
+ };
115
+ } else {
116
+ $currentFn = $options[$name];
117
+ $options[$name] = function ($v, $k) use (&$results, $currentFn) {
118
+ $currentFn($v, $k);
119
+ $results[$k] = $v;
120
+ };
121
+ }
122
+ }
123
+ }
vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Promise\PromiseInterface;
5
+ use GuzzleHttp\Psr7;
6
+ use Psr\Http\Message\RequestInterface;
7
+
8
+ /**
9
+ * Prepares requests that contain a body, adding the Content-Length,
10
+ * Content-Type, and Expect headers.
11
+ */
12
+ class PrepareBodyMiddleware
13
+ {
14
+ /** @var callable */
15
+ private $nextHandler;
16
+
17
+ /**
18
+ * @param callable $nextHandler Next handler to invoke.
19
+ */
20
+ public function __construct(callable $nextHandler)
21
+ {
22
+ $this->nextHandler = $nextHandler;
23
+ }
24
+
25
+ /**
26
+ * @param RequestInterface $request
27
+ * @param array $options
28
+ *
29
+ * @return PromiseInterface
30
+ */
31
+ public function __invoke(RequestInterface $request, array $options)
32
+ {
33
+ $fn = $this->nextHandler;
34
+
35
+ // Don't do anything if the request has no body.
36
+ if ($request->getBody()->getSize() === 0) {
37
+ return $fn($request, $options);
38
+ }
39
+
40
+ $modify = [];
41
+
42
+ // Add a default content-type if possible.
43
+ if (!$request->hasHeader('Content-Type')) {
44
+ if ($uri = $request->getBody()->getMetadata('uri')) {
45
+ if ($type = Psr7\mimetype_from_filename($uri)) {
46
+ $modify['set_headers']['Content-Type'] = $type;
47
+ }
48
+ }
49
+ }
50
+
51
+ // Add a default content-length or transfer-encoding header.
52
+ if (!$request->hasHeader('Content-Length')
53
+ && !$request->hasHeader('Transfer-Encoding')
54
+ ) {
55
+ $size = $request->getBody()->getSize();
56
+ if ($size !== null) {
57
+ $modify['set_headers']['Content-Length'] = $size;
58
+ } else {
59
+ $modify['set_headers']['Transfer-Encoding'] = 'chunked';
60
+ }
61
+ }
62
+
63
+ // Add the expect header if needed.
64
+ $this->addExpectHeader($request, $options, $modify);
65
+
66
+ return $fn(Psr7\modify_request($request, $modify), $options);
67
+ }
68
+
69
+ private function addExpectHeader(
70
+ RequestInterface $request,
71
+ array $options,
72
+ array &$modify
73
+ ) {
74
+ // Determine if the Expect header should be used
75
+ if ($request->hasHeader('Expect')) {
76
+ return;
77
+ }
78
+
79
+ $expect = isset($options['expect']) ? $options['expect'] : null;
80
+
81
+ // Return if disabled or if you're not using HTTP/1.1 or HTTP/2.0
82
+ if ($expect === false || $request->getProtocolVersion() < 1.1) {
83
+ return;
84
+ }
85
+
86
+ // The expect header is unconditionally enabled
87
+ if ($expect === true) {
88
+ $modify['set_headers']['Expect'] = '100-Continue';
89
+ return;
90
+ }
91
+
92
+ // By default, send the expect header when the payload is > 1mb
93
+ if ($expect === null) {
94
+ $expect = 1048576;
95
+ }
96
+
97
+ // Always add if the body cannot be rewound, the size cannot be
98
+ // determined, or the size is greater than the cutoff threshold
99
+ $body = $request->getBody();
100
+ $size = $body->getSize();
101
+
102
+ if ($size === null || $size >= (int) $expect || !$body->isSeekable()) {
103
+ $modify['set_headers']['Expect'] = '100-Continue';
104
+ }
105
+ }
106
+ }
vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php ADDED
@@ -0,0 +1,237 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Exception\BadResponseException;
5
+ use GuzzleHttp\Exception\TooManyRedirectsException;
6
+ use GuzzleHttp\Promise\PromiseInterface;
7
+ use GuzzleHttp\Psr7;
8
+ use Psr\Http\Message\RequestInterface;
9
+ use Psr\Http\Message\ResponseInterface;
10
+ use Psr\Http\Message\UriInterface;
11
+
12
+ /**
13
+ * Request redirect middleware.
14
+ *
15
+ * Apply this middleware like other middleware using
16
+ * {@see GuzzleHttp\Middleware::redirect()}.
17
+ */
18
+ class RedirectMiddleware
19
+ {
20
+ const HISTORY_HEADER = 'X-Guzzle-Redirect-History';
21
+
22
+ const STATUS_HISTORY_HEADER = 'X-Guzzle-Redirect-Status-History';
23
+
24
+ public static $defaultSettings = [
25
+ 'max' => 5,
26
+ 'protocols' => ['http', 'https'],
27
+ 'strict' => false,
28
+ 'referer' => false,
29
+ 'track_redirects' => false,
30
+ ];
31
+
32
+ /** @var callable */
33
+ private $nextHandler;
34
+
35
+ /**
36
+ * @param callable $nextHandler Next handler to invoke.
37
+ */
38
+ public function __construct(callable $nextHandler)
39
+ {
40
+ $this->nextHandler = $nextHandler;
41
+ }
42
+
43
+ /**
44
+ * @param RequestInterface $request
45
+ * @param array $options
46
+ *
47
+ * @return PromiseInterface
48
+ */
49
+ public function __invoke(RequestInterface $request, array $options)
50
+ {
51
+ $fn = $this->nextHandler;
52
+
53
+ if (empty($options['allow_redirects'])) {
54
+ return $fn($request, $options);
55
+ }
56
+
57
+ if ($options['allow_redirects'] === true) {
58
+ $options['allow_redirects'] = self::$defaultSettings;
59
+ } elseif (!is_array($options['allow_redirects'])) {
60
+ throw new \InvalidArgumentException('allow_redirects must be true, false, or array');
61
+ } else {
62
+ // Merge the default settings with the provided settings
63
+ $options['allow_redirects'] += self::$defaultSettings;
64
+ }
65
+
66
+ if (empty($options['allow_redirects']['max'])) {
67
+ return $fn($request, $options);
68
+ }
69
+
70
+ return $fn($request, $options)
71
+ ->then(function (ResponseInterface $response) use ($request, $options) {
72
+ return $this->checkRedirect($request, $options, $response);
73
+ });
74
+ }
75
+
76
+ /**
77
+ * @param RequestInterface $request
78
+ * @param array $options
79
+ * @param ResponseInterface|PromiseInterface $response
80
+ *
81
+ * @return ResponseInterface|PromiseInterface
82
+ */
83
+ public function checkRedirect(
84
+ RequestInterface $request,
85
+ array $options,
86
+ ResponseInterface $response
87
+ ) {
88
+ if (substr($response->getStatusCode(), 0, 1) != '3'
89
+ || !$response->hasHeader('Location')
90
+ ) {
91
+ return $response;
92
+ }
93
+
94
+ $this->guardMax($request, $options);
95
+ $nextRequest = $this->modifyRequest($request, $options, $response);
96
+
97
+ if (isset($options['allow_redirects']['on_redirect'])) {
98
+ call_user_func(
99
+ $options['allow_redirects']['on_redirect'],
100
+ $request,
101
+ $response,
102
+ $nextRequest->getUri()
103
+ );
104
+ }
105
+
106
+ /** @var PromiseInterface|ResponseInterface $promise */
107
+ $promise = $this($nextRequest, $options);
108
+
109
+ // Add headers to be able to track history of redirects.
110
+ if (!empty($options['allow_redirects']['track_redirects'])) {
111
+ return $this->withTracking(
112
+ $promise,
113
+ (string) $nextRequest->getUri(),
114
+ $response->getStatusCode()
115
+ );
116
+ }
117
+
118
+ return $promise;
119
+ }
120
+
121
+ private function withTracking(PromiseInterface $promise, $uri, $statusCode)
122
+ {
123
+ return $promise->then(
124
+ function (ResponseInterface $response) use ($uri, $statusCode) {
125
+ // Note that we are pushing to the front of the list as this
126
+ // would be an earlier response than what is currently present
127
+ // in the history header.
128
+ $historyHeader = $response->getHeader(self::HISTORY_HEADER);
129
+ $statusHeader = $response->getHeader(self::STATUS_HISTORY_HEADER);
130
+ array_unshift($historyHeader, $uri);
131
+ array_unshift($statusHeader, $statusCode);
132
+ return $response->withHeader(self::HISTORY_HEADER, $historyHeader)
133
+ ->withHeader(self::STATUS_HISTORY_HEADER, $statusHeader);
134
+ }
135
+ );
136
+ }
137
+
138
+ private function guardMax(RequestInterface $request, array &$options)
139
+ {
140
+ $current = isset($options['__redirect_count'])
141
+ ? $options['__redirect_count']
142
+ : 0;
143
+ $options['__redirect_count'] = $current + 1;
144
+ $max = $options['allow_redirects']['max'];
145
+
146
+ if ($options['__redirect_count'] > $max) {
147
+ throw new TooManyRedirectsException(
148
+ "Will not follow more than {$max} redirects",
149
+ $request
150
+ );
151
+ }
152
+ }
153
+
154
+ /**
155
+ * @param RequestInterface $request
156
+ * @param array $options
157
+ * @param ResponseInterface $response
158
+ *
159
+ * @return RequestInterface
160
+ */
161
+ public function modifyRequest(
162
+ RequestInterface $request,
163
+ array $options,
164
+ ResponseInterface $response
165
+ ) {
166
+ // Request modifications to apply.
167
+ $modify = [];
168
+ $protocols = $options['allow_redirects']['protocols'];
169
+
170
+ // Use a GET request if this is an entity enclosing request and we are
171
+ // not forcing RFC compliance, but rather emulating what all browsers
172
+ // would do.
173
+ $statusCode = $response->getStatusCode();
174
+ if ($statusCode == 303 ||
175
+ ($statusCode <= 302 && $request->getBody() && !$options['allow_redirects']['strict'])
176
+ ) {
177
+ $modify['method'] = 'GET';
178
+ $modify['body'] = '';
179
+ }
180
+
181
+ $modify['uri'] = $this->redirectUri($request, $response, $protocols);
182
+ Psr7\rewind_body($request);
183
+
184
+ // Add the Referer header if it is told to do so and only
185
+ // add the header if we are not redirecting from https to http.
186
+ if ($options['allow_redirects']['referer']
187
+ && $modify['uri']->getScheme() === $request->getUri()->getScheme()
188
+ ) {
189
+ $uri = $request->getUri()->withUserInfo('', '');
190
+ $modify['set_headers']['Referer'] = (string) $uri;
191
+ } else {
192
+ $modify['remove_headers'][] = 'Referer';
193
+ }
194
+
195
+ // Remove Authorization header if host is different.
196
+ if ($request->getUri()->getHost() !== $modify['uri']->getHost()) {
197
+ $modify['remove_headers'][] = 'Authorization';
198
+ }
199
+
200
+ return Psr7\modify_request($request, $modify);
201
+ }
202
+
203
+ /**
204
+ * Set the appropriate URL on the request based on the location header
205
+ *
206
+ * @param RequestInterface $request
207
+ * @param ResponseInterface $response
208
+ * @param array $protocols
209
+ *
210
+ * @return UriInterface
211
+ */
212
+ private function redirectUri(
213
+ RequestInterface $request,
214
+ ResponseInterface $response,
215
+ array $protocols
216
+ ) {
217
+ $location = Psr7\UriResolver::resolve(
218
+ $request->getUri(),
219
+ new Psr7\Uri($response->getHeaderLine('Location'))
220
+ );
221
+
222
+ // Ensure that the redirect URI is allowed based on the protocols.
223
+ if (!in_array($location->getScheme(), $protocols)) {
224
+ throw new BadResponseException(
225
+ sprintf(
226
+ 'Redirect URI, %s, does not use one of the allowed redirect protocols: %s',
227
+ $location,
228
+ implode(', ', $protocols)
229
+ ),
230
+ $request,
231
+ $response
232
+ );
233
+ }
234
+
235
+ return $location;
236
+ }
237
+ }
vendor/guzzlehttp/guzzle/src/RequestOptions.php ADDED
@@ -0,0 +1,255 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ /**
5
+ * This class contains a list of built-in Guzzle request options.
6
+ *
7
+ * More documentation for each option can be found at http://guzzlephp.org/.
8
+ *
9
+ * @link http://docs.guzzlephp.org/en/v6/request-options.html
10
+ */
11
+ final class RequestOptions
12
+ {
13
+ /**
14
+ * allow_redirects: (bool|array) Controls redirect behavior. Pass false
15
+ * to disable redirects, pass true to enable redirects, pass an
16
+ * associative to provide custom redirect settings. Defaults to "false".
17
+ * This option only works if your handler has the RedirectMiddleware. When
18
+ * passing an associative array, you can provide the following key value
19
+ * pairs:
20
+ *
21
+ * - max: (int, default=5) maximum number of allowed redirects.
22
+ * - strict: (bool, default=false) Set to true to use strict redirects
23
+ * meaning redirect POST requests with POST requests vs. doing what most
24
+ * browsers do which is redirect POST requests with GET requests
25
+ * - referer: (bool, default=true) Set to false to disable the Referer
26
+ * header.
27
+ * - protocols: (array, default=['http', 'https']) Allowed redirect
28
+ * protocols.
29
+ * - on_redirect: (callable) PHP callable that is invoked when a redirect
30
+ * is encountered. The callable is invoked with the request, the redirect
31
+ * response that was received, and the effective URI. Any return value
32
+ * from the on_redirect function is ignored.
33
+ */
34
+ const ALLOW_REDIRECTS = 'allow_redirects';
35
+
36
+ /**
37
+ * auth: (array) Pass an array of HTTP authentication parameters to use
38
+ * with the request. The array must contain the username in index [0],
39
+ * the password in index [1], and you can optionally provide a built-in
40
+ * authentication type in index [2]. Pass null to disable authentication
41
+ * for a request.
42
+ */
43
+ const AUTH = 'auth';
44
+
45
+ /**
46
+ * body: (resource|string|null|int|float|StreamInterface|callable|\Iterator)
47
+ * Body to send in the request.
48
+ */
49
+ const BODY = 'body';
50
+
51
+ /**
52
+ * cert: (string|array) Set to a string to specify the path to a file
53
+ * containing a PEM formatted SSL client side certificate. If a password
54
+ * is required, then set cert to an array containing the path to the PEM
55
+ * file in the first array element followed by the certificate password
56
+ * in the second array element.
57
+ */
58
+ const CERT = 'cert';
59
+
60
+ /**
61
+ * cookies: (bool|GuzzleHttp\Cookie\CookieJarInterface, default=false)
62
+ * Specifies whether or not cookies are used in a request or what cookie
63
+ * jar to use or what cookies to send. This option only works if your
64
+ * handler has the `cookie` middleware. Valid values are `false` and
65
+ * an instance of {@see GuzzleHttp\Cookie\CookieJarInterface}.
66
+ */
67
+ const COOKIES = 'cookies';
68
+
69
+ /**
70
+ * connect_timeout: (float, default=0) Float describing the number of
71
+ * seconds to wait while trying to connect to a server. Use 0 to wait
72
+ * indefinitely (the default behavior).
73
+ */
74
+ const CONNECT_TIMEOUT = 'connect_timeout';
75
+
76
+ /**
77
+ * debug: (bool|resource) Set to true or set to a PHP stream returned by
78
+ * fopen() enable debug output with the HTTP handler used to send a
79
+ * request.
80
+ */
81
+ const DEBUG = 'debug';
82
+
83
+ /**
84
+ * decode_content: (bool, default=true) Specify whether or not
85
+ * Content-Encoding responses (gzip, deflate, etc.) are automatically
86
+ * decoded.
87
+ */
88
+ const DECODE_CONTENT = 'decode_content';
89
+
90
+ /**
91
+ * delay: (int) The amount of time to delay before sending in milliseconds.
92
+ */
93
+ const DELAY = 'delay';
94
+
95
+ /**
96
+ * expect: (bool|integer) Controls the behavior of the
97
+ * "Expect: 100-Continue" header.
98
+ *
99
+ * Set to `true` to enable the "Expect: 100-Continue" header for all
100
+ * requests that sends a body. Set to `false` to disable the
101
+ * "Expect: 100-Continue" header for all requests. Set to a number so that
102
+ * the size of the payload must be greater than the number in order to send
103
+ * the Expect header. Setting to a number will send the Expect header for
104
+ * all requests in which the size of the payload cannot be determined or
105
+ * where the body is not rewindable.
106
+ *
107
+ * By default, Guzzle will add the "Expect: 100-Continue" header when the
108
+ * size of the body of a request is greater than 1 MB and a request is
109
+ * using HTTP/1.1.
110
+ */
111
+ const EXPECT = 'expect';
112
+
113
+ /**
114
+ * form_params: (array) Associative array of form field names to values
115
+ * where each value is a string or array of strings. Sets the Content-Type
116
+ * header to application/x-www-form-urlencoded when no Content-Type header
117
+ * is already present.
118
+ */
119
+ const FORM_PARAMS = 'form_params';
120
+
121
+ /**
122
+ * headers: (array) Associative array of HTTP headers. Each value MUST be
123
+ * a string or array of strings.
124
+ */
125
+ const HEADERS = 'headers';
126
+
127
+ /**
128
+ * http_errors: (bool, default=true) Set to false to disable exceptions
129
+ * when a non- successful HTTP response is received. By default,
130
+ * exceptions will be thrown for 4xx and 5xx responses. This option only
131
+ * works if your handler has the `httpErrors` middleware.
132
+ */
133
+ const HTTP_ERRORS = 'http_errors';
134
+
135
+ /**
136
+ * json: (mixed) Adds JSON data to a request. The provided value is JSON
137
+ * encoded and a Content-Type header of application/json will be added to
138
+ * the request if no Content-Type header is already present.
139
+ */
140
+ const JSON = 'json';
141
+
142
+ /**
143
+ * multipart: (array) Array of associative arrays, each containing a
144
+ * required "name" key mapping to the form field, name, a required
145
+ * "contents" key mapping to a StreamInterface|resource|string, an
146
+ * optional "headers" associative array of custom headers, and an
147
+ * optional "filename" key mapping to a string to send as the filename in
148
+ * the part. If no "filename" key is present, then no "filename" attribute
149
+ * will be added to the part.
150
+ */
151
+ const MULTIPART = 'multipart';
152
+
153
+ /**
154
+ * on_headers: (callable) A callable that is invoked when the HTTP headers
155
+ * of the response have been received but the body has not yet begun to
156
+ * download.
157
+ */
158
+ const ON_HEADERS = 'on_headers';
159
+
160
+ /**
161
+ * on_stats: (callable) allows you to get access to transfer statistics of
162
+ * a request and access the lower level transfer details of the handler
163
+ * associated with your client. ``on_stats`` is a callable that is invoked
164
+ * when a handler has finished sending a request. The callback is invoked
165
+ * with transfer statistics about the request, the response received, or
166
+ * the error encountered. Included in the data is the total amount of time
167
+ * taken to send the request.
168
+ */
169
+ const ON_STATS = 'on_stats';
170
+
171
+ /**
172
+ * progress: (callable) Defines a function to invoke when transfer
173
+ * progress is made. The function accepts the following positional
174
+ * arguments: the total number of bytes expected to be downloaded, the
175
+ * number of bytes downloaded so far, the number of bytes expected to be
176
+ * uploaded, the number of bytes uploaded so far.
177
+ */
178
+ const PROGRESS = 'progress';
179
+
180
+ /**
181
+ * proxy: (string|array) Pass a string to specify an HTTP proxy, or an
182
+ * array to specify different proxies for different protocols (where the
183
+ * key is the protocol and the value is a proxy string).
184
+ */
185
+ const PROXY = 'proxy';
186
+
187
+ /**
188
+ * query: (array|string) Associative array of query string values to add
189
+ * to the request. This option uses PHP's http_build_query() to create
190
+ * the string representation. Pass a string value if you need more
191
+ * control than what this method provides
192
+ */
193
+ const QUERY = 'query';
194
+
195
+ /**
196
+ * sink: (resource|string|StreamInterface) Where the data of the
197
+ * response is written to. Defaults to a PHP temp stream. Providing a
198
+ * string will write data to a file by the given name.
199
+ */
200
+ const SINK = 'sink';
201
+
202
+ /**
203
+ * synchronous: (bool) Set to true to inform HTTP handlers that you intend
204
+ * on waiting on the response. This can be useful for optimizations. Note
205
+ * that a promise is still returned if you are using one of the async
206
+ * client methods.
207
+ */
208
+ const SYNCHRONOUS = 'synchronous';
209
+
210
+ /**
211
+ * ssl_key: (array|string) Specify the path to a file containing a private
212
+ * SSL key in PEM format. If a password is required, then set to an array
213
+ * containing the path to the SSL key in the first array element followed
214
+ * by the password required for the certificate in the second element.
215
+ */
216
+ const SSL_KEY = 'ssl_key';
217
+
218
+ /**
219
+ * stream: Set to true to attempt to stream a response rather than
220
+ * download it all up-front.
221
+ */
222
+ const STREAM = 'stream';
223
+
224
+ /**
225
+ * verify: (bool|string, default=true) Describes the SSL certificate
226
+ * verification behavior of a request. Set to true to enable SSL
227
+ * certificate verification using the system CA bundle when available
228
+ * (the default). Set to false to disable certificate verification (this
229
+ * is insecure!). Set to a string to provide the path to a CA bundle on
230
+ * disk to enable verification using a custom certificate.
231
+ */
232
+ const VERIFY = 'verify';
233
+
234
+ /**
235
+ * timeout: (float, default=0) Float describing the timeout of the
236
+ * request in seconds. Use 0 to wait indefinitely (the default behavior).
237
+ */
238
+ const TIMEOUT = 'timeout';
239
+
240
+ /**
241
+ * read_timeout: (float, default=default_socket_timeout ini setting) Float describing
242
+ * the body read timeout, for stream requests.
243
+ */
244
+ const READ_TIMEOUT = 'read_timeout';
245
+
246
+ /**
247
+ * version: (float) Specifies the HTTP protocol version to attempt to use.
248
+ */
249
+ const VERSION = 'version';
250
+
251
+ /**
252
+ * force_ip_resolve: (bool) Force client to use only ipv4 or ipv6 protocol
253
+ */
254
+ const FORCE_IP_RESOLVE = 'force_ip_resolve';
255
+ }
vendor/guzzlehttp/guzzle/src/RetryMiddleware.php ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Promise\PromiseInterface;
5
+ use GuzzleHttp\Promise\RejectedPromise;
6
+ use GuzzleHttp\Psr7;
7
+ use Psr\Http\Message\RequestInterface;
8
+ use Psr\Http\Message\ResponseInterface;
9
+
10
+ /**
11
+ * Middleware that retries requests based on the boolean result of
12
+ * invoking the provided "decider" function.
13
+ */
14
+ class RetryMiddleware
15
+ {
16
+ /** @var callable */
17
+ private $nextHandler;
18
+
19
+ /** @var callable */
20
+ private $decider;
21
+
22
+ /**
23
+ * @param callable $decider Function that accepts the number of retries,
24
+ * a request, [response], and [exception] and
25
+ * returns true if the request is to be
26
+ * retried.
27
+ * @param callable $nextHandler Next handler to invoke.
28
+ * @param callable $delay Function that accepts the number of retries
29
+ * and [response] and returns the number of
30
+ * milliseconds to delay.
31
+ */
32
+ public function __construct(
33
+ callable $decider,
34
+ callable $nextHandler,
35
+ callable $delay = null
36
+ ) {
37
+ $this->decider = $decider;
38
+ $this->nextHandler = $nextHandler;
39
+ $this->delay = $delay ?: __CLASS__ . '::exponentialDelay';
40
+ }
41
+
42
+ /**
43
+ * Default exponential backoff delay function.
44
+ *
45
+ * @param $retries
46
+ *
47
+ * @return int
48
+ */
49
+ public static function exponentialDelay($retries)
50
+ {
51
+ return (int) pow(2, $retries - 1);
52
+ }
53
+
54
+ /**
55
+ * @param RequestInterface $request
56
+ * @param array $options
57
+ *
58
+ * @return PromiseInterface
59
+ */
60
+ public function __invoke(RequestInterface $request, array $options)
61
+ {
62
+ if (!isset($options['retries'])) {
63
+ $options['retries'] = 0;
64
+ }
65
+
66
+ $fn = $this->nextHandler;
67
+ return $fn($request, $options)
68
+ ->then(
69
+ $this->onFulfilled($request, $options),
70
+ $this->onRejected($request, $options)
71
+ );
72
+ }
73
+
74
+ private function onFulfilled(RequestInterface $req, array $options)
75
+ {
76
+ return function ($value) use ($req, $options) {
77
+ if (!call_user_func(
78
+ $this->decider,
79
+ $options['retries'],
80
+ $req,
81
+ $value,
82
+ null
83
+ )) {
84
+ return $value;
85
+ }
86
+ return $this->doRetry($req, $options, $value);
87
+ };
88
+ }
89
+
90
+ private function onRejected(RequestInterface $req, array $options)
91
+ {
92
+ return function ($reason) use ($req, $options) {
93
+ if (!call_user_func(
94
+ $this->decider,
95
+ $options['retries'],
96
+ $req,
97
+ null,
98
+ $reason
99
+ )) {
100
+ return \GuzzleHttp\Promise\rejection_for($reason);
101
+ }
102
+ return $this->doRetry($req, $options);
103
+ };
104
+ }
105
+
106
+ private function doRetry(RequestInterface $request, array $options, ResponseInterface $response = null)
107
+ {
108
+ $options['delay'] = call_user_func($this->delay, ++$options['retries'], $response);
109
+
110
+ return $this($request, $options);
111
+ }
112
+ }
vendor/guzzlehttp/guzzle/src/TransferStats.php ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use Psr\Http\Message\RequestInterface;
5
+ use Psr\Http\Message\ResponseInterface;
6
+ use Psr\Http\Message\UriInterface;
7
+
8
+ /**
9
+ * Represents data at the point after it was transferred either successfully
10
+ * or after a network error.
11
+ */
12
+ final class TransferStats
13
+ {
14
+ private $request;
15
+ private $response;
16
+ private $transferTime;
17
+ private $handlerStats;
18
+ private $handlerErrorData;
19
+
20
+ /**
21
+ * @param RequestInterface $request Request that was sent.
22
+ * @param ResponseInterface $response Response received (if any)
23
+ * @param null $transferTime Total handler transfer time.
24
+ * @param mixed $handlerErrorData Handler error data.
25
+ * @param array $handlerStats Handler specific stats.
26
+ */
27
+ public function __construct(
28
+ RequestInterface $request,
29
+ ResponseInterface $response = null,
30
+ $transferTime = null,
31
+ $handlerErrorData = null,
32
+ $handlerStats = []
33
+ ) {
34
+ $this->request = $request;
35
+ $this->response = $response;
36
+ $this->transferTime = $transferTime;
37
+ $this->handlerErrorData = $handlerErrorData;
38
+ $this->handlerStats = $handlerStats;
39
+ }
40
+
41
+ /**
42
+ * @return RequestInterface
43
+ */
44
+ public function getRequest()
45
+ {
46
+ return $this->request;
47
+ }
48
+
49
+ /**
50
+ * Returns the response that was received (if any).
51
+ *
52
+ * @return ResponseInterface|null
53
+ */
54
+ public function getResponse()
55
+ {
56
+ return $this->response;
57
+ }
58
+
59
+ /**
60
+ * Returns true if a response was received.
61
+ *
62
+ * @return bool
63
+ */
64
+ public function hasResponse()
65
+ {
66
+ return $this->response !== null;
67
+ }
68
+
69
+ /**
70
+ * Gets handler specific error data.
71
+ *
72
+ * This might be an exception, a integer representing an error code, or
73
+ * anything else. Relying on this value assumes that you know what handler
74
+ * you are using.
75
+ *
76
+ * @return mixed
77
+ */
78
+ public function getHandlerErrorData()
79
+ {
80
+ return $this->handlerErrorData;
81
+ }
82
+
83
+ /**
84
+ * Get the effective URI the request was sent to.
85
+ *
86
+ * @return UriInterface
87
+ */
88
+ public function getEffectiveUri()
89
+ {
90
+ return $this->request->getUri();
91
+ }
92
+
93
+ /**
94
+ * Get the estimated time the request was being transferred by the handler.
95
+ *
96
+ * @return float Time in seconds.
97
+ */
98
+ public function getTransferTime()
99
+ {
100
+ return $this->transferTime;
101
+ }
102
+
103
+ /**
104
+ * Gets an array of all of the handler specific transfer data.
105
+ *
106
+ * @return array
107
+ */
108
+ public function getHandlerStats()
109
+ {
110
+ return $this->handlerStats;
111
+ }
112
+
113
+ /**
114
+ * Get a specific handler statistic from the handler by name.
115
+ *
116
+ * @param string $stat Handler specific transfer stat to retrieve.
117
+ *
118
+ * @return mixed|null
119
+ */
120
+ public function getHandlerStat($stat)
121
+ {
122
+ return isset($this->handlerStats[$stat])
123
+ ? $this->handlerStats[$stat]
124
+ : null;
125
+ }
126
+ }
vendor/guzzlehttp/guzzle/src/UriTemplate.php ADDED
@@ -0,0 +1,237 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 = [
19
+ '' => ['prefix' => '', 'joiner' => ',', 'query' => false],
20
+ '+' => ['prefix' => '', 'joiner' => ',', 'query' => false],
21
+ '#' => ['prefix' => '#', 'joiner' => ',', 'query' => false],
22
+ '.' => ['prefix' => '.', 'joiner' => '.', 'query' => false],
23
+ '/' => ['prefix' => '/', 'joiner' => '/', 'query' => false],
24
+ ';' => ['prefix' => ';', 'joiner' => ';', 'query' => true],
25
+ '?' => ['prefix' => '?', 'joiner' => '&', 'query' => true],
26
+ '&' => ['prefix' => '&', 'joiner' => '&', 'query' => true]
27
+ ];
28
+
29
+ /** @var array Delimiters */
30
+ private static $delims = [':', '/', '?', '#', '[', ']', '@', '!', '$',
31
+ '&', '\'', '(', ')', '*', '+', ',', ';', '='];
32
+
33
+ /** @var array Percent encoded delimiters */
34
+ private static $delimsPct = ['%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 = [];
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 = [];
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 = ['+' => '%20', '%7e' => '~'];
102
+
103
+ $replacements = [];
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
+ if (!isset($this->variables[$value['value']])) {
111
+ continue;
112
+ }
113
+
114
+ $variable = $this->variables[$value['value']];
115
+ $actuallyUseQuery = $useQuery;
116
+ $expanded = '';
117
+
118
+ if (is_array($variable)) {
119
+ $isAssoc = $this->isAssoc($variable);
120
+ $kvp = [];
121
+ foreach ($variable as $key => $var) {
122
+ if ($isAssoc) {
123
+ $key = rawurlencode($key);
124
+ $isNestedArray = is_array($var);
125
+ } else {
126
+ $isNestedArray = false;
127
+ }
128
+
129
+ if (!$isNestedArray) {
130
+ $var = rawurlencode($var);
131
+ if ($parsed['operator'] === '+' ||
132
+ $parsed['operator'] === '#'
133
+ ) {
134
+ $var = $this->decodeReserved($var);
135
+ }
136
+ }
137
+
138
+ if ($value['modifier'] === '*') {
139
+ if ($isAssoc) {
140
+ if ($isNestedArray) {
141
+ // Nested arrays must allow for deeply nested
142
+ // structures.
143
+ $var = strtr(
144
+ http_build_query([$key => $var]),
145
+ $rfc1738to3986
146
+ );
147
+ } else {
148
+ $var = $key . '=' . $var;
149
+ }
150
+ } elseif ($key > 0 && $actuallyUseQuery) {
151
+ $var = $value['value'] . '=' . $var;
152
+ }
153
+ }
154
+
155
+ $kvp[$key] = $var;
156
+ }
157
+
158
+ if (empty($variable)) {
159
+ $actuallyUseQuery = false;
160
+ } elseif ($value['modifier'] === '*') {
161
+ $expanded = implode($joiner, $kvp);
162
+ if ($isAssoc) {
163
+ // Don't prepend the value name when using the explode
164
+ // modifier with an associative array.
165
+ $actuallyUseQuery = false;
166
+ }
167
+ } else {
168
+ if ($isAssoc) {
169
+ // When an associative array is encountered and the
170
+ // explode modifier is not set, then the result must be
171
+ // a comma separated list of keys followed by their
172
+ // respective values.
173
+ foreach ($kvp as $k => &$v) {
174
+ $v = $k . ',' . $v;
175
+ }
176
+ }
177
+ $expanded = implode(',', $kvp);
178
+ }
179
+ } else {
180
+ if ($value['modifier'] === ':') {
181
+ $variable = substr($variable, 0, $value['position']);
182
+ }
183
+ $expanded = rawurlencode($variable);
184
+ if ($parsed['operator'] === '+' || $parsed['operator'] === '#') {
185
+ $expanded = $this->decodeReserved($expanded);
186
+ }
187
+ }
188
+
189
+ if ($actuallyUseQuery) {
190
+ if (!$expanded && $joiner !== '&') {
191
+ $expanded = $value['value'];
192
+ } else {
193
+ $expanded = $value['value'] . '=' . $expanded;
194
+ }
195
+ }
196
+
197
+ $replacements[] = $expanded;
198
+ }
199
+
200
+ $ret = implode($joiner, $replacements);
201
+ if ($ret && $prefix) {
202
+ return $prefix . $ret;
203
+ }
204
+
205
+ return $ret;
206
+ }
207
+
208
+ /**
209
+ * Determines if an array is associative.
210
+ *
211
+ * This makes the assumption that input arrays are sequences or hashes.
212
+ * This assumption is a tradeoff for accuracy in favor of speed, but it
213
+ * should work in almost every case where input is supplied for a URI
214
+ * template.
215
+ *
216
+ * @param array $array Array to check
217
+ *
218
+ * @return bool
219
+ */
220
+ private function isAssoc(array $array)
221
+ {
222
+ return $array && array_keys($array)[0] !== 0;
223
+ }
224
+
225
+ /**
226
+ * Removes percent encoding on reserved characters (used with + and #
227
+ * modifiers).
228
+ *
229
+ * @param string $string String to fix
230
+ *
231
+ * @return string
232
+ */
233
+ private function decodeReserved($string)
234
+ {
235
+ return str_replace(self::$delimsPct, self::$delims, $string);
236
+ }
237
+ }
vendor/guzzlehttp/guzzle/src/functions.php ADDED
@@ -0,0 +1,333 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Handler\CurlHandler;
5
+ use GuzzleHttp\Handler\CurlMultiHandler;
6
+ use GuzzleHttp\Handler\Proxy;
7
+ use GuzzleHttp\Handler\StreamHandler;
8
+
9
+ /**
10
+ * Expands a URI template
11
+ *
12
+ * @param string $template URI template
13
+ * @param array $variables Template variables
14
+ *
15
+ * @return string
16
+ */
17
+ function uri_template($template, array $variables)
18
+ {
19
+ if (extension_loaded('uri_template')) {
20
+ // @codeCoverageIgnoreStart
21
+ return \uri_template($template, $variables);
22
+ // @codeCoverageIgnoreEnd
23
+ }
24
+
25
+ static $uriTemplate;
26
+ if (!$uriTemplate) {
27
+ $uriTemplate = new UriTemplate();
28
+ }
29
+
30
+ return $uriTemplate->expand($template, $variables);
31
+ }
32
+
33
+ /**
34
+ * Debug function used to describe the provided value type and class.
35
+ *
36
+ * @param mixed $input
37
+ *
38
+ * @return string Returns a string containing the type of the variable and
39
+ * if a class is provided, the class name.
40
+ */
41
+ function describe_type($input)
42
+ {
43
+ switch (gettype($input)) {
44
+ case 'object':
45
+ return 'object(' . get_class($input) . ')';
46
+ case 'array':
47
+ return 'array(' . count($input) . ')';
48
+ default:
49
+ ob_start();
50
+ var_dump($input);
51
+ // normalize float vs double
52
+ return str_replace('double(', 'float(', rtrim(ob_get_clean()));
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Parses an array of header lines into an associative array of headers.
58
+ *
59
+ * @param array $lines Header lines array of strings in the following
60
+ * format: "Name: Value"
61
+ * @return array
62
+ */
63
+ function headers_from_lines($lines)
64
+ {
65
+ $headers = [];
66
+
67
+ foreach ($lines as $line) {
68
+ $parts = explode(':', $line, 2);
69
+ $headers[trim($parts[0])][] = isset($parts[1])
70
+ ? trim($parts[1])
71
+ : null;
72
+ }
73
+
74
+ return $headers;
75
+ }
76
+
77
+ /**
78
+ * Returns a debug stream based on the provided variable.
79
+ *
80
+ * @param mixed $value Optional value
81
+ *
82
+ * @return resource
83
+ */
84
+ function debug_resource($value = null)
85
+ {
86
+ if (is_resource($value)) {
87
+ return $value;
88
+ } elseif (defined('STDOUT')) {
89
+ return STDOUT;
90
+ }
91
+
92
+ return fopen('php://output', 'w');
93
+ }
94
+
95
+ /**
96
+ * Chooses and creates a default handler to use based on the environment.
97
+ *
98
+ * The returned handler is not wrapped by any default middlewares.
99
+ *
100
+ * @throws \RuntimeException if no viable Handler is available.
101
+ * @return callable Returns the best handler for the given system.
102
+ */
103
+ function choose_handler()
104
+ {
105
+ $handler = null;
106
+ if (function_exists('curl_multi_exec') && function_exists('curl_exec')) {
107
+ $handler = Proxy::wrapSync(new CurlMultiHandler(), new CurlHandler());
108
+ } elseif (function_exists('curl_exec')) {
109
+ $handler = new CurlHandler();
110
+ } elseif (function_exists('curl_multi_exec')) {
111
+ $handler = new CurlMultiHandler();
112
+ }
113
+
114
+ if (ini_get('allow_url_fopen')) {
115
+ $handler = $handler
116
+ ? Proxy::wrapStreaming($handler, new StreamHandler())
117
+ : new StreamHandler();
118
+ } elseif (!$handler) {
119
+ throw new \RuntimeException('GuzzleHttp requires cURL, the '
120
+ . 'allow_url_fopen ini setting, or a custom HTTP handler.');
121
+ }
122
+
123
+ return $handler;
124
+ }
125
+
126
+ /**
127
+ * Get the default User-Agent string to use with Guzzle
128
+ *
129
+ * @return string
130
+ */
131
+ function default_user_agent()
132
+ {
133
+ static $defaultAgent = '';
134
+
135
+ if (!$defaultAgent) {
136
+ $defaultAgent = 'GuzzleHttp/' . Client::VERSION;
137
+ if (extension_loaded('curl') && function_exists('curl_version')) {
138
+ $defaultAgent .= ' curl/' . \curl_version()['version'];
139
+ }
140
+ $defaultAgent .= ' PHP/' . PHP_VERSION;
141
+ }
142
+
143
+ return $defaultAgent;
144
+ }
145
+
146
+ /**
147
+ * Returns the default cacert bundle for the current system.
148
+ *
149
+ * First, the openssl.cafile and curl.cainfo php.ini settings are checked.
150
+ * If those settings are not configured, then the common locations for
151
+ * bundles found on Red Hat, CentOS, Fedora, Ubuntu, Debian, FreeBSD, OS X
152
+ * and Windows are checked. If any of these file locations are found on
153
+ * disk, they will be utilized.
154
+ *
155
+ * Note: the result of this function is cached for subsequent calls.
156
+ *
157
+ * @return string
158
+ * @throws \RuntimeException if no bundle can be found.
159
+ */
160
+ function default_ca_bundle()
161
+ {
162
+ static $cached = null;
163
+ static $cafiles = [
164
+ // Red Hat, CentOS, Fedora (provided by the ca-certificates package)
165
+ '/etc/pki/tls/certs/ca-bundle.crt',
166
+ // Ubuntu, Debian (provided by the ca-certificates package)
167
+ '/etc/ssl/certs/ca-certificates.crt',
168
+ // FreeBSD (provided by the ca_root_nss package)
169
+ '/usr/local/share/certs/ca-root-nss.crt',
170
+ // SLES 12 (provided by the ca-certificates package)
171
+ '/var/lib/ca-certificates/ca-bundle.pem',
172
+ // OS X provided by homebrew (using the default path)
173
+ '/usr/local/etc/openssl/cert.pem',
174
+ // Google app engine
175
+ '/etc/ca-certificates.crt',
176
+ // Windows?
177
+ 'C:\\windows\\system32\\curl-ca-bundle.crt',
178
+ 'C:\\windows\\curl-ca-bundle.crt',
179
+ ];
180
+
181
+ if ($cached) {
182
+ return $cached;
183
+ }
184
+
185
+ if ($ca = ini_get('openssl.cafile')) {
186
+ return $cached = $ca;
187
+ }
188
+
189
+ if ($ca = ini_get('curl.cainfo')) {
190
+ return $cached = $ca;
191
+ }
192
+
193
+ foreach ($cafiles as $filename) {
194
+ if (file_exists($filename)) {
195
+ return $cached = $filename;
196
+ }
197
+ }
198
+
199
+ throw new \RuntimeException(<<< EOT
200
+ No system CA bundle could be found in any of the the common system locations.
201
+ PHP versions earlier than 5.6 are not properly configured to use the system's
202
+ CA bundle by default. In order to verify peer certificates, you will need to
203
+ supply the path on disk to a certificate bundle to the 'verify' request
204
+ option: http://docs.guzzlephp.org/en/latest/clients.html#verify. If you do not
205
+ need a specific certificate bundle, then Mozilla provides a commonly used CA
206
+ bundle which can be downloaded here (provided by the maintainer of cURL):
207
+ https://raw.githubusercontent.com/bagder/ca-bundle/master/ca-bundle.crt. Once
208
+ you have a CA bundle available on disk, you can set the 'openssl.cafile' PHP
209
+ ini setting to point to the path to the file, allowing you to omit the 'verify'
210
+ request option. See http://curl.haxx.se/docs/sslcerts.html for more
211
+ information.
212
+ EOT
213
+ );
214
+ }
215
+
216
+ /**
217
+ * Creates an associative array of lowercase header names to the actual
218
+ * header casing.
219
+ *
220
+ * @param array $headers
221
+ *
222
+ * @return array
223
+ */
224
+ function normalize_header_keys(array $headers)
225
+ {
226
+ $result = [];
227
+ foreach (array_keys($headers) as $key) {
228
+ $result[strtolower($key)] = $key;
229
+ }
230
+
231
+ return $result;
232
+ }
233
+
234
+ /**
235
+ * Returns true if the provided host matches any of the no proxy areas.
236
+ *
237
+ * This method will strip a port from the host if it is present. Each pattern
238
+ * can be matched with an exact match (e.g., "foo.com" == "foo.com") or a
239
+ * partial match: (e.g., "foo.com" == "baz.foo.com" and ".foo.com" ==
240
+ * "baz.foo.com", but ".foo.com" != "foo.com").
241
+ *
242
+ * Areas are matched in the following cases:
243
+ * 1. "*" (without quotes) always matches any hosts.
244
+ * 2. An exact match.
245
+ * 3. The area starts with "." and the area is the last part of the host. e.g.
246
+ * '.mit.edu' will match any host that ends with '.mit.edu'.
247
+ *
248
+ * @param string $host Host to check against the patterns.
249
+ * @param array $noProxyArray An array of host patterns.
250
+ *
251
+ * @return bool
252
+ */
253
+ function is_host_in_noproxy($host, array $noProxyArray)
254
+ {
255
+ if (strlen($host) === 0) {
256
+ throw new \InvalidArgumentException('Empty host provided');
257
+ }
258
+
259
+ // Strip port if present.
260
+ if (strpos($host, ':')) {
261
+ $host = explode($host, ':', 2)[0];
262
+ }
263
+
264
+ foreach ($noProxyArray as $area) {
265
+ // Always match on wildcards.
266
+ if ($area === '*') {
267
+ return true;
268
+ } elseif (empty($area)) {
269
+ // Don't match on empty values.
270
+ continue;
271
+ } elseif ($area === $host) {
272
+ // Exact matches.
273
+ return true;
274
+ } else {
275
+ // Special match if the area when prefixed with ".". Remove any
276
+ // existing leading "." and add a new leading ".".
277
+ $area = '.' . ltrim($area, '.');
278
+ if (substr($host, -(strlen($area))) === $area) {
279
+ return true;
280
+ }
281
+ }
282
+ }
283
+
284
+ return false;
285
+ }
286
+
287
+ /**
288
+ * Wrapper for json_decode that throws when an error occurs.
289
+ *
290
+ * @param string $json JSON data to parse
291
+ * @param bool $assoc When true, returned objects will be converted
292
+ * into associative arrays.
293
+ * @param int $depth User specified recursion depth.
294
+ * @param int $options Bitmask of JSON decode options.
295
+ *
296
+ * @return mixed
297
+ * @throws \InvalidArgumentException if the JSON cannot be decoded.
298
+ * @link http://www.php.net/manual/en/function.json-decode.php
299
+ */
300
+ function json_decode($json, $assoc = false, $depth = 512, $options = 0)
301
+ {
302
+ $data = \json_decode($json, $assoc, $depth, $options);
303
+ if (JSON_ERROR_NONE !== json_last_error()) {
304
+ throw new \InvalidArgumentException(
305
+ 'json_decode error: ' . json_last_error_msg()
306
+ );
307
+ }
308
+
309
+ return $data;
310
+ }
311
+
312
+ /**
313
+ * Wrapper for JSON encoding that throws when an error occurs.
314
+ *
315
+ * @param mixed $value The value being encoded
316
+ * @param int $options JSON encode option bitmask
317
+ * @param int $depth Set the maximum depth. Must be greater than zero.
318
+ *
319
+ * @return string
320
+ * @throws \InvalidArgumentException if the JSON cannot be encoded.
321
+ * @link http://www.php.net/manual/en/function.json-encode.php
322
+ */
323
+ function json_encode($value, $options = 0, $depth = 512)
324
+ {
325
+ $json = \json_encode($value, $options, $depth);
326
+ if (JSON_ERROR_NONE !== json_last_error()) {
327
+ throw new \InvalidArgumentException(
328
+ 'json_encode error: ' . json_last_error_msg()
329
+ );
330
+ }
331
+
332
+ return $json;
333
+ }
vendor/guzzlehttp/guzzle/src/functions_include.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // Don't redefine the functions if included multiple times.
4
+ if (!function_exists('GuzzleHttp\uri_template')) {
5
+ require __DIR__ . '/functions.php';
6
+ }
vendor/guzzlehttp/promises/CHANGELOG.md ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CHANGELOG
2
+
3
+
4
+ ## 1.3.1 - 2016-12-20
5
+
6
+ ### Fixed
7
+
8
+ - `wait()` foreign promise compatibility
9
+
10
+
11
+ ## 1.3.0 - 2016-11-18
12
+
13
+ ### Added
14
+
15
+ - Adds support for custom task queues.
16
+
17
+ ### Fixed
18
+
19
+ - Fixed coroutine promise memory leak.
20
+
21
+
22
+ ## 1.2.0 - 2016-05-18
23
+
24
+ ### Changed
25
+
26
+ - Update to now catch `\Throwable` on PHP 7+
27
+
28
+
29
+ ## 1.1.0 - 2016-03-07
30
+
31
+ ### Changed
32
+
33
+ - Update EachPromise to prevent recurring on a iterator when advancing, as this
34
+ could trigger fatal generator errors.
35
+ - Update Promise to allow recursive waiting without unwrapping exceptions.
36
+
37
+
38
+ ## 1.0.3 - 2015-10-15
39
+
40
+ ### Changed
41
+
42
+ - Update EachPromise to immediately resolve when the underlying promise iterator
43
+ is empty. Previously, such a promise would throw an exception when its `wait`
44
+ function was called.
45
+
46
+
47
+ ## 1.0.2 - 2015-05-15
48
+
49
+ ### Changed
50
+
51
+ - Conditionally require functions.php.
52
+
53
+
54
+ ## 1.0.1 - 2015-06-24
55
+
56
+ ### Changed
57
+
58
+ - Updating EachPromise to call next on the underlying promise iterator as late
59
+ as possible to ensure that generators that generate new requests based on
60
+ callbacks are not iterated until after callbacks are invoked.
61
+
62
+
63
+ ## 1.0.0 - 2015-05-12
64
+
65
+ - Initial release
vendor/guzzlehttp/promises/LICENSE ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright (c) 2015-2016 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.
vendor/guzzlehttp/promises/Makefile ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ all: clean test
2
+
3
+ test:
4
+ vendor/bin/phpunit
5
+
6
+ coverage:
7
+ vendor/bin/phpunit --coverage-html=artifacts/coverage
8
+
9
+ view-coverage:
10
+ open artifacts/coverage/index.html
11
+
12
+ clean:
13
+ rm -rf artifacts/*
vendor/guzzlehttp/promises/README.md ADDED
@@ -0,0 +1,504 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Guzzle Promises
2
+
3
+ [Promises/A+](https://promisesaplus.com/) implementation that handles promise
4
+ chaining and resolution iteratively, allowing for "infinite" promise chaining
5
+ while keeping the stack size constant. Read [this blog post](https://blog.domenic.me/youre-missing-the-point-of-promises/)
6
+ for a general introduction to promises.
7
+
8
+ - [Features](#features)
9
+ - [Quick start](#quick-start)
10
+ - [Synchronous wait](#synchronous-wait)
11
+ - [Cancellation](#cancellation)
12
+ - [API](#api)
13
+ - [Promise](#promise)
14
+ - [FulfilledPromise](#fulfilledpromise)
15
+ - [RejectedPromise](#rejectedpromise)
16
+ - [Promise interop](#promise-interop)
17
+ - [Implementation notes](#implementation-notes)
18
+
19
+
20
+ # Features
21
+
22
+ - [Promises/A+](https://promisesaplus.com/) implementation.
23
+ - Promise resolution and chaining is handled iteratively, allowing for
24
+ "infinite" promise chaining.
25
+ - Promises have a synchronous `wait` method.
26
+ - Promises can be cancelled.
27
+ - Works with any object that has a `then` function.
28
+ - C# style async/await coroutine promises using
29
+ `GuzzleHttp\Promise\coroutine()`.
30
+
31
+
32
+ # Quick start
33
+
34
+ A *promise* represents the eventual result of an asynchronous operation. The
35
+ primary way of interacting with a promise is through its `then` method, which
36
+ registers callbacks to receive either a promise's eventual value or the reason
37
+ why the promise cannot be fulfilled.
38
+
39
+
40
+ ## Callbacks
41
+
42
+ Callbacks are registered with the `then` method by providing an optional
43
+ `$onFulfilled` followed by an optional `$onRejected` function.
44
+
45
+
46
+ ```php
47
+ use GuzzleHttp\Promise\Promise;
48
+
49
+ $promise = new Promise();
50
+ $promise->then(
51
+ // $onFulfilled
52
+ function ($value) {
53
+ echo 'The promise was fulfilled.';
54
+ },
55
+ // $onRejected
56
+ function ($reason) {
57
+ echo 'The promise was rejected.';
58
+ }
59
+ );
60
+ ```
61
+
62
+ *Resolving* a promise means that you either fulfill a promise with a *value* or
63
+ reject a promise with a *reason*. Resolving a promises triggers callbacks
64
+ registered with the promises's `then` method. These callbacks are triggered
65
+ only once and in the order in which they were added.
66
+
67
+
68
+ ## Resolving a promise
69
+
70
+ Promises are fulfilled using the `resolve($value)` method. Resolving a promise
71
+ with any value other than a `GuzzleHttp\Promise\RejectedPromise` will trigger
72
+ all of the onFulfilled callbacks (resolving a promise with a rejected promise
73
+ will reject the promise and trigger the `$onRejected` callbacks).
74
+
75
+ ```php
76
+ use GuzzleHttp\Promise\Promise;
77
+
78
+ $promise = new Promise();
79
+ $promise
80
+ ->then(function ($value) {
81
+ // Return a value and don't break the chain
82
+ return "Hello, " . $value;
83
+ })
84
+ // This then is executed after the first then and receives the value
85
+ // returned from the first then.
86
+ ->then(function ($value) {
87
+ echo $value;
88
+ });
89
+
90
+ // Resolving the promise triggers the $onFulfilled callbacks and outputs
91
+ // "Hello, reader".
92
+ $promise->resolve('reader.');
93
+ ```
94
+
95
+
96
+ ## Promise forwarding
97
+
98
+ Promises can be chained one after the other. Each then in the chain is a new
99
+ promise. The return value of a promise is what's forwarded to the next
100
+ promise in the chain. Returning a promise in a `then` callback will cause the
101
+ subsequent promises in the chain to only be fulfilled when the returned promise
102
+ has been fulfilled. The next promise in the chain will be invoked with the
103
+ resolved value of the promise.
104
+
105
+ ```php
106
+ use GuzzleHttp\Promise\Promise;
107
+
108
+ $promise = new Promise();
109
+ $nextPromise = new Promise();
110
+
111
+ $promise
112
+ ->then(function ($value) use ($nextPromise) {
113
+ echo $value;
114
+ return $nextPromise;
115
+ })
116
+ ->then(function ($value) {
117
+ echo $value;
118
+ });
119
+
120
+ // Triggers the first callback and outputs "A"
121
+ $promise->resolve('A');
122
+ // Triggers the second callback and outputs "B"
123
+ $nextPromise->resolve('B');
124
+ ```
125
+
126
+ ## Promise rejection
127
+
128
+ When a promise is rejected, the `$onRejected` callbacks are invoked with the
129
+ rejection reason.
130
+
131
+ ```php
132
+ use GuzzleHttp\Promise\Promise;
133
+
134
+ $promise = new Promise();
135
+ $promise->then(null, function ($reason) {
136
+ echo $reason;
137
+ });
138
+
139
+ $promise->reject('Error!');
140
+ // Outputs "Error!"
141
+ ```
142
+
143
+ ## Rejection forwarding
144
+
145
+ If an exception is thrown in an `$onRejected` callback, subsequent
146
+ `$onRejected` callbacks are invoked with the thrown exception as the reason.
147
+
148
+ ```php
149
+ use GuzzleHttp\Promise\Promise;
150
+
151
+ $promise = new Promise();
152
+ $promise->then(null, function ($reason) {
153
+ throw new \Exception($reason);
154
+ })->then(null, function ($reason) {
155
+ assert($reason->getMessage() === 'Error!');
156
+ });
157
+
158
+ $promise->reject('Error!');
159
+ ```
160
+
161
+ You can also forward a rejection down the promise chain by returning a
162
+ `GuzzleHttp\Promise\RejectedPromise` in either an `$onFulfilled` or
163
+ `$onRejected` callback.
164
+
165
+ ```php
166
+ use GuzzleHttp\Promise\Promise;
167
+ use GuzzleHttp\Promise\RejectedPromise;
168
+
169
+ $promise = new Promise();
170
+ $promise->then(null, function ($reason) {
171
+ return new RejectedPromise($reason);
172
+ })->then(null, function ($reason) {
173
+ assert($reason === 'Error!');
174
+ });
175
+
176
+ $promise->reject('Error!');
177
+ ```
178
+
179
+ If an exception is not thrown in a `$onRejected` callback and the callback
180
+ does not return a rejected promise, downstream `$onFulfilled` callbacks are
181
+ invoked using the value returned from the `$onRejected` callback.
182
+
183
+ ```php
184
+ use GuzzleHttp\Promise\Promise;
185
+ use GuzzleHttp\Promise\RejectedPromise;
186
+
187
+ $promise = new Promise();
188
+ $promise
189
+ ->then(null, function ($reason) {
190
+ return "It's ok";
191
+ })
192
+ ->then(function ($value) {
193
+ assert($value === "It's ok");
194
+ });
195
+
196
+ $promise->reject('Error!');
197
+ ```
198
+
199
+ # Synchronous wait
200
+
201
+ You can synchronously force promises to complete using a promise's `wait`
202
+ method. When creating a promise, you can provide a wait function that is used
203
+ to synchronously force a promise to complete. When a wait function is invoked
204
+ it is expected to deliver a value to the promise or reject the promise. If the
205
+ wait function does not deliver a value, then an exception is thrown. The wait
206
+ function provided to a promise constructor is invoked when the `wait` function
207
+ of the promise is called.
208
+
209
+ ```php
210
+ $promise = new Promise(function () use (&$promise) {
211
+ $promise->resolve('foo');
212
+ });
213
+
214
+ // Calling wait will return the value of the promise.
215
+ echo $promise->wait(); // outputs "foo"
216
+ ```
217
+
218
+ If an exception is encountered while invoking the wait function of a promise,
219
+ the promise is rejected with the exception and the exception is thrown.
220
+
221
+ ```php
222
+ $promise = new Promise(function () use (&$promise) {
223
+ throw new \Exception('foo');
224
+ });
225
+
226
+ $promise->wait(); // throws the exception.
227
+ ```
228
+
229
+ Calling `wait` on a promise that has been fulfilled will not trigger the wait
230
+ function. It will simply return the previously resolved value.
231
+
232
+ ```php
233
+ $promise = new Promise(function () { die('this is not called!'); });
234
+ $promise->resolve('foo');
235
+ echo $promise->wait(); // outputs "foo"
236
+ ```
237
+
238
+ Calling `wait` on a promise that has been rejected will throw an exception. If
239
+ the rejection reason is an instance of `\Exception` the reason is thrown.
240
+ Otherwise, a `GuzzleHttp\Promise\RejectionException` is thrown and the reason
241
+ can be obtained by calling the `getReason` method of the exception.
242
+
243
+ ```php
244
+ $promise = new Promise();
245
+ $promise->reject('foo');
246
+ $promise->wait();
247
+ ```
248
+
249
+ > PHP Fatal error: Uncaught exception 'GuzzleHttp\Promise\RejectionException' with message 'The promise was rejected with value: foo'
250
+
251
+
252
+ ## Unwrapping a promise
253
+
254
+ When synchronously waiting on a promise, you are joining the state of the
255
+ promise into the current state of execution (i.e., return the value of the
256
+ promise if it was fulfilled or throw an exception if it was rejected). This is
257
+ called "unwrapping" the promise. Waiting on a promise will by default unwrap
258
+ the promise state.
259
+
260
+ You can force a promise to resolve and *not* unwrap the state of the promise
261
+ by passing `false` to the first argument of the `wait` function:
262
+
263
+ ```php
264
+ $promise = new Promise();
265
+ $promise->reject('foo');
266
+ // This will not throw an exception. It simply ensures the promise has
267
+ // been resolved.
268
+ $promise->wait(false);
269
+ ```
270
+
271
+ When unwrapping a promise, the resolved value of the promise will be waited
272
+ upon until the unwrapped value is not a promise. This means that if you resolve
273
+ promise A with a promise B and unwrap promise A, the value returned by the
274
+ wait function will be the value delivered to promise B.
275
+
276
+ **Note**: when you do not unwrap the promise, no value is returned.
277
+
278
+
279
+ # Cancellation
280
+
281
+ You can cancel a promise that has not yet been fulfilled using the `cancel()`
282
+ method of a promise. When creating a promise you can provide an optional
283
+ cancel function that when invoked cancels the action of computing a resolution
284
+ of the promise.
285
+
286
+
287
+ # API
288
+
289
+
290
+ ## Promise
291
+
292
+ When creating a promise object, you can provide an optional `$waitFn` and
293
+ `$cancelFn`. `$waitFn` is a function that is invoked with no arguments and is
294
+ expected to resolve the promise. `$cancelFn` is a function with no arguments
295
+ that is expected to cancel the computation of a promise. It is invoked when the
296
+ `cancel()` method of a promise is called.
297
+
298
+ ```php
299
+ use GuzzleHttp\Promise\Promise;
300
+
301
+ $promise = new Promise(
302
+ function () use (&$promise) {
303
+ $promise->resolve('waited');
304
+ },
305
+ function () {
306
+ // do something that will cancel the promise computation (e.g., close
307
+ // a socket, cancel a database query, etc...)
308
+ }
309
+ );
310
+
311
+ assert('waited' === $promise->wait());
312
+ ```
313
+
314
+ A promise has the following methods:
315
+
316
+ - `then(callable $onFulfilled, callable $onRejected) : PromiseInterface`
317
+
318
+ Appends fulfillment and rejection handlers to the promise, and returns a new promise resolving to the return value of the called handler.
319
+
320
+ - `otherwise(callable $onRejected) : PromiseInterface`
321
+
322
+ Appends a rejection handler callback to the promise, and returns a new promise resolving to the return value of the callback if it is called, or to its original fulfillment value if the promise is instead fulfilled.
323
+
324
+ - `wait($unwrap = true) : mixed`
325
+
326
+ Synchronously waits on the promise to complete.
327
+
328
+ `$unwrap` controls whether or not the value of the promise is returned for a
329
+ fulfilled promise or if an exception is thrown if the promise is rejected.
330
+ This is set to `true` by default.
331
+
332
+ - `cancel()`
333
+
334
+ Attempts to cancel the promise if possible. The promise being cancelled and
335
+ the parent most ancestor that has not yet been resolved will also be
336
+ cancelled. Any promises waiting on the cancelled promise to resolve will also
337
+ be cancelled.
338
+
339
+ - `getState() : string`
340
+
341
+ Returns the state of the promise. One of `pending`, `fulfilled`, or
342
+ `rejected`.
343
+
344
+ - `resolve($value)`
345
+
346
+ Fulfills the promise with the given `$value`.
347
+
348
+ - `reject($reason)`
349
+
350
+ Rejects the promise with the given `$reason`.
351
+
352
+
353
+ ## FulfilledPromise
354
+
355
+ A fulfilled promise can be created to represent a promise that has been
356
+ fulfilled.
357
+
358
+ ```php
359
+ use GuzzleHttp\Promise\FulfilledPromise;
360
+
361
+ $promise = new FulfilledPromise('value');
362
+
363
+ // Fulfilled callbacks are immediately invoked.
364
+ $promise->then(function ($value) {
365
+ echo $value;
366
+ });
367
+ ```
368
+
369
+
370
+ ## RejectedPromise
371
+
372
+ A rejected promise can be created to represent a promise that has been
373
+ rejected.
374
+
375
+ ```php
376
+ use GuzzleHttp\Promise\RejectedPromise;
377
+
378
+ $promise = new RejectedPromise('Error');
379
+
380
+ // Rejected callbacks are immediately invoked.
381
+ $promise->then(null, function ($reason) {
382
+ echo $reason;
383
+ });
384
+ ```
385
+
386
+
387
+ # Promise interop
388
+
389
+ This library works with foreign promises that have a `then` method. This means
390
+ you can use Guzzle promises with [React promises](https://github.com/reactphp/promise)
391
+ for example. When a foreign promise is returned inside of a then method
392
+ callback, promise resolution will occur recursively.
393
+
394
+ ```php
395
+ // Create a React promise
396
+ $deferred = new React\Promise\Deferred();
397
+ $reactPromise = $deferred->promise();
398
+
399
+ // Create a Guzzle promise that is fulfilled with a React promise.
400
+ $guzzlePromise = new \GuzzleHttp\Promise\Promise();
401
+ $guzzlePromise->then(function ($value) use ($reactPromise) {
402
+ // Do something something with the value...
403
+ // Return the React promise
404
+ return $reactPromise;
405
+ });
406
+ ```
407
+
408
+ Please note that wait and cancel chaining is no longer possible when forwarding
409
+ a foreign promise. You will need to wrap a third-party promise with a Guzzle
410
+ promise in order to utilize wait and cancel functions with foreign promises.
411
+
412
+
413
+ ## Event Loop Integration
414
+
415
+ In order to keep the stack size constant, Guzzle promises are resolved
416
+ asynchronously using a task queue. When waiting on promises synchronously, the
417
+ task queue will be automatically run to ensure that the blocking promise and
418
+ any forwarded promises are resolved. When using promises asynchronously in an
419
+ event loop, you will need to run the task queue on each tick of the loop. If
420
+ you do not run the task queue, then promises will not be resolved.
421
+
422
+ You can run the task queue using the `run()` method of the global task queue
423
+ instance.
424
+
425
+ ```php
426
+ // Get the global task queue
427
+ $queue = \GuzzleHttp\Promise\queue();
428
+ $queue->run();
429
+ ```
430
+
431
+ For example, you could use Guzzle promises with React using a periodic timer:
432
+
433
+ ```php
434
+ $loop = React\EventLoop\Factory::create();
435
+ $loop->addPeriodicTimer(0, [$queue, 'run']);
436
+ ```
437
+
438
+ *TODO*: Perhaps adding a `futureTick()` on each tick would be faster?
439
+
440
+
441
+ # Implementation notes
442
+
443
+
444
+ ## Promise resolution and chaining is handled iteratively
445
+
446
+ By shuffling pending handlers from one owner to another, promises are
447
+ resolved iteratively, allowing for "infinite" then chaining.
448
+
449
+ ```php
450
+ <?php
451
+ require 'vendor/autoload.php';
452
+
453
+ use GuzzleHttp\Promise\Promise;
454
+
455
+ $parent = new Promise();
456
+ $p = $parent;
457
+
458
+ for ($i = 0; $i < 1000; $i++) {
459
+ $p = $p->then(function ($v) {
460
+ // The stack size remains constant (a good thing)
461
+ echo xdebug_get_stack_depth() . ', ';
462
+ return $v + 1;
463
+ });
464
+ }
465
+
466
+ $parent->resolve(0);
467
+ var_dump($p->wait()); // int(1000)
468
+
469
+ ```
470
+
471
+ When a promise is fulfilled or rejected with a non-promise value, the promise
472
+ then takes ownership of the handlers of each child promise and delivers values
473
+ down the chain without using recursion.
474
+
475
+ When a promise is resolved with another promise, the original promise transfers
476
+ all of its pending handlers to the new promise. When the new promise is
477
+ eventually resolved, all of the pending handlers are delivered the forwarded
478
+ value.
479
+
480
+
481
+ ## A promise is the deferred.
482
+
483
+ Some promise libraries implement promises using a deferred object to represent
484
+ a computation and a promise object to represent the delivery of the result of
485
+ the computation. This is a nice separation of computation and delivery because
486
+ consumers of the promise cannot modify the value that will be eventually
487
+ delivered.
488
+
489
+ One side effect of being able to implement promise resolution and chaining
490
+ iteratively is that you need to be able for one promise to reach into the state
491
+ of another promise to shuffle around ownership of handlers. In order to achieve
492
+ this without making the handlers of a promise publicly mutable, a promise is
493
+ also the deferred value, allowing promises of the same parent class to reach
494
+ into and modify the private properties of promises of the same type. While this
495
+ does allow consumers of the value to modify the resolution or rejection of the
496
+ deferred, it is a small price to pay for keeping the stack size constant.
497
+
498
+ ```php
499
+ $promise = new Promise();
500
+ $promise->then(function ($value) { echo $value; });
501
+ // The promise is the deferred value, so you can deliver a value to it.
502
+ $promise->resolve('foo');
503
+ // prints "foo"
504
+ ```
vendor/guzzlehttp/promises/src/AggregateException.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Promise;
3
+
4
+ /**
5
+ * Exception thrown when too many errors occur in the some() or any() methods.
6
+ */
7
+ class AggregateException extends RejectionException
8
+ {
9
+ public function __construct($msg, array $reasons)
10
+ {
11
+ parent::__construct(
12
+ $reasons,
13
+ sprintf('%s; %d rejected promises', $msg, count($reasons))
14
+ );
15
+ }
16
+ }
vendor/guzzlehttp/promises/src/CancellationException.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Promise;
3
+
4
+ /**
5
+ * Exception that is set as the reason for a promise that has been cancelled.
6
+ */
7
+ class CancellationException extends RejectionException
8
+ {
9
+ }
vendor/guzzlehttp/promises/src/Coroutine.php ADDED
@@ -0,0 +1,151 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Promise;
3
+
4
+ use Exception;
5
+ use Generator;
6
+ use Throwable;
7
+
8
+ /**
9
+ * Creates a promise that is resolved using a generator that yields values or
10
+ * promises (somewhat similar to C#'s async keyword).
11
+ *
12
+ * When called, the coroutine function will start an instance of the generator
13
+ * and returns a promise that is fulfilled with its final yielded value.
14
+ *
15
+ * Control is returned back to the generator when the yielded promise settles.
16
+ * This can lead to less verbose code when doing lots of sequential async calls
17
+ * with minimal processing in between.
18
+ *
19
+ * use GuzzleHttp\Promise;
20
+ *
21
+ * function createPromise($value) {
22
+ * return new Promise\FulfilledPromise($value);
23
+ * }
24
+ *
25
+ * $promise = Promise\coroutine(function () {
26
+ * $value = (yield createPromise('a'));
27
+ * try {
28
+ * $value = (yield createPromise($value . 'b'));
29
+ * } catch (\Exception $e) {
30
+ * // The promise was rejected.
31
+ * }
32
+ * yield $value . 'c';
33
+ * });
34
+ *
35
+ * // Outputs "abc"
36
+ * $promise->then(function ($v) { echo $v; });
37
+ *
38
+ * @param callable $generatorFn Generator function to wrap into a promise.
39
+ *
40
+ * @return Promise
41
+ * @link https://github.com/petkaantonov/bluebird/blob/master/API.md#generators inspiration
42
+ */
43
+ final class Coroutine implements PromiseInterface
44
+ {
45
+ /**
46
+ * @var PromiseInterface|null
47
+ */
48
+ private $currentPromise;
49
+
50
+ /**
51
+ * @var Generator
52
+ */
53
+ private $generator;
54
+
55
+ /**
56
+ * @var Promise
57
+ */
58
+ private $result;
59
+
60
+ public function __construct(callable $generatorFn)
61
+ {
62
+ $this->generator = $generatorFn();
63
+ $this->result = new Promise(function () {
64
+ while (isset($this->currentPromise)) {
65
+ $this->currentPromise->wait();
66
+ }
67
+ });
68
+ $this->nextCoroutine($this->generator->current());
69
+ }
70
+
71
+ public function then(
72
+ callable $onFulfilled = null,
73
+ callable $onRejected = null
74
+ ) {
75
+ return $this->result->then($onFulfilled, $onRejected);
76
+ }
77
+
78
+ public function otherwise(callable $onRejected)
79
+ {
80
+ return $this->result->otherwise($onRejected);
81
+ }
82
+
83
+ public function wait($unwrap = true)
84
+ {
85
+ return $this->result->wait($unwrap);
86
+ }
87
+
88
+ public function getState()
89
+ {
90
+ return $this->result->getState();
91
+ }
92
+
93
+ public function resolve($value)
94
+ {
95
+ $this->result->resolve($value);
96
+ }
97
+
98
+ public function reject($reason)
99
+ {
100
+ $this->result->reject($reason);
101
+ }
102
+
103
+ public function cancel()
104
+ {
105
+ $this->currentPromise->cancel();
106
+ $this->result->cancel();
107
+ }
108
+
109
+ private function nextCoroutine($yielded)
110
+ {
111
+ $this->currentPromise = promise_for($yielded)
112
+ ->then([$this, '_handleSuccess'], [$this, '_handleFailure']);
113
+ }
114
+
115
+ /**
116
+ * @internal
117
+ */
118
+ public function _handleSuccess($value)
119
+ {
120
+ unset($this->currentPromise);
121
+ try {
122
+ $next = $this->generator->send($value);
123
+ if ($this->generator->valid()) {
124
+ $this->nextCoroutine($next);
125
+ } else {
126
+ $this->result->resolve($value);
127
+ }
128
+ } catch (Exception $exception) {
129
+ $this->result->reject($exception);
130
+ } catch (Throwable $throwable) {
131
+ $this->result->reject($throwable);
132
+ }
133
+ }
134
+
135
+ /**
136
+ * @internal
137
+ */
138
+ public function _handleFailure($reason)
139
+ {
140
+ unset($this->currentPromise);
141
+ try {
142
+ $nextYield = $this->generator->throw(exception_for($reason));
143
+ // The throw was caught, so keep iterating on the coroutine
144
+ $this->nextCoroutine($nextYield);
145
+ } catch (Exception $exception) {
146
+ $this->result->reject($exception);
147
+ } catch (Throwable $throwable) {
148
+ $this->result->reject($throwable);
149
+ }
150
+ }
151
+ }
vendor/guzzlehttp/promises/src/EachPromise.php ADDED
@@ -0,0 +1,229 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Promise;
3
+
4
+ /**
5
+ * Represents a promise that iterates over many promises and invokes
6
+ * side-effect functions in the process.
7
+ */
8
+ class EachPromise implements PromisorInterface
9
+ {
10
+ private $pending = [];
11
+
12
+ /** @var \Iterator */
13
+ private $iterable;
14
+
15
+ /** @var callable|int */
16
+ private $concurrency;
17
+
18
+ /** @var callable */
19
+ private $onFulfilled;
20
+
21
+ /** @var callable */
22
+ private $onRejected;
23
+
24
+ /** @var Promise */
25
+ private $aggregate;
26
+
27
+ /** @var bool */
28
+ private $mutex;
29
+
30
+ /**
31
+ * Configuration hash can include the following key value pairs:
32
+ *
33
+ * - fulfilled: (callable) Invoked when a promise fulfills. The function
34
+ * is invoked with three arguments: the fulfillment value, the index
35
+ * position from the iterable list of the promise, and the aggregate
36
+ * promise that manages all of the promises. The aggregate promise may
37
+ * be resolved from within the callback to short-circuit the promise.
38
+ * - rejected: (callable) Invoked when a promise is rejected. The
39
+ * function is invoked with three arguments: the rejection reason, the
40
+ * index position from the iterable list of the promise, and the
41
+ * aggregate promise that manages all of the promises. The aggregate
42
+ * promise may be resolved from within the callback to short-circuit
43
+ * the promise.
44
+ * - concurrency: (integer) Pass this configuration option to limit the
45
+ * allowed number of outstanding concurrently executing promises,
46
+ * creating a capped pool of promises. There is no limit by default.
47
+ *
48
+ * @param mixed $iterable Promises or values to iterate.
49
+ * @param array $config Configuration options
50
+ */
51
+ public function __construct($iterable, array $config = [])
52
+ {
53
+ $this->iterable = iter_for($iterable);
54
+
55
+ if (isset($config['concurrency'])) {
56
+ $this->concurrency = $config['concurrency'];
57
+ }
58
+
59
+ if (isset($config['fulfilled'])) {
60
+ $this->onFulfilled = $config['fulfilled'];
61
+ }
62
+
63
+ if (isset($config['rejected'])) {
64
+ $this->onRejected = $config['rejected'];
65
+ }
66
+ }
67
+
68
+ public function promise()
69
+ {
70
+ if ($this->aggregate) {
71
+ return $this->aggregate;
72
+ }
73
+
74
+ try {
75
+ $this->createPromise();
76
+ $this->iterable->rewind();
77
+ $this->refillPending();
78
+ } catch (\Throwable $e) {
79
+ $this->aggregate->reject($e);
80
+ } catch (\Exception $e) {
81
+ $this->aggregate->reject($e);
82
+ }
83
+
84
+ return $this->aggregate;
85
+ }
86
+
87
+ private function createPromise()
88
+ {
89
+ $this->mutex = false;
90
+ $this->aggregate = new Promise(function () {
91
+ reset($this->pending);
92
+ if (empty($this->pending) && !$this->iterable->valid()) {
93
+ $this->aggregate->resolve(null);
94
+ return;
95
+ }
96
+
97
+ // Consume a potentially fluctuating list of promises while
98
+ // ensuring that indexes are maintained (precluding array_shift).
99
+ while ($promise = current($this->pending)) {
100
+ next($this->pending);
101
+ $promise->wait();
102
+ if ($this->aggregate->getState() !== PromiseInterface::PENDING) {
103
+ return;
104
+ }
105
+ }
106
+ });
107
+
108
+ // Clear the references when the promise is resolved.
109
+ $clearFn = function () {
110
+ $this->iterable = $this->concurrency = $this->pending = null;
111
+ $this->onFulfilled = $this->onRejected = null;
112
+ };
113
+
114
+ $this->aggregate->then($clearFn, $clearFn);
115
+ }
116
+
117
+ private function refillPending()
118
+ {
119
+ if (!$this->concurrency) {
120
+ // Add all pending promises.
121
+ while ($this->addPending() && $this->advanceIterator());
122
+ return;
123
+ }
124
+
125
+ // Add only up to N pending promises.
126
+ $concurrency = is_callable($this->concurrency)
127
+ ? call_user_func($this->concurrency, count($this->pending))
128
+ : $this->concurrency;
129
+ $concurrency = max($concurrency - count($this->pending), 0);
130
+ // Concurrency may be set to 0 to disallow new promises.
131
+ if (!$concurrency) {
132
+ return;
133
+ }
134
+ // Add the first pending promise.
135
+ $this->addPending();
136
+ // Note this is special handling for concurrency=1 so that we do
137
+ // not advance the iterator after adding the first promise. This
138
+ // helps work around issues with generators that might not have the
139
+ // next value to yield until promise callbacks are called.
140
+ while (--$concurrency
141
+ && $this->advanceIterator()
142
+ && $this->addPending());
143
+ }
144
+
145
+ private function addPending()
146
+ {
147
+ if (!$this->iterable || !$this->iterable->valid()) {
148
+ return false;
149
+ }
150
+
151
+ $promise = promise_for($this->iterable->current());
152
+ $idx = $this->iterable->key();
153
+
154
+ $this->pending[$idx] = $promise->then(
155
+ function ($value) use ($idx) {
156
+ if ($this->onFulfilled) {
157
+ call_user_func(
158
+ $this->onFulfilled, $value, $idx, $this->aggregate
159
+ );
160
+ }
161
+ $this->step($idx);
162
+ },
163
+ function ($reason) use ($idx) {
164
+ if ($this->onRejected) {
165
+ call_user_func(
166
+ $this->onRejected, $reason, $idx, $this->aggregate
167
+ );
168
+ }
169
+ $this->step($idx);
170
+ }
171
+ );
172
+
173
+ return true;
174
+ }
175
+
176
+ private function advanceIterator()
177
+ {
178
+ // Place a lock on the iterator so that we ensure to not recurse,
179
+ // preventing fatal generator errors.
180
+ if ($this->mutex) {
181
+ return false;
182
+ }
183
+
184
+ $this->mutex = true;
185
+
186
+ try {
187
+ $this->iterable->next();
188
+ $this->mutex = false;
189
+ return true;
190
+ } catch (\Throwable $e) {
191
+ $this->aggregate->reject($e);
192
+ $this->mutex = false;
193
+ return false;
194
+ } catch (\Exception $e) {
195
+ $this->aggregate->reject($e);
196
+ $this->mutex = false;
197
+ return false;
198
+ }
199
+ }
200
+
201
+ private function step($idx)
202
+ {
203
+ // If the promise was already resolved, then ignore this step.
204
+ if ($this->aggregate->getState() !== PromiseInterface::PENDING) {
205
+ return;
206
+ }
207
+
208
+ unset($this->pending[$idx]);
209
+
210
+ // Only refill pending promises if we are not locked, preventing the
211
+ // EachPromise to recursively invoke the provided iterator, which
212
+ // cause a fatal error: "Cannot resume an already running generator"
213
+ if ($this->advanceIterator() && !$this->checkIfFinished()) {
214
+ // Add more pending promises if possible.
215
+ $this->refillPending();
216
+ }
217
+ }
218
+
219
+ private function checkIfFinished()
220
+ {
221
+ if (!$this->pending && !$this->iterable->valid()) {
222
+ // Resolve the promise if there's nothing left to do.
223
+ $this->aggregate->resolve(null);
224
+ return true;
225
+ }
226
+
227
+ return false;
228
+ }
229
+ }
vendor/guzzlehttp/promises/src/FulfilledPromise.php ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Promise;
3
+
4
+ /**
5
+ * A promise that has been fulfilled.
6
+ *
7
+ * Thenning off of this promise will invoke the onFulfilled callback
8
+ * immediately and ignore other callbacks.
9
+ */
10
+ class FulfilledPromise implements PromiseInterface
11
+ {
12
+ private $value;
13
+
14
+ public function __construct($value)
15
+ {
16
+ if (method_exists($value, 'then')) {
17
+ throw new \InvalidArgumentException(
18
+ 'You cannot create a FulfilledPromise with a promise.');
19
+ }
20
+
21
+ $this->value = $value;
22
+ }
23
+
24
+ public function then(
25
+ callable $onFulfilled = null,
26
+ callable $onRejected = null
27
+ ) {
28
+ // Return itself if there is no onFulfilled function.
29
+ if (!$onFulfilled) {
30
+ return $this;
31
+ }
32
+
33
+ $queue = queue();
34
+ $p = new Promise([$queue, 'run']);
35
+ $value = $this->value;
36
+ $queue->add(static function () use ($p, $value, $onFulfilled) {
37
+ if ($p->getState() === self::PENDING) {
38
+ try {
39
+ $p->resolve($onFulfilled($value));
40
+ } catch (\Throwable $e) {
41
+ $p->reject($e);
42
+ } catch (\Exception $e) {
43
+ $p->reject($e);
44
+ }
45
+ }
46
+ });
47
+
48
+ return $p;
49
+ }
50
+
51
+ public function otherwise(callable $onRejected)
52
+ {
53
+ return $this->then(null, $onRejected);
54
+ }
55
+
56
+ public function wait($unwrap = true, $defaultDelivery = null)
57
+ {
58
+ return $unwrap ? $this->value : null;
59
+ }
60
+
61
+ public function getState()
62
+ {
63
+ return self::FULFILLED;
64
+ }
65
+
66
+ public function resolve($value)
67
+ {
68
+ if ($value !== $this->value) {
69
+ throw new \LogicException("Cannot resolve a fulfilled promise");
70
+ }
71
+ }
72
+
73
+ public function reject($reason)
74
+ {
75
+ throw new \LogicException("Cannot reject a fulfilled promise");
76
+ }
77
+
78
+ public function cancel()
79
+ {
80
+ // pass
81
+ }
82
+ }
vendor/guzzlehttp/promises/src/Promise.php ADDED
@@ -0,0 +1,280 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Promise;
3
+
4
+ /**
5
+ * Promises/A+ implementation that avoids recursion when possible.
6
+ *
7
+ * @link https://promisesaplus.com/
8
+ */
9
+ class Promise implements PromiseInterface
10
+ {
11
+ private $state = self::PENDING;
12
+ private $result;
13
+ private $cancelFn;
14
+ private $waitFn;
15
+ private $waitList;
16
+ private $handlers = [];
17
+
18
+ /**
19
+ * @param callable $waitFn Fn that when invoked resolves the promise.
20
+ * @param callable $cancelFn Fn that when invoked cancels the promise.
21
+ */
22
+ public function __construct(
23
+ callable $waitFn = null,
24
+ callable $cancelFn = null
25
+ ) {
26
+ $this->waitFn = $waitFn;
27
+ $this->cancelFn = $cancelFn;
28
+ }
29
+
30
+ public function then(
31
+ callable $onFulfilled = null,
32
+ callable $onRejected = null
33
+ ) {
34
+ if ($this->state === self::PENDING) {
35
+ $p = new Promise(null, [$this, 'cancel']);
36
+ $this->handlers[] = [$p, $onFulfilled, $onRejected];
37
+ $p->waitList = $this->waitList;
38
+ $p->waitList[] = $this;
39
+ return $p;
40
+ }
41
+
42
+ // Return a fulfilled promise and immediately invoke any callbacks.
43
+ if ($this->state === self::FULFILLED) {
44
+ return $onFulfilled
45
+ ? promise_for($this->result)->then($onFulfilled)
46
+ : promise_for($this->result);
47
+ }
48
+
49
+ // It's either cancelled or rejected, so return a rejected promise
50
+ // and immediately invoke any callbacks.
51
+ $rejection = rejection_for($this->result);
52
+ return $onRejected ? $rejection->then(null, $onRejected) : $rejection;
53
+ }
54
+
55
+ public function otherwise(callable $onRejected)
56
+ {
57
+ return $this->then(null, $onRejected);
58
+ }
59
+
60
+ public function wait($unwrap = true)
61
+ {
62
+ $this->waitIfPending();
63
+
64
+ $inner = $this->result instanceof PromiseInterface
65
+ ? $this->result->wait($unwrap)
66
+ : $this->result;
67
+
68
+ if ($unwrap) {
69
+ if ($this->result instanceof PromiseInterface
70
+ || $this->state === self::FULFILLED
71
+ ) {
72
+ return $inner;
73
+ } else {
74
+ // It's rejected so "unwrap" and throw an exception.
75
+ throw exception_for($inner);
76
+ }
77
+ }
78
+ }
79
+
80
+ public function getState()
81
+ {
82
+ return $this->state;
83
+ }
84
+
85
+ public function cancel()
86
+ {
87
+ if ($this->state !== self::PENDING) {
88
+ return;
89
+ }
90
+
91
+ $this->waitFn = $this->waitList = null;
92
+
93
+ if ($this->cancelFn) {
94
+ $fn = $this->cancelFn;
95
+ $this->cancelFn = null;
96
+ try {
97
+ $fn();
98
+ } catch (\Throwable $e) {
99
+ $this->reject($e);
100
+ } catch (\Exception $e) {
101
+ $this->reject($e);
102
+ }
103
+ }
104
+
105
+ // Reject the promise only if it wasn't rejected in a then callback.
106
+ if ($this->state === self::PENDING) {
107
+ $this->reject(new CancellationException('Promise has been cancelled'));
108
+ }
109
+ }
110
+
111
+ public function resolve($value)
112
+ {
113
+ $this->settle(self::FULFILLED, $value);
114
+ }
115
+
116
+ public function reject($reason)
117
+ {
118
+ $this->settle(self::REJECTED, $reason);
119
+ }
120
+
121
+ private function settle($state, $value)
122
+ {
123
+ if ($this->state !== self::PENDING) {
124
+ // Ignore calls with the same resolution.
125
+ if ($state === $this->state && $value === $this->result) {
126
+ return;
127
+ }
128
+ throw $this->state === $state
129
+ ? new \LogicException("The promise is already {$state}.")
130
+ : new \LogicException("Cannot change a {$this->state} promise to {$state}");
131
+ }
132
+
133
+ if ($value === $this) {
134
+ throw new \LogicException('Cannot fulfill or reject a promise with itself');
135
+ }
136
+
137
+ // Clear out the state of the promise but stash the handlers.
138
+ $this->state = $state;
139
+ $this->result = $value;
140
+ $handlers = $this->handlers;
141
+ $this->handlers = null;
142
+ $this->waitList = $this->waitFn = null;
143
+ $this->cancelFn = null;
144
+
145
+ if (!$handlers) {
146
+ return;
147
+ }
148
+
149
+ // If the value was not a settled promise or a thenable, then resolve
150
+ // it in the task queue using the correct ID.
151
+ if (!method_exists($value, 'then')) {
152
+ $id = $state === self::FULFILLED ? 1 : 2;
153
+ // It's a success, so resolve the handlers in the queue.
154
+ queue()->add(static function () use ($id, $value, $handlers) {
155
+ foreach ($handlers as $handler) {
156
+ self::callHandler($id, $value, $handler);
157
+ }
158
+ });
159
+ } elseif ($value instanceof Promise
160
+ && $value->getState() === self::PENDING
161
+ ) {
162
+ // We can just merge our handlers onto the next promise.
163
+ $value->handlers = array_merge($value->handlers, $handlers);
164
+ } else {
165
+ // Resolve the handlers when the forwarded promise is resolved.
166
+ $value->then(
167
+ static function ($value) use ($handlers) {
168
+ foreach ($handlers as $handler) {
169
+ self::callHandler(1, $value, $handler);
170
+ }
171
+ },
172
+ static function ($reason) use ($handlers) {
173
+ foreach ($handlers as $handler) {
174
+ self::callHandler(2, $reason, $handler);
175
+ }
176
+ }
177
+ );
178
+ }
179
+ }
180
+
181
+ /**
182
+ * Call a stack of handlers using a specific callback index and value.
183
+ *
184
+ * @param int $index 1 (resolve) or 2 (reject).
185
+ * @param mixed $value Value to pass to the callback.
186
+ * @param array $handler Array of handler data (promise and callbacks).
187
+ *
188
+ * @return array Returns the next group to resolve.
189
+ */
190
+ private static function callHandler($index, $value, array $handler)
191
+ {
192
+ /** @var PromiseInterface $promise */
193
+ $promise = $handler[0];
194
+
195
+ // The promise may have been cancelled or resolved before placing
196
+ // this thunk in the queue.
197
+ if ($promise->getState() !== self::PENDING) {
198
+ return;
199
+ }
200
+
201
+ try {
202
+ if (isset($handler[$index])) {
203
+ $promise->resolve($handler[$index]($value));
204
+ } elseif ($index === 1) {
205
+ // Forward resolution values as-is.
206
+ $promise->resolve($value);
207
+ } else {
208
+ // Forward rejections down the chain.
209
+ $promise->reject($value);
210
+ }
211
+ } catch (\Throwable $reason) {
212
+ $promise->reject($reason);
213
+ } catch (\Exception $reason) {
214
+ $promise->reject($reason);
215
+ }
216
+ }
217
+
218
+ private function waitIfPending()
219
+ {
220
+ if ($this->state !== self::PENDING) {
221
+ return;
222
+ } elseif ($this->waitFn) {
223
+ $this->invokeWaitFn();
224
+ } elseif ($this->waitList) {
225
+ $this->invokeWaitList();
226
+ } else {
227
+ // If there's not wait function, then reject the promise.
228
+ $this->reject('Cannot wait on a promise that has '
229
+ . 'no internal wait function. You must provide a wait '
230
+ . 'function when constructing the promise to be able to '
231
+ . 'wait on a promise.');
232
+ }
233
+
234
+ queue()->run();
235
+
236
+ if ($this->state === self::PENDING) {
237
+ $this->reject('Invoking the wait callback did not resolve the promise');
238
+ }
239
+ }
240
+
241
+ private function invokeWaitFn()
242
+ {
243
+ try {
244
+ $wfn = $this->waitFn;
245
+ $this->waitFn = null;
246
+ $wfn(true);
247
+ } catch (\Exception $reason) {
248
+ if ($this->state === self::PENDING) {
249
+ // The promise has not been resolved yet, so reject the promise
250
+ // with the exception.
251
+ $this->reject($reason);
252
+ } else {
253
+ // The promise was already resolved, so there's a problem in
254
+ // the application.
255
+ throw $reason;
256
+ }
257
+ }
258
+ }
259
+
260
+ private function invokeWaitList()
261
+ {
262
+ $waitList = $this->waitList;
263
+ $this->waitList = null;
264
+
265
+ foreach ($waitList as $result) {
266
+ while (true) {
267
+ $result->waitIfPending();
268
+
269
+ if ($result->result instanceof Promise) {
270
+ $result = $result->result;
271
+ } else {
272
+ if ($result->result instanceof PromiseInterface) {
273
+ $result->result->wait(false);
274
+ }
275
+ break;
276
+ }
277
+ }
278
+ }
279
+ }
280
+ }
vendor/guzzlehttp/promises/src/PromiseInterface.php ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Promise;
3
+
4
+ /**
5
+ * A promise represents the eventual result of an asynchronous operation.
6
+ *
7
+ * The primary way of interacting with a promise is through its then method,
8
+ * which registers callbacks to receive either a promise’s eventual value or
9
+ * the reason why the promise cannot be fulfilled.
10
+ *
11
+ * @link https://promisesaplus.com/
12
+ */
13
+ interface PromiseInterface
14
+ {
15
+ const PENDING = 'pending';
16
+ const FULFILLED = 'fulfilled';
17
+ const REJECTED = 'rejected';
18
+
19
+ /**
20
+ * Appends fulfillment and rejection handlers to the promise, and returns
21
+ * a new promise resolving to the return value of the called handler.
22
+ *
23
+ * @param callable $onFulfilled Invoked when the promise fulfills.
24
+ * @param callable $onRejected Invoked when the promise is rejected.
25
+ *
26
+ * @return PromiseInterface
27
+ */
28
+ public function then(
29
+ callable $onFulfilled = null,
30
+ callable $onRejected = null
31
+ );
32
+
33
+ /**
34
+ * Appends a rejection handler callback to the promise, and returns a new
35
+ * promise resolving to the return value of the callback if it is called,
36
+ * or to its original fulfillment value if the promise is instead
37
+ * fulfilled.
38
+ *
39
+ * @param callable $onRejected Invoked when the promise is rejected.
40
+ *
41
+ * @return PromiseInterface
42
+ */
43
+ public function otherwise(callable $onRejected);
44
+
45
+ /**
46
+ * Get the state of the promise ("pending", "rejected", or "fulfilled").
47
+ *
48
+ * The three states can be checked against the constants defined on
49
+ * PromiseInterface: PENDING, FULFILLED, and REJECTED.
50
+ *
51
+ * @return string
52
+ */
53
+ public function getState();
54
+
55
+ /**
56
+ * Resolve the promise with the given value.
57
+ *
58
+ * @param mixed $value
59
+ * @throws \RuntimeException if the promise is already resolved.
60
+ */
61
+ public function resolve($value);
62
+
63
+ /**
64
+ * Reject the promise with the given reason.
65
+ *
66
+ * @param mixed $reason
67
+ * @throws \RuntimeException if the promise is already resolved.
68
+ */
69
+ public function reject($reason);
70
+
71
+ /**
72
+ * Cancels the promise if possible.
73
+ *
74
+ * @link https://github.com/promises-aplus/cancellation-spec/issues/7
75
+ */
76
+ public function cancel();
77
+
78
+ /**
79
+ * Waits until the promise completes if possible.
80
+ *
81
+ * Pass $unwrap as true to unwrap the result of the promise, either
82
+ * returning the resolved value or throwing the rejected exception.
83
+ *
84
+ * If the promise cannot be waited on, then the promise will be rejected.
85
+ *
86
+ * @param bool $unwrap
87
+ *
88
+ * @return mixed
89
+ * @throws \LogicException if the promise has no wait function or if the
90
+ * promise does not settle after waiting.
91
+ */
92
+ public function wait($unwrap = true);
93
+ }
vendor/guzzlehttp/promises/src/PromisorInterface.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Promise;
3
+
4
+ /**
5
+ * Interface used with classes that return a promise.
6
+ */
7
+ interface PromisorInterface
8
+ {
9
+ /**
10
+ * Returns a promise.
11
+ *
12
+ * @return PromiseInterface
13
+ */
14
+ public function promise();
15
+ }
vendor/guzzlehttp/promises/src/RejectedPromise.php ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Promise;
3
+
4
+ /**
5
+ * A promise that has been rejected.
6
+ *
7
+ * Thenning off of this promise will invoke the onRejected callback
8
+ * immediately and ignore other callbacks.
9
+ */
10
+ class RejectedPromise implements PromiseInterface
11
+ {
12
+ private $reason;
13
+
14
+ public function __construct($reason)
15
+ {
16
+ if (method_exists($reason, 'then')) {
17
+ throw new \InvalidArgumentException(
18
+ 'You cannot create a RejectedPromise with a promise.');
19
+ }
20
+
21
+ $this->reason = $reason;
22
+ }
23
+
24
+ public function then(
25
+ callable $onFulfilled = null,
26
+ callable $onRejected = null
27
+ ) {
28
+ // If there's no onRejected callback then just return self.
29
+ if (!$onRejected) {
30
+ return $this;
31
+ }
32
+
33
+ $queue = queue();
34
+ $reason = $this->reason;
35
+ $p = new Promise([$queue, 'run']);
36
+ $queue->add(static function () use ($p, $reason, $onRejected) {
37
+ if ($p->getState() === self::PENDING) {
38
+ try {
39
+ // Return a resolved promise if onRejected does not throw.
40
+ $p->resolve($onRejected($reason));
41
+ } catch (\Throwable $e) {
42
+ // onRejected threw, so return a rejected promise.
43
+ $p->reject($e);
44
+ } catch (\Exception $e) {
45
+ // onRejected threw, so return a rejected promise.
46
+ $p->reject($e);
47
+ }
48
+ }
49
+ });
50
+
51
+ return $p;
52
+ }
53
+
54
+ public function otherwise(callable $onRejected)
55
+ {
56
+ return $this->then(null, $onRejected);
57
+ }
58
+
59
+ public function wait($unwrap = true, $defaultDelivery = null)
60
+ {
61
+ if ($unwrap) {
62
+ throw exception_for($this->reason);
63
+ }
64
+ }
65
+
66
+ public function getState()
67
+ {
68
+ return self::REJECTED;
69
+ }
70
+
71
+ public function resolve($value)
72
+ {
73
+ throw new \LogicException("Cannot resolve a rejected promise");
74
+ }
75
+
76
+ public function reject($reason)
77
+ {
78
+ if ($reason !== $this->reason) {
79
+ throw new \LogicException("Cannot reject a rejected promise");
80
+ }
81
+ }
82
+
83
+ public function cancel()
84
+ {
85
+ // pass
86
+ }
87
+ }
vendor/guzzlehttp/promises/src/RejectionException.php ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Promise;
3
+
4
+ /**
5
+ * A special exception that is thrown when waiting on a rejected promise.
6
+ *
7
+ * The reason value is available via the getReason() method.
8
+ */
9
+ class RejectionException extends \RuntimeException
10
+ {
11
+ /** @var mixed Rejection reason. */
12
+ private $reason;
13
+
14
+ /**
15
+ * @param mixed $reason Rejection reason.
16
+ * @param string $description Optional description
17
+ */
18
+ public function __construct($reason, $description = null)
19
+ {
20
+ $this->reason = $reason;
21
+
22
+ $message = 'The promise was rejected';
23
+
24
+ if ($description) {
25
+ $message .= ' with reason: ' . $description;
26
+ } elseif (is_string($reason)
27
+ || (is_object($reason) && method_exists($reason, '__toString'))
28
+ ) {
29
+ $message .= ' with reason: ' . $this->reason;
30
+ } elseif ($reason instanceof \JsonSerializable) {
31
+ $message .= ' with reason: '
32
+ . json_encode($this->reason, JSON_PRETTY_PRINT);
33
+ }
34
+
35
+ parent::__construct($message);
36
+ }
37
+
38
+ /**
39
+ * Returns the rejection reason.
40
+ *
41
+ * @return mixed
42
+ */
43
+ public function getReason()
44
+ {
45
+ return $this->reason;
46
+ }
47
+ }
vendor/guzzlehttp/promises/src/TaskQueue.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Promise;
3
+
4
+ /**
5
+ * A task queue that executes tasks in a FIFO order.
6
+ *
7
+ * This task queue class is used to settle promises asynchronously and
8
+ * maintains a constant stack size. You can use the task queue asynchronously
9
+ * by calling the `run()` function of the global task queue in an event loop.
10
+ *
11
+ * GuzzleHttp\Promise\queue()->run();
12
+ */
13
+ class TaskQueue implements TaskQueueInterface
14
+ {
15
+ private $enableShutdown = true;
16
+ private $queue = [];
17
+
18
+ public function __construct($withShutdown = true)
19
+ {
20
+ if ($withShutdown) {
21
+ register_shutdown_function(function () {
22
+ if ($this->enableShutdown) {
23
+ // Only run the tasks if an E_ERROR didn't occur.
24
+ $err = error_get_last();
25
+ if (!$err || ($err['type'] ^ E_ERROR)) {
26
+ $this->run();
27
+ }
28
+ }
29
+ });
30
+ }
31
+ }
32
+
33
+ public function isEmpty()
34
+ {
35
+ return !$this->queue;
36
+ }
37
+
38
+ public function add(callable $task)
39
+ {
40
+ $this->queue[] = $task;
41
+ }
42
+
43
+ public function run()
44
+ {
45
+ /** @var callable $task */
46
+ while ($task = array_shift($this->queue)) {
47
+ $task();
48
+ }
49
+ }
50
+
51
+ /**
52
+ * The task queue will be run and exhausted by default when the process
53
+ * exits IFF the exit is not the result of a PHP E_ERROR error.
54
+ *
55
+ * You can disable running the automatic shutdown of the queue by calling
56
+ * this function. If you disable the task queue shutdown process, then you
57
+ * MUST either run the task queue (as a result of running your event loop
58
+ * or manually using the run() method) or wait on each outstanding promise.
59
+ *
60
+ * Note: This shutdown will occur before any destructors are triggered.
61
+ */
62
+ public function disableShutdown()
63
+ {
64
+ $this->enableShutdown = false;
65
+ }
66
+ }
vendor/guzzlehttp/promises/src/TaskQueueInterface.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Promise;
3
+
4
+ interface TaskQueueInterface
5
+ {
6
+ /**
7
+ * Returns true if the queue is empty.
8
+ *
9
+ * @return bool
10
+ */
11
+ public function isEmpty();
12
+
13
+ /**
14
+ * Adds a task to the queue that will be executed the next time run is
15
+ * called.
16
+ *
17
+ * @param callable $task
18
+ */
19
+ public function add(callable $task);
20
+
21
+ /**
22
+ * Execute all of the pending task in the queue.
23
+ */
24
+ public function run();
25
+ }
vendor/guzzlehttp/promises/src/functions.php ADDED
@@ -0,0 +1,457 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Promise;
3
+
4
+ /**
5
+ * Get the global task queue used for promise resolution.
6
+ *
7
+ * This task queue MUST be run in an event loop in order for promises to be
8
+ * settled asynchronously. It will be automatically run when synchronously
9
+ * waiting on a promise.
10
+ *
11
+ * <code>
12
+ * while ($eventLoop->isRunning()) {
13
+ * GuzzleHttp\Promise\queue()->run();
14
+ * }
15
+ * </code>
16
+ *
17
+ * @param TaskQueueInterface $assign Optionally specify a new queue instance.
18
+ *
19
+ * @return TaskQueueInterface
20
+ */
21
+ function queue(TaskQueueInterface $assign = null)
22
+ {
23
+ static $queue;
24
+
25
+ if ($assign) {
26
+ $queue = $assign;
27
+ } elseif (!$queue) {
28
+ $queue = new TaskQueue();
29
+ }
30
+
31
+ return $queue;
32
+ }
33
+
34
+ /**
35
+ * Adds a function to run in the task queue when it is next `run()` and returns
36
+ * a promise that is fulfilled or rejected with the result.
37
+ *
38
+ * @param callable $task Task function to run.
39
+ *
40
+ * @return PromiseInterface
41
+ */
42
+ function task(callable $task)
43
+ {
44
+ $queue = queue();
45
+ $promise = new Promise([$queue, 'run']);
46
+ $queue->add(function () use ($task, $promise) {
47
+ try {
48
+ $promise->resolve($task());
49
+ } catch (\Throwable $e) {
50
+ $promise->reject($e);
51
+ } catch (\Exception $e) {
52
+ $promise->reject($e);
53
+ }
54
+ });
55
+
56
+ return $promise;
57
+ }
58
+
59
+ /**
60
+ * Creates a promise for a value if the value is not a promise.
61
+ *
62
+ * @param mixed $value Promise or value.
63
+ *
64
+ * @return PromiseInterface
65
+ */
66
+ function promise_for($value)
67
+ {
68
+ if ($value instanceof PromiseInterface) {
69
+ return $value;
70
+ }
71
+
72
+ // Return a Guzzle promise that shadows the given promise.
73
+ if (method_exists($value, 'then')) {
74
+ $wfn = method_exists($value, 'wait') ? [$value, 'wait'] : null;
75
+ $cfn = method_exists($value, 'cancel') ? [$value, 'cancel'] : null;
76
+ $promise = new Promise($wfn, $cfn);
77
+ $value->then([$promise, 'resolve'], [$promise, 'reject']);
78
+ return $promise;
79
+ }
80
+
81
+ return new FulfilledPromise($value);
82
+ }
83
+
84
+ /**
85
+ * Creates a rejected promise for a reason if the reason is not a promise. If
86
+ * the provided reason is a promise, then it is returned as-is.
87
+ *
88
+ * @param mixed $reason Promise or reason.
89
+ *
90
+ * @return PromiseInterface
91
+ */
92
+ function rejection_for($reason)
93
+ {
94
+ if ($reason instanceof PromiseInterface) {
95
+ return $reason;
96
+ }
97
+
98
+ return new RejectedPromise($reason);
99
+ }
100
+
101
+ /**
102
+ * Create an exception for a rejected promise value.
103
+ *
104
+ * @param mixed $reason
105
+ *
106
+ * @return \Exception|\Throwable
107
+ */
108
+ function exception_for($reason)
109
+ {
110
+ return $reason instanceof \Exception || $reason instanceof \Throwable
111
+ ? $reason
112
+ : new RejectionException($reason);
113
+ }
114
+
115
+ /**
116
+ * Returns an iterator for the given value.
117
+ *
118
+ * @param mixed $value
119
+ *
120
+ * @return \Iterator
121
+ */
122
+ function iter_for($value)
123
+ {
124
+ if ($value instanceof \Iterator) {
125
+ return $value;
126
+ } elseif (is_array($value)) {
127
+ return new \ArrayIterator($value);
128
+ } else {
129
+ return new \ArrayIterator([$value]);
130
+ }
131
+ }
132
+
133
+ /**
134
+ * Synchronously waits on a promise to resolve and returns an inspection state
135
+ * array.
136
+ *
137
+ * Returns a state associative array containing a "state" key mapping to a
138
+ * valid promise state. If the state of the promise is "fulfilled", the array
139
+ * will contain a "value" key mapping to the fulfilled value of the promise. If
140
+ * the promise is rejected, the array will contain a "reason" key mapping to
141
+ * the rejection reason of the promise.
142
+ *
143
+ * @param PromiseInterface $promise Promise or value.
144
+ *
145
+ * @return array
146
+ */
147
+ function inspect(PromiseInterface $promise)
148
+ {
149
+ try {
150
+ return [
151
+ 'state' => PromiseInterface::FULFILLED,
152
+ 'value' => $promise->wait()
153
+ ];
154
+ } catch (RejectionException $e) {
155
+ return ['state' => PromiseInterface::REJECTED, 'reason' => $e->getReason()];
156
+ } catch (\Throwable $e) {
157
+ return ['state' => PromiseInterface::REJECTED, 'reason' => $e];
158
+ } catch (\Exception $e) {
159
+ return ['state' => PromiseInterface::REJECTED, 'reason' => $e];
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Waits on all of the provided promises, but does not unwrap rejected promises
165
+ * as thrown exception.
166
+ *
167
+ * Returns an array of inspection state arrays.
168
+ *
169
+ * @param PromiseInterface[] $promises Traversable of promises to wait upon.
170
+ *
171
+ * @return array
172
+ * @see GuzzleHttp\Promise\inspect for the inspection state array format.
173
+ */
174
+ function inspect_all($promises)
175
+ {
176
+ $results = [];
177
+ foreach ($promises as $key => $promise) {
178
+ $results[$key] = inspect($promise);
179
+ }
180
+
181
+ return $results;
182
+ }
183
+
184
+ /**
185
+ * Waits on all of the provided promises and returns the fulfilled values.
186
+ *
187
+ * Returns an array that contains the value of each promise (in the same order
188
+ * the promises were provided). An exception is thrown if any of the promises
189
+ * are rejected.
190
+ *
191
+ * @param mixed $promises Iterable of PromiseInterface objects to wait on.
192
+ *
193
+ * @return array
194
+ * @throws \Exception on error
195
+ * @throws \Throwable on error in PHP >=7
196
+ */
197
+ function unwrap($promises)
198
+ {
199
+ $results = [];
200
+ foreach ($promises as $key => $promise) {
201
+ $results[$key] = $promise->wait();
202
+ }
203
+
204
+ return $results;
205
+ }
206
+
207
+ /**
208
+ * Given an array of promises, return a promise that is fulfilled when all the
209
+ * items in the array are fulfilled.
210
+ *
211
+ * The promise's fulfillment value is an array with fulfillment values at
212
+ * respective positions to the original array. If any promise in the array
213
+ * rejects, the returned promise is rejected with the rejection reason.
214
+ *
215
+ * @param mixed $promises Promises or values.
216
+ *
217
+ * @return PromiseInterface
218
+ */
219
+ function all($promises)
220
+ {
221
+ $results = [];
222
+ return each(
223
+ $promises,
224
+ function ($value, $idx) use (&$results) {
225
+ $results[$idx] = $value;
226
+ },
227
+ function ($reason, $idx, Promise $aggregate) {
228
+ $aggregate->reject($reason);
229
+ }
230
+ )->then(function () use (&$results) {
231
+ ksort($results);
232
+ return $results;
233
+ });
234
+ }
235
+
236
+ /**
237
+ * Initiate a competitive race between multiple promises or values (values will
238
+ * become immediately fulfilled promises).
239
+ *
240
+ * When count amount of promises have been fulfilled, the returned promise is
241
+ * fulfilled with an array that contains the fulfillment values of the winners
242
+ * in order of resolution.
243
+ *
244
+ * This prommise is rejected with a {@see GuzzleHttp\Promise\AggregateException}
245
+ * if the number of fulfilled promises is less than the desired $count.
246
+ *
247
+ * @param int $count Total number of promises.
248
+ * @param mixed $promises Promises or values.
249
+ *
250
+ * @return PromiseInterface
251
+ */
252
+ function some($count, $promises)
253
+ {
254
+ $results = [];
255
+ $rejections = [];
256
+
257
+ return each(
258
+ $promises,
259
+ function ($value, $idx, PromiseInterface $p) use (&$results, $count) {
260
+ if ($p->getState() !== PromiseInterface::PENDING) {
261
+ return;
262
+ }
263
+ $results[$idx] = $value;
264
+ if (count($results) >= $count) {
265
+ $p->resolve(null);
266
+ }
267
+ },
268
+ function ($reason) use (&$rejections) {
269
+ $rejections[] = $reason;
270
+ }
271
+ )->then(
272
+ function () use (&$results, &$rejections, $count) {
273
+ if (count($results) !== $count) {
274
+ throw new AggregateException(
275
+ 'Not enough promises to fulfill count',
276
+ $rejections
277
+ );
278
+ }
279
+ ksort($results);
280
+ return array_values($results);
281
+ }
282
+ );
283
+ }
284
+
285
+ /**
286
+ * Like some(), with 1 as count. However, if the promise fulfills, the
287
+ * fulfillment value is not an array of 1 but the value directly.
288
+ *
289
+ * @param mixed $promises Promises or values.
290
+ *
291
+ * @return PromiseInterface
292
+ */
293
+ function any($promises)
294
+ {
295
+ return some(1, $promises)->then(function ($values) { return $values[0]; });
296
+ }
297
+
298
+ /**
299
+ * Returns a promise that is fulfilled when all of the provided promises have
300
+ * been fulfilled or rejected.
301
+ *
302
+ * The returned promise is fulfilled with an array of inspection state arrays.
303
+ *
304
+ * @param mixed $promises Promises or values.
305
+ *
306
+ * @return PromiseInterface
307
+ * @see GuzzleHttp\Promise\inspect for the inspection state array format.
308
+ */
309
+ function settle($promises)
310
+ {
311
+ $results = [];
312
+
313
+ return each(
314
+ $promises,
315
+ function ($value, $idx) use (&$results) {
316
+ $results[$idx] = ['state' => PromiseInterface::FULFILLED, 'value' => $value];
317
+ },
318
+ function ($reason, $idx) use (&$results) {
319
+ $results[$idx] = ['state' => PromiseInterface::REJECTED, 'reason' => $reason];
320
+ }
321
+ )->then(function () use (&$results) {
322
+ ksort($results);
323
+ return $results;
324
+ });
325
+ }
326
+
327
+ /**
328
+ * Given an iterator that yields promises or values, returns a promise that is
329
+ * fulfilled with a null value when the iterator has been consumed or the
330
+ * aggregate promise has been fulfilled or rejected.
331
+ *
332
+ * $onFulfilled is a function that accepts the fulfilled value, iterator
333
+ * index, and the aggregate promise. The callback can invoke any necessary side
334
+ * effects and choose to resolve or reject the aggregate promise if needed.
335
+ *
336
+ * $onRejected is a function that accepts the rejection reason, iterator
337
+ * index, and the aggregate promise. The callback can invoke any necessary side
338
+ * effects and choose to resolve or reject the aggregate promise if needed.
339
+ *
340
+ * @param mixed $iterable Iterator or array to iterate over.
341
+ * @param callable $onFulfilled
342
+ * @param callable $onRejected
343
+ *
344
+ * @return PromiseInterface
345
+ */
346
+ function each(
347
+ $iterable,
348
+ callable $onFulfilled = null,
349
+ callable $onRejected = null
350
+ ) {
351
+ return (new EachPromise($iterable, [
352
+ 'fulfilled' => $onFulfilled,
353
+ 'rejected' => $onRejected
354
+ ]))->promise();
355
+ }
356
+
357
+ /**
358
+ * Like each, but only allows a certain number of outstanding promises at any
359
+ * given time.
360
+ *
361
+ * $concurrency may be an integer or a function that accepts the number of
362
+ * pending promises and returns a numeric concurrency limit value to allow for
363
+ * dynamic a concurrency size.
364
+ *
365
+ * @param mixed $iterable
366
+ * @param int|callable $concurrency
367
+ * @param callable $onFulfilled
368
+ * @param callable $onRejected
369
+ *
370
+ * @return PromiseInterface
371
+ */
372
+ function each_limit(
373
+ $iterable,
374
+ $concurrency,
375
+ callable $onFulfilled = null,
376
+ callable $onRejected = null
377
+ ) {
378
+ return (new EachPromise($iterable, [
379
+ 'fulfilled' => $onFulfilled,
380
+ 'rejected' => $onRejected,
381
+ 'concurrency' => $concurrency
382
+ ]))->promise();
383
+ }
384
+
385
+ /**
386
+ * Like each_limit, but ensures that no promise in the given $iterable argument
387
+ * is rejected. If any promise is rejected, then the aggregate promise is
388
+ * rejected with the encountered rejection.
389
+ *
390
+ * @param mixed $iterable
391
+ * @param int|callable $concurrency
392
+ * @param callable $onFulfilled
393
+ *
394
+ * @return PromiseInterface
395
+ */
396
+ function each_limit_all(
397
+ $iterable,
398
+ $concurrency,
399
+ callable $onFulfilled = null
400
+ ) {
401
+ return each_limit(
402
+ $iterable,
403
+ $concurrency,
404
+ $onFulfilled,
405
+ function ($reason, $idx, PromiseInterface $aggregate) {
406
+ $aggregate->reject($reason);
407
+ }
408
+ );
409
+ }
410
+
411
+ /**
412
+ * Returns true if a promise is fulfilled.
413
+ *
414
+ * @param PromiseInterface $promise
415
+ *
416
+ * @return bool
417
+ */
418
+ function is_fulfilled(PromiseInterface $promise)
419
+ {
420
+ return $promise->getState() === PromiseInterface::FULFILLED;
421
+ }
422
+
423
+ /**
424
+ * Returns true if a promise is rejected.
425
+ *
426
+ * @param PromiseInterface $promise
427
+ *
428
+ * @return bool
429
+ */
430
+ function is_rejected(PromiseInterface $promise)
431
+ {
432
+ return $promise->getState() === PromiseInterface::REJECTED;
433
+ }
434
+
435
+ /**
436
+ * Returns true if a promise is fulfilled or rejected.
437
+ *
438
+ * @param PromiseInterface $promise
439
+ *
440
+ * @return bool
441
+ */
442
+ function is_settled(PromiseInterface $promise)
443
+ {
444
+ return $promise->getState() !== PromiseInterface::PENDING;
445
+ }
446
+
447
+ /**
448
+ * @see Coroutine
449
+ *
450
+ * @param callable $generatorFn
451
+ *
452
+ * @return PromiseInterface
453
+ */
454
+ function coroutine(callable $generatorFn)
455
+ {
456
+ return new Coroutine($generatorFn);
457
+ }
vendor/guzzlehttp/promises/src/functions_include.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // Don't redefine the functions if included multiple times.
4
+ if (!function_exists('GuzzleHttp\Promise\promise_for')) {
5
+ require __DIR__ . '/functions.php';
6
+ }
vendor/guzzlehttp/psr7/CHANGELOG.md ADDED
@@ -0,0 +1,225 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Change Log
2
+
3
+
4
+ All notable changes to this project will be documented in this file.
5
+
6
+ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
7
+ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
8
+
9
+
10
+ ## [Unreleased]
11
+
12
+
13
+ ## [1.5.2] - 2018-12-04
14
+
15
+ ### Fixed
16
+
17
+ - Check body size when getting the message summary
18
+
19
+
20
+ ## [1.5.1] - 2018-12-04
21
+
22
+ ### Fixed
23
+
24
+ - Get the summary of a body only if it is readable
25
+
26
+
27
+ ## [1.5.0] - 2018-12-03
28
+
29
+ ### Added
30
+
31
+ - Response first-line to response string exception (fixes #145)
32
+ - A test for #129 behavior
33
+ - `get_message_body_summary` function in order to get the message summary
34
+ - `3gp` and `mkv` mime types
35
+
36
+ ### Changed
37
+
38
+ - Clarify exception message when stream is detached
39
+
40
+ ### Deprecated
41
+
42
+ - Deprecated parsing folded header lines as per RFC 7230
43
+
44
+ ### Fixed
45
+
46
+ - Fix `AppendStream::detach` to not close streams
47
+ - `InflateStream` preserves `isSeekable` attribute of the underlying stream
48
+ - `ServerRequest::getUriFromGlobals` to support URLs in query parameters
49
+
50
+
51
+ Several other fixes and improvements.
52
+
53
+
54
+ ## [1.4.2] - 2017-03-20
55
+
56
+ ### Fixed
57
+
58
+ - Reverted BC break to `Uri::resolve` and `Uri::removeDotSegments` by removing
59
+ calls to `trigger_error` when deprecated methods are invoked.
60
+
61
+
62
+ ## [1.4.1] - 2017-02-27
63
+
64
+ ### Added
65
+
66
+ - Rriggering of silenced deprecation warnings.
67
+
68
+ ### Fixed
69
+
70
+ - Reverted BC break by reintroducing behavior to automagically fix a URI with a
71
+ relative path and an authority by adding a leading slash to the path. It's only
72
+ deprecated now.
73
+
74
+
75
+ ## [1.4.0] - 2017-02-21
76
+
77
+ ### Added
78
+
79
+ - Added common URI utility methods based on RFC 3986 (see documentation in the readme):
80
+ - `Uri::isDefaultPort`
81
+ - `Uri::isAbsolute`
82
+ - `Uri::isNetworkPathReference`
83
+ - `Uri::isAbsolutePathReference`
84
+ - `Uri::isRelativePathReference`
85
+ - `Uri::isSameDocumentReference`
86
+ - `Uri::composeComponents`
87
+ - `UriNormalizer::normalize`
88
+ - `UriNormalizer::isEquivalent`
89
+ - `UriResolver::relativize`
90
+
91
+ ### Changed
92
+
93
+ - Ensure `ServerRequest::getUriFromGlobals` returns a URI in absolute form.
94
+ - Allow `parse_response` to parse a response without delimiting space and reason.
95
+ - Ensure each URI modification results in a valid URI according to PSR-7 discussions.
96
+ Invalid modifications will throw an exception instead of returning a wrong URI or
97
+ doing some magic.
98
+ - `(new Uri)->withPath('foo')->withHost('example.com')` will throw an exception
99
+ because the path of a URI with an authority must start with a slash "/" or be empty
100
+ - `(new Uri())->withScheme('http')` will return `'http://localhost'`
101
+
102
+ ### Deprecated
103
+
104
+ - `Uri::resolve` in favor of `UriResolver::resolve`
105
+ - `Uri::removeDotSegments` in favor of `UriResolver::removeDotSegments`
106
+
107
+ ### Fixed
108
+
109
+ - `Stream::read` when length parameter <= 0.
110
+ - `copy_to_stream` reads bytes in chunks instead of `maxLen` into memory.
111
+ - `ServerRequest::getUriFromGlobals` when `Host` header contains port.
112
+ - Compatibility of URIs with `file` scheme and empty host.
113
+
114
+
115
+ ## [1.3.1] - 2016-06-25
116
+
117
+ ### Fixed
118
+
119
+ - `Uri::__toString` for network path references, e.g. `//example.org`.
120
+ - Missing lowercase normalization for host.
121
+ - Handling of URI components in case they are `'0'` in a lot of places,
122
+ e.g. as a user info password.
123
+ - `Uri::withAddedHeader` to correctly merge headers with different case.
124
+ - Trimming of header values in `Uri::withAddedHeader`. Header values may
125
+ be surrounded by whitespace which should be ignored according to RFC 7230
126
+ Section 3.2.4. This does not apply to header names.
127
+ - `Uri::withAddedHeader` with an array of header values.
128
+ - `Uri::resolve` when base path has no slash and handling of fragment.
129
+ - Handling of encoding in `Uri::with(out)QueryValue` so one can pass the
130
+ key/value both in encoded as well as decoded form to those methods. This is
131
+ consistent with withPath, withQuery etc.
132
+ - `ServerRequest::withoutAttribute` when attribute value is null.
133
+
134
+
135
+ ## [1.3.0] - 2016-04-13
136
+
137
+ ### Added
138
+
139
+ - Remaining interfaces needed for full PSR7 compatibility
140
+ (ServerRequestInterface, UploadedFileInterface, etc.).
141
+ - Support for stream_for from scalars.
142
+
143
+ ### Changed
144
+
145
+ - Can now extend Uri.
146
+
147
+ ### Fixed
148
+ - A bug in validating request methods by making it more permissive.
149
+
150
+
151
+ ## [1.2.3] - 2016-02-18
152
+
153
+ ### Fixed
154
+
155
+ - Support in `GuzzleHttp\Psr7\CachingStream` for seeking forward on remote
156
+ streams, which can sometimes return fewer bytes than requested with `fread`.
157
+ - Handling of gzipped responses with FNAME headers.
158
+
159
+
160
+ ## [1.2.2] - 2016-01-22
161
+
162
+ ### Added
163
+
164
+ - Support for URIs without any authority.
165
+ - Support for HTTP 451 'Unavailable For Legal Reasons.'
166
+ - Support for using '0' as a filename.
167
+ - Support for including non-standard ports in Host headers.
168
+
169
+
170
+ ## [1.2.1] - 2015-11-02
171
+
172
+ ### Changes
173
+
174
+ - Now supporting negative offsets when seeking to SEEK_END.
175
+
176
+
177
+ ## [1.2.0] - 2015-08-15
178
+
179
+ ### Changed
180
+
181
+ - Body as `"0"` is now properly added to a response.
182
+ - Now allowing forward seeking in CachingStream.
183
+ - Now properly parsing HTTP requests that contain proxy targets in
184
+ `parse_request`.
185
+ - functions.php is now conditionally required.
186
+ - user-info is no longer dropped when resolving URIs.
187
+
188
+
189
+ ## [1.1.0] - 2015-06-24
190
+
191
+ ### Changed
192
+
193
+ - URIs can now be relative.
194
+ - `multipart/form-data` headers are now overridden case-insensitively.
195
+ - URI paths no longer encode the following characters because they are allowed
196
+ in URIs: "(", ")", "*", "!", "'"
197
+ - A port is no longer added to a URI when the scheme is missing and no port is
198
+ present.
199
+
200
+
201
+ ## 1.0.0 - 2015-05-19
202
+
203
+ Initial release.
204
+
205
+ Currently unsupported:
206
+
207
+ - `Psr\Http\Message\ServerRequestInterface`
208
+ - `Psr\Http\Message\UploadedFileInterface`
209
+
210
+
211
+
212
+ [Unreleased]: https://github.com/guzzle/psr7/compare/1.5.2...HEAD
213
+ [1.5.2]: https://github.com/guzzle/psr7/compare/1.5.1...1.5.2
214
+ [1.5.1]: https://github.com/guzzle/psr7/compare/1.5.0...1.5.1
215
+ [1.5.0]: https://github.com/guzzle/psr7/compare/1.4.2...1.5.0
216
+ [1.4.2]: https://github.com/guzzle/psr7/compare/1.4.1...1.4.2
217
+ [1.4.1]: https://github.com/guzzle/psr7/compare/1.4.0...1.4.1
218
+ [1.4.0]: https://github.com/guzzle/psr7/compare/1.3.1...1.4.0
219
+ [1.3.1]: https://github.com/guzzle/psr7/compare/1.3.0...1.3.1
220
+ [1.3.0]: https://github.com/guzzle/psr7/compare/1.2.3...1.3.0
221
+ [1.2.3]: https://github.com/guzzle/psr7/compare/1.2.2...1.2.3
222
+ [1.2.2]: https://github.com/guzzle/psr7/compare/1.2.1...1.2.2
223
+ [1.2.1]: https://github.com/guzzle/psr7/compare/1.2.0...1.2.1
224
+ [1.2.0]: https://github.com/guzzle/psr7/compare/1.1.0...1.2.0
225
+ [1.1.0]: https://github.com/guzzle/psr7/compare/1.0.0...1.1.0
vendor/guzzlehttp/psr7/LICENSE ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright (c) 2015 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.
vendor/guzzlehttp/psr7/README.md ADDED
@@ -0,0 +1,745 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # PSR-7 Message Implementation
2
+
3
+ This repository contains a full [PSR-7](http://www.php-fig.org/psr/psr-7/)
4
+ message implementation, several stream decorators, and some helpful
5
+ functionality like query string parsing.
6
+
7
+
8
+ [![Build Status](https://travis-ci.org/guzzle/psr7.svg?branch=master)](https://travis-ci.org/guzzle/psr7)
9
+
10
+
11
+ # Stream implementation
12
+
13
+ This package comes with a number of stream implementations and stream
14
+ decorators.
15
+
16
+
17
+ ## AppendStream
18
+
19
+ `GuzzleHttp\Psr7\AppendStream`
20
+
21
+ Reads from multiple streams, one after the other.
22
+
23
+ ```php
24
+ use GuzzleHttp\Psr7;
25
+
26
+ $a = Psr7\stream_for('abc, ');
27
+ $b = Psr7\stream_for('123.');
28
+ $composed = new Psr7\AppendStream([$a, $b]);
29
+
30
+ $composed->addStream(Psr7\stream_for(' Above all listen to me'));
31
+
32
+ echo $composed; // abc, 123. Above all listen to me.
33
+ ```
34
+
35
+
36
+ ## BufferStream
37
+
38
+ `GuzzleHttp\Psr7\BufferStream`
39
+
40
+ Provides a buffer stream that can be written to fill a buffer, and read
41
+ from to remove bytes from the buffer.
42
+
43
+ This stream returns a "hwm" metadata value that tells upstream consumers
44
+ what the configured high water mark of the stream is, or the maximum
45
+ preferred size of the buffer.
46
+
47
+ ```php
48
+ use GuzzleHttp\Psr7;
49
+
50
+ // When more than 1024 bytes are in the buffer, it will begin returning
51
+ // false to writes. This is an indication that writers should slow down.
52
+ $buffer = new Psr7\BufferStream(1024);
53
+ ```
54
+
55
+
56
+ ## CachingStream
57
+
58
+ The CachingStream is used to allow seeking over previously read bytes on
59
+ non-seekable streams. This can be useful when transferring a non-seekable
60
+ entity body fails due to needing to rewind the stream (for example, resulting
61
+ from a redirect). Data that is read from the remote stream will be buffered in
62
+ a PHP temp stream so that previously read bytes are cached first in memory,
63
+ then on disk.
64
+
65
+ ```php
66
+ use GuzzleHttp\Psr7;
67
+
68
+ $original = Psr7\stream_for(fopen('http://www.google.com', 'r'));
69
+ $stream = new Psr7\CachingStream($original);
70
+
71
+ $stream->read(1024);
72
+ echo $stream->tell();
73
+ // 1024
74
+
75
+ $stream->seek(0);
76
+ echo $stream->tell();
77
+ // 0
78
+ ```
79
+
80
+
81
+ ## DroppingStream
82
+
83
+ `GuzzleHttp\Psr7\DroppingStream`
84
+
85
+ Stream decorator that begins dropping data once the size of the underlying
86
+ stream becomes too full.
87
+
88
+ ```php
89
+ use GuzzleHttp\Psr7;
90
+
91
+ // Create an empty stream
92
+ $stream = Psr7\stream_for();
93
+
94
+ // Start dropping data when the stream has more than 10 bytes
95
+ $dropping = new Psr7\DroppingStream($stream, 10);
96
+
97
+ $dropping->write('01234567890123456789');
98
+ echo $stream; // 0123456789
99
+ ```
100
+
101
+
102
+ ## FnStream
103
+
104
+ `GuzzleHttp\Psr7\FnStream`
105
+
106
+ Compose stream implementations based on a hash of functions.
107
+
108
+ Allows for easy testing and extension of a provided stream without needing
109
+ to create a concrete class for a simple extension point.
110
+
111
+ ```php
112
+
113
+ use GuzzleHttp\Psr7;
114
+
115
+ $stream = Psr7\stream_for('hi');
116
+ $fnStream = Psr7\FnStream::decorate($stream, [
117
+ 'rewind' => function () use ($stream) {
118
+ echo 'About to rewind - ';
119
+ $stream->rewind();
120
+ echo 'rewound!';
121
+ }
122
+ ]);
123
+
124
+ $fnStream->rewind();
125
+ // Outputs: About to rewind - rewound!
126
+ ```
127
+
128
+
129
+ ## InflateStream
130
+
131
+ `GuzzleHttp\Psr7\InflateStream`
132
+
133
+ Uses PHP's zlib.inflate filter to inflate deflate or gzipped content.
134
+
135
+ This stream decorator skips the first 10 bytes of the given stream to remove
136
+ the gzip header, converts the provided stream to a PHP stream resource,
137
+ then appends the zlib.inflate filter. The stream is then converted back
138
+ to a Guzzle stream resource to be used as a Guzzle stream.
139
+
140
+
141
+ ## LazyOpenStream
142
+
143
+ `GuzzleHttp\Psr7\LazyOpenStream`
144
+
145
+ Lazily reads or writes to a file that is opened only after an IO operation
146
+ take place on the stream.
147
+
148
+ ```php
149
+ use GuzzleHttp\Psr7;
150
+
151
+ $stream = new Psr7\LazyOpenStream('/path/to/file', 'r');
152
+ // The file has not yet been opened...
153
+
154
+ echo $stream->read(10);
155
+ // The file is opened and read from only when needed.
156
+ ```
157
+
158
+
159
+ ## LimitStream
160
+
161
+ `GuzzleHttp\Psr7\LimitStream`
162
+
163
+ LimitStream can be used to read a subset or slice of an existing stream object.
164
+ This can be useful for breaking a large file into smaller pieces to be sent in
165
+ chunks (e.g. Amazon S3's multipart upload API).
166
+
167
+ ```php
168
+ use GuzzleHttp\Psr7;
169
+
170
+ $original = Psr7\stream_for(fopen('/tmp/test.txt', 'r+'));
171
+ echo $original->getSize();
172
+ // >>> 1048576
173
+
174
+ // Limit the size of the body to 1024 bytes and start reading from byte 2048
175
+ $stream = new Psr7\LimitStream($original, 1024, 2048);
176
+ echo $stream->getSize();
177
+ // >>> 1024
178
+ echo $stream->tell();
179
+ // >>> 0
180
+ ```
181
+
182
+
183
+ ## MultipartStream
184
+
185
+ `GuzzleHttp\Psr7\MultipartStream`
186
+
187
+ Stream that when read returns bytes for a streaming multipart or
188
+ multipart/form-data stream.
189
+
190
+
191
+ ## NoSeekStream
192
+
193
+ `GuzzleHttp\Psr7\NoSeekStream`
194
+
195
+ NoSeekStream wraps a stream and does not allow seeking.
196
+
197
+ ```php
198
+ use GuzzleHttp\Psr7;
199
+
200
+ $original = Psr7\stream_for('foo');
201
+ $noSeek = new Psr7\NoSeekStream($original);
202
+
203
+ echo $noSeek->read(3);
204
+ // foo
205
+ var_export($noSeek->isSeekable());
206
+ // false
207
+ $noSeek->seek(0);
208
+ var_export($noSeek->read(3));
209
+ // NULL
210
+ ```
211
+
212
+
213
+ ## PumpStream
214
+
215
+ `GuzzleHttp\Psr7\PumpStream`
216
+
217
+ Provides a read only stream that pumps data from a PHP callable.
218
+
219
+ When invoking the provided callable, the PumpStream will pass the amount of
220
+ data requested to read to the callable. The callable can choose to ignore
221
+ this value and return fewer or more bytes than requested. Any extra data
222
+ returned by the provided callable is buffered internally until drained using
223
+ the read() function of the PumpStream. The provided callable MUST return
224
+ false when there is no more data to read.
225
+
226
+
227
+ ## Implementing stream decorators
228
+
229
+ Creating a stream decorator is very easy thanks to the
230
+ `GuzzleHttp\Psr7\StreamDecoratorTrait`. This trait provides methods that
231
+ implement `Psr\Http\Message\StreamInterface` by proxying to an underlying
232
+ stream. Just `use` the `StreamDecoratorTrait` and implement your custom
233
+ methods.
234
+
235
+ For example, let's say we wanted to call a specific function each time the last
236
+ byte is read from a stream. This could be implemented by overriding the
237
+ `read()` method.
238
+
239
+ ```php
240
+ use Psr\Http\Message\StreamInterface;
241
+ use GuzzleHttp\Psr7\StreamDecoratorTrait;
242
+
243
+ class EofCallbackStream implements StreamInterface
244
+ {
245
+ use StreamDecoratorTrait;
246
+
247
+ private $callback;
248
+
249
+ public function __construct(StreamInterface $stream, callable $cb)
250
+ {
251
+ $this->stream = $stream;
252
+ $this->callback = $cb;
253
+ }
254
+
255
+ public function read($length)
256
+ {
257
+ $result = $this->stream->read($length);
258
+
259
+ // Invoke the callback when EOF is hit.
260
+ if ($this->eof()) {
261
+ call_user_func($this->callback);
262
+ }
263
+
264
+ return $result;
265
+ }
266
+ }
267
+ ```
268
+
269
+ This decorator could be added to any existing stream and used like so:
270
+
271
+ ```php
272
+ use GuzzleHttp\Psr7;
273
+
274
+ $original = Psr7\stream_for('foo');
275
+
276
+ $eofStream = new EofCallbackStream($original, function () {
277
+ echo 'EOF!';
278
+ });
279
+
280
+ $eofStream->read(2);
281
+ $eofStream->read(1);
282
+ // echoes "EOF!"
283
+ $eofStream->seek(0);
284
+ $eofStream->read(3);
285
+ // echoes "EOF!"
286
+ ```
287
+
288
+
289
+ ## PHP StreamWrapper
290
+
291
+ You can use the `GuzzleHttp\Psr7\StreamWrapper` class if you need to use a
292
+ PSR-7 stream as a PHP stream resource.
293
+
294
+ Use the `GuzzleHttp\Psr7\StreamWrapper::getResource()` method to create a PHP
295
+ stream from a PSR-7 stream.
296
+
297
+ ```php
298
+ use GuzzleHttp\Psr7\StreamWrapper;
299
+
300
+ $stream = GuzzleHttp\Psr7\stream_for('hello!');
301
+ $resource = StreamWrapper::getResource($stream);
302
+ echo fread($resource, 6); // outputs hello!
303
+ ```
304
+
305
+
306
+ # Function API
307
+
308
+ There are various functions available under the `GuzzleHttp\Psr7` namespace.
309
+
310
+
311
+ ## `function str`
312
+
313
+ `function str(MessageInterface $message)`
314
+
315
+ Returns the string representation of an HTTP message.
316
+
317
+ ```php
318
+ $request = new GuzzleHttp\Psr7\Request('GET', 'http://example.com');
319
+ echo GuzzleHttp\Psr7\str($request);
320
+ ```
321
+
322
+
323
+ ## `function uri_for`
324
+
325
+ `function uri_for($uri)`
326
+
327
+ This function accepts a string or `Psr\Http\Message\UriInterface` and returns a
328
+ UriInterface for the given value. If the value is already a `UriInterface`, it
329
+ is returned as-is.
330
+
331
+ ```php
332
+ $uri = GuzzleHttp\Psr7\uri_for('http://example.com');
333
+ assert($uri === GuzzleHttp\Psr7\uri_for($uri));
334
+ ```
335
+
336
+
337
+ ## `function stream_for`
338
+
339
+ `function stream_for($resource = '', array $options = [])`
340
+
341
+ Create a new stream based on the input type.
342
+
343
+ Options is an associative array that can contain the following keys:
344
+
345
+ * - metadata: Array of custom metadata.
346
+ * - size: Size of the stream.
347
+
348
+ This method accepts the following `$resource` types:
349
+
350
+ - `Psr\Http\Message\StreamInterface`: Returns the value as-is.
351
+ - `string`: Creates a stream object that uses the given string as the contents.
352
+ - `resource`: Creates a stream object that wraps the given PHP stream resource.
353
+ - `Iterator`: If the provided value implements `Iterator`, then a read-only
354
+ stream object will be created that wraps the given iterable. Each time the
355
+ stream is read from, data from the iterator will fill a buffer and will be
356
+ continuously called until the buffer is equal to the requested read size.
357
+ Subsequent read calls will first read from the buffer and then call `next`
358
+ on the underlying iterator until it is exhausted.
359
+ - `object` with `__toString()`: If the object has the `__toString()` method,
360
+ the object will be cast to a string and then a stream will be returned that
361
+ uses the string value.
362
+ - `NULL`: When `null` is passed, an empty stream object is returned.
363
+ - `callable` When a callable is passed, a read-only stream object will be
364
+ created that invokes the given callable. The callable is invoked with the
365
+ number of suggested bytes to read. The callable can return any number of
366
+ bytes, but MUST return `false` when there is no more data to return. The
367
+ stream object that wraps the callable will invoke the callable until the
368
+ number of requested bytes are available. Any additional bytes will be
369
+ buffered and used in subsequent reads.
370
+
371
+ ```php
372
+ $stream = GuzzleHttp\Psr7\stream_for('foo');
373
+ $stream = GuzzleHttp\Psr7\stream_for(fopen('/path/to/file', 'r'));
374
+
375
+ $generator = function ($bytes) {
376
+ for ($i = 0; $i < $bytes; $i++) {
377
+ yield ' ';
378
+ }
379
+ }
380
+
381
+ $stream = GuzzleHttp\Psr7\stream_for($generator(100));
382
+ ```
383
+
384
+
385
+ ## `function parse_header`
386
+
387
+ `function parse_header($header)`
388
+
389
+ Parse an array of header values containing ";" separated data into an array of
390
+ associative arrays representing the header key value pair data of the header.
391
+ When a parameter does not contain a value, but just contains a key, this
392
+ function will inject a key with a '' string value.
393
+
394
+
395
+ ## `function normalize_header`
396
+
397
+ `function normalize_header($header)`
398
+
399
+ Converts an array of header values that may contain comma separated headers
400
+ into an array of headers with no comma separated values.
401
+
402
+
403
+ ## `function modify_request`
404
+
405
+ `function modify_request(RequestInterface $request, array $changes)`
406
+
407
+ Clone and modify a request with the given changes. This method is useful for
408
+ reducing the number of clones needed to mutate a message.
409
+
410
+ The changes can be one of:
411
+
412
+ - method: (string) Changes the HTTP method.
413
+ - set_headers: (array) Sets the given headers.
414
+ - remove_headers: (array) Remove the given headers.
415
+ - body: (mixed) Sets the given body.
416
+ - uri: (UriInterface) Set the URI.
417
+ - query: (string) Set the query string value of the URI.
418
+ - version: (string) Set the protocol version.
419
+
420
+
421
+ ## `function rewind_body`
422
+
423
+ `function rewind_body(MessageInterface $message)`
424
+
425
+ Attempts to rewind a message body and throws an exception on failure. The body
426
+ of the message will only be rewound if a call to `tell()` returns a value other
427
+ than `0`.
428
+
429
+
430
+ ## `function try_fopen`
431
+
432
+ `function try_fopen($filename, $mode)`
433
+
434
+ Safely opens a PHP stream resource using a filename.
435
+
436
+ When fopen fails, PHP normally raises a warning. This function adds an error
437
+ handler that checks for errors and throws an exception instead.
438
+
439
+
440
+ ## `function copy_to_string`
441
+
442
+ `function copy_to_string(StreamInterface $stream, $maxLen = -1)`
443
+
444
+ Copy the contents of a stream into a string until the given number of bytes
445
+ have been read.
446
+
447
+
448
+ ## `function copy_to_stream`
449
+
450
+ `function copy_to_stream(StreamInterface $source, StreamInterface $dest, $maxLen = -1)`
451
+
452
+ Copy the contents of a stream into another stream until the given number of
453
+ bytes have been read.
454
+
455
+
456
+ ## `function hash`
457
+
458
+ `function hash(StreamInterface $stream, $algo, $rawOutput = false)`
459
+
460
+ Calculate a hash of a Stream. This method reads the entire stream to calculate
461
+ a rolling hash (based on PHP's hash_init functions).
462
+
463
+
464
+ ## `function readline`
465
+
466
+ `function readline(StreamInterface $stream, $maxLength = null)`
467
+
468
+ Read a line from the stream up to the maximum allowed buffer length.
469
+
470
+
471
+ ## `function parse_request`
472
+
473
+ `function parse_request($message)`
474
+
475
+ Parses a request message string into a request object.
476
+
477
+
478
+ ## `function parse_response`
479
+
480
+ `function parse_response($message)`
481
+
482
+ Parses a response message string into a response object.
483
+
484
+
485
+ ## `function parse_query`
486
+
487
+ `function parse_query($str, $urlEncoding = true)`
488
+
489
+ Parse a query string into an associative array.
490
+
491
+ If multiple values are found for the same key, the value of that key value pair
492
+ will become an array. This function does not parse nested PHP style arrays into
493
+ an associative array (e.g., `foo[a]=1&foo[b]=2` will be parsed into
494
+ `['foo[a]' => '1', 'foo[b]' => '2']`).
495
+
496
+
497
+ ## `function build_query`
498
+
499
+ `function build_query(array $params, $encoding = PHP_QUERY_RFC3986)`
500
+
501
+ Build a query string from an array of key value pairs.
502
+
503
+ This function can use the return value of parse_query() to build a query string.
504
+ This function does not modify the provided keys when an array is encountered
505
+ (like http_build_query would).
506
+
507
+
508
+ ## `function mimetype_from_filename`
509
+
510
+ `function mimetype_from_filename($filename)`
511
+
512
+ Determines the mimetype of a file by looking at its extension.
513
+
514
+
515
+ ## `function mimetype_from_extension`
516
+
517
+ `function mimetype_from_extension($extension)`
518
+
519
+ Maps a file extensions to a mimetype.
520
+
521
+
522
+ # Additional URI Methods
523
+
524
+ Aside from the standard `Psr\Http\Message\UriInterface` implementation in form of the `GuzzleHttp\Psr7\Uri` class,
525
+ this library also provides additional functionality when working with URIs as static methods.
526
+
527
+ ## URI Types
528
+
529
+ An instance of `Psr\Http\Message\UriInterface` can either be an absolute URI or a relative reference.
530
+ An absolute URI has a scheme. A relative reference is used to express a URI relative to another URI,
531
+ the base URI. Relative references can be divided into several forms according to
532
+ [RFC 3986 Section 4.2](https://tools.ietf.org/html/rfc3986#section-4.2):
533
+
534
+ - network-path references, e.g. `//example.com/path`
535
+ - absolute-path references, e.g. `/path`
536
+ - relative-path references, e.g. `subpath`
537
+
538
+ The following methods can be used to identify the type of the URI.
539
+
540
+ ### `GuzzleHttp\Psr7\Uri::isAbsolute`
541
+
542
+ `public static function isAbsolute(UriInterface $uri): bool`
543
+
544
+ Whether the URI is absolute, i.e. it has a scheme.
545
+
546
+ ### `GuzzleHttp\Psr7\Uri::isNetworkPathReference`
547
+
548
+ `public static function isNetworkPathReference(UriInterface $uri): bool`
549
+
550
+ Whether the URI is a network-path reference. A relative reference that begins with two slash characters is
551
+ termed an network-path reference.
552
+
553
+ ### `GuzzleHttp\Psr7\Uri::isAbsolutePathReference`
554
+
555
+ `public static function isAbsolutePathReference(UriInterface $uri): bool`
556
+
557
+ Whether the URI is a absolute-path reference. A relative reference that begins with a single slash character is
558
+ termed an absolute-path reference.
559
+
560
+ ### `GuzzleHttp\Psr7\Uri::isRelativePathReference`
561
+
562
+ `public static function isRelativePathReference(UriInterface $uri): bool`
563
+
564
+ Whether the URI is a relative-path reference. A relative reference that does not begin with a slash character is
565
+ termed a relative-path reference.
566
+
567
+ ### `GuzzleHttp\Psr7\Uri::isSameDocumentReference`
568
+
569
+ `public static function isSameDocumentReference(UriInterface $uri, UriInterface $base = null): bool`
570
+
571
+ Whether the URI is a same-document reference. A same-document reference refers to a URI that is, aside from its
572
+ fragment component, identical to the base URI. When no base URI is given, only an empty URI reference
573
+ (apart from its fragment) is considered a same-document reference.
574
+
575
+ ## URI Components
576
+
577
+ Additional methods to work with URI components.
578
+
579
+ ### `GuzzleHttp\Psr7\Uri::isDefaultPort`
580
+
581
+ `public static function isDefaultPort(UriInterface $uri): bool`
582
+
583
+ Whether the URI has the default port of the current scheme. `Psr\Http\Message\UriInterface::getPort` may return null
584
+ or the standard port. This method can be used independently of the implementation.
585
+
586
+ ### `GuzzleHttp\Psr7\Uri::composeComponents`
587
+
588
+ `public static function composeComponents($scheme, $authority, $path, $query, $fragment): string`
589
+
590
+ Composes a URI reference string from its various components according to
591
+ [RFC 3986 Section 5.3](https://tools.ietf.org/html/rfc3986#section-5.3). Usually this method does not need to be called
592
+ manually but instead is used indirectly via `Psr\Http\Message\UriInterface::__toString`.
593
+
594
+ ### `GuzzleHttp\Psr7\Uri::fromParts`
595
+
596
+ `public static function fromParts(array $parts): UriInterface`
597
+
598
+ Creates a URI from a hash of [`parse_url`](http://php.net/manual/en/function.parse-url.php) components.
599
+
600
+
601
+ ### `GuzzleHttp\Psr7\Uri::withQueryValue`
602
+
603
+ `public static function withQueryValue(UriInterface $uri, $key, $value): UriInterface`
604
+
605
+ Creates a new URI with a specific query string value. Any existing query string values that exactly match the
606
+ provided key are removed and replaced with the given key value pair. A value of null will set the query string
607
+ key without a value, e.g. "key" instead of "key=value".
608
+
609
+ ### `GuzzleHttp\Psr7\Uri::withQueryValues`
610
+
611
+ `public static function withQueryValues(UriInterface $uri, array $keyValueArray): UriInterface`
612
+
613
+ Creates a new URI with multiple query string values. It has the same behavior as `withQueryValue()` but for an
614
+ associative array of key => value.
615
+
616
+ ### `GuzzleHttp\Psr7\Uri::withoutQueryValue`
617
+
618
+ `public static function withoutQueryValue(UriInterface $uri, $key): UriInterface`
619
+
620
+ Creates a new URI with a specific query string value removed. Any existing query string values that exactly match the
621
+ provided key are removed.
622
+
623
+ ## Reference Resolution
624
+
625
+ `GuzzleHttp\Psr7\UriResolver` provides methods to resolve a URI reference in the context of a base URI according
626
+ to [RFC 3986 Section 5](https://tools.ietf.org/html/rfc3986#section-5). This is for example also what web browsers
627
+ do when resolving a link in a website based on the current request URI.
628
+
629
+ ### `GuzzleHttp\Psr7\UriResolver::resolve`
630
+
631
+ `public static function resolve(UriInterface $base, UriInterface $rel): UriInterface`
632
+
633
+ Converts the relative URI into a new URI that is resolved against the base URI.
634
+
635
+ ### `GuzzleHttp\Psr7\UriResolver::removeDotSegments`
636
+
637
+ `public static function removeDotSegments(string $path): string`
638
+
639
+ Removes dot segments from a path and returns the new path according to
640
+ [RFC 3986 Section 5.2.4](https://tools.ietf.org/html/rfc3986#section-5.2.4).
641
+
642
+ ### `GuzzleHttp\Psr7\UriResolver::relativize`
643
+
644
+ `public static function relativize(UriInterface $base, UriInterface $target): UriInterface`
645
+
646
+ Returns the target URI as a relative reference from the base URI. This method is the counterpart to resolve():
647
+
648
+ ```php
649
+ (string) $target === (string) UriResolver::resolve($base, UriResolver::relativize($base, $target))
650
+ ```
651
+
652
+ One use-case is to use the current request URI as base URI and then generate relative links in your documents
653
+ to reduce the document size or offer self-contained downloadable document archives.
654
+
655
+ ```php
656
+ $base = new Uri('http://example.com/a/b/');
657
+ echo UriResolver::relativize($base, new Uri('http://example.com/a/b/c')); // prints 'c'.
658
+ echo UriResolver::relativize($base, new Uri('http://example.com/a/x/y')); // prints '../x/y'.
659
+ echo UriResolver::relativize($base, new Uri('http://example.com/a/b/?q')); // prints '?q'.
660
+ echo UriResolver::relativize($base, new Uri('http://example.org/a/b/')); // prints '//example.org/a/b/'.
661
+ ```
662
+
663
+ ## Normalization and Comparison
664
+
665
+ `GuzzleHttp\Psr7\UriNormalizer` provides methods to normalize and compare URIs according to
666
+ [RFC 3986 Section 6](https://tools.ietf.org/html/rfc3986#section-6).
667
+
668
+ ### `GuzzleHttp\Psr7\UriNormalizer::normalize`
669
+
670
+ `public static function normalize(UriInterface $uri, $flags = self::PRESERVING_NORMALIZATIONS): UriInterface`
671
+
672
+ Returns a normalized URI. The scheme and host component are already normalized to lowercase per PSR-7 UriInterface.
673
+ This methods adds additional normalizations that can be configured with the `$flags` parameter which is a bitmask
674
+ of normalizations to apply. The following normalizations are available:
675
+
676
+ - `UriNormalizer::PRESERVING_NORMALIZATIONS`
677
+
678
+ Default normalizations which only include the ones that preserve semantics.
679
+
680
+ - `UriNormalizer::CAPITALIZE_PERCENT_ENCODING`
681
+
682
+ All letters within a percent-encoding triplet (e.g., "%3A") are case-insensitive, and should be capitalized.
683
+
684
+ Example: `http://example.org/a%c2%b1b` → `http://example.org/a%C2%B1b`
685
+
686
+ - `UriNormalizer::DECODE_UNRESERVED_CHARACTERS`
687
+
688
+ Decodes percent-encoded octets of unreserved characters. For consistency, percent-encoded octets in the ranges of
689
+ ALPHA (%41–%5A and %61–%7A), DIGIT (%30–%39), hyphen (%2D), period (%2E), underscore (%5F), or tilde (%7E) should
690
+ not be created by URI producers and, when found in a URI, should be decoded to their corresponding unreserved
691
+ characters by URI normalizers.
692
+
693
+ Example: `http://example.org/%7Eusern%61me/` → `http://example.org/~username/`
694
+
695
+ - `UriNormalizer::CONVERT_EMPTY_PATH`
696
+
697
+ Converts the empty path to "/" for http and https URIs.
698
+
699
+ Example: `http://example.org` → `http://example.org/`
700
+
701
+ - `UriNormalizer::REMOVE_DEFAULT_HOST`
702
+
703
+ Removes the default host of the given URI scheme from the URI. Only the "file" scheme defines the default host
704
+ "localhost". All of `file:/myfile`, `file:///myfile`, and `file://localhost/myfile` are equivalent according to
705
+ RFC 3986.
706
+
707
+ Example: `file://localhost/myfile` → `file:///myfile`
708
+
709
+ - `UriNormalizer::REMOVE_DEFAULT_PORT`
710
+
711
+ Removes the default port of the given URI scheme from the URI.
712
+
713
+ Example: `http://example.org:80/` → `http://example.org/`
714
+
715
+ - `UriNormalizer::REMOVE_DOT_SEGMENTS`
716
+
717
+ Removes unnecessary dot-segments. Dot-segments in relative-path references are not removed as it would
718
+ change the semantics of the URI reference.
719
+
720
+ Example: `http://example.org/../a/b/../c/./d.html` → `http://example.org/a/c/d.html`
721
+
722
+ - `UriNormalizer::REMOVE_DUPLICATE_SLASHES`
723
+
724
+ Paths which include two or more adjacent slashes are converted to one. Webservers usually ignore duplicate slashes
725
+ and treat those URIs equivalent. But in theory those URIs do not need to be equivalent. So this normalization
726
+ may change the semantics. Encoded slashes (%2F) are not removed.
727
+
728
+ Example: `http://example.org//foo///bar.html` → `http://example.org/foo/bar.html`
729
+
730
+ - `UriNormalizer::SORT_QUERY_PARAMETERS`
731
+
732
+ Sort query parameters with their values in alphabetical order. However, the order of parameters in a URI may be
733
+ significant (this is not defined by the standard). So this normalization is not safe and may change the semantics
734
+ of the URI.
735
+
736
+ Example: `?lang=en&article=fred` → `?article=fred&lang=en`
737
+
738
+ ### `GuzzleHttp\Psr7\UriNormalizer::isEquivalent`
739
+
740
+ `public static function isEquivalent(UriInterface $uri1, UriInterface $uri2, $normalizations = self::PRESERVING_NORMALIZATIONS): bool`
741
+
742
+ Whether two URIs can be considered equivalent. Both URIs are normalized automatically before comparison with the given
743
+ `$normalizations` bitmask. The method also accepts relative URI references and returns true when they are equivalent.
744
+ This of course assumes they will be resolved against the same base URI. If this is not the case, determination of
745
+ equivalence or difference of relative references does not mean anything.
vendor/guzzlehttp/psr7/src/AppendStream.php ADDED
@@ -0,0 +1,241 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\StreamInterface;
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
+
20
+ /**
21
+ * @param StreamInterface[] $streams Streams to decorate. Each stream must
22
+ * be readable.
23
+ */
24
+ public function __construct(array $streams = [])
25
+ {
26
+ foreach ($streams as $stream) {
27
+ $this->addStream($stream);
28
+ }
29
+ }
30
+
31
+ public function __toString()
32
+ {
33
+ try {
34
+ $this->rewind();
35
+ return $this->getContents();
36
+ } catch (\Exception $e) {
37
+ return '';
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Add a stream to the AppendStream
43
+ *
44
+ * @param StreamInterface $stream Stream to append. Must be readable.
45
+ *
46
+ * @throws \InvalidArgumentException if the stream is not readable
47
+ */
48
+ public function addStream(StreamInterface $stream)
49
+ {
50
+ if (!$stream->isReadable()) {
51
+ throw new \InvalidArgumentException('Each stream must be readable');
52
+ }
53
+
54
+ // The stream is only seekable if all streams are seekable
55
+ if (!$stream->isSeekable()) {
56
+ $this->seekable = false;
57
+ }
58
+
59
+ $this->streams[] = $stream;
60
+ }
61
+
62
+ public function getContents()
63
+ {
64
+ return copy_to_string($this);
65
+ }
66
+
67
+ /**
68
+ * Closes each attached stream.
69
+ *
70
+ * {@inheritdoc}
71
+ */
72
+ public function close()
73
+ {
74
+ $this->pos = $this->current = 0;
75
+ $this->seekable = true;
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
+ * Returns null as it's not clear which underlying stream resource to return.
88
+ *
89
+ * {@inheritdoc}
90
+ */
91
+ public function detach()
92
+ {
93
+ $this->pos = $this->current = 0;
94
+ $this->seekable = true;
95
+
96
+ foreach ($this->streams as $stream) {
97
+ $stream->detach();
98
+ }
99
+
100
+ $this->streams = [];
101
+ }
102
+
103
+ public function tell()
104
+ {
105
+ return $this->pos;
106
+ }
107
+
108
+ /**
109
+ * Tries to calculate the size by adding the size of each stream.
110
+ *
111
+ * If any of the streams do not return a valid number, then the size of the
112
+ * append stream cannot be determined and null is returned.
113
+ *
114
+ * {@inheritdoc}
115
+ */
116
+ public function getSize()
117
+ {
118
+ $size = 0;
119
+
120
+ foreach ($this->streams as $stream) {
121
+ $s = $stream->getSize();
122
+ if ($s === null) {
123
+ return null;
124
+ }
125
+ $size += $s;
126
+ }
127
+
128
+ return $size;
129
+ }
130
+
131
+ public function eof()
132
+ {
133
+ return !$this->streams ||
134
+ ($this->current >= count($this->streams) - 1 &&
135
+ $this->streams[$this->current]->eof());
136
+ }
137
+
138
+ public function rewind()
139
+ {
140
+ $this->seek(0);
141
+ }
142
+
143
+ /**
144
+ * Attempts to seek to the given position. Only supports SEEK_SET.
145
+ *
146
+ * {@inheritdoc}
147
+ */
148
+ public function seek($offset, $whence = SEEK_SET)
149
+ {
150
+ if (!$this->seekable) {
151
+ throw new \RuntimeException('This AppendStream is not seekable');
152
+ } elseif ($whence !== SEEK_SET) {
153
+ throw new \RuntimeException('The AppendStream can only seek with SEEK_SET');
154
+ }
155
+
156
+ $this->pos = $this->current = 0;
157
+
158
+ // Rewind each stream
159
+ foreach ($this->streams as $i => $stream) {
160
+ try {
161
+ $stream->rewind();
162
+ } catch (\Exception $e) {
163
+ throw new \RuntimeException('Unable to seek stream '
164
+ . $i . ' of the AppendStream', 0, $e);
165
+ }
166
+ }
167
+
168
+ // Seek to the actual position by reading from each stream
169
+ while ($this->pos < $offset && !$this->eof()) {
170
+ $result = $this->read(min(8096, $offset - $this->pos));
171
+ if ($result === '') {
172
+ break;
173
+ }
174
+ }
175
+ }
176
+
177
+ /**
178
+ * Reads from all of the appended streams until the length is met or EOF.
179
+ *
180
+ * {@inheritdoc}
181
+ */
182
+ public function read($length)
183
+ {
184
+ $buffer = '';
185
+ $total = count($this->streams) - 1;
186
+ $remaining = $length;
187
+ $progressToNext = false;
188
+
189
+ while ($remaining > 0) {
190
+
191
+ // Progress to the next stream if needed.
192
+ if ($progressToNext || $this->streams[$this->current]->eof()) {
193
+ $progressToNext = false;
194
+ if ($this->current === $total) {
195
+ break;
196
+ }
197
+ $this->current++;
198
+ }
199
+
200
+ $result = $this->streams[$this->current]->read($remaining);
201
+
202
+ // Using a loose comparison here to match on '', false, and null
203
+ if ($result == null) {
204
+ $progressToNext = true;
205
+ continue;
206
+ }
207
+
208
+ $buffer .= $result;
209
+ $remaining = $length - strlen($buffer);
210
+ }
211
+
212
+ $this->pos += strlen($buffer);
213
+
214
+ return $buffer;
215
+ }
216
+
217
+ public function isReadable()
218
+ {
219
+ return true;
220
+ }
221
+
222
+ public function isWritable()
223
+ {
224
+ return false;
225
+ }
226
+
227
+ public function isSeekable()
228
+ {
229
+ return $this->seekable;
230
+ }
231
+
232
+ public function write($string)
233
+ {
234
+ throw new \RuntimeException('Cannot write to an AppendStream');
235
+ }
236
+
237
+ public function getMetadata($key = null)
238
+ {
239
+ return $key ? null : [];
240
+ }
241
+ }
vendor/guzzlehttp/psr7/src/BufferStream.php ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\StreamInterface;
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
+ class BufferStream implements StreamInterface
15
+ {
16
+ private $hwm;
17
+ private $buffer = '';
18
+
19
+ /**
20
+ * @param int $hwm High water mark, representing the preferred maximum
21
+ * buffer size. If the size of the buffer exceeds the high
22
+ * water mark, then calls to write will continue to succeed
23
+ * but will return false to inform writers to slow down
24
+ * until the buffer has been drained by reading from it.
25
+ */
26
+ public function __construct($hwm = 16384)
27
+ {
28
+ $this->hwm = $hwm;
29
+ }
30
+
31
+ public function __toString()
32
+ {
33
+ return $this->getContents();
34
+ }
35
+
36
+ public function getContents()
37
+ {
38
+ $buffer = $this->buffer;
39
+ $this->buffer = '';
40
+
41
+ return $buffer;
42
+ }
43
+
44
+ public function close()
45
+ {
46
+ $this->buffer = '';
47
+ }
48
+
49
+ public function detach()
50
+ {
51
+ $this->close();
52
+ }
53
+
54
+ public function getSize()
55
+ {
56
+ return strlen($this->buffer);
57
+ }
58
+
59
+ public function isReadable()
60
+ {
61
+ return true;
62
+ }
63
+
64
+ public function isWritable()
65
+ {
66
+ return true;
67
+ }
68
+
69
+ public function isSeekable()
70
+ {
71
+ return false;
72
+ }
73
+
74
+ public function rewind()
75
+ {
76
+ $this->seek(0);
77
+ }
78
+
79
+ public function seek($offset, $whence = SEEK_SET)
80
+ {
81
+ throw new \RuntimeException('Cannot seek a BufferStream');
82
+ }
83
+
84
+ public function eof()
85
+ {
86
+ return strlen($this->buffer) === 0;
87
+ }
88
+
89
+ public function tell()
90
+ {
91
+ throw new \RuntimeException('Cannot determine the position of a BufferStream');
92
+ }
93
+
94
+ /**
95
+ * Reads data from the buffer.
96
+ */
97
+ public function read($length)
98
+ {
99
+ $currentLength = strlen($this->buffer);
100
+
101
+ if ($length >= $currentLength) {
102
+ // No need to slice the buffer because we don't have enough data.
103
+ $result = $this->buffer;
104
+ $this->buffer = '';
105
+ } else {
106
+ // Slice up the result to provide a subset of the buffer.
107
+ $result = substr($this->buffer, 0, $length);
108
+ $this->buffer = substr($this->buffer, $length);
109
+ }
110
+
111
+ return $result;
112
+ }
113
+
114
+ /**
115
+ * Writes data to the buffer.
116
+ */
117
+ public function write($string)
118
+ {
119
+ $this->buffer .= $string;
120
+
121
+ // TODO: What should happen here?
122
+ if (strlen($this->buffer) >= $this->hwm) {
123
+ return false;
124
+ }
125
+
126
+ return strlen($string);
127
+ }
128
+
129
+ public function getMetadata($key = null)
130
+ {
131
+ if ($key == 'hwm') {
132
+ return $this->hwm;
133
+ }
134
+
135
+ return $key ? null : [];
136
+ }
137
+ }
vendor/guzzlehttp/psr7/src/CachingStream.php ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\StreamInterface;
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
+ public function rewind()
40
+ {
41
+ $this->seek(0);
42
+ }
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
+ } elseif ($whence == SEEK_END) {
51
+ $size = $this->remoteStream->getSize();
52
+ if ($size === null) {
53
+ $size = $this->cacheEntireStream();
54
+ }
55
+ $byte = $size + $offset;
56
+ } else {
57
+ throw new \InvalidArgumentException('Invalid whence');
58
+ }
59
+
60
+ $diff = $byte - $this->stream->getSize();
61
+
62
+ if ($diff > 0) {
63
+ // Read the remoteStream until we have read in at least the amount
64
+ // of bytes requested, or we reach the end of the file.
65
+ while ($diff > 0 && !$this->remoteStream->eof()) {
66
+ $this->read($diff);
67
+ $diff = $byte - $this->stream->getSize();
68
+ }
69
+ } else {
70
+ // We can just do a normal seek since we've already seen this byte.
71
+ $this->stream->seek($byte);
72
+ }
73
+ }
74
+
75
+ public function read($length)
76
+ {
77
+ // Perform a regular read on any previously read data from the buffer
78
+ $data = $this->stream->read($length);
79
+ $remaining = $length - strlen($data);
80
+
81
+ // More data was requested so read from the remote stream
82
+ if ($remaining) {
83
+ // If data was written to the buffer in a position that would have
84
+ // been filled from the remote stream, then we must skip bytes on
85
+ // the remote stream to emulate overwriting bytes from that
86
+ // position. This mimics the behavior of other PHP stream wrappers.
87
+ $remoteData = $this->remoteStream->read(
88
+ $remaining + $this->skipReadBytes
89
+ );
90
+
91
+ if ($this->skipReadBytes) {
92
+ $len = strlen($remoteData);
93
+ $remoteData = substr($remoteData, $this->skipReadBytes);
94
+ $this->skipReadBytes = max(0, $this->skipReadBytes - $len);
95
+ }
96
+
97
+ $data .= $remoteData;
98
+ $this->stream->write($remoteData);
99
+ }
100
+
101
+ return $data;
102
+ }
103
+
104
+ public function write($string)
105
+ {
106
+ // When appending to the end of the currently read stream, you'll want
107
+ // to skip bytes from being read from the remote stream to emulate
108
+ // other stream wrappers. Basically replacing bytes of data of a fixed
109
+ // length.
110
+ $overflow = (strlen($string) + $this->tell()) - $this->remoteStream->tell();
111
+ if ($overflow > 0) {
112
+ $this->skipReadBytes += $overflow;
113
+ }
114
+
115
+ return $this->stream->write($string);
116
+ }
117
+
118
+ public function eof()
119
+ {
120
+ return $this->stream->eof() && $this->remoteStream->eof();
121
+ }
122
+
123
+ /**
124
+ * Close both the remote stream and buffer stream
125
+ */
126
+ public function close()
127
+ {
128
+ $this->remoteStream->close() && $this->stream->close();
129
+ }
130
+
131
+ private function cacheEntireStream()
132
+ {
133
+ $target = new FnStream(['write' => 'strlen']);
134
+ copy_to_stream($this, $target);
135
+
136
+ return $this->tell();
137
+ }
138
+ }
vendor/guzzlehttp/psr7/src/DroppingStream.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\StreamInterface;
5
+
6
+ /**
7
+ * Stream decorator that begins dropping data once the size of the underlying
8
+ * stream becomes too full.
9
+ */
10
+ class DroppingStream implements StreamInterface
11
+ {
12
+ use StreamDecoratorTrait;
13
+
14
+ private $maxLength;
15
+
16
+ /**
17
+ * @param StreamInterface $stream Underlying stream to decorate.
18
+ * @param int $maxLength Maximum size before dropping data.
19
+ */
20
+ public function __construct(StreamInterface $stream, $maxLength)
21
+ {
22
+ $this->stream = $stream;
23
+ $this->maxLength = $maxLength;
24
+ }
25
+
26
+ public function write($string)
27
+ {
28
+ $diff = $this->maxLength - $this->stream->getSize();
29
+
30
+ // Begin returning 0 when the underlying stream is too large.
31
+ if ($diff <= 0) {
32
+ return 0;
33
+ }
34
+
35
+ // Write the stream or a subset of the stream if needed.
36
+ if (strlen($string) < $diff) {
37
+ return $this->stream->write($string);
38
+ }
39
+
40
+ return $this->stream->write(substr($string, 0, $diff));
41
+ }
42
+ }
vendor/guzzlehttp/psr7/src/FnStream.php ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\StreamInterface;
5
+
6
+ /**
7
+ * Compose stream implementations based on a hash of functions.
8
+ *
9
+ * Allows for easy testing and extension of a provided stream without needing
10
+ * to create a concrete class for a simple extension point.
11
+ */
12
+ class FnStream implements StreamInterface
13
+ {
14
+ /** @var array */
15
+ private $methods;
16
+
17
+ /** @var array Methods that must be implemented in the given array */
18
+ private static $slots = ['__toString', 'close', 'detach', 'rewind',
19
+ 'getSize', 'tell', 'eof', 'isSeekable', 'seek', 'isWritable', 'write',
20
+ 'isReadable', 'read', 'getContents', 'getMetadata'];
21
+
22
+ /**
23
+ * @param array $methods Hash of method name to a callable.
24
+ */
25
+ public function __construct(array $methods)
26
+ {
27
+ $this->methods = $methods;
28
+
29
+ // Create the functions on the class
30
+ foreach ($methods as $name => $fn) {
31
+ $this->{'_fn_' . $name} = $fn;
32
+ }
33
+ }
34
+
35
+ /**
36
+ * Lazily determine which methods are not implemented.
37
+ * @throws \BadMethodCallException
38
+ */
39
+ public function __get($name)
40
+ {
41
+ throw new \BadMethodCallException(str_replace('_fn_', '', $name)
42
+ . '() is not implemented in the FnStream');
43
+ }
44
+
45
+ /**
46
+ * The close method is called on the underlying stream only if possible.
47
+ */
48
+ public function __destruct()
49
+ {
50
+ if (isset($this->_fn_close)) {
51
+ call_user_func($this->_fn_close);
52
+ }
53
+ }
54
+
55
+ /**
56
+ * An unserialize would allow the __destruct to run when the unserialized value goes out of scope.
57
+ * @throws \LogicException
58
+ */
59
+ public function __wakeup()
60
+ {
61
+ throw new \LogicException('FnStream should never be unserialized');
62
+ }
63
+
64
+ /**
65
+ * Adds custom functionality to an underlying stream by intercepting
66
+ * specific method calls.
67
+ *
68
+ * @param StreamInterface $stream Stream to decorate
69
+ * @param array $methods Hash of method name to a closure
70
+ *
71
+ * @return FnStream
72
+ */
73
+ public static function decorate(StreamInterface $stream, array $methods)
74
+ {
75
+ // If any of the required methods were not provided, then simply
76
+ // proxy to the decorated stream.
77
+ foreach (array_diff(self::$slots, array_keys($methods)) as $diff) {
78
+ $methods[$diff] = [$stream, $diff];
79
+ }
80
+
81
+ return new self($methods);
82
+ }
83
+
84
+ public function __toString()
85
+ {
86
+ return call_user_func($this->_fn___toString);
87
+ }
88
+
89
+ public function close()
90
+ {
91
+ return call_user_func($this->_fn_close);
92
+ }
93
+
94
+ public function detach()
95
+ {
96
+ return call_user_func($this->_fn_detach);
97
+ }
98
+
99
+ public function getSize()
100
+ {
101
+ return call_user_func($this->_fn_getSize);
102
+ }
103
+
104
+ public function tell()
105
+ {
106
+ return call_user_func($this->_fn_tell);
107
+ }
108
+
109
+ public function eof()
110
+ {
111
+ return call_user_func($this->_fn_eof);
112
+ }
113
+
114
+ public function isSeekable()
115
+ {
116
+ return call_user_func($this->_fn_isSeekable);
117
+ }
118
+
119
+ public function rewind()
120
+ {
121
+ call_user_func($this->_fn_rewind);
122
+ }
123
+
124
+ public function seek($offset, $whence = SEEK_SET)
125
+ {
126
+ call_user_func($this->_fn_seek, $offset, $whence);
127
+ }
128
+
129
+ public function isWritable()
130
+ {
131
+ return call_user_func($this->_fn_isWritable);
132
+ }
133
+
134
+ public function write($string)
135
+ {
136
+ return call_user_func($this->_fn_write, $string);
137
+ }
138
+
139
+ public function isReadable()
140
+ {
141
+ return call_user_func($this->_fn_isReadable);
142
+ }
143
+
144
+ public function read($length)
145
+ {
146
+ return call_user_func($this->_fn_read, $length);
147
+ }
148
+
149
+ public function getContents()
150
+ {
151
+ return call_user_func($this->_fn_getContents);
152
+ }
153
+
154
+ public function getMetadata($key = null)
155
+ {
156
+ return call_user_func($this->_fn_getMetadata, $key);
157
+ }
158
+ }
vendor/guzzlehttp/psr7/src/InflateStream.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\StreamInterface;
5
+
6
+ /**
7
+ * Uses PHP's zlib.inflate filter to inflate deflate or gzipped content.
8
+ *
9
+ * This stream decorator skips the first 10 bytes of the given stream to remove
10
+ * the gzip header, converts the provided stream to a PHP stream resource,
11
+ * then appends the zlib.inflate filter. The stream is then converted back
12
+ * to a Guzzle stream resource to be used as a Guzzle stream.
13
+ *
14
+ * @link http://tools.ietf.org/html/rfc1952
15
+ * @link http://php.net/manual/en/filters.compression.php
16
+ */
17
+ class InflateStream implements StreamInterface
18
+ {
19
+ use StreamDecoratorTrait;
20
+
21
+ public function __construct(StreamInterface $stream)
22
+ {
23
+ // read the first 10 bytes, ie. gzip header
24
+ $header = $stream->read(10);
25
+ $filenameHeaderLength = $this->getLengthOfPossibleFilenameHeader($stream, $header);
26
+ // Skip the header, that is 10 + length of filename + 1 (nil) bytes
27
+ $stream = new LimitStream($stream, -1, 10 + $filenameHeaderLength);
28
+ $resource = StreamWrapper::getResource($stream);
29
+ stream_filter_append($resource, 'zlib.inflate', STREAM_FILTER_READ);
30
+ $this->stream = $stream->isSeekable() ? new Stream($resource) : new NoSeekStream(new Stream($resource));
31
+ }
32
+
33
+ /**
34
+ * @param StreamInterface $stream
35
+ * @param $header
36
+ * @return int
37
+ */
38
+ private function getLengthOfPossibleFilenameHeader(StreamInterface $stream, $header)
39
+ {
40
+ $filename_header_length = 0;
41
+
42
+ if (substr(bin2hex($header), 6, 2) === '08') {
43
+ // we have a filename, read until nil
44
+ $filename_header_length = 1;
45
+ while ($stream->read(1) !== chr(0)) {
46
+ $filename_header_length++;
47
+ }
48
+ }
49
+
50
+ return $filename_header_length;
51
+ }
52
+ }
vendor/guzzlehttp/psr7/src/LazyOpenStream.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\StreamInterface;
5
+
6
+ /**
7
+ * Lazily reads or writes to a file that is opened only after an IO operation
8
+ * take place on the stream.
9
+ */
10
+ class LazyOpenStream implements StreamInterface
11
+ {
12
+ use StreamDecoratorTrait;
13
+
14
+ /** @var string File to open */
15
+ private $filename;
16
+
17
+ /** @var string $mode */
18
+ private $mode;
19
+
20
+ /**
21
+ * @param string $filename File to lazily open
22
+ * @param string $mode fopen mode to use when opening the stream
23
+ */
24
+ public function __construct($filename, $mode)
25
+ {
26
+ $this->filename = $filename;
27
+ $this->mode = $mode;
28
+ }
29
+
30
+ /**
31
+ * Creates the underlying stream lazily when required.
32
+ *
33
+ * @return StreamInterface
34
+ */
35
+ protected function createStream()
36
+ {
37
+ return stream_for(try_fopen($this->filename, $this->mode));
38
+ }
39
+ }
vendor/guzzlehttp/psr7/src/LimitStream.php ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\StreamInterface;
5
+
6
+
7
+ /**
8
+ * Decorator used to return only a subset of a stream
9
+ */
10
+ class LimitStream implements StreamInterface
11
+ {
12
+ use StreamDecoratorTrait;
13
+
14
+ /** @var int Offset to start reading from */
15
+ private $offset;
16
+
17
+ /** @var int Limit the number of bytes that can be read */
18
+ private $limit;
19
+
20
+ /**
21
+ * @param StreamInterface $stream Stream to wrap
22
+ * @param int $limit Total number of bytes to allow to be read
23
+ * from the stream. Pass -1 for no limit.
24
+ * @param int $offset Position to seek to before reading (only
25
+ * works on seekable streams).
26
+ */
27
+ public function __construct(
28
+ StreamInterface $stream,
29
+ $limit = -1,
30
+ $offset = 0
31
+ ) {
32
+ $this->stream = $stream;
33
+ $this->setLimit($limit);
34
+ $this->setOffset($offset);
35
+ }
36
+
37
+ public function eof()
38
+ {
39
+ // Always return true if the underlying stream is EOF
40
+ if ($this->stream->eof()) {
41
+ return true;
42
+ }
43
+
44
+ // No limit and the underlying stream is not at EOF
45
+ if ($this->limit == -1) {
46
+ return false;
47
+ }
48
+
49
+ return $this->stream->tell() >= $this->offset + $this->limit;
50
+ }
51
+
52
+ /**
53
+ * Returns the size of the limited subset of data
54
+ * {@inheritdoc}
55
+ */
56
+ public function getSize()
57
+ {
58
+ if (null === ($length = $this->stream->getSize())) {
59
+ return null;
60
+ } elseif ($this->limit == -1) {
61
+ return $length - $this->offset;
62
+ } else {
63
+ return min($this->limit, $length - $this->offset);
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Allow for a bounded seek on the read limited stream
69
+ * {@inheritdoc}
70
+ */
71
+ public function seek($offset, $whence = SEEK_SET)
72
+ {
73
+ if ($whence !== SEEK_SET || $offset < 0) {
74
+ throw new \RuntimeException(sprintf(
75
+ 'Cannot seek to offset % with whence %s',
76
+ $offset,
77
+ $whence
78
+ ));
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
+ $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
+ * @throws \RuntimeException if the stream cannot be seeked.
107
+ */
108
+ public function setOffset($offset)
109
+ {
110
+ $current = $this->stream->tell();
111
+
112
+ if ($current !== $offset) {
113
+ // If the stream cannot seek to the offset position, then read to it
114
+ if ($this->stream->isSeekable()) {
115
+ $this->stream->seek($offset);
116
+ } elseif ($current > $offset) {
117
+ throw new \RuntimeException("Could not seek to stream offset $offset");
118
+ } else {
119
+ $this->stream->read($offset - $current);
120
+ }
121
+ }
122
+
123
+ $this->offset = $offset;
124
+ }
125
+
126
+ /**
127
+ * Set the limit of bytes that the decorator allows to be read from the
128
+ * stream.
129
+ *
130
+ * @param int $limit Number of bytes to allow to be read from the stream.
131
+ * Use -1 for no limit.
132
+ */
133
+ public function setLimit($limit)
134
+ {
135
+ $this->limit = $limit;
136
+ }
137
+
138
+ public function read($length)
139
+ {
140
+ if ($this->limit == -1) {
141
+ return $this->stream->read($length);
142
+ }
143
+
144
+ // Check if the current position is less than the total allowed
145
+ // bytes + original offset
146
+ $remaining = ($this->offset + $this->limit) - $this->stream->tell();
147
+ if ($remaining > 0) {
148
+ // Only return the amount of requested data, ensuring that the byte
149
+ // limit is not exceeded
150
+ return $this->stream->read(min($remaining, $length));
151
+ }
152
+
153
+ return '';
154
+ }
155
+ }
vendor/guzzlehttp/psr7/src/MessageTrait.php ADDED
@@ -0,0 +1,183 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\StreamInterface;
5
+
6
+ /**
7
+ * Trait implementing functionality common to requests and responses.
8
+ */
9
+ trait MessageTrait
10
+ {
11
+ /** @var array Map of all registered headers, as original name => array of values */
12
+ private $headers = [];
13
+
14
+ /** @var array Map of lowercase header name => original name at registration */
15
+ private $headerNames = [];
16
+
17
+ /** @var string */
18
+ private $protocol = '1.1';
19
+
20
+ /** @var StreamInterface */
21
+ private $stream;
22
+
23
+ public function getProtocolVersion()
24
+ {
25
+ return $this->protocol;
26
+ }
27
+
28
+ public function withProtocolVersion($version)
29
+ {
30
+ if ($this->protocol === $version) {
31
+ return $this;
32
+ }
33
+
34
+ $new = clone $this;
35
+ $new->protocol = $version;
36
+ return $new;
37
+ }
38
+
39
+ public function getHeaders()
40
+ {
41
+ return $this->headers;
42
+ }
43
+
44
+ public function hasHeader($header)
45
+ {
46
+ return isset($this->headerNames[strtolower($header)]);
47
+ }
48
+
49
+ public function getHeader($header)
50
+ {
51
+ $header = strtolower($header);
52
+
53
+ if (!isset($this->headerNames[$header])) {
54
+ return [];
55
+ }
56
+
57
+ $header = $this->headerNames[$header];
58
+
59
+ return $this->headers[$header];
60
+ }
61
+
62
+ public function getHeaderLine($header)
63
+ {
64
+ return implode(', ', $this->getHeader($header));
65
+ }
66
+
67
+ public function withHeader($header, $value)
68
+ {
69
+ if (!is_array($value)) {
70
+ $value = [$value];
71
+ }
72
+
73
+ $value = $this->trimHeaderValues($value);
74
+ $normalized = strtolower($header);
75
+
76
+ $new = clone $this;
77
+ if (isset($new->headerNames[$normalized])) {
78
+ unset($new->headers[$new->headerNames[$normalized]]);
79
+ }
80
+ $new->headerNames[$normalized] = $header;
81
+ $new->headers[$header] = $value;
82
+
83
+ return $new;
84
+ }
85
+
86
+ public function withAddedHeader($header, $value)
87
+ {
88
+ if (!is_array($value)) {
89
+ $value = [$value];
90
+ }
91
+
92
+ $value = $this->trimHeaderValues($value);
93
+ $normalized = strtolower($header);
94
+
95
+ $new = clone $this;
96
+ if (isset($new->headerNames[$normalized])) {
97
+ $header = $this->headerNames[$normalized];
98
+ $new->headers[$header] = array_merge($this->headers[$header], $value);
99
+ } else {
100
+ $new->headerNames[$normalized] = $header;
101
+ $new->headers[$header] = $value;
102
+ }
103
+
104
+ return $new;
105
+ }
106
+
107
+ public function withoutHeader($header)
108
+ {
109
+ $normalized = strtolower($header);
110
+
111
+ if (!isset($this->headerNames[$normalized])) {
112
+ return $this;
113
+ }
114
+
115
+ $header = $this->headerNames[$normalized];
116
+
117
+ $new = clone $this;
118
+ unset($new->headers[$header], $new->headerNames[$normalized]);
119
+
120
+ return $new;
121
+ }
122
+
123
+ public function getBody()
124
+ {
125
+ if (!$this->stream) {
126
+ $this->stream = stream_for('');
127
+ }
128
+
129
+ return $this->stream;
130
+ }
131
+
132
+ public function withBody(StreamInterface $body)
133
+ {
134
+ if ($body === $this->stream) {
135
+ return $this;
136
+ }
137
+
138
+ $new = clone $this;
139
+ $new->stream = $body;
140
+ return $new;
141
+ }
142
+
143
+ private function setHeaders(array $headers)
144
+ {
145
+ $this->headerNames = $this->headers = [];
146
+ foreach ($headers as $header => $value) {
147
+ if (!is_array($value)) {
148
+ $value = [$value];
149
+ }
150
+
151
+ $value = $this->trimHeaderValues($value);
152
+ $normalized = strtolower($header);
153
+ if (isset($this->headerNames[$normalized])) {
154
+ $header = $this->headerNames[$normalized];
155
+ $this->headers[$header] = array_merge($this->headers[$header], $value);
156
+ } else {
157
+ $this->headerNames[$normalized] = $header;
158
+ $this->headers[$header] = $value;
159
+ }
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Trims whitespace from the header values.
165
+ *
166
+ * Spaces and tabs ought to be excluded by parsers when extracting the field value from a header field.
167
+ *
168
+ * header-field = field-name ":" OWS field-value OWS
169
+ * OWS = *( SP / HTAB )
170
+ *
171
+ * @param string[] $values Header values
172
+ *
173
+ * @return string[] Trimmed header values
174
+ *
175
+ * @see https://tools.ietf.org/html/rfc7230#section-3.2.4
176
+ */
177
+ private function trimHeaderValues(array $values)
178
+ {
179
+ return array_map(function ($value) {
180
+ return trim($value, " \t");
181
+ }, $values);
182
+ }
183
+ }
vendor/guzzlehttp/psr7/src/MultipartStream.php ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\StreamInterface;
5
+
6
+ /**
7
+ * Stream that when read returns bytes for a streaming multipart or
8
+ * multipart/form-data stream.
9
+ */
10
+ class MultipartStream implements StreamInterface
11
+ {
12
+ use StreamDecoratorTrait;
13
+
14
+ private $boundary;
15
+
16
+ /**
17
+ * @param array $elements Array of associative arrays, each containing a
18
+ * required "name" key mapping to the form field,
19
+ * name, a required "contents" key mapping to a
20
+ * StreamInterface/resource/string, an optional
21
+ * "headers" associative array of custom headers,
22
+ * and an optional "filename" key mapping to a
23
+ * string to send as the filename in the part.
24
+ * @param string $boundary You can optionally provide a specific boundary
25
+ *
26
+ * @throws \InvalidArgumentException
27
+ */
28
+ public function __construct(array $elements = [], $boundary = null)
29
+ {
30
+ $this->boundary = $boundary ?: sha1(uniqid('', true));
31
+ $this->stream = $this->createStream($elements);
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 headers needed before transferring the content of a POST file
51
+ */
52
+ private function getHeaders(array $headers)
53
+ {
54
+ $str = '';
55
+ foreach ($headers as $key => $value) {
56
+ $str .= "{$key}: {$value}\r\n";
57
+ }
58
+
59
+ return "--{$this->boundary}\r\n" . trim($str) . "\r\n\r\n";
60
+ }
61
+
62
+ /**
63
+ * Create the aggregate stream that will be used to upload the POST data
64
+ */
65
+ protected function createStream(array $elements)
66
+ {
67
+ $stream = new AppendStream();
68
+
69
+ foreach ($elements as $element) {
70
+ $this->addElement($stream, $element);
71
+ }
72
+
73
+ // Add the trailing boundary with CRLF
74
+ $stream->addStream(stream_for("--{$this->boundary}--\r\n"));
75
+
76
+ return $stream;
77
+ }
78
+
79
+ private function addElement(AppendStream $stream, array $element)
80
+ {
81
+ foreach (['contents', 'name'] as $key) {
82
+ if (!array_key_exists($key, $element)) {
83
+ throw new \InvalidArgumentException("A '{$key}' key is required");
84
+ }
85
+ }
86
+
87
+ $element['contents'] = stream_for($element['contents']);
88
+
89
+ if (empty($element['filename'])) {
90
+ $uri = $element['contents']->getMetadata('uri');
91
+ if (substr($uri, 0, 6) !== 'php://') {
92
+ $element['filename'] = $uri;
93
+ }
94
+ }
95
+
96
+ list($body, $headers) = $this->createElement(
97
+ $element['name'],
98
+ $element['contents'],
99
+ isset($element['filename']) ? $element['filename'] : null,
100
+ isset($element['headers']) ? $element['headers'] : []
101
+ );
102
+
103
+ $stream->addStream(stream_for($this->getHeaders($headers)));
104
+ $stream->addStream($body);
105
+ $stream->addStream(stream_for("\r\n"));
106
+ }
107
+
108
+ /**
109
+ * @return array
110
+ */
111
+ private function createElement($name, StreamInterface $stream, $filename, array $headers)
112
+ {
113
+ // Set a default content-disposition header if one was no provided
114
+ $disposition = $this->getHeader($headers, 'content-disposition');
115
+ if (!$disposition) {
116
+ $headers['Content-Disposition'] = ($filename === '0' || $filename)
117
+ ? sprintf('form-data; name="%s"; filename="%s"',
118
+ $name,
119
+ basename($filename))
120
+ : "form-data; name=\"{$name}\"";
121
+ }
122
+
123
+ // Set a default content-length header if one was no provided
124
+ $length = $this->getHeader($headers, 'content-length');
125
+ if (!$length) {
126
+ if ($length = $stream->getSize()) {
127
+ $headers['Content-Length'] = (string) $length;
128
+ }
129
+ }
130
+
131
+ // Set a default Content-Type if one was not supplied
132
+ $type = $this->getHeader($headers, 'content-type');
133
+ if (!$type && ($filename === '0' || $filename)) {
134
+ if ($type = mimetype_from_filename($filename)) {
135
+ $headers['Content-Type'] = $type;
136
+ }
137
+ }
138
+
139
+ return [$stream, $headers];
140
+ }
141
+
142
+ private function getHeader(array $headers, $key)
143
+ {
144
+ $lowercaseHeader = strtolower($key);
145
+ foreach ($headers as $k => $v) {
146
+ if (strtolower($k) === $lowercaseHeader) {
147
+ return $v;
148
+ }
149
+ }
150
+
151
+ return null;
152
+ }
153
+ }
vendor/guzzlehttp/psr7/src/NoSeekStream.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\StreamInterface;
5
+
6
+ /**
7
+ * Stream decorator that prevents a stream from being seeked
8
+ */
9
+ class NoSeekStream implements StreamInterface
10
+ {
11
+ use StreamDecoratorTrait;
12
+
13
+ public function seek($offset, $whence = SEEK_SET)
14
+ {
15
+ throw new \RuntimeException('Cannot seek a NoSeekStream');
16
+ }
17
+
18
+ public function isSeekable()
19
+ {
20
+ return false;
21
+ }
22
+ }
vendor/guzzlehttp/psr7/src/PumpStream.php ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\StreamInterface;
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
+ try {
54
+ return copy_to_string($this);
55
+ } catch (\Exception $e) {
56
+ return '';
57
+ }
58
+ }
59
+
60
+ public function close()
61
+ {
62
+ $this->detach();
63
+ }
64
+
65
+ public function detach()
66
+ {
67
+ $this->tellPos = false;
68
+ $this->source = null;
69
+ }
70
+
71
+ public function getSize()
72
+ {
73
+ return $this->size;
74
+ }
75
+
76
+ public function tell()
77
+ {
78
+ return $this->tellPos;
79
+ }
80
+
81
+ public function eof()
82
+ {
83
+ return !$this->source;
84
+ }
85
+
86
+ public function isSeekable()
87
+ {
88
+ return false;
89
+ }
90
+
91
+ public function rewind()
92
+ {
93
+ $this->seek(0);
94
+ }
95
+
96
+ public function seek($offset, $whence = SEEK_SET)
97
+ {
98
+ throw new \RuntimeException('Cannot seek a PumpStream');
99
+ }
100
+
101
+ public function isWritable()
102
+ {
103
+ return false;
104
+ }
105
+
106
+ public function write($string)
107
+ {
108
+ throw new \RuntimeException('Cannot write to a PumpStream');
109
+ }
110
+
111
+ public function isReadable()
112
+ {
113
+ return true;
114
+ }
115
+
116
+ public function read($length)
117
+ {
118
+ $data = $this->buffer->read($length);
119
+ $readLen = strlen($data);
120
+ $this->tellPos += $readLen;
121
+ $remaining = $length - $readLen;
122
+
123
+ if ($remaining) {
124
+ $this->pump($remaining);
125
+ $data .= $this->buffer->read($remaining);
126
+ $this->tellPos += strlen($data) - $readLen;
127
+ }
128
+
129
+ return $data;
130
+ }
131
+
132
+ public function getContents()
133
+ {
134
+ $result = '';
135
+ while (!$this->eof()) {
136
+ $result .= $this->read(1000000);
137
+ }
138
+
139
+ return $result;
140
+ }
141
+
142
+ public function getMetadata($key = null)
143
+ {
144
+ if (!$key) {
145
+ return $this->metadata;
146
+ }
147
+
148
+ return isset($this->metadata[$key]) ? $this->metadata[$key] : null;
149
+ }
150
+
151
+ private function pump($length)
152
+ {
153
+ if ($this->source) {
154
+ do {
155
+ $data = call_user_func($this->source, $length);
156
+ if ($data === false || $data === null) {
157
+ $this->source = null;
158
+ return;
159
+ }
160
+ $this->buffer->write($data);
161
+ $length -= strlen($data);
162
+ } while ($length > 0);
163
+ }
164
+ }
165
+ }
vendor/guzzlehttp/psr7/src/Request.php ADDED
@@ -0,0 +1,142 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use InvalidArgumentException;
5
+ use Psr\Http\Message\RequestInterface;
6
+ use Psr\Http\Message\StreamInterface;
7
+ use Psr\Http\Message\UriInterface;
8
+
9
+ /**
10
+ * PSR-7 request implementation.
11
+ */
12
+ class Request implements RequestInterface
13
+ {
14
+ use MessageTrait;
15
+
16
+ /** @var string */
17
+ private $method;
18
+
19
+ /** @var null|string */
20
+ private $requestTarget;
21
+
22
+ /** @var UriInterface */
23
+ private $uri;
24
+
25
+ /**
26
+ * @param string $method HTTP method
27
+ * @param string|UriInterface $uri URI
28
+ * @param array $headers Request headers
29
+ * @param string|null|resource|StreamInterface $body Request body
30
+ * @param string $version Protocol version
31
+ */
32
+ public function __construct(
33
+ $method,
34
+ $uri,
35
+ array $headers = [],
36
+ $body = null,
37
+ $version = '1.1'
38
+ ) {
39
+ if (!($uri instanceof UriInterface)) {
40
+ $uri = new Uri($uri);
41
+ }
42
+
43
+ $this->method = strtoupper($method);
44
+ $this->uri = $uri;
45
+ $this->setHeaders($headers);
46
+ $this->protocol = $version;
47
+
48
+ if (!isset($this->headerNames['host'])) {
49
+ $this->updateHostFromUri();
50
+ }
51
+
52
+ if ($body !== '' && $body !== null) {
53
+ $this->stream = stream_for($body);
54
+ }
55
+ }
56
+
57
+ public function getRequestTarget()
58
+ {
59
+ if ($this->requestTarget !== null) {
60
+ return $this->requestTarget;
61
+ }
62
+
63
+ $target = $this->uri->getPath();
64
+ if ($target == '') {
65
+ $target = '/';
66
+ }
67
+ if ($this->uri->getQuery() != '') {
68
+ $target .= '?' . $this->uri->getQuery();
69
+ }
70
+
71
+ return $target;
72
+ }
73
+
74
+ public function withRequestTarget($requestTarget)
75
+ {
76
+ if (preg_match('#\s#', $requestTarget)) {
77
+ throw new InvalidArgumentException(
78
+ 'Invalid request target provided; cannot contain whitespace'
79
+ );
80
+ }
81
+
82
+ $new = clone $this;
83
+ $new->requestTarget = $requestTarget;
84
+ return $new;
85
+ }
86
+
87
+ public function getMethod()
88
+ {
89
+ return $this->method;
90
+ }
91
+
92
+ public function withMethod($method)
93
+ {
94
+ $new = clone $this;
95
+ $new->method = strtoupper($method);
96
+ return $new;
97
+ }
98
+
99
+ public function getUri()
100
+ {
101
+ return $this->uri;
102
+ }
103
+
104
+ public function withUri(UriInterface $uri, $preserveHost = false)
105
+ {
106
+ if ($uri === $this->uri) {
107
+ return $this;
108
+ }
109
+
110
+ $new = clone $this;
111
+ $new->uri = $uri;
112
+
113
+ if (!$preserveHost || !isset($this->headerNames['host'])) {
114
+ $new->updateHostFromUri();
115
+ }
116
+
117
+ return $new;
118
+ }
119
+
120
+ private function updateHostFromUri()
121
+ {
122
+ $host = $this->uri->getHost();
123
+
124
+ if ($host == '') {
125
+ return;
126
+ }
127
+
128
+ if (($port = $this->uri->getPort()) !== null) {
129
+ $host .= ':' . $port;
130
+ }
131
+
132
+ if (isset($this->headerNames['host'])) {
133
+ $header = $this->headerNames['host'];
134
+ } else {
135
+ $header = 'Host';
136
+ $this->headerNames['host'] = 'Host';
137
+ }
138
+ // Ensure Host is the first header.
139
+ // See: http://tools.ietf.org/html/rfc7230#section-5.4
140
+ $this->headers = [$header => [$host]] + $this->headers;
141
+ }
142
+ }
vendor/guzzlehttp/psr7/src/Response.php ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\ResponseInterface;
5
+ use Psr\Http\Message\StreamInterface;
6
+
7
+ /**
8
+ * PSR-7 response implementation.
9
+ */
10
+ class Response implements ResponseInterface
11
+ {
12
+ use MessageTrait;
13
+
14
+ /** @var array Map of standard HTTP status code/reason phrases */
15
+ private static $phrases = [
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
+ 300 => 'Multiple Choices',
29
+ 301 => 'Moved Permanently',
30
+ 302 => 'Found',
31
+ 303 => 'See Other',
32
+ 304 => 'Not Modified',
33
+ 305 => 'Use Proxy',
34
+ 306 => 'Switch Proxy',
35
+ 307 => 'Temporary Redirect',
36
+ 400 => 'Bad Request',
37
+ 401 => 'Unauthorized',
38
+ 402 => 'Payment Required',
39
+ 403 => 'Forbidden',
40
+ 404 => 'Not Found',
41
+ 405 => 'Method Not Allowed',
42
+ 406 => 'Not Acceptable',
43
+ 407 => 'Proxy Authentication Required',
44
+ 408 => 'Request Time-out',
45
+ 409 => 'Conflict',
46
+ 410 => 'Gone',
47
+ 411 => 'Length Required',
48
+ 412 => 'Precondition Failed',
49
+ 413 => 'Request Entity Too Large',
50
+ 414 => 'Request-URI Too Large',
51
+ 415 => 'Unsupported Media Type',
52
+ 416 => 'Requested range not satisfiable',
53
+ 417 => 'Expectation Failed',
54
+ 418 => 'I\'m a teapot',
55
+ 422 => 'Unprocessable Entity',
56
+ 423 => 'Locked',
57
+ 424 => 'Failed Dependency',
58
+ 425 => 'Unordered Collection',
59
+ 426 => 'Upgrade Required',
60
+ 428 => 'Precondition Required',
61
+ 429 => 'Too Many Requests',
62
+ 431 => 'Request Header Fields Too Large',
63
+ 451 => 'Unavailable For Legal Reasons',
64
+ 500 => 'Internal Server Error',
65
+ 501 => 'Not Implemented',
66
+ 502 => 'Bad Gateway',
67
+ 503 => 'Service Unavailable',
68
+ 504 => 'Gateway Time-out',
69
+ 505 => 'HTTP Version not supported',
70
+ 506 => 'Variant Also Negotiates',
71
+ 507 => 'Insufficient Storage',
72
+ 508 => 'Loop Detected',
73
+ 511 => 'Network Authentication Required',
74
+ ];
75
+
76
+ /** @var string */
77
+ private $reasonPhrase = '';
78
+
79
+ /** @var int */
80
+ private $statusCode = 200;
81
+
82
+ /**
83
+ * @param int $status Status code
84
+ * @param array $headers Response headers
85
+ * @param string|null|resource|StreamInterface $body Response body
86
+ * @param string $version Protocol version
87
+ * @param string|null $reason Reason phrase (when empty a default will be used based on the status code)
88
+ */
89
+ public function __construct(
90
+ $status = 200,
91
+ array $headers = [],
92
+ $body = null,
93
+ $version = '1.1',
94
+ $reason = null
95
+ ) {
96
+ if (filter_var($status, FILTER_VALIDATE_INT) === false) {
97
+ throw new \InvalidArgumentException('Status code must be an integer value.');
98
+ }
99
+
100
+ $this->statusCode = (int) $status;
101
+
102
+ if ($body !== '' && $body !== null) {
103
+ $this->stream = stream_for($body);
104
+ }
105
+
106
+ $this->setHeaders($headers);
107
+ if ($reason == '' && isset(self::$phrases[$this->statusCode])) {
108
+ $this->reasonPhrase = self::$phrases[$this->statusCode];
109
+ } else {
110
+ $this->reasonPhrase = (string) $reason;
111
+ }
112
+
113
+ $this->protocol = $version;
114
+ }
115
+
116
+ public function getStatusCode()
117
+ {
118
+ return $this->statusCode;
119
+ }
120
+
121
+ public function getReasonPhrase()
122
+ {
123
+ return $this->reasonPhrase;
124
+ }
125
+
126
+ public function withStatus($code, $reasonPhrase = '')
127
+ {
128
+ $new = clone $this;
129
+ $new->statusCode = (int) $code;
130
+ if ($reasonPhrase == '' && isset(self::$phrases[$new->statusCode])) {
131
+ $reasonPhrase = self::$phrases[$new->statusCode];
132
+ }
133
+ $new->reasonPhrase = $reasonPhrase;
134
+ return $new;
135
+ }
136
+ }
vendor/guzzlehttp/psr7/src/Rfc7230.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace GuzzleHttp\Psr7;
4
+
5
+ final class Rfc7230
6
+ {
7
+ /**
8
+ * Header related regular expressions (copied from amphp/http package)
9
+ * (Note: once we require PHP 7.x we could just depend on the upstream package)
10
+ *
11
+ * Note: header delimiter (\r\n) is modified to \r?\n to accept line feed only delimiters for BC reasons.
12
+ *
13
+ * @link https://github.com/amphp/http/blob/v1.0.1/src/Rfc7230.php#L12-L15
14
+ * @license https://github.com/amphp/http/blob/v1.0.1/LICENSE
15
+ */
16
+ const HEADER_REGEX = "(^([^()<>@,;:\\\"/[\]?={}\x01-\x20\x7F]++):[ \t]*+((?:[ \t]*+[\x21-\x7E\x80-\xFF]++)*+)[ \t]*+\r?\n)m";
17
+ const HEADER_FOLD_REGEX = "(\r?\n[ \t]++)";
18
+ }
vendor/guzzlehttp/psr7/src/ServerRequest.php ADDED
@@ -0,0 +1,376 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace GuzzleHttp\Psr7;
4
+
5
+ use InvalidArgumentException;
6
+ use Psr\Http\Message\ServerRequestInterface;
7
+ use Psr\Http\Message\UriInterface;
8
+ use Psr\Http\Message\StreamInterface;
9
+ use Psr\Http\Message\UploadedFileInterface;
10
+
11
+ /**
12
+ * Server-side HTTP request
13
+ *
14
+ * Extends the Request definition to add methods for accessing incoming data,
15
+ * specifically server parameters, cookies, matched path parameters, query
16
+ * string arguments, body parameters, and upload file information.
17
+ *
18
+ * "Attributes" are discovered via decomposing the request (and usually
19
+ * specifically the URI path), and typically will be injected by the application.
20
+ *
21
+ * Requests are considered immutable; all methods that might change state are
22
+ * implemented such that they retain the internal state of the current
23
+ * message and return a new instance that contains the changed state.
24
+ */
25
+ class ServerRequest extends Request implements ServerRequestInterface
26
+ {
27
+ /**
28
+ * @var array
29
+ */
30
+ private $attributes = [];
31
+
32
+ /**
33
+ * @var array
34
+ */
35
+ private $cookieParams = [];
36
+
37
+ /**
38
+ * @var null|array|object
39
+ */
40
+ private $parsedBody;
41
+
42
+ /**
43
+ * @var array
44
+ */
45
+ private $queryParams = [];
46
+
47
+ /**
48
+ * @var array
49
+ */
50
+ private $serverParams;
51
+
52
+ /**
53
+ * @var array
54
+ */
55
+ private $uploadedFiles = [];
56
+
57
+ /**
58
+ * @param string $method HTTP method
59
+ * @param string|UriInterface $uri URI
60
+ * @param array $headers Request headers
61
+ * @param string|null|resource|StreamInterface $body Request body
62
+ * @param string $version Protocol version
63
+ * @param array $serverParams Typically the $_SERVER superglobal
64
+ */
65
+ public function __construct(
66
+ $method,
67
+ $uri,
68
+ array $headers = [],
69
+ $body = null,
70
+ $version = '1.1',
71
+ array $serverParams = []
72
+ ) {
73
+ $this->serverParams = $serverParams;
74
+
75
+ parent::__construct($method, $uri, $headers, $body, $version);
76
+ }
77
+
78
+ /**
79
+ * Return an UploadedFile instance array.
80
+ *
81
+ * @param array $files A array which respect $_FILES structure
82
+ * @throws InvalidArgumentException for unrecognized values
83
+ * @return array
84
+ */
85
+ public static function normalizeFiles(array $files)
86
+ {
87
+ $normalized = [];
88
+
89
+ foreach ($files as $key => $value) {
90
+ if ($value instanceof UploadedFileInterface) {
91
+ $normalized[$key] = $value;
92
+ } elseif (is_array($value) && isset($value['tmp_name'])) {
93
+ $normalized[$key] = self::createUploadedFileFromSpec($value);
94
+ } elseif (is_array($value)) {
95
+ $normalized[$key] = self::normalizeFiles($value);
96
+ continue;
97
+ } else {
98
+ throw new InvalidArgumentException('Invalid value in files specification');
99
+ }
100
+ }
101
+
102
+ return $normalized;
103
+ }
104
+
105
+ /**
106
+ * Create and return an UploadedFile instance from a $_FILES specification.
107
+ *
108
+ * If the specification represents an array of values, this method will
109
+ * delegate to normalizeNestedFileSpec() and return that return value.
110
+ *
111
+ * @param array $value $_FILES struct
112
+ * @return array|UploadedFileInterface
113
+ */
114
+ private static function createUploadedFileFromSpec(array $value)
115
+ {
116
+ if (is_array($value['tmp_name'])) {
117
+ return self::normalizeNestedFileSpec($value);
118
+ }
119
+
120
+ return new UploadedFile(
121
+ $value['tmp_name'],
122
+ (int) $value['size'],
123
+ (int) $value['error'],
124
+ $value['name'],
125
+ $value['type']
126
+ );
127
+ }
128
+
129
+ /**
130
+ * Normalize an array of file specifications.
131
+ *
132
+ * Loops through all nested files and returns a normalized array of
133
+ * UploadedFileInterface instances.
134
+ *
135
+ * @param array $files
136
+ * @return UploadedFileInterface[]
137
+ */
138
+ private static function normalizeNestedFileSpec(array $files = [])
139
+ {
140
+ $normalizedFiles = [];
141
+
142
+ foreach (array_keys($files['tmp_name']) as $key) {
143
+ $spec = [
144
+ 'tmp_name' => $files['tmp_name'][$key],
145
+ 'size' => $files['size'][$key],
146
+ 'error' => $files['error'][$key],
147
+ 'name' => $files['name'][$key],
148
+ 'type' => $files['type'][$key],
149
+ ];
150
+ $normalizedFiles[$key] = self::createUploadedFileFromSpec($spec);
151
+ }
152
+
153
+ return $normalizedFiles;
154
+ }
155
+
156
+ /**
157
+ * Return a ServerRequest populated with superglobals:
158
+ * $_GET
159
+ * $_POST
160
+ * $_COOKIE
161
+ * $_FILES
162
+ * $_SERVER
163
+ *
164
+ * @return ServerRequestInterface
165
+ */
166
+ public static function fromGlobals()
167
+ {
168
+ $method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'GET';
169
+ $headers = getallheaders();
170
+ $uri = self::getUriFromGlobals();
171
+ $body = new LazyOpenStream('php://input', 'r+');
172
+ $protocol = isset($_SERVER['SERVER_PROTOCOL']) ? str_replace('HTTP/', '', $_SERVER['SERVER_PROTOCOL']) : '1.1';
173
+
174
+ $serverRequest = new ServerRequest($method, $uri, $headers, $body, $protocol, $_SERVER);
175
+
176
+ return $serverRequest
177
+ ->withCookieParams($_COOKIE)
178
+ ->withQueryParams($_GET)
179
+ ->withParsedBody($_POST)
180
+ ->withUploadedFiles(self::normalizeFiles($_FILES));
181
+ }
182
+
183
+ private static function extractHostAndPortFromAuthority($authority)
184
+ {
185
+ $uri = 'http://'.$authority;
186
+ $parts = parse_url($uri);
187
+ if (false === $parts) {
188
+ return [null, null];
189
+ }
190
+
191
+ $host = isset($parts['host']) ? $parts['host'] : null;
192
+ $port = isset($parts['port']) ? $parts['port'] : null;
193
+
194
+ return [$host, $port];
195
+ }
196
+
197
+ /**
198
+ * Get a Uri populated with values from $_SERVER.
199
+ *
200
+ * @return UriInterface
201
+ */
202
+ public static function getUriFromGlobals()
203
+ {
204
+ $uri = new Uri('');
205
+
206
+ $uri = $uri->withScheme(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? 'https' : 'http');
207
+
208
+ $hasPort = false;
209
+ if (isset($_SERVER['HTTP_HOST'])) {
210
+ list($host, $port) = self::extractHostAndPortFromAuthority($_SERVER['HTTP_HOST']);
211
+ if ($host !== null) {
212
+ $uri = $uri->withHost($host);
213
+ }
214
+
215
+ if ($port !== null) {
216
+ $hasPort = true;
217
+ $uri = $uri->withPort($port);
218
+ }
219
+ } elseif (isset($_SERVER['SERVER_NAME'])) {
220
+ $uri = $uri->withHost($_SERVER['SERVER_NAME']);
221
+ } elseif (isset($_SERVER['SERVER_ADDR'])) {
222
+ $uri = $uri->withHost($_SERVER['SERVER_ADDR']);
223
+ }
224
+
225
+ if (!$hasPort && isset($_SERVER['SERVER_PORT'])) {
226
+ $uri = $uri->withPort($_SERVER['SERVER_PORT']);
227
+ }
228
+
229
+ $hasQuery = false;
230
+ if (isset($_SERVER['REQUEST_URI'])) {
231
+ $requestUriParts = explode('?', $_SERVER['REQUEST_URI'], 2);
232
+ $uri = $uri->withPath($requestUriParts[0]);
233
+ if (isset($requestUriParts[1])) {
234
+ $hasQuery = true;
235
+ $uri = $uri->withQuery($requestUriParts[1]);
236
+ }
237
+ }
238
+
239
+ if (!$hasQuery && isset($_SERVER['QUERY_STRING'])) {
240
+ $uri = $uri->withQuery($_SERVER['QUERY_STRING']);
241
+ }
242
+
243
+ return $uri;
244
+ }
245
+
246
+
247
+ /**
248
+ * {@inheritdoc}
249
+ */
250
+ public function getServerParams()
251
+ {
252
+ return $this->serverParams;
253
+ }
254
+
255
+ /**
256
+ * {@inheritdoc}
257
+ */
258
+ public function getUploadedFiles()
259
+ {
260
+ return $this->uploadedFiles;
261
+ }
262
+
263
+ /**
264
+ * {@inheritdoc}
265
+ */
266
+ public function withUploadedFiles(array $uploadedFiles)
267
+ {
268
+ $new = clone $this;
269
+ $new->uploadedFiles = $uploadedFiles;
270
+
271
+ return $new;
272
+ }
273
+
274
+ /**
275
+ * {@inheritdoc}
276
+ */
277
+ public function getCookieParams()
278
+ {
279
+ return $this->cookieParams;
280
+ }
281
+
282
+ /**
283
+ * {@inheritdoc}
284
+ */
285
+ public function withCookieParams(array $cookies)
286
+ {
287
+ $new = clone $this;
288
+ $new->cookieParams = $cookies;
289
+
290
+ return $new;
291
+ }
292
+
293
+ /**
294
+ * {@inheritdoc}
295
+ */
296
+ public function getQueryParams()
297
+ {
298
+ return $this->queryParams;
299
+ }
300
+
301
+ /**
302
+ * {@inheritdoc}
303
+ */
304
+ public function withQueryParams(array $query)
305
+ {
306
+ $new = clone $this;
307
+ $new->queryParams = $query;
308
+
309
+ return $new;
310
+ }
311
+
312
+ /**
313
+ * {@inheritdoc}
314
+ */
315
+ public function getParsedBody()
316
+ {
317
+ return $this->parsedBody;
318
+ }
319
+
320
+ /**
321
+ * {@inheritdoc}
322
+ */
323
+ public function withParsedBody($data)
324
+ {
325
+ $new = clone $this;
326
+ $new->parsedBody = $data;
327
+
328
+ return $new;
329
+ }
330
+
331
+ /**
332
+ * {@inheritdoc}
333
+ */
334
+ public function getAttributes()
335
+ {
336
+ return $this->attributes;
337
+ }
338
+
339
+ /**
340
+ * {@inheritdoc}
341
+ */
342
+ public function getAttribute($attribute, $default = null)
343
+ {
344
+ if (false === array_key_exists($attribute, $this->attributes)) {
345
+ return $default;
346
+ }
347
+
348
+ return $this->attributes[$attribute];
349
+ }
350
+
351
+ /**
352
+ * {@inheritdoc}
353
+ */
354
+ public function withAttribute($attribute, $value)
355
+ {
356
+ $new = clone $this;
357
+ $new->attributes[$attribute] = $value;
358
+
359
+ return $new;
360
+ }
361
+
362
+ /**
363
+ * {@inheritdoc}
364
+ */
365
+ public function withoutAttribute($attribute)
366
+ {
367
+ if (false === array_key_exists($attribute, $this->attributes)) {
368
+ return $this;
369
+ }
370
+
371
+ $new = clone $this;
372
+ unset($new->attributes[$attribute]);
373
+
374
+ return $new;
375
+ }
376
+ }
vendor/guzzlehttp/psr7/src/Stream.php ADDED
@@ -0,0 +1,270 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\StreamInterface;
5
+
6
+ /**
7
+ * PHP stream implementation.
8
+ *
9
+ * @var $stream
10
+ */
11
+ class Stream implements StreamInterface
12
+ {
13
+ private $stream;
14
+ private $size;
15
+ private $seekable;
16
+ private $readable;
17
+ private $writable;
18
+ private $uri;
19
+ private $customMetadata;
20
+
21
+ /** @var array Hash of readable and writable stream types */
22
+ private static $readWriteHash = [
23
+ 'read' => [
24
+ 'r' => true, 'w+' => true, 'r+' => true, 'x+' => true, 'c+' => true,
25
+ 'rb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true,
26
+ 'c+b' => true, 'rt' => true, 'w+t' => true, 'r+t' => true,
27
+ 'x+t' => true, 'c+t' => true, 'a+' => true, 'rb+' => true,
28
+ ],
29
+ 'write' => [
30
+ 'w' => true, 'w+' => true, 'rw' => true, 'r+' => true, 'x+' => true,
31
+ 'c+' => true, 'wb' => true, 'w+b' => true, 'r+b' => true, 'rb+' => true,
32
+ 'x+b' => true, 'c+b' => true, 'w+t' => true, 'r+t' => true,
33
+ 'x+t' => true, 'c+t' => true, 'a' => true, 'a+' => true
34
+ ]
35
+ ];
36
+
37
+ /**
38
+ * This constructor accepts an associative array of options.
39
+ *
40
+ * - size: (int) If a read stream would otherwise have an indeterminate
41
+ * size, but the size is known due to foreknowledge, then you can
42
+ * provide that size, in bytes.
43
+ * - metadata: (array) Any additional metadata to return when the metadata
44
+ * of the stream is accessed.
45
+ *
46
+ * @param resource $stream Stream resource to wrap.
47
+ * @param array $options Associative array of options.
48
+ *
49
+ * @throws \InvalidArgumentException if the stream is not a stream resource
50
+ */
51
+ public function __construct($stream, $options = [])
52
+ {
53
+ if (!is_resource($stream)) {
54
+ throw new \InvalidArgumentException('Stream must be a resource');
55
+ }
56
+
57
+ if (isset($options['size'])) {
58
+ $this->size = $options['size'];
59
+ }
60
+
61
+ $this->customMetadata = isset($options['metadata'])
62
+ ? $options['metadata']
63
+ : [];
64
+
65
+ $this->stream = $stream;
66
+ $meta = stream_get_meta_data($this->stream);
67
+ $this->seekable = $meta['seekable'];
68
+ $this->readable = isset(self::$readWriteHash['read'][$meta['mode']]);
69
+ $this->writable = isset(self::$readWriteHash['write'][$meta['mode']]);
70
+ $this->uri = $this->getMetadata('uri');
71
+ }
72
+
73
+ /**
74
+ * Closes the stream when the destructed
75
+ */
76
+ public function __destruct()
77
+ {
78
+ $this->close();
79
+ }
80
+
81
+ public function __toString()
82
+ {
83
+ try {
84
+ $this->seek(0);
85
+ return (string) stream_get_contents($this->stream);
86
+ } catch (\Exception $e) {
87
+ return '';
88
+ }
89
+ }
90
+
91
+ public function getContents()
92
+ {
93
+ if (!isset($this->stream)) {
94
+ throw new \RuntimeException('Stream is detached');
95
+ }
96
+
97
+ $contents = stream_get_contents($this->stream);
98
+
99
+ if ($contents === false) {
100
+ throw new \RuntimeException('Unable to read stream contents');
101
+ }
102
+
103
+ return $contents;
104
+ }
105
+
106
+ public function close()
107
+ {
108
+ if (isset($this->stream)) {
109
+ if (is_resource($this->stream)) {
110
+ fclose($this->stream);
111
+ }
112
+ $this->detach();
113
+ }
114
+ }
115
+
116
+ public function detach()
117
+ {
118
+ if (!isset($this->stream)) {
119
+ return null;
120
+ }
121
+
122
+ $result = $this->stream;
123
+ unset($this->stream);
124
+ $this->size = $this->uri = null;
125
+ $this->readable = $this->writable = $this->seekable = false;
126
+
127
+ return $result;
128
+ }
129
+
130
+ public function getSize()
131
+ {
132
+ if ($this->size !== null) {
133
+ return $this->size;
134
+ }
135
+
136
+ if (!isset($this->stream)) {
137
+ return null;
138
+ }
139
+
140
+ // Clear the stat cache if the stream has a URI
141
+ if ($this->uri) {
142
+ clearstatcache(true, $this->uri);
143
+ }
144
+
145
+ $stats = fstat($this->stream);
146
+ if (isset($stats['size'])) {
147
+ $this->size = $stats['size'];
148
+ return $this->size;
149
+ }
150
+
151
+ return null;
152
+ }
153
+
154
+ public function isReadable()
155
+ {
156
+ return $this->readable;
157
+ }
158
+
159
+ public function isWritable()
160
+ {
161
+ return $this->writable;
162
+ }
163
+
164
+ public function isSeekable()
165
+ {
166
+ return $this->seekable;
167
+ }
168
+
169
+ public function eof()
170
+ {
171
+ if (!isset($this->stream)) {
172
+ throw new \RuntimeException('Stream is detached');
173
+ }
174
+
175
+ return feof($this->stream);
176
+ }
177
+
178
+ public function tell()
179
+ {
180
+ if (!isset($this->stream)) {
181
+ throw new \RuntimeException('Stream is detached');
182
+ }
183
+
184
+ $result = ftell($this->stream);
185
+
186
+ if ($result === false) {
187
+ throw new \RuntimeException('Unable to determine stream position');
188
+ }
189
+
190
+ return $result;
191
+ }
192
+
193
+ public function rewind()
194
+ {
195
+ $this->seek(0);
196
+ }
197
+
198
+ public function seek($offset, $whence = SEEK_SET)
199
+ {
200
+ if (!isset($this->stream)) {
201
+ throw new \RuntimeException('Stream is detached');
202
+ }
203
+ if (!$this->seekable) {
204
+ throw new \RuntimeException('Stream is not seekable');
205
+ }
206
+ if (fseek($this->stream, $offset, $whence) === -1) {
207
+ throw new \RuntimeException('Unable to seek to stream position '
208
+ . $offset . ' with whence ' . var_export($whence, true));
209
+ }
210
+ }
211
+
212
+ public function read($length)
213
+ {
214
+ if (!isset($this->stream)) {
215
+ throw new \RuntimeException('Stream is detached');
216
+ }
217
+ if (!$this->readable) {
218
+ throw new \RuntimeException('Cannot read from non-readable stream');
219
+ }
220
+ if ($length < 0) {
221
+ throw new \RuntimeException('Length parameter cannot be negative');
222
+ }
223
+
224
+ if (0 === $length) {
225
+ return '';
226
+ }
227
+
228
+ $string = fread($this->stream, $length);
229
+ if (false === $string) {
230
+ throw new \RuntimeException('Unable to read from stream');
231
+ }
232
+
233
+ return $string;
234
+ }
235
+
236
+ public function write($string)
237
+ {
238
+ if (!isset($this->stream)) {
239
+ throw new \RuntimeException('Stream is detached');
240
+ }
241
+ if (!$this->writable) {
242
+ throw new \RuntimeException('Cannot write to a non-writable stream');
243
+ }
244
+
245
+ // We can't know the size after writing anything
246
+ $this->size = null;
247
+ $result = fwrite($this->stream, $string);
248
+
249
+ if ($result === false) {
250
+ throw new \RuntimeException('Unable to write to stream');
251
+ }
252
+
253
+ return $result;
254
+ }
255
+
256
+ public function getMetadata($key = null)
257
+ {
258
+ if (!isset($this->stream)) {
259
+ return $key ? null : [];
260
+ } elseif (!$key) {
261
+ return $this->customMetadata + stream_get_meta_data($this->stream);
262
+ } elseif (isset($this->customMetadata[$key])) {
263
+ return $this->customMetadata[$key];
264
+ }
265
+
266
+ $meta = stream_get_meta_data($this->stream);
267
+
268
+ return isset($meta[$key]) ? $meta[$key] : null;
269
+ }
270
+ }
vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\StreamInterface;
5
+
6
+ /**
7
+ * Stream decorator trait
8
+ * @property StreamInterface stream
9
+ */
10
+ trait StreamDecoratorTrait
11
+ {
12
+ /**
13
+ * @param StreamInterface $stream Stream to decorate
14
+ */
15
+ public function __construct(StreamInterface $stream)
16
+ {
17
+ $this->stream = $stream;
18
+ }
19
+
20
+ /**
21
+ * Magic method used to create a new stream if streams are not added in
22
+ * the constructor of a decorator (e.g., LazyOpenStream).
23
+ *
24
+ * @param string $name Name of the property (allows "stream" only).
25
+ *
26
+ * @return StreamInterface
27
+ */
28
+ public function __get($name)
29
+ {
30
+ if ($name == 'stream') {
31
+ $this->stream = $this->createStream();
32
+ return $this->stream;
33
+ }
34
+
35
+ throw new \UnexpectedValueException("$name not found on class");
36
+ }
37
+
38
+ public function __toString()
39
+ {
40
+ try {
41
+ if ($this->isSeekable()) {
42
+ $this->seek(0);
43
+ }
44
+ return $this->getContents();
45
+ } catch (\Exception $e) {
46
+ // Really, PHP? https://bugs.php.net/bug.php?id=53648
47
+ trigger_error('StreamDecorator::__toString exception: '
48
+ . (string) $e, E_USER_ERROR);
49
+ return '';
50
+ }
51
+ }
52
+
53
+ public function getContents()
54
+ {
55
+ return copy_to_string($this);
56
+ }
57
+
58
+ /**
59
+ * Allow decorators to implement custom methods
60
+ *
61
+ * @param string $method Missing method name
62
+ * @param array $args Method arguments
63
+ *
64
+ * @return mixed
65
+ */
66
+ public function __call($method, array $args)
67
+ {
68
+ $result = call_user_func_array([$this->stream, $method], $args);
69
+
70
+ // Always return the wrapped object if the result is a return $this
71
+ return $result === $this->stream ? $this : $result;
72
+ }
73
+
74
+ public function close()
75
+ {
76
+ $this->stream->close();
77
+ }
78
+
79
+ public function getMetadata($key = null)
80
+ {
81
+ return $this->stream->getMetadata($key);
82
+ }
83
+
84
+ public function detach()
85
+ {
86
+ return $this->stream->detach();
87
+ }
88
+
89
+ public function getSize()
90
+ {
91
+ return $this->stream->getSize();
92
+ }
93
+
94
+ public function eof()
95
+ {
96
+ return $this->stream->eof();
97
+ }
98
+
99
+ public function tell()
100
+ {
101
+ return $this->stream->tell();
102
+ }
103
+
104
+ public function isReadable()
105
+ {
106
+ return $this->stream->isReadable();
107
+ }
108
+
109
+ public function isWritable()
110
+ {
111
+ return $this->stream->isWritable();
112
+ }
113
+
114
+ public function isSeekable()
115
+ {
116
+ return $this->stream->isSeekable();
117
+ }
118
+
119
+ public function rewind()
120
+ {
121
+ $this->seek(0);
122
+ }
123
+
124
+ public function seek($offset, $whence = SEEK_SET)
125
+ {
126
+ $this->stream->seek($offset, $whence);
127
+ }
128
+
129
+ public function read($length)
130
+ {
131
+ return $this->stream->read($length);
132
+ }
133
+
134
+ public function write($string)
135
+ {
136
+ return $this->stream->write($string);
137
+ }
138
+
139
+ /**
140
+ * Implement in subclasses to dynamically create streams when requested.
141
+ *
142
+ * @return StreamInterface
143
+ * @throws \BadMethodCallException
144
+ */
145
+ protected function createStream()
146
+ {
147
+ throw new \BadMethodCallException('Not implemented');
148
+ }
149
+ }
vendor/guzzlehttp/psr7/src/StreamWrapper.php ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\StreamInterface;
5
+
6
+ /**
7
+ * Converts Guzzle streams into PHP stream resources.
8
+ */
9
+ class StreamWrapper
10
+ {
11
+ /** @var resource */
12
+ public $context;
13
+
14
+ /** @var StreamInterface */
15
+ private $stream;
16
+
17
+ /** @var string r, r+, or w */
18
+ private $mode;
19
+
20
+ /**
21
+ * Returns a resource representing the stream.
22
+ *
23
+ * @param StreamInterface $stream The stream to get a resource for
24
+ *
25
+ * @return resource
26
+ * @throws \InvalidArgumentException if stream is not readable or writable
27
+ */
28
+ public static function getResource(StreamInterface $stream)
29
+ {
30
+ self::register();
31
+
32
+ if ($stream->isReadable()) {
33
+ $mode = $stream->isWritable() ? 'r+' : 'r';
34
+ } elseif ($stream->isWritable()) {
35
+ $mode = 'w';
36
+ } else {
37
+ throw new \InvalidArgumentException('The stream must be readable, '
38
+ . 'writable, or both.');
39
+ }
40
+
41
+ return fopen('guzzle://stream', $mode, null, self::createStreamContext($stream));
42
+ }
43
+
44
+ /**
45
+ * Creates a stream context that can be used to open a stream as a php stream resource.
46
+ *
47
+ * @param StreamInterface $stream
48
+ *
49
+ * @return resource
50
+ */
51
+ public static function createStreamContext(StreamInterface $stream)
52
+ {
53
+ return stream_context_create([
54
+ 'guzzle' => ['stream' => $stream]
55
+ ]);
56
+ }
57
+
58
+ /**
59
+ * Registers the stream wrapper if needed
60
+ */
61
+ public static function register()
62
+ {
63
+ if (!in_array('guzzle', stream_get_wrappers())) {
64
+ stream_wrapper_register('guzzle', __CLASS__);
65
+ }
66
+ }
67
+
68
+ public function stream_open($path, $mode, $options, &$opened_path)
69
+ {
70
+ $options = stream_context_get_options($this->context);
71
+
72
+ if (!isset($options['guzzle']['stream'])) {
73
+ return false;
74
+ }
75
+
76
+ $this->mode = $mode;
77
+ $this->stream = $options['guzzle']['stream'];
78
+
79
+ return true;
80
+ }
81
+
82
+ public function stream_read($count)
83
+ {
84
+ return $this->stream->read($count);
85
+ }
86
+
87
+ public function stream_write($data)
88
+ {
89
+ return (int) $this->stream->write($data);
90
+ }
91
+
92
+ public function stream_tell()
93
+ {
94
+ return $this->stream->tell();
95
+ }
96
+
97
+ public function stream_eof()
98
+ {
99
+ return $this->stream->eof();
100
+ }
101
+
102
+ public function stream_seek($offset, $whence)
103
+ {
104
+ $this->stream->seek($offset, $whence);
105
+
106
+ return true;
107
+ }
108
+
109
+ public function stream_cast($cast_as)
110
+ {
111
+ $stream = clone($this->stream);
112
+
113
+ return $stream->detach();
114
+ }
115
+
116
+ public function stream_stat()
117
+ {
118
+ static $modeMap = [
119
+ 'r' => 33060,
120
+ 'rb' => 33060,
121
+ 'r+' => 33206,
122
+ 'w' => 33188,
123
+ 'wb' => 33188
124
+ ];
125
+
126
+ return [
127
+ 'dev' => 0,
128
+ 'ino' => 0,
129
+ 'mode' => $modeMap[$this->mode],
130
+ 'nlink' => 0,
131
+ 'uid' => 0,
132
+ 'gid' => 0,
133
+ 'rdev' => 0,
134
+ 'size' => $this->stream->getSize() ?: 0,
135
+ 'atime' => 0,
136
+ 'mtime' => 0,
137
+ 'ctime' => 0,
138
+ 'blksize' => 0,
139
+ 'blocks' => 0
140
+ ];
141
+ }
142
+
143
+ public function url_stat($path, $flags)
144
+ {
145
+ return [
146
+ 'dev' => 0,
147
+ 'ino' => 0,
148
+ 'mode' => 0,
149
+ 'nlink' => 0,
150
+ 'uid' => 0,
151
+ 'gid' => 0,
152
+ 'rdev' => 0,
153
+ 'size' => 0,
154
+ 'atime' => 0,
155
+ 'mtime' => 0,
156
+ 'ctime' => 0,
157
+ 'blksize' => 0,
158
+ 'blocks' => 0
159
+ ];
160
+ }
161
+ }
vendor/guzzlehttp/psr7/src/UploadedFile.php ADDED
@@ -0,0 +1,316 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use InvalidArgumentException;
5
+ use Psr\Http\Message\StreamInterface;
6
+ use Psr\Http\Message\UploadedFileInterface;
7
+ use RuntimeException;
8
+
9
+ class UploadedFile implements UploadedFileInterface
10
+ {
11
+ /**
12
+ * @var int[]
13
+ */
14
+ private static $errors = [
15
+ UPLOAD_ERR_OK,
16
+ UPLOAD_ERR_INI_SIZE,
17
+ UPLOAD_ERR_FORM_SIZE,
18
+ UPLOAD_ERR_PARTIAL,
19
+ UPLOAD_ERR_NO_FILE,
20
+ UPLOAD_ERR_NO_TMP_DIR,
21
+ UPLOAD_ERR_CANT_WRITE,
22
+ UPLOAD_ERR_EXTENSION,
23
+ ];
24
+
25
+ /**
26
+ * @var string
27
+ */
28
+ private $clientFilename;
29
+
30
+ /**
31
+ * @var string
32
+ */
33
+ private $clientMediaType;
34
+
35
+ /**
36
+ * @var int
37
+ */
38
+ private $error;
39
+
40
+ /**
41
+ * @var null|string
42
+ */
43
+ private $file;
44
+
45
+ /**
46
+ * @var bool
47
+ */
48
+ private $moved = false;
49
+
50
+ /**
51
+ * @var int
52
+ */
53
+ private $size;
54
+
55
+ /**
56
+ * @var StreamInterface|null
57
+ */
58
+ private $stream;
59
+
60
+ /**
61
+ * @param StreamInterface|string|resource $streamOrFile
62
+ * @param int $size
63
+ * @param int $errorStatus
64
+ * @param string|null $clientFilename
65
+ * @param string|null $clientMediaType
66
+ */
67
+ public function __construct(
68
+ $streamOrFile,
69
+ $size,
70
+ $errorStatus,
71
+ $clientFilename = null,
72
+ $clientMediaType = null
73
+ ) {
74
+ $this->setError($errorStatus);
75
+ $this->setSize($size);
76
+ $this->setClientFilename($clientFilename);
77
+ $this->setClientMediaType($clientMediaType);
78
+
79
+ if ($this->isOk()) {
80
+ $this->setStreamOrFile($streamOrFile);
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Depending on the value set file or stream variable
86
+ *
87
+ * @param mixed $streamOrFile
88
+ * @throws InvalidArgumentException
89
+ */
90
+ private function setStreamOrFile($streamOrFile)
91
+ {
92
+ if (is_string($streamOrFile)) {
93
+ $this->file = $streamOrFile;
94
+ } elseif (is_resource($streamOrFile)) {
95
+ $this->stream = new Stream($streamOrFile);
96
+ } elseif ($streamOrFile instanceof StreamInterface) {
97
+ $this->stream = $streamOrFile;
98
+ } else {
99
+ throw new InvalidArgumentException(
100
+ 'Invalid stream or file provided for UploadedFile'
101
+ );
102
+ }
103
+ }
104
+
105
+ /**
106
+ * @param int $error
107
+ * @throws InvalidArgumentException
108
+ */
109
+ private function setError($error)
110
+ {
111
+ if (false === is_int($error)) {
112
+ throw new InvalidArgumentException(
113
+ 'Upload file error status must be an integer'
114
+ );
115
+ }
116
+
117
+ if (false === in_array($error, UploadedFile::$errors)) {
118
+ throw new InvalidArgumentException(
119
+ 'Invalid error status for UploadedFile'
120
+ );
121
+ }
122
+
123
+ $this->error = $error;
124
+ }
125
+
126
+ /**
127
+ * @param int $size
128
+ * @throws InvalidArgumentException
129
+ */
130
+ private function setSize($size)
131
+ {
132
+ if (false === is_int($size)) {
133
+ throw new InvalidArgumentException(
134
+ 'Upload file size must be an integer'
135
+ );
136
+ }
137
+
138
+ $this->size = $size;
139
+ }
140
+
141
+ /**
142
+ * @param mixed $param
143
+ * @return boolean
144
+ */
145
+ private function isStringOrNull($param)
146
+ {
147
+ return in_array(gettype($param), ['string', 'NULL']);
148
+ }
149
+
150
+ /**
151
+ * @param mixed $param
152
+ * @return boolean
153
+ */
154
+ private function isStringNotEmpty($param)
155
+ {
156
+ return is_string($param) && false === empty($param);
157
+ }
158
+
159
+ /**
160
+ * @param string|null $clientFilename
161
+ * @throws InvalidArgumentException
162
+ */
163
+ private function setClientFilename($clientFilename)
164
+ {
165
+ if (false === $this->isStringOrNull($clientFilename)) {
166
+ throw new InvalidArgumentException(
167
+ 'Upload file client filename must be a string or null'
168
+ );
169
+ }
170
+
171
+ $this->clientFilename = $clientFilename;
172
+ }
173
+
174
+ /**
175
+ * @param string|null $clientMediaType
176
+ * @throws InvalidArgumentException
177
+ */
178
+ private function setClientMediaType($clientMediaType)
179
+ {
180
+ if (false === $this->isStringOrNull($clientMediaType)) {
181
+ throw new InvalidArgumentException(
182
+ 'Upload file client media type must be a string or null'
183
+ );
184
+ }
185
+
186
+ $this->clientMediaType = $clientMediaType;
187
+ }
188
+
189
+ /**
190
+ * Return true if there is no upload error
191
+ *
192
+ * @return boolean
193
+ */
194
+ private function isOk()
195
+ {
196
+ return $this->error === UPLOAD_ERR_OK;
197
+ }
198
+
199
+ /**
200
+ * @return boolean
201
+ */
202
+ public function isMoved()
203
+ {
204
+ return $this->moved;
205
+ }
206
+
207
+ /**
208
+ * @throws RuntimeException if is moved or not ok
209
+ */
210
+ private function validateActive()
211
+ {
212
+ if (false === $this->isOk()) {
213
+ throw new RuntimeException('Cannot retrieve stream due to upload error');
214
+ }
215
+
216
+ if ($this->isMoved()) {
217
+ throw new RuntimeException('Cannot retrieve stream after it has already been moved');
218
+ }
219
+ }
220
+
221
+ /**
222
+ * {@inheritdoc}
223
+ * @throws RuntimeException if the upload was not successful.
224
+ */
225
+ public function getStream()
226
+ {
227
+ $this->validateActive();
228
+
229
+ if ($this->stream instanceof StreamInterface) {
230
+ return $this->stream;
231
+ }
232
+
233
+ return new LazyOpenStream($this->file, 'r+');
234
+ }
235
+
236
+ /**
237
+ * {@inheritdoc}
238
+ *
239
+ * @see http://php.net/is_uploaded_file
240
+ * @see http://php.net/move_uploaded_file
241
+ * @param string $targetPath Path to which to move the uploaded file.
242
+ * @throws RuntimeException if the upload was not successful.
243
+ * @throws InvalidArgumentException if the $path specified is invalid.
244
+ * @throws RuntimeException on any error during the move operation, or on
245
+ * the second or subsequent call to the method.
246
+ */
247
+ public function moveTo($targetPath)
248
+ {
249
+ $this->validateActive();
250
+
251
+ if (false === $this->isStringNotEmpty($targetPath)) {
252
+ throw new InvalidArgumentException(
253
+ 'Invalid path provided for move operation; must be a non-empty string'
254
+ );
255
+ }
256
+
257
+ if ($this->file) {
258
+ $this->moved = php_sapi_name() == 'cli'
259
+ ? rename($this->file, $targetPath)
260
+ : move_uploaded_file($this->file, $targetPath);
261
+ } else {
262
+ copy_to_stream(
263
+ $this->getStream(),
264
+ new LazyOpenStream($targetPath, 'w')
265
+ );
266
+
267
+ $this->moved = true;
268
+ }
269
+
270
+ if (false === $this->moved) {
271
+ throw new RuntimeException(
272
+ sprintf('Uploaded file could not be moved to %s', $targetPath)
273
+ );
274
+ }
275
+ }
276
+
277
+ /**
278
+ * {@inheritdoc}
279
+ *
280
+ * @return int|null The file size in bytes or null if unknown.
281
+ */
282
+ public function getSize()
283
+ {
284
+ return $this->size;
285
+ }
286
+
287
+ /**
288
+ * {@inheritdoc}
289
+ *
290
+ * @see http://php.net/manual/en/features.file-upload.errors.php
291
+ * @return int One of PHP's UPLOAD_ERR_XXX constants.
292
+ */
293
+ public function getError()
294
+ {
295
+ return $this->error;
296
+ }
297
+
298
+ /**
299
+ * {@inheritdoc}
300
+ *
301
+ * @return string|null The filename sent by the client or null if none
302
+ * was provided.
303
+ */
304
+ public function getClientFilename()
305
+ {
306
+ return $this->clientFilename;
307
+ }
308
+
309
+ /**
310
+ * {@inheritdoc}
311
+ */
312
+ public function getClientMediaType()
313
+ {
314
+ return $this->clientMediaType;
315
+ }
316
+ }
vendor/guzzlehttp/psr7/src/Uri.php ADDED
@@ -0,0 +1,738 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\UriInterface;
5
+
6
+ /**
7
+ * PSR-7 URI implementation.
8
+ *
9
+ * @author Michael Dowling
10
+ * @author Tobias Schultze
11
+ * @author Matthew Weier O'Phinney
12
+ */
13
+ class Uri implements UriInterface
14
+ {
15
+ /**
16
+ * Absolute http and https URIs require a host per RFC 7230 Section 2.7
17
+ * but in generic URIs the host can be empty. So for http(s) URIs
18
+ * we apply this default host when no host is given yet to form a
19
+ * valid URI.
20
+ */
21
+ const HTTP_DEFAULT_HOST = 'localhost';
22
+
23
+ private static $defaultPorts = [
24
+ 'http' => 80,
25
+ 'https' => 443,
26
+ 'ftp' => 21,
27
+ 'gopher' => 70,
28
+ 'nntp' => 119,
29
+ 'news' => 119,
30
+ 'telnet' => 23,
31
+ 'tn3270' => 23,
32
+ 'imap' => 143,
33
+ 'pop' => 110,
34
+ 'ldap' => 389,
35
+ ];
36
+
37
+ private static $charUnreserved = 'a-zA-Z0-9_\-\.~';
38
+ private static $charSubDelims = '!\$&\'\(\)\*\+,;=';
39
+ private static $replaceQuery = ['=' => '%3D', '&' => '%26'];
40
+
41
+ /** @var string Uri scheme. */
42
+ private $scheme = '';
43
+
44
+ /** @var string Uri user info. */
45
+ private $userInfo = '';
46
+
47
+ /** @var string Uri host. */
48
+ private $host = '';
49
+
50
+ /** @var int|null Uri port. */
51
+ private $port;
52
+
53
+ /** @var string Uri path. */
54
+ private $path = '';
55
+
56
+ /** @var string Uri query string. */
57
+ private $query = '';
58
+
59
+ /** @var string Uri fragment. */
60
+ private $fragment = '';
61
+
62
+ /**
63
+ * @param string $uri URI to parse
64
+ */
65
+ public function __construct($uri = '')
66
+ {
67
+ // weak type check to also accept null until we can add scalar type hints
68
+ if ($uri != '') {
69
+ $parts = parse_url($uri);
70
+ if ($parts === false) {
71
+ throw new \InvalidArgumentException("Unable to parse URI: $uri");
72
+ }
73
+ $this->applyParts($parts);
74
+ }
75
+ }
76
+
77
+ public function __toString()
78
+ {
79
+ return self::composeComponents(
80
+ $this->scheme,
81
+ $this->getAuthority(),
82
+ $this->path,
83
+ $this->query,
84
+ $this->fragment
85
+ );
86
+ }
87
+
88
+ /**
89
+ * Composes a URI reference string from its various components.
90
+ *
91
+ * Usually this method does not need to be called manually but instead is used indirectly via
92
+ * `Psr\Http\Message\UriInterface::__toString`.
93
+ *
94
+ * PSR-7 UriInterface treats an empty component the same as a missing component as
95
+ * getQuery(), getFragment() etc. always return a string. This explains the slight
96
+ * difference to RFC 3986 Section 5.3.
97
+ *
98
+ * Another adjustment is that the authority separator is added even when the authority is missing/empty
99
+ * for the "file" scheme. This is because PHP stream functions like `file_get_contents` only work with
100
+ * `file:///myfile` but not with `file:/myfile` although they are equivalent according to RFC 3986. But
101
+ * `file:///` is the more common syntax for the file scheme anyway (Chrome for example redirects to
102
+ * that format).
103
+ *
104
+ * @param string $scheme
105
+ * @param string $authority
106
+ * @param string $path
107
+ * @param string $query
108
+ * @param string $fragment
109
+ *
110
+ * @return string
111
+ *
112
+ * @link https://tools.ietf.org/html/rfc3986#section-5.3
113
+ */
114
+ public static function composeComponents($scheme, $authority, $path, $query, $fragment)
115
+ {
116
+ $uri = '';
117
+
118
+ // weak type checks to also accept null until we can add scalar type hints
119
+ if ($scheme != '') {
120
+ $uri .= $scheme . ':';
121
+ }
122
+
123
+ if ($authority != ''|| $scheme === 'file') {
124
+ $uri .= '//' . $authority;
125
+ }
126
+
127
+ $uri .= $path;
128
+
129
+ if ($query != '') {
130
+ $uri .= '?' . $query;
131
+ }
132
+
133
+ if ($fragment != '') {
134
+ $uri .= '#' . $fragment;
135
+ }
136
+
137
+ return $uri;
138
+ }
139
+
140
+ /**
141
+ * Whether the URI has the default port of the current scheme.
142
+ *
143
+ * `Psr\Http\Message\UriInterface::getPort` may return null or the standard port. This method can be used
144
+ * independently of the implementation.
145
+ *
146
+ * @param UriInterface $uri
147
+ *
148
+ * @return bool
149
+ */
150
+ public static function isDefaultPort(UriInterface $uri)
151
+ {
152
+ return $uri->getPort() === null
153
+ || (isset(self::$defaultPorts[$uri->getScheme()]) && $uri->getPort() === self::$defaultPorts[$uri->getScheme()]);
154
+ }
155
+
156
+ /**
157
+ * Whether the URI is absolute, i.e. it has a scheme.
158
+ *
159
+ * An instance of UriInterface can either be an absolute URI or a relative reference. This method returns true
160
+ * if it is the former. An absolute URI has a scheme. A relative reference is used to express a URI relative
161
+ * to another URI, the base URI. Relative references can be divided into several forms:
162
+ * - network-path references, e.g. '//example.com/path'
163
+ * - absolute-path references, e.g. '/path'
164
+ * - relative-path references, e.g. 'subpath'
165
+ *
166
+ * @param UriInterface $uri
167
+ *
168
+ * @return bool
169
+ * @see Uri::isNetworkPathReference
170
+ * @see Uri::isAbsolutePathReference
171
+ * @see Uri::isRelativePathReference
172
+ * @link https://tools.ietf.org/html/rfc3986#section-4
173
+ */
174
+ public static function isAbsolute(UriInterface $uri)
175
+ {
176
+ return $uri->getScheme() !== '';
177
+ }
178
+
179
+ /**
180
+ * Whether the URI is a network-path reference.
181
+ *
182
+ * A relative reference that begins with two slash characters is termed an network-path reference.
183
+ *
184
+ * @param UriInterface $uri
185
+ *
186
+ * @return bool
187
+ * @link https://tools.ietf.org/html/rfc3986#section-4.2
188
+ */
189
+ public static function isNetworkPathReference(UriInterface $uri)
190
+ {
191
+ return $uri->getScheme() === '' && $uri->getAuthority() !== '';
192
+ }
193
+
194
+ /**
195
+ * Whether the URI is a absolute-path reference.
196
+ *
197
+ * A relative reference that begins with a single slash character is termed an absolute-path reference.
198
+ *
199
+ * @param UriInterface $uri
200
+ *
201
+ * @return bool
202
+ * @link https://tools.ietf.org/html/rfc3986#section-4.2
203
+ */
204
+ public static function isAbsolutePathReference(UriInterface $uri)
205
+ {
206
+ return $uri->getScheme() === ''
207
+ && $uri->getAuthority() === ''
208
+ && isset($uri->getPath()[0])
209
+ && $uri->getPath()[0] === '/';
210
+ }
211
+
212
+ /**
213
+ * Whether the URI is a relative-path reference.
214
+ *
215
+ * A relative reference that does not begin with a slash character is termed a relative-path reference.
216
+ *
217
+ * @param UriInterface $uri
218
+ *
219
+ * @return bool
220
+ * @link https://tools.ietf.org/html/rfc3986#section-4.2
221
+ */
222
+ public static function isRelativePathReference(UriInterface $uri)
223
+ {
224
+ return $uri->getScheme() === ''
225
+ && $uri->getAuthority() === ''
226
+ && (!isset($uri->getPath()[0]) || $uri->getPath()[0] !== '/');
227
+ }
228
+
229
+ /**
230
+ * Whether the URI is a same-document reference.
231
+ *
232
+ * A same-document reference refers to a URI that is, aside from its fragment
233
+ * component, identical to the base URI. When no base URI is given, only an empty
234
+ * URI reference (apart from its fragment) is considered a same-document reference.
235
+ *
236
+ * @param UriInterface $uri The URI to check
237
+ * @param UriInterface|null $base An optional base URI to compare against
238
+ *
239
+ * @return bool
240
+ * @link https://tools.ietf.org/html/rfc3986#section-4.4
241
+ */
242
+ public static function isSameDocumentReference(UriInterface $uri, UriInterface $base = null)
243
+ {
244
+ if ($base !== null) {
245
+ $uri = UriResolver::resolve($base, $uri);
246
+
247
+ return ($uri->getScheme() === $base->getScheme())
248
+ && ($uri->getAuthority() === $base->getAuthority())
249
+ && ($uri->getPath() === $base->getPath())
250
+ && ($uri->getQuery() === $base->getQuery());
251
+ }
252
+
253
+ return $uri->getScheme() === '' && $uri->getAuthority() === '' && $uri->getPath() === '' && $uri->getQuery() === '';
254
+ }
255
+
256
+ /**
257
+ * Removes dot segments from a path and returns the new path.
258
+ *
259
+ * @param string $path
260
+ *
261
+ * @return string
262
+ *
263
+ * @deprecated since version 1.4. Use UriResolver::removeDotSegments instead.
264
+ * @see UriResolver::removeDotSegments
265
+ */
266
+ public static function removeDotSegments($path)
267
+ {
268
+ return UriResolver::removeDotSegments($path);
269
+ }
270
+
271
+ /**
272
+ * Converts the relative URI into a new URI that is resolved against the base URI.
273
+ *
274
+ * @param UriInterface $base Base URI
275
+ * @param string|UriInterface $rel Relative URI
276
+ *
277
+ * @return UriInterface
278
+ *
279
+ * @deprecated since version 1.4. Use UriResolver::resolve instead.
280
+ * @see UriResolver::resolve
281
+ */
282
+ public static function resolve(UriInterface $base, $rel)
283
+ {
284
+ if (!($rel instanceof UriInterface)) {
285
+ $rel = new self($rel);
286
+ }
287
+
288
+ return UriResolver::resolve($base, $rel);
289
+ }
290
+
291
+ /**
292
+ * Creates a new URI with a specific query string value removed.
293
+ *
294
+ * Any existing query string values that exactly match the provided key are
295
+ * removed.
296
+ *
297
+ * @param UriInterface $uri URI to use as a base.
298
+ * @param string $key Query string key to remove.
299
+ *
300
+ * @return UriInterface
301
+ */
302
+ public static function withoutQueryValue(UriInterface $uri, $key)
303
+ {
304
+ $result = self::getFilteredQueryString($uri, [$key]);
305
+
306
+ return $uri->withQuery(implode('&', $result));
307
+ }
308
+
309
+ /**
310
+ * Creates a new URI with a specific query string value.
311
+ *
312
+ * Any existing query string values that exactly match the provided key are
313
+ * removed and replaced with the given key value pair.
314
+ *
315
+ * A value of null will set the query string key without a value, e.g. "key"
316
+ * instead of "key=value".
317
+ *
318
+ * @param UriInterface $uri URI to use as a base.
319
+ * @param string $key Key to set.
320
+ * @param string|null $value Value to set
321
+ *
322
+ * @return UriInterface
323
+ */
324
+ public static function withQueryValue(UriInterface $uri, $key, $value)
325
+ {
326
+ $result = self::getFilteredQueryString($uri, [$key]);
327
+
328
+ $result[] = self::generateQueryString($key, $value);
329
+
330
+ return $uri->withQuery(implode('&', $result));
331
+ }
332
+
333
+ /**
334
+ * Creates a new URI with multiple specific query string values.
335
+ *
336
+ * It has the same behavior as withQueryValue() but for an associative array of key => value.
337
+ *
338
+ * @param UriInterface $uri URI to use as a base.
339
+ * @param array $keyValueArray Associative array of key and values
340
+ *
341
+ * @return UriInterface
342
+ */
343
+ public static function withQueryValues(UriInterface $uri, array $keyValueArray)
344
+ {
345
+ $result = self::getFilteredQueryString($uri, array_keys($keyValueArray));
346
+
347
+ foreach ($keyValueArray as $key => $value) {
348
+ $result[] = self::generateQueryString($key, $value);
349
+ }
350
+
351
+ return $uri->withQuery(implode('&', $result));
352
+ }
353
+
354
+ /**
355
+ * Creates a URI from a hash of `parse_url` components.
356
+ *
357
+ * @param array $parts
358
+ *
359
+ * @return UriInterface
360
+ * @link http://php.net/manual/en/function.parse-url.php
361
+ *
362
+ * @throws \InvalidArgumentException If the components do not form a valid URI.
363
+ */
364
+ public static function fromParts(array $parts)
365
+ {
366
+ $uri = new self();
367
+ $uri->applyParts($parts);
368
+ $uri->validateState();
369
+
370
+ return $uri;
371
+ }
372
+
373
+ public function getScheme()
374
+ {
375
+ return $this->scheme;
376
+ }
377
+
378
+ public function getAuthority()
379
+ {
380
+ $authority = $this->host;
381
+ if ($this->userInfo !== '') {
382
+ $authority = $this->userInfo . '@' . $authority;
383
+ }
384
+
385
+ if ($this->port !== null) {
386
+ $authority .= ':' . $this->port;
387
+ }
388
+
389
+ return $authority;
390
+ }
391
+
392
+ public function getUserInfo()
393
+ {
394
+ return $this->userInfo;
395
+ }
396
+
397
+ public function getHost()
398
+ {
399
+ return $this->host;
400
+ }
401
+
402
+ public function getPort()
403
+ {
404
+ return $this->port;
405
+ }
406
+
407
+ public function getPath()
408
+ {
409
+ return $this->path;
410
+ }
411
+
412
+ public function getQuery()
413
+ {
414
+ return $this->query;
415
+ }
416
+
417
+ public function getFragment()
418
+ {
419
+ return $this->fragment;
420
+ }
421
+
422
+ public function withScheme($scheme)
423
+ {
424
+ $scheme = $this->filterScheme($scheme);
425
+
426
+ if ($this->scheme === $scheme) {
427
+ return $this;
428
+ }
429
+
430
+ $new = clone $this;
431
+ $new->scheme = $scheme;
432
+ $new->removeDefaultPort();
433
+ $new->validateState();
434
+
435
+ return $new;
436
+ }
437
+
438
+ public function withUserInfo($user, $password = null)
439
+ {
440
+ $info = $user;
441
+ if ($password != '') {
442
+ $info .= ':' . $password;
443
+ }
444
+
445
+ if ($this->userInfo === $info) {
446
+ return $this;
447
+ }
448
+
449
+ $new = clone $this;
450
+ $new->userInfo = $info;
451
+ $new->validateState();
452
+
453
+ return $new;
454
+ }
455
+
456
+ public function withHost($host)
457
+ {
458
+ $host = $this->filterHost($host);
459
+
460
+ if ($this->host === $host) {
461
+ return $this;
462
+ }
463
+
464
+ $new = clone $this;
465
+ $new->host = $host;
466
+ $new->validateState();
467
+
468
+ return $new;
469
+ }
470
+
471
+ public function withPort($port)
472
+ {
473
+ $port = $this->filterPort($port);
474
+
475
+ if ($this->port === $port) {
476
+ return $this;
477
+ }
478
+
479
+ $new = clone $this;
480
+ $new->port = $port;
481
+ $new->removeDefaultPort();
482
+ $new->validateState();
483
+
484
+ return $new;
485
+ }
486
+
487
+ public function withPath($path)
488
+ {
489
+ $path = $this->filterPath($path);
490
+
491
+ if ($this->path === $path) {
492
+ return $this;
493
+ }
494
+
495
+ $new = clone $this;
496
+ $new->path = $path;
497
+ $new->validateState();
498
+
499
+ return $new;
500
+ }
501
+
502
+ public function withQuery($query)
503
+ {
504
+ $query = $this->filterQueryAndFragment($query);
505
+
506
+ if ($this->query === $query) {
507
+ return $this;
508
+ }
509
+
510
+ $new = clone $this;
511
+ $new->query = $query;
512
+
513
+ return $new;
514
+ }
515
+
516
+ public function withFragment($fragment)
517
+ {
518
+ $fragment = $this->filterQueryAndFragment($fragment);
519
+
520
+ if ($this->fragment === $fragment) {
521
+ return $this;
522
+ }
523
+
524
+ $new = clone $this;
525
+ $new->fragment = $fragment;
526
+
527
+ return $new;
528
+ }
529
+
530
+ /**
531
+ * Apply parse_url parts to a URI.
532
+ *
533
+ * @param array $parts Array of parse_url parts to apply.
534
+ */
535
+ private function applyParts(array $parts)
536
+ {
537
+ $this->scheme = isset($parts['scheme'])
538
+ ? $this->filterScheme($parts['scheme'])
539
+ : '';
540
+ $this->userInfo = isset($parts['user']) ? $parts['user'] : '';
541
+ $this->host = isset($parts['host'])
542
+ ? $this->filterHost($parts['host'])
543
+ : '';
544
+ $this->port = isset($parts['port'])
545
+ ? $this->filterPort($parts['port'])
546
+ : null;
547
+ $this->path = isset($parts['path'])
548
+ ? $this->filterPath($parts['path'])
549
+ : '';
550
+ $this->query = isset($parts['query'])
551
+ ? $this->filterQueryAndFragment($parts['query'])
552
+ : '';
553
+ $this->fragment = isset($parts['fragment'])
554
+ ? $this->filterQueryAndFragment($parts['fragment'])
555
+ : '';
556
+ if (isset($parts['pass'])) {
557
+ $this->userInfo .= ':' . $parts['pass'];
558
+ }
559
+
560
+ $this->removeDefaultPort();
561
+ }
562
+
563
+ /**
564
+ * @param string $scheme
565
+ *
566
+ * @return string
567
+ *
568
+ * @throws \InvalidArgumentException If the scheme is invalid.
569
+ */
570
+ private function filterScheme($scheme)
571
+ {
572
+ if (!is_string($scheme)) {
573
+ throw new \InvalidArgumentException('Scheme must be a string');
574
+ }
575
+
576
+ return strtolower($scheme);
577
+ }
578
+
579
+ /**
580
+ * @param string $host
581
+ *
582
+ * @return string
583
+ *
584
+ * @throws \InvalidArgumentException If the host is invalid.
585
+ */
586
+ private function filterHost($host)
587
+ {
588
+ if (!is_string($host)) {
589
+ throw new \InvalidArgumentException('Host must be a string');
590
+ }
591
+
592
+ return strtolower($host);
593
+ }
594
+
595
+ /**
596
+ * @param int|null $port
597
+ *
598
+ * @return int|null
599
+ *
600
+ * @throws \InvalidArgumentException If the port is invalid.
601
+ */
602
+ private function filterPort($port)
603
+ {
604
+ if ($port === null) {
605
+ return null;
606
+ }
607
+
608
+ $port = (int) $port;
609
+ if (1 > $port || 0xffff < $port) {
610
+ throw new \InvalidArgumentException(
611
+ sprintf('Invalid port: %d. Must be between 1 and 65535', $port)
612
+ );
613
+ }
614
+
615
+ return $port;
616
+ }
617
+
618
+ /**
619
+ * @param UriInterface $uri
620
+ * @param array $keys
621
+ *
622
+ * @return array
623
+ */
624
+ private static function getFilteredQueryString(UriInterface $uri, array $keys)
625
+ {
626
+ $current = $uri->getQuery();
627
+
628
+ if ($current === '') {
629
+ return [];
630
+ }
631
+
632
+ $decodedKeys = array_map('rawurldecode', $keys);
633
+
634
+ return array_filter(explode('&', $current), function ($part) use ($decodedKeys) {
635
+ return !in_array(rawurldecode(explode('=', $part)[0]), $decodedKeys, true);
636
+ });
637
+ }
638
+
639
+ /**
640
+ * @param string $key
641
+ * @param string|null $value
642
+ *
643
+ * @return string
644
+ */
645
+ private static function generateQueryString($key, $value)
646
+ {
647
+ // Query string separators ("=", "&") within the key or value need to be encoded
648
+ // (while preventing double-encoding) before setting the query string. All other
649
+ // chars that need percent-encoding will be encoded by withQuery().
650
+ $queryString = strtr($key, self::$replaceQuery);
651
+
652
+ if ($value !== null) {
653
+ $queryString .= '=' . strtr($value, self::$replaceQuery);
654
+ }
655
+
656
+ return $queryString;
657
+ }
658
+
659
+ private function removeDefaultPort()
660
+ {
661
+ if ($this->port !== null && self::isDefaultPort($this)) {
662
+ $this->port = null;
663
+ }
664
+ }
665
+
666
+ /**
667
+ * Filters the path of a URI
668
+ *
669
+ * @param string $path
670
+ *
671
+ * @return string
672
+ *
673
+ * @throws \InvalidArgumentException If the path is invalid.
674
+ */
675
+ private function filterPath($path)
676
+ {
677
+ if (!is_string($path)) {
678
+ throw new \InvalidArgumentException('Path must be a string');
679
+ }
680
+
681
+ return preg_replace_callback(
682
+ '/(?:[^' . self::$charUnreserved . self::$charSubDelims . '%:@\/]++|%(?![A-Fa-f0-9]{2}))/',
683
+ [$this, 'rawurlencodeMatchZero'],
684
+ $path
685
+ );
686
+ }
687
+
688
+ /**
689
+ * Filters the query string or fragment of a URI.
690
+ *
691
+ * @param string $str
692
+ *
693
+ * @return string
694
+ *
695
+ * @throws \InvalidArgumentException If the query or fragment is invalid.
696
+ */
697
+ private function filterQueryAndFragment($str)
698
+ {
699
+ if (!is_string($str)) {
700
+ throw new \InvalidArgumentException('Query and fragment must be a string');
701
+ }
702
+
703
+ return preg_replace_callback(
704
+ '/(?:[^' . self::$charUnreserved . self::$charSubDelims . '%:@\/\?]++|%(?![A-Fa-f0-9]{2}))/',
705
+ [$this, 'rawurlencodeMatchZero'],
706
+ $str
707
+ );
708
+ }
709
+
710
+ private function rawurlencodeMatchZero(array $match)
711
+ {
712
+ return rawurlencode($match[0]);
713
+ }
714
+
715
+ private function validateState()
716
+ {
717
+ if ($this->host === '' && ($this->scheme === 'http' || $this->scheme === 'https')) {
718
+ $this->host = self::HTTP_DEFAULT_HOST;
719
+ }
720
+
721
+ if ($this->getAuthority() === '') {
722
+ if (0 === strpos($this->path, '//')) {
723
+ throw new \InvalidArgumentException('The path of a URI without an authority must not start with two slashes "//"');
724
+ }
725
+ if ($this->scheme === '' && false !== strpos(explode('/', $this->path, 2)[0], ':')) {
726
+ throw new \InvalidArgumentException('A relative URI must not have a path beginning with a segment containing a colon');
727
+ }
728
+ } elseif (isset($this->path[0]) && $this->path[0] !== '/') {
729
+ @trigger_error(
730
+ 'The path of a URI with an authority must start with a slash "/" or be empty. Automagically fixing the URI ' .
731
+ 'by adding a leading slash to the path is deprecated since version 1.4 and will throw an exception instead.',
732
+ E_USER_DEPRECATED
733
+ );
734
+ $this->path = '/'. $this->path;
735
+ //throw new \InvalidArgumentException('The path of a URI with an authority must start with a slash "/" or be empty');
736
+ }
737
+ }
738
+ }
vendor/guzzlehttp/psr7/src/UriNormalizer.php ADDED
@@ -0,0 +1,216 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\UriInterface;
5
+
6
+ /**
7
+ * Provides methods to normalize and compare URIs.
8
+ *
9
+ * @author Tobias Schultze
10
+ *
11
+ * @link https://tools.ietf.org/html/rfc3986#section-6
12
+ */
13
+ final class UriNormalizer
14
+ {
15
+ /**
16
+ * Default normalizations which only include the ones that preserve semantics.
17
+ *
18
+ * self::CAPITALIZE_PERCENT_ENCODING | self::DECODE_UNRESERVED_CHARACTERS | self::CONVERT_EMPTY_PATH |
19
+ * self::REMOVE_DEFAULT_HOST | self::REMOVE_DEFAULT_PORT | self::REMOVE_DOT_SEGMENTS
20
+ */
21
+ const PRESERVING_NORMALIZATIONS = 63;
22
+
23
+ /**
24
+ * All letters within a percent-encoding triplet (e.g., "%3A") are case-insensitive, and should be capitalized.
25
+ *
26
+ * Example: http://example.org/a%c2%b1b → http://example.org/a%C2%B1b
27
+ */
28
+ const CAPITALIZE_PERCENT_ENCODING = 1;
29
+
30
+ /**
31
+ * Decodes percent-encoded octets of unreserved characters.
32
+ *
33
+ * For consistency, percent-encoded octets in the ranges of ALPHA (%41–%5A and %61–%7A), DIGIT (%30–%39),
34
+ * hyphen (%2D), period (%2E), underscore (%5F), or tilde (%7E) should not be created by URI producers and,
35
+ * when found in a URI, should be decoded to their corresponding unreserved characters by URI normalizers.
36
+ *
37
+ * Example: http://example.org/%7Eusern%61me/ → http://example.org/~username/
38
+ */
39
+ const DECODE_UNRESERVED_CHARACTERS = 2;
40
+
41
+ /**
42
+ * Converts the empty path to "/" for http and https URIs.
43
+ *
44
+ * Example: http://example.org → http://example.org/
45
+ */
46
+ const CONVERT_EMPTY_PATH = 4;
47
+
48
+ /**
49
+ * Removes the default host of the given URI scheme from the URI.
50
+ *
51
+ * Only the "file" scheme defines the default host "localhost".
52
+ * All of `file:/myfile`, `file:///myfile`, and `file://localhost/myfile`
53
+ * are equivalent according to RFC 3986. The first format is not accepted
54
+ * by PHPs stream functions and thus already normalized implicitly to the
55
+ * second format in the Uri class. See `GuzzleHttp\Psr7\Uri::composeComponents`.
56
+ *
57
+ * Example: file://localhost/myfile → file:///myfile
58
+ */
59
+ const REMOVE_DEFAULT_HOST = 8;
60
+
61
+ /**
62
+ * Removes the default port of the given URI scheme from the URI.
63
+ *
64
+ * Example: http://example.org:80/ → http://example.org/
65
+ */
66
+ const REMOVE_DEFAULT_PORT = 16;
67
+
68
+ /**
69
+ * Removes unnecessary dot-segments.
70
+ *
71
+ * Dot-segments in relative-path references are not removed as it would
72
+ * change the semantics of the URI reference.
73
+ *
74
+ * Example: http://example.org/../a/b/../c/./d.html → http://example.org/a/c/d.html
75
+ */
76
+ const REMOVE_DOT_SEGMENTS = 32;
77
+
78
+ /**
79
+ * Paths which include two or more adjacent slashes are converted to one.
80
+ *
81
+ * Webservers usually ignore duplicate slashes and treat those URIs equivalent.
82
+ * But in theory those URIs do not need to be equivalent. So this normalization
83
+ * may change the semantics. Encoded slashes (%2F) are not removed.
84
+ *
85
+ * Example: http://example.org//foo///bar.html → http://example.org/foo/bar.html
86
+ */
87
+ const REMOVE_DUPLICATE_SLASHES = 64;
88
+
89
+ /**
90
+ * Sort query parameters with their values in alphabetical order.
91
+ *
92
+ * However, the order of parameters in a URI may be significant (this is not defined by the standard).
93
+ * So this normalization is not safe and may change the semantics of the URI.
94
+ *
95
+ * Example: ?lang=en&article=fred → ?article=fred&lang=en
96
+ *
97
+ * Note: The sorting is neither locale nor Unicode aware (the URI query does not get decoded at all) as the
98
+ * purpose is to be able to compare URIs in a reproducible way, not to have the params sorted perfectly.
99
+ */
100
+ const SORT_QUERY_PARAMETERS = 128;
101
+
102
+ /**
103
+ * Returns a normalized URI.
104
+ *
105
+ * The scheme and host component are already normalized to lowercase per PSR-7 UriInterface.
106
+ * This methods adds additional normalizations that can be configured with the $flags parameter.
107
+ *
108
+ * PSR-7 UriInterface cannot distinguish between an empty component and a missing component as
109
+ * getQuery(), getFragment() etc. always return a string. This means the URIs "/?#" and "/" are
110
+ * treated equivalent which is not necessarily true according to RFC 3986. But that difference
111
+ * is highly uncommon in reality. So this potential normalization is implied in PSR-7 as well.
112
+ *
113
+ * @param UriInterface $uri The URI to normalize
114
+ * @param int $flags A bitmask of normalizations to apply, see constants
115
+ *
116
+ * @return UriInterface The normalized URI
117
+ * @link https://tools.ietf.org/html/rfc3986#section-6.2
118
+ */
119
+ public static function normalize(UriInterface $uri, $flags = self::PRESERVING_NORMALIZATIONS)
120
+ {
121
+ if ($flags & self::CAPITALIZE_PERCENT_ENCODING) {
122
+ $uri = self::capitalizePercentEncoding($uri);
123
+ }
124
+
125
+ if ($flags & self::DECODE_UNRESERVED_CHARACTERS) {
126
+ $uri = self::decodeUnreservedCharacters($uri);
127
+ }
128
+
129
+ if ($flags & self::CONVERT_EMPTY_PATH && $uri->getPath() === '' &&
130
+ ($uri->getScheme() === 'http' || $uri->getScheme() === 'https')
131
+ ) {
132
+ $uri = $uri->withPath('/');
133
+ }
134
+
135
+ if ($flags & self::REMOVE_DEFAULT_HOST && $uri->getScheme() === 'file' && $uri->getHost() === 'localhost') {
136
+ $uri = $uri->withHost('');
137
+ }
138
+
139
+ if ($flags & self::REMOVE_DEFAULT_PORT && $uri->getPort() !== null && Uri::isDefaultPort($uri)) {
140
+ $uri = $uri->withPort(null);
141
+ }
142
+
143
+ if ($flags & self::REMOVE_DOT_SEGMENTS && !Uri::isRelativePathReference($uri)) {
144
+ $uri = $uri->withPath(UriResolver::removeDotSegments($uri->getPath()));
145
+ }
146
+
147
+ if ($flags & self::REMOVE_DUPLICATE_SLASHES) {
148
+ $uri = $uri->withPath(preg_replace('#//++#', '/', $uri->getPath()));
149
+ }
150
+
151
+ if ($flags & self::SORT_QUERY_PARAMETERS && $uri->getQuery() !== '') {
152
+ $queryKeyValues = explode('&', $uri->getQuery());
153
+ sort($queryKeyValues);
154
+ $uri = $uri->withQuery(implode('&', $queryKeyValues));
155
+ }
156
+
157
+ return $uri;
158
+ }
159
+
160
+ /**
161
+ * Whether two URIs can be considered equivalent.
162
+ *
163
+ * Both URIs are normalized automatically before comparison with the given $normalizations bitmask. The method also
164
+ * accepts relative URI references and returns true when they are equivalent. This of course assumes they will be
165
+ * resolved against the same base URI. If this is not the case, determination of equivalence or difference of
166
+ * relative references does not mean anything.
167
+ *
168
+ * @param UriInterface $uri1 An URI to compare
169
+ * @param UriInterface $uri2 An URI to compare
170
+ * @param int $normalizations A bitmask of normalizations to apply, see constants
171
+ *
172
+ * @return bool
173
+ * @link https://tools.ietf.org/html/rfc3986#section-6.1
174
+ */
175
+ public static function isEquivalent(UriInterface $uri1, UriInterface $uri2, $normalizations = self::PRESERVING_NORMALIZATIONS)
176
+ {
177
+ return (string) self::normalize($uri1, $normalizations) === (string) self::normalize($uri2, $normalizations);
178
+ }
179
+
180
+ private static function capitalizePercentEncoding(UriInterface $uri)
181
+ {
182
+ $regex = '/(?:%[A-Fa-f0-9]{2})++/';
183
+
184
+ $callback = function (array $match) {
185
+ return strtoupper($match[0]);
186
+ };
187
+
188
+ return
189
+ $uri->withPath(
190
+ preg_replace_callback($regex, $callback, $uri->getPath())
191
+ )->withQuery(
192
+ preg_replace_callback($regex, $callback, $uri->getQuery())
193
+ );
194
+ }
195
+
196
+ private static function decodeUnreservedCharacters(UriInterface $uri)
197
+ {
198
+ $regex = '/%(?:2D|2E|5F|7E|3[0-9]|[46][1-9A-F]|[57][0-9A])/i';
199
+
200
+ $callback = function (array $match) {
201
+ return rawurldecode($match[0]);
202
+ };
203
+
204
+ return
205
+ $uri->withPath(
206
+ preg_replace_callback($regex, $callback, $uri->getPath())
207
+ )->withQuery(
208
+ preg_replace_callback($regex, $callback, $uri->getQuery())
209
+ );
210
+ }
211
+
212
+ private function __construct()
213
+ {
214
+ // cannot be instantiated
215
+ }
216
+ }
vendor/guzzlehttp/psr7/src/UriResolver.php ADDED
@@ -0,0 +1,219 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\UriInterface;
5
+
6
+ /**
7
+ * Resolves a URI reference in the context of a base URI and the opposite way.
8
+ *
9
+ * @author Tobias Schultze
10
+ *
11
+ * @link https://tools.ietf.org/html/rfc3986#section-5
12
+ */
13
+ final class UriResolver
14
+ {
15
+ /**
16
+ * Removes dot segments from a path and returns the new path.
17
+ *
18
+ * @param string $path
19
+ *
20
+ * @return string
21
+ * @link http://tools.ietf.org/html/rfc3986#section-5.2.4
22
+ */
23
+ public static function removeDotSegments($path)
24
+ {
25
+ if ($path === '' || $path === '/') {
26
+ return $path;
27
+ }
28
+
29
+ $results = [];
30
+ $segments = explode('/', $path);
31
+ foreach ($segments as $segment) {
32
+ if ($segment === '..') {
33
+ array_pop($results);
34
+ } elseif ($segment !== '.') {
35
+ $results[] = $segment;
36
+ }
37
+ }
38
+
39
+ $newPath = implode('/', $results);
40
+
41
+ if ($path[0] === '/' && (!isset($newPath[0]) || $newPath[0] !== '/')) {
42
+ // Re-add the leading slash if necessary for cases like "/.."
43
+ $newPath = '/' . $newPath;
44
+ } elseif ($newPath !== '' && ($segment === '.' || $segment === '..')) {
45
+ // Add the trailing slash if necessary
46
+ // If newPath is not empty, then $segment must be set and is the last segment from the foreach
47
+ $newPath .= '/';
48
+ }
49
+
50
+ return $newPath;
51
+ }
52
+
53
+ /**
54
+ * Converts the relative URI into a new URI that is resolved against the base URI.
55
+ *
56
+ * @param UriInterface $base Base URI
57
+ * @param UriInterface $rel Relative URI
58
+ *
59
+ * @return UriInterface
60
+ * @link http://tools.ietf.org/html/rfc3986#section-5.2
61
+ */
62
+ public static function resolve(UriInterface $base, UriInterface $rel)
63
+ {
64
+ if ((string) $rel === '') {
65
+ // we can simply return the same base URI instance for this same-document reference
66
+ return $base;
67
+ }
68
+
69
+ if ($rel->getScheme() != '') {
70
+ return $rel->withPath(self::removeDotSegments($rel->getPath()));
71
+ }
72
+
73
+ if ($rel->getAuthority() != '') {
74
+ $targetAuthority = $rel->getAuthority();
75
+ $targetPath = self::removeDotSegments($rel->getPath());
76
+ $targetQuery = $rel->getQuery();
77
+ } else {
78
+ $targetAuthority = $base->getAuthority();
79
+ if ($rel->getPath() === '') {
80
+ $targetPath = $base->getPath();
81
+ $targetQuery = $rel->getQuery() != '' ? $rel->getQuery() : $base->getQuery();
82
+ } else {
83
+ if ($rel->getPath()[0] === '/') {
84
+ $targetPath = $rel->getPath();
85
+ } else {
86
+ if ($targetAuthority != '' && $base->getPath() === '') {
87
+ $targetPath = '/' . $rel->getPath();
88
+ } else {
89
+ $lastSlashPos = strrpos($base->getPath(), '/');
90
+ if ($lastSlashPos === false) {
91
+ $targetPath = $rel->getPath();
92
+ } else {
93
+ $targetPath = substr($base->getPath(), 0, $lastSlashPos + 1) . $rel->getPath();
94
+ }
95
+ }
96
+ }
97
+ $targetPath = self::removeDotSegments($targetPath);
98
+ $targetQuery = $rel->getQuery();
99
+ }
100
+ }
101
+
102
+ return new Uri(Uri::composeComponents(
103
+ $base->getScheme(),
104
+ $targetAuthority,
105
+ $targetPath,
106
+ $targetQuery,
107
+ $rel->getFragment()
108
+ ));
109
+ }
110
+
111
+ /**
112
+ * Returns the target URI as a relative reference from the base URI.
113
+ *
114
+ * This method is the counterpart to resolve():
115
+ *
116
+ * (string) $target === (string) UriResolver::resolve($base, UriResolver::relativize($base, $target))
117
+ *
118
+ * One use-case is to use the current request URI as base URI and then generate relative links in your documents
119
+ * to reduce the document size or offer self-contained downloadable document archives.
120
+ *
121
+ * $base = new Uri('http://example.com/a/b/');
122
+ * echo UriResolver::relativize($base, new Uri('http://example.com/a/b/c')); // prints 'c'.
123
+ * echo UriResolver::relativize($base, new Uri('http://example.com/a/x/y')); // prints '../x/y'.
124
+ * echo UriResolver::relativize($base, new Uri('http://example.com/a/b/?q')); // prints '?q'.
125
+ * echo UriResolver::relativize($base, new Uri('http://example.org/a/b/')); // prints '//example.org/a/b/'.
126
+ *
127
+ * This method also accepts a target that is already relative and will try to relativize it further. Only a
128
+ * relative-path reference will be returned as-is.
129
+ *
130
+ * echo UriResolver::relativize($base, new Uri('/a/b/c')); // prints 'c' as well
131
+ *
132
+ * @param UriInterface $base Base URI
133
+ * @param UriInterface $target Target URI
134
+ *
135
+ * @return UriInterface The relative URI reference
136
+ */
137
+ public static function relativize(UriInterface $base, UriInterface $target)
138
+ {
139
+ if ($target->getScheme() !== '' &&
140
+ ($base->getScheme() !== $target->getScheme() || $target->getAuthority() === '' && $base->getAuthority() !== '')
141
+ ) {
142
+ return $target;
143
+ }
144
+
145
+ if (Uri::isRelativePathReference($target)) {
146
+ // As the target is already highly relative we return it as-is. It would be possible to resolve
147
+ // the target with `$target = self::resolve($base, $target);` and then try make it more relative
148
+ // by removing a duplicate query. But let's not do that automatically.
149
+ return $target;
150
+ }
151
+
152
+ if ($target->getAuthority() !== '' && $base->getAuthority() !== $target->getAuthority()) {
153
+ return $target->withScheme('');
154
+ }
155
+
156
+ // We must remove the path before removing the authority because if the path starts with two slashes, the URI
157
+ // would turn invalid. And we also cannot set a relative path before removing the authority, as that is also
158
+ // invalid.
159
+ $emptyPathUri = $target->withScheme('')->withPath('')->withUserInfo('')->withPort(null)->withHost('');
160
+
161
+ if ($base->getPath() !== $target->getPath()) {
162
+ return $emptyPathUri->withPath(self::getRelativePath($base, $target));
163
+ }
164
+
165
+ if ($base->getQuery() === $target->getQuery()) {
166
+ // Only the target fragment is left. And it must be returned even if base and target fragment are the same.
167
+ return $emptyPathUri->withQuery('');
168
+ }
169
+
170
+ // If the base URI has a query but the target has none, we cannot return an empty path reference as it would
171
+ // inherit the base query component when resolving.
172
+ if ($target->getQuery() === '') {
173
+ $segments = explode('/', $target->getPath());
174
+ $lastSegment = end($segments);
175
+
176
+ return $emptyPathUri->withPath($lastSegment === '' ? './' : $lastSegment);
177
+ }
178
+
179
+ return $emptyPathUri;
180
+ }
181
+
182
+ private static function getRelativePath(UriInterface $base, UriInterface $target)
183
+ {
184
+ $sourceSegments = explode('/', $base->getPath());
185
+ $targetSegments = explode('/', $target->getPath());
186
+ array_pop($sourceSegments);
187
+ $targetLastSegment = array_pop($targetSegments);
188
+ foreach ($sourceSegments as $i => $segment) {
189
+ if (isset($targetSegments[$i]) && $segment === $targetSegments[$i]) {
190
+ unset($sourceSegments[$i], $targetSegments[$i]);
191
+ } else {
192
+ break;
193
+ }
194
+ }
195
+ $targetSegments[] = $targetLastSegment;
196
+ $relativePath = str_repeat('../', count($sourceSegments)) . implode('/', $targetSegments);
197
+
198
+ // A reference to am empty last segment or an empty first sub-segment must be prefixed with "./".
199
+ // This also applies to a segment with a colon character (e.g., "file:colon") that cannot be used
200
+ // as the first segment of a relative-path reference, as it would be mistaken for a scheme name.
201
+ if ('' === $relativePath || false !== strpos(explode('/', $relativePath, 2)[0], ':')) {
202
+ $relativePath = "./$relativePath";
203
+ } elseif ('/' === $relativePath[0]) {
204
+ if ($base->getAuthority() != '' && $base->getPath() === '') {
205
+ // In this case an extra slash is added by resolve() automatically. So we must not add one here.
206
+ $relativePath = ".$relativePath";
207
+ } else {
208
+ $relativePath = "./$relativePath";
209
+ }
210
+ }
211
+
212
+ return $relativePath;
213
+ }
214
+
215
+ private function __construct()
216
+ {
217
+ // cannot be instantiated
218
+ }
219
+ }
vendor/guzzlehttp/psr7/src/functions.php ADDED
@@ -0,0 +1,898 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\MessageInterface;
5
+ use Psr\Http\Message\RequestInterface;
6
+ use Psr\Http\Message\ResponseInterface;
7
+ use Psr\Http\Message\ServerRequestInterface;
8
+ use Psr\Http\Message\StreamInterface;
9
+ use Psr\Http\Message\UriInterface;
10
+
11
+ /**
12
+ * Returns the string representation of an HTTP message.
13
+ *
14
+ * @param MessageInterface $message Message to convert to a string.
15
+ *
16
+ * @return string
17
+ */
18
+ function str(MessageInterface $message)
19
+ {
20
+ if ($message instanceof RequestInterface) {
21
+ $msg = trim($message->getMethod() . ' '
22
+ . $message->getRequestTarget())
23
+ . ' HTTP/' . $message->getProtocolVersion();
24
+ if (!$message->hasHeader('host')) {
25
+ $msg .= "\r\nHost: " . $message->getUri()->getHost();
26
+ }
27
+ } elseif ($message instanceof ResponseInterface) {
28
+ $msg = 'HTTP/' . $message->getProtocolVersion() . ' '
29
+ . $message->getStatusCode() . ' '
30
+ . $message->getReasonPhrase();
31
+ } else {
32
+ throw new \InvalidArgumentException('Unknown message type');
33
+ }
34
+
35
+ foreach ($message->getHeaders() as $name => $values) {
36
+ $msg .= "\r\n{$name}: " . implode(', ', $values);
37
+ }
38
+
39
+ return "{$msg}\r\n\r\n" . $message->getBody();
40
+ }
41
+
42
+ /**
43
+ * Returns a UriInterface for the given value.
44
+ *
45
+ * This function accepts a string or {@see Psr\Http\Message\UriInterface} and
46
+ * returns a UriInterface for the given value. If the value is already a
47
+ * `UriInterface`, it is returned as-is.
48
+ *
49
+ * @param string|UriInterface $uri
50
+ *
51
+ * @return UriInterface
52
+ * @throws \InvalidArgumentException
53
+ */
54
+ function uri_for($uri)
55
+ {
56
+ if ($uri instanceof UriInterface) {
57
+ return $uri;
58
+ } elseif (is_string($uri)) {
59
+ return new Uri($uri);
60
+ }
61
+
62
+ throw new \InvalidArgumentException('URI must be a string or UriInterface');
63
+ }
64
+
65
+ /**
66
+ * Create a new stream based on the input type.
67
+ *
68
+ * Options is an associative array that can contain the following keys:
69
+ * - metadata: Array of custom metadata.
70
+ * - size: Size of the stream.
71
+ *
72
+ * @param resource|string|null|int|float|bool|StreamInterface|callable|\Iterator $resource Entity body data
73
+ * @param array $options Additional options
74
+ *
75
+ * @return StreamInterface
76
+ * @throws \InvalidArgumentException if the $resource arg is not valid.
77
+ */
78
+ function stream_for($resource = '', array $options = [])
79
+ {
80
+ if (is_scalar($resource)) {
81
+ $stream = fopen('php://temp', 'r+');
82
+ if ($resource !== '') {
83
+ fwrite($stream, $resource);
84
+ fseek($stream, 0);
85
+ }
86
+ return new Stream($stream, $options);
87
+ }
88
+
89
+ switch (gettype($resource)) {
90
+ case 'resource':
91
+ return new Stream($resource, $options);
92
+ case 'object':
93
+ if ($resource instanceof StreamInterface) {
94
+ return $resource;
95
+ } elseif ($resource instanceof \Iterator) {
96
+ return new PumpStream(function () use ($resource) {
97
+ if (!$resource->valid()) {
98
+ return false;
99
+ }
100
+ $result = $resource->current();
101
+ $resource->next();
102
+ return $result;
103
+ }, $options);
104
+ } elseif (method_exists($resource, '__toString')) {
105
+ return stream_for((string) $resource, $options);
106
+ }
107
+ break;
108
+ case 'NULL':
109
+ return new Stream(fopen('php://temp', 'r+'), $options);
110
+ }
111
+
112
+ if (is_callable($resource)) {
113
+ return new PumpStream($resource, $options);
114
+ }
115
+
116
+ throw new \InvalidArgumentException('Invalid resource type: ' . gettype($resource));
117
+ }
118
+
119
+ /**
120
+ * Parse an array of header values containing ";" separated data into an
121
+ * array of associative arrays representing the header key value pair
122
+ * data of the header. When a parameter does not contain a value, but just
123
+ * contains a key, this function will inject a key with a '' string value.
124
+ *
125
+ * @param string|array $header Header to parse into components.
126
+ *
127
+ * @return array Returns the parsed header values.
128
+ */
129
+ function parse_header($header)
130
+ {
131
+ static $trimmed = "\"' \n\t\r";
132
+ $params = $matches = [];
133
+
134
+ foreach (normalize_header($header) as $val) {
135
+ $part = [];
136
+ foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) as $kvp) {
137
+ if (preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches)) {
138
+ $m = $matches[0];
139
+ if (isset($m[1])) {
140
+ $part[trim($m[0], $trimmed)] = trim($m[1], $trimmed);
141
+ } else {
142
+ $part[] = trim($m[0], $trimmed);
143
+ }
144
+ }
145
+ }
146
+ if ($part) {
147
+ $params[] = $part;
148
+ }
149
+ }
150
+
151
+ return $params;
152
+ }
153
+
154
+ /**
155
+ * Converts an array of header values that may contain comma separated
156
+ * headers into an array of headers with no comma separated values.
157
+ *
158
+ * @param string|array $header Header to normalize.
159
+ *
160
+ * @return array Returns the normalized header field values.
161
+ */
162
+ function normalize_header($header)
163
+ {
164
+ if (!is_array($header)) {
165
+ return array_map('trim', explode(',', $header));
166
+ }
167
+
168
+ $result = [];
169
+ foreach ($header as $value) {
170
+ foreach ((array) $value as $v) {
171
+ if (strpos($v, ',') === false) {
172
+ $result[] = $v;
173
+ continue;
174
+ }
175
+ foreach (preg_split('/,(?=([^"]*"[^"]*")*[^"]*$)/', $v) as $vv) {
176
+ $result[] = trim($vv);
177
+ }
178
+ }
179
+ }
180
+
181
+ return $result;
182
+ }
183
+
184
+ /**
185
+ * Clone and modify a request with the given changes.
186
+ *
187
+ * The changes can be one of:
188
+ * - method: (string) Changes the HTTP method.
189
+ * - set_headers: (array) Sets the given headers.
190
+ * - remove_headers: (array) Remove the given headers.
191
+ * - body: (mixed) Sets the given body.
192
+ * - uri: (UriInterface) Set the URI.
193
+ * - query: (string) Set the query string value of the URI.
194
+ * - version: (string) Set the protocol version.
195
+ *
196
+ * @param RequestInterface $request Request to clone and modify.
197
+ * @param array $changes Changes to apply.
198
+ *
199
+ * @return RequestInterface
200
+ */
201
+ function modify_request(RequestInterface $request, array $changes)
202
+ {
203
+ if (!$changes) {
204
+ return $request;
205
+ }
206
+
207
+ $headers = $request->getHeaders();
208
+
209
+ if (!isset($changes['uri'])) {
210
+ $uri = $request->getUri();
211
+ } else {
212
+ // Remove the host header if one is on the URI
213
+ if ($host = $changes['uri']->getHost()) {
214
+ $changes['set_headers']['Host'] = $host;
215
+
216
+ if ($port = $changes['uri']->getPort()) {
217
+ $standardPorts = ['http' => 80, 'https' => 443];
218
+ $scheme = $changes['uri']->getScheme();
219
+ if (isset($standardPorts[$scheme]) && $port != $standardPorts[$scheme]) {
220
+ $changes['set_headers']['Host'] .= ':'.$port;
221
+ }
222
+ }
223
+ }
224
+ $uri = $changes['uri'];
225
+ }
226
+
227
+ if (!empty($changes['remove_headers'])) {
228
+ $headers = _caseless_remove($changes['remove_headers'], $headers);
229
+ }
230
+
231
+ if (!empty($changes['set_headers'])) {
232
+ $headers = _caseless_remove(array_keys($changes['set_headers']), $headers);
233
+ $headers = $changes['set_headers'] + $headers;
234
+ }
235
+
236
+ if (isset($changes['query'])) {
237
+ $uri = $uri->withQuery($changes['query']);
238
+ }
239
+
240
+ if ($request instanceof ServerRequestInterface) {
241
+ return (new ServerRequest(
242
+ isset($changes['method']) ? $changes['method'] : $request->getMethod(),
243
+ $uri,
244
+ $headers,
245
+ isset($changes['body']) ? $changes['body'] : $request->getBody(),
246
+ isset($changes['version'])
247
+ ? $changes['version']
248
+ : $request->getProtocolVersion(),
249
+ $request->getServerParams()
250
+ ))
251
+ ->withParsedBody($request->getParsedBody())
252
+ ->withQueryParams($request->getQueryParams())
253
+ ->withCookieParams($request->getCookieParams())
254
+ ->withUploadedFiles($request->getUploadedFiles());
255
+ }
256
+
257
+ return new Request(
258
+ isset($changes['method']) ? $changes['method'] : $request->getMethod(),
259
+ $uri,
260
+ $headers,
261
+ isset($changes['body']) ? $changes['body'] : $request->getBody(),
262
+ isset($changes['version'])
263
+ ? $changes['version']
264
+ : $request->getProtocolVersion()
265
+ );
266
+ }
267
+
268
+ /**
269
+ * Attempts to rewind a message body and throws an exception on failure.
270
+ *
271
+ * The body of the message will only be rewound if a call to `tell()` returns a
272
+ * value other than `0`.
273
+ *
274
+ * @param MessageInterface $message Message to rewind
275
+ *
276
+ * @throws \RuntimeException
277
+ */
278
+ function rewind_body(MessageInterface $message)
279
+ {
280
+ $body = $message->getBody();
281
+
282
+ if ($body->tell()) {
283
+ $body->rewind();
284
+ }
285
+ }
286
+
287
+ /**
288
+ * Safely opens a PHP stream resource using a filename.
289
+ *
290
+ * When fopen fails, PHP normally raises a warning. This function adds an
291
+ * error handler that checks for errors and throws an exception instead.
292
+ *
293
+ * @param string $filename File to open
294
+ * @param string $mode Mode used to open the file
295
+ *
296
+ * @return resource
297
+ * @throws \RuntimeException if the file cannot be opened
298
+ */
299
+ function try_fopen($filename, $mode)
300
+ {
301
+ $ex = null;
302
+ set_error_handler(function () use ($filename, $mode, &$ex) {
303
+ $ex = new \RuntimeException(sprintf(
304
+ 'Unable to open %s using mode %s: %s',
305
+ $filename,
306
+ $mode,
307
+ func_get_args()[1]
308
+ ));
309
+ });
310
+
311
+ $handle = fopen($filename, $mode);
312
+ restore_error_handler();
313
+
314
+ if ($ex) {
315
+ /** @var $ex \RuntimeException */
316
+ throw $ex;
317
+ }
318
+
319
+ return $handle;
320
+ }
321
+
322
+ /**
323
+ * Copy the contents of a stream into a string until the given number of
324
+ * bytes have been read.
325
+ *
326
+ * @param StreamInterface $stream Stream to read
327
+ * @param int $maxLen Maximum number of bytes to read. Pass -1
328
+ * to read the entire stream.
329
+ * @return string
330
+ * @throws \RuntimeException on error.
331
+ */
332
+ function copy_to_string(StreamInterface $stream, $maxLen = -1)
333
+ {
334
+ $buffer = '';
335
+
336
+ if ($maxLen === -1) {
337
+ while (!$stream->eof()) {
338
+ $buf = $stream->read(1048576);
339
+ // Using a loose equality here to match on '' and false.
340
+ if ($buf == null) {
341
+ break;
342
+ }
343
+ $buffer .= $buf;
344
+ }
345
+ return $buffer;
346
+ }
347
+
348
+ $len = 0;
349
+ while (!$stream->eof() && $len < $maxLen) {
350
+ $buf = $stream->read($maxLen - $len);
351
+ // Using a loose equality here to match on '' and false.
352
+ if ($buf == null) {
353
+ break;
354
+ }
355
+ $buffer .= $buf;
356
+ $len = strlen($buffer);
357
+ }
358
+
359
+ return $buffer;
360
+ }
361
+
362
+ /**
363
+ * Copy the contents of a stream into another stream until the given number
364
+ * of bytes have been read.
365
+ *
366
+ * @param StreamInterface $source Stream to read from
367
+ * @param StreamInterface $dest Stream to write to
368
+ * @param int $maxLen Maximum number of bytes to read. Pass -1
369
+ * to read the entire stream.
370
+ *
371
+ * @throws \RuntimeException on error.
372
+ */
373
+ function copy_to_stream(
374
+ StreamInterface $source,
375
+ StreamInterface $dest,
376
+ $maxLen = -1
377
+ ) {
378
+ $bufferSize = 8192;
379
+
380
+ if ($maxLen === -1) {
381
+ while (!$source->eof()) {
382
+ if (!$dest->write($source->read($bufferSize))) {
383
+ break;
384
+ }
385
+ }
386
+ } else {
387
+ $remaining = $maxLen;
388
+ while ($remaining > 0 && !$source->eof()) {
389
+ $buf = $source->read(min($bufferSize, $remaining));
390
+ $len = strlen($buf);
391
+ if (!$len) {
392
+ break;
393
+ }
394
+ $remaining -= $len;
395
+ $dest->write($buf);
396
+ }
397
+ }
398
+ }
399
+
400
+ /**
401
+ * Calculate a hash of a Stream
402
+ *
403
+ * @param StreamInterface $stream Stream to calculate the hash for
404
+ * @param string $algo Hash algorithm (e.g. md5, crc32, etc)
405
+ * @param bool $rawOutput Whether or not to use raw output
406
+ *
407
+ * @return string Returns the hash of the stream
408
+ * @throws \RuntimeException on error.
409
+ */
410
+ function hash(
411
+ StreamInterface $stream,
412
+ $algo,
413
+ $rawOutput = false
414
+ ) {
415
+ $pos = $stream->tell();
416
+
417
+ if ($pos > 0) {
418
+ $stream->rewind();
419
+ }
420
+
421
+ $ctx = hash_init($algo);
422
+ while (!$stream->eof()) {
423
+ hash_update($ctx, $stream->read(1048576));
424
+ }
425
+
426
+ $out = hash_final($ctx, (bool) $rawOutput);
427
+ $stream->seek($pos);
428
+
429
+ return $out;
430
+ }
431
+
432
+ /**
433
+ * Read a line from the stream up to the maximum allowed buffer length
434
+ *
435
+ * @param StreamInterface $stream Stream to read from
436
+ * @param int $maxLength Maximum buffer length
437
+ *
438
+ * @return string
439
+ */
440
+ function readline(StreamInterface $stream, $maxLength = null)
441
+ {
442
+ $buffer = '';
443
+ $size = 0;
444
+
445
+ while (!$stream->eof()) {
446
+ // Using a loose equality here to match on '' and false.
447
+ if (null == ($byte = $stream->read(1))) {
448
+ return $buffer;
449
+ }
450
+ $buffer .= $byte;
451
+ // Break when a new line is found or the max length - 1 is reached
452
+ if ($byte === "\n" || ++$size === $maxLength - 1) {
453
+ break;
454
+ }
455
+ }
456
+
457
+ return $buffer;
458
+ }
459
+
460
+ /**
461
+ * Parses a request message string into a request object.
462
+ *
463
+ * @param string $message Request message string.
464
+ *
465
+ * @return Request
466
+ */
467
+ function parse_request($message)
468
+ {
469
+ $data = _parse_message($message);
470
+ $matches = [];
471
+ if (!preg_match('/^[\S]+\s+([a-zA-Z]+:\/\/|\/).*/', $data['start-line'], $matches)) {
472
+ throw new \InvalidArgumentException('Invalid request string');
473
+ }
474
+ $parts = explode(' ', $data['start-line'], 3);
475
+ $version = isset($parts[2]) ? explode('/', $parts[2])[1] : '1.1';
476
+
477
+ $request = new Request(
478
+ $parts[0],
479
+ $matches[1] === '/' ? _parse_request_uri($parts[1], $data['headers']) : $parts[1],
480
+ $data['headers'],
481
+ $data['body'],
482
+ $version
483
+ );
484
+
485
+ return $matches[1] === '/' ? $request : $request->withRequestTarget($parts[1]);
486
+ }
487
+
488
+ /**
489
+ * Parses a response message string into a response object.
490
+ *
491
+ * @param string $message Response message string.
492
+ *
493
+ * @return Response
494
+ */
495
+ function parse_response($message)
496
+ {
497
+ $data = _parse_message($message);
498
+ // According to https://tools.ietf.org/html/rfc7230#section-3.1.2 the space
499
+ // between status-code and reason-phrase is required. But browsers accept
500
+ // responses without space and reason as well.
501
+ if (!preg_match('/^HTTP\/.* [0-9]{3}( .*|$)/', $data['start-line'])) {
502
+ throw new \InvalidArgumentException('Invalid response string: ' . $data['start-line']);
503
+ }
504
+ $parts = explode(' ', $data['start-line'], 3);
505
+
506
+ return new Response(
507
+ $parts[1],
508
+ $data['headers'],
509
+ $data['body'],
510
+ explode('/', $parts[0])[1],
511
+ isset($parts[2]) ? $parts[2] : null
512
+ );
513
+ }
514
+
515
+ /**
516
+ * Parse a query string into an associative array.
517
+ *
518
+ * If multiple values are found for the same key, the value of that key
519
+ * value pair will become an array. This function does not parse nested
520
+ * PHP style arrays into an associative array (e.g., foo[a]=1&foo[b]=2 will
521
+ * be parsed into ['foo[a]' => '1', 'foo[b]' => '2']).
522
+ *
523
+ * @param string $str Query string to parse
524
+ * @param int|bool $urlEncoding How the query string is encoded
525
+ *
526
+ * @return array
527
+ */
528
+ function parse_query($str, $urlEncoding = true)
529
+ {
530
+ $result = [];
531
+
532
+ if ($str === '') {
533
+ return $result;
534
+ }
535
+
536
+ if ($urlEncoding === true) {
537
+ $decoder = function ($value) {
538
+ return rawurldecode(str_replace('+', ' ', $value));
539
+ };
540
+ } elseif ($urlEncoding === PHP_QUERY_RFC3986) {
541
+ $decoder = 'rawurldecode';
542
+ } elseif ($urlEncoding === PHP_QUERY_RFC1738) {
543
+ $decoder = 'urldecode';
544
+ } else {
545
+ $decoder = function ($str) { return $str; };
546
+ }
547
+
548
+ foreach (explode('&', $str) as $kvp) {
549
+ $parts = explode('=', $kvp, 2);
550
+ $key = $decoder($parts[0]);
551
+ $value = isset($parts[1]) ? $decoder($parts[1]) : null;
552
+ if (!isset($result[$key])) {
553
+ $result[$key] = $value;
554
+ } else {
555
+ if (!is_array($result[$key])) {
556
+ $result[$key] = [$result[$key]];
557
+ }
558
+ $result[$key][] = $value;
559
+ }
560
+ }
561
+
562
+ return $result;
563
+ }
564
+
565
+ /**
566
+ * Build a query string from an array of key value pairs.
567
+ *
568
+ * This function can use the return value of parse_query() to build a query
569
+ * string. This function does not modify the provided keys when an array is
570
+ * encountered (like http_build_query would).
571
+ *
572
+ * @param array $params Query string parameters.
573
+ * @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986
574
+ * to encode using RFC3986, or PHP_QUERY_RFC1738
575
+ * to encode using RFC1738.
576
+ * @return string
577
+ */
578
+ function build_query(array $params, $encoding = PHP_QUERY_RFC3986)
579
+ {
580
+ if (!$params) {
581
+ return '';
582
+ }
583
+
584
+ if ($encoding === false) {
585
+ $encoder = function ($str) { return $str; };
586
+ } elseif ($encoding === PHP_QUERY_RFC3986) {
587
+ $encoder = 'rawurlencode';
588
+ } elseif ($encoding === PHP_QUERY_RFC1738) {
589
+ $encoder = 'urlencode';
590
+ } else {
591
+ throw new \InvalidArgumentException('Invalid type');
592
+ }
593
+
594
+ $qs = '';
595
+ foreach ($params as $k => $v) {
596
+ $k = $encoder($k);
597
+ if (!is_array($v)) {
598
+ $qs .= $k;
599
+ if ($v !== null) {
600
+ $qs .= '=' . $encoder($v);
601
+ }
602
+ $qs .= '&';
603
+ } else {
604
+ foreach ($v as $vv) {
605
+ $qs .= $k;
606
+ if ($vv !== null) {
607
+ $qs .= '=' . $encoder($vv);
608
+ }
609
+ $qs .= '&';
610
+ }
611
+ }
612
+ }
613
+
614
+ return $qs ? (string) substr($qs, 0, -1) : '';
615
+ }
616
+
617
+ /**
618
+ * Determines the mimetype of a file by looking at its extension.
619
+ *
620
+ * @param $filename
621
+ *
622
+ * @return null|string
623
+ */
624
+ function mimetype_from_filename($filename)
625
+ {
626
+ return mimetype_from_extension(pathinfo($filename, PATHINFO_EXTENSION));
627
+ }
628
+
629
+ /**
630
+ * Maps a file extensions to a mimetype.
631
+ *
632
+ * @param $extension string The file extension.
633
+ *
634
+ * @return string|null
635
+ * @link http://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x/conf/mime.types
636
+ */
637
+ function mimetype_from_extension($extension)
638
+ {
639
+ static $mimetypes = [
640
+ '3gp' => 'video/3gpp',
641
+ '7z' => 'application/x-7z-compressed',
642
+ 'aac' => 'audio/x-aac',
643
+ 'ai' => 'application/postscript',
644
+ 'aif' => 'audio/x-aiff',
645
+ 'asc' => 'text/plain',
646
+ 'asf' => 'video/x-ms-asf',
647
+ 'atom' => 'application/atom+xml',
648
+ 'avi' => 'video/x-msvideo',
649
+ 'bmp' => 'image/bmp',
650
+ 'bz2' => 'application/x-bzip2',
651
+ 'cer' => 'application/pkix-cert',
652
+ 'crl' => 'application/pkix-crl',
653
+ 'crt' => 'application/x-x509-ca-cert',
654
+ 'css' => 'text/css',
655
+ 'csv' => 'text/csv',
656
+ 'cu' => 'application/cu-seeme',
657
+ 'deb' => 'application/x-debian-package',
658
+ 'doc' => 'application/msword',
659
+ 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
660
+ 'dvi' => 'application/x-dvi',
661
+ 'eot' => 'application/vnd.ms-fontobject',
662
+ 'eps' => 'application/postscript',
663
+ 'epub' => 'application/epub+zip',
664
+ 'etx' => 'text/x-setext',
665
+ 'flac' => 'audio/flac',
666
+ 'flv' => 'video/x-flv',
667
+ 'gif' => 'image/gif',
668
+ 'gz' => 'application/gzip',
669
+ 'htm' => 'text/html',
670
+ 'html' => 'text/html',
671
+ 'ico' => 'image/x-icon',
672
+ 'ics' => 'text/calendar',
673
+ 'ini' => 'text/plain',
674
+ 'iso' => 'application/x-iso9660-image',
675
+ 'jar' => 'application/java-archive',
676
+ 'jpe' => 'image/jpeg',
677
+ 'jpeg' => 'image/jpeg',
678
+ 'jpg' => 'image/jpeg',
679
+ 'js' => 'text/javascript',
680
+ 'json' => 'application/json',
681
+ 'latex' => 'application/x-latex',
682
+ 'log' => 'text/plain',
683
+ 'm4a' => 'audio/mp4',
684
+ 'm4v' => 'video/mp4',
685
+ 'mid' => 'audio/midi',
686
+ 'midi' => 'audio/midi',
687
+ 'mov' => 'video/quicktime',
688
+ 'mkv' => 'video/x-matroska',
689
+ 'mp3' => 'audio/mpeg',
690
+ 'mp4' => 'video/mp4',
691
+ 'mp4a' => 'audio/mp4',
692
+ 'mp4v' => 'video/mp4',
693
+ 'mpe' => 'video/mpeg',
694
+ 'mpeg' => 'video/mpeg',
695
+ 'mpg' => 'video/mpeg',
696
+ 'mpg4' => 'video/mp4',
697
+ 'oga' => 'audio/ogg',
698
+ 'ogg' => 'audio/ogg',
699
+ 'ogv' => 'video/ogg',
700
+ 'ogx' => 'application/ogg',
701
+ 'pbm' => 'image/x-portable-bitmap',
702
+ 'pdf' => 'application/pdf',
703
+ 'pgm' => 'image/x-portable-graymap',
704
+ 'png' => 'image/png',
705
+ 'pnm' => 'image/x-portable-anymap',
706
+ 'ppm' => 'image/x-portable-pixmap',
707
+ 'ppt' => 'application/vnd.ms-powerpoint',
708
+ 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
709
+ 'ps' => 'application/postscript',
710
+ 'qt' => 'video/quicktime',
711
+ 'rar' => 'application/x-rar-compressed',
712
+ 'ras' => 'image/x-cmu-raster',
713
+ 'rss' => 'application/rss+xml',
714
+ 'rtf' => 'application/rtf',
715
+ 'sgm' => 'text/sgml',
716
+ 'sgml' => 'text/sgml',
717
+ 'svg' => 'image/svg+xml',
718
+ 'swf' => 'application/x-shockwave-flash',
719
+ 'tar' => 'application/x-tar',
720
+ 'tif' => 'image/tiff',
721
+ 'tiff' => 'image/tiff',
722
+ 'torrent' => 'application/x-bittorrent',
723
+ 'ttf' => 'application/x-font-ttf',
724
+ 'txt' => 'text/plain',
725
+ 'wav' => 'audio/x-wav',
726
+ 'webm' => 'video/webm',
727
+ 'wma' => 'audio/x-ms-wma',
728
+ 'wmv' => 'video/x-ms-wmv',
729
+ 'woff' => 'application/x-font-woff',
730
+ 'wsdl' => 'application/wsdl+xml',
731
+ 'xbm' => 'image/x-xbitmap',
732
+ 'xls' => 'application/vnd.ms-excel',
733
+ 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
734
+ 'xml' => 'application/xml',
735
+ 'xpm' => 'image/x-xpixmap',
736
+ 'xwd' => 'image/x-xwindowdump',
737
+ 'yaml' => 'text/yaml',
738
+ 'yml' => 'text/yaml',
739
+ 'zip' => 'application/zip',
740
+ ];
741
+
742
+ $extension = strtolower($extension);
743
+
744
+ return isset($mimetypes[$extension])
745
+ ? $mimetypes[$extension]
746
+ : null;
747
+ }
748
+
749
+ /**
750
+ * Parses an HTTP message into an associative array.
751
+ *
752
+ * The array contains the "start-line" key containing the start line of
753
+ * the message, "headers" key containing an associative array of header
754
+ * array values, and a "body" key containing the body of the message.
755
+ *
756
+ * @param string $message HTTP request or response to parse.
757
+ *
758
+ * @return array
759
+ * @internal
760
+ */
761
+ function _parse_message($message)
762
+ {
763
+ if (!$message) {
764
+ throw new \InvalidArgumentException('Invalid message');
765
+ }
766
+
767
+ $message = ltrim($message, "\r\n");
768
+
769
+ $messageParts = preg_split("/\r?\n\r?\n/", $message, 2);
770
+
771
+ if ($messageParts === false || count($messageParts) !== 2) {
772
+ throw new \InvalidArgumentException('Invalid message: Missing header delimiter');
773
+ }
774
+
775
+ list($rawHeaders, $body) = $messageParts;
776
+ $rawHeaders .= "\r\n"; // Put back the delimiter we split previously
777
+ $headerParts = preg_split("/\r?\n/", $rawHeaders, 2);
778
+
779
+ if ($headerParts === false || count($headerParts) !== 2) {
780
+ throw new \InvalidArgumentException('Invalid message: Missing status line');
781
+ }
782
+
783
+ list($startLine, $rawHeaders) = $headerParts;
784
+
785
+ if (preg_match("/(?:^HTTP\/|^[A-Z]+ \S+ HTTP\/)(\d+(?:\.\d+)?)/i", $startLine, $matches) && $matches[1] === '1.0') {
786
+ // Header folding is deprecated for HTTP/1.1, but allowed in HTTP/1.0
787
+ $rawHeaders = preg_replace(Rfc7230::HEADER_FOLD_REGEX, ' ', $rawHeaders);
788
+ }
789
+
790
+ /** @var array[] $headerLines */
791
+ $count = preg_match_all(Rfc7230::HEADER_REGEX, $rawHeaders, $headerLines, PREG_SET_ORDER);
792
+
793
+ // If these aren't the same, then one line didn't match and there's an invalid header.
794
+ if ($count !== substr_count($rawHeaders, "\n")) {
795
+ // Folding is deprecated, see https://tools.ietf.org/html/rfc7230#section-3.2.4
796
+ if (preg_match(Rfc7230::HEADER_FOLD_REGEX, $rawHeaders)) {
797
+ throw new \InvalidArgumentException('Invalid header syntax: Obsolete line folding');
798
+ }
799
+
800
+ throw new \InvalidArgumentException('Invalid header syntax');
801
+ }
802
+
803
+ $headers = [];
804
+
805
+ foreach ($headerLines as $headerLine) {
806
+ $headers[$headerLine[1]][] = $headerLine[2];
807
+ }
808
+
809
+ return [
810
+ 'start-line' => $startLine,
811
+ 'headers' => $headers,
812
+ 'body' => $body,
813
+ ];
814
+ }
815
+
816
+ /**
817
+ * Constructs a URI for an HTTP request message.
818
+ *
819
+ * @param string $path Path from the start-line
820
+ * @param array $headers Array of headers (each value an array).
821
+ *
822
+ * @return string
823
+ * @internal
824
+ */
825
+ function _parse_request_uri($path, array $headers)
826
+ {
827
+ $hostKey = array_filter(array_keys($headers), function ($k) {
828
+ return strtolower($k) === 'host';
829
+ });
830
+
831
+ // If no host is found, then a full URI cannot be constructed.
832
+ if (!$hostKey) {
833
+ return $path;
834
+ }
835
+
836
+ $host = $headers[reset($hostKey)][0];
837
+ $scheme = substr($host, -4) === ':443' ? 'https' : 'http';
838
+
839
+ return $scheme . '://' . $host . '/' . ltrim($path, '/');
840
+ }
841
+
842
+ /**
843
+ * Get a short summary of the message body
844
+ *
845
+ * Will return `null` if the response is not printable.
846
+ *
847
+ * @param MessageInterface $message The message to get the body summary
848
+ * @param int $truncateAt The maximum allowed size of the summary
849
+ *
850
+ * @return null|string
851
+ */
852
+ function get_message_body_summary(MessageInterface $message, $truncateAt = 120)
853
+ {
854
+ $body = $message->getBody();
855
+
856
+ if (!$body->isSeekable() || !$body->isReadable()) {
857
+ return null;
858
+ }
859
+
860
+ $size = $body->getSize();
861
+
862
+ if ($size === 0) {
863
+ return null;
864
+ }
865
+
866
+ $summary = $body->read($truncateAt);
867
+ $body->rewind();
868
+
869
+ if ($size > $truncateAt) {
870
+ $summary .= ' (truncated...)';
871
+ }
872
+
873
+ // Matches any printable character, including unicode characters:
874
+ // letters, marks, numbers, punctuation, spacing, and separators.
875
+ if (preg_match('/[^\pL\pM\pN\pP\pS\pZ\n\r\t]/', $summary)) {
876
+ return null;
877
+ }
878
+
879
+ return $summary;
880
+ }
881
+
882
+ /** @internal */
883
+ function _caseless_remove($keys, array $data)
884
+ {
885
+ $result = [];
886
+
887
+ foreach ($keys as &$key) {
888
+ $key = strtolower($key);
889
+ }
890
+
891
+ foreach ($data as $k => $v) {
892
+ if (!in_array(strtolower($k), $keys)) {
893
+ $result[$k] = $v;
894
+ }
895
+ }
896
+
897
+ return $result;
898
+ }
vendor/guzzlehttp/psr7/src/functions_include.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // Don't redefine the functions if included multiple times.
4
+ if (!function_exists('GuzzleHttp\Psr7\str')) {
5
+ require __DIR__ . '/functions.php';
6
+ }
vendor/psr/http-message/CHANGELOG.md ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file, in reverse chronological order by release.
4
+
5
+ ## 1.0.1 - 2016-08-06
6
+
7
+ ### Added
8
+
9
+ - Nothing.
10
+
11
+ ### Deprecated
12
+
13
+ - Nothing.
14
+
15
+ ### Removed
16
+
17
+ - Nothing.
18
+
19
+ ### Fixed
20
+
21
+ - Updated all `@return self` annotation references in interfaces to use
22
+ `@return static`, which more closelly follows the semantics of the
23
+ specification.
24
+ - Updated the `MessageInterface::getHeaders()` return annotation to use the
25
+ value `string[][]`, indicating the format is a nested array of strings.
26
+ - Updated the `@link` annotation for `RequestInterface::withRequestTarget()`
27
+ to point to the correct section of RFC 7230.
28
+ - Updated the `ServerRequestInterface::withUploadedFiles()` parameter annotation
29
+ to add the parameter name (`$uploadedFiles`).
30
+ - Updated a `@throws` annotation for the `UploadedFileInterface::moveTo()`
31
+ method to correctly reference the method parameter (it was referencing an
32
+ incorrect parameter name previously).
33
+
34
+ ## 1.0.0 - 2016-05-18
35
+
36
+ Initial stable release; reflects accepted PSR-7 specification.
vendor/psr/http-message/LICENSE ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright (c) 2014 PHP Framework Interoperability Group
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.
vendor/psr/http-message/README.md ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ PSR Http Message
2
+ ================
3
+
4
+ This repository holds all interfaces/classes/traits related to
5
+ [PSR-7](http://www.php-fig.org/psr/psr-7/).
6
+
7
+ Note that this is not a HTTP message implementation of its own. It is merely an
8
+ interface that describes a HTTP message. See the specification for more details.
9
+
10
+ Usage
11
+ -----
12
+
13
+ We'll certainly need some stuff in here.
vendor/psr/http-message/src/MessageInterface.php ADDED
@@ -0,0 +1,187 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Psr\Http\Message;
4
+
5
+ /**
6
+ * HTTP messages consist of requests from a client to a server and responses
7
+ * from a server to a client. This interface defines the methods common to
8
+ * each.
9
+ *
10
+ * Messages are considered immutable; all methods that might change state MUST
11
+ * be implemented such that they retain the internal state of the current
12
+ * message and return an instance that contains the changed state.
13
+ *
14
+ * @link http://www.ietf.org/rfc/rfc7230.txt
15
+ * @link http://www.ietf.org/rfc/rfc7231.txt
16
+ */
17
+ interface MessageInterface
18
+ {
19
+ /**
20
+ * Retrieves the HTTP protocol version as a string.
21
+ *
22
+ * The string MUST contain only the HTTP version number (e.g., "1.1", "1.0").
23
+ *
24
+ * @return string HTTP protocol version.
25
+ */
26
+ public function getProtocolVersion();
27
+
28
+ /**
29
+ * Return an instance with the specified HTTP protocol version.
30
+ *
31
+ * The version string MUST contain only the HTTP version number (e.g.,
32
+ * "1.1", "1.0").
33
+ *
34
+ * This method MUST be implemented in such a way as to retain the
35
+ * immutability of the message, and MUST return an instance that has the
36
+ * new protocol version.
37
+ *
38
+ * @param string $version HTTP protocol version
39
+ * @return static
40
+ */
41
+ public function withProtocolVersion($version);
42
+
43
+ /**
44
+ * Retrieves all message header values.
45
+ *
46
+ * The keys represent the header name as it will be sent over the wire, and
47
+ * each value is an array of strings associated with the header.
48
+ *
49
+ * // Represent the headers as a string
50
+ * foreach ($message->getHeaders() as $name => $values) {
51
+ * echo $name . ": " . implode(", ", $values);
52
+ * }
53
+ *
54
+ * // Emit headers iteratively:
55
+ * foreach ($message->getHeaders() as $name => $values) {
56
+ * foreach ($values as $value) {
57
+ * header(sprintf('%s: %s', $name, $value), false);
58
+ * }
59
+ * }
60
+ *
61
+ * While header names are not case-sensitive, getHeaders() will preserve the
62
+ * exact case in which headers were originally specified.
63
+ *
64
+ * @return string[][] Returns an associative array of the message's headers. Each
65
+ * key MUST be a header name, and each value MUST be an array of strings
66
+ * for that header.
67
+ */
68
+ public function getHeaders();
69
+
70
+ /**
71
+ * Checks if a header exists by the given case-insensitive name.
72
+ *
73
+ * @param string $name Case-insensitive header field name.
74
+ * @return bool Returns true if any header names match the given header
75
+ * name using a case-insensitive string comparison. Returns false if
76
+ * no matching header name is found in the message.
77
+ */
78
+ public function hasHeader($name);
79
+
80
+ /**
81
+ * Retrieves a message header value by the given case-insensitive name.
82
+ *
83
+ * This method returns an array of all the header values of the given
84
+ * case-insensitive header name.
85
+ *
86
+ * If the header does not appear in the message, this method MUST return an
87
+ * empty array.
88
+ *
89
+ * @param string $name Case-insensitive header field name.
90
+ * @return string[] An array of string values as provided for the given
91
+ * header. If the header does not appear in the message, this method MUST
92
+ * return an empty array.
93
+ */
94
+ public function getHeader($name);
95
+
96
+ /**
97
+ * Retrieves a comma-separated string of the values for a single header.
98
+ *
99
+ * This method returns all of the header values of the given
100
+ * case-insensitive header name as a string concatenated together using
101
+ * a comma.
102
+ *
103
+ * NOTE: Not all header values may be appropriately represented using
104
+ * comma concatenation. For such headers, use getHeader() instead
105
+ * and supply your own delimiter when concatenating.
106
+ *
107
+ * If the header does not appear in the message, this method MUST return
108
+ * an empty string.
109
+ *
110
+ * @param string $name Case-insensitive header field name.
111
+ * @return string A string of values as provided for the given header
112
+ * concatenated together using a comma. If the header does not appear in
113
+ * the message, this method MUST return an empty string.
114
+ */
115
+ public function getHeaderLine($name);
116
+
117
+ /**
118
+ * Return an instance with the provided value replacing the specified header.
119
+ *
120
+ * While header names are case-insensitive, the casing of the header will
121
+ * be preserved by this function, and returned from getHeaders().
122
+ *
123
+ * This method MUST be implemented in such a way as to retain the
124
+ * immutability of the message, and MUST return an instance that has the
125
+ * new and/or updated header and value.
126
+ *
127
+ * @param string $name Case-insensitive header field name.
128
+ * @param string|string[] $value Header value(s).
129
+ * @return static
130
+ * @throws \InvalidArgumentException for invalid header names or values.
131
+ */
132
+ public function withHeader($name, $value);
133
+
134
+ /**
135
+ * Return an instance with the specified header appended with the given value.
136
+ *
137
+ * Existing values for the specified header will be maintained. The new
138
+ * value(s) will be appended to the existing list. If the header did not
139
+ * exist previously, it will be added.
140
+ *
141
+ * This method MUST be implemented in such a way as to retain the
142
+ * immutability of the message, and MUST return an instance that has the
143
+ * new header and/or value.
144
+ *
145
+ * @param string $name Case-insensitive header field name to add.
146
+ * @param string|string[] $value Header value(s).
147
+ * @return static
148
+ * @throws \InvalidArgumentException for invalid header names or values.
149
+ */
150
+ public function withAddedHeader($name, $value);
151
+
152
+ /**
153
+ * Return an instance without the specified header.
154
+ *
155
+ * Header resolution MUST be done without case-sensitivity.
156
+ *
157
+ * This method MUST be implemented in such a way as to retain the
158
+ * immutability of the message, and MUST return an instance that removes
159
+ * the named header.
160
+ *
161
+ * @param string $name Case-insensitive header field name to remove.
162
+ * @return static
163
+ */
164
+ public function withoutHeader($name);
165
+
166
+ /**
167
+ * Gets the body of the message.
168
+ *
169
+ * @return StreamInterface Returns the body as a stream.
170
+ */
171
+ public function getBody();
172
+
173
+ /**
174
+ * Return an instance with the specified message body.
175
+ *
176
+ * The body MUST be a StreamInterface object.
177
+ *
178
+ * This method MUST be implemented in such a way as to retain the
179
+ * immutability of the message, and MUST return a new instance that has the
180
+ * new body stream.
181
+ *
182
+ * @param StreamInterface $body Body.
183
+ * @return static
184
+ * @throws \InvalidArgumentException When the body is not valid.
185
+ */
186
+ public function withBody(StreamInterface $body);
187
+ }
vendor/psr/http-message/src/RequestInterface.php ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Psr\Http\Message;
4
+
5
+ /**
6
+ * Representation of an outgoing, client-side request.
7
+ *
8
+ * Per the HTTP specification, this interface includes properties for
9
+ * each of the following:
10
+ *
11
+ * - Protocol version
12
+ * - HTTP method
13
+ * - URI
14
+ * - Headers
15
+ * - Message body
16
+ *
17
+ * During construction, implementations MUST attempt to set the Host header from
18
+ * a provided URI if no Host header is provided.
19
+ *
20
+ * Requests are considered immutable; all methods that might change state MUST
21
+ * be implemented such that they retain the internal state of the current
22
+ * message and return an instance that contains the changed state.
23
+ */
24
+ interface RequestInterface extends MessageInterface
25
+ {
26
+ /**
27
+ * Retrieves the message's request target.
28
+ *
29
+ * Retrieves the message's request-target either as it will appear (for
30
+ * clients), as it appeared at request (for servers), or as it was
31
+ * specified for the instance (see withRequestTarget()).
32
+ *
33
+ * In most cases, this will be the origin-form of the composed URI,
34
+ * unless a value was provided to the concrete implementation (see
35
+ * withRequestTarget() below).
36
+ *
37
+ * If no URI is available, and no request-target has been specifically
38
+ * provided, this method MUST return the string "/".
39
+ *
40
+ * @return string
41
+ */
42
+ public function getRequestTarget();
43
+
44
+ /**
45
+ * Return an instance with the specific request-target.
46
+ *
47
+ * If the request needs a non-origin-form request-target — e.g., for
48
+ * specifying an absolute-form, authority-form, or asterisk-form —
49
+ * this method may be used to create an instance with the specified
50
+ * request-target, verbatim.
51
+ *
52
+ * This method MUST be implemented in such a way as to retain the
53
+ * immutability of the message, and MUST return an instance that has the
54
+ * changed request target.
55
+ *
56
+ * @link http://tools.ietf.org/html/rfc7230#section-5.3 (for the various
57
+ * request-target forms allowed in request messages)
58
+ * @param mixed $requestTarget
59
+ * @return static
60
+ */
61
+ public function withRequestTarget($requestTarget);
62
+
63
+ /**
64
+ * Retrieves the HTTP method of the request.
65
+ *
66
+ * @return string Returns the request method.
67
+ */
68
+ public function getMethod();
69
+
70
+ /**
71
+ * Return an instance with the provided HTTP method.
72
+ *
73
+ * While HTTP method names are typically all uppercase characters, HTTP
74
+ * method names are case-sensitive and thus implementations SHOULD NOT
75
+ * modify the given string.
76
+ *
77
+ * This method MUST be implemented in such a way as to retain the
78
+ * immutability of the message, and MUST return an instance that has the
79
+ * changed request method.
80
+ *
81
+ * @param string $method Case-sensitive method.
82
+ * @return static
83
+ * @throws \InvalidArgumentException for invalid HTTP methods.
84
+ */
85
+ public function withMethod($method);
86
+
87
+ /**
88
+ * Retrieves the URI instance.
89
+ *
90
+ * This method MUST return a UriInterface instance.
91
+ *
92
+ * @link http://tools.ietf.org/html/rfc3986#section-4.3
93
+ * @return UriInterface Returns a UriInterface instance
94
+ * representing the URI of the request.
95
+ */
96
+ public function getUri();
97
+
98
+ /**
99
+ * Returns an instance with the provided URI.
100
+ *
101
+ * This method MUST update the Host header of the returned request by
102
+ * default if the URI contains a host component. If the URI does not
103
+ * contain a host component, any pre-existing Host header MUST be carried
104
+ * over to the returned request.
105
+ *
106
+ * You can opt-in to preserving the original state of the Host header by
107
+ * setting `$preserveHost` to `true`. When `$preserveHost` is set to
108
+ * `true`, this method interacts with the Host header in the following ways:
109
+ *
110
+ * - If the Host header is missing or empty, and the new URI contains
111
+ * a host component, this method MUST update the Host header in the returned
112
+ * request.
113
+ * - If the Host header is missing or empty, and the new URI does not contain a
114
+ * host component, this method MUST NOT update the Host header in the returned
115
+ * request.
116
+ * - If a Host header is present and non-empty, this method MUST NOT update
117
+ * the Host header in the returned request.
118
+ *
119
+ * This method MUST be implemented in such a way as to retain the
120
+ * immutability of the message, and MUST return an instance that has the
121
+ * new UriInterface instance.
122
+ *
123
+ * @link http://tools.ietf.org/html/rfc3986#section-4.3
124
+ * @param UriInterface $uri New request URI to use.
125
+ * @param bool $preserveHost Preserve the original state of the Host header.
126
+ * @return static
127
+ */
128
+ public function withUri(UriInterface $uri, $preserveHost = false);
129
+ }
vendor/psr/http-message/src/ResponseInterface.php ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Psr\Http\Message;
4
+
5
+ /**
6
+ * Representation of an outgoing, server-side response.
7
+ *
8
+ * Per the HTTP specification, this interface includes properties for
9
+ * each of the following:
10
+ *
11
+ * - Protocol version
12
+ * - Status code and reason phrase
13
+ * - Headers
14
+ * - Message body
15
+ *
16
+ * Responses are considered immutable; all methods that might change state MUST
17
+ * be implemented such that they retain the internal state of the current
18
+ * message and return an instance that contains the changed state.
19
+ */
20
+ interface ResponseInterface extends MessageInterface
21
+ {
22
+ /**
23
+ * Gets the response status code.
24
+ *
25
+ * The status code is a 3-digit integer result code of the server's attempt
26
+ * to understand and satisfy the request.
27
+ *
28
+ * @return int Status code.
29
+ */
30
+ public function getStatusCode();
31
+
32
+ /**
33
+ * Return an instance with the specified status code and, optionally, reason phrase.
34
+ *
35
+ * If no reason phrase is specified, implementations MAY choose to default
36
+ * to the RFC 7231 or IANA recommended reason phrase for the response's
37
+ * status code.
38
+ *
39
+ * This method MUST be implemented in such a way as to retain the
40
+ * immutability of the message, and MUST return an instance that has the
41
+ * updated status and reason phrase.
42
+ *
43
+ * @link http://tools.ietf.org/html/rfc7231#section-6
44
+ * @link http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
45
+ * @param int $code The 3-digit integer result code to set.
46
+ * @param string $reasonPhrase The reason phrase to use with the
47
+ * provided status code; if none is provided, implementations MAY
48
+ * use the defaults as suggested in the HTTP specification.
49
+ * @return static
50
+ * @throws \InvalidArgumentException For invalid status code arguments.
51
+ */
52
+ public function withStatus($code, $reasonPhrase = '');
53
+
54
+ /**
55
+ * Gets the response reason phrase associated with the status code.
56
+ *
57
+ * Because a reason phrase is not a required element in a response
58
+ * status line, the reason phrase value MAY be null. Implementations MAY
59
+ * choose to return the default RFC 7231 recommended reason phrase (or those
60
+ * listed in the IANA HTTP Status Code Registry) for the response's
61
+ * status code.
62
+ *
63
+ * @link http://tools.ietf.org/html/rfc7231#section-6
64
+ * @link http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
65
+ * @return string Reason phrase; must return an empty string if none present.
66
+ */
67
+ public function getReasonPhrase();
68
+ }
vendor/psr/http-message/src/ServerRequestInterface.php ADDED
@@ -0,0 +1,261 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Psr\Http\Message;
4
+
5
+ /**
6
+ * Representation of an incoming, server-side HTTP request.
7
+ *
8
+ * Per the HTTP specification, this interface includes properties for
9
+ * each of the following:
10
+ *
11
+ * - Protocol version
12
+ * - HTTP method
13
+ * - URI
14
+ * - Headers
15
+ * - Message body
16
+ *
17
+ * Additionally, it encapsulates all data as it has arrived to the
18
+ * application from the CGI and/or PHP environment, including:
19
+ *
20
+ * - The values represented in $_SERVER.
21
+ * - Any cookies provided (generally via $_COOKIE)
22
+ * - Query string arguments (generally via $_GET, or as parsed via parse_str())
23
+ * - Upload files, if any (as represented by $_FILES)
24
+ * - Deserialized body parameters (generally from $_POST)
25
+ *
26
+ * $_SERVER values MUST be treated as immutable, as they represent application
27
+ * state at the time of request; as such, no methods are provided to allow
28
+ * modification of those values. The other values provide such methods, as they
29
+ * can be restored from $_SERVER or the request body, and may need treatment
30
+ * during the application (e.g., body parameters may be deserialized based on
31
+ * content type).
32
+ *
33
+ * Additionally, this interface recognizes the utility of introspecting a
34
+ * request to derive and match additional parameters (e.g., via URI path
35
+ * matching, decrypting cookie values, deserializing non-form-encoded body
36
+ * content, matching authorization headers to users, etc). These parameters
37
+ * are stored in an "attributes" property.
38
+ *
39
+ * Requests are considered immutable; all methods that might change state MUST
40
+ * be implemented such that they retain the internal state of the current
41
+ * message and return an instance that contains the changed state.
42
+ */
43
+ interface ServerRequestInterface extends RequestInterface
44
+ {
45
+ /**
46
+ * Retrieve server parameters.
47
+ *
48
+ * Retrieves data related to the incoming request environment,
49
+ * typically derived from PHP's $_SERVER superglobal. The data IS NOT
50
+ * REQUIRED to originate from $_SERVER.
51
+ *
52
+ * @return array
53
+ */
54
+ public function getServerParams();
55
+
56
+ /**
57
+ * Retrieve cookies.
58
+ *
59
+ * Retrieves cookies sent by the client to the server.
60
+ *
61
+ * The data MUST be compatible with the structure of the $_COOKIE
62
+ * superglobal.
63
+ *
64
+ * @return array
65
+ */
66
+ public function getCookieParams();
67
+
68
+ /**
69
+ * Return an instance with the specified cookies.
70
+ *
71
+ * The data IS NOT REQUIRED to come from the $_COOKIE superglobal, but MUST
72
+ * be compatible with the structure of $_COOKIE. Typically, this data will
73
+ * be injected at instantiation.
74
+ *
75
+ * This method MUST NOT update the related Cookie header of the request
76
+ * instance, nor related values in the server params.
77
+ *
78
+ * This method MUST be implemented in such a way as to retain the
79
+ * immutability of the message, and MUST return an instance that has the
80
+ * updated cookie values.
81
+ *
82
+ * @param array $cookies Array of key/value pairs representing cookies.
83
+ * @return static
84
+ */
85
+ public function withCookieParams(array $cookies);
86
+
87
+ /**
88
+ * Retrieve query string arguments.
89
+ *
90
+ * Retrieves the deserialized query string arguments, if any.
91
+ *
92
+ * Note: the query params might not be in sync with the URI or server
93
+ * params. If you need to ensure you are only getting the original
94
+ * values, you may need to parse the query string from `getUri()->getQuery()`
95
+ * or from the `QUERY_STRING` server param.
96
+ *
97
+ * @return array
98
+ */
99
+ public function getQueryParams();
100
+
101
+ /**
102
+ * Return an instance with the specified query string arguments.
103
+ *
104
+ * These values SHOULD remain immutable over the course of the incoming
105
+ * request. They MAY be injected during instantiation, such as from PHP's
106
+ * $_GET superglobal, or MAY be derived from some other value such as the
107
+ * URI. In cases where the arguments are parsed from the URI, the data
108
+ * MUST be compatible with what PHP's parse_str() would return for
109
+ * purposes of how duplicate query parameters are handled, and how nested
110
+ * sets are handled.
111
+ *
112
+ * Setting query string arguments MUST NOT change the URI stored by the
113
+ * request, nor the values in the server params.
114
+ *
115
+ * This method MUST be implemented in such a way as to retain the
116
+ * immutability of the message, and MUST return an instance that has the
117
+ * updated query string arguments.
118
+ *
119
+ * @param array $query Array of query string arguments, typically from
120
+ * $_GET.
121
+ * @return static
122
+ */
123
+ public function withQueryParams(array $query);
124
+
125
+ /**
126
+ * Retrieve normalized file upload data.
127
+ *
128
+ * This method returns upload metadata in a normalized tree, with each leaf
129
+ * an instance of Psr\Http\Message\UploadedFileInterface.
130
+ *
131
+ * These values MAY be prepared from $_FILES or the message body during
132
+ * instantiation, or MAY be injected via withUploadedFiles().
133
+ *
134
+ * @return array An array tree of UploadedFileInterface instances; an empty
135
+ * array MUST be returned if no data is present.
136
+ */
137
+ public function getUploadedFiles();
138
+
139
+ /**
140
+ * Create a new instance with the specified uploaded files.
141
+ *
142
+ * This method MUST be implemented in such a way as to retain the
143
+ * immutability of the message, and MUST return an instance that has the
144
+ * updated body parameters.
145
+ *
146
+ * @param array $uploadedFiles An array tree of UploadedFileInterface instances.
147
+ * @return static
148
+ * @throws \InvalidArgumentException if an invalid structure is provided.
149
+ */
150
+ public function withUploadedFiles(array $uploadedFiles);
151
+
152
+ /**
153
+ * Retrieve any parameters provided in the request body.
154
+ *
155
+ * If the request Content-Type is either application/x-www-form-urlencoded
156
+ * or multipart/form-data, and the request method is POST, this method MUST
157
+ * return the contents of $_POST.
158
+ *
159
+ * Otherwise, this method may return any results of deserializing
160
+ * the request body content; as parsing returns structured content, the
161
+ * potential types MUST be arrays or objects only. A null value indicates
162
+ * the absence of body content.
163
+ *
164
+ * @return null|array|object The deserialized body parameters, if any.
165
+ * These will typically be an array or object.
166
+ */
167
+ public function getParsedBody();
168
+
169
+ /**
170
+ * Return an instance with the specified body parameters.
171
+ *
172
+ * These MAY be injected during instantiation.
173
+ *
174
+ * If the request Content-Type is either application/x-www-form-urlencoded
175
+ * or multipart/form-data, and the request method is POST, use this method
176
+ * ONLY to inject the contents of $_POST.
177
+ *
178
+ * The data IS NOT REQUIRED to come from $_POST, but MUST be the results of
179
+ * deserializing the request body content. Deserialization/parsing returns
180
+ * structured data, and, as such, this method ONLY accepts arrays or objects,
181
+ * or a null value if nothing was available to parse.
182
+ *
183
+ * As an example, if content negotiation determines that the request data
184
+ * is a JSON payload, this method could be used to create a request
185
+ * instance with the deserialized parameters.
186
+ *
187
+ * This method MUST be implemented in such a way as to retain the
188
+ * immutability of the message, and MUST return an instance that has the
189
+ * updated body parameters.
190
+ *
191
+ * @param null|array|object $data The deserialized body data. This will
192
+ * typically be in an array or object.
193
+ * @return static
194
+ * @throws \InvalidArgumentException if an unsupported argument type is
195
+ * provided.
196
+ */
197
+ public function withParsedBody($data);
198
+
199
+ /**
200
+ * Retrieve attributes derived from the request.
201
+ *
202
+ * The request "attributes" may be used to allow injection of any
203
+ * parameters derived from the request: e.g., the results of path
204
+ * match operations; the results of decrypting cookies; the results of
205
+ * deserializing non-form-encoded message bodies; etc. Attributes
206
+ * will be application and request specific, and CAN be mutable.
207
+ *
208
+ * @return array Attributes derived from the request.
209
+ */
210
+ public function getAttributes();
211
+
212
+ /**
213
+ * Retrieve a single derived request attribute.
214
+ *
215
+ * Retrieves a single derived request attribute as described in
216
+ * getAttributes(). If the attribute has not been previously set, returns
217
+ * the default value as provided.
218
+ *
219
+ * This method obviates the need for a hasAttribute() method, as it allows
220
+ * specifying a default value to return if the attribute is not found.
221
+ *
222
+ * @see getAttributes()
223
+ * @param string $name The attribute name.
224
+ * @param mixed $default Default value to return if the attribute does not exist.
225
+ * @return mixed
226
+ */
227
+ public function getAttribute($name, $default = null);
228
+
229
+ /**
230
+ * Return an instance with the specified derived request attribute.
231
+ *
232
+ * This method allows setting a single derived request attribute as
233
+ * described in getAttributes().
234
+ *
235
+ * This method MUST be implemented in such a way as to retain the
236
+ * immutability of the message, and MUST return an instance that has the
237
+ * updated attribute.
238
+ *
239
+ * @see getAttributes()
240
+ * @param string $name The attribute name.
241
+ * @param mixed $value The value of the attribute.
242
+ * @return static
243
+ */
244
+ public function withAttribute($name, $value);
245
+
246
+ /**
247
+ * Return an instance that removes the specified derived request attribute.
248
+ *
249
+ * This method allows removing a single derived request attribute as
250
+ * described in getAttributes().
251
+ *
252
+ * This method MUST be implemented in such a way as to retain the
253
+ * immutability of the message, and MUST return an instance that removes
254
+ * the attribute.
255
+ *
256
+ * @see getAttributes()
257
+ * @param string $name The attribute name.
258
+ * @return static
259
+ */
260
+ public function withoutAttribute($name);
261
+ }
vendor/psr/http-message/src/StreamInterface.php ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Psr\Http\Message;
4
+
5
+ /**
6
+ * Describes a data stream.
7
+ *
8
+ * Typically, an instance will wrap a PHP stream; this interface provides
9
+ * a wrapper around the most common operations, including serialization of
10
+ * the entire stream to a string.
11
+ */
12
+ interface StreamInterface
13
+ {
14
+ /**
15
+ * Reads all data from the stream into a string, from the beginning to end.
16
+ *
17
+ * This method MUST attempt to seek to the beginning of the stream before
18
+ * reading data and read the stream until the end is reached.
19
+ *
20
+ * Warning: This could attempt to load a large amount of data into memory.
21
+ *
22
+ * This method MUST NOT raise an exception in order to conform with PHP's
23
+ * string casting operations.
24
+ *
25
+ * @see http://php.net/manual/en/language.oop5.magic.php#object.tostring
26
+ * @return string
27
+ */
28
+ public function __toString();
29
+
30
+ /**
31
+ * Closes the stream and any underlying resources.
32
+ *
33
+ * @return void
34
+ */
35
+ public function close();
36
+
37
+ /**
38
+ * Separates any underlying resources from the stream.
39
+ *
40
+ * After the stream has been detached, the stream is in an unusable state.
41
+ *
42
+ * @return resource|null Underlying PHP stream, if any
43
+ */
44
+ public function detach();
45
+
46
+ /**
47
+ * Get the size of the stream if known.
48
+ *
49
+ * @return int|null Returns the size in bytes if known, or null if unknown.
50
+ */
51
+ public function getSize();
52
+
53
+ /**
54
+ * Returns the current position of the file read/write pointer
55
+ *
56
+ * @return int Position of the file pointer
57
+ * @throws \RuntimeException on error.
58
+ */
59
+ public function tell();
60
+
61
+ /**
62
+ * Returns true if the stream is at the end of the stream.
63
+ *
64
+ * @return bool
65
+ */
66
+ public function eof();
67
+
68
+ /**
69
+ * Returns whether or not the stream is seekable.
70
+ *
71
+ * @return bool
72
+ */
73
+ public function isSeekable();
74
+
75
+ /**
76
+ * Seek to a position in the stream.
77
+ *
78
+ * @link http://www.php.net/manual/en/function.fseek.php
79
+ * @param int $offset Stream offset
80
+ * @param int $whence Specifies how the cursor position will be calculated
81
+ * based on the seek offset. Valid values are identical to the built-in
82
+ * PHP $whence values for `fseek()`. SEEK_SET: Set position equal to
83
+ * offset bytes SEEK_CUR: Set position to current location plus offset
84
+ * SEEK_END: Set position to end-of-stream plus offset.
85
+ * @throws \RuntimeException on failure.
86
+ */
87
+ public function seek($offset, $whence = SEEK_SET);
88
+
89
+ /**
90
+ * Seek to the beginning of the stream.
91
+ *
92
+ * If the stream is not seekable, this method will raise an exception;
93
+ * otherwise, it will perform a seek(0).
94
+ *
95
+ * @see seek()
96
+ * @link http://www.php.net/manual/en/function.fseek.php
97
+ * @throws \RuntimeException on failure.
98
+ */
99
+ public function rewind();
100
+
101
+ /**
102
+ * Returns whether or not the stream is writable.
103
+ *
104
+ * @return bool
105
+ */
106
+ public function isWritable();
107
+
108
+ /**
109
+ * Write data to the stream.
110
+ *
111
+ * @param string $string The string that is to be written.
112
+ * @return int Returns the number of bytes written to the stream.
113
+ * @throws \RuntimeException on failure.
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 underlying stream
129
+ * call returns fewer bytes.
130
+ * @return string Returns the data read from the stream, or an empty string
131
+ * if no bytes are available.
132
+ * @throws \RuntimeException if an error occurs.
133
+ */
134
+ public function read($length);
135
+
136
+ /**
137
+ * Returns the remaining contents in a string
138
+ *
139
+ * @return string
140
+ * @throws \RuntimeException if unable to read or an error occurs while
141
+ * reading.
142
+ */
143
+ public function getContents();
144
+
145
+ /**
146
+ * Get stream metadata as an associative array or retrieve a specific key.
147
+ *
148
+ * The keys returned are identical to the keys returned from PHP's
149
+ * stream_get_meta_data() function.
150
+ *
151
+ * @link http://php.net/manual/en/function.stream-get-meta-data.php
152
+ * @param string $key Specific metadata to retrieve.
153
+ * @return array|mixed|null Returns an associative array if no key is
154
+ * provided. Returns a specific key value if a key is provided and the
155
+ * value is found, or null if the key is not found.
156
+ */
157
+ public function getMetadata($key = null);
158
+ }
vendor/psr/http-message/src/UploadedFileInterface.php ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Psr\Http\Message;
4
+
5
+ /**
6
+ * Value object representing a file uploaded through an HTTP request.
7
+ *
8
+ * Instances of this interface are considered immutable; all methods that
9
+ * might change state MUST be implemented such that they retain the internal
10
+ * state of the current instance and return an instance that contains the
11
+ * changed state.
12
+ */
13
+ interface UploadedFileInterface
14
+ {
15
+ /**
16
+ * Retrieve a stream representing the uploaded file.
17
+ *
18
+ * This method MUST return a StreamInterface instance, representing the
19
+ * uploaded file. The purpose of this method is to allow utilizing native PHP
20
+ * stream functionality to manipulate the file upload, such as
21
+ * stream_copy_to_stream() (though the result will need to be decorated in a
22
+ * native PHP stream wrapper to work with such functions).
23
+ *
24
+ * If the moveTo() method has been called previously, this method MUST raise
25
+ * an exception.
26
+ *
27
+ * @return StreamInterface Stream representation of the uploaded file.
28
+ * @throws \RuntimeException in cases when no stream is available or can be
29
+ * created.
30
+ */
31
+ public function getStream();
32
+
33
+ /**
34
+ * Move the uploaded file to a new location.
35
+ *
36
+ * Use this method as an alternative to move_uploaded_file(). This method is
37
+ * guaranteed to work in both SAPI and non-SAPI environments.
38
+ * Implementations must determine which environment they are in, and use the
39
+ * appropriate method (move_uploaded_file(), rename(), or a stream
40
+ * operation) to perform the operation.
41
+ *
42
+ * $targetPath may be an absolute path, or a relative path. If it is a
43
+ * relative path, resolution should be the same as used by PHP's rename()
44
+ * function.
45
+ *
46
+ * The original file or stream MUST be removed on completion.
47
+ *
48
+ * If this method is called more than once, any subsequent calls MUST raise
49
+ * an exception.
50
+ *
51
+ * When used in an SAPI environment where $_FILES is populated, when writing
52
+ * files via moveTo(), is_uploaded_file() and move_uploaded_file() SHOULD be
53
+ * used to ensure permissions and upload status are verified correctly.
54
+ *
55
+ * If you wish to move to a stream, use getStream(), as SAPI operations
56
+ * cannot guarantee writing to stream destinations.
57
+ *
58
+ * @see http://php.net/is_uploaded_file
59
+ * @see http://php.net/move_uploaded_file
60
+ * @param string $targetPath Path to which to move the uploaded file.
61
+ * @throws \InvalidArgumentException if the $targetPath specified is invalid.
62
+ * @throws \RuntimeException on any error during the move operation, or on
63
+ * the second or subsequent call to the method.
64
+ */
65
+ public function moveTo($targetPath);
66
+
67
+ /**
68
+ * Retrieve the file size.
69
+ *
70
+ * Implementations SHOULD return the value stored in the "size" key of
71
+ * the file in the $_FILES array if available, as PHP calculates this based
72
+ * on the actual size transmitted.
73
+ *
74
+ * @return int|null The file size in bytes or null if unknown.
75
+ */
76
+ public function getSize();
77
+
78
+ /**
79
+ * Retrieve the error associated with the uploaded file.
80
+ *
81
+ * The return value MUST be one of PHP's UPLOAD_ERR_XXX constants.
82
+ *
83
+ * If the file was uploaded successfully, this method MUST return
84
+ * UPLOAD_ERR_OK.
85
+ *
86
+ * Implementations SHOULD return the value stored in the "error" key of
87
+ * the file in the $_FILES array.
88
+ *
89
+ * @see http://php.net/manual/en/features.file-upload.errors.php
90
+ * @return int One of PHP's UPLOAD_ERR_XXX constants.
91
+ */
92
+ public function getError();
93
+
94
+ /**
95
+ * Retrieve the filename sent by the client.
96
+ *
97
+ * Do not trust the value returned by this method. A client could send
98
+ * a malicious filename with the intention to corrupt or hack your
99
+ * application.
100
+ *
101
+ * Implementations SHOULD return the value stored in the "name" key of
102
+ * the file in the $_FILES array.
103
+ *
104
+ * @return string|null The filename sent by the client or null if none
105
+ * was provided.
106
+ */
107
+ public function getClientFilename();
108
+
109
+ /**
110
+ * Retrieve the media type sent by the client.
111
+ *
112
+ * Do not trust the value returned by this method. A client could send
113
+ * a malicious media type with the intention to corrupt or hack your
114
+ * application.
115
+ *
116
+ * Implementations SHOULD return the value stored in the "type" key of
117
+ * the file in the $_FILES array.
118
+ *
119
+ * @return string|null The media type sent by the client or null if none
120
+ * was provided.
121
+ */
122
+ public function getClientMediaType();
123
+ }
vendor/psr/http-message/src/UriInterface.php ADDED
@@ -0,0 +1,323 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Psr\Http\Message;
3
+
4
+ /**
5
+ * Value object representing a URI.
6
+ *
7
+ * This interface is meant to represent URIs according to RFC 3986 and to
8
+ * provide methods for most common operations. Additional functionality for
9
+ * working with URIs can be provided on top of the interface or externally.
10
+ * Its primary use is for HTTP requests, but may also be used in other
11
+ * contexts.
12
+ *
13
+ * Instances of this interface are considered immutable; all methods that
14
+ * might change state MUST be implemented such that they retain the internal
15
+ * state of the current instance and return an instance that contains the
16
+ * changed state.
17
+ *
18
+ * Typically the Host header will be also be present in the request message.
19
+ * For server-side requests, the scheme will typically be discoverable in the
20
+ * server parameters.
21
+ *
22
+ * @link http://tools.ietf.org/html/rfc3986 (the URI specification)
23
+ */
24
+ interface UriInterface
25
+ {
26
+ /**
27
+ * Retrieve the scheme component of the URI.
28
+ *
29
+ * If no scheme is present, this method MUST return an empty string.
30
+ *
31
+ * The value returned MUST be normalized to lowercase, per RFC 3986
32
+ * Section 3.1.
33
+ *
34
+ * The trailing ":" character is not part of the scheme and MUST NOT be
35
+ * added.
36
+ *
37
+ * @see https://tools.ietf.org/html/rfc3986#section-3.1
38
+ * @return string The URI scheme.
39
+ */
40
+ public function getScheme();
41
+
42
+ /**
43
+ * Retrieve the authority component of the URI.
44
+ *
45
+ * If no authority information is present, this method MUST return an empty
46
+ * string.
47
+ *
48
+ * The authority syntax of the URI is:
49
+ *
50
+ * <pre>
51
+ * [user-info@]host[:port]
52
+ * </pre>
53
+ *
54
+ * If the port component is not set or is the standard port for the current
55
+ * scheme, it SHOULD NOT be included.
56
+ *
57
+ * @see https://tools.ietf.org/html/rfc3986#section-3.2
58
+ * @return string The URI authority, in "[user-info@]host[:port]" format.
59
+ */
60
+ public function getAuthority();
61
+
62
+ /**
63
+ * Retrieve the user information component of the URI.
64
+ *
65
+ * If no user information is present, this method MUST return an empty
66
+ * string.
67
+ *
68
+ * If a user is present in the URI, this will return that value;
69
+ * additionally, if the password is also present, it will be appended to the
70
+ * user value, with a colon (":") separating the values.
71
+ *
72
+ * The trailing "@" character is not part of the user information and MUST
73
+ * NOT be added.
74
+ *
75
+ * @return string The URI user information, in "username[:password]" format.
76
+ */
77
+ public function getUserInfo();
78
+
79
+ /**
80
+ * Retrieve the host component of the URI.
81
+ *
82
+ * If no host is present, this method MUST return an empty string.
83
+ *
84
+ * The value returned MUST be normalized to lowercase, per RFC 3986
85
+ * Section 3.2.2.
86
+ *
87
+ * @see http://tools.ietf.org/html/rfc3986#section-3.2.2
88
+ * @return string The URI host.
89
+ */
90
+ public function getHost();
91
+
92
+ /**
93
+ * Retrieve the port component of the URI.
94
+ *
95
+ * If a port is present, and it is non-standard for the current scheme,
96
+ * this method MUST return it as an integer. If the port is the standard port
97
+ * used with the current scheme, this method SHOULD return null.
98
+ *
99
+ * If no port is present, and no scheme is present, this method MUST return
100
+ * a null value.
101
+ *
102
+ * If no port is present, but a scheme is present, this method MAY return
103
+ * the standard port for that scheme, but SHOULD return null.
104
+ *
105
+ * @return null|int The URI port.
106
+ */
107
+ public function getPort();
108
+
109
+ /**
110
+ * Retrieve the path component of the URI.
111
+ *
112
+ * The path can either be empty or absolute (starting with a slash) or
113
+ * rootless (not starting with a slash). Implementations MUST support all
114
+ * three syntaxes.
115
+ *
116
+ * Normally, the empty path "" and absolute path "/" are considered equal as
117
+ * defined in RFC 7230 Section 2.7.3. But this method MUST NOT automatically
118
+ * do this normalization because in contexts with a trimmed base path, e.g.
119
+ * the front controller, this difference becomes significant. It's the task
120
+ * of the user to handle both "" and "/".
121
+ *
122
+ * The value returned MUST be percent-encoded, but MUST NOT double-encode
123
+ * any characters. To determine what characters to encode, please refer to
124
+ * RFC 3986, Sections 2 and 3.3.
125
+ *
126
+ * As an example, if the value should include a slash ("/") not intended as
127
+ * delimiter between path segments, that value MUST be passed in encoded
128
+ * form (e.g., "%2F") to the instance.
129
+ *
130
+ * @see https://tools.ietf.org/html/rfc3986#section-2
131
+ * @see https://tools.ietf.org/html/rfc3986#section-3.3
132
+ * @return string The URI path.
133
+ */
134
+ public function getPath();
135
+
136
+ /**
137
+ * Retrieve the query string of the URI.
138
+ *
139
+ * If no query string is present, this method MUST return an empty string.
140
+ *
141
+ * The leading "?" character is not part of the query and MUST NOT be
142
+ * added.
143
+ *
144
+ * The value returned MUST be percent-encoded, but MUST NOT double-encode
145
+ * any characters. To determine what characters to encode, please refer to
146
+ * RFC 3986, Sections 2 and 3.4.
147
+ *
148
+ * As an example, if a value in a key/value pair of the query string should
149
+ * include an ampersand ("&") not intended as a delimiter between values,
150
+ * that value MUST be passed in encoded form (e.g., "%26") to the instance.
151
+ *
152
+ * @see https://tools.ietf.org/html/rfc3986#section-2
153
+ * @see https://tools.ietf.org/html/rfc3986#section-3.4
154
+ * @return string The URI query string.
155
+ */
156
+ public function getQuery();
157
+
158
+ /**
159
+ * Retrieve the fragment component of the URI.
160
+ *
161
+ * If no fragment is present, this method MUST return an empty string.
162
+ *
163
+ * The leading "#" character is not part of the fragment and MUST NOT be
164
+ * added.
165
+ *
166
+ * The value returned MUST be percent-encoded, but MUST NOT double-encode
167
+ * any characters. To determine what characters to encode, please refer to
168
+ * RFC 3986, Sections 2 and 3.5.
169
+ *
170
+ * @see https://tools.ietf.org/html/rfc3986#section-2
171
+ * @see https://tools.ietf.org/html/rfc3986#section-3.5
172
+ * @return string The URI fragment.
173
+ */
174
+ public function getFragment();
175
+
176
+ /**
177
+ * Return an instance with the specified scheme.
178
+ *
179
+ * This method MUST retain the state of the current instance, and return
180
+ * an instance that contains the specified scheme.
181
+ *
182
+ * Implementations MUST support the schemes "http" and "https" case
183
+ * insensitively, and MAY accommodate other schemes if required.
184
+ *
185
+ * An empty scheme is equivalent to removing the scheme.
186
+ *
187
+ * @param string $scheme The scheme to use with the new instance.
188
+ * @return static A new instance with the specified scheme.
189
+ * @throws \InvalidArgumentException for invalid or unsupported schemes.
190
+ */
191
+ public function withScheme($scheme);
192
+
193
+ /**
194
+ * Return an instance with the specified user information.
195
+ *
196
+ * This method MUST retain the state of the current instance, and return
197
+ * an instance that contains the specified user information.
198
+ *
199
+ * Password is optional, but the user information MUST include the
200
+ * user; an empty string for the user is equivalent to removing user
201
+ * information.
202
+ *
203
+ * @param string $user The user name to use for authority.
204
+ * @param null|string $password The password associated with $user.
205
+ * @return static A new instance with the specified user information.
206
+ */
207
+ public function withUserInfo($user, $password = null);
208
+
209
+ /**
210
+ * Return an instance with the specified host.
211
+ *
212
+ * This method MUST retain the state of the current instance, and return
213
+ * an instance that contains the specified host.
214
+ *
215
+ * An empty host value is equivalent to removing the host.
216
+ *
217
+ * @param string $host The hostname to use with the new instance.
218
+ * @return static A new instance with the specified host.
219
+ * @throws \InvalidArgumentException for invalid hostnames.
220
+ */
221
+ public function withHost($host);
222
+
223
+ /**
224
+ * Return an instance with the specified port.
225
+ *
226
+ * This method MUST retain the state of the current instance, and return
227
+ * an instance that contains the specified port.
228
+ *
229
+ * Implementations MUST raise an exception for ports outside the
230
+ * established TCP and UDP port ranges.
231
+ *
232
+ * A null value provided for the port is equivalent to removing the port
233
+ * information.
234
+ *
235
+ * @param null|int $port The port to use with the new instance; a null value
236
+ * removes the port information.
237
+ * @return static A new instance with the specified port.
238
+ * @throws \InvalidArgumentException for invalid ports.
239
+ */
240
+ public function withPort($port);
241
+
242
+ /**
243
+ * Return an instance with the specified path.
244
+ *
245
+ * This method MUST retain the state of the current instance, and return
246
+ * an instance that contains the specified path.
247
+ *
248
+ * The path can either be empty or absolute (starting with a slash) or
249
+ * rootless (not starting with a slash). Implementations MUST support all
250
+ * three syntaxes.
251
+ *
252
+ * If the path is intended to be domain-relative rather than path relative then
253
+ * it must begin with a slash ("/"). Paths not starting with a slash ("/")
254
+ * are assumed to be relative to some base path known to the application or
255
+ * consumer.
256
+ *
257
+ * Users can provide both encoded and decoded path characters.
258
+ * Implementations ensure the correct encoding as outlined in getPath().
259
+ *
260
+ * @param string $path The path to use with the new instance.
261
+ * @return static A new instance with the specified path.
262
+ * @throws \InvalidArgumentException for invalid paths.
263
+ */
264
+ public function withPath($path);
265
+
266
+ /**
267
+ * Return an instance with the specified query string.
268
+ *
269
+ * This method MUST retain the state of the current instance, and return
270
+ * an instance that contains the specified query string.
271
+ *
272
+ * Users can provide both encoded and decoded query characters.
273
+ * Implementations ensure the correct encoding as outlined in getQuery().
274
+ *
275
+ * An empty query string value is equivalent to removing the query string.
276
+ *
277
+ * @param string $query The query string to use with the new instance.
278
+ * @return static A new instance with the specified query string.
279
+ * @throws \InvalidArgumentException for invalid query strings.
280
+ */
281
+ public function withQuery($query);
282
+
283
+ /**
284
+ * Return an instance with the specified URI fragment.
285
+ *
286
+ * This method MUST retain the state of the current instance, and return
287
+ * an instance that contains the specified URI fragment.
288
+ *
289
+ * Users can provide both encoded and decoded fragment characters.
290
+ * Implementations ensure the correct encoding as outlined in getFragment().
291
+ *
292
+ * An empty fragment value is equivalent to removing the fragment.
293
+ *
294
+ * @param string $fragment The fragment to use with the new instance.
295
+ * @return static A new instance with the specified fragment.
296
+ */
297
+ public function withFragment($fragment);
298
+
299
+ /**
300
+ * Return the string representation as a URI reference.
301
+ *
302
+ * Depending on which components of the URI are present, the resulting
303
+ * string is either a full URI or relative reference according to RFC 3986,
304
+ * Section 4.1. The method concatenates the various components of the URI,
305
+ * using the appropriate delimiters:
306
+ *
307
+ * - If a scheme is present, it MUST be suffixed by ":".
308
+ * - If an authority is present, it MUST be prefixed by "//".
309
+ * - The path can be concatenated without delimiters. But there are two
310
+ * cases where the path has to be adjusted to make the URI reference
311
+ * valid as PHP does not allow to throw an exception in __toString():
312
+ * - If the path is rootless and an authority is present, the path MUST
313
+ * be prefixed by "/".
314
+ * - If the path is starting with more than one "/" and no authority is
315
+ * present, the starting slashes MUST be reduced to one.
316
+ * - If a query is present, it MUST be prefixed by "?".
317
+ * - If a fragment is present, it MUST be prefixed by "#".
318
+ *
319
+ * @see http://tools.ietf.org/html/rfc3986#section-4.1
320
+ * @return string
321
+ */
322
+ public function __toString();
323
+ }
vendor/ralouphie/getallheaders/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Ralph Khattar
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
vendor/ralouphie/getallheaders/README.md ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ getallheaders
2
+ =============
3
+
4
+ PHP `getallheaders()` polyfill. Compatible with PHP >= 5.3.
5
+
6
+ [![Build Status](https://travis-ci.org/ralouphie/getallheaders.svg?branch=master)](https://travis-ci.org/ralouphie/getallheaders)
7
+ [![Coverage Status](https://coveralls.io/repos/ralouphie/getallheaders/badge.png?branch=master)](https://coveralls.io/r/ralouphie/getallheaders?branch=master)
8
+ [![Latest Stable Version](https://poser.pugx.org/ralouphie/getallheaders/v/stable.png)](https://packagist.org/packages/ralouphie/getallheaders)
9
+ [![Latest Unstable Version](https://poser.pugx.org/ralouphie/getallheaders/v/unstable.png)](https://packagist.org/packages/ralouphie/getallheaders)
10
+ [![License](https://poser.pugx.org/ralouphie/getallheaders/license.png)](https://packagist.org/packages/ralouphie/getallheaders)
11
+
12
+
13
+ This is a simple polyfill for [`getallheaders()`](http://www.php.net/manual/en/function.getallheaders.php).
14
+
15
+ ## Install
16
+
17
+ ```
18
+ composer require ralouphie/getallheaders
19
+ ```
vendor/ralouphie/getallheaders/src/getallheaders.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if (!function_exists('getallheaders')) {
4
+
5
+ /**
6
+ * Get all HTTP header key/values as an associative array for the current request.
7
+ *
8
+ * @return string[string] The HTTP header key/value pairs.
9
+ */
10
+ function getallheaders()
11
+ {
12
+ $headers = array();
13
+
14
+ $copy_server = array(
15
+ 'CONTENT_TYPE' => 'Content-Type',
16
+ 'CONTENT_LENGTH' => 'Content-Length',
17
+ 'CONTENT_MD5' => 'Content-Md5',
18
+ );
19
+
20
+ foreach ($_SERVER as $key => $value) {
21
+ if (substr($key, 0, 5) === 'HTTP_') {
22
+ $key = substr($key, 5);
23
+ if (!isset($copy_server[$key]) || !isset($_SERVER[$key])) {
24
+ $key = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $key))));
25
+ $headers[$key] = $value;
26
+ }
27
+ } elseif (isset($copy_server[$key])) {
28
+ $headers[$copy_server[$key]] = $value;
29
+ }
30
+ }
31
+
32
+ if (!isset($headers['Authorization'])) {
33
+ if (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) {
34
+ $headers['Authorization'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
35
+ } elseif (isset($_SERVER['PHP_AUTH_USER'])) {
36
+ $basic_pass = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : '';
37
+ $headers['Authorization'] = 'Basic ' . base64_encode($_SERVER['PHP_AUTH_USER'] . ':' . $basic_pass);
38
+ } elseif (isset($_SERVER['PHP_AUTH_DIGEST'])) {
39
+ $headers['Authorization'] = $_SERVER['PHP_AUTH_DIGEST'];
40
+ }
41
+ }
42
+
43
+ return $headers;
44
+ }
45
+
46
+ }